Files
app.gaertan.art/src/components/portfolio/JustifiedGallery.tsx

60 lines
1.7 KiB
TypeScript

"use client";
import {
JustifiedImage,
justifyPortfolioImages,
} from "@/utils/justifyPortfolioImages";
import { useEffect, useRef, useState } from "react";
import { ImageCard } from "./ImageCard";
interface Props {
images: JustifiedImage[];
rowHeight?: number;
gap?: number;
}
export function JustifiedGallery({ images, rowHeight = 200, gap = 4 }: Props) {
const containerRef = useRef<HTMLDivElement>(null);
const [containerWidth, setContainerWidth] = useState(1200);
const [rows, setRows] = useState<JustifiedImage[][]>([]);
useEffect(() => {
if (!containerRef.current) return;
const observer = new ResizeObserver(([entry]) => {
setContainerWidth(entry.contentRect.width);
});
observer.observe(containerRef.current);
return () => observer.disconnect();
}, []);
useEffect(() => {
const newRows = justifyPortfolioImages(images, containerWidth, rowHeight, gap);
setRows(newRows);
}, [images, containerWidth, rowHeight, gap]);
return (
<div ref={containerRef} className="w-full">
{rows.length === 0 && (
<p className="text-muted-foreground text-center py-20">No images to display</p>
)}
{rows.map((row, i) => (
<div key={i} className="flex gap-[4px] mb-[4px]">
{row.map((img) => (
<div key={img.id} style={{ width: img.width, height: img.height }}>
<ImageCard
image={{
id: img.id,
altText: img.altText,
url: img.url,
backgroundColor: img.backgroundColor,
}}
variant="mosaic"
/>
</div>
))}
</div>
))}
</div>
);
}