import type * as PageTree from 'fumadocs-core/page-tree'; import { TreeContextProvider } from 'fumadocs-ui/contexts/tree'; import { SidebarProvider } from 'fumadocs-ui/components/sidebar/base'; import { ArrowRight, Pencil } from 'lucide-react'; import { config } from 'virtual:seemore/config'; import type { RouteEntry } from '../../shared/types.js'; import { usePageModule } from '../lib/pages.js'; import { useRouteUrl } from '../router.js'; import { feature } from '../lib/features.js'; import { pruneTree, usePageTree } from '../lib/tree.js'; import { mdxComponents } from '../mdx/components.js'; import { usePrefetch } from '../features/prefetch.js'; import { PagePreview } from '../features/preview.js'; import { useSearchHighlight } from '../features/highlight.js'; import { useHashScroll } from '../features/anchors.js'; import { InlineEditor } from '../features/edit.js'; import { SeemoreProvider } from './Provider.js'; import { useExternalLinkBridge } from './ExternalLinkBridge.js'; import { Header } from './Header.js'; import { Sidebar } from './Sidebar.js'; import { Breadcrumb } from './Breadcrumb.js'; import { PageActions } from './PageActions.js'; import { BackToTop, PageFooter, SiteFooter } from './Footer.js'; import { SelectionCopyButton } from './SelectionCopyButton.js'; import { IntegratedToc, Toc, TocProvider } from './Toc.js'; /** * The shell seemore owns. fumadocs-ui supplies the primitives — sidebar, * TOC, search dialog, MDX components — and one layout, tuned by feature flags, arranges them. */ export function DocsLayout({ children }: { children: React.ReactNode }) { const tree = usePageTree(); useExternalLinkBridge(); return ( {children} ); } export function DocPage({ entry }: { entry: RouteEntry }) { const full = usePageTree(); const url = useRouteUrl(); const tree = feature('navigation.prune') ? pruneTree(full, url) : full; // `use()` on the cached module promise, inside the hook: already-loaded pages render // synchronously, which is what makes `renderToString` emit a complete page. const page = usePageModule(entry); const Content = page.default; usePrefetch(); useSearchHighlight(); useHashScroll(); const integrated = feature('toc.integrate'); // Dev only, and off unless asked for: the editor writes to the user's files, and a static // build has no server to write through. `import.meta.env.DEV` also keeps it out of the bundle. const editable = import.meta.env.DEV && feature('content.edit'); return (
{integrated ? : undefined}
{feature('navigation.path') ? : undefined}
{editable ? : undefined}
{config.editLink !== undefined && feature('content.action.edit') ? ( ) : undefined} {feature('navigation.footer') ? : undefined}
{integrated ? undefined : }
{feature('navigation.top') ? : undefined}
); } export function NotFound() { return (

Page not found

There is no page at this address.

); } /** * A page whose own markup threw — an `.mdx` file reaching for a component seemore does not * provide, most often. `seemore build` refuses to write such a page at all; here, in the dev * server and on client-side navigation, the reason replaces the article, because React * unmounts the whole app when nothing catches the error and a blank screen says nothing. */ export function PageError({ message }: { message: string }) { return (

This page failed to render

              {message}
            
); } /** * The generated index: when no `index.md` or root `README.md` claims `/`, the home address * lists every page instead of apologising. * * Rendered from the same page tree the sidebar reads, so the order — `meta.json`, frontmatter * `order`, then title — is the order a reader would click through. Same shell as a page: * header, sidebar, footer — only the article is generated. */ export function Overview() { const tree = usePageTree(); return (

{config.title}

{config.description !== undefined ?

{config.description}

: undefined}
{feature('navigation.top') ? : undefined}
); } /** Pages render as card grids; a folder opens a titled section holding its own cards. */ type Segment = { pages: PageTree.Item[] } | { folder: PageTree.Folder }; /** h2 at the top level, one step smaller per nesting level, capped at h6. */ const SECTION_HEADING_TAGS = ['h2', 'h3', 'h4', 'h5', 'h6'] as const; function OverviewSections({ nodes, depth = 0 }: { nodes: PageTree.Node[]; depth?: number }) { const segments: Segment[] = []; for (const node of nodes) { if (node.type === 'page') { const last = segments.at(-1); if (last !== undefined && 'pages' in last) last.pages.push(node); else segments.push({ pages: [node] }); } else if (node.type === 'folder') { segments.push({ folder: node }); } } const Heading = SECTION_HEADING_TAGS[Math.min(depth, SECTION_HEADING_TAGS.length - 1)] ?? 'h6'; return ( <> {segments.map((segment, index) => 'pages' in segment ? ( ) : (
{segment.folder.name} {typeof segment.folder.description === 'string' && segment.folder.description !== '' ? (

{segment.folder.description}

) : undefined} {/* A folder stands for its index page when it has one, and lists the rest under it. */}
), )} ); } function OverviewGrid({ pages }: { pages: PageTree.Item[] }) { if (pages.length === 0) return undefined; return (
{pages.map((page) => ( {page.name} {typeof page.description === 'string' && page.description !== '' ? ( {page.description} ) : undefined} ))}
); } function joinUrl(base: string, path: string): string { return `${base.replace(/\/+$/, '')}/${path.replace(/^\/+/, '')}`; }