// app.jsx — Router + scroll/header logic function useHashRoute() { const [route, setRoute] = React.useState(() => window.location.hash.replace(/^#/, '') || '/'); React.useEffect(() => { const onHash = () => setRoute(window.location.hash.replace(/^#/, '') || '/'); window.addEventListener('hashchange', onHash); return () => window.removeEventListener('hashchange', onHash); }, []); const navigate = React.useCallback((path, hash) => { const target = '#' + path + (hash || ''); if (window.location.hash !== target) { window.location.hash = target; } else if (hash) { // same path, ensure we scroll setTimeout(() => { const id = hash.replace(/^#/, ''); document.getElementById(id)?.scrollIntoView({ behavior: 'smooth' }); }, 50); } }, []); return [route, navigate]; } function App() { const [route, navigate] = useHashRoute(); const [menuOpen, setMenuOpen] = React.useState(false); const [onDark, setOnDark] = React.useState(true); // Parse route -> path + hash const [path, hashFragment] = React.useMemo(() => { const idx = route.indexOf('#'); if (idx >= 0) return [route.slice(0, idx) || '/', route.slice(idx)]; return [route || '/', '']; }, [route]); // Scroll to top on path change; or to anchor if hash React.useEffect(() => { setMenuOpen(false); if (hashFragment) { setTimeout(() => { const id = hashFragment.replace(/^#/, ''); const el = document.getElementById(id); if (el) el.scrollIntoView({ behavior: 'smooth' }); else window.scrollTo(0, 0); }, 80); } else { window.scrollTo(0, 0); } }, [path, hashFragment]); // Header dark/light: dark while hero is in view (homepage only) React.useEffect(() => { const isHomepage = path === '/' || path === ''; if (!isHomepage) { // page-hero is dark on detail pages, then light const pageHero = document.querySelector('.page-hero'); if (pageHero) { const obs = new IntersectionObserver((entries) => { entries.forEach(e => setOnDark(e.isIntersecting && e.intersectionRatio > 0.3)); }, { threshold: [0, 0.3, 0.6, 1] }); obs.observe(pageHero); return () => obs.disconnect(); } else { setOnDark(false); return; } } const hero = document.getElementById('hero'); if (!hero) { setOnDark(false); return; } const obs = new IntersectionObserver((entries) => { entries.forEach(e => setOnDark(e.intersectionRatio > 0.3)); }, { threshold: [0, 0.3, 0.6, 1] }); obs.observe(hero); return () => obs.disconnect(); }, [path]); // Route -> view let view; if (path === '/' || path === '') view = ; else if (path === '/kinesiologie') view = ; else if (path === '/reiki') view = ; else if (path === '/agenda') view = ; else if (path === '/cercles-de-femmes' || path === '/cercles') view = ; else if (path === '/journal') view = ; else if (path.startsWith('/journal/')) view = ; else if (path === '/temoignages') view = ; else if (path === '/contact') view = ; else if (path === '/prendre-rendez-vous') view = ; else if (path === '/mentions-legales') view = ; else if (path === '/confidentialite') view = ; else if (path === '/cgv-annulation' || path === '/conditions-annulation') view = ; else if (path === '/reservation-confirmee') view = ; else view = ; return ( <>
setMenuOpen(true)} navigate={navigate} /> setMenuOpen(false)} navigate={navigate} />
{view}