@farming-labs/docs 0.2.60 → 0.2.62

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 (51) hide show
  1. package/README.md +1 -1
  2. package/package.json +11 -1
  3. package/dist/agent-BFqyqEnC.mjs +0 -4547
  4. package/dist/agent-DlxriaTs.mjs +0 -624
  5. package/dist/agent-evals-kJs2Y9xR.mjs +0 -2144
  6. package/dist/agent-export-BgUaiW8f.mjs +0 -869
  7. package/dist/agent-scope-CCaIY1aK.mjs +0 -283
  8. package/dist/agents-Djh-HXih.mjs +0 -219
  9. package/dist/analytics-Bx44lg6d.mjs +0 -177
  10. package/dist/cli/index.d.mts +0 -15
  11. package/dist/cli/index.mjs +0 -452
  12. package/dist/client/react.d.mts +0 -45
  13. package/dist/client/react.mjs +0 -223
  14. package/dist/cloud-BH_sHX64.mjs +0 -1615
  15. package/dist/cloud-analytics-CSyFE6SS.mjs +0 -132
  16. package/dist/cloud-ask-ai-B2WnG4fF.d.mts +0 -23
  17. package/dist/cloud-ask-ai-hnJfj8-X.mjs +0 -382
  18. package/dist/code-blocks-qe0T8-xe.mjs +0 -871
  19. package/dist/codeblocks-Bq67u32v.mjs +0 -250
  20. package/dist/config-DASewQ0x.mjs +0 -363
  21. package/dist/dev-DgY5xGl9.mjs +0 -1333
  22. package/dist/docs-cloud-server.d.mts +0 -70
  23. package/dist/docs-cloud-server.mjs +0 -310
  24. package/dist/doctor-CO1VMcF_.mjs +0 -1906
  25. package/dist/downgrade-BZs86NVr.mjs +0 -184
  26. package/dist/errors-CVqZ3kOO.mjs +0 -20
  27. package/dist/golden-evaluations-BN9u2wxw.mjs +0 -1483
  28. package/dist/i18n-CAlj1ADU.mjs +0 -40
  29. package/dist/index.d.mts +0 -1099
  30. package/dist/index.mjs +0 -9
  31. package/dist/init-Bd_k06bR.mjs +0 -1233
  32. package/dist/mcp-B_yXL5G5.mjs +0 -137
  33. package/dist/mcp.d.mts +0 -287
  34. package/dist/mcp.mjs +0 -4135
  35. package/dist/metadata-BDuewuzq.mjs +0 -237
  36. package/dist/package-version-qik_4J6C.mjs +0 -128
  37. package/dist/reading-time-BkEft6SD.mjs +0 -741
  38. package/dist/review-NC-sOdXn.mjs +0 -665
  39. package/dist/robots-DskPvGPw.mjs +0 -178
  40. package/dist/robots-ltltiLJF.mjs +0 -197
  41. package/dist/search-C1JitPwi.d.mts +0 -397
  42. package/dist/search-D57JXQLj.mjs +0 -1758
  43. package/dist/search-o4Ud6OXv.mjs +0 -102
  44. package/dist/server.d.mts +0 -341
  45. package/dist/server.mjs +0 -11
  46. package/dist/sitemap-Cq-Yj_iA.mjs +0 -247
  47. package/dist/sitemap-server-C1ibVKOy.mjs +0 -1137
  48. package/dist/templates-DNw15P-x.mjs +0 -2373
  49. package/dist/types-XHABMh_f.d.mts +0 -3248
  50. package/dist/upgrade-BCJTCW3O.mjs +0 -56
  51. package/dist/utils-6UCLxv4B.mjs +0 -225
@@ -1,2373 +0,0 @@
1
- import path from "node:path";
2
-
3
- //#region src/cli/templates.ts
4
- const THEME_INFO = {
5
- fumadocs: {
6
- factory: "fumadocs",
7
- nextImport: "@farming-labs/theme",
8
- svelteImport: "@farming-labs/svelte-theme",
9
- astroImport: "@farming-labs/astro-theme",
10
- nuxtImport: "@farming-labs/nuxt-theme",
11
- nextCssImport: "default"
12
- },
13
- darksharp: {
14
- factory: "darksharp",
15
- nextImport: "@farming-labs/theme/darksharp",
16
- svelteImport: "@farming-labs/svelte-theme/darksharp",
17
- astroImport: "@farming-labs/astro-theme/darksharp",
18
- nuxtImport: "@farming-labs/nuxt-theme/darksharp",
19
- nextCssImport: "darksharp"
20
- },
21
- "pixel-border": {
22
- factory: "pixelBorder",
23
- nextImport: "@farming-labs/theme/pixel-border",
24
- svelteImport: "@farming-labs/svelte-theme/pixel-border",
25
- astroImport: "@farming-labs/astro-theme/pixel-border",
26
- nuxtImport: "@farming-labs/nuxt-theme/pixel-border",
27
- nextCssImport: "pixel-border"
28
- },
29
- colorful: {
30
- factory: "colorful",
31
- nextImport: "@farming-labs/theme/colorful",
32
- svelteImport: "@farming-labs/svelte-theme/colorful",
33
- astroImport: "@farming-labs/astro-theme/colorful",
34
- nuxtImport: "@farming-labs/nuxt-theme/colorful",
35
- nextCssImport: "colorful"
36
- },
37
- darkbold: {
38
- factory: "darkbold",
39
- nextImport: "@farming-labs/theme/darkbold",
40
- svelteImport: "@farming-labs/svelte-theme/darkbold",
41
- astroImport: "@farming-labs/astro-theme/darkbold",
42
- nuxtImport: "@farming-labs/nuxt-theme/darkbold",
43
- nextCssImport: "darkbold"
44
- },
45
- shiny: {
46
- factory: "shiny",
47
- nextImport: "@farming-labs/theme/shiny",
48
- svelteImport: "@farming-labs/svelte-theme/shiny",
49
- astroImport: "@farming-labs/astro-theme/shiny",
50
- nuxtImport: "@farming-labs/nuxt-theme/shiny",
51
- nextCssImport: "shiny"
52
- },
53
- ledger: {
54
- factory: "ledger",
55
- nextImport: "@farming-labs/theme/ledger",
56
- svelteImport: "@farming-labs/svelte-theme/ledger",
57
- astroImport: "@farming-labs/astro-theme/ledger",
58
- nuxtImport: "@farming-labs/nuxt-theme/ledger",
59
- nextCssImport: "ledger"
60
- },
61
- greentree: {
62
- factory: "greentree",
63
- nextImport: "@farming-labs/theme/greentree",
64
- svelteImport: "@farming-labs/svelte-theme/greentree",
65
- astroImport: "@farming-labs/astro-theme/greentree",
66
- nuxtImport: "@farming-labs/nuxt-theme/greentree",
67
- nextCssImport: "greentree"
68
- },
69
- concrete: {
70
- factory: "concrete",
71
- nextImport: "@farming-labs/theme/concrete",
72
- svelteImport: "@farming-labs/svelte-theme/concrete",
73
- astroImport: "@farming-labs/astro-theme/concrete",
74
- nuxtImport: "@farming-labs/nuxt-theme/concrete",
75
- nextCssImport: "concrete"
76
- },
77
- "command-grid": {
78
- factory: "commandGrid",
79
- nextImport: "@farming-labs/theme/command-grid",
80
- svelteImport: "@farming-labs/svelte-theme/command-grid",
81
- astroImport: "@farming-labs/astro-theme/command-grid",
82
- nuxtImport: "@farming-labs/nuxt-theme/command-grid",
83
- nextCssImport: "command-grid"
84
- },
85
- hardline: {
86
- factory: "hardline",
87
- nextImport: "@farming-labs/theme/hardline",
88
- svelteImport: "@farming-labs/svelte-theme/hardline",
89
- astroImport: "@farming-labs/astro-theme/hardline",
90
- nuxtImport: "@farming-labs/nuxt-theme/hardline",
91
- nextCssImport: "hardline"
92
- }
93
- };
94
- function getThemeInfo(theme) {
95
- return THEME_INFO[theme] ?? THEME_INFO.fumadocs;
96
- }
97
- function getThemeCssImport(theme) {
98
- return `@farming-labs/theme/${getThemeInfo(theme).nextCssImport}/css`;
99
- }
100
- function hasBuiltInThemeCssImport(content) {
101
- return /["']@farming-labs\/(?:theme|svelte-theme|astro-theme|nuxt-theme)\/[^"'\n]*\/css["']/.test(content);
102
- }
103
- function toPosixPath(value) {
104
- return value.replace(/\\/g, "/");
105
- }
106
- function stripScriptExtension(value) {
107
- return value.replace(/\.(?:[cm]?[jt]sx?)$/i, "");
108
- }
109
- function relativeImport(fromFile, toFile) {
110
- const fromPosix = toPosixPath(fromFile);
111
- const toPosix = stripScriptExtension(toPosixPath(toFile));
112
- const rel = path.posix.relative(path.posix.dirname(fromPosix), toPosix);
113
- return rel.startsWith(".") ? rel : `./${rel}`;
114
- }
115
- function relativeAssetPath(fromFile, toFile) {
116
- const fromPosix = toPosixPath(fromFile);
117
- const toPosix = toPosixPath(toFile);
118
- const rel = path.posix.relative(path.posix.dirname(fromPosix), toPosix);
119
- return rel.startsWith(".") ? rel : `./${rel}`;
120
- }
121
- function extractImportSpecifier(importLine) {
122
- const fromMatch = importLine.match(/\bfrom\s+["']([^"']+)["']/);
123
- if (fromMatch) return fromMatch[1];
124
- const bareImportMatch = importLine.match(/^\s*import\s+["']([^"']+)["']/);
125
- if (bareImportMatch) return bareImportMatch[1];
126
- return null;
127
- }
128
- function addImportLine(content, importLine) {
129
- if (content.includes(importLine)) return content;
130
- const specifier = extractImportSpecifier(importLine);
131
- if (specifier) {
132
- if (new RegExp(String.raw`\bimport(?:\s+type)?[\s\S]*?\bfrom\s+["']${specifier.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}["']|^\s*import\s+["']${specifier.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}["']`, "m").test(content)) return content;
133
- }
134
- const lines = content.split("\n");
135
- const lastImportIdx = lines.reduce((acc, line, index) => {
136
- const trimmed = line.trimStart();
137
- return trimmed.startsWith("import ") || trimmed.startsWith("import type ") ? index : acc;
138
- }, -1);
139
- if (lastImportIdx >= 0) lines.splice(lastImportIdx + 1, 0, importLine);
140
- else lines.unshift(importLine, "");
141
- return lines.join("\n");
142
- }
143
- function renderI18nConfig(cfg, indent = " ") {
144
- const i18n = cfg.i18n;
145
- if (!i18n || i18n.locales.length === 0) return "";
146
- return `${indent}i18n: {\n${indent} locales: [${i18n.locales.map((locale) => `"${locale}"`).join(", ")}],\n${indent} defaultLocale: "${i18n.defaultLocale}",\n${indent}},\n`;
147
- }
148
- function renderApiReferenceConfig(cfg, indent = " ") {
149
- const apiReference = cfg.apiReference;
150
- if (!apiReference) return "";
151
- const rendererLine = cfg.framework === "nextjs" ? `${indent} renderer: "fumadocs",\n` : "";
152
- return `${indent}apiReference: {\n${indent} enabled: true,\n${indent} path: "${apiReference.path}",\n${rendererLine}${indent} routeRoot: "${apiReference.routeRoot}",\n${indent}},\n`;
153
- }
154
- function toLocaleImportName(locale) {
155
- return `LocalePage_${locale.replace(/[^a-zA-Z0-9_$]/g, "_")}`;
156
- }
157
- function getThemeExportName(themeName) {
158
- const base = themeName.replace(/\.ts$/i, "").trim();
159
- if (!base) return "customTheme";
160
- return base.replace(/-([a-z])/g, (_, c) => c.toUpperCase()).replace(/^./, (c) => c.toLowerCase());
161
- }
162
- function getCustomThemeCssImportPath(globalCssRelPath, themeName) {
163
- if (globalCssRelPath.startsWith("app/")) return `../themes/${themeName}.css`;
164
- if (globalCssRelPath.startsWith("src/")) return `../../themes/${themeName}.css`;
165
- return `../themes/${themeName}.css`;
166
- }
167
- /** Content for themes/{name}.ts - createTheme with the given name */
168
- function customThemeTsTemplate(themeName) {
169
- return `\
170
- import { createTheme } from "@farming-labs/docs";
171
-
172
- export const ${getThemeExportName(themeName)} = createTheme({
173
- name: "${themeName.replace(/\.ts$/i, "")}",
174
- ui: {
175
- colors: {
176
- primary: "#e11d48",
177
- background: "#09090b",
178
- foreground: "#fafafa",
179
- muted: "#71717a",
180
- border: "#27272a",
181
- },
182
- radius: "0.5rem",
183
- },
184
- });
185
- `;
186
- }
187
- function customThemeCssTemplate(themeName) {
188
- return `\
189
- /* Custom theme: ${themeName} - edit variables and selectors as needed */
190
- @import "@farming-labs/theme/presets/black";
191
-
192
- .dark {
193
- --color-fd-primary: #e11d48;
194
- --color-fd-background: #09090b;
195
- --color-fd-border: #27272a;
196
- --radius: 0.5rem;
197
- }
198
- `;
199
- }
200
- /** Config import for Next.js root layout → root docs.config */
201
- function nextRootLayoutConfigImport(useAlias, nextAppDir = "app") {
202
- if (useAlias) return "@/docs.config";
203
- return nextAppDir === "src/app" ? "../../docs.config" : "../docs.config";
204
- }
205
- /** Config import for Next.js app/{entry}/layout.tsx → root docs.config */
206
- function nextDocsLayoutConfigImport(useAlias, nextAppDir = "app") {
207
- if (useAlias) return "@/docs.config";
208
- return nextAppDir === "src/app" ? "../../../docs.config" : "../../docs.config";
209
- }
210
- function nextApiReferenceConfigImport(useAlias, nextAppDir = "app", filePath) {
211
- if (useAlias) return "@/docs.config";
212
- return relativeImport(filePath, "docs.config.ts");
213
- }
214
- /** Config import for SvelteKit src/lib/docs.server.ts → src/lib/docs.config */
215
- function svelteServerConfigImport(useAlias) {
216
- return useAlias ? "$lib/docs.config" : "./docs.config";
217
- }
218
- /** Config import for SvelteKit src/routes/{entry}/+layout.svelte → src/lib/docs.config */
219
- function svelteLayoutConfigImport(useAlias) {
220
- return useAlias ? "$lib/docs.config" : "../../lib/docs.config";
221
- }
222
- /** Config import for SvelteKit src/routes/{entry}/[...slug]/+page.svelte → src/lib/docs.config */
223
- function sveltePageConfigImport(useAlias) {
224
- return useAlias ? "$lib/docs.config" : "../../../lib/docs.config";
225
- }
226
- /** Server import for SvelteKit +layout.server.js → src/lib/docs.server */
227
- function svelteLayoutServerImport(useAlias) {
228
- return useAlias ? "$lib/docs.server" : "../../lib/docs.server";
229
- }
230
- function svelteRouteServerImport(filePath, useAlias) {
231
- if (useAlias) return "$lib/docs.server";
232
- return relativeImport(filePath, "src/lib/docs.server.ts");
233
- }
234
- function svelteRouteConfigImport(filePath, useAlias) {
235
- if (useAlias) return "$lib/docs.config";
236
- return relativeImport(filePath, "src/lib/docs.config.ts");
237
- }
238
- function astroServerConfigImport(useAlias) {
239
- return useAlias ? "@/lib/docs.config" : "./docs.config";
240
- }
241
- function astroPageConfigImport(useAlias, depth) {
242
- if (useAlias) return "@/lib/docs.config";
243
- return `${"../".repeat(depth)}lib/docs.config`;
244
- }
245
- function astroPageServerImport(useAlias, depth) {
246
- if (useAlias) return "@/lib/docs.server";
247
- return `${"../".repeat(depth)}lib/docs.server`;
248
- }
249
- function astroRouteServerImport(filePath, useAlias) {
250
- if (useAlias) return "@/lib/docs.server";
251
- return relativeImport(filePath, "src/lib/docs.server.ts");
252
- }
253
- function astroRouteConfigImport(filePath, useAlias) {
254
- if (useAlias) return "@/lib/docs.config";
255
- return relativeImport(filePath, "src/lib/docs.config.ts");
256
- }
257
- function docsConfigTemplate(cfg) {
258
- if (cfg.theme === "custom" && cfg.customThemeName) {
259
- const exportName = getThemeExportName(cfg.customThemeName);
260
- return `\
261
- import { defineDocs } from "@farming-labs/docs";
262
- import { ${exportName} } from "${cfg.useAlias ? "@/themes/" + cfg.customThemeName.replace(/\.ts$/i, "") : "./themes/" + cfg.customThemeName.replace(/\.ts$/i, "")}";
263
-
264
- export default defineDocs({
265
- entry: "${cfg.entry}",
266
- ${renderI18nConfig(cfg)}${renderApiReferenceConfig(cfg)} theme: ${exportName}({
267
- ui: {
268
- colors: { primary: "#6366f1" },
269
- },
270
- }),
271
-
272
- metadata: {
273
- titleTemplate: "%s – ${cfg.projectName}",
274
- description: "Documentation for ${cfg.projectName}",
275
- },
276
- });
277
- `;
278
- }
279
- const t = getThemeInfo(cfg.theme);
280
- return `\
281
- import { defineDocs } from "@farming-labs/docs";
282
- import { ${t.factory} } from "${t.nextImport}";
283
-
284
- export default defineDocs({
285
- entry: "${cfg.entry}",
286
- ${renderI18nConfig(cfg)}${renderApiReferenceConfig(cfg)} theme: ${t.factory}({
287
- ui: {
288
- colors: { primary: "#6366f1" },
289
- },
290
- }),
291
-
292
- metadata: {
293
- titleTemplate: "%s – ${cfg.projectName}",
294
- description: "Documentation for ${cfg.projectName}",
295
- },
296
- });
297
- `;
298
- }
299
- function nextConfigTemplate() {
300
- return `\
301
- import { withDocs } from "@farming-labs/next/config";
302
-
303
- export default withDocs();
304
- `;
305
- }
306
- function nextConfigMergedTemplate(existingContent) {
307
- if (existingContent.includes("withDocs")) return existingContent;
308
- const lines = existingContent.split("\n");
309
- const importLine = "import { withDocs } from \"@farming-labs/next/config\";";
310
- const exportIdx = lines.findIndex((l) => l.match(/export\s+default/));
311
- if (exportIdx === -1) return `${importLine}\n\n${existingContent}\n\nexport default withDocs();\n`;
312
- const lastImportIdx = lines.reduce((acc, l, i) => l.trimStart().startsWith("import ") ? i : acc, -1);
313
- if (lastImportIdx >= 0) lines.splice(lastImportIdx + 1, 0, importLine);
314
- else lines.unshift(importLine, "");
315
- const adjustedExportIdx = exportIdx + (lastImportIdx >= 0 ? exportIdx > lastImportIdx ? 1 : 0 : 2);
316
- const simpleMatch = lines[adjustedExportIdx].match(/^(\s*export\s+default\s+)(.*?)(;?\s*)$/);
317
- if (simpleMatch) {
318
- const [, prefix, value, suffix] = simpleMatch;
319
- lines[adjustedExportIdx] = `${prefix}withDocs(${value})${suffix}`;
320
- }
321
- return lines.join("\n");
322
- }
323
- function rootLayoutTemplate(cfg, globalCssRelPath = "app/globals.css") {
324
- let cssImport;
325
- if (globalCssRelPath.startsWith("app/")) cssImport = "./" + globalCssRelPath.slice(4);
326
- else if (globalCssRelPath.startsWith("src/app/")) cssImport = "./" + globalCssRelPath.slice(8);
327
- else cssImport = "../" + globalCssRelPath;
328
- const appDir = cfg.nextAppDir ?? "app";
329
- return `\
330
- import type { Metadata } from "next";
331
- import { RootProvider } from "@farming-labs/theme";
332
- import docsConfig from "${nextRootLayoutConfigImport(cfg.useAlias, appDir)}";
333
- ${cfg.apiReference ? "import \"@farming-labs/next/api-reference.css\";\n" : ""}import "${cssImport}";
334
-
335
- export const metadata: Metadata = {
336
- title: {
337
- default: "Docs",
338
- template: docsConfig.metadata?.titleTemplate ?? "%s",
339
- },
340
- description: docsConfig.metadata?.description,
341
- };
342
-
343
- export default function RootLayout({
344
- children,
345
- }: {
346
- children: React.ReactNode;
347
- }) {
348
- return (
349
- <html lang="en" suppressHydrationWarning>
350
- <body>
351
- <RootProvider>{children}</RootProvider>
352
- </body>
353
- </html>
354
- );
355
- }
356
- `;
357
- }
358
- /**
359
- * Injects RootProvider (import + wrapper) into an existing root layout without overwriting.
360
- * Returns the modified content, or null if RootProvider is already present or injection isn't possible.
361
- */
362
- function injectRootProviderIntoLayout(content) {
363
- if (!content || content.includes("RootProvider")) return null;
364
- let out = content;
365
- const themeImport = "import { RootProvider } from \"@farming-labs/theme\";";
366
- if (!out.includes("@farming-labs/theme")) {
367
- const lines = out.split("\n");
368
- let lastImportIdx = -1;
369
- for (let i = 0; i < lines.length; i++) {
370
- const trimmed = lines[i].trimStart();
371
- if (trimmed.startsWith("import ") || trimmed.startsWith("import type ")) lastImportIdx = i;
372
- }
373
- if (lastImportIdx >= 0) {
374
- lines.splice(lastImportIdx + 1, 0, themeImport);
375
- out = lines.join("\n");
376
- } else out = themeImport + "\n" + out;
377
- }
378
- if (!out.includes("<RootProvider>")) {
379
- const childrenPattern = /\{children\}/;
380
- if (childrenPattern.test(out)) out = out.replace(childrenPattern, "<RootProvider>{children}</RootProvider>");
381
- }
382
- return out === content ? null : out;
383
- }
384
- function globalCssTemplate(theme, customThemeName, globalCssRelPath) {
385
- if (theme === "custom" && customThemeName && globalCssRelPath) return `\
386
- @import "tailwindcss";
387
- @import "${getCustomThemeCssImportPath(globalCssRelPath, customThemeName.replace(/\.css$/i, ""))}";
388
- `;
389
- return `\
390
- @import "tailwindcss";
391
- @import "${getThemeCssImport(theme)}";
392
- `;
393
- }
394
- function injectCssImport(existingContent, theme, customThemeName, globalCssRelPath) {
395
- const importLine = theme === "custom" && customThemeName && globalCssRelPath ? `@import "${getCustomThemeCssImportPath(globalCssRelPath, customThemeName.replace(/\.css$/i, ""))}";` : `@import "${getThemeCssImport(theme)}";`;
396
- if (existingContent.includes(importLine)) return null;
397
- if (theme !== "custom" && hasBuiltInThemeCssImport(existingContent)) return null;
398
- if (theme === "custom" && existingContent.includes("themes/") && existingContent.includes(".css")) return null;
399
- const lines = existingContent.split("\n");
400
- const lastImportIdx = lines.reduce((acc, l, i) => l.trimStart().startsWith("@import") ? i : acc, -1);
401
- if (lastImportIdx >= 0) lines.splice(lastImportIdx + 1, 0, importLine);
402
- else lines.unshift(importLine);
403
- return lines.join("\n");
404
- }
405
- function docsLayoutTemplate(cfg) {
406
- const appDir = cfg.nextAppDir ?? "app";
407
- return `\
408
- import docsConfig from "${nextDocsLayoutConfigImport(cfg.useAlias, appDir)}";
409
- import { createNextDocsLayout, createNextDocsMetadata } from "@farming-labs/next/layout";
410
-
411
- export const metadata = createNextDocsMetadata(docsConfig);
412
-
413
- const DocsLayout = createNextDocsLayout(docsConfig);
414
-
415
- export default function Layout({ children }: { children: React.ReactNode }) {
416
- return (
417
- <>
418
- <DocsLayout>{children}</DocsLayout>
419
- </>
420
- );
421
- }
422
- `;
423
- }
424
- function nextApiReferencePageTemplate(cfg, filePath) {
425
- const appDir = cfg.nextAppDir ?? "app";
426
- return `
427
- import docsConfig from "${nextApiReferenceConfigImport(cfg.useAlias, appDir, filePath)}";
428
- import { createNextApiReferencePage } from "@farming-labs/next/api-reference";
429
-
430
- const ApiReferencePage = createNextApiReferencePage(docsConfig);
431
-
432
- export const dynamic = "force-dynamic";
433
- export const revalidate = 0;
434
-
435
- export default ApiReferencePage;
436
- `;
437
- }
438
- function nextLocaleDocPageTemplate(defaultLocale) {
439
- return `\
440
- import type { ComponentType } from "react";
441
-
442
- type SearchParams = Promise<{ lang?: string | string[] | undefined }> | undefined;
443
-
444
- function normalizeLang(value: string | string[] | undefined) {
445
- return Array.isArray(value) ? value[0] : value;
446
- }
447
-
448
- export async function resolveLocaleDocPage<T extends ComponentType>(
449
- searchParams: SearchParams,
450
- pages: Record<string, T>,
451
- fallbackLocale = "${defaultLocale}",
452
- ) {
453
- const params = (await searchParams) ?? {};
454
- const locale = normalizeLang(params.lang) ?? fallbackLocale;
455
-
456
- return pages[locale] ?? pages[fallbackLocale];
457
- }
458
- `;
459
- }
460
- function nextLocalizedPageTemplate(options) {
461
- const importLines = options.pageImports.map(({ locale, importPath }) => `import ${toLocaleImportName(locale)} from "${importPath}";`).join("\n");
462
- const pageMap = options.pageImports.map(({ locale }) => ` ${JSON.stringify(locale)}: ${toLocaleImportName(locale)},`).join("\n");
463
- return `\
464
- ${importLines}
465
- import { resolveLocaleDocPage } from "${options.helperImport}";
466
-
467
- type PageProps = {
468
- searchParams?: Promise<{ lang?: string | string[] | undefined }>;
469
- };
470
-
471
- export default async function ${options.componentName}({ searchParams }: PageProps) {
472
- const Page = await resolveLocaleDocPage(searchParams, {
473
- ${pageMap}
474
- }, "${options.defaultLocale}");
475
-
476
- return <Page />;
477
- }
478
- `;
479
- }
480
- function postcssConfigTemplate() {
481
- return `\
482
- const config = {
483
- plugins: {
484
- "@tailwindcss/postcss": {},
485
- },
486
- };
487
-
488
- export default config;
489
- `;
490
- }
491
- /** @param useAlias - When false, paths (e.g. @/*) are omitted so no alias is added. */
492
- function tsconfigTemplate(useAlias = false) {
493
- return `\
494
- {
495
- "compilerOptions": {
496
- "target": "ES2017",
497
- "lib": ["dom", "dom.iterable", "esnext"],
498
- "allowJs": true,
499
- "skipLibCheck": true,
500
- "strict": true,
501
- "noEmit": true,
502
- "esModuleInterop": true,
503
- "module": "esnext",
504
- "moduleResolution": "bundler",
505
- "resolveJsonModule": true,
506
- "isolatedModules": true,
507
- "jsx": "react-jsx",
508
- "incremental": true,
509
- "plugins": [{ "name": "next" }]${useAlias ? ",\n \"paths\": { \"@/*\": [\"./*\"] }" : ""}
510
- },
511
- "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
512
- "exclude": ["node_modules"]
513
- }
514
- `;
515
- }
516
- function welcomePageTemplate(cfg) {
517
- const appDir = cfg.nextAppDir ?? "app";
518
- return `\
519
- ---
520
- title: "Documentation"
521
- description: "Welcome to ${cfg.projectName} documentation"
522
- ---
523
-
524
- # Welcome to ${cfg.projectName}
525
-
526
- Get started with our documentation. Browse the pages on the left to learn more.
527
-
528
- <Callout type="info">
529
- This documentation was generated by \`@farming-labs/docs\`. Edit the MDX files in \`${appDir}/${cfg.entry}/\` to customize.
530
- </Callout>
531
-
532
- ## Overview
533
-
534
- This is your documentation home page. From here you can navigate to:
535
-
536
- - [Installation](/${cfg.entry}/installation) — How to install and set up the project
537
- - [Quickstart](/${cfg.entry}/quickstart) — Get up and running in minutes
538
-
539
- ## Features
540
-
541
- - **MDX Support** — Write docs with Markdown and React components
542
- - **Syntax Highlighting** — Code blocks with automatic highlighting
543
- - **Dark Mode** — Built-in theme switching
544
- - **Search** — Full-text search across all pages
545
- - **Responsive** — Works on any screen size
546
-
547
- ---
548
-
549
- ## Next Steps
550
-
551
- Start by reading the [Installation](/${cfg.entry}/installation) guide, then follow the [Quickstart](/${cfg.entry}/quickstart) to build something.
552
- `;
553
- }
554
- function installationPageTemplate(cfg) {
555
- const t = getThemeInfo(cfg.theme);
556
- return `\
557
- ---
558
- title: "Installation"
559
- description: "How to install and set up ${cfg.projectName}"
560
- ---
561
-
562
- # Installation
563
-
564
- Follow these steps to install and configure ${cfg.projectName}.
565
-
566
- <Callout type="info">
567
- Prerequisites: Node.js 18+ and a package manager (pnpm, npm, or yarn).
568
- </Callout>
569
-
570
- ## Install Dependencies
571
-
572
- \`\`\`bash
573
- pnpm add @farming-labs/docs @farming-labs/next @farming-labs/theme
574
- \`\`\`
575
-
576
- ## Configuration
577
-
578
- Your project includes a \`docs.config.ts\` at the root:
579
-
580
- \`\`\`ts
581
- import { defineDocs } from "@farming-labs/docs";
582
- import { ${t.factory} } from "${t.nextImport}";
583
-
584
- export default defineDocs({
585
- entry: "${cfg.entry}",
586
- theme: ${t.factory}({
587
- ui: { colors: { primary: "#6366f1" } },
588
- }),
589
- });
590
- \`\`\`
591
-
592
- ## Project Structure
593
-
594
- \`\`\`
595
- ${cfg.nextAppDir ?? "app"}/
596
- ${cfg.entry}/
597
- layout.tsx # Docs layout
598
- page.mdx # /${cfg.entry}
599
- installation/
600
- page.mdx # /${cfg.entry}/installation
601
- quickstart/
602
- page.mdx # /${cfg.entry}/quickstart
603
- docs.config.ts # Docs configuration
604
- next.config.ts # Next.js config with withDocs()
605
- \`\`\`
606
-
607
- ## What's Next?
608
-
609
- Head to the [Quickstart](/${cfg.entry}/quickstart) guide to start writing your first page.
610
- `;
611
- }
612
- function quickstartPageTemplate(cfg) {
613
- const t = getThemeInfo(cfg.theme);
614
- return `\
615
- ---
616
- title: "Quickstart"
617
- description: "Get up and running in minutes"
618
- ---
619
-
620
- # Quickstart
621
-
622
- This guide walks you through creating your first documentation page.
623
-
624
- ## Creating a Page
625
-
626
- Create a new folder under \`${cfg.nextAppDir ?? "app"}/${cfg.entry}/\` with a \`page.mdx\` file:
627
-
628
- \`\`\`bash
629
- mkdir -p ${cfg.nextAppDir ?? "app"}/${cfg.entry}/my-page
630
- \`\`\`
631
-
632
- Then create \`${cfg.nextAppDir ?? "app"}/${cfg.entry}/my-page/page.mdx\`:
633
-
634
- \`\`\`mdx
635
- ---
636
- title: "My Page"
637
- description: "A custom documentation page"
638
- ---
639
-
640
- # My Page
641
-
642
- Write your content here using **Markdown** and JSX components.
643
- \`\`\`
644
-
645
- Your page is now available at \`/${cfg.entry}/my-page\`.
646
-
647
- ## Using Components
648
-
649
- ### Callouts
650
-
651
- <Callout type="info">
652
- This is an informational callout. Use it for tips and notes.
653
- </Callout>
654
-
655
- <Callout type="warn">
656
- This is a warning callout. Use it for important caveats.
657
- </Callout>
658
-
659
- ### Code Blocks
660
-
661
- Code blocks are automatically syntax-highlighted:
662
-
663
- \`\`\`typescript
664
- function greet(name: string): string {
665
- return \\\`Hello, \\\${name}!\\\`;
666
- }
667
-
668
- console.log(greet("World"));
669
- \`\`\`
670
-
671
- ## Customizing the Theme
672
-
673
- Edit \`docs.config.ts\` to change colors, typography, and component defaults:
674
-
675
- \`\`\`ts
676
- theme: ${t.factory}({
677
- ui: {
678
- colors: { primary: "#22c55e" },
679
- },
680
- }),
681
- \`\`\`
682
-
683
- ## Deploying
684
-
685
- Build your docs for production:
686
-
687
- \`\`\`bash
688
- pnpm build
689
- \`\`\`
690
-
691
- Deploy to Vercel, Netlify, or any Node.js hosting platform.
692
- `;
693
- }
694
- function tanstackDocsConfigTemplate(cfg) {
695
- if (cfg.theme === "custom" && cfg.customThemeName) {
696
- const exportName = getThemeExportName(cfg.customThemeName);
697
- return `\
698
- import { defineDocs } from "@farming-labs/docs";
699
- import { ${exportName} } from "./themes/${cfg.customThemeName.replace(/\.ts$/i, "")}";
700
-
701
- export default defineDocs({
702
- entry: "${cfg.entry}",
703
- contentDir: "${cfg.entry}",
704
- ${renderApiReferenceConfig(cfg)} theme: ${exportName}({
705
- ui: {
706
- colors: { primary: "#6366f1" },
707
- },
708
- }),
709
- nav: {
710
- title: "${cfg.projectName} Docs",
711
- url: "/${cfg.entry}",
712
- },
713
- themeToggle: {
714
- enabled: true,
715
- default: "dark",
716
- },
717
- metadata: {
718
- titleTemplate: "%s – ${cfg.projectName}",
719
- description: "Documentation for ${cfg.projectName}",
720
- },
721
- });
722
- `;
723
- }
724
- const t = getThemeInfo(cfg.theme);
725
- return `\
726
- import { defineDocs } from "@farming-labs/docs";
727
- import { ${t.factory} } from "${t.nextImport}";
728
-
729
- export default defineDocs({
730
- entry: "${cfg.entry}",
731
- contentDir: "${cfg.entry}",
732
- ${renderApiReferenceConfig(cfg)} theme: ${t.factory}({
733
- ui: {
734
- colors: { primary: "#6366f1" },
735
- },
736
- }),
737
- nav: {
738
- title: "${cfg.projectName} Docs",
739
- url: "/${cfg.entry}",
740
- },
741
- themeToggle: {
742
- enabled: true,
743
- default: "dark",
744
- },
745
- metadata: {
746
- titleTemplate: "%s – ${cfg.projectName}",
747
- description: "Documentation for ${cfg.projectName}",
748
- },
749
- });
750
- `;
751
- }
752
- function tanstackDocsServerTemplate() {
753
- return `\
754
- import { createDocsServer } from "@farming-labs/tanstack-start/server";
755
- import docsConfig from "../../docs.config";
756
-
757
- export const docsServer = createDocsServer({
758
- ...docsConfig,
759
- rootDir: process.cwd(),
760
- });
761
- `;
762
- }
763
- function tanstackDocsFunctionsTemplate() {
764
- return `\
765
- import { createServerFn } from "@tanstack/react-start";
766
- import { docsServer } from "./docs.server";
767
-
768
- export const loadDocPage = createServerFn({ method: "GET" })
769
- .inputValidator((data: { pathname: string; locale?: string }) => data)
770
- .handler(async ({ data }) => docsServer.load(data));
771
- `;
772
- }
773
- function tanstackDocsFunctionsImport(opts) {
774
- if (opts.useAlias) return "@/lib/docs.functions";
775
- return relativeImport(opts.filePath, "src/lib/docs.functions.ts");
776
- }
777
- function tanstackDocsConfigImport(filePath) {
778
- return relativeImport(filePath, "docs.config.ts");
779
- }
780
- function tanstackDocsIndexRouteTemplate(opts) {
781
- const entryUrl = `/${opts.entry.replace(/^\/+|\/+$/g, "")}`;
782
- return `\
783
- import { createFileRoute } from "@tanstack/react-router";
784
- import { toDocsMarkdownUrl } from "@farming-labs/docs";
785
- import { TanstackDocsPage } from "@farming-labs/tanstack-start/react";
786
- import { loadDocPage } from "${tanstackDocsFunctionsImport(opts)}";
787
- import docsConfig from "${tanstackDocsConfigImport(opts.filePath)}";
788
-
789
- export const Route = createFileRoute("${entryUrl}/")({
790
- loader: () => loadDocPage({ data: { pathname: "${entryUrl}" } }),
791
- head: ({ loaderData }) => ({
792
- links: loaderData && !docsConfig.staticExport
793
- ? [{ rel: "alternate", type: "text/markdown", href: toDocsMarkdownUrl(loaderData.url, { locale: loaderData.locale }) }]
794
- : [],
795
- meta: [
796
- { title: loaderData ? \`\${loaderData.title} – ${opts.projectName}\` : "${opts.projectName}" },
797
- ...(loaderData?.description
798
- ? [{ name: "description", content: loaderData.description }]
799
- : []),
800
- ],
801
- }),
802
- component: DocsIndexPage,
803
- });
804
-
805
- function DocsIndexPage() {
806
- const data = Route.useLoaderData();
807
- return <TanstackDocsPage config={docsConfig} data={data} />;
808
- }
809
- `;
810
- }
811
- function tanstackDocsCatchAllRouteTemplate(opts) {
812
- const entryUrl = `/${opts.entry.replace(/^\/+|\/+$/g, "")}`;
813
- const serverImport = opts.useAlias ? "@/lib/docs.server" : relativeImport(opts.filePath, "src/lib/docs.server.ts");
814
- return `\
815
- import { createFileRoute, notFound } from "@tanstack/react-router";
816
- import { isDocsPublicGetRequest, toDocsMarkdownUrl } from "@farming-labs/docs";
817
- import { TanstackDocsPage } from "@farming-labs/tanstack-start/react";
818
- import { loadDocPage } from "${tanstackDocsFunctionsImport(opts)}";
819
- import { docsServer } from "${serverImport}";
820
- import docsConfig from "${tanstackDocsConfigImport(opts.filePath)}";
821
-
822
- export const Route = createFileRoute("${entryUrl}/$")({
823
- server: {
824
- handlers: {
825
- GET: async ({ request }) => {
826
- const url = new URL(request.url);
827
- if (isDocsPublicGetRequest(${JSON.stringify(opts.entry)}, url, request, { sitemap: docsConfig.sitemap, llms: docsConfig.llmsTxt, robots: docsConfig.robots })) {
828
- return docsServer.GET({ request });
829
- }
830
- return undefined;
831
- },
832
- },
833
- },
834
- loader: async ({ location }) => {
835
- try {
836
- return await loadDocPage({ data: { pathname: location.pathname } });
837
- } catch (error) {
838
- if (
839
- error &&
840
- typeof error === "object" &&
841
- "status" in error &&
842
- (error as { status?: unknown }).status === 404
843
- ) {
844
- throw notFound();
845
- }
846
- throw error;
847
- }
848
- },
849
- head: ({ loaderData }) => ({
850
- links: loaderData && !docsConfig.staticExport
851
- ? [{ rel: "alternate", type: "text/markdown", href: toDocsMarkdownUrl(loaderData.url, { locale: loaderData.locale }) }]
852
- : [],
853
- meta: [
854
- { title: loaderData ? \`\${loaderData.title} – ${opts.projectName}\` : "${opts.projectName}" },
855
- ...(loaderData?.description
856
- ? [{ name: "description", content: loaderData.description }]
857
- : []),
858
- ],
859
- }),
860
- component: DocsCatchAllPage,
861
- });
862
-
863
- function DocsCatchAllPage() {
864
- const data = Route.useLoaderData();
865
- return <TanstackDocsPage config={docsConfig} data={data} />;
866
- }
867
- `;
868
- }
869
- function tanstackApiDocsRouteTemplate(useAlias, filePath) {
870
- return `\
871
- import { createFileRoute } from "@tanstack/react-router";
872
- import { docsServer } from "${useAlias ? "@/lib/docs.server" : relativeImport(filePath, "src/lib/docs.server.ts")}";
873
-
874
- export const Route = createFileRoute("/api/docs")({
875
- server: {
876
- handlers: {
877
- GET: async ({ request }) => docsServer.GET({ request }),
878
- POST: async ({ request }) => docsServer.POST({ request }),
879
- },
880
- },
881
- });
882
- `;
883
- }
884
- function tanstackDocsPublicRouteTemplate(useAlias, filePath, entry) {
885
- return `\
886
- import { createFileRoute } from "@tanstack/react-router";
887
- import { isDocsMcpRequest, isDocsPublicGetRequest } from "@farming-labs/docs";
888
- import { docsServer } from "${useAlias ? "@/lib/docs.server" : relativeImport(filePath, "src/lib/docs.server.ts")}";
889
- import docsConfig from "${tanstackDocsConfigImport(filePath)}";
890
-
891
- const docsEntry = ${JSON.stringify(entry)};
892
-
893
- async function handlePublicDocsRequest(request: Request) {
894
- const url = new URL(request.url);
895
- const method = request.method.toUpperCase();
896
-
897
- if (isDocsMcpRequest(url)) {
898
- if (method === "OPTIONS") return docsServer.MCP.OPTIONS({ request });
899
- if (method === "POST") return docsServer.MCP.POST({ request });
900
- if (method === "DELETE") return docsServer.MCP.DELETE({ request });
901
- if (method === "GET" || method === "HEAD") return docsServer.MCP.GET({ request });
902
- return new Response("Method Not Allowed", {
903
- status: 405,
904
- headers: { Allow: "GET, HEAD, POST, DELETE, OPTIONS" },
905
- });
906
- }
907
-
908
- if ((method === "GET" || method === "HEAD") && isDocsPublicGetRequest(docsEntry, url, request, { sitemap: docsConfig.sitemap, llms: docsConfig.llmsTxt, robots: docsConfig.robots })) {
909
- return docsServer.GET({ request });
910
- }
911
-
912
- return new Response("Not Found", { status: 404 });
913
- }
914
-
915
- export const Route = createFileRoute("/$")({
916
- server: {
917
- handlers: {
918
- GET: async ({ request }) => handlePublicDocsRequest(request),
919
- POST: async ({ request }) => handlePublicDocsRequest(request),
920
- DELETE: async ({ request }) => handlePublicDocsRequest(request),
921
- OPTIONS: async ({ request }) => handlePublicDocsRequest(request),
922
- },
923
- },
924
- });
925
- `;
926
- }
927
- function tanstackApiReferenceRouteTemplate(opts) {
928
- const routePath = `/${opts.apiReferencePath}${opts.catchAll ? "/$" : "/"}`;
929
- return `\
930
- import { createFileRoute } from "@tanstack/react-router";
931
- import { createTanstackApiReference } from "@farming-labs/tanstack-start/api-reference";
932
- import docsConfig from "${tanstackDocsConfigImport(opts.filePath)}";
933
-
934
- const handler = createTanstackApiReference(docsConfig);
935
-
936
- export const Route = createFileRoute("${routePath}")({
937
- server: {
938
- handlers: {
939
- GET: handler,
940
- },
941
- },
942
- });
943
- `;
944
- }
945
- function tanstackRootRouteTemplate(globalCssRelPath) {
946
- return `\
947
- import appCss from "${relativeAssetPath("src/routes/__root.tsx", globalCssRelPath)}?url";
948
- import { createRootRoute, HeadContent, Outlet, Scripts } from "@tanstack/react-router";
949
- import { RootProvider } from "@farming-labs/theme/tanstack";
950
-
951
- export const Route = createRootRoute({
952
- head: () => ({
953
- links: [{ rel: "stylesheet", href: appCss }],
954
- meta: [
955
- { charSet: "utf-8" },
956
- { name: "viewport", content: "width=device-width, initial-scale=1" },
957
- { title: "Docs" },
958
- ],
959
- }),
960
- component: RootComponent,
961
- });
962
-
963
- function RootComponent() {
964
- return (
965
- <html lang="en" suppressHydrationWarning>
966
- <head>
967
- <HeadContent />
968
- </head>
969
- <body>
970
- <RootProvider>
971
- <Outlet />
972
- </RootProvider>
973
- <Scripts />
974
- </body>
975
- </html>
976
- );
977
- }
978
- `;
979
- }
980
- function injectTanstackRootProviderIntoRoute(content) {
981
- if (!content || content.includes("RootProvider")) return null;
982
- let out = addImportLine(content, "import { RootProvider } from \"@farming-labs/theme/tanstack\";");
983
- if (out.includes("<Outlet />")) out = out.replace("<Outlet />", "<RootProvider><Outlet /></RootProvider>");
984
- else if (out.includes("<Outlet></Outlet>")) out = out.replace("<Outlet></Outlet>", "<RootProvider><Outlet /></RootProvider>");
985
- else return null;
986
- return out === content ? null : out;
987
- }
988
- function tanstackViteConfigTemplate(useAlias) {
989
- return `\
990
- import { defineConfig } from "vite";
991
- import tailwindcss from "@tailwindcss/vite";
992
- ${useAlias ? "import tsconfigPaths from \"vite-tsconfig-paths\";\n" : ""}import { tanstackStart } from "@tanstack/react-start/plugin/vite";
993
- import { docsMdx } from "@farming-labs/tanstack-start/vite";
994
-
995
- export default defineConfig({
996
- plugins: [tailwindcss(), docsMdx(), ${useAlias ? "tsconfigPaths({ ignoreConfigErrors: true }), " : ""}tanstackStart()],
997
- });
998
- `;
999
- }
1000
- function injectTanstackVitePlugins(content, useAlias) {
1001
- if (!content) return null;
1002
- let out = content;
1003
- out = addImportLine(out, "import tailwindcss from \"@tailwindcss/vite\";");
1004
- if (useAlias) out = addImportLine(out, "import tsconfigPaths from \"vite-tsconfig-paths\";");
1005
- out = addImportLine(out, "import { docsMdx } from \"@farming-labs/tanstack-start/vite\";");
1006
- const additions = [];
1007
- if (!out.includes("tailwindcss()")) additions.push("tailwindcss()");
1008
- if (!out.includes("docsMdx()")) additions.push("docsMdx()");
1009
- if (useAlias && !out.includes("tsconfigPaths(")) additions.push("tsconfigPaths({ ignoreConfigErrors: true })");
1010
- if (additions.length === 0) return out === content ? null : out;
1011
- const pluginsMatch = out.match(/plugins\s*:\s*\[([\s\S]*?)\]/m);
1012
- if (pluginsMatch) {
1013
- const current = pluginsMatch[1].trim();
1014
- const existing = current ? `${current}${current.endsWith(",") ? "" : ","}` : "";
1015
- const replacement = `plugins: [\n ${existing}${existing ? "\n " : ""}${additions.join(",\n ")}\n ]`;
1016
- return out.replace(pluginsMatch[0], replacement);
1017
- }
1018
- const configMatch = out.match(/defineConfig\(\s*\{/);
1019
- if (configMatch) {
1020
- const insertion = `defineConfig({\n plugins: [${additions.join(", ")}],`;
1021
- return out.replace(configMatch[0], insertion);
1022
- }
1023
- return out === content ? null : out;
1024
- }
1025
- function tanstackWelcomePageTemplate(cfg) {
1026
- return `\
1027
- ---
1028
- title: "Documentation"
1029
- description: "Welcome to ${cfg.projectName} documentation"
1030
- ---
1031
-
1032
- # Welcome to ${cfg.projectName}
1033
-
1034
- This docs site is powered by \`@farming-labs/docs\` and TanStack Start.
1035
-
1036
- ## Overview
1037
-
1038
- - Content lives in \`${cfg.entry}/\`
1039
- - Routes live in \`src/routes/${cfg.entry}/\`
1040
- - Search is served from \`/api/docs\`
1041
-
1042
- ## Next Steps
1043
-
1044
- Read the [Installation](/${cfg.entry}/installation) guide, then continue to [Quickstart](/${cfg.entry}/quickstart).
1045
- `;
1046
- }
1047
- function tanstackInstallationPageTemplate(cfg) {
1048
- if (cfg.theme === "custom" && cfg.customThemeName) {
1049
- const baseName = cfg.customThemeName.replace(/\.(ts|css)$/i, "");
1050
- const exportName = getThemeExportName(baseName);
1051
- const cssImportPath = getCustomThemeCssImportPath("src/styles/app.css", baseName);
1052
- return `\
1053
- ---
1054
- title: "Installation"
1055
- description: "How to install and set up ${cfg.projectName}"
1056
- ---
1057
-
1058
- # Installation
1059
-
1060
- Add the docs packages to your TanStack Start app:
1061
-
1062
- \`\`\`bash
1063
- pnpm add @farming-labs/docs @farming-labs/theme @farming-labs/tanstack-start
1064
- \`\`\`
1065
-
1066
- The scaffold also configures MDX through \`docsMdx()\` in \`vite.config.ts\`.
1067
-
1068
- ## Theme CSS
1069
-
1070
- Keep your config theme and global CSS import aligned:
1071
-
1072
- \`\`\`ts title="docs.config.ts"
1073
- import { defineDocs } from "@farming-labs/docs";
1074
- import { ${exportName} } from "./themes/${baseName}";
1075
-
1076
- export default defineDocs({
1077
- entry: "${cfg.entry}",
1078
- contentDir: "${cfg.entry}",
1079
- theme: ${exportName}(),
1080
- });
1081
- \`\`\`
1082
-
1083
- \`\`\`css title="src/styles/app.css"
1084
- @import "tailwindcss";
1085
- @import "${cssImportPath}";
1086
- \`\`\`
1087
-
1088
- ## Generated Files
1089
-
1090
- \`\`\`
1091
- docs.config.ts
1092
- themes/${baseName}.ts
1093
- themes/${baseName}.css
1094
- ${cfg.entry}/
1095
- src/lib/docs.server.ts
1096
- src/lib/docs.functions.ts
1097
- src/routes/${cfg.entry}/index.tsx
1098
- src/routes/${cfg.entry}/$.tsx
1099
- src/routes/api/docs.ts
1100
- src/routes/$.ts
1101
- \`\`\`
1102
- `;
1103
- }
1104
- const t = getThemeInfo(cfg.theme);
1105
- return `\
1106
- ---
1107
- title: "Installation"
1108
- description: "How to install and set up ${cfg.projectName}"
1109
- ---
1110
-
1111
- # Installation
1112
-
1113
- Add the docs packages to your TanStack Start app:
1114
-
1115
- \`\`\`bash
1116
- pnpm add @farming-labs/docs @farming-labs/theme @farming-labs/tanstack-start
1117
- \`\`\`
1118
-
1119
- The scaffold also configures MDX through \`docsMdx()\` in \`vite.config.ts\`.
1120
-
1121
- ## Theme CSS
1122
-
1123
- Keep your config theme and global CSS import aligned:
1124
-
1125
- \`\`\`ts title="docs.config.ts"
1126
- import { defineDocs } from "@farming-labs/docs";
1127
- import { ${t.factory} } from "${t.nextImport}";
1128
-
1129
- export default defineDocs({
1130
- entry: "${cfg.entry}",
1131
- contentDir: "${cfg.entry}",
1132
- theme: ${t.factory}(),
1133
- });
1134
- \`\`\`
1135
-
1136
- \`\`\`css title="src/styles/app.css"
1137
- @import "tailwindcss";
1138
- @import "@farming-labs/theme/${t.nextCssImport}/css";
1139
- \`\`\`
1140
-
1141
- ## Generated Files
1142
-
1143
- \`\`\`
1144
- docs.config.ts
1145
- ${cfg.entry}/
1146
- src/lib/docs.server.ts
1147
- src/lib/docs.functions.ts
1148
- src/routes/${cfg.entry}/index.tsx
1149
- src/routes/${cfg.entry}/$.tsx
1150
- src/routes/api/docs.ts
1151
- \`\`\`
1152
- `;
1153
- }
1154
- function tanstackQuickstartPageTemplate(cfg) {
1155
- return `\
1156
- ---
1157
- title: "Quickstart"
1158
- description: "Get up and running in minutes"
1159
- ---
1160
-
1161
- # Quickstart
1162
-
1163
- Create a new page under \`${cfg.entry}/\`:
1164
-
1165
- \`\`\`bash
1166
- mkdir -p ${cfg.entry}/my-page
1167
- \`\`\`
1168
-
1169
- Then add \`${cfg.entry}/my-page/page.mdx\`:
1170
-
1171
- \`\`\`mdx
1172
- ---
1173
- title: "My Page"
1174
- description: "A custom documentation page"
1175
- ---
1176
-
1177
- # My Page
1178
-
1179
- Write your content here using **MDX**.
1180
- \`\`\`
1181
-
1182
- Visit [/${cfg.entry}/my-page](/${cfg.entry}/my-page) after starting the dev server.
1183
- `;
1184
- }
1185
- function svelteDocsConfigTemplate(cfg) {
1186
- if (cfg.theme === "custom" && cfg.customThemeName) {
1187
- const exportName = getThemeExportName(cfg.customThemeName);
1188
- return `\
1189
- import { defineDocs } from "@farming-labs/docs";
1190
- import { ${exportName} } from "${"../../themes/" + cfg.customThemeName.replace(/\.ts$/i, "")}";
1191
-
1192
- export default defineDocs({
1193
- entry: "${cfg.entry}",
1194
- contentDir: "${cfg.entry}",
1195
- ${renderI18nConfig(cfg)}${renderApiReferenceConfig(cfg)} theme: ${exportName}({
1196
- ui: {
1197
- colors: { primary: "#6366f1" },
1198
- },
1199
- }),
1200
-
1201
- nav: {
1202
- title: "${cfg.projectName}",
1203
- url: "/${cfg.entry}",
1204
- },
1205
-
1206
- breadcrumb: { enabled: true },
1207
-
1208
- metadata: {
1209
- titleTemplate: "%s – ${cfg.projectName}",
1210
- description: "Documentation for ${cfg.projectName}",
1211
- },
1212
- });
1213
- `;
1214
- }
1215
- const t = getThemeInfo(cfg.theme);
1216
- return `\
1217
- import { defineDocs } from "@farming-labs/docs";
1218
- import { ${t.factory} } from "${t.svelteImport}";
1219
-
1220
- export default defineDocs({
1221
- entry: "${cfg.entry}",
1222
- contentDir: "${cfg.entry}",
1223
- ${renderI18nConfig(cfg)}${renderApiReferenceConfig(cfg)} theme: ${t.factory}({
1224
- ui: {
1225
- colors: { primary: "#6366f1" },
1226
- },
1227
- }),
1228
-
1229
- nav: {
1230
- title: "${cfg.projectName}",
1231
- url: "/${cfg.entry}",
1232
- },
1233
-
1234
- breadcrumb: { enabled: true },
1235
-
1236
- metadata: {
1237
- titleTemplate: "%s – ${cfg.projectName}",
1238
- description: "Documentation for ${cfg.projectName}",
1239
- },
1240
- });
1241
- `;
1242
- }
1243
- function svelteDocsServerTemplate(cfg) {
1244
- return `\
1245
- import { createDocsServer } from "@farming-labs/svelte/server";
1246
- import config from "${svelteServerConfigImport(cfg.useAlias)}";
1247
-
1248
- // preload for production
1249
- const contentFiles = import.meta.glob(["/${cfg.entry ?? "docs"}/**/*.{md,mdx,svx}", "/AGENTS.md", "/AGENT.md", "/skill.md", "/.farming-labs/sitemap-manifest.json"], {
1250
- query: "?raw",
1251
- import: "default",
1252
- eager: true,
1253
- }) as Record<string, string>;
1254
-
1255
- export const { load, GET, POST, MCP } = createDocsServer({
1256
- ...config,
1257
- _preloadedContent: contentFiles,
1258
- });
1259
- `;
1260
- }
1261
- function svelteDocsLayoutTemplate(cfg) {
1262
- return `\
1263
- <script>
1264
- import { DocsLayout } from "@farming-labs/svelte-theme";
1265
- import config from "${svelteLayoutConfigImport(cfg.useAlias)}";
1266
-
1267
- let { data, children } = $props();
1268
- <\/script>
1269
-
1270
- <DocsLayout tree={data.tree} {config}>
1271
- {@render children()}
1272
- </DocsLayout>
1273
- `;
1274
- }
1275
- function svelteDocsLayoutServerTemplate(cfg) {
1276
- return `\
1277
- export { load } from "${svelteLayoutServerImport(cfg.useAlias)}";
1278
- `;
1279
- }
1280
- function svelteDocsPageTemplate(cfg) {
1281
- return `\
1282
- <script>
1283
- import { DocsContent } from "@farming-labs/svelte-theme";
1284
- import config from "${sveltePageConfigImport(cfg.useAlias)}";
1285
-
1286
- let { data } = $props();
1287
- <\/script>
1288
-
1289
- <DocsContent {data} {config} />
1290
- `;
1291
- }
1292
- function svelteApiReferenceRouteTemplate(filePath, useAlias) {
1293
- return `\
1294
- import { createSvelteApiReference } from "@farming-labs/svelte/api-reference";
1295
- import config from "${useAlias ? "$lib/docs.config" : relativeImport(filePath, "src/lib/docs.config.ts")}";
1296
-
1297
- export const GET = createSvelteApiReference(config);
1298
- `;
1299
- }
1300
- function svelteDocsApiRouteTemplate(filePath, useAlias) {
1301
- return `\
1302
- export { GET, POST } from "${svelteRouteServerImport(filePath, useAlias)}";
1303
- `;
1304
- }
1305
- function svelteDocsPublicHookTemplate(filePath, useAlias) {
1306
- const serverImport = svelteRouteServerImport(filePath, useAlias);
1307
- return `\
1308
- import { isDocsLlmsTxtPublicRequest, isDocsMcpRequest, isDocsPublicGetRequest } from "@farming-labs/docs";
1309
- import type { Handle } from "@sveltejs/kit";
1310
- import config from "${svelteRouteConfigImport(filePath, useAlias)}";
1311
- import { GET, MCP } from "${serverImport}";
1312
-
1313
- const docsEntry = config.entry ?? "docs";
1314
-
1315
- export const handle: Handle = async ({ event, resolve }) => {
1316
- const method = event.request.method.toUpperCase();
1317
-
1318
- if (isDocsMcpRequest(event.url)) {
1319
- if (method === "OPTIONS") return MCP.OPTIONS({ request: event.request });
1320
- if (method === "POST") return MCP.POST({ request: event.request });
1321
- if (method === "DELETE") return MCP.DELETE({ request: event.request });
1322
- if (method === "GET" || method === "HEAD") return MCP.GET({ request: event.request });
1323
- return new Response("Method Not Allowed", {
1324
- status: 405,
1325
- headers: { Allow: "GET, HEAD, POST, DELETE, OPTIONS" },
1326
- });
1327
- }
1328
-
1329
- if ((method === "GET" || method === "HEAD") && isDocsLlmsTxtPublicRequest(event.url, config.llmsTxt, docsEntry)) {
1330
- const nativeResponse = await resolve(event);
1331
- if (nativeResponse.status !== 404) return nativeResponse;
1332
- }
1333
-
1334
- if ((method === "GET" || method === "HEAD") && isDocsPublicGetRequest(docsEntry, event.url, event.request, { sitemap: config.sitemap, llms: config.llmsTxt, robots: config.robots })) {
1335
- return GET({ url: event.url, request: event.request });
1336
- }
1337
-
1338
- return resolve(event);
1339
- };
1340
- `;
1341
- }
1342
- function injectSvelteDocsPublicHook(content, filePath, useAlias) {
1343
- if (content.includes("isDocsPublicGetRequest") || content.includes("docsPublicHandle")) return null;
1344
- if (/export\s*{\s*handle\b/.test(content)) return null;
1345
- const serverImport = svelteRouteServerImport(filePath, useAlias);
1346
- const configImport = svelteRouteConfigImport(filePath, useAlias);
1347
- let next = content.trimEnd();
1348
- let hasExistingHandle = false;
1349
- for (const [pattern, replacement] of [
1350
- [/\bexport\s+const\s+handle(\s*:\s*[^=]+)?\s*=/, "const existingHandle$1 ="],
1351
- [/\bexport\s+async\s+function\s+handle\b/, "async function existingHandle"],
1352
- [/\bexport\s+function\s+handle\b/, "function existingHandle"]
1353
- ]) if (pattern.test(next)) {
1354
- next = next.replace(pattern, replacement);
1355
- next = next.replace(/const existingHandle(:[^=\n]*?)\s+=/, "const existingHandle$1 =");
1356
- hasExistingHandle = true;
1357
- break;
1358
- }
1359
- const imports = [
1360
- "import { isDocsLlmsTxtPublicRequest, isDocsMcpRequest, isDocsPublicGetRequest } from \"@farming-labs/docs\";",
1361
- ...next.includes("Handle") ? [] : ["import type { Handle } from \"@sveltejs/kit\";"],
1362
- ...hasExistingHandle && !next.includes("sequence") ? ["import { sequence } from \"@sveltejs/kit/hooks\";"] : [],
1363
- `import docsConfig from "${configImport}";`,
1364
- `import { GET as docsGET, MCP as docsMCP } from "${serverImport}";`
1365
- ];
1366
- const docsHandle = `\
1367
- const docsEntry = docsConfig.entry ?? "docs";
1368
-
1369
- const docsPublicHandle: Handle = async ({ event, resolve }) => {
1370
- const method = event.request.method.toUpperCase();
1371
-
1372
- if (isDocsMcpRequest(event.url)) {
1373
- if (method === "OPTIONS") return docsMCP.OPTIONS({ request: event.request });
1374
- if (method === "POST") return docsMCP.POST({ request: event.request });
1375
- if (method === "DELETE") return docsMCP.DELETE({ request: event.request });
1376
- if (method === "GET" || method === "HEAD") return docsMCP.GET({ request: event.request });
1377
- return new Response("Method Not Allowed", {
1378
- status: 405,
1379
- headers: { Allow: "GET, HEAD, POST, DELETE, OPTIONS" },
1380
- });
1381
- }
1382
-
1383
- if ((method === "GET" || method === "HEAD") && isDocsLlmsTxtPublicRequest(event.url, docsConfig.llmsTxt, docsEntry)) {
1384
- const nativeResponse = await resolve(event);
1385
- if (nativeResponse.status !== 404) return nativeResponse;
1386
- }
1387
-
1388
- if ((method === "GET" || method === "HEAD") && isDocsPublicGetRequest(docsEntry, event.url, event.request, { sitemap: docsConfig.sitemap, llms: docsConfig.llmsTxt, robots: docsConfig.robots })) {
1389
- return docsGET({ url: event.url, request: event.request });
1390
- }
1391
-
1392
- return resolve(event);
1393
- };`;
1394
- const exportLine = hasExistingHandle ? "export const handle = sequence(docsPublicHandle, existingHandle);" : "export const handle = docsPublicHandle;";
1395
- return `${imports.join("\n")}\n${next}\n\n${docsHandle}\n\n${exportLine}\n`;
1396
- }
1397
- function svelteRootLayoutTemplate(globalCssRelPath) {
1398
- let cssImport;
1399
- if (globalCssRelPath.startsWith("src/")) cssImport = "./" + globalCssRelPath.slice(4);
1400
- else cssImport = "../" + globalCssRelPath;
1401
- return `\
1402
- <script>
1403
- import "${cssImport}";
1404
-
1405
- let { children } = $props();
1406
- <\/script>
1407
-
1408
- {@render children()}
1409
- `;
1410
- }
1411
- function svelteGlobalCssTemplate(theme, customThemeName, globalCssRelPath) {
1412
- if (theme === "custom" && customThemeName && globalCssRelPath) return `\
1413
- @import "${getCustomThemeCssImportPath(globalCssRelPath, customThemeName.replace(/\.css$/i, ""))}";
1414
- `;
1415
- return `\
1416
- @import "${getThemeCssImport(theme)}";
1417
- `;
1418
- }
1419
- function svelteCssImportLine(theme, customThemeName, globalCssRelPath) {
1420
- if (theme === "custom" && customThemeName && globalCssRelPath) return `@import "${getCustomThemeCssImportPath(globalCssRelPath, customThemeName.replace(/\.css$/i, ""))}";`;
1421
- return `@import "${getThemeCssImport(theme)}";`;
1422
- }
1423
- function injectSvelteCssImport(existingContent, theme, customThemeName, globalCssRelPath) {
1424
- const importLine = svelteCssImportLine(theme, customThemeName, globalCssRelPath);
1425
- if (existingContent.includes(importLine)) return null;
1426
- if (theme !== "custom" && hasBuiltInThemeCssImport(existingContent)) return null;
1427
- if (theme === "custom" && existingContent.includes("themes/") && existingContent.includes(".css")) return null;
1428
- const lines = existingContent.split("\n");
1429
- const lastImportIdx = lines.reduce((acc, l, i) => l.trimStart().startsWith("@import") ? i : acc, -1);
1430
- if (lastImportIdx >= 0) lines.splice(lastImportIdx + 1, 0, importLine);
1431
- else lines.unshift(importLine);
1432
- return lines.join("\n");
1433
- }
1434
- function svelteWelcomePageTemplate(cfg) {
1435
- return `\
1436
- ---
1437
- title: "Documentation"
1438
- description: "Welcome to ${cfg.projectName} documentation"
1439
- ---
1440
-
1441
- # Welcome to ${cfg.projectName}
1442
-
1443
- Get started with our documentation. Browse the pages on the left to learn more.
1444
-
1445
- ## Overview
1446
-
1447
- This documentation was generated by \`@farming-labs/docs\`. Edit the markdown files in \`${cfg.entry}/\` to customize.
1448
-
1449
- ## Features
1450
-
1451
- - **Markdown Support** — Write docs with standard Markdown
1452
- - **Syntax Highlighting** — Code blocks with automatic highlighting
1453
- - **Dark Mode** — Built-in theme switching
1454
- - **Search** — Full-text search across all pages
1455
- - **Responsive** — Works on any screen size
1456
-
1457
- ---
1458
-
1459
- ## Next Steps
1460
-
1461
- Start by reading the [Installation](/${cfg.entry}/installation) guide, then follow the [Quickstart](/${cfg.entry}/quickstart) to build something.
1462
- `;
1463
- }
1464
- function svelteInstallationPageTemplate(cfg) {
1465
- const t = getThemeInfo(cfg.theme);
1466
- return `\
1467
- ---
1468
- title: "Installation"
1469
- description: "How to install and set up ${cfg.projectName}"
1470
- ---
1471
-
1472
- # Installation
1473
-
1474
- Follow these steps to install and configure ${cfg.projectName}.
1475
-
1476
- ## Prerequisites
1477
-
1478
- - Node.js 18+
1479
- - A package manager (pnpm, npm, or yarn)
1480
-
1481
- ## Install Dependencies
1482
-
1483
- \`\`\`bash
1484
- pnpm add @farming-labs/docs @farming-labs/svelte @farming-labs/svelte-theme @farming-labs/theme
1485
- \`\`\`
1486
-
1487
- ## Configuration
1488
-
1489
- Your project includes a \`docs.config.ts\` in \`src/lib/\`:
1490
-
1491
- \`\`\`ts title="src/lib/docs.config.ts"
1492
- import { defineDocs } from "@farming-labs/docs";
1493
- import { ${t.factory} } from "${t.svelteImport}";
1494
-
1495
- export default defineDocs({
1496
- entry: "${cfg.entry}",
1497
- contentDir: "${cfg.entry}",
1498
- theme: ${t.factory}({
1499
- ui: { colors: { primary: "#6366f1" } },
1500
- }),
1501
- });
1502
- \`\`\`
1503
-
1504
- ## Project Structure
1505
-
1506
- \`\`\`
1507
- ${cfg.entry}/ # Markdown content
1508
- page.md # /${cfg.entry}
1509
- installation/
1510
- page.md # /${cfg.entry}/installation
1511
- quickstart/
1512
- page.md # /${cfg.entry}/quickstart
1513
- src/
1514
- hooks.server.ts # Public docs aliases
1515
- lib/
1516
- docs.config.ts # Docs configuration
1517
- docs.server.ts # Server-side docs loader
1518
- routes/
1519
- api/docs/+server.ts # Search/AI API route
1520
- ${cfg.entry}/
1521
- +layout.svelte # Docs layout
1522
- +layout.server.js # Layout data loader
1523
- [...slug]/
1524
- +page.svelte # Dynamic doc page
1525
- \`\`\`
1526
-
1527
- ## What's Next?
1528
-
1529
- Head to the [Quickstart](/${cfg.entry}/quickstart) guide to start writing your first page.
1530
- `;
1531
- }
1532
- function svelteQuickstartPageTemplate(cfg) {
1533
- const t = getThemeInfo(cfg.theme);
1534
- return `\
1535
- ---
1536
- title: "Quickstart"
1537
- description: "Get up and running in minutes"
1538
- ---
1539
-
1540
- # Quickstart
1541
-
1542
- This guide walks you through creating your first documentation page.
1543
-
1544
- ## Creating a Page
1545
-
1546
- Create a new folder under \`${cfg.entry}/\` with a \`page.md\` file:
1547
-
1548
- \`\`\`bash
1549
- mkdir -p ${cfg.entry}/my-page
1550
- \`\`\`
1551
-
1552
- Then create \`${cfg.entry}/my-page/page.md\`:
1553
-
1554
- \`\`\`md
1555
- ---
1556
- title: "My Page"
1557
- description: "A custom documentation page"
1558
- ---
1559
-
1560
- # My Page
1561
-
1562
- Write your content here using **Markdown**.
1563
- \`\`\`
1564
-
1565
- Your page is now available at \`/${cfg.entry}/my-page\`.
1566
-
1567
- ## Code Blocks
1568
-
1569
- Code blocks are automatically syntax-highlighted:
1570
-
1571
- \`\`\`typescript
1572
- function greet(name: string): string {
1573
- return \\\`Hello, \\\${name}!\\\`;
1574
- }
1575
-
1576
- console.log(greet("World"));
1577
- \`\`\`
1578
-
1579
- ## Customizing the Theme
1580
-
1581
- Edit \`src/lib/docs.config.ts\` to change colors, typography, and component defaults:
1582
-
1583
- \`\`\`ts title="src/lib/docs.config.ts"
1584
- theme: ${t.factory}({
1585
- ui: {
1586
- colors: { primary: "#22c55e" },
1587
- },
1588
- }),
1589
- \`\`\`
1590
-
1591
- ## Deploying
1592
-
1593
- Build your docs for production:
1594
-
1595
- \`\`\`bash
1596
- pnpm build
1597
- \`\`\`
1598
-
1599
- Deploy to Vercel, Netlify, or any Node.js hosting platform.
1600
- `;
1601
- }
1602
- function astroDocsConfigTemplate(cfg) {
1603
- if (cfg.theme === "custom" && cfg.customThemeName) {
1604
- const exportName = getThemeExportName(cfg.customThemeName);
1605
- return `\
1606
- import { defineDocs } from "@farming-labs/docs";
1607
- import { ${exportName} } from "${"../../themes/" + cfg.customThemeName.replace(/\.ts$/i, "")}";
1608
-
1609
- export default defineDocs({
1610
- entry: "${cfg.entry}",
1611
- contentDir: "${cfg.entry}",
1612
- ${renderI18nConfig(cfg)}${renderApiReferenceConfig(cfg)} theme: ${exportName}({
1613
- ui: {
1614
- colors: { primary: "#6366f1" },
1615
- },
1616
- }),
1617
-
1618
- nav: {
1619
- title: "${cfg.projectName}",
1620
- url: "/${cfg.entry}",
1621
- },
1622
-
1623
- breadcrumb: { enabled: true },
1624
-
1625
- metadata: {
1626
- titleTemplate: "%s – ${cfg.projectName}",
1627
- description: "Documentation for ${cfg.projectName}",
1628
- },
1629
- });
1630
- `;
1631
- }
1632
- const t = getThemeInfo(cfg.theme);
1633
- return `\
1634
- import { defineDocs } from "@farming-labs/docs";
1635
- import { ${t.factory} } from "${t.astroImport}";
1636
-
1637
- export default defineDocs({
1638
- entry: "${cfg.entry}",
1639
- contentDir: "${cfg.entry}",
1640
- ${renderI18nConfig(cfg)}${renderApiReferenceConfig(cfg)} theme: ${t.factory}({
1641
- ui: {
1642
- colors: { primary: "#6366f1" },
1643
- },
1644
- }),
1645
-
1646
- nav: {
1647
- title: "${cfg.projectName}",
1648
- url: "/${cfg.entry}",
1649
- },
1650
-
1651
- breadcrumb: { enabled: true },
1652
-
1653
- metadata: {
1654
- titleTemplate: "%s – ${cfg.projectName}",
1655
- description: "Documentation for ${cfg.projectName}",
1656
- },
1657
- });
1658
- `;
1659
- }
1660
- function astroDocsServerTemplate(cfg) {
1661
- return `\
1662
- import { createDocsServer } from "@farming-labs/astro/server";
1663
- import config from "${astroServerConfigImport(cfg.useAlias)}";
1664
-
1665
- const contentFiles = import.meta.glob(["/${cfg.entry ?? "docs"}/**/*.{md,mdx}", "/AGENTS.md", "/AGENT.md", "/skill.md", "/.farming-labs/sitemap-manifest.json"], {
1666
- query: "?raw",
1667
- import: "default",
1668
- eager: true,
1669
- }) as Record<string, string>;
1670
-
1671
- export const { load, GET, POST, MCP } = createDocsServer({
1672
- ...config,
1673
- _preloadedContent: contentFiles,
1674
- });
1675
- `;
1676
- }
1677
- const ASTRO_ADAPTER_INFO = {
1678
- vercel: {
1679
- pkg: "@astrojs/vercel",
1680
- import: "@astrojs/vercel"
1681
- },
1682
- netlify: {
1683
- pkg: "@astrojs/netlify",
1684
- import: "@astrojs/netlify"
1685
- },
1686
- node: {
1687
- pkg: "@astrojs/node",
1688
- import: "@astrojs/node"
1689
- },
1690
- cloudflare: {
1691
- pkg: "@astrojs/cloudflare",
1692
- import: "@astrojs/cloudflare"
1693
- }
1694
- };
1695
- function getAstroAdapterPkg(adapter) {
1696
- return ASTRO_ADAPTER_INFO[adapter]?.pkg ?? ASTRO_ADAPTER_INFO.vercel.pkg;
1697
- }
1698
- function astroConfigTemplate(adapter = "vercel") {
1699
- const info = ASTRO_ADAPTER_INFO[adapter] ?? ASTRO_ADAPTER_INFO.vercel;
1700
- const adapterCall = adapter === "node" ? `${adapter}({ mode: "standalone" })` : `${adapter}()`;
1701
- return `\
1702
- import { defineConfig } from "astro/config";
1703
- import ${adapter} from "${info.import}";
1704
-
1705
- export default defineConfig({
1706
- output: "server",
1707
- adapter: ${adapterCall},
1708
- });
1709
- `;
1710
- }
1711
- function astroDocsPageTemplate(cfg) {
1712
- return `\
1713
- ---
1714
- import DocsLayout from "@farming-labs/astro-theme/src/components/DocsLayout.astro";
1715
- import DocsContent from "@farming-labs/astro-theme/src/components/DocsContent.astro";
1716
- import SearchDialog from "@farming-labs/astro-theme/src/components/SearchDialog.astro";
1717
- import config from "${astroPageConfigImport(cfg.useAlias, 2)}";
1718
- import { load } from "${astroPageServerImport(cfg.useAlias, 2)}";
1719
- import "${getThemeCssImport(cfg.theme)}";
1720
-
1721
- const data = await load(Astro.url.pathname);
1722
- ---
1723
-
1724
- <html lang="en">
1725
- <head>
1726
- <meta charset="utf-8" />
1727
- <meta name="viewport" content="width=device-width, initial-scale=1" />
1728
- <title>{data.title} – Docs</title>
1729
- </head>
1730
- <body>
1731
- <DocsLayout tree={data.tree} config={config}>
1732
- <DocsContent data={data} config={config} />
1733
- </DocsLayout>
1734
- <SearchDialog config={config} />
1735
- </body>
1736
- </html>
1737
- `;
1738
- }
1739
- function astroDocsIndexTemplate(cfg) {
1740
- return `\
1741
- ---
1742
- import DocsLayout from "@farming-labs/astro-theme/src/components/DocsLayout.astro";
1743
- import DocsContent from "@farming-labs/astro-theme/src/components/DocsContent.astro";
1744
- import SearchDialog from "@farming-labs/astro-theme/src/components/SearchDialog.astro";
1745
- import config from "${astroPageConfigImport(cfg.useAlias, 2)}";
1746
- import { load } from "${astroPageServerImport(cfg.useAlias, 2)}";
1747
- import "${getThemeCssImport(cfg.theme)}";
1748
-
1749
- const data = await load(Astro.url.pathname);
1750
- ---
1751
-
1752
- <html lang="en">
1753
- <head>
1754
- <meta charset="utf-8" />
1755
- <meta name="viewport" content="width=device-width, initial-scale=1" />
1756
- <title>{data.title} – Docs</title>
1757
- </head>
1758
- <body>
1759
- <DocsLayout tree={data.tree} config={config}>
1760
- <DocsContent data={data} config={config} />
1761
- </DocsLayout>
1762
- <SearchDialog config={config} />
1763
- </body>
1764
- </html>
1765
- `;
1766
- }
1767
- function astroApiRouteTemplate(cfg) {
1768
- return `\
1769
- import type { APIRoute } from "astro";
1770
- import { GET as docsGET, POST as docsPOST } from "${astroPageServerImport(cfg.useAlias, 2)}";
1771
-
1772
- export const GET: APIRoute = async ({ request }) => {
1773
- return docsGET({ request });
1774
- };
1775
-
1776
- export const POST: APIRoute = async ({ request }) => {
1777
- return docsPOST({ request });
1778
- };
1779
- `;
1780
- }
1781
- function astroDocsMiddlewareTemplate(filePath, useAlias) {
1782
- const serverImport = astroRouteServerImport(filePath, useAlias);
1783
- return `\
1784
- import { isDocsLlmsTxtPublicRequest, isDocsMcpRequest, isDocsPublicGetRequest } from "@farming-labs/docs";
1785
- import type { MiddlewareHandler } from "astro";
1786
- import config from "${astroRouteConfigImport(filePath, useAlias)}";
1787
- import { GET, MCP } from "${serverImport}";
1788
-
1789
- const docsEntry = config.entry ?? "docs";
1790
-
1791
- export const onRequest: MiddlewareHandler = async (context, next) => {
1792
- const method = context.request.method.toUpperCase();
1793
-
1794
- if (isDocsMcpRequest(context.url)) {
1795
- if (method === "OPTIONS") return MCP.OPTIONS({ request: context.request });
1796
- if (method === "POST") return MCP.POST({ request: context.request });
1797
- if (method === "DELETE") return MCP.DELETE({ request: context.request });
1798
- if (method === "GET" || method === "HEAD") return MCP.GET({ request: context.request });
1799
- return new Response("Method Not Allowed", {
1800
- status: 405,
1801
- headers: { Allow: "GET, HEAD, POST, DELETE, OPTIONS" },
1802
- });
1803
- }
1804
-
1805
- if ((method === "GET" || method === "HEAD") && isDocsLlmsTxtPublicRequest(context.url, config.llmsTxt, docsEntry)) {
1806
- const nativeResponse = await next();
1807
- if (nativeResponse.status !== 404) return nativeResponse;
1808
- }
1809
-
1810
- if ((method === "GET" || method === "HEAD") && isDocsPublicGetRequest(docsEntry, context.url, context.request, { sitemap: config.sitemap, llms: config.llmsTxt, robots: config.robots })) {
1811
- return GET({ request: context.request });
1812
- }
1813
-
1814
- return next();
1815
- };
1816
- `;
1817
- }
1818
- function injectAstroDocsMiddleware(content, filePath, useAlias) {
1819
- if (content.includes("isDocsPublicGetRequest") || content.includes("docsPublicMiddleware")) return null;
1820
- if (/export\s*{\s*onRequest\b/.test(content)) return null;
1821
- const serverImport = astroRouteServerImport(filePath, useAlias);
1822
- const configImport = astroRouteConfigImport(filePath, useAlias);
1823
- let next = content.trimEnd();
1824
- let hasExistingMiddleware = false;
1825
- for (const [pattern, replacement] of [
1826
- [/\bexport\s+const\s+onRequest(\s*:\s*[^=]+)?\s*=/, "const existingOnRequest$1 ="],
1827
- [/\bexport\s+async\s+function\s+onRequest\b/, "async function existingOnRequest"],
1828
- [/\bexport\s+function\s+onRequest\b/, "function existingOnRequest"]
1829
- ]) if (pattern.test(next)) {
1830
- next = next.replace(pattern, replacement);
1831
- next = next.replace(/const existingOnRequest(:[^=\n]*?)\s+=/, "const existingOnRequest$1 =");
1832
- hasExistingMiddleware = true;
1833
- break;
1834
- }
1835
- const imports = [
1836
- "import { isDocsLlmsTxtPublicRequest, isDocsMcpRequest, isDocsPublicGetRequest } from \"@farming-labs/docs\";",
1837
- ...next.includes("MiddlewareHandler") ? [] : ["import type { MiddlewareHandler } from \"astro\";"],
1838
- ...hasExistingMiddleware && !next.includes("sequence") ? ["import { sequence } from \"astro:middleware\";"] : [],
1839
- `import docsConfig from "${configImport}";`,
1840
- `import { GET as docsGET, MCP as docsMCP } from "${serverImport}";`
1841
- ];
1842
- const docsMiddleware = `\
1843
- const docsEntry = docsConfig.entry ?? "docs";
1844
-
1845
- const docsPublicMiddleware: MiddlewareHandler = async (context, next) => {
1846
- const method = context.request.method.toUpperCase();
1847
-
1848
- if (isDocsMcpRequest(context.url)) {
1849
- if (method === "OPTIONS") return docsMCP.OPTIONS({ request: context.request });
1850
- if (method === "POST") return docsMCP.POST({ request: context.request });
1851
- if (method === "DELETE") return docsMCP.DELETE({ request: context.request });
1852
- if (method === "GET" || method === "HEAD") return docsMCP.GET({ request: context.request });
1853
- return new Response("Method Not Allowed", {
1854
- status: 405,
1855
- headers: { Allow: "GET, HEAD, POST, DELETE, OPTIONS" },
1856
- });
1857
- }
1858
-
1859
- if ((method === "GET" || method === "HEAD") && isDocsLlmsTxtPublicRequest(context.url, docsConfig.llmsTxt, docsEntry)) {
1860
- const nativeResponse = await next();
1861
- if (nativeResponse.status !== 404) return nativeResponse;
1862
- }
1863
-
1864
- if ((method === "GET" || method === "HEAD") && isDocsPublicGetRequest(docsEntry, context.url, context.request, { sitemap: docsConfig.sitemap, llms: docsConfig.llmsTxt, robots: docsConfig.robots })) {
1865
- return docsGET({ request: context.request });
1866
- }
1867
-
1868
- return next();
1869
- };`;
1870
- const exportLine = hasExistingMiddleware ? "export const onRequest = sequence(docsPublicMiddleware, existingOnRequest);" : "export const onRequest = docsPublicMiddleware;";
1871
- return `${imports.join("\n")}\n${next}\n\n${docsMiddleware}\n\n${exportLine}\n`;
1872
- }
1873
- function astroApiReferenceRouteTemplate(filePath) {
1874
- return `\
1875
- import { createAstroApiReference } from "@farming-labs/astro/api-reference";
1876
- import config from "${relativeImport(filePath, "src/lib/docs.config.ts")}";
1877
-
1878
- export const GET = createAstroApiReference(config);
1879
- `;
1880
- }
1881
- function astroGlobalCssTemplate(theme, customThemeName, globalCssRelPath) {
1882
- if (theme === "custom" && customThemeName && globalCssRelPath) return `\
1883
- @import "${getCustomThemeCssImportPath(globalCssRelPath, customThemeName.replace(/\.css$/i, ""))}";
1884
- `;
1885
- return `\
1886
- @import "${getThemeCssImport(theme)}";
1887
- `;
1888
- }
1889
- function astroCssImportLine(theme, customThemeName, globalCssRelPath) {
1890
- if (theme === "custom" && customThemeName && globalCssRelPath) return `@import "${getCustomThemeCssImportPath(globalCssRelPath, customThemeName.replace(/\.css$/i, ""))}";`;
1891
- return `@import "${getThemeCssImport(theme)}";`;
1892
- }
1893
- function injectAstroCssImport(existingContent, theme, customThemeName, globalCssRelPath) {
1894
- const importLine = astroCssImportLine(theme, customThemeName, globalCssRelPath);
1895
- if (existingContent.includes(importLine)) return null;
1896
- if (theme !== "custom" && hasBuiltInThemeCssImport(existingContent)) return null;
1897
- if (theme === "custom" && existingContent.includes("themes/") && existingContent.includes(".css")) return null;
1898
- const lines = existingContent.split("\n");
1899
- const lastImportIdx = lines.reduce((acc, l, i) => l.trimStart().startsWith("@import") ? i : acc, -1);
1900
- if (lastImportIdx >= 0) lines.splice(lastImportIdx + 1, 0, importLine);
1901
- else lines.unshift(importLine);
1902
- return lines.join("\n");
1903
- }
1904
- function astroWelcomePageTemplate(cfg) {
1905
- return `\
1906
- ---
1907
- title: "Documentation"
1908
- description: "Welcome to ${cfg.projectName} documentation"
1909
- ---
1910
-
1911
- # Welcome to ${cfg.projectName}
1912
-
1913
- Get started with our documentation. Browse the pages on the left to learn more.
1914
-
1915
- ## Overview
1916
-
1917
- This documentation was generated by \`@farming-labs/docs\`. Edit the markdown files in \`${cfg.entry}/\` to customize.
1918
-
1919
- ## Features
1920
-
1921
- - **Markdown Support** — Write docs with standard Markdown
1922
- - **Syntax Highlighting** — Code blocks with automatic highlighting
1923
- - **Dark Mode** — Built-in theme switching
1924
- - **Search** — Full-text search across all pages
1925
- - **Responsive** — Works on any screen size
1926
-
1927
- ---
1928
-
1929
- ## Next Steps
1930
-
1931
- Start by reading the [Installation](/${cfg.entry}/installation) guide, then follow the [Quickstart](/${cfg.entry}/quickstart) to build something.
1932
- `;
1933
- }
1934
- function astroInstallationPageTemplate(cfg) {
1935
- const t = getThemeInfo(cfg.theme);
1936
- return `\
1937
- ---
1938
- title: "Installation"
1939
- description: "How to install and set up ${cfg.projectName}"
1940
- ---
1941
-
1942
- # Installation
1943
-
1944
- Follow these steps to install and configure ${cfg.projectName}.
1945
-
1946
- ## Prerequisites
1947
-
1948
- - Node.js 18+
1949
- - A package manager (pnpm, npm, or yarn)
1950
-
1951
- ## Install Dependencies
1952
-
1953
- \\\`\\\`\\\`bash
1954
- pnpm add @farming-labs/docs @farming-labs/astro @farming-labs/astro-theme @farming-labs/theme
1955
- \\\`\\\`\\\`
1956
-
1957
- ## Configuration
1958
-
1959
- Your project includes a \\\`docs.config.ts\\\` in \\\`src/lib/\\\`:
1960
-
1961
- \\\`\\\`\\\`ts title="src/lib/docs.config.ts"
1962
- import { defineDocs } from "@farming-labs/docs";
1963
- import { ${t.factory} } from "${t.astroImport}";
1964
-
1965
- export default defineDocs({
1966
- entry: "${cfg.entry}",
1967
- contentDir: "${cfg.entry}",
1968
- theme: ${t.factory}({
1969
- ui: { colors: { primary: "#6366f1" } },
1970
- }),
1971
- });
1972
- \\\`\\\`\\\`
1973
-
1974
- ## Project Structure
1975
-
1976
- \\\`\\\`\\\`
1977
- ${cfg.entry}/ # Markdown content
1978
- page.md # /${cfg.entry}
1979
- installation/
1980
- page.md # /${cfg.entry}/installation
1981
- quickstart/
1982
- page.md # /${cfg.entry}/quickstart
1983
- src/
1984
- middleware.ts # Public docs aliases
1985
- lib/
1986
- docs.config.ts # Docs configuration
1987
- docs.server.ts # Server-side docs loader
1988
- pages/
1989
- ${cfg.entry}/
1990
- index.astro # Docs index page
1991
- [...slug].astro # Dynamic doc page
1992
- api/
1993
- ${cfg.entry}.ts # Search/AI API route
1994
- \\\`\\\`\\\`
1995
-
1996
- ## What's Next?
1997
-
1998
- Head to the [Quickstart](/${cfg.entry}/quickstart) guide to start writing your first page.
1999
- `;
2000
- }
2001
- function astroQuickstartPageTemplate(cfg) {
2002
- const t = getThemeInfo(cfg.theme);
2003
- return `\
2004
- ---
2005
- title: "Quickstart"
2006
- description: "Get up and running in minutes"
2007
- ---
2008
-
2009
- # Quickstart
2010
-
2011
- This guide walks you through creating your first documentation page.
2012
-
2013
- ## Creating a Page
2014
-
2015
- Create a new folder under \\\`${cfg.entry}/\\\` with a \\\`page.md\\\` file:
2016
-
2017
- \\\`\\\`\\\`bash
2018
- mkdir -p ${cfg.entry}/my-page
2019
- \\\`\\\`\\\`
2020
-
2021
- Then create \\\`${cfg.entry}/my-page/page.md\\\`:
2022
-
2023
- \\\`\\\`\\\`md
2024
- ---
2025
- title: "My Page"
2026
- description: "A custom documentation page"
2027
- ---
2028
-
2029
- # My Page
2030
-
2031
- Write your content here using **Markdown**.
2032
- \\\`\\\`\\\`
2033
-
2034
- Your page is now available at \\\`/${cfg.entry}/my-page\\\`.
2035
-
2036
- ## Customizing the Theme
2037
-
2038
- Edit \\\`src/lib/docs.config.ts\\\` to change colors, typography, and component defaults:
2039
-
2040
- \\\`\\\`\\\`ts title="src/lib/docs.config.ts"
2041
- theme: ${t.factory}({
2042
- ui: {
2043
- colors: { primary: "#22c55e" },
2044
- },
2045
- }),
2046
- \\\`\\\`\\\`
2047
-
2048
- ## Deploying
2049
-
2050
- Build your docs for production:
2051
-
2052
- \\\`\\\`\\\`bash
2053
- pnpm build
2054
- \\\`\\\`\\\`
2055
-
2056
- Deploy to Vercel, Netlify, or any Node.js hosting platform.
2057
- `;
2058
- }
2059
- function nuxtDocsConfigTemplate(cfg) {
2060
- if (cfg.theme === "custom" && cfg.customThemeName) {
2061
- const exportName = getThemeExportName(cfg.customThemeName);
2062
- return `\
2063
- import { defineDocs } from "@farming-labs/docs";
2064
- import { ${exportName} } from "${cfg.useAlias ? "~/themes/" + cfg.customThemeName.replace(/\.ts$/i, "") : "./themes/" + cfg.customThemeName.replace(/\.ts$/i, "")}";
2065
-
2066
- export default defineDocs({
2067
- entry: "${cfg.entry}",
2068
- contentDir: "${cfg.entry}",
2069
- ${renderI18nConfig(cfg)}${renderApiReferenceConfig(cfg)} theme: ${exportName}({
2070
- ui: {
2071
- colors: { primary: "#6366f1" },
2072
- },
2073
- }),
2074
-
2075
- nav: {
2076
- title: "${cfg.projectName}",
2077
- url: "/${cfg.entry}",
2078
- },
2079
-
2080
- breadcrumb: { enabled: true },
2081
-
2082
- metadata: {
2083
- titleTemplate: "%s – ${cfg.projectName}",
2084
- description: "Documentation for ${cfg.projectName}",
2085
- },
2086
- });
2087
- `;
2088
- }
2089
- const t = getThemeInfo(cfg.theme);
2090
- return `\
2091
- import { defineDocs } from "@farming-labs/docs";
2092
- import { ${t.factory} } from "${t.nuxtImport}";
2093
-
2094
- export default defineDocs({
2095
- entry: "${cfg.entry}",
2096
- contentDir: "${cfg.entry}",
2097
- ${renderI18nConfig(cfg)}${renderApiReferenceConfig(cfg)} theme: ${t.factory}({
2098
- ui: {
2099
- colors: { primary: "#6366f1" },
2100
- },
2101
- }),
2102
-
2103
- nav: {
2104
- title: "${cfg.projectName}",
2105
- url: "/${cfg.entry}",
2106
- },
2107
-
2108
- breadcrumb: { enabled: true },
2109
-
2110
- metadata: {
2111
- titleTemplate: "%s – ${cfg.projectName}",
2112
- description: "Documentation for ${cfg.projectName}",
2113
- },
2114
- });
2115
- `;
2116
- }
2117
- function nuxtServerApiDocsRouteTemplate(cfg) {
2118
- return `\
2119
- import { defineDocsHandler } from "@farming-labs/nuxt/server";
2120
- import config from "${cfg.useAlias ? "~/docs.config" : "../../docs.config"}";
2121
-
2122
- export default defineDocsHandler(config, useStorage);
2123
- `;
2124
- }
2125
- function nuxtServerDocsPublicMiddlewareTemplate(cfg) {
2126
- return `\
2127
- import { defineDocsPublicHandler } from "@farming-labs/nuxt/server";
2128
- import config from "${cfg.useAlias ? "~/docs.config" : "../../docs.config"}";
2129
-
2130
- export default defineDocsPublicHandler(config, useStorage);
2131
- `;
2132
- }
2133
- function nuxtServerApiReferenceRouteTemplate(filePath, useAlias) {
2134
- return `\
2135
- import { defineApiReferenceHandler } from "@farming-labs/nuxt/api-reference";
2136
- import config from "${useAlias ? "~/docs.config" : relativeImport(filePath, "docs.config.ts")}";
2137
-
2138
- export default defineApiReferenceHandler(config);
2139
- `;
2140
- }
2141
- function nuxtDocsPageTemplate(cfg) {
2142
- return `\
2143
- <script setup lang="ts">
2144
- import { DocsLayout, DocsContent } from "@farming-labs/nuxt-theme";
2145
- import config from "${cfg.useAlias ? "~/docs.config" : "../../docs.config"}";
2146
-
2147
- const route = useRoute();
2148
- const pathname = computed(() => route.path);
2149
-
2150
- const { data, error } = await useAsyncData(\`docs-\${pathname.value}\`, () =>
2151
- $fetch("/api/docs", {
2152
- query: { pathname: pathname.value },
2153
- })
2154
- );
2155
-
2156
- if (error.value) {
2157
- throw createError({
2158
- statusCode: 404,
2159
- statusMessage: "Page not found",
2160
- });
2161
- }
2162
- <\/script>
2163
-
2164
- <template>
2165
- <div v-if="data" class="fd-docs-wrapper">
2166
- <DocsLayout :tree="data.tree" :config="config">
2167
- <DocsContent :data="data" :config="config" />
2168
- </DocsLayout>
2169
- </div>
2170
- </template>
2171
- `;
2172
- }
2173
- function nuxtConfigTemplate(cfg) {
2174
- return `\
2175
- export default defineNuxtConfig({
2176
- compatibilityDate: "2024-11-01",
2177
-
2178
- css: ["${getThemeCssImport(cfg.theme)}"],
2179
-
2180
- vite: {
2181
- optimizeDeps: {
2182
- include: ["@farming-labs/docs", "@farming-labs/nuxt", "@farming-labs/nuxt-theme", "@farming-labs/theme"],
2183
- },
2184
- },
2185
-
2186
- nitro: {
2187
- moduleSideEffects: ["@farming-labs/nuxt/server"],
2188
- serverAssets: [{ baseName: "${cfg.entry}", dir: "${cfg.entry}" }],
2189
- },
2190
- });
2191
- `;
2192
- }
2193
- function nuxtWelcomePageTemplate(cfg) {
2194
- return `\
2195
- ---
2196
- order: 1
2197
- title: Documentation
2198
- description: Welcome to ${cfg.projectName} documentation
2199
- icon: book
2200
- ---
2201
-
2202
- # Welcome to ${cfg.projectName}
2203
-
2204
- Get started with our documentation. Browse the pages on the left to learn more.
2205
-
2206
- ## Overview
2207
-
2208
- This documentation was generated by \`@farming-labs/docs\`. Edit the markdown files in \`${cfg.entry}/\` to customize.
2209
-
2210
- ## Features
2211
-
2212
- - **Markdown Support** — Write docs with standard Markdown
2213
- - **Syntax Highlighting** — Code blocks with automatic highlighting
2214
- - **Dark Mode** — Built-in theme switching
2215
- - **Search** — Full-text search across all pages (⌘ K)
2216
- - **Responsive** — Works on any screen size
2217
-
2218
- ---
2219
-
2220
- ## Next Steps
2221
-
2222
- Start by reading the [Installation](/${cfg.entry}/installation) guide, then follow the [Quickstart](/${cfg.entry}/quickstart) to build something.
2223
- `;
2224
- }
2225
- function nuxtInstallationPageTemplate(cfg) {
2226
- const t = getThemeInfo(cfg.theme);
2227
- return `\
2228
- ---
2229
- order: 3
2230
- title: Installation
2231
- description: How to install and set up ${cfg.projectName}
2232
- icon: terminal
2233
- ---
2234
-
2235
- # Installation
2236
-
2237
- Follow these steps to install and configure ${cfg.projectName}.
2238
-
2239
- ## Prerequisites
2240
-
2241
- - Node.js 18+
2242
- - A package manager (pnpm, npm, or yarn)
2243
-
2244
- ## Install Dependencies
2245
-
2246
- \`\`\`bash
2247
- pnpm add @farming-labs/docs @farming-labs/nuxt @farming-labs/nuxt-theme @farming-labs/theme
2248
- \`\`\`
2249
-
2250
- ## Configuration
2251
-
2252
- Your project includes a \`docs.config.ts\` at the root:
2253
-
2254
- \`\`\`ts title="docs.config.ts"
2255
- import { defineDocs } from "@farming-labs/docs";
2256
- import { ${t.factory} } from "${t.nuxtImport}";
2257
-
2258
- export default defineDocs({
2259
- entry: "${cfg.entry}",
2260
- contentDir: "${cfg.entry}",
2261
- theme: ${t.factory}({
2262
- ui: { colors: { primary: "#6366f1" } },
2263
- }),
2264
- });
2265
- \`\`\`
2266
-
2267
- ## Project Structure
2268
-
2269
- \`\`\`
2270
- ${cfg.entry}/ # Markdown content
2271
- page.md
2272
- installation/page.md
2273
- quickstart/page.md
2274
- server/
2275
- api/docs.ts # Page data, search, and AI chat API
2276
- middleware/docs-public.ts # llms.txt, sitemap, .well-known, .md, and MCP aliases
2277
- pages/
2278
- ${cfg.entry}/[[...slug]].vue # Docs catch-all page
2279
- docs.config.ts
2280
- nuxt.config.ts
2281
- \`\`\`
2282
-
2283
- ## What's Next?
2284
-
2285
- Head to the [Quickstart](/${cfg.entry}/quickstart) guide to start writing your first page.
2286
- `;
2287
- }
2288
- function nuxtQuickstartPageTemplate(cfg) {
2289
- const t = getThemeInfo(cfg.theme);
2290
- return `\
2291
- ---
2292
- order: 2
2293
- title: Quickstart
2294
- description: Get up and running in minutes
2295
- icon: rocket
2296
- ---
2297
-
2298
- # Quickstart
2299
-
2300
- This guide walks you through creating your first documentation page.
2301
-
2302
- ## Creating a Page
2303
-
2304
- Create a new folder under \`${cfg.entry}/\` with a \`page.md\` file:
2305
-
2306
- \`\`\`bash
2307
- mkdir -p ${cfg.entry}/my-page
2308
- \`\`\`
2309
-
2310
- Then create \`${cfg.entry}/my-page/page.md\`:
2311
-
2312
- \`\`\`md
2313
- ---
2314
- title: "My Page"
2315
- description: "A custom documentation page"
2316
- ---
2317
-
2318
- # My Page
2319
-
2320
- Write your content here using **Markdown**.
2321
- \`\`\`
2322
-
2323
- Your page is now available at \`/${cfg.entry}/my-page\`.
2324
-
2325
- ## Customizing the Theme
2326
-
2327
- Edit \`docs.config.ts\` to change colors and typography:
2328
-
2329
- \`\`\`ts
2330
- theme: ${t.factory}({
2331
- ui: {
2332
- colors: { primary: "#22c55e" },
2333
- },
2334
- }),
2335
- \`\`\`
2336
-
2337
- ## Deploying
2338
-
2339
- Build your docs for production:
2340
-
2341
- \`\`\`bash
2342
- pnpm build
2343
- \`\`\`
2344
-
2345
- Deploy to Vercel, Netlify, or any Node.js hosting platform.
2346
- `;
2347
- }
2348
- function nuxtGlobalCssTemplate(theme, customThemeName, globalCssRelPath) {
2349
- if (theme === "custom" && customThemeName && globalCssRelPath) return `\
2350
- @import "${getCustomThemeCssImportPath(globalCssRelPath, customThemeName.replace(/\.css$/i, ""))}";
2351
- `;
2352
- return `\
2353
- @import "${getThemeCssImport(theme)}";
2354
- `;
2355
- }
2356
- function nuxtCssImportLine(theme, customThemeName, globalCssRelPath) {
2357
- if (theme === "custom" && customThemeName && globalCssRelPath) return `@import "${getCustomThemeCssImportPath(globalCssRelPath, customThemeName.replace(/\.css$/i, ""))}";`;
2358
- return `@import "${getThemeCssImport(theme)}";`;
2359
- }
2360
- function injectNuxtCssImport(existingContent, theme, customThemeName, globalCssRelPath) {
2361
- const importLine = nuxtCssImportLine(theme, customThemeName, globalCssRelPath);
2362
- if (existingContent.includes(importLine)) return null;
2363
- if (theme !== "custom" && hasBuiltInThemeCssImport(existingContent)) return null;
2364
- if (theme === "custom" && existingContent.includes("themes/") && existingContent.includes(".css")) return null;
2365
- const lines = existingContent.split("\n");
2366
- const lastImportIdx = lines.reduce((acc, l, i) => l.trimStart().startsWith("@import") ? i : acc, -1);
2367
- if (lastImportIdx >= 0) lines.splice(lastImportIdx + 1, 0, importLine);
2368
- else lines.unshift(importLine);
2369
- return lines.join("\n");
2370
- }
2371
-
2372
- //#endregion
2373
- export { svelteDocsPublicHookTemplate as $, nextConfigMergedTemplate as A, nuxtServerApiDocsRouteTemplate as B, injectRootProviderIntoLayout as C, injectTanstackVitePlugins as D, injectTanstackRootProviderIntoRoute as E, nuxtDocsConfigTemplate as F, quickstartPageTemplate as G, nuxtServerDocsPublicMiddlewareTemplate as H, nuxtDocsPageTemplate as I, svelteDocsApiRouteTemplate as J, rootLayoutTemplate as K, nuxtGlobalCssTemplate as L, nextLocaleDocPageTemplate as M, nextLocalizedPageTemplate as N, installationPageTemplate as O, nuxtConfigTemplate as P, svelteDocsPageTemplate as Q, nuxtInstallationPageTemplate as R, injectNuxtCssImport as S, injectSvelteDocsPublicHook as T, nuxtWelcomePageTemplate as U, nuxtServerApiReferenceRouteTemplate as V, postcssConfigTemplate as W, svelteDocsLayoutServerTemplate as X, svelteDocsConfigTemplate as Y, svelteDocsLayoutTemplate as Z, getAstroAdapterPkg as _, tanstackViteConfigTemplate as _t, astroDocsIndexTemplate as a, svelteWelcomePageTemplate as at, injectAstroDocsMiddleware as b, welcomePageTemplate as bt, astroDocsServerTemplate as c, tanstackDocsCatchAllRouteTemplate as ct, astroQuickstartPageTemplate as d, tanstackDocsIndexRouteTemplate as dt, svelteDocsServerTemplate as et, astroWelcomePageTemplate as f, tanstackDocsPublicRouteTemplate as ft, docsLayoutTemplate as g, tanstackRootRouteTemplate as gt, docsConfigTemplate as h, tanstackQuickstartPageTemplate as ht, astroDocsConfigTemplate as i, svelteRootLayoutTemplate as it, nextConfigTemplate as j, nextApiReferencePageTemplate as k, astroGlobalCssTemplate as l, tanstackDocsConfigTemplate as lt, customThemeTsTemplate as m, tanstackInstallationPageTemplate as mt, astroApiRouteTemplate as n, svelteInstallationPageTemplate as nt, astroDocsMiddlewareTemplate as o, tanstackApiDocsRouteTemplate as ot, customThemeCssTemplate as p, tanstackDocsServerTemplate as pt, svelteApiReferenceRouteTemplate as q, astroConfigTemplate as r, svelteQuickstartPageTemplate as rt, astroDocsPageTemplate as s, tanstackApiReferenceRouteTemplate as st, astroApiReferenceRouteTemplate as t, svelteGlobalCssTemplate as tt, astroInstallationPageTemplate as u, tanstackDocsFunctionsTemplate as ut, globalCssTemplate as v, tanstackWelcomePageTemplate as vt, injectSvelteCssImport as w, injectCssImport as x, injectAstroCssImport as y, tsconfigTemplate as yt, nuxtQuickstartPageTemplate as z };