create-fumadocs-app 16.0.33 → 16.0.35

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 (95) hide show
  1. package/dist/bin.d.ts +1 -1
  2. package/dist/bin.js +155 -206
  3. package/dist/bin.js.map +1 -0
  4. package/dist/constants-DkM_O5ux.js +140 -0
  5. package/dist/constants-DkM_O5ux.js.map +1 -0
  6. package/dist/index-CulTgtuF.d.ts +67 -0
  7. package/dist/index-CulTgtuF.d.ts.map +1 -0
  8. package/dist/index.d.ts +2 -63
  9. package/dist/index.js +4 -7
  10. package/dist/plugins/biome.base.d.ts +40 -45
  11. package/dist/plugins/biome.base.d.ts.map +1 -0
  12. package/dist/plugins/biome.base.js +37 -17
  13. package/dist/plugins/biome.base.js.map +1 -0
  14. package/dist/plugins/biome.d.ts +4 -2
  15. package/dist/plugins/biome.d.ts.map +1 -0
  16. package/dist/plugins/biome.js +30 -40
  17. package/dist/plugins/biome.js.map +1 -0
  18. package/dist/plugins/biome.next.d.ts +41 -49
  19. package/dist/plugins/biome.next.d.ts.map +1 -0
  20. package/dist/plugins/biome.next.js +43 -17
  21. package/dist/plugins/biome.next.js.map +1 -0
  22. package/dist/plugins/eslint.d.ts +4 -2
  23. package/dist/plugins/eslint.d.ts.map +1 -0
  24. package/dist/plugins/eslint.js +30 -33
  25. package/dist/plugins/eslint.js.map +1 -0
  26. package/dist/plugins/next-use-src.d.ts +5 -2
  27. package/dist/plugins/next-use-src.d.ts.map +1 -0
  28. package/dist/plugins/next-use-src.js +33 -35
  29. package/dist/plugins/next-use-src.js.map +1 -0
  30. package/dist/plugins/orama-cloud.d.ts +4 -2
  31. package/dist/plugins/orama-cloud.d.ts.map +1 -0
  32. package/dist/plugins/orama-cloud.js +211 -276
  33. package/dist/plugins/orama-cloud.js.map +1 -0
  34. package/dist/src-z4C6ZcL7.js +89 -0
  35. package/dist/src-z4C6ZcL7.js.map +1 -0
  36. package/package.json +19 -18
  37. package/template/+next+fuma-docs-mdx/app/docs/[[...slug]]/page.tsx +2 -9
  38. package/template/+next+fuma-docs-mdx/app/docs/layout.tsx +1 -1
  39. package/template/+next+fuma-docs-mdx/app/og/docs/[...slug]/route.tsx +2 -9
  40. package/template/+next+fuma-docs-mdx/package.json +3 -3
  41. package/template/+next+fuma-docs-mdx/source.config.ts +1 -6
  42. package/template/+next+fuma-docs-mdx+static/README.md +45 -0
  43. package/template/+next+fuma-docs-mdx+static/app/(home)/layout.tsx +6 -0
  44. package/template/+next+fuma-docs-mdx+static/app/(home)/page.tsx +16 -0
  45. package/template/+next+fuma-docs-mdx+static/app/api/search/route.ts +9 -0
  46. package/template/+next+fuma-docs-mdx+static/app/docs/[[...slug]]/page.tsx +47 -0
  47. package/template/+next+fuma-docs-mdx+static/app/docs/layout.tsx +11 -0
  48. package/template/+next+fuma-docs-mdx+static/app/global.css +3 -0
  49. package/template/+next+fuma-docs-mdx+static/app/layout.tsx +17 -0
  50. package/template/+next+fuma-docs-mdx+static/app/llms-full.txt/route.ts +10 -0
  51. package/template/+next+fuma-docs-mdx+static/app/og/docs/[...slug]/route.tsx +27 -0
  52. package/template/+next+fuma-docs-mdx+static/components/provider.tsx +8 -0
  53. package/template/+next+fuma-docs-mdx+static/components/search.tsx +46 -0
  54. package/template/+next+fuma-docs-mdx+static/content/docs/index.mdx +13 -0
  55. package/template/+next+fuma-docs-mdx+static/content/docs/test.mdx +17 -0
  56. package/template/+next+fuma-docs-mdx+static/example.gitignore +26 -0
  57. package/template/+next+fuma-docs-mdx+static/lib/layout.shared.tsx +9 -0
  58. package/template/+next+fuma-docs-mdx+static/lib/source.ts +26 -0
  59. package/template/+next+fuma-docs-mdx+static/mdx-components.tsx +9 -0
  60. package/template/+next+fuma-docs-mdx+static/next.config.mjs +11 -0
  61. package/template/+next+fuma-docs-mdx+static/package.json +32 -0
  62. package/template/+next+fuma-docs-mdx+static/postcss.config.mjs +5 -0
  63. package/template/+next+fuma-docs-mdx+static/source.config.ts +22 -0
  64. package/template/+next+fuma-docs-mdx+static/tsconfig.json +36 -0
  65. package/template/+orama-cloud/@app/components/search.tsx +1 -6
  66. package/template/react-router/app/docs/page.tsx +1 -6
  67. package/template/react-router/app/root.tsx +1 -3
  68. package/template/react-router/package.json +7 -7
  69. package/template/react-router/tsconfig.json +1 -6
  70. package/template/react-router-spa/app/components/search.tsx +1 -6
  71. package/template/react-router-spa/app/docs/page.tsx +2 -7
  72. package/template/react-router-spa/app/root.tsx +1 -3
  73. package/template/react-router-spa/package.json +7 -7
  74. package/template/react-router-spa/tsconfig.json +1 -6
  75. package/template/tanstack-start/content/docs/index.mdx +1 -4
  76. package/template/tanstack-start/package.json +7 -8
  77. package/template/tanstack-start/src/components/not-found.tsx +2 -2
  78. package/template/tanstack-start/src/routes/__root.tsx +1 -6
  79. package/template/tanstack-start/src/routes/docs/$.tsx +1 -6
  80. package/template/tanstack-start/src/routes/index.tsx +1 -3
  81. package/template/tanstack-start/vite.config.ts +0 -4
  82. package/template/tanstack-start-spa/content/docs/index.mdx +1 -4
  83. package/template/tanstack-start-spa/package.json +9 -9
  84. package/template/tanstack-start-spa/src/components/not-found.tsx +2 -2
  85. package/template/tanstack-start-spa/src/components/search.tsx +1 -6
  86. package/template/tanstack-start-spa/src/routes/__root.tsx +1 -6
  87. package/template/tanstack-start-spa/src/routes/docs/$.tsx +2 -7
  88. package/template/waku/package.json +6 -4
  89. package/template/waku/src/lib/source.ts +2 -0
  90. package/template/waku/src/pages/docs/[...slugs].tsx +2 -9
  91. package/template/waku/src/pages/docs/_layout.tsx +1 -1
  92. package/dist/chunk-7QPQHHV2.js +0 -179
  93. package/dist/chunk-BEZTHMLF.js +0 -51
  94. package/dist/chunk-EM5SN2F4.js +0 -130
  95. package/dist/chunk-JCFTHRDR.js +0 -50
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orama-cloud.js","names":["path","SyntaxKind","path","path","tasks: Promise<unknown>[]"],"sources":["../../src/transform/shared.ts","../../src/transform/react-router.ts","../../src/transform/tanstack-start.ts","../../src/transform/index.ts","../../src/plugins/orama-cloud.ts"],"sourcesContent":["import { IndentationText, Project, QuoteKind } from 'ts-morph';\nimport fs from 'node:fs/promises';\n\nconst project = new Project({\n manipulationSettings: {\n indentationText: IndentationText.TwoSpaces,\n quoteKind: QuoteKind.Single,\n },\n});\n\nexport async function createSourceFile(path: string) {\n return project.createSourceFile(path, (await fs.readFile(path)).toString(), {\n overwrite: true,\n });\n}\n\nexport function getCodeValue(v: string) {\n return new Function(`return ${v}`)();\n}\n","import { ArrayLiteralExpression, MethodDeclaration, SourceFile, ts } from 'ts-morph';\nimport { getCodeValue } from '@/transform/shared';\nimport SyntaxKind = ts.SyntaxKind;\n\n/**\n * filter items in a specific array initializer in the prerender function\n */\nexport function filterReactRouterPrerenderArray(\n sourceFile: SourceFile,\n array: 'paths' | 'excluded',\n filter: (item: string) => boolean,\n) {\n const methodBody = getPrerenderMethod(sourceFile)?.getBody();\n if (!methodBody) return;\n\n const initializer = methodBody\n .getDescendantsOfKind(SyntaxKind.VariableDeclaration)\n .find((item) => item.getName() === array)\n ?.getInitializerIfKind(SyntaxKind.ArrayLiteralExpression);\n\n if (!initializer) return;\n for (const element of initializer.getElements()) {\n if (!filter(getCodeValue(element.getText()))) {\n initializer.removeElement(element);\n }\n }\n}\n\n/**\n * Add a new route to route config\n */\nexport function addReactRouterRoute(\n sourceFile: SourceFile,\n routes: { path: string; entry: string }[],\n) {\n modifyReactRouterRoutes(sourceFile, (arr) => {\n for (const { path, entry } of routes) {\n arr.addElement(`route('${path}', '${entry}')`);\n }\n });\n}\n\n/**\n * Remove routes from route config (root level only)\n */\nexport function filterReactRouterRoute(\n sourceFile: SourceFile,\n filter: (item: { path: string; entry: string }) => boolean,\n) {\n modifyReactRouterRoutes(sourceFile, (arr) => {\n for (const element of arr.getElements()) {\n if (\n !element.isKind(SyntaxKind.CallExpression) ||\n element.getFirstChildByKind(SyntaxKind.Identifier)?.getText() !== 'route'\n )\n continue;\n const args = element.getArguments();\n\n if (\n filter({\n path: getCodeValue(args[0].getText()),\n entry: getCodeValue(args[1].getText()),\n })\n )\n continue;\n\n arr.removeElement(element);\n }\n });\n}\n\nexport function modifyReactRouterRoutes(\n sourceFile: SourceFile,\n mod: (array: ArrayLiteralExpression) => void,\n) {\n const initializer = sourceFile\n .getDefaultExportSymbol()\n ?.getValueDeclaration()\n ?.getFirstDescendantByKind(SyntaxKind.ArrayLiteralExpression);\n if (initializer) mod(initializer);\n}\n\n/**\n * Find the prerender method from the config\n */\nfunction getPrerenderMethod(sourceFile: SourceFile): MethodDeclaration | null {\n return (\n sourceFile\n .getDefaultExportSymbol()\n ?.getValueDeclaration()\n ?.getFirstDescendantByKind(SyntaxKind.ObjectLiteralExpression)\n ?.getProperty('prerender')\n ?.asKind(SyntaxKind.MethodDeclaration) ?? null\n );\n}\n","import { CallExpression, SourceFile, SyntaxKind } from 'ts-morph';\nimport { getCodeValue } from '@/transform/shared';\n\n/**\n * Add path to the `pages` array in tanstack start vite config.\n *\n * If the `pages` property doesn't exist, create one.\n */\nexport function addTanstackPrerender(sourceFile: SourceFile, paths: string[]) {\n const optionsArg = getTanstackStartCall(sourceFile)\n ?.getArguments()[0]\n ?.asKind(SyntaxKind.ObjectLiteralExpression);\n if (!optionsArg) {\n return;\n }\n\n const pagesProperty = optionsArg.getProperty('pages')?.asKind(SyntaxKind.PropertyAssignment);\n\n function toItem(path: string) {\n return `{ path: '${path}' }`;\n }\n\n if (pagesProperty) {\n const initializer = pagesProperty.getInitializerIfKindOrThrow(\n SyntaxKind.ArrayLiteralExpression,\n );\n\n const existingPaths = new Set<string>();\n for (const element of initializer.getElements()) {\n const value = element\n .asKind(SyntaxKind.ObjectLiteralExpression)\n ?.getProperty('path')\n ?.asKind(SyntaxKind.PropertyAssignment)\n ?.getInitializer()\n ?.getText();\n\n if (value) {\n existingPaths.add(getCodeValue(value));\n }\n }\n\n for (const path of paths) {\n if (existingPaths.has(path)) continue;\n initializer.addElement(toItem(path));\n }\n } else {\n optionsArg.addProperty(`pages: [\\n${paths.map((path) => ` ${toItem(path)}`).join(',\\n')}\\n]`);\n }\n}\n\n/**\n * Find the tanstackStart call expression\n */\nfunction getTanstackStartCall(sourceFile: SourceFile): CallExpression | undefined {\n const pluginsProperty = sourceFile\n .getDefaultExportSymbol()\n ?.getValueDeclaration()\n ?.getFirstDescendantByKind(SyntaxKind.ObjectLiteralExpression)\n ?.getProperty('plugins')\n ?.getFirstChildByKind(SyntaxKind.ArrayLiteralExpression);\n\n if (!pluginsProperty) return;\n\n for (const element of pluginsProperty.getElements()) {\n const expression = element.asKind(SyntaxKind.CallExpression);\n if (expression?.getFirstChildByKind(SyntaxKind.Identifier)?.getText() === 'tanstackStart') {\n return expression;\n }\n }\n}\n","import { TemplatePluginContext } from '@/index';\nimport { createSourceFile } from '@/transform/shared';\nimport path from 'node:path';\nimport {\n addReactRouterRoute,\n filterReactRouterPrerenderArray,\n filterReactRouterRoute,\n} from '@/transform/react-router';\nimport fs from 'node:fs/promises';\nimport { addTanstackPrerender } from '@/transform/tanstack-start';\nimport { StructureKind, SyntaxKind } from 'ts-morph';\n\ninterface RootLayoutMod {\n addSearchDialog: (specifier: string) => void;\n}\n\nexport async function rootProvider(\n { appDir, template }: TemplatePluginContext,\n fn: (mod: RootLayoutMod) => void,\n) {\n const file = await createSourceFile(path.join(appDir, template.rootProviderPath));\n fn({\n addSearchDialog(specifier) {\n const elements = file.getDescendantsOfKind(SyntaxKind.JsxElement);\n\n for (const element of elements) {\n const provider = element.getFirstChildByKind(SyntaxKind.JsxOpeningElement);\n if (provider?.getTagNameNode().getText() !== 'RootProvider') continue;\n\n // Skip if search prop already exists\n if (\n provider\n .getAttributes()\n .some(\n (attr) =>\n attr.isKind(SyntaxKind.JsxAttribute) && attr.getNameNode().getText() === 'search',\n )\n )\n continue;\n\n provider.addAttribute({\n kind: StructureKind.JsxAttribute,\n name: 'search',\n initializer: '{{ SearchDialog }}',\n });\n file.addImportDeclaration({\n moduleSpecifier: specifier,\n defaultImport: 'SearchDialog',\n });\n break;\n }\n },\n });\n await file.save();\n}\n\ninterface ReactRouterRoutesMod {\n /**\n * @param path API route's path\n * @param entry route's file path\n * @param code create the file if specified\n */\n addRoute: (path: string, entry: string, code?: string) => void;\n\n /**\n * @param path API route's path\n */\n removeRoute: (path: string) => void;\n}\n\nexport async function reactRouterRoutes(\n { dest, appDir }: TemplatePluginContext,\n fn: (mod: ReactRouterRoutesMod) => void,\n) {\n const configFile = await createSourceFile(path.join(dest, 'react-router.config.ts'));\n const routesFile = await createSourceFile(path.join(appDir, 'routes.ts'));\n const tasks: Promise<unknown>[] = [];\n\n function normalizePath(v: string) {\n return v.split('/').filter(Boolean).join('/');\n }\n\n fn({\n addRoute: (p, entry, code) => {\n addReactRouterRoute(routesFile, [{ path: p, entry }]);\n\n if (code) {\n tasks.push(fs.writeFile(path.join(appDir, entry), code));\n }\n },\n removeRoute: (p) => {\n const normalizedPath = normalizePath(p);\n\n filterReactRouterRoute(routesFile, (item) => {\n if (normalizePath(item.path) !== normalizedPath) return true;\n\n tasks.push(fs.unlink(path.join(appDir, item.entry)).catch(() => null));\n return false;\n });\n\n filterReactRouterPrerenderArray(\n configFile,\n 'excluded',\n (item) => normalizePath(item) !== normalizedPath,\n );\n\n filterReactRouterPrerenderArray(\n configFile,\n 'paths',\n (item) => normalizePath(item) !== normalizedPath,\n );\n },\n });\n\n await Promise.all([...tasks, routesFile.save(), configFile.save()]);\n}\n\nexport interface TanstackStartRoutesMod {\n addRoute: (options: {\n /**\n * file path relative to `routes`\n */\n path: string;\n\n /**\n * Generated route path of `path`\n */\n route: string;\n\n /**\n * if specified, create the file\n */\n code?: string;\n\n /**\n * if true, add to prerender list\n */\n prerender?: boolean;\n }) => void;\n\n removeRoute: (options: {\n /**\n * file path relative to routes directory\n */\n path: string;\n\n route: string;\n }) => void;\n}\n\nexport async function tanstackStartRoutes(\n { appDir, dest }: TemplatePluginContext,\n fn: (mod: TanstackStartRoutesMod) => void,\n) {\n const configFile = await createSourceFile(path.join(dest, 'vite.config.ts'));\n const tasks: Promise<unknown>[] = [];\n\n fn({\n addRoute(options) {\n if (options.code) {\n tasks.push(fs.writeFile(path.join(appDir, 'routes', options.path), options.code));\n }\n\n if (options.prerender) {\n addTanstackPrerender(configFile, [options.route]);\n }\n },\n removeRoute(options) {\n tasks.push(fs.unlink(path.join(appDir, 'routes', options.path)).catch(() => null));\n },\n });\n\n await Promise.all([...tasks, configFile.save()]);\n}\n","import { TemplatePlugin } from '@/index';\nimport { copy, pick, writeFile } from '@/utils';\nimport path from 'node:path';\nimport { depVersions, sourceDir } from '@/constants';\nimport fs from 'node:fs/promises';\nimport { reactRouterRoutes, rootProvider, tanstackStartRoutes } from '@/transform';\n\nexport function oramaCloud(): TemplatePlugin {\n return {\n packageJson(packageJson) {\n return {\n ...packageJson,\n scripts: {\n ...packageJson.scripts,\n build: `${packageJson.scripts!.build} && bun scripts/sync-content.ts`,\n },\n dependencies: {\n ...packageJson.dependencies,\n ...pick(depVersions, ['@orama/core']),\n },\n };\n },\n readme(content) {\n return `${content}\\n\\n## Orama Cloud\n \nThis project uses Orama Cloud for 3rd party search solution.\n\nSee https://fumadocs.dev/docs/headless/search/orama-cloud for integrating Orama Cloud to Fumadocs.`;\n },\n async afterWrite() {\n const { dest, appDir, template } = this;\n await copy(path.join(sourceDir, 'template/+orama-cloud/@root'), dest);\n await copy(path.join(sourceDir, 'template/+orama-cloud/@app'), appDir);\n\n await rootProvider(this, (mod) => mod.addSearchDialog('@/components/search'));\n\n if (template.value === 'tanstack-start') {\n await tanstackStartRoutes(this, (mod) => {\n mod.addRoute({\n path: 'static[.]json.ts',\n route: '/static.json',\n code: route.tanstack,\n prerender: true,\n });\n mod.removeRoute({\n path: 'api/search.ts',\n route: '/api/search',\n });\n });\n } else if (template.value.startsWith('react-router')) {\n await reactRouterRoutes(this, (mod) => {\n mod.addRoute('static.json', 'routes/static.ts', route['react-router']);\n mod.removeRoute('api/search');\n });\n } else if (template.value.startsWith('+next')) {\n await Promise.all([\n fs.unlink(path.join(appDir, 'app/api/search/route.ts')).catch(() => null),\n writeFile(path.join(appDir, 'app/static.json/route.ts'), route.next),\n ]);\n } else {\n await Promise.all([\n fs.unlink(path.join(appDir, 'pages/api/search.ts')).catch(() => null),\n writeFile(path.join(appDir, 'pages/static.json.ts'), route.waku),\n ]);\n }\n\n const filePath = {\n '+next+fuma-docs-mdx': '.next/server/app/static.json.body',\n '+next+fuma-docs-mdx+static': '.next/server/app/static.json.body',\n 'tanstack-start': '.output/public/static.json',\n 'tanstack-start-spa': 'dist/client/static.json',\n 'react-router': 'build/client/static.json',\n 'react-router-spa': 'build/client/static.json',\n waku: 'dist/public/static.json',\n }[template.value];\n\n await writeFile(\n path.join(dest, 'scripts/sync-content.ts'),\n `import { type OramaDocument, sync } from 'fumadocs-core/search/orama-cloud';\nimport * as fs from 'node:fs/promises';\nimport { OramaCloud } from '@orama/core';\n\n// the path of pre-rendered \\`static.json\\`\nconst filePath = '${filePath}';\n\nasync function main() {\n const orama = new OramaCloud({\n projectId: process.env.NEXT_PUBLIC_ORAMA_PROJECT_ID,\n apiKey: process.env.ORAMA_PRIVATE_API_KEY,\n });\n\n const content = await fs.readFile(filePath);\n const records = JSON.parse(content.toString()) as OramaDocument[];\n\n await sync(orama, {\n index: process.env.NEXT_PUBLIC_ORAMA_DATASOURCE_ID,\n documents: records,\n });\n\n console.log(\\`search updated: \\${records.length} records\\`);\n}\n\nvoid main();`,\n );\n },\n };\n}\n\nconst route = {\n next: `import { exportSearchIndexes } from '@/lib/export-search-indexes';\n\nexport const revalidate = false;\n\nexport async function GET() {\n return Response.json(await exportSearchIndexes());\n}`,\n 'react-router': `import { exportSearchIndexes } from '@/lib/export-search-indexes';\n\nexport async function loader() {\n return Response.json(await exportSearchIndexes());\n}`,\n tanstack: `import { createFileRoute } from '@tanstack/react-router';\nimport { exportSearchIndexes } from '@/lib/export-search-indexes';\n\nexport const Route = createFileRoute('/static.json')({\n server: {\n handlers: {\n GET: async () => Response.json(await exportSearchIndexes()),\n },\n },\n});`,\n waku: `import { exportSearchIndexes } from '@/lib/export-search-indexes';\n\nexport async function GET() {\n return Response.json(await exportSearchIndexes());\n}\n\nexport const getConfig = () => ({\n render: 'static',\n});`,\n};\n"],"mappings":"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"}
@@ -0,0 +1,89 @@
1
+ import { a as copy, i as templates, r as sourceDir, s as tryGitInit, t as depVersions } from "./constants-DkM_O5ux.js";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { x } from "tinyexec";
5
+
6
+ //#region src/auto-install.ts
7
+ const managers = [
8
+ "npm",
9
+ "yarn",
10
+ "bun",
11
+ "pnpm"
12
+ ];
13
+ function getPackageManager() {
14
+ const userAgent = process.env.npm_config_user_agent ?? "";
15
+ if (userAgent.startsWith("yarn")) return "yarn";
16
+ if (userAgent.startsWith("pnpm")) return "pnpm";
17
+ if (userAgent.startsWith("bun")) return "bun";
18
+ return "npm";
19
+ }
20
+ async function autoInstall(manager, dest) {
21
+ await x(manager, ["install"], {
22
+ throwOnError: true,
23
+ nodeOptions: {
24
+ env: {
25
+ ...process.env,
26
+ NODE_ENV: "development",
27
+ DISABLE_OPENCOLLECTIVE: "1"
28
+ },
29
+ cwd: dest
30
+ }
31
+ });
32
+ }
33
+
34
+ //#endregion
35
+ //#region src/index.ts
36
+ async function create(createOptions) {
37
+ const { outputDir, plugins = [], packageManager = "npm", initializeGit = false, installDeps = false, log = console.log } = createOptions;
38
+ let template = templates.find((item) => item.value === createOptions.template);
39
+ for (const plugin of plugins) template = await plugin.template?.call({ dest: outputDir }, template) ?? template;
40
+ const appDir = path.join(outputDir, template.appDir);
41
+ const projectName = path.basename(outputDir);
42
+ const pluginContext = {
43
+ template,
44
+ dest: outputDir,
45
+ log,
46
+ appDir
47
+ };
48
+ await copy(path.join(sourceDir, "template", template.value), outputDir, { rename(file) {
49
+ file = file.replace("example.gitignore", ".gitignore");
50
+ return template.rename?.(file) ?? file;
51
+ } });
52
+ const packageJsonPath = path.join(outputDir, "package.json");
53
+ let packageJson = await initPackageJson(projectName, packageJsonPath);
54
+ for (const plugin of plugins) packageJson = await plugin.packageJson?.call(pluginContext, packageJson) ?? packageJson;
55
+ await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
56
+ const readmePath = path.join(outputDir, "README.md");
57
+ let readme = `# ${projectName}\n\n${await fs.readFile(readmePath)}`;
58
+ for (const plugin of plugins) readme = await plugin.readme?.call(pluginContext, readme) ?? readme;
59
+ await fs.writeFile(readmePath, readme);
60
+ for (const plugin of plugins) await plugin.afterWrite?.call(pluginContext);
61
+ if (installDeps) try {
62
+ await autoInstall(packageManager, outputDir);
63
+ log("Installed dependencies");
64
+ } catch (err) {
65
+ log(`Failed to install dependencies: ${err}`);
66
+ }
67
+ if (initializeGit && await tryGitInit(outputDir)) log("Initialized Git repository");
68
+ }
69
+ async function initPackageJson(projectName, packageJsonPath) {
70
+ function replaceWorkspaceDeps(deps = {}) {
71
+ for (const k in deps) if (deps[k].startsWith("workspace:") && k in depVersions) deps[k] = depVersions[k];
72
+ return deps;
73
+ }
74
+ const packageJson = JSON.parse((await fs.readFile(packageJsonPath)).toString());
75
+ return {
76
+ ...packageJson,
77
+ name: projectName,
78
+ scripts: {
79
+ ...packageJson.scripts,
80
+ postinstall: "fumadocs-mdx"
81
+ },
82
+ dependencies: replaceWorkspaceDeps(packageJson.dependencies),
83
+ devDependencies: replaceWorkspaceDeps(packageJson.devDependencies)
84
+ };
85
+ }
86
+
87
+ //#endregion
88
+ export { getPackageManager as n, managers as r, create as t };
89
+ //# sourceMappingURL=src-z4C6ZcL7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"src-z4C6ZcL7.js","names":["pluginContext: TemplatePluginContext","packageJson: PackageJsonType"],"sources":["../src/auto-install.ts","../src/index.ts"],"sourcesContent":["import { x } from 'tinyexec';\n\nexport type PackageManager = (typeof managers)[number];\n\nexport const managers = ['npm', 'yarn', 'bun', 'pnpm'] as const;\n\nexport function getPackageManager(): PackageManager {\n const userAgent = process.env.npm_config_user_agent ?? '';\n\n if (userAgent.startsWith('yarn')) {\n return 'yarn';\n }\n\n if (userAgent.startsWith('pnpm')) {\n return 'pnpm';\n }\n\n if (userAgent.startsWith('bun')) {\n return 'bun';\n }\n\n return 'npm';\n}\n\nexport async function autoInstall(manager: PackageManager, dest: string) {\n await x(manager, ['install'], {\n throwOnError: true,\n nodeOptions: {\n env: {\n ...process.env,\n NODE_ENV: 'development',\n DISABLE_OPENCOLLECTIVE: '1',\n },\n cwd: dest,\n },\n });\n}\n","import path from 'node:path';\nimport fs from 'node:fs/promises';\nimport { copy, tryGitInit } from '@/utils';\nimport type { PackageManager } from './auto-install';\nimport { autoInstall } from './auto-install';\nimport { depVersions, sourceDir, type TemplateInfo, templates } from './constants';\n\nexport type Template = TemplateInfo['value'];\nexport interface Options {\n outputDir: string;\n template: Template;\n\n /**\n * the package manager to use\n *\n * @defaultValue 'npm'\n */\n packageManager?: PackageManager;\n\n installDeps?: boolean;\n initializeGit?: boolean;\n log?: (message: string) => void;\n plugins?: TemplatePlugin[];\n}\n\nexport interface TemplatePluginContext {\n template: TemplateInfo;\n log: (message: string) => void;\n /**\n * output directory\n */\n dest: string;\n\n /**\n * output directory for app code (e.g. under `/src`)\n */\n appDir: string;\n}\n\nexport type PackageJsonType = {\n name?: string;\n version?: string;\n private?: boolean;\n scripts?: Record<string, string>;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n} & Record<string, unknown>;\n\ntype Awaitable<T> = T | Promise<T>;\n\nexport interface TemplatePlugin {\n template?: (\n this: Pick<TemplatePluginContext, 'dest'>,\n info: TemplateInfo,\n ) => Awaitable<void | TemplateInfo>;\n packageJson?: (\n this: TemplatePluginContext,\n packageJson: PackageJsonType,\n ) => Awaitable<void | PackageJsonType>;\n afterWrite?: (this: TemplatePluginContext) => Awaitable<void>;\n readme?: (this: TemplatePluginContext, content: string) => Awaitable<void | string>;\n}\n\nexport async function create(createOptions: Options): Promise<void> {\n const {\n outputDir,\n plugins = [],\n packageManager = 'npm',\n initializeGit = false,\n installDeps = false,\n log = console.log,\n } = createOptions;\n\n let template = templates.find((item) => item.value === createOptions.template)!;\n for (const plugin of plugins) {\n template = (await plugin.template?.call({ dest: outputDir }, template)) ?? template;\n }\n\n const appDir = path.join(outputDir, template.appDir);\n const projectName = path.basename(outputDir);\n const pluginContext: TemplatePluginContext = {\n template,\n dest: outputDir,\n log,\n appDir,\n };\n\n await copy(path.join(sourceDir, 'template', template.value), outputDir, {\n rename(file) {\n file = file.replace('example.gitignore', '.gitignore');\n\n return template.rename?.(file) ?? file;\n },\n });\n\n const packageJsonPath = path.join(outputDir, 'package.json');\n let packageJson = await initPackageJson(projectName, packageJsonPath);\n for (const plugin of plugins) {\n packageJson = (await plugin.packageJson?.call(pluginContext, packageJson)) ?? packageJson;\n }\n await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));\n\n const readmePath = path.join(outputDir, 'README.md');\n let readme = `# ${projectName}\\n\\n${await fs.readFile(readmePath)}`;\n for (const plugin of plugins) {\n readme = (await plugin.readme?.call(pluginContext, readme)) ?? readme;\n }\n await fs.writeFile(readmePath, readme);\n\n for (const plugin of plugins) {\n await plugin.afterWrite?.call(pluginContext);\n }\n\n if (installDeps) {\n try {\n await autoInstall(packageManager, outputDir);\n log('Installed dependencies');\n } catch (err) {\n log(`Failed to install dependencies: ${err}`);\n }\n }\n\n if (initializeGit && (await tryGitInit(outputDir))) {\n log('Initialized Git repository');\n }\n}\n\nasync function initPackageJson(\n projectName: string,\n packageJsonPath: string,\n): Promise<PackageJsonType> {\n function replaceWorkspaceDeps(deps: Record<string, string> = {}) {\n for (const k in deps) {\n if (deps[k].startsWith('workspace:') && k in depVersions) {\n deps[k] = depVersions[k as keyof typeof depVersions];\n }\n }\n\n return deps;\n }\n\n const packageJson: PackageJsonType = JSON.parse((await fs.readFile(packageJsonPath)).toString());\n\n return {\n ...packageJson,\n name: projectName,\n scripts: {\n ...packageJson.scripts,\n postinstall: 'fumadocs-mdx',\n },\n dependencies: replaceWorkspaceDeps(packageJson.dependencies),\n devDependencies: replaceWorkspaceDeps(packageJson.devDependencies),\n };\n}\n"],"mappings":";;;;;;AAIA,MAAa,WAAW;CAAC;CAAO;CAAQ;CAAO;CAAO;AAEtD,SAAgB,oBAAoC;CAClD,MAAM,YAAY,QAAQ,IAAI,yBAAyB;AAEvD,KAAI,UAAU,WAAW,OAAO,CAC9B,QAAO;AAGT,KAAI,UAAU,WAAW,OAAO,CAC9B,QAAO;AAGT,KAAI,UAAU,WAAW,MAAM,CAC7B,QAAO;AAGT,QAAO;;AAGT,eAAsB,YAAY,SAAyB,MAAc;AACvE,OAAM,EAAE,SAAS,CAAC,UAAU,EAAE;EAC5B,cAAc;EACd,aAAa;GACX,KAAK;IACH,GAAG,QAAQ;IACX,UAAU;IACV,wBAAwB;IACzB;GACD,KAAK;GACN;EACF,CAAC;;;;;AC4BJ,eAAsB,OAAO,eAAuC;CAClE,MAAM,EACJ,WACA,UAAU,EAAE,EACZ,iBAAiB,OACjB,gBAAgB,OAChB,cAAc,OACd,MAAM,QAAQ,QACZ;CAEJ,IAAI,WAAW,UAAU,MAAM,SAAS,KAAK,UAAU,cAAc,SAAS;AAC9E,MAAK,MAAM,UAAU,QACnB,YAAY,MAAM,OAAO,UAAU,KAAK,EAAE,MAAM,WAAW,EAAE,SAAS,IAAK;CAG7E,MAAM,SAAS,KAAK,KAAK,WAAW,SAAS,OAAO;CACpD,MAAM,cAAc,KAAK,SAAS,UAAU;CAC5C,MAAMA,gBAAuC;EAC3C;EACA,MAAM;EACN;EACA;EACD;AAED,OAAM,KAAK,KAAK,KAAK,WAAW,YAAY,SAAS,MAAM,EAAE,WAAW,EACtE,OAAO,MAAM;AACX,SAAO,KAAK,QAAQ,qBAAqB,aAAa;AAEtD,SAAO,SAAS,SAAS,KAAK,IAAI;IAErC,CAAC;CAEF,MAAM,kBAAkB,KAAK,KAAK,WAAW,eAAe;CAC5D,IAAI,cAAc,MAAM,gBAAgB,aAAa,gBAAgB;AACrE,MAAK,MAAM,UAAU,QACnB,eAAe,MAAM,OAAO,aAAa,KAAK,eAAe,YAAY,IAAK;AAEhF,OAAM,GAAG,UAAU,iBAAiB,KAAK,UAAU,aAAa,MAAM,EAAE,CAAC;CAEzE,MAAM,aAAa,KAAK,KAAK,WAAW,YAAY;CACpD,IAAI,SAAS,KAAK,YAAY,MAAM,MAAM,GAAG,SAAS,WAAW;AACjE,MAAK,MAAM,UAAU,QACnB,UAAU,MAAM,OAAO,QAAQ,KAAK,eAAe,OAAO,IAAK;AAEjE,OAAM,GAAG,UAAU,YAAY,OAAO;AAEtC,MAAK,MAAM,UAAU,QACnB,OAAM,OAAO,YAAY,KAAK,cAAc;AAG9C,KAAI,YACF,KAAI;AACF,QAAM,YAAY,gBAAgB,UAAU;AAC5C,MAAI,yBAAyB;UACtB,KAAK;AACZ,MAAI,mCAAmC,MAAM;;AAIjD,KAAI,iBAAkB,MAAM,WAAW,UAAU,CAC/C,KAAI,6BAA6B;;AAIrC,eAAe,gBACb,aACA,iBAC0B;CAC1B,SAAS,qBAAqB,OAA+B,EAAE,EAAE;AAC/D,OAAK,MAAM,KAAK,KACd,KAAI,KAAK,GAAG,WAAW,aAAa,IAAI,KAAK,YAC3C,MAAK,KAAK,YAAY;AAI1B,SAAO;;CAGT,MAAMC,cAA+B,KAAK,OAAO,MAAM,GAAG,SAAS,gBAAgB,EAAE,UAAU,CAAC;AAEhG,QAAO;EACL,GAAG;EACH,MAAM;EACN,SAAS;GACP,GAAG,YAAY;GACf,aAAa;GACd;EACD,cAAc,qBAAqB,YAAY,aAAa;EAC5D,iBAAiB,qBAAqB,YAAY,gBAAgB;EACnE"}
package/package.json CHANGED
@@ -1,34 +1,37 @@
1
1
  {
2
2
  "name": "create-fumadocs-app",
3
- "version": "16.0.33",
3
+ "version": "16.0.35",
4
4
  "description": "Create a new documentation site with Fumadocs",
5
5
  "keywords": [
6
- "react",
7
6
  "Docs",
8
- "Fumadocs"
7
+ "Fumadocs",
8
+ "react"
9
9
  ],
10
10
  "homepage": "https://fumadocs.dev",
11
- "repository": "github:fuma-nama/fumadocs",
12
11
  "license": "MIT",
13
12
  "author": "Fuma Nama",
14
- "type": "module",
13
+ "repository": "github:fuma-nama/fumadocs",
15
14
  "bin": "./dist/bin.js",
15
+ "files": [
16
+ "dist/*",
17
+ "template/*"
18
+ ],
19
+ "type": "module",
16
20
  "module": "./dist/index.js",
17
21
  "types": "./dist/index.d.ts",
18
22
  "exports": {
19
23
  ".": {
20
- "import": "./dist/index.js",
21
- "types": "./dist/index.d.ts"
24
+ "types": "./dist/index.d.ts",
25
+ "import": "./dist/index.js"
22
26
  },
23
27
  "./plugins/*": {
24
- "import": "./dist/plugins/*.js",
25
- "types": "./dist/plugins/*.d.ts"
28
+ "types": "./dist/plugins/*.d.ts",
29
+ "import": "./dist/plugins/*.js"
26
30
  }
27
31
  },
28
- "files": [
29
- "template/*",
30
- "dist/*"
31
- ],
32
+ "publishConfig": {
33
+ "access": "public"
34
+ },
32
35
  "dependencies": {
33
36
  "@clack/prompts": "^0.11.0",
34
37
  "@commander-js/extra-typings": "^14.0.0",
@@ -41,6 +44,7 @@
41
44
  "@types/cross-spawn": "^6.0.6",
42
45
  "@types/node": "24.10.2",
43
46
  "tinyglobby": "^0.2.15",
47
+ "tsdown": "^0.18.4",
44
48
  "typescript": "^5.9.3",
45
49
  "eslint-config-custom": "0.0.0",
46
50
  "tsconfig": "0.0.0"
@@ -48,13 +52,10 @@
48
52
  "engines": {
49
53
  "node": ">=18.17.0"
50
54
  },
51
- "publishConfig": {
52
- "access": "public"
53
- },
54
55
  "scripts": {
55
- "build": "pnpm run sync && tsup",
56
+ "build": "pnpm run sync && tsdown",
56
57
  "clean": "rimraf dist",
57
- "dev": "tsup --watch",
58
+ "dev": "tsdown --watch",
58
59
  "lint": "eslint .",
59
60
  "types:check": "tsc --noEmit",
60
61
  "sync": "bun ./scripts/sync.ts"
@@ -1,10 +1,5 @@
1
1
  import { getPageImage, source } from '@/lib/source';
2
- import {
3
- DocsBody,
4
- DocsDescription,
5
- DocsPage,
6
- DocsTitle,
7
- } from 'fumadocs-ui/layouts/docs/page';
2
+ import { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/layouts/docs/page';
8
3
  import { notFound } from 'next/navigation';
9
4
  import { getMDXComponents } from '@/mdx-components';
10
5
  import type { Metadata } from 'next';
@@ -37,9 +32,7 @@ export async function generateStaticParams() {
37
32
  return source.generateParams();
38
33
  }
39
34
 
40
- export async function generateMetadata(
41
- props: PageProps<'/docs/[[...slug]]'>,
42
- ): Promise<Metadata> {
35
+ export async function generateMetadata(props: PageProps<'/docs/[[...slug]]'>): Promise<Metadata> {
43
36
  const params = await props.params;
44
37
  const page = source.getPage(params.slug);
45
38
  if (!page) notFound();
@@ -4,7 +4,7 @@ import { baseOptions } from '@/lib/layout.shared';
4
4
 
5
5
  export default function Layout({ children }: LayoutProps<'/docs'>) {
6
6
  return (
7
- <DocsLayout tree={source.pageTree} {...baseOptions()}>
7
+ <DocsLayout tree={source.getPageTree()} {...baseOptions()}>
8
8
  {children}
9
9
  </DocsLayout>
10
10
  );
@@ -5,20 +5,13 @@ import { generate as DefaultImage } from 'fumadocs-ui/og';
5
5
 
6
6
  export const revalidate = false;
7
7
 
8
- export async function GET(
9
- _req: Request,
10
- { params }: RouteContext<'/og/docs/[...slug]'>,
11
- ) {
8
+ export async function GET(_req: Request, { params }: RouteContext<'/og/docs/[...slug]'>) {
12
9
  const { slug } = await params;
13
10
  const page = source.getPage(slug.slice(0, -1));
14
11
  if (!page) notFound();
15
12
 
16
13
  return new ImageResponse(
17
- <DefaultImage
18
- title={page.data.title}
19
- description={page.data.description}
20
- site="My App"
21
- />,
14
+ <DefaultImage title={page.data.title} description={page.data.description} site="My App" />,
22
15
  {
23
16
  width: 1200,
24
17
  height: 630,
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "example-next-mdx",
2
+ "name": "example-next",
3
3
  "version": "0.0.0",
4
4
  "private": true,
5
5
  "scripts": {
@@ -12,8 +12,8 @@
12
12
  "fumadocs-core": "workspace:*",
13
13
  "fumadocs-mdx": "workspace:*",
14
14
  "fumadocs-ui": "workspace:*",
15
- "lucide-react": "^0.561.0",
16
- "next": "16.0.10",
15
+ "lucide-react": "^0.562.0",
16
+ "next": "16.1.1",
17
17
  "react": "^19.2.3",
18
18
  "react-dom": "^19.2.3"
19
19
  },
@@ -1,9 +1,4 @@
1
- import {
2
- defineConfig,
3
- defineDocs,
4
- frontmatterSchema,
5
- metaSchema,
6
- } from 'fumadocs-mdx/config';
1
+ import { defineConfig, defineDocs, frontmatterSchema, metaSchema } from 'fumadocs-mdx/config';
7
2
 
8
3
  // You can customise Zod schemas for frontmatter and `meta.json` here
9
4
  // see https://fumadocs.dev/docs/mdx/collections
@@ -0,0 +1,45 @@
1
+ This is a Next.js application generated with
2
+ [Create Fumadocs](https://github.com/fuma-nama/fumadocs).
3
+
4
+ It is a Next.js app with [Static Export](https://nextjs.org/docs/app/guides/static-exports) configured.
5
+
6
+ Run development server:
7
+
8
+ ```bash
9
+ npm run dev
10
+ # or
11
+ pnpm dev
12
+ # or
13
+ yarn dev
14
+ ```
15
+
16
+ Open http://localhost:3000 with your browser to see the result.
17
+
18
+ ## Explore
19
+
20
+ In the project, you can see:
21
+
22
+ - `lib/source.ts`: Code for content source adapter, [`loader()`](https://fumadocs.dev/docs/headless/source-api) provides the interface to access your content.
23
+ - `lib/layout.shared.tsx`: Shared options for layouts, optional but preferred to keep.
24
+
25
+ | Route | Description |
26
+ | ------------------------- | ------------------------------------------------------ |
27
+ | `app/(home)` | The route group for your landing page and other pages. |
28
+ | `app/docs` | The documentation layout and pages. |
29
+ | `app/api/search/route.ts` | The Route Handler for search. |
30
+
31
+ ### Fumadocs MDX
32
+
33
+ A `source.config.ts` config file has been included, you can customise different options like frontmatter schema.
34
+
35
+ Read the [Introduction](https://fumadocs.dev/docs/mdx) for further details.
36
+
37
+ ## Learn More
38
+
39
+ To learn more about Next.js and Fumadocs, take a look at the following
40
+ resources:
41
+
42
+ - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js
43
+ features and API.
44
+ - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
45
+ - [Fumadocs](https://fumadocs.dev) - learn about Fumadocs
@@ -0,0 +1,6 @@
1
+ import { HomeLayout } from 'fumadocs-ui/layouts/home';
2
+ import { baseOptions } from '@/lib/layout.shared';
3
+
4
+ export default function Layout({ children }: LayoutProps<'/'>) {
5
+ return <HomeLayout {...baseOptions()}>{children}</HomeLayout>;
6
+ }
@@ -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
+ }
@@ -0,0 +1,9 @@
1
+ import { source } from '@/lib/source';
2
+ import { createFromSource } from 'fumadocs-core/search/server';
3
+
4
+ export const revalidate = false;
5
+
6
+ export const { staticGET: GET } = createFromSource(source, {
7
+ // https://docs.orama.com/docs/orama-js/supported-languages
8
+ language: 'english',
9
+ });
@@ -0,0 +1,47 @@
1
+ import { getPageImage, source } from '@/lib/source';
2
+ import { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/layouts/docs/page';
3
+ import { notFound } from 'next/navigation';
4
+ import { getMDXComponents } from '@/mdx-components';
5
+ import type { Metadata } from 'next';
6
+ import { createRelativeLink } from 'fumadocs-ui/mdx';
7
+
8
+ export default async function Page(props: PageProps<'/docs/[[...slug]]'>) {
9
+ const params = await props.params;
10
+ const page = source.getPage(params.slug);
11
+ if (!page) notFound();
12
+
13
+ const MDX = page.data.body;
14
+
15
+ return (
16
+ <DocsPage toc={page.data.toc} full={page.data.full}>
17
+ <DocsTitle>{page.data.title}</DocsTitle>
18
+ <DocsDescription>{page.data.description}</DocsDescription>
19
+ <DocsBody>
20
+ <MDX
21
+ components={getMDXComponents({
22
+ // this allows you to link to other pages with relative file paths
23
+ a: createRelativeLink(source, page),
24
+ })}
25
+ />
26
+ </DocsBody>
27
+ </DocsPage>
28
+ );
29
+ }
30
+
31
+ export async function generateStaticParams() {
32
+ return source.generateParams();
33
+ }
34
+
35
+ export async function generateMetadata(props: PageProps<'/docs/[[...slug]]'>): Promise<Metadata> {
36
+ const params = await props.params;
37
+ const page = source.getPage(params.slug);
38
+ if (!page) notFound();
39
+
40
+ return {
41
+ title: page.data.title,
42
+ description: page.data.description,
43
+ openGraph: {
44
+ images: getPageImage(page).url,
45
+ },
46
+ };
47
+ }
@@ -0,0 +1,11 @@
1
+ import { source } from '@/lib/source';
2
+ import { DocsLayout } from 'fumadocs-ui/layouts/docs';
3
+ import { baseOptions } from '@/lib/layout.shared';
4
+
5
+ export default function Layout({ children }: LayoutProps<'/docs'>) {
6
+ return (
7
+ <DocsLayout tree={source.getPageTree()} {...baseOptions()}>
8
+ {children}
9
+ </DocsLayout>
10
+ );
11
+ }
@@ -0,0 +1,3 @@
1
+ @import 'tailwindcss';
2
+ @import 'fumadocs-ui/css/neutral.css';
3
+ @import 'fumadocs-ui/css/preset.css';
@@ -0,0 +1,17 @@
1
+ import { Inter } from 'next/font/google';
2
+ import { Provider } from '@/components/provider';
3
+ import './global.css';
4
+
5
+ const inter = Inter({
6
+ subsets: ['latin'],
7
+ });
8
+
9
+ export default function Layout({ children }: LayoutProps<'/'>) {
10
+ return (
11
+ <html lang="en" className={inter.className} suppressHydrationWarning>
12
+ <body className="flex flex-col min-h-screen">
13
+ <Provider>{children}</Provider>
14
+ </body>
15
+ </html>
16
+ );
17
+ }
@@ -0,0 +1,10 @@
1
+ import { getLLMText, source } from '@/lib/source';
2
+
3
+ export const revalidate = false;
4
+
5
+ export async function GET() {
6
+ const scan = source.getPages().map(getLLMText);
7
+ const scanned = await Promise.all(scan);
8
+
9
+ return new Response(scanned.join('\n\n'));
10
+ }
@@ -0,0 +1,27 @@
1
+ import { getPageImage, source } from '@/lib/source';
2
+ import { notFound } from 'next/navigation';
3
+ import { ImageResponse } from 'next/og';
4
+ import { generate as DefaultImage } from 'fumadocs-ui/og';
5
+
6
+ export const revalidate = false;
7
+
8
+ export async function GET(_req: Request, { params }: RouteContext<'/og/docs/[...slug]'>) {
9
+ const { slug } = await params;
10
+ const page = source.getPage(slug.slice(0, -1));
11
+ if (!page) notFound();
12
+
13
+ return new ImageResponse(
14
+ <DefaultImage title={page.data.title} description={page.data.description} site="My App" />,
15
+ {
16
+ width: 1200,
17
+ height: 630,
18
+ },
19
+ );
20
+ }
21
+
22
+ export function generateStaticParams() {
23
+ return source.getPages().map((page) => ({
24
+ lang: page.locale,
25
+ slug: getPageImage(page).segments,
26
+ }));
27
+ }
@@ -0,0 +1,8 @@
1
+ 'use client';
2
+ import SearchDialog from '@/components/search';
3
+ import { RootProvider } from 'fumadocs-ui/provider/next';
4
+ import { type ReactNode } from 'react';
5
+
6
+ export function Provider({ children }: { children: ReactNode }) {
7
+ return <RootProvider search={{ SearchDialog }}>{children}</RootProvider>;
8
+ }
@@ -0,0 +1,46 @@
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 search={search} onSearchChange={setSearch} isLoading={query.isLoading} {...props}>
35
+ <SearchDialogOverlay />
36
+ <SearchDialogContent>
37
+ <SearchDialogHeader>
38
+ <SearchDialogIcon />
39
+ <SearchDialogInput />
40
+ <SearchDialogClose />
41
+ </SearchDialogHeader>
42
+ <SearchDialogList items={query.data !== 'empty' ? query.data : null} />
43
+ </SearchDialogContent>
44
+ </SearchDialog>
45
+ );
46
+ }
@@ -0,0 +1,13 @@
1
+ ---
2
+ title: Hello World
3
+ description: Your first document
4
+ ---
5
+
6
+ Welcome to the docs! You can start writing documents in `/content/docs`.
7
+
8
+ ## What is Next?
9
+
10
+ <Cards>
11
+ <Card title="Learn more about Next.js" href="https://nextjs.org/docs" />
12
+ <Card title="Learn more about Fumadocs" href="https://fumadocs.dev" />
13
+ </Cards>
@@ -0,0 +1,17 @@
1
+ ---
2
+ title: Components
3
+ description: Components
4
+ ---
5
+
6
+ ## Code Block
7
+
8
+ ```js
9
+ console.log('Hello World');
10
+ ```
11
+
12
+ ## Cards
13
+
14
+ <Cards>
15
+ <Card title="Learn more about Next.js" href="https://nextjs.org/docs" />
16
+ <Card title="Learn more about Fumadocs" href="https://fumadocs.dev" />
17
+ </Cards>
@@ -0,0 +1,26 @@
1
+ # deps
2
+ /node_modules
3
+
4
+ # generated content
5
+ .source
6
+
7
+ # test & build
8
+ /coverage
9
+ /.next/
10
+ /out/
11
+ /build
12
+ *.tsbuildinfo
13
+
14
+ # misc
15
+ .DS_Store
16
+ *.pem
17
+ /.pnp
18
+ .pnp.js
19
+ npm-debug.log*
20
+ yarn-debug.log*
21
+ yarn-error.log*
22
+
23
+ # others
24
+ .env*.local
25
+ .vercel
26
+ next-env.d.ts
@@ -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: 'My App',
7
+ },
8
+ };
9
+ }