/* NEKTAR — Section 02 · Le lieu Deux modes : défilement (slideshow) + éditorial (photos décalées crème) */ const { useState, useEffect, useRef, useCallback } = React; const TWEAK_DEFAULTS = { mode: "défilement" }; /* Photos — 4 sélectionnées pour l'éditorial, 8 pour le défilement */ const PHOTO_IDS = [ '1TEstUhVD3N47mYYylKHWpY4880UyyWpV', // LG1_9285 '1rMY-385QRZlJoUXb45qouWsjAAZqNe8A', // LG1_9363 '1urxtR7pHDDTrQ2PRgSr2SJ1d4OUfq_LW', // LG1_9379 '1MImo3cywdkv19Tt9aR45jW3FghqEUMny', // LG1_9383 '1x_gKGYXKSa4Aox4DNrn3rDrIZlRqXm5b', // LG1_9389 '1_SEoQHJaVdQiMMCWrqWzarTE7p_IiESf', // LG1_9430 '1fywRqv_02oeApJearFWXj11RoKhti14R', // LG1_9440 '1MfJ-e4ST1sH7hchWSmnKJPFWQi_M12-0', // LG1_9463 ]; const PHOTOS = PHOTO_IDS.map(id => `https://drive.google.com/thumbnail?id=${id}&sz=w2400` ); const AUTO_DELAY = 3000; // 3s entre chaque slide const RESUME_DELAY = 4000; // ms avant reprise auto après action manuelle /* ------------------------------------------------------- SVG Arrows — 1px or, no fill (design system) ------------------------------------------------------- */ function ArrowLeft() { return ( ); } function ArrowRight() { return ( ); } /* ------------------------------------------------------- Gallery ------------------------------------------------------- */ function Gallery() { const [current, setCurrent] = useState(0); const [paused, setPaused] = useState(false); const [progKey, setProgKey] = useState(0); const total = PHOTOS.length; const autoRef = useRef(null); const resumeRef = useRef(null); const touchX = useRef(null); /* Navigate to slide index */ const goTo = useCallback((idx) => { setCurrent(((idx % total) + total) % total); setProgKey(k => k + 1); }, [total]); const goNext = useCallback(() => goTo(current + 1), [goTo, current]); const goPrev = useCallback(() => goTo(current - 1), [goTo, current]); /* Manual action — pause, navigate, schedule resume */ const manual = useCallback((fn) => { setPaused(true); clearTimeout(resumeRef.current); fn(); resumeRef.current = setTimeout(() => setPaused(false), RESUME_DELAY); }, []); /* Auto-advance */ useEffect(() => { if (paused) { clearInterval(autoRef.current); return; } autoRef.current = setInterval(() => { setCurrent(c => (c + 1) % total); setProgKey(k => k + 1); }, AUTO_DELAY); return () => clearInterval(autoRef.current); }, [paused, total]); /* Keyboard ← → */ useEffect(() => { const onKey = (e) => { if (e.key === 'ArrowLeft') manual(goPrev); if (e.key === 'ArrowRight') manual(goNext); }; window.addEventListener('keydown', onKey); return () => window.removeEventListener('keydown', onKey); }, [manual, goPrev, goNext]); /* Touch swipe */ const onTouchStart = (e) => { touchX.current = e.touches[0].clientX; }; const onTouchEnd = (e) => { if (touchX.current === null) return; const dx = e.changedTouches[0].clientX - touchX.current; touchX.current = null; if (Math.abs(dx) < 44) return; // ignore micro-taps manual(dx < 0 ? goNext : goPrev); }; return (
setPaused(true)} onMouseLeave={() => setPaused(false)} onTouchStart={onTouchStart} onTouchEnd={onTouchEnd} > {/* Slides */} {PHOTOS.map((url, i) => (
{`Nektar
))} {/* Flèche gauche */} {/* Flèche droite */} {/* Label "GALERIE" centré sur la photo */} {/* Dots de pagination — centrés en bas, or */} {/* Barre de progression — key force le reset à chaque changement */}
); } /* ------------------------------------------------------- Editorial Carousel — paires décalées, flèches or, auto 3s ------------------------------------------------------- */ function EditorialCarousel() { // Construire les paires : [photos 0+1], [photos 2+3], [photos 4+5], [photos 6+7] const PAIRS = []; for (let i = 0; i < PHOTO_IDS.length - 1; i += 2) { PAIRS.push([ `https://drive.google.com/thumbnail?id=${PHOTO_IDS[i]}&sz=w2400`, `https://drive.google.com/thumbnail?id=${PHOTO_IDS[i + 1]}&sz=w2400`, ]); } const [current, setCurrent] = useState(0); const [paused, setPaused] = useState(false); const [progKey, setProgKey] = useState(0); const total = PAIRS.length; const autoRef = useRef(null); const resumeRef = useRef(null); const goTo = useCallback((idx) => { setCurrent(((idx % total) + total) % total); setProgKey(k => k + 1); }, [total]); const goNext = useCallback(() => goTo(current + 1), [goTo, current]); const goPrev = useCallback(() => goTo(current - 1), [goTo, current]); const manual = useCallback((fn) => { setPaused(true); clearTimeout(resumeRef.current); fn(); resumeRef.current = setTimeout(() => setPaused(false), 4000); }, []); // Auto-avance 3s useEffect(() => { if (paused) { clearInterval(autoRef.current); return; } autoRef.current = setInterval(() => { setCurrent(c => (c + 1) % total); setProgKey(k => k + 1); }, 3000); return () => clearInterval(autoRef.current); }, [paused, total]); // Clavier ← → useEffect(() => { const onKey = (e) => { if (e.key === 'ArrowLeft') manual(goPrev); if (e.key === 'ArrowRight') manual(goNext); }; window.addEventListener('keydown', onKey); return () => window.removeEventListener('keydown', onKey); }, [manual, goPrev, goNext]); const [leftUrl, rightUrl] = PAIRS[current]; return (
setPaused(true)} onMouseLeave={() => setPaused(false)} > {/* Paire courante — fade in à chaque changement */}
Nektar
Nektar
{/* Flèche gauche */} {/* Flèche droite */} {/* Barre de progression */}
); } /* ------------------------------------------------------- App ------------------------------------------------------- */ function App() { const [t, setTweak] = useTweaks(TWEAK_DEFAULTS); const isEditorial = t.mode === "éditorial"; return (
{/* Mode éditorial — desktop uniquement */} {isEditorial && (
)} {/* Mode défilement — toujours sur mobile, optionnel sur desktop */}
setTweak("mode", v)} />
); } ReactDOM.createRoot(document.getElementById('root')).render();