create-fumadocs-app 16.0.5 → 16.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/bin.js +2 -2
  2. package/dist/{chunk-F7NHHEKG.js → chunk-PGCMK5N3.js} +1 -1
  3. package/dist/{chunk-XPRRZX4H.js → chunk-QKIRNPKF.js} +10 -3
  4. package/dist/index.d.ts +1 -1
  5. package/dist/index.js +2 -2
  6. package/dist/plugins/biome.js +1 -1
  7. package/dist/plugins/eslint.js +1 -1
  8. package/dist/plugins/orama-cloud.js +7 -5
  9. package/package.json +2 -2
  10. package/template/+next+fuma-docs-mdx/package.json +3 -3
  11. package/template/+next+fuma-docs-mdx/tsconfig.json +8 -2
  12. package/template/react-router/package.json +3 -3
  13. package/template/react-router-spa/package.json +4 -4
  14. package/template/tanstack-start/content/docs/index.mdx +1 -1
  15. package/template/tanstack-start/package.json +8 -8
  16. package/template/tanstack-start/src/routes/docs/$.tsx +26 -19
  17. package/template/tanstack-start-spa/README.md +12 -0
  18. package/template/tanstack-start-spa/content/docs/index.mdx +34 -0
  19. package/template/tanstack-start-spa/content/docs/test.mdx +12 -0
  20. package/template/tanstack-start-spa/example.gitignore +19 -0
  21. package/template/tanstack-start-spa/package.json +38 -0
  22. package/template/tanstack-start-spa/source.config.ts +7 -0
  23. package/template/tanstack-start-spa/src/components/not-found.tsx +28 -0
  24. package/template/tanstack-start-spa/src/components/search.tsx +51 -0
  25. package/template/tanstack-start-spa/src/lib/layout.shared.tsx +9 -0
  26. package/template/tanstack-start-spa/src/lib/source.ts +15 -0
  27. package/template/tanstack-start-spa/src/router.tsx +12 -0
  28. package/template/tanstack-start-spa/src/routes/__root.tsx +51 -0
  29. package/template/tanstack-start-spa/src/routes/api/search.ts +16 -0
  30. package/template/tanstack-start-spa/src/routes/docs/$.tsx +109 -0
  31. package/template/tanstack-start-spa/src/routes/index.tsx +24 -0
  32. package/template/tanstack-start-spa/src/styles/app.css +3 -0
  33. package/template/tanstack-start-spa/tsconfig.json +24 -0
  34. package/template/tanstack-start-spa/vite.config.ts +39 -0
  35. package/template/waku/package.json +4 -4
package/dist/bin.js CHANGED
@@ -3,11 +3,11 @@ import {
3
3
  create,
4
4
  getPackageManager,
5
5
  managers
6
- } from "./chunk-F7NHHEKG.js";
6
+ } from "./chunk-PGCMK5N3.js";
7
7
  import {
8
8
  isCI,
9
9
  templates
10
- } from "./chunk-XPRRZX4H.js";
10
+ } from "./chunk-QKIRNPKF.js";
11
11
 
12
12
  // src/bin.ts
13
13
  import fs from "fs/promises";
@@ -4,7 +4,7 @@ import {
4
4
  sourceDir,
5
5
  templates,
6
6
  tryGitInit
7
- } from "./chunk-XPRRZX4H.js";
7
+ } from "./chunk-QKIRNPKF.js";
8
8
 
9
9
  // src/index.ts
10
10
  import path from "path";
@@ -94,14 +94,14 @@ import { fileURLToPath } from "url";
94
94
  // ../create-app-versions/package.json
95
95
  var package_default = {
96
96
  name: "create-fumadocs-versions",
97
- version: "16.0.5",
97
+ version: "16.0.6",
98
98
  private: true,
99
99
  description: "Used to track dependency versions in create-fumadocs-app",
100
100
  dependencies: {
101
- eslint: "^9.38.0",
102
- "@biomejs/biome": "^2.2.6",
101
+ "@biomejs/biome": "^2.3.1",
103
102
  "@eslint/eslintrc": "^3.3.1",
104
103
  "@orama/core": "^1.2.13",
104
+ eslint: "^9.38.0",
105
105
  "fumadocs-core": "workspace:*",
106
106
  "fumadocs-mdx": "workspace:*",
107
107
  "fumadocs-ui": "workspace:*"
@@ -143,6 +143,13 @@ var templates = [
143
143
  label: "Tanstack Start: Fumadocs MDX (not RSC)",
144
144
  appDir: "src",
145
145
  rootProviderPath: "routes/__root.tsx"
146
+ },
147
+ {
148
+ value: "tanstack-start-spa",
149
+ label: "Tanstack Start SPA: Fumadocs MDX (not RSC)",
150
+ hint: "SPA mode allows you to host the site statically, compatible with a CDN.",
151
+ appDir: "src",
152
+ rootProviderPath: "routes/__root.tsx"
146
153
  }
147
154
  ];
148
155
  var depVersions = package_default.dependencies;
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ type PackageManager = (typeof managers)[number];
2
2
  declare const managers: readonly ["npm", "yarn", "bun", "pnpm"];
3
3
 
4
4
  interface TemplateInfo {
5
- value: '+next+fuma-docs-mdx' | 'waku' | 'react-router' | 'react-router-spa' | 'tanstack-start';
5
+ value: '+next+fuma-docs-mdx' | 'waku' | 'react-router' | 'react-router-spa' | 'tanstack-start' | 'tanstack-start-spa';
6
6
  label: string;
7
7
  appDir: string;
8
8
  /**
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  create
3
- } from "./chunk-F7NHHEKG.js";
4
- import "./chunk-XPRRZX4H.js";
3
+ } from "./chunk-PGCMK5N3.js";
4
+ import "./chunk-QKIRNPKF.js";
5
5
  export {
6
6
  create
7
7
  };
@@ -8,7 +8,7 @@ import {
8
8
  depVersions,
9
9
  pick,
10
10
  writeFile
11
- } from "../chunk-XPRRZX4H.js";
11
+ } from "../chunk-QKIRNPKF.js";
12
12
 
13
13
  // src/plugins/biome.ts
14
14
  import path from "path";
@@ -2,7 +2,7 @@ import {
2
2
  depVersions,
3
3
  pick,
4
4
  writeFile
5
- } from "../chunk-XPRRZX4H.js";
5
+ } from "../chunk-QKIRNPKF.js";
6
6
 
7
7
  // src/plugins/eslint.ts
8
8
  import path from "path";
@@ -4,7 +4,7 @@ import {
4
4
  pick,
5
5
  sourceDir,
6
6
  writeFile
7
- } from "../chunk-XPRRZX4H.js";
7
+ } from "../chunk-QKIRNPKF.js";
8
8
 
9
9
  // src/plugins/orama-cloud.ts
10
10
  import path2 from "path";
@@ -148,11 +148,12 @@ async function rootProvider({ appDir, template }, fn) {
148
148
  name: "search",
149
149
  initializer: "{{ SearchDialog }}"
150
150
  });
151
+ file.addImportDeclaration({
152
+ moduleSpecifier: specifier,
153
+ defaultImport: "SearchDialog"
154
+ });
155
+ break;
151
156
  }
152
- file.addImportDeclaration({
153
- moduleSpecifier: specifier,
154
- defaultImport: "SearchDialog"
155
- });
156
157
  }
157
158
  });
158
159
  await file.save();
@@ -286,6 +287,7 @@ See https://fumadocs.dev/docs/headless/search/orama-cloud for integrating Orama
286
287
  const filePath = {
287
288
  "+next+fuma-docs-mdx": ".next/server/app/static.json.body",
288
289
  "tanstack-start": ".output/public/static.json",
290
+ "tanstack-start-spa": "dist/client/static.json",
289
291
  "react-router": "build/client/static.json",
290
292
  "react-router-spa": "build/client/static.json",
291
293
  waku: "dist/public/static.json"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-fumadocs-app",
3
- "version": "16.0.5",
3
+ "version": "16.0.6",
4
4
  "description": "Create a new documentation site with Fumadocs",
5
5
  "keywords": [
6
6
  "react",
@@ -32,7 +32,7 @@
32
32
  "dependencies": {
33
33
  "@clack/prompts": "^0.11.0",
34
34
  "@commander-js/extra-typings": "^14.0.0",
35
- "commander": "^14.0.1",
35
+ "commander": "^14.0.2",
36
36
  "picocolors": "^1.1.1",
37
37
  "tinyexec": "^1.0.1",
38
38
  "ts-morph": "^27.0.2"
@@ -11,19 +11,19 @@
11
11
  "fumadocs-core": "workspace:*",
12
12
  "fumadocs-mdx": "workspace:*",
13
13
  "fumadocs-ui": "workspace:*",
14
- "lucide-react": "^0.546.0",
14
+ "lucide-react": "^0.548.0",
15
15
  "next": "16.0.0",
16
16
  "react": "^19.2.0",
17
17
  "react-dom": "^19.2.0"
18
18
  },
19
19
  "devDependencies": {
20
- "@tailwindcss/postcss": "^4.1.15",
20
+ "@tailwindcss/postcss": "^4.1.16",
21
21
  "@types/mdx": "^2.0.13",
22
22
  "@types/node": "^24.9.1",
23
23
  "@types/react": "^19.2.2",
24
24
  "@types/react-dom": "^19.2.2",
25
25
  "postcss": "^8.5.6",
26
- "tailwindcss": "^4.1.15",
26
+ "tailwindcss": "^4.1.16",
27
27
  "typescript": "^5.9.3"
28
28
  }
29
29
  }
@@ -13,7 +13,7 @@
13
13
  "moduleResolution": "bundler",
14
14
  "resolveJsonModule": true,
15
15
  "isolatedModules": true,
16
- "jsx": "preserve",
16
+ "jsx": "react-jsx",
17
17
  "incremental": true,
18
18
  "paths": {
19
19
  "@/*": ["./*"],
@@ -25,6 +25,12 @@
25
25
  }
26
26
  ]
27
27
  },
28
- "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
28
+ "include": [
29
+ "next-env.d.ts",
30
+ "**/*.ts",
31
+ "**/*.tsx",
32
+ ".next/types/**/*.ts",
33
+ ".next/dev/types/**/*.ts"
34
+ ],
29
35
  "exclude": ["node_modules"]
30
36
  }
@@ -21,15 +21,15 @@
21
21
  },
22
22
  "devDependencies": {
23
23
  "@react-router/dev": "^7.9.4",
24
- "@tailwindcss/vite": "^4.1.15",
24
+ "@tailwindcss/vite": "^4.1.16",
25
25
  "@types/mdx": "^2.0.13",
26
26
  "@types/node": "^24.9.1",
27
27
  "@types/react": "^19.2.2",
28
28
  "@types/react-dom": "^19.2.2",
29
29
  "react-router-devtools": "^5.1.3",
30
- "tailwindcss": "^4.1.15",
30
+ "tailwindcss": "^4.1.16",
31
31
  "typescript": "^5.9.3",
32
- "vite": "^7.1.11",
32
+ "vite": "^7.1.12",
33
33
  "vite-tsconfig-paths": "^5.1.4"
34
34
  }
35
35
  }
@@ -20,17 +20,17 @@
20
20
  "react-router": "^7.9.4"
21
21
  },
22
22
  "devDependencies": {
23
- "serve": "^14.2.5",
24
23
  "@react-router/dev": "^7.9.4",
25
- "@tailwindcss/vite": "^4.1.15",
24
+ "@tailwindcss/vite": "^4.1.16",
26
25
  "@types/mdx": "^2.0.13",
27
26
  "@types/node": "^24.9.1",
28
27
  "@types/react": "^19.2.2",
29
28
  "@types/react-dom": "^19.2.2",
30
29
  "react-router-devtools": "^5.1.3",
31
- "tailwindcss": "^4.1.15",
30
+ "serve": "^14.2.5",
31
+ "tailwindcss": "^4.1.16",
32
32
  "typescript": "^5.9.3",
33
- "vite": "^7.1.11",
33
+ "vite": "^7.1.12",
34
34
  "vite-tsconfig-paths": "^5.1.4"
35
35
  }
36
36
  }
@@ -4,7 +4,7 @@ description: Your favourite docs framework.
4
4
  icon: Rocket
5
5
  ---
6
6
 
7
- Hey there! Fumadocs is a docs framework built for Next.js, but do you know it also works on Tanstack Start?
7
+ Hey there! Fumadocs is the docs framework that also works on Tanstack Start!
8
8
 
9
9
  ## Heading
10
10
 
@@ -9,26 +9,26 @@
9
9
  "start": "node .output/server/index.mjs"
10
10
  },
11
11
  "dependencies": {
12
- "@tanstack/react-router": "^1.133.21",
13
- "@tanstack/react-router-devtools": "^1.133.21",
14
- "@tanstack/react-start": "^1.133.21",
12
+ "@tanstack/react-router": "^1.133.32",
13
+ "@tanstack/react-router-devtools": "^1.133.34",
14
+ "@tanstack/react-start": "^1.133.34",
15
15
  "fumadocs-core": "workspace:*",
16
16
  "fumadocs-mdx": "workspace:*",
17
17
  "fumadocs-ui": "workspace:*",
18
- "lucide-static": "^0.546.0",
18
+ "lucide-static": "^0.548.0",
19
19
  "react": "^19.2.0",
20
20
  "react-dom": "^19.2.0",
21
21
  "tailwind-merge": "^3.3.1",
22
- "vite": "^7.1.11"
22
+ "vite": "^7.1.12"
23
23
  },
24
24
  "devDependencies": {
25
- "@tailwindcss/vite": "^4.1.15",
25
+ "@tailwindcss/vite": "^4.1.16",
26
26
  "@types/mdx": "^2.0.13",
27
27
  "@types/node": "^24.9.1",
28
28
  "@types/react": "^19.2.2",
29
29
  "@types/react-dom": "^19.2.2",
30
- "@vitejs/plugin-react": "^5.0.4",
31
- "tailwindcss": "^4.1.15",
30
+ "@vitejs/plugin-react": "^5.1.0",
31
+ "tailwindcss": "^4.1.16",
32
32
  "typescript": "^5.9.3",
33
33
  "vite-tsconfig-paths": "^5.1.4"
34
34
  }
@@ -73,28 +73,35 @@ function Page() {
73
73
  );
74
74
  }
75
75
 
76
- function transformPageTree(tree: PageTree.Folder): PageTree.Folder {
77
- function transform<T extends PageTree.Item | PageTree.Separator>(item: T) {
78
- if (typeof item.icon !== 'string') return item;
76
+ function transformPageTree(root: PageTree.Root): PageTree.Root {
77
+ function mapNode<T extends PageTree.Node>(item: T): T {
78
+ if (typeof item.icon === 'string') {
79
+ item = {
80
+ ...item,
81
+ icon: (
82
+ <span
83
+ dangerouslySetInnerHTML={{
84
+ __html: item.icon,
85
+ }}
86
+ />
87
+ ),
88
+ };
89
+ }
79
90
 
80
- return {
81
- ...item,
82
- icon: (
83
- <span
84
- dangerouslySetInnerHTML={{
85
- __html: item.icon,
86
- }}
87
- />
88
- ),
89
- };
91
+ if (item.type === 'folder') {
92
+ return {
93
+ ...item,
94
+ index: item.index ? mapNode(item.index) : undefined,
95
+ children: item.children.map(mapNode),
96
+ };
97
+ }
98
+
99
+ return item;
90
100
  }
91
101
 
92
102
  return {
93
- ...tree,
94
- index: tree.index ? transform(tree.index) : undefined,
95
- children: tree.children.map((item) => {
96
- if (item.type === 'folder') return transformPageTree(item);
97
- return transform(item);
98
- }),
103
+ ...root,
104
+ children: root.children.map(mapNode),
105
+ fallback: root.fallback ? transformPageTree(root.fallback) : undefined,
99
106
  };
100
107
  }
@@ -0,0 +1,12 @@
1
+ This is a Tanstack Start application generated with
2
+ [Create Fumadocs](https://github.com/fuma-nama/fumadocs).
3
+
4
+ Run development server:
5
+
6
+ ```bash
7
+ npm run dev
8
+ # or
9
+ pnpm dev
10
+ # or
11
+ yarn dev
12
+ ```
@@ -0,0 +1,34 @@
1
+ ---
2
+ title: Hello World
3
+ description: Your favourite docs framework.
4
+ icon: Rocket
5
+ ---
6
+
7
+ Hey there! Fumadocs is the docs framework that also works on Tanstack Start!
8
+
9
+ ## Heading
10
+
11
+ Hello World!
12
+
13
+ <Cards>
14
+ <Card
15
+ title="Learn more about Tanstack Start"
16
+ href="https://tanstack.com/start"
17
+ />
18
+ <Card title="Learn more about Fumadocs" href="https://fumadocs.dev" />
19
+ </Cards>
20
+
21
+ ### CodeBlock
22
+
23
+ ```ts
24
+ console.log('Hello World');
25
+ ```
26
+
27
+ #### Table
28
+
29
+ | Head | Description |
30
+ | ------------------------------- | ----------------------------------- |
31
+ | `hello` | Hello World |
32
+ | very **important** | Hey |
33
+ | _Surprisingly_ | Fumadocs |
34
+ | very long text that looks weird | hello world hello world hello world |
@@ -0,0 +1,12 @@
1
+ ---
2
+ title: Test
3
+ description: This is another page
4
+ ---
5
+
6
+ Hello World again!
7
+
8
+ ## Installation
9
+
10
+ ```npm
11
+ npm i fumadocs-core fumadocs-ui
12
+ ```
@@ -0,0 +1,19 @@
1
+ node_modules
2
+
3
+ .DS_Store
4
+ .cache
5
+ .vercel
6
+ .output
7
+ .nitro
8
+ /build/
9
+ /api/
10
+ /server/build
11
+ /public/build
12
+ /test-results/
13
+ /playwright-report/
14
+ /blob-report/
15
+ /playwright/.cache/
16
+ .tanstack
17
+
18
+ src/routeTree.gen.ts
19
+ .source
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "example-tanstack-start-spa",
3
+ "private": true,
4
+ "sideEffects": false,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite dev",
8
+ "build": "vite build",
9
+ "start": "serve dist/client"
10
+ },
11
+ "dependencies": {
12
+ "@orama/orama": "^3.1.16",
13
+ "@tanstack/react-router": "^1.133.32",
14
+ "@tanstack/react-router-devtools": "^1.133.34",
15
+ "@tanstack/react-start": "^1.133.34",
16
+ "@tanstack/start-static-server-functions": "^1.133.34",
17
+ "fumadocs-core": "workspace:*",
18
+ "fumadocs-mdx": "workspace:*",
19
+ "fumadocs-ui": "workspace:*",
20
+ "lucide-static": "^0.548.0",
21
+ "react": "^19.2.0",
22
+ "react-dom": "^19.2.0",
23
+ "tailwind-merge": "^3.3.1",
24
+ "vite": "^7.1.12"
25
+ },
26
+ "devDependencies": {
27
+ "@tailwindcss/vite": "^4.1.16",
28
+ "@types/mdx": "^2.0.13",
29
+ "@types/node": "^24.9.1",
30
+ "@types/react": "^19.2.2",
31
+ "@types/react-dom": "^19.2.2",
32
+ "@vitejs/plugin-react": "^5.1.0",
33
+ "serve": "^14.2.5",
34
+ "tailwindcss": "^4.1.16",
35
+ "typescript": "^5.9.3",
36
+ "vite-tsconfig-paths": "^5.1.4"
37
+ }
38
+ }
@@ -0,0 +1,7 @@
1
+ import { defineConfig, defineDocs } from 'fumadocs-mdx/config';
2
+
3
+ export const docs = defineDocs({
4
+ dir: 'content/docs',
5
+ });
6
+
7
+ export default defineConfig();
@@ -0,0 +1,28 @@
1
+ import { Link } from '@tanstack/react-router';
2
+ import { HomeLayout } from 'fumadocs-ui/layouts/home';
3
+
4
+ export function NotFound() {
5
+ return (
6
+ <HomeLayout
7
+ nav={{
8
+ title: 'Tanstack Start',
9
+ }}
10
+ className="text-center py-32 justify-center"
11
+ >
12
+ <div className="flex flex-col items-center gap-4">
13
+ <h1 className="text-6xl font-bold text-fd-muted-foreground">404</h1>
14
+ <h2 className="text-2xl font-semibold">Page Not Found</h2>
15
+ <p className="text-fd-muted-foreground max-w-md">
16
+ The page you are looking for might have been removed, had its name
17
+ changed, or is temporarily unavailable.
18
+ </p>
19
+ <Link
20
+ to="/"
21
+ className="mt-4 px-4 py-2 rounded-lg bg-fd-primary text-fd-primary-foreground font-medium text-sm hover:opacity-90 transition-opacity"
22
+ >
23
+ Back to Home
24
+ </Link>
25
+ </div>
26
+ </HomeLayout>
27
+ );
28
+ }
@@ -0,0 +1,51 @@
1
+ 'use client';
2
+ import {
3
+ SearchDialog,
4
+ SearchDialogClose,
5
+ SearchDialogContent,
6
+ SearchDialogHeader,
7
+ SearchDialogIcon,
8
+ SearchDialogInput,
9
+ SearchDialogList,
10
+ SearchDialogOverlay,
11
+ type SharedProps,
12
+ } from 'fumadocs-ui/components/dialog/search';
13
+ import { useDocsSearch } from 'fumadocs-core/search/client';
14
+ import { create } from '@orama/orama';
15
+ import { useI18n } from 'fumadocs-ui/contexts/i18n';
16
+
17
+ function initOrama() {
18
+ return create({
19
+ schema: { _: 'string' },
20
+ // https://docs.orama.com/docs/orama-js/supported-languages
21
+ language: 'english',
22
+ });
23
+ }
24
+
25
+ export default function DefaultSearchDialog(props: SharedProps) {
26
+ const { locale } = useI18n(); // (optional) for i18n
27
+ const { search, setSearch, query } = useDocsSearch({
28
+ type: 'static',
29
+ initOrama,
30
+ locale,
31
+ });
32
+
33
+ return (
34
+ <SearchDialog
35
+ search={search}
36
+ onSearchChange={setSearch}
37
+ isLoading={query.isLoading}
38
+ {...props}
39
+ >
40
+ <SearchDialogOverlay />
41
+ <SearchDialogContent>
42
+ <SearchDialogHeader>
43
+ <SearchDialogIcon />
44
+ <SearchDialogInput />
45
+ <SearchDialogClose />
46
+ </SearchDialogHeader>
47
+ <SearchDialogList items={query.data !== 'empty' ? query.data : null} />
48
+ </SearchDialogContent>
49
+ </SearchDialog>
50
+ );
51
+ }
@@ -0,0 +1,9 @@
1
+ import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';
2
+
3
+ export function baseOptions(): BaseLayoutProps {
4
+ return {
5
+ nav: {
6
+ title: 'Tanstack Start',
7
+ },
8
+ };
9
+ }
@@ -0,0 +1,15 @@
1
+ import { loader } from 'fumadocs-core/source';
2
+ import * as icons from 'lucide-static';
3
+ import { create, docs } from '@/.source';
4
+
5
+ export const source = loader({
6
+ source: await create.sourceAsync(docs.doc, docs.meta),
7
+ baseUrl: '/docs',
8
+ icon(icon) {
9
+ if (!icon) {
10
+ return;
11
+ }
12
+
13
+ if (icon in icons) return icons[icon as keyof typeof icons];
14
+ },
15
+ });
@@ -0,0 +1,12 @@
1
+ import { createRouter as createTanStackRouter } from '@tanstack/react-router';
2
+ import { routeTree } from './routeTree.gen';
3
+ import { NotFound } from '@/components/not-found';
4
+
5
+ export function getRouter() {
6
+ return createTanStackRouter({
7
+ routeTree,
8
+ defaultPreload: 'intent',
9
+ scrollRestoration: true,
10
+ defaultNotFoundComponent: NotFound,
11
+ });
12
+ }
@@ -0,0 +1,51 @@
1
+ import {
2
+ createRootRoute,
3
+ HeadContent,
4
+ Outlet,
5
+ Scripts,
6
+ } from '@tanstack/react-router';
7
+ import * as React from 'react';
8
+ import appCss from '@/styles/app.css?url';
9
+ import { RootProvider } from 'fumadocs-ui/provider/tanstack';
10
+ import SearchDialog from '@/components/search';
11
+
12
+ export const Route = createRootRoute({
13
+ head: () => ({
14
+ meta: [
15
+ {
16
+ charSet: 'utf-8',
17
+ },
18
+ {
19
+ name: 'viewport',
20
+ content: 'width=device-width, initial-scale=1',
21
+ },
22
+ {
23
+ title: 'Fumadocs on TanStack Start',
24
+ },
25
+ ],
26
+ links: [{ rel: 'stylesheet', href: appCss }],
27
+ }),
28
+ component: RootComponent,
29
+ });
30
+
31
+ function RootComponent() {
32
+ return (
33
+ <RootDocument>
34
+ <Outlet />
35
+ </RootDocument>
36
+ );
37
+ }
38
+
39
+ function RootDocument({ children }: { children: React.ReactNode }) {
40
+ return (
41
+ <html suppressHydrationWarning>
42
+ <head>
43
+ <HeadContent />
44
+ </head>
45
+ <body className="flex flex-col min-h-screen">
46
+ <RootProvider search={{ SearchDialog }}>{children}</RootProvider>
47
+ <Scripts />
48
+ </body>
49
+ </html>
50
+ );
51
+ }
@@ -0,0 +1,16 @@
1
+ import { createFileRoute } from '@tanstack/react-router';
2
+ import { source } from '@/lib/source';
3
+ import { createFromSource } from 'fumadocs-core/search/server';
4
+
5
+ const server = createFromSource(source, {
6
+ // https://docs.orama.com/docs/orama-js/supported-languages
7
+ language: 'english',
8
+ });
9
+
10
+ export const Route = createFileRoute('/api/search')({
11
+ server: {
12
+ handlers: {
13
+ GET: () => server.staticGET(),
14
+ },
15
+ },
16
+ });
@@ -0,0 +1,109 @@
1
+ import { createFileRoute, notFound } from '@tanstack/react-router';
2
+ import { DocsLayout } from 'fumadocs-ui/layouts/docs';
3
+ import { createServerFn } from '@tanstack/react-start';
4
+ import { source } from '@/lib/source';
5
+ import type * as PageTree from 'fumadocs-core/page-tree';
6
+ import { useMemo } from 'react';
7
+ import { docs } from '@/.source';
8
+ import {
9
+ DocsBody,
10
+ DocsDescription,
11
+ DocsPage,
12
+ DocsTitle,
13
+ } from 'fumadocs-ui/page';
14
+ import defaultMdxComponents from 'fumadocs-ui/mdx';
15
+ import { createClientLoader } from 'fumadocs-mdx/runtime/vite';
16
+ import { baseOptions } from '@/lib/layout.shared';
17
+ import { staticFunctionMiddleware } from '@tanstack/start-static-server-functions';
18
+
19
+ export const Route = createFileRoute('/docs/$')({
20
+ component: Page,
21
+ loader: async ({ params }) => {
22
+ const slugs = params._splat?.split('/') ?? [];
23
+ const data = await loader({ data: slugs });
24
+ await clientLoader.preload(data.path);
25
+ return data;
26
+ },
27
+ });
28
+
29
+ const loader = createServerFn({
30
+ method: 'GET',
31
+ })
32
+ .inputValidator((slugs: string[]) => slugs)
33
+ .middleware([staticFunctionMiddleware])
34
+ .handler(async ({ data: slugs }) => {
35
+ const page = source.getPage(slugs);
36
+ if (!page) throw notFound();
37
+
38
+ return {
39
+ tree: source.pageTree as object,
40
+ path: page.path,
41
+ };
42
+ });
43
+
44
+ const clientLoader = createClientLoader(docs.doc, {
45
+ id: 'docs',
46
+ component({ toc, frontmatter, default: MDX }) {
47
+ return (
48
+ <DocsPage toc={toc}>
49
+ <DocsTitle>{frontmatter.title}</DocsTitle>
50
+ <DocsDescription>{frontmatter.description}</DocsDescription>
51
+ <DocsBody>
52
+ <MDX
53
+ components={{
54
+ ...defaultMdxComponents,
55
+ }}
56
+ />
57
+ </DocsBody>
58
+ </DocsPage>
59
+ );
60
+ },
61
+ });
62
+
63
+ function Page() {
64
+ const data = Route.useLoaderData();
65
+ const Content = clientLoader.getComponent(data.path);
66
+ const tree = useMemo(
67
+ () => transformPageTree(data.tree as PageTree.Folder),
68
+ [data.tree],
69
+ );
70
+
71
+ return (
72
+ <DocsLayout {...baseOptions()} tree={tree}>
73
+ <Content />
74
+ </DocsLayout>
75
+ );
76
+ }
77
+
78
+ function transformPageTree(root: PageTree.Root): PageTree.Root {
79
+ function mapNode<T extends PageTree.Node>(item: T): T {
80
+ if (typeof item.icon === 'string') {
81
+ item = {
82
+ ...item,
83
+ icon: (
84
+ <span
85
+ dangerouslySetInnerHTML={{
86
+ __html: item.icon,
87
+ }}
88
+ />
89
+ ),
90
+ };
91
+ }
92
+
93
+ if (item.type === 'folder') {
94
+ return {
95
+ ...item,
96
+ index: item.index ? mapNode(item.index) : undefined,
97
+ children: item.children.map(mapNode),
98
+ };
99
+ }
100
+
101
+ return item;
102
+ }
103
+
104
+ return {
105
+ ...root,
106
+ children: root.children.map(mapNode),
107
+ fallback: root.fallback ? transformPageTree(root.fallback) : undefined,
108
+ };
109
+ }
@@ -0,0 +1,24 @@
1
+ import { createFileRoute, Link } from '@tanstack/react-router';
2
+ import { HomeLayout } from 'fumadocs-ui/layouts/home';
3
+ import { baseOptions } from '@/lib/layout.shared';
4
+
5
+ export const Route = createFileRoute('/')({
6
+ component: Home,
7
+ });
8
+
9
+ function Home() {
10
+ return (
11
+ <HomeLayout {...baseOptions()} className="text-center py-32 justify-center">
12
+ <h1 className="font-medium text-xl mb-4">Fumadocs on Tanstack Start.</h1>
13
+ <Link
14
+ to="/docs/$"
15
+ params={{
16
+ _splat: '',
17
+ }}
18
+ className="px-3 py-2 rounded-lg bg-fd-primary text-fd-primary-foreground font-medium text-sm mx-auto"
19
+ >
20
+ Open Docs
21
+ </Link>
22
+ </HomeLayout>
23
+ );
24
+ }
@@ -0,0 +1,3 @@
1
+ @import 'tailwindcss';
2
+ @import 'fumadocs-ui/css/neutral.css';
3
+ @import 'fumadocs-ui/css/preset.css';
@@ -0,0 +1,24 @@
1
+ {
2
+ "include": ["**/*.ts", "**/*.tsx"],
3
+ "compilerOptions": {
4
+ "strict": true,
5
+ "esModuleInterop": true,
6
+ "jsx": "react-jsx",
7
+ "module": "ESNext",
8
+ "moduleResolution": "Bundler",
9
+ "lib": ["DOM", "DOM.Iterable", "ES2022"],
10
+ "types": ["vite/client"],
11
+ "isolatedModules": true,
12
+ "resolveJsonModule": true,
13
+ "skipLibCheck": true,
14
+ "target": "ES2022",
15
+ "allowJs": true,
16
+ "forceConsistentCasingInFileNames": true,
17
+ "baseUrl": ".",
18
+ "paths": {
19
+ "@/*": ["./src/*"],
20
+ "@/.source": [".source"]
21
+ },
22
+ "noEmit": true
23
+ }
24
+ }
@@ -0,0 +1,39 @@
1
+ import react from '@vitejs/plugin-react';
2
+ import { tanstackStart } from '@tanstack/react-start/plugin/vite';
3
+ import { defineConfig } from 'vite';
4
+ import tsConfigPaths from 'vite-tsconfig-paths';
5
+ import tailwindcss from '@tailwindcss/vite';
6
+ import mdx from 'fumadocs-mdx/vite';
7
+
8
+ export default defineConfig({
9
+ server: {
10
+ port: 3000,
11
+ },
12
+ plugins: [
13
+ mdx(await import('./source.config')),
14
+ tailwindcss(),
15
+ tsConfigPaths({
16
+ projects: ['./tsconfig.json'],
17
+ }),
18
+ tanstackStart({
19
+ spa: {
20
+ enabled: true,
21
+ prerender: {
22
+ outputPath: 'index.html',
23
+ enabled: true,
24
+ crawlLinks: true,
25
+ },
26
+ },
27
+
28
+ pages: [
29
+ {
30
+ path: '/docs',
31
+ },
32
+ {
33
+ path: '/api/search',
34
+ },
35
+ ],
36
+ }),
37
+ react(),
38
+ ],
39
+ });
@@ -15,17 +15,17 @@
15
15
  "react": "^19.2.0",
16
16
  "react-dom": "^19.2.0",
17
17
  "react-server-dom-webpack": "^19.2.0",
18
- "waku": "^0.26.1"
18
+ "waku": "^0.27.0"
19
19
  },
20
20
  "devDependencies": {
21
- "@tailwindcss/vite": "^4.1.15",
21
+ "@tailwindcss/vite": "^4.1.16",
22
22
  "@types/mdx": "^2.0.13",
23
23
  "@types/node": "^24.9.1",
24
24
  "@types/react": "^19.2.2",
25
25
  "@types/react-dom": "^19.2.2",
26
- "tailwindcss": "^4.1.15",
26
+ "tailwindcss": "^4.1.16",
27
27
  "typescript": "^5.9.3",
28
- "vite": "^7.1.11",
28
+ "vite": "^7.1.12",
29
29
  "vite-tsconfig-paths": "^5.1.4"
30
30
  }
31
31
  }