// 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}
>
);
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render();