"use client"; import Image from "next/image"; import { useEffect, useRef, useState } from "react"; export function Gallery({ images, alt }: { images: string[]; alt: string }) { const [open, setOpen] = useState(null); const touchStartX = useRef(null); const thumbsRef = useRef(null); // Keyboard + scroll lock useEffect(() => { if (open === null) return; const prev = document.body.style.overflow; document.body.style.overflow = "hidden"; const onKey = (e: KeyboardEvent) => { if (e.key === "Escape") setOpen(null); if (e.key === "ArrowRight") setOpen((i) => (i === null ? null : (i + 1) % images.length)); if (e.key === "ArrowLeft") setOpen((i) => (i === null ? null : (i - 1 + images.length) % images.length)); }; window.addEventListener("keydown", onKey); return () => { window.removeEventListener("keydown", onKey); document.body.style.overflow = prev; }; }, [open, images.length]); // Scroll active thumbnail into view useEffect(() => { if (open === null || !thumbsRef.current) return; const btn = thumbsRef.current.children[open] as HTMLElement | undefined; btn?.scrollIntoView({ block: "nearest", inline: "center", behavior: "smooth" }); }, [open]); if (images.length === 0) return null; const [hero, ...rest] = images; const go = (dir: 1 | -1) => setOpen((i) => (i === null ? null : (i + dir + images.length) % images.length)); return ( <> {/* Grid */}
{rest.slice(0, 4).map((src, idx) => ( ))}
{/* Lightbox */} {open !== null && (
setOpen(null)} role="dialog" aria-modal="true" onTouchStart={(e) => { touchStartX.current = e.touches[0].clientX; }} onTouchEnd={(e) => { if (touchStartX.current === null) return; const dx = e.changedTouches[0].clientX - (touchStartX.current as number); if (Math.abs(dx) > 50) go(dx < 0 ? 1 : -1); touchStartX.current = null; }} > {/* Top bar */}
e.stopPropagation()}> {open + 1} / {images.length}
{/* Image */}
e.stopPropagation()} >
{`${alt}
{/* Thumbnail strip */}
e.stopPropagation()} >
{images.map((src, idx) => ( ))}
)} ); }