'use client' import { type IDocsConfig, useDocsConfig } from '@duck-docs/context' import { scrollIntoViewWithin } from '@duck-docs/lib/scroll-into-view-within' import type { ISidebarNavItem } from '@duck-docs/types/nav' import { cn } from '@gentleduck/libs/cn' import { ChevronRight } from 'lucide-react' import Link from 'next/link' import { usePathname } from 'next/navigation' import * as React from 'react' export interface IDocsSidebarNavProps { config?: IDocsConfig } function getSidebarItemKey(item: ISidebarNavItem) { return item.href ?? `${item.title}-${item.label ?? 'item'}` } function isPathActive(pathname: string, href: string) { return pathname === href || (href !== '/docs' && pathname.startsWith(`${href}/`)) } function isPathCurrent(pathname: string, href: string) { return pathname === href } function hasActivePath(item: ISidebarNavItem, pathname: string | null): boolean { if (!pathname) return false if (item.href && isPathActive(pathname, item.href)) return true return Boolean(item.items?.some((child) => hasActivePath(child, pathname))) } export function DocsSidebarNav({ config }: IDocsSidebarNavProps) { const pathname = usePathname() const fallbackConfig = useDocsConfig() const resolvedConfig = config ?? fallbackConfig const items = pathname?.startsWith('/charts') ? resolvedConfig.chartsNav : resolvedConfig.sidebarNav return items?.length ? (
{items.map((item) => ( ))}
) : null } function SidebarItem({ item, pathname, depth = 0, }: { item: ISidebarNavItem pathname: string | null depth?: number }) { const hasChildren = Boolean(item.items?.length) const isCollapsible = hasChildren && Boolean(item.collapsible) const isCurrent = Boolean(pathname && item.href && isPathCurrent(pathname, item.href)) const isActiveBranch = hasActivePath(item, pathname) const isActive = isCurrent || (hasChildren && isActiveBranch) const [isOpen, setIsOpen] = React.useState(() => Boolean(item.defaultOpen)) const linkRef = React.useRef(null) React.useEffect(() => { if (!isCurrent || !linkRef.current) return scrollIntoViewWithin(linkRef.current, linkRef.current.closest('[class*="overflow"]')) }, [isCurrent]) const toggle = isCollapsible ? ( ) : null const childList = hasChildren ? ( {depth === 0 ? (
    {item.items?.map((child) => ( ))}
) : (
    {item.items?.map((child) => ( ))}
)}
) : null if (depth === 0) { return (
{item.href ? ( {item.title || Section overview} ) : ( {item.title} )}
{item.label && ( {item.label} )} {toggle}
{childList}
) } // Pull the active border out by the parent border width so it sits ON // TOP of the parent border instead of next to it. Depth-1 parent uses // border-l-2; deeper parents use border-l (1px). const activeOverlay = depth === 1 ? '-ml-0.5 border-primary border-l-2' : '-ml-px border-primary border-l' return (
  • {item.href && !item.disabled ? ( 1 && 'px-3', isActive ? 'text-foreground' : 'text-muted-foreground', )} href={item.href} rel={item.external ? 'noreferrer' : ''} scroll target={item.external ? '_blank' : ''}> {item.title} {item.label && ( {item.label} )} {item.external && (opens in a new tab)} ) : ( 1 && 'px-3', )}> {item.title} {item.label && ( {item.label} )} )} {toggle &&
    {toggle}
    }
    {childList}
  • ) } function AnimatedHeightCollapse({ open, children }: { open: boolean; children: React.ReactNode }) { return (
    {children}
    ) } export { SidebarItem as DocsSidebarNavItem } export function DocsSidebarNavItems({ items, pathname, depth = 0, }: { items: ISidebarNavItem[] pathname: string | null className?: string depth?: number accordionDefault?: boolean }) { return items?.length ? ( ) : null }