2bd18771dc
New standalone app at docs-site/ — Fumadocs (fumadocs-core/ui 16, fumadocs-mdx
15) on TanStack Start (Vite 7 + nitro-v2 bun preset, React 19, Tailwind 4),
mirroring the web/ console stack but with no auth/i18n/orval — docs stay public.
- catch-all docs route (routes/docs/$.tsx), Orama search (routes/api/search.ts),
RootProvider shell, MDX component map, shared nav, custom 404
- content/docs/: hand-written index.mdx + meta.json nav, plus 7 pages imported
from repo docs/ + README (leading H1 stripped, YAML frontmatter added; kept as
.md so existing </{ don't trip MDX JSX). Content is a one-time snapshot.
- mdx() is plugins[0]; tsconfig collections/* -> ./.source/*; SSR search variant;
@source for fumadocs-ui classes. Generated .source/routeTree/dist/.output ignored.
Verified: bun run build (client+SSR+nitro) green, tsc clean, dev + prod servers
serve all routes 200 with SSR content + nav, search returns hits, 404 works.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
59 lines
1.8 KiB
TypeScript
59 lines
1.8 KiB
TypeScript
import { createFileRoute, notFound } from '@tanstack/react-router'
|
|
import { DocsLayout } from 'fumadocs-ui/layouts/docs'
|
|
import { createServerFn } from '@tanstack/react-start'
|
|
import { source } from '@/lib/source'
|
|
import browserCollections from 'collections/browser'
|
|
import { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/layouts/docs/page'
|
|
import { baseOptions } from '@/lib/layout.shared'
|
|
import { useFumadocsLoader } from 'fumadocs-core/source/client'
|
|
import { Suspense } from 'react'
|
|
import { useMDXComponents } from '@/components/mdx'
|
|
|
|
export const Route = createFileRoute('/docs/$')({
|
|
component: Page,
|
|
loader: async ({ params }) => {
|
|
const slugs = params._splat?.split('/') ?? []
|
|
const data = await serverLoader({ data: slugs })
|
|
await clientLoader.preload(data.path)
|
|
return data
|
|
},
|
|
})
|
|
|
|
const serverLoader = createServerFn({
|
|
method: 'GET',
|
|
})
|
|
.validator((slugs: string[]) => slugs)
|
|
.handler(async ({ data: slugs }) => {
|
|
const page = source.getPage(slugs)
|
|
if (!page) throw notFound()
|
|
|
|
return {
|
|
path: page.path,
|
|
pageTree: await source.serializePageTree(source.getPageTree()),
|
|
}
|
|
})
|
|
|
|
const clientLoader = browserCollections.docs.createClientLoader({
|
|
component({ toc, frontmatter, default: MDX }, _props: undefined) {
|
|
return (
|
|
<DocsPage toc={toc}>
|
|
<DocsTitle>{frontmatter.title}</DocsTitle>
|
|
<DocsDescription>{frontmatter.description}</DocsDescription>
|
|
<DocsBody>
|
|
<MDX components={useMDXComponents()} />
|
|
</DocsBody>
|
|
</DocsPage>
|
|
)
|
|
},
|
|
})
|
|
|
|
function Page() {
|
|
const data = useFumadocsLoader(Route.useLoaderData())
|
|
|
|
return (
|
|
<DocsLayout {...baseOptions()} tree={data.pageTree}>
|
|
<Suspense>{clientLoader.useContent(data.path)}</Suspense>
|
|
</DocsLayout>
|
|
)
|
|
}
|