feat(Navbar): active section highlight via IntersectionObserver
This commit is contained in:
@@ -33,8 +33,13 @@ const navLinks = [
|
||||
{ label: "Shop", href: "/shop" },
|
||||
];
|
||||
|
||||
const anchorIds = navLinks
|
||||
.filter((l) => l.href.startsWith("#"))
|
||||
.map((l) => l.href.slice(1));
|
||||
|
||||
export function Navbar() {
|
||||
const [scrolled, setScrolled] = useState(false);
|
||||
const [activeSection, setActiveSection] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
const onScroll = () => setScrolled(window.scrollY > 8);
|
||||
@@ -42,6 +47,33 @@ export function Navbar() {
|
||||
return () => window.removeEventListener("scroll", onScroll);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const visible = new Set<string>();
|
||||
|
||||
const updateActive = () => {
|
||||
for (const id of anchorIds) {
|
||||
if (visible.has(id)) { setActiveSection(id); return; }
|
||||
}
|
||||
setActiveSection("");
|
||||
};
|
||||
|
||||
const observers = anchorIds.map((id) => {
|
||||
const el = document.getElementById(id);
|
||||
if (!el) return null;
|
||||
const obs = new IntersectionObserver(
|
||||
([entry]) => {
|
||||
entry.isIntersecting ? visible.add(id) : visible.delete(id);
|
||||
updateActive();
|
||||
},
|
||||
{ rootMargin: "-100px 0px -50% 0px" }
|
||||
);
|
||||
obs.observe(el);
|
||||
return obs;
|
||||
});
|
||||
|
||||
return () => observers.forEach((o) => o?.disconnect());
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<header
|
||||
className={`sticky top-0 z-50 w-full h-[6.25rem] flex items-center px-[2rem] transition-[background-color,backdrop-filter] duration-300 ${
|
||||
@@ -87,7 +119,11 @@ export function Navbar() {
|
||||
}
|
||||
history.replaceState(null, "", link.href);
|
||||
}}
|
||||
className="text-[1.125rem] font-semibold text-[#222221] tracking-[0.01125rem] hover:text-[#f6a701] transition-colors cursor-pointer"
|
||||
className={`text-[1.125rem] font-semibold tracking-[0.01125rem] transition-colors cursor-pointer ${
|
||||
activeSection === link.href.slice(1)
|
||||
? "text-[#f6a701]"
|
||||
: "text-[#222221] hover:text-[#f6a701]"
|
||||
}`}
|
||||
>
|
||||
{link.label}
|
||||
</a>
|
||||
|
||||
Reference in New Issue
Block a user