create-fumadocs-app 16.0.4 → 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 (36) hide show
  1. package/README.md +1 -1
  2. package/dist/bin.js +2 -2
  3. package/dist/{chunk-UXPTMGXV.js → chunk-PGCMK5N3.js} +1 -1
  4. package/dist/{chunk-ZWEHS3HT.js → chunk-QKIRNPKF.js} +16 -41
  5. package/dist/index.d.ts +1 -1
  6. package/dist/index.js +2 -2
  7. package/dist/plugins/biome.js +1 -1
  8. package/dist/plugins/eslint.js +4 -4
  9. package/dist/plugins/orama-cloud.js +7 -5
  10. package/package.json +3 -3
  11. package/template/+next+fuma-docs-mdx/package.json +3 -3
  12. package/template/+next+fuma-docs-mdx/tsconfig.json +8 -2
  13. package/template/react-router/package.json +3 -3
  14. package/template/react-router-spa/package.json +4 -4
  15. package/template/tanstack-start/content/docs/index.mdx +1 -1
  16. package/template/tanstack-start/package.json +8 -8
  17. package/template/tanstack-start/src/routes/docs/$.tsx +26 -19
  18. package/template/tanstack-start-spa/README.md +12 -0
  19. package/template/tanstack-start-spa/content/docs/index.mdx +34 -0
  20. package/template/tanstack-start-spa/content/docs/test.mdx +12 -0
  21. package/template/tanstack-start-spa/example.gitignore +19 -0
  22. package/template/tanstack-start-spa/package.json +38 -0
  23. package/template/tanstack-start-spa/source.config.ts +7 -0
  24. package/template/tanstack-start-spa/src/components/not-found.tsx +28 -0
  25. package/template/tanstack-start-spa/src/components/search.tsx +51 -0
  26. package/template/tanstack-start-spa/src/lib/layout.shared.tsx +9 -0
  27. package/template/tanstack-start-spa/src/lib/source.ts +15 -0
  28. package/template/tanstack-start-spa/src/router.tsx +12 -0
  29. package/template/tanstack-start-spa/src/routes/__root.tsx +51 -0
  30. package/template/tanstack-start-spa/src/routes/api/search.ts +16 -0
  31. package/template/tanstack-start-spa/src/routes/docs/$.tsx +109 -0
  32. package/template/tanstack-start-spa/src/routes/index.tsx +24 -0
  33. package/template/tanstack-start-spa/src/styles/app.css +3 -0
  34. package/template/tanstack-start-spa/tsconfig.json +24 -0
  35. package/template/tanstack-start-spa/vite.config.ts +39 -0
  36. package/template/waku/package.json +4 -4
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Create Fumadocs App
2
2
 
3
- A CLI tool to create new Next.js documentation sites with Fumadocs.
3
+ A CLI tool to create new documentation sites with Fumadocs.
4
4
 
5
5
  ```bash
6
6
  npx create-fumadocs-app
package/dist/bin.js CHANGED
@@ -3,11 +3,11 @@ import {
3
3
  create,
4
4
  getPackageManager,
5
5
  managers
6
- } from "./chunk-UXPTMGXV.js";
6
+ } from "./chunk-PGCMK5N3.js";
7
7
  import {
8
8
  isCI,
9
9
  templates
10
- } from "./chunk-ZWEHS3HT.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-ZWEHS3HT.js";
7
+ } from "./chunk-QKIRNPKF.js";
8
8
 
9
9
  // src/index.ts
10
10
  import path from "path";
@@ -91,49 +91,20 @@ function pick(obj, keys) {
91
91
  // src/constants.ts
92
92
  import { fileURLToPath } from "url";
93
93
 
94
- // src/versions.js
95
- var versions = { "fumadocs-core": "16.0.3", "fumadocs-ui": "16.0.3", "fumadocs-mdx": "13.0.1", "@fumadocs/mdx-remote": "1.4.3", "@fumadocs/content-collections": "1.2.4" };
96
-
97
94
  // ../create-app-versions/package.json
98
95
  var package_default = {
99
- name: "example-versions",
100
- version: "0.0.0",
96
+ name: "create-fumadocs-versions",
97
+ version: "16.0.6",
101
98
  private: true,
102
99
  description: "Used to track dependency versions in create-fumadocs-app",
103
100
  dependencies: {
104
- "@biomejs/biome": "^2.2.6",
105
- "@content-collections/core": "^0.11.1",
106
- "@content-collections/mdx": "^0.2.2",
107
- "@content-collections/next": "^0.2.8",
101
+ "@biomejs/biome": "^2.3.1",
102
+ "@eslint/eslintrc": "^3.3.1",
108
103
  "@orama/core": "^1.2.13",
109
- "@react-router/dev": "^7.9.4",
110
- "@react-router/node": "^7.9.4",
111
- "@react-router/serve": "^7.9.4",
112
- "@tailwindcss/postcss": "^4.1.15",
113
- "@tailwindcss/vite": "^4.1.15",
114
- "@tanstack/react-router": "^1.133.21",
115
- "@tanstack/react-start": "^1.133.21",
116
- "@types/mdx": "^2.0.13",
117
- "@types/node": "24.9.1",
118
- "@types/react": "^19.2.2",
119
- "@types/react-dom": "^19.2.2",
120
- "@vitejs/plugin-react": "^5.0.4",
121
- "gray-matter": "^4.0.3",
122
- isbot: "^5.1.31",
123
- "lucide-react": "^0.546.0",
124
- next: "16.0.0",
125
- postcss: "^8.5.6",
126
- react: "^19.2.0",
127
- "react-dom": "^19.2.0",
128
- "react-router": "^7.9.4",
129
- "react-router-devtools": "^5.1.3",
130
- shiki: "^3.13.0",
131
- tailwindcss: "^4.1.15",
132
- tinyglobby: "^0.2.15",
133
- typescript: "^5.9.3",
134
- vinxi: "^0.5.8",
135
- vite: "^7.1.11",
136
- "vite-tsconfig-paths": "^5.1.4"
104
+ eslint: "^9.38.0",
105
+ "fumadocs-core": "workspace:*",
106
+ "fumadocs-mdx": "workspace:*",
107
+ "fumadocs-ui": "workspace:*"
137
108
  }
138
109
  };
139
110
 
@@ -172,12 +143,16 @@ var templates = [
172
143
  label: "Tanstack Start: Fumadocs MDX (not RSC)",
173
144
  appDir: "src",
174
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"
175
153
  }
176
154
  ];
177
- var depVersions = {
178
- ...versions,
179
- ...package_default.dependencies
180
- };
155
+ var depVersions = package_default.dependencies;
181
156
 
182
157
  export {
183
158
  writeFile,
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-UXPTMGXV.js";
4
- import "./chunk-ZWEHS3HT.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-ZWEHS3HT.js";
11
+ } from "../chunk-QKIRNPKF.js";
12
12
 
13
13
  // src/plugins/biome.ts
14
14
  import path from "path";
@@ -1,7 +1,8 @@
1
1
  import {
2
2
  depVersions,
3
+ pick,
3
4
  writeFile
4
- } from "../chunk-ZWEHS3HT.js";
5
+ } from "../chunk-QKIRNPKF.js";
5
6
 
6
7
  // src/plugins/eslint.ts
7
8
  import path from "path";
@@ -43,9 +44,8 @@ function eslint() {
43
44
  },
44
45
  devDependencies: {
45
46
  ...packageJson.devDependencies,
46
- eslint: "^9",
47
- "eslint-config-next": depVersions.next,
48
- "@eslint/eslintrc": "^3"
47
+ "eslint-config-next": packageJson.dependencies.next,
48
+ ...pick(depVersions, ["eslint", "@eslint/eslintrc"])
49
49
  }
50
50
  };
51
51
  },
@@ -4,7 +4,7 @@ import {
4
4
  pick,
5
5
  sourceDir,
6
6
  writeFile
7
- } from "../chunk-ZWEHS3HT.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.4",
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"
@@ -52,7 +52,7 @@
52
52
  "access": "public"
53
53
  },
54
54
  "scripts": {
55
- "build": "tsup",
55
+ "build": "pnpm run sync && tsup",
56
56
  "clean": "rimraf dist",
57
57
  "dev": "tsup --watch",
58
58
  "lint": "eslint .",
@@ -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
  }