@farming-labs/docs 0.0.20 → 0.0.22

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 (2) hide show
  1. package/dist/cli/index.mjs +60 -23
  2. package/package.json +1 -1
@@ -79,6 +79,17 @@ function detectGlobalCssFiles(cwd) {
79
79
  return GLOBAL_CSS_CANDIDATES.filter((rel) => fs.existsSync(path.join(cwd, rel)));
80
80
  }
81
81
  /**
82
+ * Detect whether the Next.js project uses `app` or `src/app` for the App Router.
83
+ * Returns the directory that exists; if both exist, prefers src/app; if neither, returns null.
84
+ */
85
+ function detectNextAppDir(cwd) {
86
+ const hasSrcApp = fs.existsSync(path.join(cwd, "src", "app"));
87
+ const hasApp = fs.existsSync(path.join(cwd, "app"));
88
+ if (hasSrcApp) return "src/app";
89
+ if (hasApp) return "app";
90
+ return null;
91
+ }
92
+ /**
82
93
  * Run a shell command synchronously, inheriting stdio.
83
94
  */
84
95
  function exec(command, cwd) {
@@ -257,13 +268,15 @@ function customThemeCssTemplate(themeName) {
257
268
  }
258
269
  `;
259
270
  }
260
- /** Config import for Next.js app/layout.tsx → root docs.config */
261
- function nextRootLayoutConfigImport(useAlias) {
262
- return useAlias ? "@/docs.config" : "../docs.config";
271
+ /** Config import for Next.js root layout → root docs.config */
272
+ function nextRootLayoutConfigImport(useAlias, nextAppDir = "app") {
273
+ if (useAlias) return "@/docs.config";
274
+ return nextAppDir === "src/app" ? "../../docs.config" : "../docs.config";
263
275
  }
264
276
  /** Config import for Next.js app/{entry}/layout.tsx → root docs.config */
265
- function nextDocsLayoutConfigImport(useAlias) {
266
- return useAlias ? "@/docs.config" : "../../docs.config";
277
+ function nextDocsLayoutConfigImport(useAlias, nextAppDir = "app") {
278
+ if (useAlias) return "@/docs.config";
279
+ return nextAppDir === "src/app" ? "../../../docs.config" : "../../docs.config";
267
280
  }
268
281
  /** Config import for SvelteKit src/lib/docs.server.ts → src/lib/docs.config */
269
282
  function svelteServerConfigImport(useAlias) {
@@ -363,10 +376,11 @@ function rootLayoutTemplate(cfg, globalCssRelPath = "app/globals.css") {
363
376
  if (globalCssRelPath.startsWith("app/")) cssImport = "./" + globalCssRelPath.slice(4);
364
377
  else if (globalCssRelPath.startsWith("src/app/")) cssImport = "./" + globalCssRelPath.slice(8);
365
378
  else cssImport = "../" + globalCssRelPath;
379
+ const appDir = cfg.nextAppDir ?? "app";
366
380
  return `\
367
381
  import type { Metadata } from "next";
368
382
  import { RootProvider } from "@farming-labs/theme";
369
- import docsConfig from "${nextRootLayoutConfigImport(cfg.useAlias)}";
383
+ import docsConfig from "${nextRootLayoutConfigImport(cfg.useAlias, appDir)}";
370
384
  import "${cssImport}";
371
385
 
372
386
  export const metadata: Metadata = {
@@ -440,8 +454,9 @@ function injectCssImport(existingContent, theme, customThemeName, globalCssRelPa
440
454
  return lines.join("\n");
441
455
  }
442
456
  function docsLayoutTemplate(cfg) {
457
+ const appDir = cfg.nextAppDir ?? "app";
443
458
  return `\
444
- import docsConfig from "${nextDocsLayoutConfigImport(cfg.useAlias)}";
459
+ import docsConfig from "${nextDocsLayoutConfigImport(cfg.useAlias, appDir)}";
445
460
  import { createDocsLayout, createDocsMetadata } from "@farming-labs/theme";
446
461
 
447
462
  export const metadata = createDocsMetadata(docsConfig);
@@ -494,6 +509,7 @@ function tsconfigTemplate(useAlias = false) {
494
509
  `;
495
510
  }
496
511
  function welcomePageTemplate(cfg) {
512
+ const appDir = cfg.nextAppDir ?? "app";
497
513
  return `\
498
514
  ---
499
515
  title: "Documentation"
@@ -505,7 +521,7 @@ description: "Welcome to ${cfg.projectName} documentation"
505
521
  Get started with our documentation. Browse the pages on the left to learn more.
506
522
 
507
523
  <Callout type="info">
508
- This documentation was generated by \`@farming-labs/docs\`. Edit the MDX files in \`app/${cfg.entry}/\` to customize.
524
+ This documentation was generated by \`@farming-labs/docs\`. Edit the MDX files in \`${appDir}/${cfg.entry}/\` to customize.
509
525
  </Callout>
510
526
 
511
527
  ## Overview
@@ -571,7 +587,7 @@ export default defineDocs({
571
587
  ## Project Structure
572
588
 
573
589
  \`\`\`
574
- app/
590
+ ${cfg.nextAppDir ?? "app"}/
575
591
  ${cfg.entry}/
576
592
  layout.tsx # Docs layout
577
593
  page.mdx # /${cfg.entry}
@@ -602,13 +618,13 @@ This guide walks you through creating your first documentation page.
602
618
 
603
619
  ## Creating a Page
604
620
 
605
- Create a new folder under \`app/${cfg.entry}/\` with a \`page.mdx\` file:
621
+ Create a new folder under \`${cfg.nextAppDir ?? "app"}/${cfg.entry}/\` with a \`page.mdx\` file:
606
622
 
607
623
  \`\`\`bash
608
- mkdir -p app/${cfg.entry}/my-page
624
+ mkdir -p ${cfg.nextAppDir ?? "app"}/${cfg.entry}/my-page
609
625
  \`\`\`
610
626
 
611
- Then create \`app/${cfg.entry}/my-page/page.mdx\`:
627
+ Then create \`${cfg.nextAppDir ?? "app"}/${cfg.entry}/my-page/page.mdx\`:
612
628
 
613
629
  \`\`\`mdx
614
630
  ---
@@ -1832,6 +1848,7 @@ async function init(options = {}) {
1832
1848
  }
1833
1849
  const devCmd = pmFresh === "yarn" ? "yarn dev" : pmFresh === "npm" ? "npm run dev" : pmFresh === "bun" ? "bun dev" : "pnpm dev";
1834
1850
  p.outro(pc.green(`Done! Run ${pc.cyan(`cd ${projectName} && ${devCmd}`)} to start the dev server and navigate to the /docs.`));
1851
+ p.outro(pc.green("Happy documenting!"));
1835
1852
  process.exit(0);
1836
1853
  }
1837
1854
  let framework = detectFramework(cwd);
@@ -1871,6 +1888,24 @@ async function init(options = {}) {
1871
1888
  }
1872
1889
  framework = picked;
1873
1890
  }
1891
+ let nextAppDir = "app";
1892
+ if (framework === "nextjs") {
1893
+ const detected = detectNextAppDir(cwd);
1894
+ if (detected) {
1895
+ nextAppDir = detected;
1896
+ p.log.info(`Using App Router at ${pc.cyan(nextAppDir)} (detected ${detected === "src/app" ? "src directory" : "root app"})`);
1897
+ } else {
1898
+ const useSrcApp = await p.confirm({
1899
+ message: "Do you use the src directory for the App Router? (e.g. src/app instead of app)",
1900
+ initialValue: false
1901
+ });
1902
+ if (p.isCancel(useSrcApp)) {
1903
+ p.outro(pc.red("Init cancelled."));
1904
+ process.exit(0);
1905
+ }
1906
+ nextAppDir = useSrcApp ? "src/app" : "app";
1907
+ }
1908
+ }
1874
1909
  const theme = await p.select({
1875
1910
  message: "Which theme would you like to use?",
1876
1911
  options: [
@@ -1998,7 +2033,7 @@ async function init(options = {}) {
1998
2033
  const entryPath = entry.trim() || defaultEntry;
1999
2034
  const detectedCssFiles = detectGlobalCssFiles(cwd);
2000
2035
  let globalCssRelPath;
2001
- const defaultCssPath = framework === "sveltekit" ? "src/app.css" : framework === "astro" ? "src/styles/global.css" : framework === "nuxt" ? "assets/css/main.css" : "app/globals.css";
2036
+ const defaultCssPath = framework === "sveltekit" ? "src/app.css" : framework === "astro" ? "src/styles/global.css" : framework === "nuxt" ? "assets/css/main.css" : framework === "nextjs" ? `${nextAppDir}/globals.css` : "app/globals.css";
2002
2037
  if (detectedCssFiles.length === 1) {
2003
2038
  globalCssRelPath = detectedCssFiles[0];
2004
2039
  p.log.info(`Found global CSS at ${pc.cyan(globalCssRelPath)}`);
@@ -2041,7 +2076,8 @@ async function init(options = {}) {
2041
2076
  projectName,
2042
2077
  framework,
2043
2078
  useAlias,
2044
- astroAdapter
2079
+ astroAdapter,
2080
+ ...framework === "nextjs" && { nextAppDir }
2045
2081
  };
2046
2082
  const s = p.spinner();
2047
2083
  s.start("Scaffolding docs files");
@@ -2183,6 +2219,7 @@ async function init(options = {}) {
2183
2219
  }
2184
2220
  }
2185
2221
  function scaffoldNextJs(cwd, cfg, globalCssRelPath, write, skipped, written) {
2222
+ const appDir = cfg.nextAppDir ?? "app";
2186
2223
  if (cfg.theme === "custom" && cfg.customThemeName) {
2187
2224
  const baseName = cfg.customThemeName.replace(/\.(ts|css)$/i, "");
2188
2225
  write(`themes/${baseName}.ts`, customThemeTsTemplate(baseName));
@@ -2198,16 +2235,16 @@ function scaffoldNextJs(cwd, cfg, globalCssRelPath, write, skipped, written) {
2198
2235
  written.push(configFile + " (updated)");
2199
2236
  } else skipped.push(configFile + " (already configured)");
2200
2237
  } else write("next.config.ts", nextConfigTemplate());
2201
- const rootLayoutPath = path.join(cwd, "app/layout.tsx");
2238
+ const rootLayoutPath = path.join(cwd, `${appDir}/layout.tsx`);
2202
2239
  const existingRootLayout = readFileSafe(rootLayoutPath);
2203
- if (!existingRootLayout) write("app/layout.tsx", rootLayoutTemplate(cfg, globalCssRelPath), true);
2240
+ if (!existingRootLayout) write(`${appDir}/layout.tsx`, rootLayoutTemplate(cfg, globalCssRelPath), true);
2204
2241
  else if (!existingRootLayout.includes("RootProvider")) {
2205
2242
  const injected = injectRootProviderIntoLayout(existingRootLayout);
2206
2243
  if (injected) {
2207
2244
  writeFileSafe(rootLayoutPath, injected, true);
2208
- written.push("app/layout.tsx (injected RootProvider)");
2209
- } else skipped.push("app/layout.tsx (could not inject RootProvider)");
2210
- } else skipped.push("app/layout.tsx (already has RootProvider)");
2245
+ written.push(`${appDir}/layout.tsx (injected RootProvider)`);
2246
+ } else skipped.push(`${appDir}/layout.tsx (could not inject RootProvider)`);
2247
+ } else skipped.push(`${appDir}/layout.tsx (already has RootProvider)`);
2211
2248
  const globalCssAbsPath = path.join(cwd, globalCssRelPath);
2212
2249
  const existingGlobalCss = readFileSafe(globalCssAbsPath);
2213
2250
  if (existingGlobalCss) {
@@ -2217,12 +2254,12 @@ function scaffoldNextJs(cwd, cfg, globalCssRelPath, write, skipped, written) {
2217
2254
  written.push(globalCssRelPath + " (updated)");
2218
2255
  } else skipped.push(globalCssRelPath + " (already configured)");
2219
2256
  } else write(globalCssRelPath, globalCssTemplate(cfg.theme, cfg.customThemeName, globalCssRelPath));
2220
- write(`app/${cfg.entry}/layout.tsx`, docsLayoutTemplate(cfg));
2257
+ write(`${appDir}/${cfg.entry}/layout.tsx`, docsLayoutTemplate(cfg));
2221
2258
  write("postcss.config.mjs", postcssConfigTemplate());
2222
2259
  if (!fileExists(path.join(cwd, "tsconfig.json"))) write("tsconfig.json", tsconfigTemplate(cfg.useAlias));
2223
- write(`app/${cfg.entry}/page.mdx`, welcomePageTemplate(cfg));
2224
- write(`app/${cfg.entry}/installation/page.mdx`, installationPageTemplate(cfg));
2225
- write(`app/${cfg.entry}/quickstart/page.mdx`, quickstartPageTemplate(cfg));
2260
+ write(`${appDir}/${cfg.entry}/page.mdx`, welcomePageTemplate(cfg));
2261
+ write(`${appDir}/${cfg.entry}/installation/page.mdx`, installationPageTemplate(cfg));
2262
+ write(`${appDir}/${cfg.entry}/quickstart/page.mdx`, quickstartPageTemplate(cfg));
2226
2263
  }
2227
2264
  function scaffoldSvelteKit(cwd, cfg, globalCssRelPath, write, skipped, written) {
2228
2265
  if (cfg.theme === "custom" && cfg.customThemeName) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farming-labs/docs",
3
- "version": "0.0.20",
3
+ "version": "0.0.22",
4
4
  "description": "Modern, flexible MDX-based docs framework — core types, config, and CLI",
5
5
  "keywords": [
6
6
  "docs",