"use client"; import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react"; import type { GalleryImage } from "@/generated/prisma/client"; import { WaffleMenuImage } from "./WaffleMenuImage"; const INTERVAL_MS = 5000; const MAX_VISIBLE = 3; /** gap-3 = 0.75rem — garder aligné avec les classes Tailwind */ const GAP_PX = 12; const SLIDE_EASE = "cubic-bezier(0.25, 0.46, 0.45, 0.94)"; type Props = { images: GalleryImage[]; }; /** Nombre de positions « première image à gauche » : 0 … len-3 → len-2 positions */ function positionCount(len: number) { return Math.max(0, len - 2); } export function GalleryCarousel({ images }: Props) { const viewportRef = useRef(null); const [startIndex, setStartIndex] = useState(0); const [paused, setPaused] = useState(false); const [metrics, setMetrics] = useState({ itemW: 0, step: 0 }); const len = images.length; const positions = positionCount(len); useLayoutEffect(() => { const el = viewportRef.current; if (!el) return; function measure() { const node = viewportRef.current; if (!node) return; const w = node.clientWidth; if (w <= 0) return; const itemW = (w - 2 * GAP_PX) / MAX_VISIBLE; const step = itemW + GAP_PX; setMetrics((m) => m.itemW === itemW && m.step === step ? m : { itemW, step } ); } measure(); const ro = new ResizeObserver(measure); ro.observe(el); return () => ro.disconnect(); }, []); const advance = useCallback(() => { if (len <= MAX_VISIBLE || positions <= 1) return; setStartIndex((i) => (i + 1) % positions); }, [len, positions]); useEffect(() => { if (len <= MAX_VISIBLE || paused || positions <= 1) return undefined; const t = window.setInterval(advance, INTERVAL_MS); return () => window.clearInterval(t); }, [len, paused, positions, advance]); useEffect(() => { if (startIndex >= positions) setStartIndex(0); }, [startIndex, positions]); function goToPosition(i: number) { if (i < 0 || i >= positions || i === startIndex) return; setStartIndex(i); } if (len === 0) { return (

Photos à venir — ajoutez-en depuis l’administration (section Galerie).

); } if (len <= MAX_VISIBLE) { const gridClass = len === 1 ? "mx-auto grid max-w-md grid-cols-1 gap-3 sm:gap-4" : len === 2 ? "mx-auto grid max-w-2xl grid-cols-2 gap-3 sm:gap-4" : "grid grid-cols-1 gap-3 sm:grid-cols-3 sm:gap-4"; return (
{images.map((img) => (
))}
); } const translateX = metrics.step > 0 ? -startIndex * metrics.step : 0; return (
setPaused(true)} onMouseLeave={() => setPaused(false)} >
{images.map((img) => (
0 ? { width: metrics.itemW, minWidth: metrics.itemW } : { width: "calc((100% - 24px) / 3)", minWidth: "calc((100% - 24px) / 3)" } } >
))}
{positions > 1 ? (
{Array.from({ length: positions }).map((_, i) => (
) : null}
); }