@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.
- package/dist/ai-wXWLPFI5.js +112 -0
- package/dist/ai-wXWLPFI5.js.map +1 -0
- package/dist/{all-BBf7I8hG.js → all-BmDsMSFN.js} +3 -3
- package/dist/{all-BBf7I8hG.js.map → all-BmDsMSFN.js.map} +1 -1
- package/dist/features/ai.js +1 -1
- package/dist/features/all.js +1 -1
- package/dist/features/search.d.ts +55 -10
- package/dist/features/search.d.ts.map +1 -1
- package/dist/features/search.js +2 -2
- package/dist/index.js +68 -169
- package/dist/index.js.map +1 -1
- package/dist/{search-WfSdiGx-.js → search-BbzvfJal.js} +134 -77
- package/dist/search-BbzvfJal.js.map +1 -0
- package/package.json +4 -4
- package/dist/ai-C19ZOP53.js +0 -100
- package/dist/ai-C19ZOP53.js.map +0 -1
- package/dist/search-WfSdiGx-.js.map +0 -1
|
@@ -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-
|
|
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-
|
|
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-
|
|
27
|
+
//# sourceMappingURL=all-BmDsMSFN.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"all-
|
|
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"}
|
package/dist/features/ai.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as ai } from "../ai-
|
|
1
|
+
import { t as ai } from "../ai-wXWLPFI5.js";
|
|
2
2
|
export { ai };
|
package/dist/features/all.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as features } from "../all-
|
|
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
|
-
|
|
24
|
+
head: string;
|
|
22
25
|
documents: string;
|
|
23
26
|
};
|
|
24
|
-
sync: (env: Env
|
|
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
|
-
|
|
43
|
+
head: string;
|
|
38
44
|
documents: string;
|
|
39
45
|
};
|
|
40
|
-
sync: (env: Env
|
|
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
|
-
|
|
81
|
+
exportIndexes: (src: SourceRef, async: boolean) => {
|
|
82
|
+
head: string;
|
|
55
83
|
documents: string;
|
|
56
|
-
file: (async: boolean) => string;
|
|
57
84
|
};
|
|
58
|
-
sync: (env: Env
|
|
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:
|
|
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":"
|
|
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"}
|
package/dist/features/search.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as search } from "../search-
|
|
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-
|
|
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.
|
|
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
|
|
239
|
-
at,
|
|
250
|
+
const slot = getSlot({
|
|
240
251
|
layoutId,
|
|
241
252
|
name,
|
|
242
253
|
isPage,
|
|
243
254
|
uiLibrary
|
|
244
255
|
});
|
|
245
|
-
if (
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
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
|
-
|
|
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
|
-
|
|
264
|
+
<${component}
|
|
278
265
|
slots={{
|
|
279
|
-
|
|
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
|
-
|
|
289
|
-
)
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
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
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
return
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
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 === "
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
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
|
-
|
|
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
|
}
|