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>
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
/// <reference types="vite/client" />
|
||||
import { createRootRoute, HeadContent, Outlet, Scripts } from '@tanstack/react-router'
|
||||
import * as React from 'react'
|
||||
import { RootProvider } from 'fumadocs-ui/provider/tanstack'
|
||||
import appCss from '@/styles/app.css?url'
|
||||
|
||||
export const Route = createRootRoute({
|
||||
head: () => ({
|
||||
meta: [
|
||||
{ charSet: 'utf-8' },
|
||||
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
|
||||
{ name: 'color-scheme', content: 'dark light' },
|
||||
{ title: 'punktfunk docs' },
|
||||
],
|
||||
links: [{ rel: 'stylesheet', href: appCss }],
|
||||
}),
|
||||
component: RootComponent,
|
||||
})
|
||||
|
||||
function RootComponent() {
|
||||
return (
|
||||
<RootDocument>
|
||||
<Outlet />
|
||||
</RootDocument>
|
||||
)
|
||||
}
|
||||
|
||||
function RootDocument({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<head>
|
||||
<HeadContent />
|
||||
</head>
|
||||
<body className="flex flex-col min-h-screen">
|
||||
<RootProvider>{children}</RootProvider>
|
||||
<Scripts />
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { createFileRoute } from '@tanstack/react-router'
|
||||
import { source } from '@/lib/source'
|
||||
import { createFromSource } from 'fumadocs-core/search/server'
|
||||
|
||||
const server = createFromSource(source, {
|
||||
// https://docs.orama.com/docs/orama-js/supported-languages
|
||||
language: 'english',
|
||||
})
|
||||
|
||||
export const Route = createFileRoute('/api/search')({
|
||||
server: {
|
||||
handlers: {
|
||||
GET: async ({ request }) => server.GET(request),
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,58 @@
|
||||
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>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import { createFileRoute, Link } from '@tanstack/react-router'
|
||||
import { HomeLayout } from 'fumadocs-ui/layouts/home'
|
||||
import { baseOptions } from '@/lib/layout.shared'
|
||||
|
||||
export const Route = createFileRoute('/')({ component: Home })
|
||||
|
||||
function Home() {
|
||||
return (
|
||||
<HomeLayout {...baseOptions()}>
|
||||
<main className="flex flex-1 flex-col items-center justify-center gap-6 px-4 py-24 text-center">
|
||||
<h1 className="text-4xl font-bold tracking-tight">punktfunk</h1>
|
||||
<p className="max-w-xl text-fd-muted-foreground">
|
||||
A ground-up low-latency desktop and game streaming stack, built Linux-first, with a
|
||||
shared Rust protocol core and native clients per platform.
|
||||
</p>
|
||||
<Link
|
||||
to="/docs/$"
|
||||
params={{ _splat: '' }}
|
||||
className="rounded-lg bg-fd-primary px-5 py-2.5 font-medium text-fd-primary-foreground"
|
||||
>
|
||||
Read the docs
|
||||
</Link>
|
||||
</main>
|
||||
</HomeLayout>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user