Files
docusaurus-photogrid/PhotoGrid.jsx
2026-03-27 01:50:51 +00:00

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>
</>
);
}