91 lines
2.3 KiB
JavaScript
91 lines
2.3 KiB
JavaScript
import React, { useMemo } from "react";
|
|
|
|
/**
|
|
* PhotoGrid — Instagram-style masonry grid for Docusaurus.
|
|
*
|
|
* Usage in any .mdx page:
|
|
*
|
|
* import PhotoGrid from "@site/src/components/PhotoGrid";
|
|
*
|
|
* <PhotoGrid
|
|
* photos={[
|
|
* "/img/gallery/cat-01.jpg",
|
|
* "/img/gallery/sunset-02.webp",
|
|
* "/img/gallery/meme-03.png",
|
|
* ]}
|
|
* shuffle
|
|
* />
|
|
*
|
|
* Props:
|
|
* photos — string[] — paths relative to /static (required)
|
|
* columns — number — desktop columns, default 3
|
|
* gap — string — grid gap, default "12px"
|
|
* shuffle — boolean — randomize order on each page load, default false
|
|
*/
|
|
export default function PhotoGrid({ photos = [], columns = 3, gap = "12px", shuffle = false }) {
|
|
const displayPhotos = useMemo(() => {
|
|
if (!shuffle) return photos;
|
|
const arr = [...photos];
|
|
for (let i = arr.length - 1; i > 0; i--) {
|
|
const j = Math.floor(Math.random() * (i + 1));
|
|
[arr[i], arr[j]] = [arr[j], arr[i]];
|
|
}
|
|
return arr;
|
|
}, [photos, shuffle]);
|
|
|
|
if (!displayPhotos.length) return null;
|
|
|
|
return (
|
|
<>
|
|
<style>{`
|
|
.photo-grid {
|
|
column-count: ${columns};
|
|
column-gap: ${gap};
|
|
}
|
|
.photo-grid__item {
|
|
break-inside: avoid;
|
|
margin-bottom: ${gap};
|
|
cursor: pointer;
|
|
display: block;
|
|
border-radius: 6px;
|
|
overflow: hidden;
|
|
line-height: 0;
|
|
transition: opacity 0.2s ease;
|
|
}
|
|
.photo-grid__item:hover {
|
|
opacity: 0.85;
|
|
}
|
|
.photo-grid__item img {
|
|
width: 100%;
|
|
height: auto;
|
|
display: block;
|
|
}
|
|
@media (max-width: 768px) {
|
|
.photo-grid {
|
|
column-count: 1 !important;
|
|
}
|
|
}
|
|
@media (min-width: 769px) and (max-width: 1024px) {
|
|
.photo-grid {
|
|
column-count: 2 !important;
|
|
}
|
|
}
|
|
`}</style>
|
|
|
|
<div className="photo-grid">
|
|
{displayPhotos.map((src, i) => (
|
|
<a
|
|
key={src}
|
|
className="photo-grid__item"
|
|
href={src}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
>
|
|
<img src={src} alt="" loading="lazy" />
|
|
</a>
|
|
))}
|
|
</div>
|
|
</>
|
|
);
|
|
}
|