From c792c62c86e4d9f4de8402610bb63000cd79bc3a Mon Sep 17 00:00:00 2001 From: NtskwK Date: Wed, 21 Jan 2026 11:03:03 +0800 Subject: feat(docs): add React Router docs with Fumadocs --- packages/docs/app/app.css | 3 ++ packages/docs/app/docs/page.tsx | 51 +++++++++++++++++++++++ packages/docs/app/docs/search.ts | 12 ++++++ packages/docs/app/lib/layout.shared.tsx | 9 ++++ packages/docs/app/lib/source.ts | 7 ++++ packages/docs/app/root.tsx | 73 +++++++++++++++++++++++++++++++++ packages/docs/app/routes.ts | 7 ++++ packages/docs/app/routes/home.tsx | 30 ++++++++++++++ 8 files changed, 192 insertions(+) create mode 100644 packages/docs/app/app.css create mode 100644 packages/docs/app/docs/page.tsx create mode 100644 packages/docs/app/docs/search.ts create mode 100644 packages/docs/app/lib/layout.shared.tsx create mode 100644 packages/docs/app/lib/source.ts create mode 100644 packages/docs/app/root.tsx create mode 100644 packages/docs/app/routes.ts create mode 100644 packages/docs/app/routes/home.tsx (limited to 'packages/docs/app') diff --git a/packages/docs/app/app.css b/packages/docs/app/app.css new file mode 100644 index 0000000..50b3bc2 --- /dev/null +++ b/packages/docs/app/app.css @@ -0,0 +1,3 @@ +@import 'tailwindcss'; +@import 'fumadocs-ui/css/neutral.css'; +@import 'fumadocs-ui/css/preset.css'; diff --git a/packages/docs/app/docs/page.tsx b/packages/docs/app/docs/page.tsx new file mode 100644 index 0000000..2618989 --- /dev/null +++ b/packages/docs/app/docs/page.tsx @@ -0,0 +1,51 @@ +import type { Route } from './+types/page'; +import { DocsLayout } from 'fumadocs-ui/layouts/docs'; +import { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/layouts/docs/page'; +import { source } from '@/lib/source'; +import defaultMdxComponents from 'fumadocs-ui/mdx'; +import browserCollections from 'fumadocs-mdx:collections/browser'; +import { baseOptions } from '@/lib/layout.shared'; +import { useFumadocsLoader } from 'fumadocs-core/source/client'; + +export async function loader({ params }: Route.LoaderArgs) { + const slugs = params['*'].split('/').filter((v) => v.length > 0); + const page = source.getPage(slugs); + if (!page) throw new Response('Not found', { status: 404 }); + + return { + path: page.path, + pageTree: await source.serializePageTree(source.getPageTree()), + }; +} + +const clientLoader = browserCollections.docs.createClientLoader({ + component( + { toc, frontmatter, default: Mdx }, + // you can define props for the `` component + props?: { + className?: string; + }, + ) { + return ( + + {frontmatter.title} + + {frontmatter.title} + {frontmatter.description} + + + + + ); + }, +}); + +export default function Page({ loaderData }: Route.ComponentProps) { + const { path, pageTree } = useFumadocsLoader(loaderData); + + return ( + + {clientLoader.useContent(path)} + + ); +} diff --git a/packages/docs/app/docs/search.ts b/packages/docs/app/docs/search.ts new file mode 100644 index 0000000..9603c72 --- /dev/null +++ b/packages/docs/app/docs/search.ts @@ -0,0 +1,12 @@ +import type { Route } from './+types/search'; +import { createFromSource } from 'fumadocs-core/search/server'; +import { source } from '@/lib/source'; + +const server = createFromSource(source, { + // https://docs.orama.com/docs/orama-js/supported-languages + language: 'english', +}); + +export async function loader({ request }: Route.LoaderArgs) { + return server.GET(request); +} diff --git a/packages/docs/app/lib/layout.shared.tsx b/packages/docs/app/lib/layout.shared.tsx new file mode 100644 index 0000000..af2b6f0 --- /dev/null +++ b/packages/docs/app/lib/layout.shared.tsx @@ -0,0 +1,9 @@ +import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared'; + +export function baseOptions(): BaseLayoutProps { + return { + nav: { + title: 'React Router', + }, + }; +} diff --git a/packages/docs/app/lib/source.ts b/packages/docs/app/lib/source.ts new file mode 100644 index 0000000..97cf767 --- /dev/null +++ b/packages/docs/app/lib/source.ts @@ -0,0 +1,7 @@ +import { loader } from 'fumadocs-core/source'; +import { docs } from 'fumadocs-mdx:collections/server'; + +export const source = loader({ + source: docs.toFumadocsSource(), + baseUrl: '/docs', +}); diff --git a/packages/docs/app/root.tsx b/packages/docs/app/root.tsx new file mode 100644 index 0000000..08b8aa8 --- /dev/null +++ b/packages/docs/app/root.tsx @@ -0,0 +1,73 @@ +import { + isRouteErrorResponse, + Links, + Meta, + Outlet, + Scripts, + ScrollRestoration, +} from 'react-router'; +import { RootProvider } from 'fumadocs-ui/provider/react-router'; +import type { Route } from './+types/root'; +import './app.css'; + +export const links: Route.LinksFunction = () => [ + { rel: 'preconnect', href: 'https://fonts.googleapis.com' }, + { + rel: 'preconnect', + href: 'https://fonts.gstatic.com', + crossOrigin: 'anonymous', + }, + { + rel: 'stylesheet', + href: 'https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap', + }, +]; + +export function Layout({ children }: { children: React.ReactNode }) { + return ( + + + + + + + + + {children} + + + + + ); +} + +export default function App() { + return ; +} + +export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) { + let message = 'Oops!'; + let details = 'An unexpected error occurred.'; + let stack: string | undefined; + + if (isRouteErrorResponse(error)) { + message = error.status === 404 ? '404' : 'Error'; + details = + error.status === 404 ? 'The requested page could not be found.' : error.statusText || details; + } else if (import.meta.env.DEV && error && error instanceof Error) { + details = error.message; + stack = error.stack; + } + + return ( +
+

{message}

+

{details}

+ {stack && ( +
+          {stack}
+        
+ )} +
+ ); +} diff --git a/packages/docs/app/routes.ts b/packages/docs/app/routes.ts new file mode 100644 index 0000000..60dd630 --- /dev/null +++ b/packages/docs/app/routes.ts @@ -0,0 +1,7 @@ +import { index, route, type RouteConfig } from '@react-router/dev/routes'; + +export default [ + index('routes/home.tsx'), + route('docs/*', 'docs/page.tsx'), + route('api/search', 'docs/search.ts'), +] satisfies RouteConfig; diff --git a/packages/docs/app/routes/home.tsx b/packages/docs/app/routes/home.tsx new file mode 100644 index 0000000..7f03ba9 --- /dev/null +++ b/packages/docs/app/routes/home.tsx @@ -0,0 +1,30 @@ +import type { Route } from './+types/home'; +import { HomeLayout } from 'fumadocs-ui/layouts/home'; +import { Link } from 'react-router'; +import { baseOptions } from '@/lib/layout.shared'; + +export function meta({}: Route.MetaArgs) { + return [ + { title: 'New React Router App' }, + { name: 'description', content: 'Welcome to React Router!' }, + ]; +} + +export default function Home() { + return ( + +
+

Fumadocs on React Router.

+

+ The truly flexible docs framework on React.js. +

+ + Open Docs + +
+
+ ); +} -- cgit v1.2.3-70-g09d2