@fumadocs/cli 1.7.0 → 1.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,112 @@
1
+ import { t as docs } from "./docs--WqEHTyl.js";
2
+ import { r as findSource } from "./utils-DbMe7h6c.js";
3
+ import path from "node:path";
4
+ //#region src/features/ai.ts
5
+ const providers = {
6
+ openrouter: {
7
+ label: "AI SDK",
8
+ hint: "default to OpenRouter",
9
+ env: "OPENROUTER_API_KEY"
10
+ },
11
+ llmgateway: {
12
+ label: "LLMGateway",
13
+ hint: "open-source LLM gateway, API key required",
14
+ env: "LLM_GATEWAY_API_KEY"
15
+ },
16
+ inkeep: {
17
+ label: "Inkeep AI",
18
+ hint: "API key required",
19
+ env: "INKEEP_API_KEY"
20
+ }
21
+ };
22
+ const ai = {
23
+ id: "ai",
24
+ title: "AI Chat",
25
+ description: "Ask AI dialog for your docs",
26
+ requires: [docs],
27
+ options: { provider: {
28
+ message: "Choose an AI provider",
29
+ choices: Object.entries(providers).map(([value, { label, hint }]) => ({
30
+ value,
31
+ label,
32
+ hint
33
+ }))
34
+ } },
35
+ supports: (project) => project.static ? "AI chat requires a server to run the chat route handler." : true,
36
+ async apply(ctx, { provider }) {
37
+ await ctx.install(`ai/${provider}`);
38
+ ctx.env(providers[provider].env, "");
39
+ if (ctx.project.source.dynamic) await readDynamicSource(ctx);
40
+ const { cwd, baseDir, info, config } = ctx.project;
41
+ const clientLayoutImport = `@/${path.posix.join(config.aliases.componentsDir, "ai/layout")}`;
42
+ const layout = await findSource(cwd, path.join(baseDir, info.routesDir), "<DocsLayout");
43
+ let layoutModule;
44
+ let wired = false;
45
+ if (layout !== void 0) await ctx.source(layout, (file) => {
46
+ wired = file.code.includes(`'${clientLayoutImport}'`);
47
+ const declaration = !wired && file.program.body.find((node) => node.type === "ImportDeclaration" && node.importKind !== "type" && /^fumadocs-ui\/layouts\/(docs|notebook|glass|spacious)$/.test(node.source.value) && node.specifiers.length === 1 && node.specifiers[0].local.name === "DocsLayout");
48
+ if (!declaration) return;
49
+ layoutModule = declaration.source.value;
50
+ file.s.overwrite(declaration.source.start, declaration.source.end, `'${clientLayoutImport}'`);
51
+ });
52
+ if (layoutModule) await ctx.write(path.join(baseDir, config.aliases.componentsDir, "ai/layout.tsx"), clientLayout(layoutModule));
53
+ else if (!wired) ctx.note("Pass the AI chat to your docs layout, see https://fumadocs.dev/docs/integrations/llms#ask-ai.");
54
+ ctx.note(`Set ${providers[provider].env} in \`.env.local\`.`);
55
+ }
56
+ };
57
+ const floatingTrigger = `
58
+ <AISearchTrigger
59
+ position="float"
60
+ className={buttonVariants({
61
+ variant: 'secondary',
62
+ className: 'text-fd-muted-foreground rounded-2xl',
63
+ })}
64
+ >
65
+ <MessageCircleIcon className="size-4.5" />
66
+ Ask AI
67
+ </AISearchTrigger>`;
68
+ /** a client component rendering the docs layout with the installed chat */
69
+ function clientLayout(layoutModule) {
70
+ const trigger = /\/(docs|notebook)$/.test(layoutModule);
71
+ return `'use client';
72
+ import { DocsLayout as Layout, type DocsLayoutProps } from '${layoutModule}';
73
+ ${trigger ? `import { buttonVariants } from 'fumadocs-ui/components/ui/button';
74
+ import { MessageCircleIcon } from 'lucide-react';
75
+ ` : ""}import {
76
+ AISearch,
77
+ AISearchPanel,${trigger ? "\n AISearchTrigger," : ""}
78
+ useAISearchContext,
79
+ useHotKey,
80
+ } from './search';
81
+
82
+ export function DocsLayout(props: DocsLayoutProps) {
83
+ return (
84
+ <AISearch>
85
+ <ChatLayout {...props} />${trigger ? floatingTrigger : ""}
86
+ </AISearch>
87
+ );
88
+ }
89
+
90
+ function ChatLayout(props: DocsLayoutProps) {
91
+ const { open, setOpen } = useAISearchContext();
92
+ useHotKey();
93
+
94
+ return <Layout {...props} aiChat={{ open, onOpenChange: setOpen, panel: <AISearchPanel /> }} />;
95
+ }
96
+ `;
97
+ }
98
+ /** the installed chat route indexes pages of a static `source`, runtime sources resolve on demand */
99
+ async function readDynamicSource(ctx) {
100
+ const { cwd, baseDir } = ctx.project;
101
+ const route = await findSource(cwd, baseDir, "createSearchServer");
102
+ if (!(route !== void 0 && await ctx.source(route, (file) => {
103
+ file.s.replaceAll("import { source } from '@/lib/source';", "import { getSource } from '@/lib/source';");
104
+ file.s.replaceAll("source.getPages()", "(await getSource()).getPages()");
105
+ file.s.replaceAll(" if (!('getText' in page.data)) return null;\n\n", "");
106
+ file.s.replaceAll("await page.data.getText('processed')", "page.data.content");
107
+ }))) ctx.note("Read pages from `getSource()` in the chat route, the search index is built from `page.data.content`.");
108
+ }
109
+ //#endregion
110
+ export { ai as t };
111
+
112
+ //# sourceMappingURL=ai-wXWLPFI5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-wXWLPFI5.js","names":[],"sources":["../src/features/ai.ts"],"sourcesContent":["import path from 'node:path';\nimport type { ImportDeclaration } from 'oxc-parser';\nimport type { Feature, FeatureContext } from '@/features';\nimport { findSource } from './utils';\nimport { docs } from './docs';\n\nconst providers = {\n openrouter: { label: 'AI SDK', hint: 'default to OpenRouter', env: 'OPENROUTER_API_KEY' },\n llmgateway: {\n label: 'LLMGateway',\n hint: 'open-source LLM gateway, API key required',\n env: 'LLM_GATEWAY_API_KEY',\n },\n inkeep: { label: 'Inkeep AI', hint: 'API key required', env: 'INKEEP_API_KEY' },\n};\n\nexport type AIProvider = keyof typeof providers;\n\nexport const ai: Feature<{ provider: AIProvider }> = {\n id: 'ai',\n title: 'AI Chat',\n description: 'Ask AI dialog for your docs',\n requires: [docs],\n options: {\n provider: {\n message: 'Choose an AI provider',\n choices: Object.entries(providers).map(([value, { label, hint }]) => ({\n value: value as AIProvider,\n label,\n hint,\n })),\n },\n },\n supports: (project) =>\n project.static ? 'AI chat requires a server to run the chat route handler.' : true,\n async apply(ctx, { provider }) {\n await ctx.install(`ai/${provider}`);\n ctx.env(providers[provider].env, '');\n if (ctx.project.source.dynamic) await readDynamicSource(ctx);\n\n const { cwd, baseDir, info, config } = ctx.project;\n // e.g. `./components` -> `@/components/ai/layout`\n const clientLayoutImport = `@/${path.posix.join(config.aliases.componentsDir, 'ai/layout')}`;\n const layout = await findSource(cwd, path.join(baseDir, info.routesDir), '<DocsLayout');\n let layoutModule: string | undefined;\n let wired = false;\n\n if (layout !== undefined) {\n await ctx.source(layout, (file) => {\n wired = file.code.includes(`'${clientLayoutImport}'`);\n // `aiChat` takes client state, render the layout from a client component\n const declaration =\n !wired &&\n file.program.body.find(\n (node): node is ImportDeclaration =>\n node.type === 'ImportDeclaration' &&\n node.importKind !== 'type' &&\n /^fumadocs-ui\\/layouts\\/(docs|notebook|glass|spacious)$/.test(node.source.value) &&\n node.specifiers.length === 1 &&\n node.specifiers[0].local.name === 'DocsLayout',\n );\n if (!declaration) return;\n\n layoutModule = declaration.source.value;\n file.s.overwrite(\n declaration.source.start,\n declaration.source.end,\n `'${clientLayoutImport}'`,\n );\n });\n }\n\n if (layoutModule) {\n await ctx.write(\n path.join(baseDir, config.aliases.componentsDir, 'ai/layout.tsx'),\n clientLayout(layoutModule),\n );\n } else if (!wired) {\n ctx.note(\n 'Pass the AI chat to your docs layout, see https://fumadocs.dev/docs/integrations/llms#ask-ai.',\n );\n }\n ctx.note(`Set ${providers[provider].env} in \\`.env.local\\`.`);\n },\n};\n\nconst floatingTrigger = `\n <AISearchTrigger\n position=\"float\"\n className={buttonVariants({\n variant: 'secondary',\n className: 'text-fd-muted-foreground rounded-2xl',\n })}\n >\n <MessageCircleIcon className=\"size-4.5\" />\n Ask AI\n </AISearchTrigger>`;\n\n/** a client component rendering the docs layout with the installed chat */\nfunction clientLayout(layoutModule: string) {\n // Glass and Spacious layouts have their own trigger\n const trigger = /\\/(docs|notebook)$/.test(layoutModule);\n\n return `'use client';\nimport { DocsLayout as Layout, type DocsLayoutProps } from '${layoutModule}';\n${\n trigger\n ? `import { buttonVariants } from 'fumadocs-ui/components/ui/button';\nimport { MessageCircleIcon } from 'lucide-react';\n`\n : ''\n}import {\n AISearch,\n AISearchPanel,${trigger ? '\\n AISearchTrigger,' : ''}\n useAISearchContext,\n useHotKey,\n} from './search';\n\nexport function DocsLayout(props: DocsLayoutProps) {\n return (\n <AISearch>\n <ChatLayout {...props} />${trigger ? floatingTrigger : ''}\n </AISearch>\n );\n}\n\nfunction ChatLayout(props: DocsLayoutProps) {\n const { open, setOpen } = useAISearchContext();\n useHotKey();\n\n return <Layout {...props} aiChat={{ open, onOpenChange: setOpen, panel: <AISearchPanel /> }} />;\n}\n`;\n}\n\n/** the installed chat route indexes pages of a static `source`, runtime sources resolve on demand */\nasync function readDynamicSource(ctx: FeatureContext) {\n const { cwd, baseDir } = ctx.project;\n const route = await findSource(cwd, baseDir, 'createSearchServer');\n const edited =\n route !== undefined &&\n (await ctx.source(route, (file) => {\n file.s.replaceAll(\n \"import { source } from '@/lib/source';\",\n \"import { getSource } from '@/lib/source';\",\n );\n file.s.replaceAll('source.getPages()', '(await getSource()).getPages()');\n // every page of a runtime source carries its Markdown\n file.s.replaceAll(\" if (!('getText' in page.data)) return null;\\n\\n\", '');\n file.s.replaceAll(\"await page.data.getText('processed')\", 'page.data.content');\n }));\n\n if (!edited)\n ctx.note(\n 'Read pages from `getSource()` in the chat route, the search index is built from `page.data.content`.',\n );\n}\n"],"mappings":";;;;AAMA,MAAM,YAAY;CAChB,YAAY;EAAE,OAAO;EAAU,MAAM;EAAyB,KAAK;CAAqB;CACxF,YAAY;EACV,OAAO;EACP,MAAM;EACN,KAAK;CACP;CACA,QAAQ;EAAE,OAAO;EAAa,MAAM;EAAoB,KAAK;CAAiB;AAChF;AAIA,MAAa,KAAwC;CACnD,IAAI;CACJ,OAAO;CACP,aAAa;CACb,UAAU,CAAC,IAAI;CACf,SAAS,EACP,UAAU;EACR,SAAS;EACT,SAAS,OAAO,QAAQ,SAAS,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,aAAa;GAC7D;GACP;GACA;EACF,EAAE;CACJ,EACF;CACA,WAAW,YACT,QAAQ,SAAS,6DAA6D;CAChF,MAAM,MAAM,KAAK,EAAE,YAAY;EAC7B,MAAM,IAAI,QAAQ,MAAM,UAAU;EAClC,IAAI,IAAI,UAAU,SAAS,CAAC,KAAK,EAAE;EACnC,IAAI,IAAI,QAAQ,OAAO,SAAS,MAAM,kBAAkB,GAAG;EAE3D,MAAM,EAAE,KAAK,SAAS,MAAM,WAAW,IAAI;EAE3C,MAAM,qBAAqB,KAAK,KAAK,MAAM,KAAK,OAAO,QAAQ,eAAe,WAAW;EACzF,MAAM,SAAS,MAAM,WAAW,KAAK,KAAK,KAAK,SAAS,KAAK,SAAS,GAAG,aAAa;EACtF,IAAI;EACJ,IAAI,QAAQ;EAEZ,IAAI,WAAW,KAAA,GACb,MAAM,IAAI,OAAO,SAAS,SAAS;GACjC,QAAQ,KAAK,KAAK,SAAS,IAAI,mBAAmB,EAAE;GAEpD,MAAM,cACJ,CAAC,SACD,KAAK,QAAQ,KAAK,MACf,SACC,KAAK,SAAS,uBACd,KAAK,eAAe,UACpB,yDAAyD,KAAK,KAAK,OAAO,KAAK,KAC/E,KAAK,WAAW,WAAW,KAC3B,KAAK,WAAW,EAAE,CAAC,MAAM,SAAS,YACtC;GACF,IAAI,CAAC,aAAa;GAElB,eAAe,YAAY,OAAO;GAClC,KAAK,EAAE,UACL,YAAY,OAAO,OACnB,YAAY,OAAO,KACnB,IAAI,mBAAmB,EACzB;EACF,CAAC;EAGH,IAAI,cACF,MAAM,IAAI,MACR,KAAK,KAAK,SAAS,OAAO,QAAQ,eAAe,eAAe,GAChE,aAAa,YAAY,CAC3B;OACK,IAAI,CAAC,OACV,IAAI,KACF,+FACF;EAEF,IAAI,KAAK,OAAO,UAAU,SAAS,CAAC,IAAI,oBAAoB;CAC9D;AACF;AAEA,MAAM,kBAAkB;;;;;;;;;;;;AAaxB,SAAS,aAAa,cAAsB;CAE1C,MAAM,UAAU,qBAAqB,KAAK,YAAY;CAEtD,OAAO;8DACqD,aAAa;EAEzE,UACI;;IAGA,GACL;;kBAEiB,UAAU,yBAAyB,GAAG;;;;;;;;iCAQvB,UAAU,kBAAkB,GAAG;;;;;;;;;;;;AAYhE;;AAGA,eAAe,kBAAkB,KAAqB;CACpD,MAAM,EAAE,KAAK,YAAY,IAAI;CAC7B,MAAM,QAAQ,MAAM,WAAW,KAAK,SAAS,oBAAoB;CAcjE,IAAI,EAZF,UAAU,KAAA,KACT,MAAM,IAAI,OAAO,QAAQ,SAAS;EACjC,KAAK,EAAE,WACL,0CACA,2CACF;EACA,KAAK,EAAE,WAAW,qBAAqB,gCAAgC;EAEvE,KAAK,EAAE,WAAW,yDAAyD,EAAE;EAC7E,KAAK,EAAE,WAAW,wCAAwC,mBAAmB;CAC/E,CAAC,IAGD,IAAI,KACF,sGACF;AACJ"}
@@ -1,8 +1,8 @@
1
1
  import { t as docs } from "./docs--WqEHTyl.js";
2
- import { t as ai } from "./ai-C19ZOP53.js";
2
+ import { t as ai } from "./ai-wXWLPFI5.js";
3
3
  import { r as llms } from "./llms-Br0RJXXg.js";
4
4
  import { t as og } from "./og-LFlX1Bl4.js";
5
- import { t as search } from "./search-WfSdiGx-.js";
5
+ import { t as search } from "./search-BbzvfJal.js";
6
6
  import { t as mcp } from "./mcp-Ce_W93we.js";
7
7
  import { n as webmcp } from "./webmcp-DyTLrsXL.js";
8
8
  import { t as feedback } from "./feedback-Brj092vC.js";
@@ -24,4 +24,4 @@ const features = [
24
24
  //#endregion
25
25
  export { features as t };
26
26
 
27
- //# sourceMappingURL=all-BBf7I8hG.js.map
27
+ //# sourceMappingURL=all-BmDsMSFN.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"all-BBf7I8hG.js","names":[],"sources":["../src/features/all.ts"],"sourcesContent":["import type { AnyFeature } from '.';\nimport { docs } from './docs';\nimport { ai } from './ai';\nimport { llms } from './llms';\nimport { og } from './og';\nimport { search } from './search';\nimport { mcp } from './mcp';\nimport { webmcp } from './webmcp';\nimport { feedback } from './feedback';\nimport { epub } from './epub';\nimport { lint } from './lint';\n\nexport const features: AnyFeature[] = [\n docs,\n ai,\n llms,\n mcp,\n webmcp,\n og,\n search,\n feedback,\n epub,\n lint,\n];\n"],"mappings":";;;;;;;;;;;AAYA,MAAa,WAAyB;CACpC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF"}
1
+ {"version":3,"file":"all-BmDsMSFN.js","names":[],"sources":["../src/features/all.ts"],"sourcesContent":["import type { AnyFeature } from '.';\nimport { docs } from './docs';\nimport { ai } from './ai';\nimport { llms } from './llms';\nimport { og } from './og';\nimport { search } from './search';\nimport { mcp } from './mcp';\nimport { webmcp } from './webmcp';\nimport { feedback } from './feedback';\nimport { epub } from './epub';\nimport { lint } from './lint';\n\nexport const features: AnyFeature[] = [\n docs,\n ai,\n llms,\n mcp,\n webmcp,\n og,\n search,\n feedback,\n epub,\n lint,\n];\n"],"mappings":";;;;;;;;;;;AAYA,MAAa,WAAyB;CACpC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF"}
@@ -1,2 +1,2 @@
1
- import { t as ai } from "../ai-C19ZOP53.js";
1
+ import { t as ai } from "../ai-wXWLPFI5.js";
2
2
  export { ai };
@@ -1,2 +1,2 @@
1
- import { t as features } from "../all-BBf7I8hG.js";
1
+ import { t as features } from "../all-BmDsMSFN.js";
2
2
  export { features };
@@ -1,11 +1,14 @@
1
+ import { o as ReactFramework, s as SourceInfo } from "../index-DI66DoV8.js";
1
2
  import { r as Feature } from "../index-Cs7hw2un.js";
2
- import { t as SourceRef } from "../utils-CxJ7kw39.js";
3
+ import { p as FormattedRoute, t as SourceRef } from "../utils-CxJ7kw39.js";
3
4
  //#region src/features/search.d.ts
4
5
  /** how client code reads public env variables */
5
6
  interface Env {
6
7
  prefix: string;
7
8
  read: string;
8
9
  }
10
+ /** `scripts/sync-content.ts`, syncing the search indexes pre-rendered to `output` */
11
+ export declare const syncScript: (output: string, imports: string, body: string) => string;
9
12
  declare const providers: {
10
13
  'orama-cloud': {
11
14
  label: string;
@@ -18,10 +21,13 @@ declare const providers: {
18
21
  static: true;
19
22
  dialog: (env: Env) => string;
20
23
  exportIndexes: ({ ref }: SourceRef) => {
21
- imports: string;
24
+ head: string;
22
25
  documents: string;
23
26
  };
24
- sync: (env: Env) => string;
27
+ sync: (env: Env, { output }: {
28
+ dir: string;
29
+ output: string;
30
+ }) => string;
25
31
  };
26
32
  algolia: {
27
33
  label: string;
@@ -34,10 +40,32 @@ declare const providers: {
34
40
  static: true;
35
41
  dialog: (env: Env) => string;
36
42
  exportIndexes: ({ ref }: SourceRef) => {
37
- imports: string;
43
+ head: string;
38
44
  documents: string;
39
45
  };
40
- sync: (env: Env) => string;
46
+ sync: (env: Env, { output }: {
47
+ dir: string;
48
+ output: string;
49
+ }) => string;
50
+ };
51
+ meilisearch: {
52
+ label: string;
53
+ hint: string;
54
+ dependencies: {
55
+ meilisearch: null;
56
+ };
57
+ publicEnv: string[];
58
+ privateEnv: string[];
59
+ static: true;
60
+ dialog: (env: Env) => string;
61
+ exportIndexes: ({ ref }: SourceRef) => {
62
+ head: string;
63
+ documents: string;
64
+ };
65
+ sync: (env: Env, { output }: {
66
+ dir: string;
67
+ output: string;
68
+ }) => string;
41
69
  };
42
70
  typesense: {
43
71
  label: string;
@@ -50,12 +78,14 @@ declare const providers: {
50
78
  privateEnv: string[];
51
79
  static: true;
52
80
  dialog: (env: Env) => string;
53
- exportIndexes: (src: SourceRef) => {
54
- imports: string;
81
+ exportIndexes: (src: SourceRef, async: boolean) => {
82
+ head: string;
55
83
  documents: string;
56
- file: (async: boolean) => string;
57
84
  };
58
- sync: (env: Env) => string;
85
+ sync: (env: Env, { output }: {
86
+ dir: string;
87
+ output: string;
88
+ }) => string;
59
89
  };
60
90
  mixedbread: {
61
91
  label: string;
@@ -67,7 +97,10 @@ declare const providers: {
67
97
  privateEnv: string[];
68
98
  static: false;
69
99
  dialog: () => string;
70
- sync: (_env: Env, dir: string) => string;
100
+ sync: (_env: Env, { dir }: {
101
+ dir: string;
102
+ output: string;
103
+ }) => string;
71
104
  searchRoute: {
72
105
  next: string;
73
106
  'react-router': string;
@@ -77,6 +110,18 @@ declare const providers: {
77
110
  };
78
111
  };
79
112
  export type SearchProvider = keyof typeof providers;
113
+ /** pre-rendered on build to export the search indexes */
114
+ export declare const staticJson: (framework: ReactFramework) => FormattedRoute;
115
+ export declare const staticRoute: (framework: ReactFramework, head: string, documents: string) => string;
116
+ /** where `static.json` is pre-rendered on build, `config` is the Vite config of TanStack Start */
117
+ export declare function staticOutput(framework: ReactFramework, config?: string): string;
118
+ /** runs the sync script after build */
119
+ export declare const syncCommand = "node --env-file-if-exists=.env.local scripts/sync-content.ts";
120
+ /** the files written by a provider, relative to the project, `output` is where `static.json` is pre-rendered */
121
+ export declare function templates(name: SearchProvider, framework: ReactFramework, { baseDir, source }: {
122
+ baseDir: string;
123
+ source: Pick<SourceInfo, 'dynamic' | 'async' | 'dir'>;
124
+ }, output: string): [file: string, content: string][];
80
125
  export declare const search: Feature<{
81
126
  provider: SearchProvider;
82
127
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"search.d.ts","names":[],"sources":["../../src/features/search.ts"],"mappings":";;;;UAwBU;EACR;EACA;;cA6GI;;;;;MAIc;;;;;;;;;;;;;;;;MA+CA;;;;;;;;;;;;;;;;MA+CA;MAAiB;;;;;;;;;;;;;;;;;MAgDjB;;;;;;;;;;;;;;;YAqER,8BAA8B;qBAe7B,QAAQ;EAAU,UAAU"}
1
+ {"version":3,"file":"search.d.ts","names":["_$__project_route0.FormattedRoute"],"sources":["../../src/features/search.ts"],"mappings":";;;;;UAyBU;EACR;EACA;;;qBAsEW,aAAU,gBACP,iBACC;cAqCX;;;;;MAIc;;;;;;;;;;;MATc;MAAgB;;;;;;;MAyD9B;;;;;;;;;;;MAzDc;MAAgB;;;;;;;MAyG9B;;;;;;;;;;;MAzGc;MAAgB;;;;;;;MA4J9B;MAAiB;;;;;;;;;;;MA5JH;MAAgB;;;;;;;MA4M9B;;;;;;;MA5Mc;MAAgB;;;;;;;;;;YAiRtC,8BAA8B;;qBAG7B,aAAU,WAAe,mBAAAA;qBAGzB,cAAW,WAAe,gBAAc,cAAc;;wBASnD,aAAa,WAAW,gBAAgB;;qBAgB3C;;wBAGG,UACd,MAAM,gBACN,WAAW,kBACT,SAAS;EAAY;EAAiB,QAAQ,KAAK;GACrD,kBACE,cAAc;qBAmBL,QAAQ;EAAU,UAAU"}
@@ -1,2 +1,2 @@
1
- import { t as search } from "../search-WfSdiGx-.js";
2
- export { search };
1
+ import { a as syncCommand, i as staticRoute, n as staticJson, o as syncScript, r as staticOutput, s as templates, t as search } from "../search-BbzvfJal.js";
2
+ export { search, staticJson, staticOutput, staticRoute, syncCommand, syncScript, templates };
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import { t as exists } from "./fs-D6J9dOEx.js";
5
5
  import { i as loadProject, n as frameworks } from "./project-DwRVTm4p.js";
6
6
  import { n as UIRegistries, t as FumadocsComponentInstaller } from "./installer-C4662Woc.js";
7
7
  import { t as runFeature } from "./features-Do6x9Tsz.js";
8
- import { t as features } from "./all-BBf7I8hG.js";
8
+ import { t as features } from "./all-BmDsMSFN.js";
9
9
  import fs from "node:fs/promises";
10
10
  import path from "node:path";
11
11
  import { cac } from "cac";
@@ -66,7 +66,7 @@ async function runTree(args) {
66
66
  }
67
67
  //#endregion
68
68
  //#region package.json
69
- var version = "1.7.0";
69
+ var version = "1.7.2";
70
70
  //#endregion
71
71
  //#region src/commands/customise.ts
72
72
  async function customise(config, connector) {
@@ -126,6 +126,18 @@ async function customise(config, connector) {
126
126
  },
127
127
  hint: "a docs layout with floating, translucent panels"
128
128
  },
129
+ ...config.uiLibrary === "base-ui" ? [{
130
+ label: "Spacious Layout",
131
+ value: {
132
+ id: "spacious",
133
+ targets: [{
134
+ subRegistry,
135
+ name: "layouts/spacious"
136
+ }],
137
+ print: () => printLayout(config, ["fumadocs-ui/layouts/spacious", "@/layouts/spacious"], ["fumadocs-ui/layouts/spacious/page", "@/layouts/spacious/page"])
138
+ },
139
+ hint: "a docs layout with the page in an inset panel, Base UI only"
140
+ }] : [],
129
141
  {
130
142
  label: "Home Layout",
131
143
  value: {
@@ -235,202 +247,89 @@ async function printLayout(config, ...maps) {
235
247
  function printSlot({ at, layoutId, name, isPage, uiLibrary }) {
236
248
  intro(picocolors.bold("What is Next?"));
237
249
  log.info(`You can check the installed layout slot in "${at}".`);
238
- const code = getSlotCode({
239
- at,
250
+ const slot = getSlot({
240
251
  layoutId,
241
252
  name,
242
253
  isPage,
243
254
  uiLibrary
244
255
  });
245
- if (code) {
246
- const layoutComponent = layoutId === "glass" ? "<GlassLayout />" : "<DocsLayout />";
247
- if (isPage) log.info(`${picocolors.bold("At your <DocsPage /> component, update your \"slots\" prop:")}\n\n${code}`);
248
- else log.info(`${picocolors.bold(`At your ${layoutComponent} component, update your "slots" prop:`)}\n\n${code}`);
249
- }
250
- }
251
- function getSlotCode({ at, layoutId, name, isPage, uiLibrary }) {
252
- if (layoutId === "glass") {
253
- if (isPage) return;
254
- switch (name) {
255
- case "header": return `import { Header } from '${at}';
256
+ if (!slot) return;
257
+ const [imports, value] = slot;
258
+ const component = isPage ? "DocsPage" : "DocsLayout";
259
+ log.info(`${picocolors.bold(`At your <${component} /> component, update your "slots" prop:`)}
256
260
 
257
- return (
258
- <GlassLayout
259
- slots={{
260
- header: Header,
261
- }}
262
- >
263
- ...
264
- </GlassLayout>
265
- );`;
266
- case "sidebar": {
267
- const imports = [
268
- "Sidebar",
269
- "SidebarDrawer",
270
- "SidebarProvider",
271
- "useSidebar"
272
- ];
273
- if (uiLibrary === "base-ui") imports.push("drawerHandle");
274
- return `import { ${imports.join(", ")} } from '${at}';
261
+ import { ${imports} } from '${at}';
275
262
 
276
263
  return (
277
- <GlassLayout
264
+ <${component}
278
265
  slots={{
279
- sidebar: {
280
- main: Sidebar,
281
- provider: SidebarProvider,
282
- use: useSidebar,
283
- drawer: SidebarDrawer,${uiLibrary === "base-ui" ? "\n drawerHandle," : ""}
284
- },
266
+ ${value},
285
267
  }}
286
268
  >
287
269
  ...
288
- </GlassLayout>
289
- );`;
290
- }
291
- default: return;
292
- }
293
- }
294
- if (isPage) switch (name) {
295
- case "toc":
296
- if (layoutId === "flux") return `import { TOCProvider, TOC } from '${at}';
297
-
298
- return (
299
- <DocsPage
300
- slots={{
301
- toc: {
270
+ </${component}>
271
+ );`);
272
+ }
273
+ /** the names to import from slot file, and the entry of `slots` prop */
274
+ function getSlot({ layoutId, name, isPage, uiLibrary }) {
275
+ if (isPage) {
276
+ if (layoutId === "glass") return;
277
+ switch (name) {
278
+ case "toc":
279
+ if (layoutId === "flux") return ["TOCProvider, TOC", `toc: {
302
280
  provider: TOCProvider,
303
281
  main: TOC,
304
- },
305
- }}
306
- >
307
- ...
308
- </DocsPage>
309
- );`;
310
- return `import { TOCProvider, TOC, TOCPopover } from '${at}';
311
-
312
- return (
313
- <DocsPage
314
- slots={{
315
- toc: {
282
+ }`];
283
+ if (layoutId === "spacious") return ["TOCProvider, TOC, TOCPopover, TOCDropdown", `toc: {
316
284
  provider: TOCProvider,
317
285
  main: TOC,
318
286
  popover: TOCPopover,
319
- },
320
- }}
321
- >
322
- ...
323
- </DocsPage>
324
- );`;
325
- case "container": return `import { Container } from '${at}';
326
-
327
- return (
328
- <DocsPage
329
- slots={{
330
- container: Container,
331
- }}
332
- >
333
- ...
334
- </DocsPage>
335
- );`;
336
- case "footer": return `import { Footer } from '${at}';
337
-
338
- return (
339
- <DocsPage
340
- slots={{
341
- footer: Footer,
342
- }}
343
- >
344
- ...
345
- </DocsPage>
346
- );`;
347
- case "breadcrumb": return `import { Breadcrumb } from '${at}';
348
-
349
- return (
350
- <DocsPage
351
- slots={{
352
- breadcrumb: Breadcrumb,
353
- }}
354
- >
355
- ...
356
- </DocsPage>
357
- );`;
358
- default: return;
287
+ dropdown: TOCDropdown,
288
+ }`];
289
+ return ["TOCProvider, TOC, TOCPopover", `toc: {
290
+ provider: TOCProvider,
291
+ main: TOC,
292
+ popover: TOCPopover,
293
+ }`];
294
+ case "container": return ["Container", "container: Container"];
295
+ case "footer": return ["Footer", "footer: Footer"];
296
+ case "breadcrumb": return ["Breadcrumb", "breadcrumb: Breadcrumb"];
297
+ default: return;
298
+ }
359
299
  }
360
300
  switch (name) {
361
301
  case "sidebar":
362
- if (layoutId === "notebook") return `import {
363
- SidebarProvider,
364
- Sidebar,
365
- SidebarTrigger,
366
- SidebarCollapseTrigger,
367
- useSidebar,
368
- } from '${at}';
369
-
370
- return (
371
- <DocsLayout
372
- slots={{
373
- sidebar: {
302
+ if (layoutId === "glass") {
303
+ const drawerHandle = uiLibrary === "base-ui";
304
+ return [`Sidebar, SidebarDrawer, SidebarProvider, useSidebar${drawerHandle ? ", drawerHandle" : ""}`, `sidebar: {
305
+ main: Sidebar,
306
+ provider: SidebarProvider,
307
+ use: useSidebar,
308
+ drawer: SidebarDrawer,${drawerHandle ? "\n drawerHandle," : ""}
309
+ }`];
310
+ }
311
+ if (layoutId === "spacious") return ["Sidebar, SidebarDrawer, SidebarProvider", `sidebar: {
312
+ provider: SidebarProvider,
313
+ main: Sidebar,
314
+ drawer: SidebarDrawer,
315
+ }`];
316
+ if (layoutId === "notebook") return ["SidebarProvider, Sidebar, SidebarTrigger, SidebarCollapseTrigger, useSidebar", `sidebar: {
374
317
  provider: SidebarProvider,
375
318
  root: Sidebar,
376
319
  trigger: SidebarTrigger,
377
320
  collapseTrigger: SidebarCollapseTrigger,
378
321
  useSidebar: useSidebar,
379
- },
380
- }}
381
- >
382
- ...
383
- </DocsLayout>
384
- );`;
385
- return `import { SidebarProvider, Sidebar, SidebarTrigger, useSidebar } from '${at}';
386
-
387
- return (
388
- <DocsLayout
389
- slots={{
390
- sidebar: {
322
+ }`];
323
+ return ["SidebarProvider, Sidebar, SidebarTrigger, useSidebar", `sidebar: {
391
324
  provider: SidebarProvider,
392
325
  root: Sidebar,
393
326
  trigger: SidebarTrigger,
394
327
  useSidebar: useSidebar,
395
- },
396
- }}
397
- >
398
- ...
399
- </DocsLayout>
400
- );`;
401
- case "container": return `import { Container } from '${at}';
402
-
403
- return (
404
- <DocsLayout
405
- slots={{
406
- container: Container,
407
- }}
408
- >
409
- ...
410
- </DocsLayout>
411
- );`;
412
- case "header": return `import { Header } from '${at}';
413
-
414
- return (
415
- <DocsLayout
416
- slots={{
417
- header: Header,
418
- }}
419
- >
420
- ...
421
- </DocsLayout>
422
- );`;
423
- case "tab-dropdown": return `import { TabDropdown } from '${at}';
424
-
425
- return (
426
- <DocsLayout
427
- slots={{
428
- tabDropdown: TabDropdown,
429
- }}
430
- >
431
- ...
432
- </DocsLayout>
433
- );`;
328
+ }`];
329
+ case "header": return ["Header", "header: Header"];
330
+ case "container": return ["Container", "container: Container"];
331
+ case "tab-dropdown": return ["TabDropdown", "tabDropdown: TabDropdown"];
332
+ case "actions": return ["HeaderActions", "actions: HeaderActions"];
434
333
  default: return;
435
334
  }
436
335
  }