Files
apex/client/src/components/SectionNav.jsx
T
lejayandCursor 30921aade6 v2.1
Ship configurator updates with catalog DB included for server deploy.

Co-authored-by: Cursor <[email protected]>
2026-10-07 17:13:03 +02:00

76 lines
2.2 KiB
React

import { useEffect, useRef, useState } from 'react';
import styles from './SectionNav.module.css';
export default function SectionNav({ sections }) {
const [active, setActive] = useState(sections[0]?.id ?? '');
const navRef = useRef(null);
const isClickScrolling = useRef(false);
const clickTimeout = useRef(null);
useEffect(() => {
const els = sections
.map((s) => document.getElementById(s.id))
.filter(Boolean);
if (els.length === 0) return undefined;
const ratios = new Map();
const observer = new IntersectionObserver(
(entries) => {
if (isClickScrolling.current) return;
for (const entry of entries) {
ratios.set(entry.target.id, entry.intersectionRatio);
}
let best = '';
let bestRatio = -1;
for (const [id, ratio] of ratios) {
if (ratio > bestRatio) {
best = id;
bestRatio = ratio;
}
}
if (best && bestRatio > 0) setActive(best);
},
{ threshold: [0, 0.1, 0.25, 0.5, 0.75, 1] }
);
for (const el of els) observer.observe(el);
return () => observer.disconnect();
}, [sections]);
useEffect(() => () => clearTimeout(clickTimeout.current), []);
const handleClick = (id) => {
const el = document.getElementById(id);
if (!el) return;
setActive(id);
isClickScrolling.current = true;
const nav = navRef.current;
const stickyBottom = nav ? nav.getBoundingClientRect().bottom : 0;
const top = el.getBoundingClientRect().top + window.scrollY - stickyBottom - 8;
window.scrollTo({ top, behavior: 'smooth' });
clearTimeout(clickTimeout.current);
clickTimeout.current = setTimeout(() => {
isClickScrolling.current = false;
}, 800);
};
return (
<nav ref={navRef} className={styles.sectionNav}>
<div className={styles.inner}>
{sections.map((s) => (
<button
key={s.id}
type="button"
onClick={() => handleClick(s.id)}
className={`${styles.item} ${active === s.id ? styles.itemActive : ''}`}
>
{s.label}
</button>
))}
</div>
</nav>
);
}