import { Link, useLocation } from "@tanstack/react-router"; import { ChevronDown, ChevronRight } from "lucide-react"; import { useCallback, useEffect, useMemo, useState } from "react"; import { type DocsNavNode } from "~/docs"; interface DocsNavProps { nodes: DocsNavNode[]; mobile?: boolean; onNavigate?: () => void; } const ACTIVE_OPTIONS_EXACT = { exact: true }; function nodeContainsHref(node: DocsNavNode, href: string): boolean { if (node.type === "page") return node.href === href; return node.children.some((child) => nodeContainsHref(child, href)); } function clsx(...classes: (string | false | null | undefined)[]): string { return classes.filter(Boolean).join(" "); } function PageLink({ node, mobile, onNavigate, }: { node: Extract; mobile?: boolean; onNavigate?: () => void; }) { const location = useLocation(); const isActive = location.pathname === node.href; return ( {node.label} ); } function GroupNode({ node, mobile, onNavigate, }: { node: Extract; mobile?: boolean; onNavigate?: () => void; }) { const location = useLocation(); const currentHref = location.pathname; const containsActive = useMemo(() => nodeContainsHref(node, currentHref), [node, currentHref]); const [isOpen, setIsOpen] = useState(containsActive); const toggle = useCallback(() => setIsOpen((open) => !open), []); useEffect(() => { setIsOpen(containsActive); }, [containsActive]); return (
{isOpen && (
)}
); } function CategoryNode({ node, mobile, onNavigate, }: { node: Extract; mobile?: boolean; onNavigate?: () => void; }) { return (
{node.label}
); } function NavTree({ nodes, mobile, onNavigate }: DocsNavProps) { return (
{nodes.map((node) => { if (node.type === "category") { return ( ); } if (node.type === "group") { return ( ); } return ( ); })}
); } export function DocsNav({ nodes, mobile, onNavigate }: DocsNavProps) { return (
); }