"use client"; import { Button } from "@/components/docs/Button"; import { useIsInsideMobileNavigation } from "@/components/docs/MobileNavigation"; import { useSectionStore } from "@/components/docs/SectionProvider"; import { Tag } from "@/components/docs/Tag"; import { remToPx } from "@/lib/remToPx"; import clsx from "clsx"; import { AnimatePresence, motion, useIsPresent } from "framer-motion"; import Link from "next/link"; import { usePathname } from "next/navigation"; import { useRef } from "react"; interface NavGroup { title: string; links: Array<{ title: string; href: string; }>; } function useInitialValue(value: T, condition = true) { const initialValue = useRef(value).current; return condition ? initialValue : value; } function TopLevelNavItem({ href, children, }: { href: string; children: React.ReactNode; }) { return (
  • {children}
  • ); } function NavLink({ href, children, tag, active = false, isAnchorLink = false, }: { href: string; children: React.ReactNode; tag?: string; active?: boolean; isAnchorLink?: boolean; }) { return ( {children} {tag && ( {tag} )} ); } function VisibleSectionHighlight({ group, pathname, }: { group: NavGroup; pathname: string; }) { const [sections, visibleSections] = useInitialValue( [ useSectionStore((s) => s.sections), useSectionStore((s) => s.visibleSections), ], useIsInsideMobileNavigation() ); const isPresent = useIsPresent(); const firstVisibleSectionIndex = Math.max( 0, [{ id: "_top" }, ...sections].findIndex( (section) => section.id === visibleSections[0] ) ); const itemHeight = remToPx(2); const height = isPresent ? Math.max(1, visibleSections.length) * itemHeight : itemHeight; const top = group.links.findIndex((link) => link.href === pathname) * itemHeight + firstVisibleSectionIndex * itemHeight; return ( ); } function ActivePageMarker({ group, pathname, }: { group: NavGroup; pathname: string; }) { const itemHeight = remToPx(2); const offset = remToPx(0.25); const activePageIndex = group.links.findIndex( (link) => link.href === pathname ); const top = offset + activePageIndex * itemHeight; return ( ); } function NavigationGroup({ group, className, }: { group: NavGroup; className?: string; }) { // If this is the mobile navigation then we always render the initial // state, so that the state does not change during the close animation. // The state will still update when we re-open (re-render) the navigation. const isInsideMobileNavigation = useIsInsideMobileNavigation(); const [pathname, sections] = useInitialValue( [usePathname(), useSectionStore((s) => s.sections)], isInsideMobileNavigation ); const isActiveGroup = group.links.findIndex((link) => link.href === pathname) !== -1; return (
  • {group.title}
    {isActiveGroup && ( )} {isActiveGroup && ( )}
      {group.links.map((link) => ( {link.title} {link.href === pathname && sections.length > 0 && ( {sections.map((section) => (
    • {section.title}
    • ))}
      )}
      ))}
  • ); } export const navigation: Array = [ { title: "Guides", links: [ { title: "Introduction", href: "/docs" }, { title: "Installation", href: "/docs/install" }, ], }, ]; export function Navigation(props: React.ComponentPropsWithoutRef<"nav">) { return ( ); }