import { useEffect, useState } from 'react'; import { useLocation, useNavigate } from 'react-router'; import { DocContent } from '@/components/DocContent'; import { PanelProvider, usePanelContent } from '@/components/docs/panel-context'; import { Footer } from '@/components/Footer'; import { Menu } from '@/components/icons'; import { LanguageSwitcher } from '@/components/LanguageSwitcher'; import { PageLinks } from '@/components/PageLinks'; import { SearchSlot } from '@/components/Search'; import { SideNav } from '@/components/SideNav'; import { Button } from '@/components/ui/button'; import { Sheet, SheetContent, SheetTitle, SheetTrigger } from '@/components/ui/sheet'; import { VersionSwitcher } from '@/components/VersionSwitcher'; import { renderInlineMarkdown } from '@/lib/inline-markdown'; import { getOperation, operationSections } from '@/lib/openapi'; import { docsHomeUrl, getScopeByPathname } from '@/lib/site-config'; import type { DocModule, NormalizedDocsPage, SiteModel, TocEntry } from '@/lib/types'; /** * 404 view driven by the `errors.404` config key. The standard defaults to * redirecting home; that happens after hydration rather than during render, * because the prerendered 404.html must stay a static page for hosts that * serve it for every unknown path. */ function NotFound({ site }: { site: SiteModel }) { const navigate = useNavigate(); const { redirect, title, description } = site.error404; useEffect(() => { if (redirect) { navigate(docsHomeUrl, { replace: true }); } }, [redirect, navigate]); return (

{title || site.labels.notFound}

{description &&

{renderInlineMarkdown(description)}

}
); } export interface DocsProps { page: NormalizedDocsPage | null; doc: DocModule | null; site: SiteModel; } export function Docs({ page, doc, site }: DocsProps) { if (!page || !doc) { return (
); } // API reference pages append their generated section anchors to the TOC. const operation = getOperation(doc.frontmatter?.openapi); const toc = operation ? [...(doc.toc || []), ...operationSections(operation)] : doc.toc; return ( ); } function DocsBody({ page, doc, site, toc, }: { page: NormalizedDocsPage; doc: DocModule; site: SiteModel; toc: TocEntry[] | undefined; }) { const { pathname } = useLocation(); const [menuOpen, setMenuOpen] = useState(false); // Navigation follows the scope (version/language) that owns the current page. const scopeDocs = getScopeByPathname(pathname).docs; const { tabs, navigation } = scopeDocs; // A in the page replaces the table of contents in the right rail. const panel = usePanelContent(); // Close the mobile menu and start each newly loaded page at the top. Hash // links keep their native section-scrolling behavior. // biome-ignore lint/correctness/useExhaustiveDependencies: pathname is the trigger useEffect(() => { setMenuOpen(false); if (!window.location.hash) { window.scrollTo({ top: 0, left: 0 }); } }, [pathname]); return (
}> {site.labels.menu}
{site.labels.documentationNavigation}
{panel ?? ( )}
); }