create-fumadocs-app 16.0.0 → 16.0.2
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-KVKS2K3W.js → chunk-6C2B326N.js} +198 -196
- package/dist/create-app.d.ts +35 -8
- package/dist/create-app.js +3 -5
- package/dist/index.js +110 -32
- package/package.json +3 -2
- package/template/+next+fuma-docs-mdx/app/(home)/page.tsx +16 -0
- package/template/{+next+tailwindcss → +next+fuma-docs-mdx}/app/layout.tsx +1 -1
- package/template/{+next → +next+fuma-docs-mdx}/example.gitignore +0 -2
- package/template/+next+fuma-docs-mdx/lib/layout.shared.tsx +9 -0
- package/template/+next+fuma-docs-mdx/lib/source.ts +1 -1
- package/template/{+next → +next+fuma-docs-mdx}/mdx-components.tsx +0 -1
- package/template/+next+fuma-docs-mdx/package.json +29 -0
- package/template/+next+fuma-docs-mdx/source.config.ts +1 -0
- package/template/+next+fuma-docs-mdx/tsconfig.json +2 -2
- package/template/{+next → +orama-cloud/+next+fuma-docs-mdx}/app/layout.tsx +4 -9
- package/template/+orama-cloud/+next+fuma-docs-mdx/app/static.json/route.ts +7 -0
- package/template/+orama-cloud/@app/components/search.tsx +59 -0
- package/template/+orama-cloud/@app/lib/export-static-indexes.ts +14 -0
- package/template/+orama-cloud/@root/.env.example +6 -0
- package/template/+orama-cloud/react-router/app/root.tsx +76 -0
- package/template/+orama-cloud/react-router/app/routes/static.ts +5 -0
- package/template/+orama-cloud/react-router/app/routes.ts +8 -0
- package/template/+orama-cloud/react-router-spa/app/root.tsx +76 -0
- package/template/+orama-cloud/react-router-spa/app/routes/static.ts +5 -0
- package/template/+orama-cloud/react-router-spa/app/routes.ts +8 -0
- package/template/+orama-cloud/tanstack-start/src/routes/__root.tsx +51 -0
- package/template/+orama-cloud/tanstack-start/src/routes/static[.]json.ts +10 -0
- package/template/+orama-cloud/tanstack-start/vite.config.ts +27 -0
- package/template/+orama-cloud/waku/src/components/provider.tsx +8 -0
- package/template/+orama-cloud/waku/src/pages/api/static.json.ts +9 -0
- package/template/react-router/app/docs/page.tsx +4 -4
- package/template/react-router/example.gitignore +0 -1
- package/template/react-router-spa/README.md +12 -0
- package/template/react-router-spa/app/app.css +3 -0
- package/template/react-router-spa/app/components/search.tsx +50 -0
- package/template/react-router-spa/app/docs/page.tsx +53 -0
- package/template/react-router-spa/app/docs/search.ts +10 -0
- package/template/react-router-spa/app/lib/layout.shared.tsx +9 -0
- package/template/react-router-spa/app/lib/source.ts +7 -0
- package/template/react-router-spa/app/root.tsx +76 -0
- package/template/react-router-spa/app/routes/home.tsx +30 -0
- package/template/react-router-spa/app/routes.ts +7 -0
- package/template/react-router-spa/content/docs/index.mdx +32 -0
- package/template/react-router-spa/content/docs/test.mdx +24 -0
- package/template/react-router-spa/example.gitignore +7 -0
- package/template/react-router-spa/package.json +36 -0
- package/template/react-router-spa/public/favicon.ico +0 -0
- package/template/react-router-spa/react-router.config.ts +18 -0
- package/template/react-router-spa/serve.json +3 -0
- package/template/react-router-spa/source.config.ts +7 -0
- package/template/react-router-spa/tsconfig.json +28 -0
- package/template/react-router-spa/vite.config.ts +10 -0
- package/template/tanstack-start/example.gitignore +9 -1
- package/template/tanstack-start/package.json +6 -6
- package/template/waku/example.gitignore +3 -1
- package/template/waku/package.json +3 -3
- package/template/+next/README.md +0 -37
- package/template/+next/app/(home)/page.tsx +0 -42
- package/template/+next/lib/layout.shared.tsx +0 -30
- package/template/+next+content-collections/app/docs/[[...slug]]/page.tsx +0 -51
- package/template/+next+content-collections/content-collections.ts +0 -26
- package/template/+next+content-collections/lib/source.ts +0 -8
- package/template/+next+content-collections/next.config.mjs +0 -8
- package/template/+next+content-collections/tsconfig.json +0 -35
- package/template/+next+tailwindcss/app/(home)/page.tsx +0 -19
- package/template/{+next → +next+fuma-docs-mdx}/app/(home)/layout.tsx +0 -0
- package/template/{+next → +next+fuma-docs-mdx}/app/api/search/route.ts +0 -0
- package/template/{+next → +next+fuma-docs-mdx}/app/docs/layout.tsx +1 -1
- /package/template/{+next+tailwindcss → +next+fuma-docs-mdx}/app/global.css +0 -0
- /package/template/{+next → +next+fuma-docs-mdx}/content/docs/index.mdx +0 -0
- /package/template/{+next → +next+fuma-docs-mdx}/content/docs/test.mdx +0 -0
- /package/template/{+next+tailwindcss → +next+fuma-docs-mdx}/postcss.config.mjs +0 -0
package/dist/index.js
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
copy,
|
|
3
4
|
create,
|
|
4
5
|
cwd,
|
|
6
|
+
depVersions,
|
|
5
7
|
getPackageManager,
|
|
6
8
|
managers,
|
|
9
|
+
pick,
|
|
10
|
+
sourceDir,
|
|
7
11
|
templates
|
|
8
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-6C2B326N.js";
|
|
9
13
|
|
|
10
14
|
// src/index.ts
|
|
11
|
-
import
|
|
12
|
-
import
|
|
15
|
+
import fs2 from "fs/promises";
|
|
16
|
+
import path2 from "path";
|
|
13
17
|
import {
|
|
14
18
|
cancel,
|
|
15
19
|
confirm,
|
|
@@ -23,6 +27,85 @@ import {
|
|
|
23
27
|
} from "@clack/prompts";
|
|
24
28
|
import pc from "picocolors";
|
|
25
29
|
import { program } from "commander";
|
|
30
|
+
|
|
31
|
+
// src/plugins/orama-cloud.ts
|
|
32
|
+
import path from "path";
|
|
33
|
+
import fs from "fs/promises";
|
|
34
|
+
var oramaCloud = {
|
|
35
|
+
packageJson(packageJson) {
|
|
36
|
+
return {
|
|
37
|
+
...packageJson,
|
|
38
|
+
scripts: {
|
|
39
|
+
...packageJson.scripts,
|
|
40
|
+
build: `${packageJson.build} && bun scripts/sync-content.ts`
|
|
41
|
+
},
|
|
42
|
+
dependencies: {
|
|
43
|
+
...packageJson.dependencies,
|
|
44
|
+
...pick(depVersions, ["@orama/core"])
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
},
|
|
48
|
+
readme(content) {
|
|
49
|
+
return `${content}
|
|
50
|
+
|
|
51
|
+
## Orama Cloud
|
|
52
|
+
|
|
53
|
+
This project uses Orama Cloud for 3rd party search solution.
|
|
54
|
+
|
|
55
|
+
See https://fumadocs.dev/docs/headless/search/orama-cloud for integrating Orama Cloud to Fumadocs.`;
|
|
56
|
+
},
|
|
57
|
+
async afterWrite() {
|
|
58
|
+
const { dest, template, options } = this;
|
|
59
|
+
const appDir = path.join(dest, options.useSrcDir ? "src" : ".");
|
|
60
|
+
await copy(path.join(sourceDir, "template/+orama-cloud/@root"), dest);
|
|
61
|
+
await copy(path.join(sourceDir, "template/+orama-cloud/@app"), appDir);
|
|
62
|
+
const filePath = {
|
|
63
|
+
"+next+fuma-docs-mdx": ".next/server/app/static.json.body",
|
|
64
|
+
"tanstack-start": ".output/public/static.json",
|
|
65
|
+
"react-router": "build/client/static.json",
|
|
66
|
+
"react-router-spa": "build/client/static.json",
|
|
67
|
+
waku: "dist/public/static.json"
|
|
68
|
+
}[template.value];
|
|
69
|
+
const SyncContentScript = `import { type OramaDocument, sync } from 'fumadocs-core/search/orama-cloud';
|
|
70
|
+
import * as fs from 'node:fs/promises';
|
|
71
|
+
import { OramaCloud } from '@orama/core';
|
|
72
|
+
|
|
73
|
+
// the path of pre-rendered \`static.json\`
|
|
74
|
+
const filePath = ${JSON.stringify(filePath)};
|
|
75
|
+
|
|
76
|
+
async function main() {
|
|
77
|
+
const orama = new OramaCloud({
|
|
78
|
+
projectId: process.env.NEXT_PUBLIC_ORAMA_PROJECT_ID,
|
|
79
|
+
apiKey: process.env.ORAMA_PRIVATE_API_KEY,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const content = await fs.readFile(filePath);
|
|
83
|
+
const records = JSON.parse(content.toString()) as OramaDocument[];
|
|
84
|
+
|
|
85
|
+
await sync(orama, {
|
|
86
|
+
index: process.env.NEXT_PUBLIC_ORAMA_DATASOURCE_ID,
|
|
87
|
+
documents: records,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
console.log(\`search updated: \${records.length} records\`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
void main();
|
|
94
|
+
`;
|
|
95
|
+
await fs.mkdir(path.join(dest, "scripts"), { recursive: true });
|
|
96
|
+
await fs.writeFile(
|
|
97
|
+
path.join(dest, "scripts/sync-content.ts"),
|
|
98
|
+
SyncContentScript
|
|
99
|
+
);
|
|
100
|
+
await copy(
|
|
101
|
+
path.join(sourceDir, `template/+orama-cloud/${template.value}`),
|
|
102
|
+
appDir
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
var orama_cloud_default = oramaCloud;
|
|
107
|
+
|
|
108
|
+
// src/index.ts
|
|
26
109
|
program.argument("[name]", "the project name");
|
|
27
110
|
program.option("--src", "(Next.js only) enable `src/` directory");
|
|
28
111
|
program.option("--no-src", "(Next.js only) disable `src/` directory");
|
|
@@ -35,9 +118,9 @@ program.option("--no-install", "Disable installing packages automatically");
|
|
|
35
118
|
program.option("--no-git", "Disable auto Git repository initialization");
|
|
36
119
|
program.option(
|
|
37
120
|
"--template <name>",
|
|
38
|
-
`template to choose: ${templates.join(", ")}`,
|
|
121
|
+
`template to choose: ${templates.map((v) => v.value).join(", ")}`,
|
|
39
122
|
(value) => {
|
|
40
|
-
if (!templates.
|
|
123
|
+
if (!templates.some((item) => item.value === value)) {
|
|
41
124
|
throw new Error(`Invalid template: ${value}.`);
|
|
42
125
|
}
|
|
43
126
|
return value;
|
|
@@ -71,29 +154,7 @@ async function main(config) {
|
|
|
71
154
|
return select({
|
|
72
155
|
message: "Choose a template",
|
|
73
156
|
initialValue: "+next+fuma-docs-mdx",
|
|
74
|
-
options:
|
|
75
|
-
{
|
|
76
|
-
value: "+next+fuma-docs-mdx",
|
|
77
|
-
label: "Next.js: Fumadocs MDX",
|
|
78
|
-
hint: "recommended"
|
|
79
|
-
},
|
|
80
|
-
{
|
|
81
|
-
value: "+next+content-collections",
|
|
82
|
-
label: "Next.js: Content Collections"
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
value: "waku",
|
|
86
|
-
label: "Waku: Fumadocs MDX"
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
value: "react-router",
|
|
90
|
-
label: "React Router: Fumadocs MDX (not RSC)"
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
value: "tanstack-start",
|
|
94
|
-
label: "Tanstack Start: Fumadocs MDX (not RSC)"
|
|
95
|
-
}
|
|
96
|
-
]
|
|
157
|
+
options: templates
|
|
97
158
|
});
|
|
98
159
|
},
|
|
99
160
|
src: async (v) => {
|
|
@@ -131,6 +192,23 @@ async function main(config) {
|
|
|
131
192
|
]
|
|
132
193
|
});
|
|
133
194
|
},
|
|
195
|
+
search: () => {
|
|
196
|
+
return select({
|
|
197
|
+
message: "Choose a search solution?",
|
|
198
|
+
options: [
|
|
199
|
+
{
|
|
200
|
+
value: "orama",
|
|
201
|
+
label: "Default",
|
|
202
|
+
hint: "local search powered by Orama, recommended"
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
value: "orama-cloud",
|
|
206
|
+
label: "Orama Cloud",
|
|
207
|
+
hint: "3rd party search solution, signup needed"
|
|
208
|
+
}
|
|
209
|
+
]
|
|
210
|
+
});
|
|
211
|
+
},
|
|
134
212
|
installDeps: () => {
|
|
135
213
|
if (config.install !== void 0)
|
|
136
214
|
return Promise.resolve(config.install);
|
|
@@ -147,8 +225,8 @@ async function main(config) {
|
|
|
147
225
|
}
|
|
148
226
|
);
|
|
149
227
|
const projectName = options.name.toLowerCase().replace(/\s/, "-");
|
|
150
|
-
const dest =
|
|
151
|
-
const destDir = await
|
|
228
|
+
const dest = path2.resolve(cwd, projectName);
|
|
229
|
+
const destDir = await fs2.readdir(dest).catch(() => null);
|
|
152
230
|
if (destDir && destDir.length > 0) {
|
|
153
231
|
const del = await confirm({
|
|
154
232
|
message: `directory ${projectName} already exists, do you want to delete its files?`
|
|
@@ -162,7 +240,7 @@ async function main(config) {
|
|
|
162
240
|
info2.start(`Deleting files in ${projectName}`);
|
|
163
241
|
await Promise.all(
|
|
164
242
|
destDir.map((item) => {
|
|
165
|
-
return
|
|
243
|
+
return fs2.rm(path2.join(dest, item), {
|
|
166
244
|
recursive: true,
|
|
167
245
|
force: true
|
|
168
246
|
});
|
|
@@ -175,13 +253,13 @@ async function main(config) {
|
|
|
175
253
|
info.start(`Generating Project`);
|
|
176
254
|
await create({
|
|
177
255
|
packageManager: manager,
|
|
178
|
-
tailwindcss: true,
|
|
179
256
|
template: options.template,
|
|
180
257
|
outputDir: dest,
|
|
181
258
|
installDeps: options.installDeps,
|
|
182
259
|
lint: options.lint,
|
|
183
260
|
useSrcDir: options.src,
|
|
184
261
|
initializeGit: config.git ?? true,
|
|
262
|
+
plugins: options.search === "orama-cloud" ? [orama_cloud_default] : [],
|
|
185
263
|
log: (message) => {
|
|
186
264
|
info.message(message);
|
|
187
265
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-fumadocs-app",
|
|
3
|
-
"version": "16.0.
|
|
3
|
+
"version": "16.0.2",
|
|
4
4
|
"description": "Create a new documentation site with Fumadocs",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"NextJs",
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
"clean": "rimraf dist",
|
|
46
46
|
"dev": "tsup --watch",
|
|
47
47
|
"lint": "eslint .",
|
|
48
|
-
"types:check": "tsc --noEmit"
|
|
48
|
+
"types:check": "tsc --noEmit",
|
|
49
|
+
"sync": "bun ./scripts/sync.ts"
|
|
49
50
|
}
|
|
50
51
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import Link from 'next/link';
|
|
2
|
+
|
|
3
|
+
export default function HomePage() {
|
|
4
|
+
return (
|
|
5
|
+
<div className="flex flex-col justify-center text-center flex-1">
|
|
6
|
+
<h1 className="text-2xl font-bold mb-4">Hello World</h1>
|
|
7
|
+
<p>
|
|
8
|
+
You can open{' '}
|
|
9
|
+
<Link href="/docs" className="font-medium underline">
|
|
10
|
+
/docs
|
|
11
|
+
</Link>{' '}
|
|
12
|
+
and see the documentation.
|
|
13
|
+
</p>
|
|
14
|
+
</div>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
@@ -21,7 +21,7 @@ export function getPageImage(page: InferPageType<typeof source>) {
|
|
|
21
21
|
export async function getLLMText(page: InferPageType<typeof source>) {
|
|
22
22
|
const processed = await page.data.getText('processed');
|
|
23
23
|
|
|
24
|
-
return `# ${page.data.title}
|
|
24
|
+
return `# ${page.data.title}
|
|
25
25
|
|
|
26
26
|
${processed}`;
|
|
27
27
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import defaultMdxComponents from 'fumadocs-ui/mdx';
|
|
2
2
|
import type { MDXComponents } from 'mdx/types';
|
|
3
3
|
|
|
4
|
-
// use this function to get MDX components, you will need it for rendering MDX
|
|
5
4
|
export function getMDXComponents(components?: MDXComponents): MDXComponents {
|
|
6
5
|
return {
|
|
7
6
|
...defaultMdxComponents,
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "example-next-mdx",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"build": "next build",
|
|
7
|
+
"dev": "next dev",
|
|
8
|
+
"start": "next start"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"fumadocs-core": "workspace:*",
|
|
12
|
+
"fumadocs-mdx": "workspace:*",
|
|
13
|
+
"fumadocs-ui": "workspace:*",
|
|
14
|
+
"lucide-react": "^0.546.0",
|
|
15
|
+
"next": "16.0.0",
|
|
16
|
+
"react": "^19.2.0",
|
|
17
|
+
"react-dom": "^19.2.0"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@tailwindcss/postcss": "^4.1.15",
|
|
21
|
+
"@types/mdx": "^2.0.13",
|
|
22
|
+
"@types/node": "^24.9.1",
|
|
23
|
+
"@types/react": "^19.2.2",
|
|
24
|
+
"@types/react-dom": "^19.2.2",
|
|
25
|
+
"postcss": "^8.5.6",
|
|
26
|
+
"tailwindcss": "^4.1.15",
|
|
27
|
+
"typescript": "^5.9.3"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { RootProvider } from 'fumadocs-ui/provider/next';
|
|
2
|
-
import '
|
|
2
|
+
import './global.css';
|
|
3
3
|
import { Inter } from 'next/font/google';
|
|
4
|
+
import SearchDialog from '@/components/search';
|
|
4
5
|
|
|
5
6
|
const inter = Inter({
|
|
6
7
|
subsets: ['latin'],
|
|
@@ -9,14 +10,8 @@ const inter = Inter({
|
|
|
9
10
|
export default function Layout({ children }: LayoutProps<'/'>) {
|
|
10
11
|
return (
|
|
11
12
|
<html lang="en" className={inter.className} suppressHydrationWarning>
|
|
12
|
-
<body
|
|
13
|
-
|
|
14
|
-
display: 'flex',
|
|
15
|
-
flexDirection: 'column',
|
|
16
|
-
minHeight: '100vh',
|
|
17
|
-
}}
|
|
18
|
-
>
|
|
19
|
-
<RootProvider>{children}</RootProvider>
|
|
13
|
+
<body className="flex flex-col min-h-screen">
|
|
14
|
+
<RootProvider search={{ SearchDialog }}>{children}</RootProvider>
|
|
20
15
|
</body>
|
|
21
16
|
</html>
|
|
22
17
|
);
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
SearchDialog,
|
|
5
|
+
SearchDialogClose,
|
|
6
|
+
SearchDialogContent,
|
|
7
|
+
SearchDialogFooter,
|
|
8
|
+
SearchDialogHeader,
|
|
9
|
+
SearchDialogIcon,
|
|
10
|
+
SearchDialogInput,
|
|
11
|
+
SearchDialogList,
|
|
12
|
+
SearchDialogOverlay,
|
|
13
|
+
type SharedProps,
|
|
14
|
+
} from 'fumadocs-ui/components/dialog/search';
|
|
15
|
+
import { useDocsSearch } from 'fumadocs-core/search/client';
|
|
16
|
+
import { OramaCloud } from '@orama/core';
|
|
17
|
+
import { useI18n } from 'fumadocs-ui/contexts/i18n';
|
|
18
|
+
|
|
19
|
+
const client = new OramaCloud({
|
|
20
|
+
projectId: process.env.NEXT_PUBLIC_ORAMA_DATASOURCE_ID,
|
|
21
|
+
apiKey: process.env.NEXT_PUBLIC_ORAMA_API_KEY,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
export default function CustomSearchDialog(props: SharedProps) {
|
|
25
|
+
const { locale } = useI18n(); // (optional) for i18n
|
|
26
|
+
const { search, setSearch, query } = useDocsSearch({
|
|
27
|
+
type: 'orama-cloud',
|
|
28
|
+
client,
|
|
29
|
+
locale,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<SearchDialog
|
|
34
|
+
search={search}
|
|
35
|
+
onSearchChange={setSearch}
|
|
36
|
+
isLoading={query.isLoading}
|
|
37
|
+
{...props}
|
|
38
|
+
>
|
|
39
|
+
<SearchDialogOverlay />
|
|
40
|
+
<SearchDialogContent>
|
|
41
|
+
<SearchDialogHeader>
|
|
42
|
+
<SearchDialogIcon />
|
|
43
|
+
<SearchDialogInput />
|
|
44
|
+
<SearchDialogClose />
|
|
45
|
+
</SearchDialogHeader>
|
|
46
|
+
<SearchDialogList items={query.data !== 'empty' ? query.data : null} />
|
|
47
|
+
<SearchDialogFooter>
|
|
48
|
+
<a
|
|
49
|
+
href="https://orama.com"
|
|
50
|
+
rel="noreferrer noopener"
|
|
51
|
+
className="ms-auto text-xs text-fd-muted-foreground"
|
|
52
|
+
>
|
|
53
|
+
Search powered by Orama
|
|
54
|
+
</a>
|
|
55
|
+
</SearchDialogFooter>
|
|
56
|
+
</SearchDialogContent>
|
|
57
|
+
</SearchDialog>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { source } from '@/lib/source';
|
|
2
|
+
import type { OramaDocument } from 'fumadocs-core/search/orama-cloud';
|
|
3
|
+
|
|
4
|
+
export async function exportSearchIndexes() {
|
|
5
|
+
return source.getPages().map((page) => {
|
|
6
|
+
return {
|
|
7
|
+
id: page.url,
|
|
8
|
+
structured: page.data.structuredData,
|
|
9
|
+
url: page.url,
|
|
10
|
+
title: page.data.title,
|
|
11
|
+
description: page.data.description,
|
|
12
|
+
} satisfies OramaDocument;
|
|
13
|
+
});
|
|
14
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
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/react-router';
|
|
10
|
+
import type { Route } from './+types/root';
|
|
11
|
+
import './app.css';
|
|
12
|
+
import SearchDialog from '@/components/search';
|
|
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 className="flex flex-col min-h-screen">
|
|
37
|
+
<RootProvider search={{ SearchDialog }}>{children}</RootProvider>
|
|
38
|
+
<ScrollRestoration />
|
|
39
|
+
<Scripts />
|
|
40
|
+
</body>
|
|
41
|
+
</html>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export default function App() {
|
|
46
|
+
return <Outlet />;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) {
|
|
50
|
+
let message = 'Oops!';
|
|
51
|
+
let details = 'An unexpected error occurred.';
|
|
52
|
+
let stack: string | undefined;
|
|
53
|
+
|
|
54
|
+
if (isRouteErrorResponse(error)) {
|
|
55
|
+
message = error.status === 404 ? '404' : 'Error';
|
|
56
|
+
details =
|
|
57
|
+
error.status === 404
|
|
58
|
+
? 'The requested page could not be found.'
|
|
59
|
+
: error.statusText || details;
|
|
60
|
+
} else if (import.meta.env.DEV && error && error instanceof Error) {
|
|
61
|
+
details = error.message;
|
|
62
|
+
stack = error.stack;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<main className="pt-16 p-4 container mx-auto">
|
|
67
|
+
<h1>{message}</h1>
|
|
68
|
+
<p>{details}</p>
|
|
69
|
+
{stack && (
|
|
70
|
+
<pre className="w-full p-4 overflow-x-auto">
|
|
71
|
+
<code>{stack}</code>
|
|
72
|
+
</pre>
|
|
73
|
+
)}
|
|
74
|
+
</main>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { index, route, type RouteConfig } from '@react-router/dev/routes';
|
|
2
|
+
|
|
3
|
+
export default [
|
|
4
|
+
index('routes/home.tsx'),
|
|
5
|
+
route('docs/*', 'docs/page.tsx'),
|
|
6
|
+
route('api/search', 'docs/search.ts'),
|
|
7
|
+
route('static.json', 'routes/static.ts'),
|
|
8
|
+
] satisfies RouteConfig;
|
|
@@ -0,0 +1,76 @@
|
|
|
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/react-router';
|
|
10
|
+
import type { Route } from './+types/root';
|
|
11
|
+
import './app.css';
|
|
12
|
+
import SearchDialog from '@/components/search';
|
|
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 className="flex flex-col min-h-screen">
|
|
37
|
+
<RootProvider search={{ SearchDialog }}>{children}</RootProvider>
|
|
38
|
+
<ScrollRestoration />
|
|
39
|
+
<Scripts />
|
|
40
|
+
</body>
|
|
41
|
+
</html>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export default function App() {
|
|
46
|
+
return <Outlet />;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) {
|
|
50
|
+
let message = 'Oops!';
|
|
51
|
+
let details = 'An unexpected error occurred.';
|
|
52
|
+
let stack: string | undefined;
|
|
53
|
+
|
|
54
|
+
if (isRouteErrorResponse(error)) {
|
|
55
|
+
message = error.status === 404 ? '404' : 'Error';
|
|
56
|
+
details =
|
|
57
|
+
error.status === 404
|
|
58
|
+
? 'The requested page could not be found.'
|
|
59
|
+
: error.statusText || details;
|
|
60
|
+
} else if (import.meta.env.DEV && error && error instanceof Error) {
|
|
61
|
+
details = error.message;
|
|
62
|
+
stack = error.stack;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<main className="pt-16 p-4 container mx-auto">
|
|
67
|
+
<h1>{message}</h1>
|
|
68
|
+
<p>{details}</p>
|
|
69
|
+
{stack && (
|
|
70
|
+
<pre className="w-full p-4 overflow-x-auto">
|
|
71
|
+
<code>{stack}</code>
|
|
72
|
+
</pre>
|
|
73
|
+
)}
|
|
74
|
+
</main>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { index, route, type RouteConfig } from '@react-router/dev/routes';
|
|
2
|
+
|
|
3
|
+
export default [
|
|
4
|
+
index('routes/home.tsx'),
|
|
5
|
+
route('docs/*', 'docs/page.tsx'),
|
|
6
|
+
route('api/search', 'docs/search.ts'),
|
|
7
|
+
route('static.json', 'routes/static.ts'),
|
|
8
|
+
] satisfies RouteConfig;
|