Initial deploy
هذا الالتزام موجود في:
83
components/nav-links.tsx
Normal file
83
components/nav-links.tsx
Normal file
@@ -0,0 +1,83 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
type NavItem = {
|
||||
label: string;
|
||||
href: string;
|
||||
};
|
||||
|
||||
type NavLinksProps = {
|
||||
items: NavItem[];
|
||||
alignEnd: boolean;
|
||||
};
|
||||
|
||||
function getHashId(href: string) {
|
||||
return href.split("#")[1] ?? "";
|
||||
}
|
||||
|
||||
export function NavLinks({ items, alignEnd }: NavLinksProps) {
|
||||
const [activeId, setActiveId] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
const sectionIds = items.map((item) => getHashId(item.href)).filter(Boolean);
|
||||
const sections = sectionIds
|
||||
.map((id) => document.getElementById(id))
|
||||
.filter((section): section is HTMLElement => Boolean(section));
|
||||
|
||||
if (sections.length === 0) {
|
||||
setActiveId("");
|
||||
return;
|
||||
}
|
||||
|
||||
function syncFromHash() {
|
||||
const nextId = window.location.hash.replace("#", "");
|
||||
if (sectionIds.includes(nextId)) {
|
||||
setActiveId(nextId);
|
||||
}
|
||||
}
|
||||
|
||||
syncFromHash();
|
||||
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
const visible = entries
|
||||
.filter((entry) => entry.isIntersecting)
|
||||
.sort((a, b) => b.intersectionRatio - a.intersectionRatio)[0];
|
||||
|
||||
if (visible?.target.id) {
|
||||
setActiveId(visible.target.id);
|
||||
}
|
||||
},
|
||||
{ rootMargin: "-28% 0px -58% 0px", threshold: [0.12, 0.24, 0.36] }
|
||||
);
|
||||
|
||||
sections.forEach((section) => observer.observe(section));
|
||||
window.addEventListener("hashchange", syncFromHash);
|
||||
|
||||
return () => {
|
||||
observer.disconnect();
|
||||
window.removeEventListener("hashchange", syncFromHash);
|
||||
};
|
||||
}, [items]);
|
||||
|
||||
return (
|
||||
<nav aria-label="Primary" className="nav-scroll">
|
||||
<ul className={`nav-list ${alignEnd ? "md:justify-end" : "md:justify-start"}`}>
|
||||
{items.map((item) => {
|
||||
const itemId = getHashId(item.href);
|
||||
const isActive = activeId === itemId;
|
||||
|
||||
return (
|
||||
<li key={item.href}>
|
||||
<Link href={item.href} className="nav-link-pill" data-active={isActive || undefined}>
|
||||
{item.label}
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
المرجع في مشكلة جديدة
حظر مستخدم