create-fumadocs-app 15.1.3 → 15.2.0
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.
- package/dist/{chunk-K4QGKCVK.js → chunk-R4Y2JVJN.js} +124 -69
- package/dist/create-app.js +1 -1
- package/dist/index.js +33 -20
- package/package.json +2 -2
- package/template/react-router/README.md +12 -0
- package/template/react-router/app/app.css +6 -0
- package/template/react-router/app/docs/page.tsx +63 -0
- package/template/react-router/app/docs/search.ts +18 -0
- package/template/react-router/app/root.tsx +78 -0
- package/template/react-router/app/routes/home.tsx +34 -0
- package/template/react-router/app/routes.ts +7 -0
- package/template/react-router/app/source.ts +60 -0
- package/template/react-router/content/docs/index.mdx +32 -0
- package/template/react-router/content/docs/test.mdx +8 -0
- package/template/react-router/example.gitignore +6 -0
- package/template/react-router/public/favicon.ico +0 -0
- package/template/react-router/react-router.config.ts +9 -0
- package/template/react-router/tsconfig.json +27 -0
- package/template/react-router/vite.config.ts +13 -0
- /package/template/{+shared → +next}/README.md +0 -0
- /package/template/{+shared → +next}/app/(home)/layout.tsx +0 -0
- /package/template/{+shared → +next}/app/(home)/page.tsx +0 -0
- /package/template/{+shared → +next}/app/api/search/route.ts +0 -0
- /package/template/{+shared → +next}/app/docs/layout.tsx +0 -0
- /package/template/{+shared → +next}/app/layout.config.tsx +0 -0
- /package/template/{+shared → +next}/app/layout.tsx +0 -0
- /package/template/{+shared → +next}/content/docs/index.mdx +0 -0
- /package/template/{+shared → +next}/content/docs/test.mdx +0 -0
- /package/template/{+shared → +next}/example.gitignore +0 -0
- /package/template/{+eslint → +next+eslint}/.eslintrc.json +0 -0
- /package/template/{+tailwindcss → +next+tailwindcss}/app/(home)/page.tsx +0 -0
- /package/template/{+tailwindcss → +next+tailwindcss}/app/global.css +0 -0
- /package/template/{+tailwindcss → +next+tailwindcss}/app/layout.tsx +0 -0
- /package/template/{+tailwindcss → +next+tailwindcss}/postcss.config.mjs +0 -0
|
@@ -60,7 +60,7 @@ function tryGitInit(root) {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
// src/versions.js
|
|
63
|
-
var versions = { "fumadocs-core": "15.
|
|
63
|
+
var versions = { "fumadocs-core": "15.2.0", "fumadocs-ui": "15.2.0", "fumadocs-mdx": "11.5.7", "@fumadocs/mdx-remote": "1.3.0", "@fumadocs/content-collections": "1.1.8" };
|
|
64
64
|
|
|
65
65
|
// ../create-app-versions/package.json
|
|
66
66
|
var package_default = {
|
|
@@ -73,17 +73,28 @@ var package_default = {
|
|
|
73
73
|
"@content-collections/core": "^0.8.2",
|
|
74
74
|
"@content-collections/mdx": "^0.2.2",
|
|
75
75
|
"@content-collections/next": "^0.2.6",
|
|
76
|
-
"@
|
|
76
|
+
"@react-router/dev": "^7.4.1",
|
|
77
|
+
"@react-router/node": "^7.4.1",
|
|
78
|
+
"@react-router/serve": "^7.4.1",
|
|
79
|
+
"@tailwindcss/postcss": "^4.0.17",
|
|
80
|
+
"@tailwindcss/vite": "^4.0.17",
|
|
77
81
|
"@types/mdx": "^2.0.13",
|
|
78
|
-
"@types/node": "22.13.
|
|
82
|
+
"@types/node": "22.13.14",
|
|
79
83
|
"@types/react": "^19.0.12",
|
|
80
84
|
"@types/react-dom": "^19.0.4",
|
|
81
|
-
|
|
85
|
+
"gray-matter": "^4.0.3",
|
|
86
|
+
isbot: "^5.1.17",
|
|
87
|
+
next: "15.2.4",
|
|
82
88
|
postcss: "^8.5.3",
|
|
83
|
-
react: "^19.
|
|
84
|
-
"react-dom": "^19.
|
|
85
|
-
|
|
86
|
-
|
|
89
|
+
react: "^19.1.0",
|
|
90
|
+
"react-dom": "^19.1.0",
|
|
91
|
+
"react-router": "^7.4.1",
|
|
92
|
+
"react-router-devtools": "^1.1.8",
|
|
93
|
+
shiki: "^3.2.1",
|
|
94
|
+
tailwindcss: "^4.0.17",
|
|
95
|
+
typescript: "^5.8.2",
|
|
96
|
+
vite: "^6.2.3",
|
|
97
|
+
"vite-tsconfig-paths": "^5.1.4"
|
|
87
98
|
}
|
|
88
99
|
};
|
|
89
100
|
|
|
@@ -137,35 +148,56 @@ async function create(options) {
|
|
|
137
148
|
} = options;
|
|
138
149
|
const projectName = path.basename(options.outputDir);
|
|
139
150
|
const dest = path.resolve(cwd, options.outputDir);
|
|
151
|
+
const isNext = options.template === "content-collections" || options.template === "fuma-docs-mdx";
|
|
140
152
|
function defaultRename(file) {
|
|
141
153
|
file = file.replace("example.gitignore", ".gitignore");
|
|
142
154
|
if (!options.useSrcDir) {
|
|
143
155
|
return file;
|
|
144
156
|
}
|
|
145
|
-
|
|
146
|
-
const
|
|
157
|
+
if (isNext) {
|
|
158
|
+
for (const dir of ["app", "lib"]) {
|
|
159
|
+
const relative = path.relative(path.join(dest, dir), file);
|
|
160
|
+
if (!relative.startsWith(`..${path.sep}`)) {
|
|
161
|
+
return path.join(dest, "src", dir, relative);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
} else if (options.template === "react-router") {
|
|
165
|
+
const relative = path.relative(path.join(dest, "app"), file);
|
|
147
166
|
if (!relative.startsWith(`..${path.sep}`)) {
|
|
148
|
-
return path.join(dest, "src",
|
|
167
|
+
return path.join(dest, "src", relative);
|
|
149
168
|
}
|
|
150
169
|
}
|
|
151
170
|
return file;
|
|
152
171
|
}
|
|
153
|
-
|
|
172
|
+
if (isNext) {
|
|
173
|
+
await copy(path.join(sourceDir, `template/+next`), dest, defaultRename);
|
|
174
|
+
}
|
|
154
175
|
await copy(
|
|
155
176
|
path.join(sourceDir, `template/${options.template}`),
|
|
156
177
|
dest,
|
|
157
178
|
defaultRename
|
|
158
179
|
);
|
|
159
|
-
if (options.tailwindcss) {
|
|
180
|
+
if (isNext && options.tailwindcss) {
|
|
160
181
|
await copy(
|
|
161
|
-
path.join(sourceDir, `template/+tailwindcss`),
|
|
182
|
+
path.join(sourceDir, `template/+next+tailwindcss`),
|
|
162
183
|
dest,
|
|
163
184
|
defaultRename
|
|
164
185
|
);
|
|
186
|
+
if (options.useSrcDir) {
|
|
187
|
+
const cssPath = path.join(dest, "src/app/global.css");
|
|
188
|
+
await fs.writeFile(
|
|
189
|
+
cssPath,
|
|
190
|
+
(await fs.readFile(cssPath)).toString().replace("../", "../../")
|
|
191
|
+
);
|
|
192
|
+
}
|
|
165
193
|
log("Configured Tailwind CSS");
|
|
166
194
|
}
|
|
167
|
-
if (options.eslint) {
|
|
168
|
-
await copy(
|
|
195
|
+
if (isNext && options.eslint) {
|
|
196
|
+
await copy(
|
|
197
|
+
path.join(sourceDir, `template/+next+eslint`),
|
|
198
|
+
dest,
|
|
199
|
+
defaultRename
|
|
200
|
+
);
|
|
169
201
|
log("Configured ESLint");
|
|
170
202
|
}
|
|
171
203
|
if (options.useSrcDir) {
|
|
@@ -178,16 +210,12 @@ async function create(options) {
|
|
|
178
210
|
});
|
|
179
211
|
}
|
|
180
212
|
await fs.writeFile(tsconfigPath, JSON.stringify(config, null, 2));
|
|
181
|
-
if (options.tailwindcss) {
|
|
182
|
-
const cssPath = path.join(dest, "src/app/global.css");
|
|
183
|
-
await fs.writeFile(
|
|
184
|
-
cssPath,
|
|
185
|
-
(await fs.readFile(cssPath)).toString().replace("../", "../../")
|
|
186
|
-
);
|
|
187
|
-
}
|
|
188
213
|
}
|
|
189
214
|
const packageJson = createPackageJson(projectName, options);
|
|
190
|
-
await fs.writeFile(
|
|
215
|
+
await fs.writeFile(
|
|
216
|
+
path.join(dest, "package.json"),
|
|
217
|
+
JSON.stringify(packageJson, null, 2)
|
|
218
|
+
);
|
|
191
219
|
const readMe = await getReadme(dest, projectName);
|
|
192
220
|
await fs.writeFile(path.join(dest, "README.md"), readMe);
|
|
193
221
|
if (installDeps) {
|
|
@@ -219,65 +247,92 @@ async function copy(from, to, rename = (s) => s) {
|
|
|
219
247
|
}
|
|
220
248
|
}
|
|
221
249
|
function createPackageJson(projectName, options) {
|
|
222
|
-
|
|
250
|
+
if (options.template === "react-router") {
|
|
251
|
+
return {
|
|
252
|
+
name: projectName,
|
|
253
|
+
private: true,
|
|
254
|
+
type: "module",
|
|
255
|
+
scripts: {
|
|
256
|
+
build: "react-router build",
|
|
257
|
+
dev: "react-router dev",
|
|
258
|
+
start: "react-router-serve ./build/server/index.js",
|
|
259
|
+
typecheck: "react-router typegen && tsc"
|
|
260
|
+
},
|
|
261
|
+
dependencies: {
|
|
262
|
+
...pick(versions, [
|
|
263
|
+
"@fumadocs/mdx-remote",
|
|
264
|
+
"fumadocs-core",
|
|
265
|
+
"fumadocs-ui"
|
|
266
|
+
]),
|
|
267
|
+
...pick(package_default.dependencies, [
|
|
268
|
+
"@react-router/node",
|
|
269
|
+
"@react-router/serve",
|
|
270
|
+
"gray-matter",
|
|
271
|
+
"isbot",
|
|
272
|
+
"react",
|
|
273
|
+
"react-dom",
|
|
274
|
+
"react-router",
|
|
275
|
+
"shiki"
|
|
276
|
+
])
|
|
277
|
+
},
|
|
278
|
+
devDependencies: pick(package_default.dependencies, [
|
|
279
|
+
"@react-router/dev",
|
|
280
|
+
"@tailwindcss/vite",
|
|
281
|
+
"@types/node",
|
|
282
|
+
"@types/react",
|
|
283
|
+
"@types/react-dom",
|
|
284
|
+
"react-router-devtools",
|
|
285
|
+
"tailwindcss",
|
|
286
|
+
"typescript",
|
|
287
|
+
"vite",
|
|
288
|
+
"vite-tsconfig-paths"
|
|
289
|
+
])
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
return {
|
|
223
293
|
name: projectName,
|
|
224
294
|
version: "0.0.0",
|
|
225
295
|
private: true,
|
|
226
296
|
scripts: {
|
|
227
297
|
build: "next build",
|
|
228
298
|
dev: "next dev",
|
|
229
|
-
start: "next start"
|
|
299
|
+
start: "next start",
|
|
300
|
+
...options.template === "fuma-docs-mdx" ? {
|
|
301
|
+
postinstall: "fumadocs-mdx"
|
|
302
|
+
} : null
|
|
230
303
|
},
|
|
231
304
|
dependencies: {
|
|
232
305
|
...pick(package_default.dependencies, ["next", "react", "react-dom"]),
|
|
233
|
-
...pick(versions, ["fumadocs-ui", "fumadocs-core"])
|
|
306
|
+
...pick(versions, ["fumadocs-ui", "fumadocs-core"]),
|
|
307
|
+
...options.template === "content-collections" ? {
|
|
308
|
+
...pick(package_default.dependencies, [
|
|
309
|
+
"@content-collections/mdx",
|
|
310
|
+
"@content-collections/core",
|
|
311
|
+
"@content-collections/next"
|
|
312
|
+
]),
|
|
313
|
+
...pick(versions, ["@fumadocs/content-collections"])
|
|
314
|
+
} : null,
|
|
315
|
+
...options.template === "fuma-docs-mdx" ? pick(versions, ["fumadocs-mdx"]) : null
|
|
234
316
|
},
|
|
235
|
-
devDependencies:
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
};
|
|
242
|
-
if (options.template === "content-collections") {
|
|
243
|
-
Object.assign(
|
|
244
|
-
packageJson.dependencies,
|
|
245
|
-
pick(package_default.dependencies, [
|
|
246
|
-
"@content-collections/mdx",
|
|
247
|
-
"@content-collections/core",
|
|
248
|
-
"@content-collections/next"
|
|
317
|
+
devDependencies: {
|
|
318
|
+
...pick(package_default.dependencies, [
|
|
319
|
+
"@types/node",
|
|
320
|
+
"@types/react",
|
|
321
|
+
"@types/react-dom",
|
|
322
|
+
"typescript"
|
|
249
323
|
]),
|
|
250
|
-
pick(
|
|
251
|
-
);
|
|
252
|
-
}
|
|
253
|
-
if (options.template === "fuma-docs-mdx") {
|
|
254
|
-
packageJson.scripts.postinstall = "fumadocs-mdx";
|
|
255
|
-
Object.assign(
|
|
256
|
-
packageJson.dependencies,
|
|
257
|
-
pick(versions, ["fumadocs-mdx"])
|
|
258
|
-
);
|
|
259
|
-
Object.assign(
|
|
260
|
-
packageJson.devDependencies,
|
|
261
|
-
pick(package_default.dependencies, ["@types/mdx"])
|
|
262
|
-
);
|
|
263
|
-
}
|
|
264
|
-
if (options.tailwindcss) {
|
|
265
|
-
Object.assign(
|
|
266
|
-
packageJson.devDependencies,
|
|
267
|
-
pick(package_default.dependencies, [
|
|
324
|
+
...options.tailwindcss ? pick(package_default.dependencies, [
|
|
268
325
|
"@tailwindcss/postcss",
|
|
269
326
|
"tailwindcss",
|
|
270
327
|
"postcss"
|
|
271
|
-
])
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
}
|
|
280
|
-
return JSON.stringify(packageJson, void 0, 2);
|
|
328
|
+
]) : null,
|
|
329
|
+
...options.template === "fuma-docs-mdx" ? pick(package_default.dependencies, ["@types/mdx"]) : null,
|
|
330
|
+
...options.eslint ? {
|
|
331
|
+
eslint: "^8",
|
|
332
|
+
"eslint-config-next": package_default.dependencies.next
|
|
333
|
+
} : null
|
|
334
|
+
}
|
|
335
|
+
};
|
|
281
336
|
}
|
|
282
337
|
function pick(obj, keys) {
|
|
283
338
|
const result = {};
|
package/dist/create-app.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -3,10 +3,9 @@ import {
|
|
|
3
3
|
create,
|
|
4
4
|
cwd,
|
|
5
5
|
getPackageManager
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-R4Y2JVJN.js";
|
|
7
7
|
|
|
8
8
|
// src/index.ts
|
|
9
|
-
import { existsSync } from "node:fs";
|
|
10
9
|
import fs from "node:fs/promises";
|
|
11
10
|
import path from "node:path";
|
|
12
11
|
import {
|
|
@@ -32,23 +31,32 @@ async function main() {
|
|
|
32
31
|
defaultValue: "my-app"
|
|
33
32
|
}),
|
|
34
33
|
template: () => select({
|
|
35
|
-
message: "Choose a
|
|
34
|
+
message: "Choose a template",
|
|
36
35
|
initialValue: "fuma-docs-mdx",
|
|
37
36
|
options: [
|
|
38
37
|
{
|
|
39
38
|
value: "fuma-docs-mdx",
|
|
40
|
-
label: "Fumadocs MDX",
|
|
39
|
+
label: "Next.js: Fumadocs MDX",
|
|
41
40
|
hint: "recommended"
|
|
42
41
|
},
|
|
43
|
-
{
|
|
42
|
+
{
|
|
43
|
+
value: "content-collections",
|
|
44
|
+
label: "Next.js: Content Collections"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
value: "react-router",
|
|
48
|
+
label: "React Router: MDX Remote"
|
|
49
|
+
}
|
|
44
50
|
]
|
|
45
51
|
}),
|
|
46
52
|
src: () => confirm({ message: "Use `/src` directory?", initialValue: false }),
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
53
|
+
eslint: (v) => {
|
|
54
|
+
if (v.results.template === "react-router") return;
|
|
55
|
+
return confirm({
|
|
56
|
+
message: "Add default ESLint configuration?",
|
|
57
|
+
initialValue: false
|
|
58
|
+
});
|
|
59
|
+
},
|
|
52
60
|
installDeps: () => confirm({
|
|
53
61
|
message: `Do you want to install packages automatically? (detected as ${manager})`
|
|
54
62
|
})
|
|
@@ -62,9 +70,10 @@ async function main() {
|
|
|
62
70
|
);
|
|
63
71
|
const projectName = options.name.toLowerCase().replace(/\s/, "-");
|
|
64
72
|
const dest = path.resolve(cwd, projectName);
|
|
65
|
-
|
|
73
|
+
const destDir = await fs.readdir(dest).catch(() => null);
|
|
74
|
+
if (destDir && destDir.length > 0) {
|
|
66
75
|
const del = await confirm({
|
|
67
|
-
message:
|
|
76
|
+
message: `directory ${projectName} already exists, do you want to delete its files?`
|
|
68
77
|
});
|
|
69
78
|
if (isCancel(del)) {
|
|
70
79
|
cancel();
|
|
@@ -72,23 +81,27 @@ async function main() {
|
|
|
72
81
|
}
|
|
73
82
|
if (del) {
|
|
74
83
|
const info2 = spinner();
|
|
75
|
-
info2.start(`Deleting ${projectName}`);
|
|
76
|
-
await
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
84
|
+
info2.start(`Deleting files in ${projectName}`);
|
|
85
|
+
await Promise.all(
|
|
86
|
+
destDir.map((item) => {
|
|
87
|
+
return fs.rm(path.join(dest, item), {
|
|
88
|
+
recursive: true,
|
|
89
|
+
force: true
|
|
90
|
+
});
|
|
91
|
+
})
|
|
92
|
+
);
|
|
93
|
+
info2.stop(`Deleted files in ${projectName}`);
|
|
81
94
|
}
|
|
82
95
|
}
|
|
83
96
|
const info = spinner();
|
|
84
97
|
info.start(`Generating Project`);
|
|
85
98
|
await create({
|
|
86
99
|
packageManager: manager,
|
|
87
|
-
tailwindcss:
|
|
100
|
+
tailwindcss: true,
|
|
88
101
|
template: options.template,
|
|
89
102
|
outputDir: dest,
|
|
90
103
|
installDeps: options.installDeps,
|
|
91
|
-
eslint: options.eslint,
|
|
104
|
+
eslint: options.eslint === true,
|
|
92
105
|
useSrcDir: options.src,
|
|
93
106
|
log: (message) => {
|
|
94
107
|
info.message(message);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-fumadocs-app",
|
|
3
|
-
"version": "15.
|
|
3
|
+
"version": "15.2.0",
|
|
4
4
|
"description": "Create a new documentation site with Fumadocs",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"NextJs",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@types/cross-spawn": "^6.0.6",
|
|
28
|
-
"@types/node": "22.13.
|
|
28
|
+
"@types/node": "22.13.14",
|
|
29
29
|
"fast-glob": "^3.3.3",
|
|
30
30
|
"eslint-config-custom": "0.0.0",
|
|
31
31
|
"tsconfig": "0.0.0"
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { Route } from './+types/page';
|
|
2
|
+
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
|
|
3
|
+
import {
|
|
4
|
+
DocsBody,
|
|
5
|
+
DocsDescription,
|
|
6
|
+
DocsPage,
|
|
7
|
+
DocsTitle,
|
|
8
|
+
} from 'fumadocs-ui/page';
|
|
9
|
+
import { source } from '@/source';
|
|
10
|
+
import defaultMdxComponents from 'fumadocs-ui/mdx';
|
|
11
|
+
import { executeMdxSync } from '@fumadocs/mdx-remote/client';
|
|
12
|
+
import type { PageTree } from 'fumadocs-core/server';
|
|
13
|
+
import { createCompiler } from '@fumadocs/mdx-remote';
|
|
14
|
+
|
|
15
|
+
export function meta({}: Route.MetaArgs) {
|
|
16
|
+
return [
|
|
17
|
+
{ title: 'New React Router App' },
|
|
18
|
+
{ name: 'description', content: 'Welcome to React Router!' },
|
|
19
|
+
];
|
|
20
|
+
}
|
|
21
|
+
const compiler = createCompiler({
|
|
22
|
+
development: false,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export async function loader({ params }: Route.LoaderArgs) {
|
|
26
|
+
const slugs = params['*'].split('/').filter((v) => v.length > 0);
|
|
27
|
+
const page = source.getPage(slugs);
|
|
28
|
+
if (!page) throw new Error('Not found');
|
|
29
|
+
|
|
30
|
+
const compiled = String(
|
|
31
|
+
await compiler.compileFile({
|
|
32
|
+
value: page.data.content,
|
|
33
|
+
}),
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
page,
|
|
38
|
+
compiled,
|
|
39
|
+
tree: source.pageTree,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export default function Page(props: Route.ComponentProps) {
|
|
44
|
+
const { page, compiled, tree } = props.loaderData;
|
|
45
|
+
const { default: Mdx, toc } = executeMdxSync(compiled);
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<DocsLayout
|
|
49
|
+
nav={{
|
|
50
|
+
title: 'React Router',
|
|
51
|
+
}}
|
|
52
|
+
tree={tree as PageTree.Root}
|
|
53
|
+
>
|
|
54
|
+
<DocsPage toc={toc}>
|
|
55
|
+
<DocsTitle>{page.data.title}</DocsTitle>
|
|
56
|
+
<DocsDescription>{page.data.description}</DocsDescription>
|
|
57
|
+
<DocsBody>
|
|
58
|
+
<Mdx components={defaultMdxComponents} />
|
|
59
|
+
</DocsBody>
|
|
60
|
+
</DocsPage>
|
|
61
|
+
</DocsLayout>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Route } from './+types/search';
|
|
2
|
+
import { createSearchAPI } from 'fumadocs-core/search/server';
|
|
3
|
+
import { source } from '@/source';
|
|
4
|
+
import { structure } from 'fumadocs-core/mdx-plugins';
|
|
5
|
+
|
|
6
|
+
const server = createSearchAPI('advanced', {
|
|
7
|
+
indexes: source.getPages().map((page) => ({
|
|
8
|
+
id: page.url,
|
|
9
|
+
url: page.url,
|
|
10
|
+
title: page.data.title ?? '',
|
|
11
|
+
description: page.data.description,
|
|
12
|
+
structuredData: structure(page.data.content),
|
|
13
|
+
})),
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export async function loader({ request }: Route.LoaderArgs) {
|
|
17
|
+
return server.GET(request);
|
|
18
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isRouteErrorResponse,
|
|
3
|
+
Links,
|
|
4
|
+
Meta,
|
|
5
|
+
Outlet,
|
|
6
|
+
Scripts,
|
|
7
|
+
ScrollRestoration,
|
|
8
|
+
} from 'react-router';
|
|
9
|
+
import { RootProvider } from 'fumadocs-ui/provider/base';
|
|
10
|
+
import { ReactRouterProvider } from 'fumadocs-core/framework/react-router';
|
|
11
|
+
import type { Route } from './+types/root';
|
|
12
|
+
import './app.css';
|
|
13
|
+
|
|
14
|
+
export const links: Route.LinksFunction = () => [
|
|
15
|
+
{ rel: 'preconnect', href: 'https://fonts.googleapis.com' },
|
|
16
|
+
{
|
|
17
|
+
rel: 'preconnect',
|
|
18
|
+
href: 'https://fonts.gstatic.com',
|
|
19
|
+
crossOrigin: 'anonymous',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
rel: 'stylesheet',
|
|
23
|
+
href: 'https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap',
|
|
24
|
+
},
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
export function Layout({ children }: { children: React.ReactNode }) {
|
|
28
|
+
return (
|
|
29
|
+
<html lang="en" suppressHydrationWarning>
|
|
30
|
+
<head>
|
|
31
|
+
<meta charSet="utf-8" />
|
|
32
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
33
|
+
<Meta />
|
|
34
|
+
<Links />
|
|
35
|
+
</head>
|
|
36
|
+
<body>
|
|
37
|
+
<ReactRouterProvider>
|
|
38
|
+
<RootProvider>{children}</RootProvider>
|
|
39
|
+
</ReactRouterProvider>
|
|
40
|
+
<ScrollRestoration />
|
|
41
|
+
<Scripts />
|
|
42
|
+
</body>
|
|
43
|
+
</html>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export default function App() {
|
|
48
|
+
return <Outlet />;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) {
|
|
52
|
+
let message = 'Oops!';
|
|
53
|
+
let details = 'An unexpected error occurred.';
|
|
54
|
+
let stack: string | undefined;
|
|
55
|
+
|
|
56
|
+
if (isRouteErrorResponse(error)) {
|
|
57
|
+
message = error.status === 404 ? '404' : 'Error';
|
|
58
|
+
details =
|
|
59
|
+
error.status === 404
|
|
60
|
+
? 'The requested page could not be found.'
|
|
61
|
+
: error.statusText || details;
|
|
62
|
+
} else if (import.meta.env.DEV && error && error instanceof Error) {
|
|
63
|
+
details = error.message;
|
|
64
|
+
stack = error.stack;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<main className="pt-16 p-4 container mx-auto">
|
|
69
|
+
<h1>{message}</h1>
|
|
70
|
+
<p>{details}</p>
|
|
71
|
+
{stack && (
|
|
72
|
+
<pre className="w-full p-4 overflow-x-auto">
|
|
73
|
+
<code>{stack}</code>
|
|
74
|
+
</pre>
|
|
75
|
+
)}
|
|
76
|
+
</main>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Route } from './+types/home';
|
|
2
|
+
import { HomeLayout } from 'fumadocs-ui/layouts/home';
|
|
3
|
+
import { Link } from 'react-router';
|
|
4
|
+
|
|
5
|
+
export function meta({}: Route.MetaArgs) {
|
|
6
|
+
return [
|
|
7
|
+
{ title: 'New React Router App' },
|
|
8
|
+
{ name: 'description', content: 'Welcome to React Router!' },
|
|
9
|
+
];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default function Home() {
|
|
13
|
+
return (
|
|
14
|
+
<HomeLayout
|
|
15
|
+
className="text-center"
|
|
16
|
+
nav={{
|
|
17
|
+
title: 'React Router',
|
|
18
|
+
}}
|
|
19
|
+
>
|
|
20
|
+
<div className="py-12">
|
|
21
|
+
<h1 className="text-xl font-bold mb-2">Fumadocs on React Router.</h1>
|
|
22
|
+
<p className="text-fd-muted-foreground mb-8">
|
|
23
|
+
The truly flexible docs framework on React.js.
|
|
24
|
+
</p>
|
|
25
|
+
<Link
|
|
26
|
+
className="text-sm bg-fd-primary text-fd-primary-foreground rounded-full font-medium px-4 py-2.5"
|
|
27
|
+
to="/docs"
|
|
28
|
+
>
|
|
29
|
+
Open Docs
|
|
30
|
+
</Link>
|
|
31
|
+
</div>
|
|
32
|
+
</HomeLayout>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import {
|
|
2
|
+
loader,
|
|
3
|
+
type MetaData,
|
|
4
|
+
type PageData,
|
|
5
|
+
type Source,
|
|
6
|
+
type VirtualFile,
|
|
7
|
+
} from 'fumadocs-core/source';
|
|
8
|
+
import matter from 'gray-matter';
|
|
9
|
+
import * as path from 'node:path';
|
|
10
|
+
|
|
11
|
+
const files = Object.entries(
|
|
12
|
+
import.meta.glob<true, 'raw'>('/content/docs/**/*', {
|
|
13
|
+
eager: true,
|
|
14
|
+
query: '?raw',
|
|
15
|
+
import: 'default',
|
|
16
|
+
}),
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
const virtualFiles: VirtualFile[] = files.flatMap(([file, content]) => {
|
|
20
|
+
const ext = path.extname(file);
|
|
21
|
+
const virtualPath = path.relative(
|
|
22
|
+
'content/docs',
|
|
23
|
+
path.join(process.cwd(), file),
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
if (ext === '.mdx' || ext === '.md') {
|
|
27
|
+
const parsed = matter(content);
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
type: 'page',
|
|
31
|
+
path: virtualPath,
|
|
32
|
+
data: {
|
|
33
|
+
...parsed.data,
|
|
34
|
+
content: parsed.content,
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (ext === '.json') {
|
|
40
|
+
return {
|
|
41
|
+
type: 'meta',
|
|
42
|
+
path: virtualPath,
|
|
43
|
+
data: JSON.parse(content),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return [];
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
export const source = loader({
|
|
51
|
+
source: {
|
|
52
|
+
files: virtualFiles,
|
|
53
|
+
} as Source<{
|
|
54
|
+
pageData: PageData & {
|
|
55
|
+
content: string;
|
|
56
|
+
};
|
|
57
|
+
metaData: MetaData;
|
|
58
|
+
}>,
|
|
59
|
+
baseUrl: '/docs',
|
|
60
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Hello World
|
|
3
|
+
description: |
|
|
4
|
+
Your first `document`
|
|
5
|
+
You'll love it!
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Hey there! Fumadocs is the docs framework that also works on React Router!
|
|
9
|
+
|
|
10
|
+
## Heading
|
|
11
|
+
|
|
12
|
+
Hello World
|
|
13
|
+
|
|
14
|
+
<Cards>
|
|
15
|
+
<Card title="Learn more about React Router" href="https://reactrouter.com" />
|
|
16
|
+
<Card title="Learn more about Fumadocs" href="https://fumadocs.vercel.app" />
|
|
17
|
+
</Cards>
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
console.log('I love React!');
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Heading
|
|
24
|
+
|
|
25
|
+
#### Heading
|
|
26
|
+
|
|
27
|
+
| Head | Description |
|
|
28
|
+
| ------------------------------- | ----------------------------------- |
|
|
29
|
+
| `hello` | Hello World |
|
|
30
|
+
| very **important** | Hey |
|
|
31
|
+
| _Surprisingly_ | Fumadocs |
|
|
32
|
+
| very long text that looks weird | hello world hello world hello world |
|
|
Binary file
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Config } from '@react-router/dev/config';
|
|
2
|
+
import { source } from './app/source';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
ssr: true,
|
|
6
|
+
async prerender({ getStaticPaths }) {
|
|
7
|
+
return [...getStaticPaths(), ...source.getPages().map((page) => page.url)];
|
|
8
|
+
},
|
|
9
|
+
} satisfies Config;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"include": [
|
|
3
|
+
"**/*",
|
|
4
|
+
"**/.server/**/*",
|
|
5
|
+
"**/.client/**/*",
|
|
6
|
+
".react-router/types/**/*"
|
|
7
|
+
],
|
|
8
|
+
"compilerOptions": {
|
|
9
|
+
"lib": ["DOM", "DOM.Iterable", "ES2022"],
|
|
10
|
+
"types": ["node", "vite/client"],
|
|
11
|
+
"target": "esnext",
|
|
12
|
+
"module": "esnext",
|
|
13
|
+
"moduleResolution": "bundler",
|
|
14
|
+
"jsx": "react-jsx",
|
|
15
|
+
"rootDirs": [".", "./.react-router/types"],
|
|
16
|
+
"baseUrl": ".",
|
|
17
|
+
"paths": {
|
|
18
|
+
"@/*": ["./app/*"]
|
|
19
|
+
},
|
|
20
|
+
"esModuleInterop": true,
|
|
21
|
+
"verbatimModuleSyntax": true,
|
|
22
|
+
"noEmit": true,
|
|
23
|
+
"resolveJsonModule": true,
|
|
24
|
+
"skipLibCheck": true,
|
|
25
|
+
"strict": true
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { reactRouter } from '@react-router/dev/vite';
|
|
2
|
+
import tailwindcss from '@tailwindcss/vite';
|
|
3
|
+
import { defineConfig } from 'vite';
|
|
4
|
+
import tsconfigPaths from 'vite-tsconfig-paths';
|
|
5
|
+
|
|
6
|
+
export default defineConfig({
|
|
7
|
+
build: {
|
|
8
|
+
rollupOptions: {
|
|
9
|
+
external: ['shiki'],
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
plugins: [tailwindcss(), reactRouter(), tsconfigPaths()],
|
|
13
|
+
});
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|