"use client"; import { useReducedMotion } from "../motion/Preferences.tsx"; import { useEffect, useState, type ReactNode } from "react"; import { AnimatePresence, motion, useScroll, useSpring, useTransform, } from "motion/react"; import { Dialog } from "./Dialog.tsx"; export type NavLink = { href: string; label: string }; export function Nav({ brand, links, currentPath, trackChapters = true, className = "", }: { brand: ReactNode; links: NavLink[]; currentPath?: string; trackChapters?: boolean; className?: string; }) { const reduce = useReducedMotion(); const path = currentPath ?? (typeof window !== "undefined" ? window.location.pathname : ""); const { scrollYProgress } = useScroll(); const scaleX = useSpring(scrollYProgress, { stiffness: 140, damping: 28, mass: 0.4, }); const progress = reduce ? scrollYProgress : scaleX; const nodeLeft = useTransform( progress, (v) => `calc(${(v * 100).toFixed(3)}% - 3px)`, ); const [chapter, setChapter] = useState(""); const [open, setOpen] = useState(false); useEffect(() => { if (!trackChapters) return; const sections = Array.from(document.querySelectorAll("[data-chapter]")); if (sections.length === 0) return; const io = new IntersectionObserver( (entries) => { for (const e of entries) { if (e.isIntersecting) setChapter(e.target.getAttribute("data-chapter") ?? ""); } }, { rootMargin: "-40% 0px -55% 0px" }, ); sections.forEach((s) => io.observe(s)); return () => io.disconnect(); }, [trackChapters]); return ( <>
{brand}
{chapter && ( {chapter} )}
{brand}

Mizu — Interface Archive

); }