@farming-labs/docs 0.0.2-beta.14 → 0.0.2-beta.17
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/cli/index.mjs +815 -20
- package/dist/index.d.mts +40 -8
- package/package.json +1 -1
package/dist/cli/index.mjs
CHANGED
|
@@ -16,6 +16,8 @@ function detectFramework(cwd) {
|
|
|
16
16
|
};
|
|
17
17
|
if (allDeps["next"]) return "nextjs";
|
|
18
18
|
if (allDeps["@sveltejs/kit"]) return "sveltekit";
|
|
19
|
+
if (allDeps["astro"]) return "astro";
|
|
20
|
+
if (allDeps["nuxt"]) return "nuxt";
|
|
19
21
|
return null;
|
|
20
22
|
}
|
|
21
23
|
function detectPackageManager(cwd) {
|
|
@@ -65,7 +67,9 @@ const GLOBAL_CSS_CANDIDATES = [
|
|
|
65
67
|
"styles/globals.css",
|
|
66
68
|
"styles/global.css",
|
|
67
69
|
"src/styles/globals.css",
|
|
68
|
-
"src/styles/global.css"
|
|
70
|
+
"src/styles/global.css",
|
|
71
|
+
"assets/css/main.css",
|
|
72
|
+
"assets/main.css"
|
|
69
73
|
];
|
|
70
74
|
/**
|
|
71
75
|
* Find existing global CSS files in the project.
|
|
@@ -133,22 +137,45 @@ const THEME_INFO = {
|
|
|
133
137
|
factory: "fumadocs",
|
|
134
138
|
nextImport: "@farming-labs/theme",
|
|
135
139
|
svelteImport: "@farming-labs/svelte-theme",
|
|
140
|
+
astroImport: "@farming-labs/astro-theme",
|
|
141
|
+
nuxtImport: "@farming-labs/nuxt-theme",
|
|
136
142
|
nextCssImport: "default",
|
|
137
|
-
svelteCssTheme: "fumadocs"
|
|
143
|
+
svelteCssTheme: "fumadocs",
|
|
144
|
+
astroCssTheme: "fumadocs",
|
|
145
|
+
nuxtCssTheme: "fumadocs"
|
|
138
146
|
},
|
|
139
147
|
darksharp: {
|
|
140
148
|
factory: "darksharp",
|
|
141
149
|
nextImport: "@farming-labs/theme/darksharp",
|
|
142
150
|
svelteImport: "@farming-labs/svelte-theme/darksharp",
|
|
151
|
+
astroImport: "@farming-labs/astro-theme/darksharp",
|
|
152
|
+
nuxtImport: "@farming-labs/nuxt-theme/darksharp",
|
|
143
153
|
nextCssImport: "darksharp",
|
|
144
|
-
svelteCssTheme: "darksharp"
|
|
154
|
+
svelteCssTheme: "darksharp",
|
|
155
|
+
astroCssTheme: "darksharp",
|
|
156
|
+
nuxtCssTheme: "darksharp"
|
|
145
157
|
},
|
|
146
158
|
"pixel-border": {
|
|
147
159
|
factory: "pixelBorder",
|
|
148
160
|
nextImport: "@farming-labs/theme/pixel-border",
|
|
149
161
|
svelteImport: "@farming-labs/svelte-theme/pixel-border",
|
|
162
|
+
astroImport: "@farming-labs/astro-theme/pixel-border",
|
|
163
|
+
nuxtImport: "@farming-labs/nuxt-theme/pixel-border",
|
|
150
164
|
nextCssImport: "pixel-border",
|
|
151
|
-
svelteCssTheme: "pixel-border"
|
|
165
|
+
svelteCssTheme: "pixel-border",
|
|
166
|
+
astroCssTheme: "pixel-border",
|
|
167
|
+
nuxtCssTheme: "pixel-border"
|
|
168
|
+
},
|
|
169
|
+
colorful: {
|
|
170
|
+
factory: "colorful",
|
|
171
|
+
nextImport: "@farming-labs/theme/colorful",
|
|
172
|
+
svelteImport: "@farming-labs/svelte-theme/colorful",
|
|
173
|
+
astroImport: "@farming-labs/astro-theme/colorful",
|
|
174
|
+
nuxtImport: "@farming-labs/nuxt-theme/colorful",
|
|
175
|
+
nextCssImport: "colorful",
|
|
176
|
+
svelteCssTheme: "colorful",
|
|
177
|
+
astroCssTheme: "colorful",
|
|
178
|
+
nuxtCssTheme: "colorful"
|
|
152
179
|
}
|
|
153
180
|
};
|
|
154
181
|
function getThemeInfo(theme) {
|
|
@@ -178,6 +205,17 @@ function sveltePageConfigImport(useAlias) {
|
|
|
178
205
|
function svelteLayoutServerImport(useAlias) {
|
|
179
206
|
return useAlias ? "$lib/docs.server" : "../../lib/docs.server";
|
|
180
207
|
}
|
|
208
|
+
function astroServerConfigImport(useAlias) {
|
|
209
|
+
return useAlias ? "@/lib/docs.config" : "./docs.config";
|
|
210
|
+
}
|
|
211
|
+
function astroPageConfigImport(useAlias, depth) {
|
|
212
|
+
if (useAlias) return "@/lib/docs.config";
|
|
213
|
+
return `${"../".repeat(depth)}lib/docs.config`;
|
|
214
|
+
}
|
|
215
|
+
function astroPageServerImport(useAlias, depth) {
|
|
216
|
+
if (useAlias) return "@/lib/docs.server";
|
|
217
|
+
return `${"../".repeat(depth)}lib/docs.server`;
|
|
218
|
+
}
|
|
181
219
|
function docsConfigTemplate(cfg) {
|
|
182
220
|
const t = getThemeInfo(cfg.theme);
|
|
183
221
|
return `\
|
|
@@ -768,6 +806,643 @@ pnpm build
|
|
|
768
806
|
Deploy to Vercel, Netlify, or any Node.js hosting platform.
|
|
769
807
|
`;
|
|
770
808
|
}
|
|
809
|
+
function astroDocsConfigTemplate(cfg) {
|
|
810
|
+
const t = getThemeInfo(cfg.theme);
|
|
811
|
+
return `\
|
|
812
|
+
import { defineDocs } from "@farming-labs/docs";
|
|
813
|
+
import { ${t.factory} } from "${t.astroImport}";
|
|
814
|
+
|
|
815
|
+
export default defineDocs({
|
|
816
|
+
entry: "${cfg.entry}",
|
|
817
|
+
contentDir: "${cfg.entry}",
|
|
818
|
+
theme: ${t.factory}({
|
|
819
|
+
ui: {
|
|
820
|
+
colors: { primary: "#6366f1" },
|
|
821
|
+
},
|
|
822
|
+
}),
|
|
823
|
+
|
|
824
|
+
nav: {
|
|
825
|
+
title: "${cfg.projectName}",
|
|
826
|
+
url: "/${cfg.entry}",
|
|
827
|
+
},
|
|
828
|
+
|
|
829
|
+
breadcrumb: { enabled: true },
|
|
830
|
+
|
|
831
|
+
metadata: {
|
|
832
|
+
titleTemplate: "%s – ${cfg.projectName}",
|
|
833
|
+
description: "Documentation for ${cfg.projectName}",
|
|
834
|
+
},
|
|
835
|
+
});
|
|
836
|
+
`;
|
|
837
|
+
}
|
|
838
|
+
function astroDocsServerTemplate(cfg) {
|
|
839
|
+
return `\
|
|
840
|
+
import { createDocsServer } from "@farming-labs/astro/server";
|
|
841
|
+
import config from "${astroServerConfigImport(cfg.useAlias)}";
|
|
842
|
+
|
|
843
|
+
const contentFiles = import.meta.glob("/${cfg.entry ?? "docs"}/**/*.{md,mdx}", {
|
|
844
|
+
query: "?raw",
|
|
845
|
+
import: "default",
|
|
846
|
+
eager: true,
|
|
847
|
+
}) as Record<string, string>;
|
|
848
|
+
|
|
849
|
+
export const { load, GET, POST } = createDocsServer({
|
|
850
|
+
...config,
|
|
851
|
+
_preloadedContent: contentFiles,
|
|
852
|
+
});
|
|
853
|
+
`;
|
|
854
|
+
}
|
|
855
|
+
const ASTRO_ADAPTER_INFO = {
|
|
856
|
+
vercel: {
|
|
857
|
+
pkg: "@astrojs/vercel",
|
|
858
|
+
import: "@astrojs/vercel"
|
|
859
|
+
},
|
|
860
|
+
netlify: {
|
|
861
|
+
pkg: "@astrojs/netlify",
|
|
862
|
+
import: "@astrojs/netlify"
|
|
863
|
+
},
|
|
864
|
+
node: {
|
|
865
|
+
pkg: "@astrojs/node",
|
|
866
|
+
import: "@astrojs/node"
|
|
867
|
+
},
|
|
868
|
+
cloudflare: {
|
|
869
|
+
pkg: "@astrojs/cloudflare",
|
|
870
|
+
import: "@astrojs/cloudflare"
|
|
871
|
+
}
|
|
872
|
+
};
|
|
873
|
+
function getAstroAdapterPkg(adapter) {
|
|
874
|
+
return ASTRO_ADAPTER_INFO[adapter]?.pkg ?? ASTRO_ADAPTER_INFO.vercel.pkg;
|
|
875
|
+
}
|
|
876
|
+
function astroConfigTemplate(adapter = "vercel") {
|
|
877
|
+
const info = ASTRO_ADAPTER_INFO[adapter] ?? ASTRO_ADAPTER_INFO.vercel;
|
|
878
|
+
const adapterCall = adapter === "node" ? `${adapter}({ mode: "standalone" })` : `${adapter}()`;
|
|
879
|
+
return `\
|
|
880
|
+
import { defineConfig } from "astro/config";
|
|
881
|
+
import ${adapter} from "${info.import}";
|
|
882
|
+
|
|
883
|
+
export default defineConfig({
|
|
884
|
+
output: "server",
|
|
885
|
+
adapter: ${adapterCall},
|
|
886
|
+
});
|
|
887
|
+
`;
|
|
888
|
+
}
|
|
889
|
+
function astroDocsPageTemplate(cfg) {
|
|
890
|
+
return `\
|
|
891
|
+
---
|
|
892
|
+
import DocsLayout from "@farming-labs/astro-theme/src/components/DocsLayout.astro";
|
|
893
|
+
import DocsContent from "@farming-labs/astro-theme/src/components/DocsContent.astro";
|
|
894
|
+
import SearchDialog from "@farming-labs/astro-theme/src/components/SearchDialog.astro";
|
|
895
|
+
import config from "${astroPageConfigImport(cfg.useAlias, 2)}";
|
|
896
|
+
import { load } from "${astroPageServerImport(cfg.useAlias, 2)}";
|
|
897
|
+
import "${`@farming-labs/astro-theme/${getThemeInfo(cfg.theme).astroCssTheme}/css`}";
|
|
898
|
+
|
|
899
|
+
const data = await load(Astro.url.pathname);
|
|
900
|
+
---
|
|
901
|
+
|
|
902
|
+
<html lang="en">
|
|
903
|
+
<head>
|
|
904
|
+
<meta charset="utf-8" />
|
|
905
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
906
|
+
<title>{data.title} – Docs</title>
|
|
907
|
+
</head>
|
|
908
|
+
<body>
|
|
909
|
+
<DocsLayout tree={data.tree} config={config}>
|
|
910
|
+
<DocsContent data={data} config={config} />
|
|
911
|
+
</DocsLayout>
|
|
912
|
+
<SearchDialog config={config} />
|
|
913
|
+
</body>
|
|
914
|
+
</html>
|
|
915
|
+
`;
|
|
916
|
+
}
|
|
917
|
+
function astroDocsIndexTemplate(cfg) {
|
|
918
|
+
return `\
|
|
919
|
+
---
|
|
920
|
+
import DocsLayout from "@farming-labs/astro-theme/src/components/DocsLayout.astro";
|
|
921
|
+
import DocsContent from "@farming-labs/astro-theme/src/components/DocsContent.astro";
|
|
922
|
+
import SearchDialog from "@farming-labs/astro-theme/src/components/SearchDialog.astro";
|
|
923
|
+
import config from "${astroPageConfigImport(cfg.useAlias, 2)}";
|
|
924
|
+
import { load } from "${astroPageServerImport(cfg.useAlias, 2)}";
|
|
925
|
+
import "${`@farming-labs/astro-theme/${getThemeInfo(cfg.theme).astroCssTheme}/css`}";
|
|
926
|
+
|
|
927
|
+
const data = await load(Astro.url.pathname);
|
|
928
|
+
---
|
|
929
|
+
|
|
930
|
+
<html lang="en">
|
|
931
|
+
<head>
|
|
932
|
+
<meta charset="utf-8" />
|
|
933
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
934
|
+
<title>{data.title} – Docs</title>
|
|
935
|
+
</head>
|
|
936
|
+
<body>
|
|
937
|
+
<DocsLayout tree={data.tree} config={config}>
|
|
938
|
+
<DocsContent data={data} config={config} />
|
|
939
|
+
</DocsLayout>
|
|
940
|
+
<SearchDialog config={config} />
|
|
941
|
+
</body>
|
|
942
|
+
</html>
|
|
943
|
+
`;
|
|
944
|
+
}
|
|
945
|
+
function astroApiRouteTemplate(cfg) {
|
|
946
|
+
return `\
|
|
947
|
+
import type { APIRoute } from "astro";
|
|
948
|
+
import { GET as docsGET, POST as docsPOST } from "${astroPageServerImport(cfg.useAlias, 2)}";
|
|
949
|
+
|
|
950
|
+
export const GET: APIRoute = async ({ request }) => {
|
|
951
|
+
return docsGET({ request });
|
|
952
|
+
};
|
|
953
|
+
|
|
954
|
+
export const POST: APIRoute = async ({ request }) => {
|
|
955
|
+
return docsPOST({ request });
|
|
956
|
+
};
|
|
957
|
+
`;
|
|
958
|
+
}
|
|
959
|
+
function astroGlobalCssTemplate(theme) {
|
|
960
|
+
return `\
|
|
961
|
+
@import "@farming-labs/astro-theme/${theme}/css";
|
|
962
|
+
`;
|
|
963
|
+
}
|
|
964
|
+
function astroCssImportLine(theme) {
|
|
965
|
+
return `@import "@farming-labs/astro-theme/${theme}/css";`;
|
|
966
|
+
}
|
|
967
|
+
function injectAstroCssImport(existingContent, theme) {
|
|
968
|
+
const importLine = astroCssImportLine(theme);
|
|
969
|
+
if (existingContent.includes(importLine)) return null;
|
|
970
|
+
const lines = existingContent.split("\n");
|
|
971
|
+
const lastImportIdx = lines.reduce((acc, l, i) => l.trimStart().startsWith("@import") ? i : acc, -1);
|
|
972
|
+
if (lastImportIdx >= 0) lines.splice(lastImportIdx + 1, 0, importLine);
|
|
973
|
+
else lines.unshift(importLine);
|
|
974
|
+
return lines.join("\n");
|
|
975
|
+
}
|
|
976
|
+
function astroWelcomePageTemplate(cfg) {
|
|
977
|
+
return `\
|
|
978
|
+
---
|
|
979
|
+
title: "Documentation"
|
|
980
|
+
description: "Welcome to ${cfg.projectName} documentation"
|
|
981
|
+
---
|
|
982
|
+
|
|
983
|
+
# Welcome to ${cfg.projectName}
|
|
984
|
+
|
|
985
|
+
Get started with our documentation. Browse the pages on the left to learn more.
|
|
986
|
+
|
|
987
|
+
## Overview
|
|
988
|
+
|
|
989
|
+
This documentation was generated by \`@farming-labs/docs\`. Edit the markdown files in \`${cfg.entry}/\` to customize.
|
|
990
|
+
|
|
991
|
+
## Features
|
|
992
|
+
|
|
993
|
+
- **Markdown Support** — Write docs with standard Markdown
|
|
994
|
+
- **Syntax Highlighting** — Code blocks with automatic highlighting
|
|
995
|
+
- **Dark Mode** — Built-in theme switching
|
|
996
|
+
- **Search** — Full-text search across all pages
|
|
997
|
+
- **Responsive** — Works on any screen size
|
|
998
|
+
|
|
999
|
+
---
|
|
1000
|
+
|
|
1001
|
+
## Next Steps
|
|
1002
|
+
|
|
1003
|
+
Start by reading the [Installation](/${cfg.entry}/installation) guide, then follow the [Quickstart](/${cfg.entry}/quickstart) to build something.
|
|
1004
|
+
`;
|
|
1005
|
+
}
|
|
1006
|
+
function astroInstallationPageTemplate(cfg) {
|
|
1007
|
+
const t = getThemeInfo(cfg.theme);
|
|
1008
|
+
return `\
|
|
1009
|
+
---
|
|
1010
|
+
title: "Installation"
|
|
1011
|
+
description: "How to install and set up ${cfg.projectName}"
|
|
1012
|
+
---
|
|
1013
|
+
|
|
1014
|
+
# Installation
|
|
1015
|
+
|
|
1016
|
+
Follow these steps to install and configure ${cfg.projectName}.
|
|
1017
|
+
|
|
1018
|
+
## Prerequisites
|
|
1019
|
+
|
|
1020
|
+
- Node.js 18+
|
|
1021
|
+
- A package manager (pnpm, npm, or yarn)
|
|
1022
|
+
|
|
1023
|
+
## Install Dependencies
|
|
1024
|
+
|
|
1025
|
+
\\\`\\\`\\\`bash
|
|
1026
|
+
pnpm add @farming-labs/docs @farming-labs/astro @farming-labs/astro-theme
|
|
1027
|
+
\\\`\\\`\\\`
|
|
1028
|
+
|
|
1029
|
+
## Configuration
|
|
1030
|
+
|
|
1031
|
+
Your project includes a \\\`docs.config.ts\\\` in \\\`src/lib/\\\`:
|
|
1032
|
+
|
|
1033
|
+
\\\`\\\`\\\`ts title="src/lib/docs.config.ts"
|
|
1034
|
+
import { defineDocs } from "@farming-labs/docs";
|
|
1035
|
+
import { ${t.factory} } from "${t.astroImport}";
|
|
1036
|
+
|
|
1037
|
+
export default defineDocs({
|
|
1038
|
+
entry: "${cfg.entry}",
|
|
1039
|
+
contentDir: "${cfg.entry}",
|
|
1040
|
+
theme: ${t.factory}({
|
|
1041
|
+
ui: { colors: { primary: "#6366f1" } },
|
|
1042
|
+
}),
|
|
1043
|
+
});
|
|
1044
|
+
\\\`\\\`\\\`
|
|
1045
|
+
|
|
1046
|
+
## Project Structure
|
|
1047
|
+
|
|
1048
|
+
\\\`\\\`\\\`
|
|
1049
|
+
${cfg.entry}/ # Markdown content
|
|
1050
|
+
page.md # /${cfg.entry}
|
|
1051
|
+
installation/
|
|
1052
|
+
page.md # /${cfg.entry}/installation
|
|
1053
|
+
quickstart/
|
|
1054
|
+
page.md # /${cfg.entry}/quickstart
|
|
1055
|
+
src/
|
|
1056
|
+
lib/
|
|
1057
|
+
docs.config.ts # Docs configuration
|
|
1058
|
+
docs.server.ts # Server-side docs loader
|
|
1059
|
+
pages/
|
|
1060
|
+
${cfg.entry}/
|
|
1061
|
+
index.astro # Docs index page
|
|
1062
|
+
[...slug].astro # Dynamic doc page
|
|
1063
|
+
api/
|
|
1064
|
+
${cfg.entry}.ts # Search/AI API route
|
|
1065
|
+
\\\`\\\`\\\`
|
|
1066
|
+
|
|
1067
|
+
## What's Next?
|
|
1068
|
+
|
|
1069
|
+
Head to the [Quickstart](/${cfg.entry}/quickstart) guide to start writing your first page.
|
|
1070
|
+
`;
|
|
1071
|
+
}
|
|
1072
|
+
function astroQuickstartPageTemplate(cfg) {
|
|
1073
|
+
const t = getThemeInfo(cfg.theme);
|
|
1074
|
+
return `\
|
|
1075
|
+
---
|
|
1076
|
+
title: "Quickstart"
|
|
1077
|
+
description: "Get up and running in minutes"
|
|
1078
|
+
---
|
|
1079
|
+
|
|
1080
|
+
# Quickstart
|
|
1081
|
+
|
|
1082
|
+
This guide walks you through creating your first documentation page.
|
|
1083
|
+
|
|
1084
|
+
## Creating a Page
|
|
1085
|
+
|
|
1086
|
+
Create a new folder under \\\`${cfg.entry}/\\\` with a \\\`page.md\\\` file:
|
|
1087
|
+
|
|
1088
|
+
\\\`\\\`\\\`bash
|
|
1089
|
+
mkdir -p ${cfg.entry}/my-page
|
|
1090
|
+
\\\`\\\`\\\`
|
|
1091
|
+
|
|
1092
|
+
Then create \\\`${cfg.entry}/my-page/page.md\\\`:
|
|
1093
|
+
|
|
1094
|
+
\\\`\\\`\\\`md
|
|
1095
|
+
---
|
|
1096
|
+
title: "My Page"
|
|
1097
|
+
description: "A custom documentation page"
|
|
1098
|
+
---
|
|
1099
|
+
|
|
1100
|
+
# My Page
|
|
1101
|
+
|
|
1102
|
+
Write your content here using **Markdown**.
|
|
1103
|
+
\\\`\\\`\\\`
|
|
1104
|
+
|
|
1105
|
+
Your page is now available at \\\`/${cfg.entry}/my-page\\\`.
|
|
1106
|
+
|
|
1107
|
+
## Customizing the Theme
|
|
1108
|
+
|
|
1109
|
+
Edit \\\`src/lib/docs.config.ts\\\` to change colors, typography, and component defaults:
|
|
1110
|
+
|
|
1111
|
+
\\\`\\\`\\\`ts title="src/lib/docs.config.ts"
|
|
1112
|
+
theme: ${t.factory}({
|
|
1113
|
+
ui: {
|
|
1114
|
+
colors: { primary: "#22c55e" },
|
|
1115
|
+
},
|
|
1116
|
+
}),
|
|
1117
|
+
\\\`\\\`\\\`
|
|
1118
|
+
|
|
1119
|
+
## Deploying
|
|
1120
|
+
|
|
1121
|
+
Build your docs for production:
|
|
1122
|
+
|
|
1123
|
+
\\\`\\\`\\\`bash
|
|
1124
|
+
pnpm build
|
|
1125
|
+
\\\`\\\`\\\`
|
|
1126
|
+
|
|
1127
|
+
Deploy to Vercel, Netlify, or any Node.js hosting platform.
|
|
1128
|
+
`;
|
|
1129
|
+
}
|
|
1130
|
+
function nuxtDocsConfigTemplate(cfg) {
|
|
1131
|
+
const t = getThemeInfo(cfg.theme);
|
|
1132
|
+
return `\
|
|
1133
|
+
import { defineDocs } from "@farming-labs/docs";
|
|
1134
|
+
import { ${t.factory} } from "${t.nuxtImport}";
|
|
1135
|
+
|
|
1136
|
+
export default defineDocs({
|
|
1137
|
+
entry: "${cfg.entry}",
|
|
1138
|
+
contentDir: "${cfg.entry}",
|
|
1139
|
+
theme: ${t.factory}({
|
|
1140
|
+
ui: {
|
|
1141
|
+
colors: { primary: "#6366f1" },
|
|
1142
|
+
},
|
|
1143
|
+
}),
|
|
1144
|
+
|
|
1145
|
+
nav: {
|
|
1146
|
+
title: "${cfg.projectName}",
|
|
1147
|
+
url: "/${cfg.entry}",
|
|
1148
|
+
},
|
|
1149
|
+
|
|
1150
|
+
breadcrumb: { enabled: true },
|
|
1151
|
+
|
|
1152
|
+
metadata: {
|
|
1153
|
+
titleTemplate: "%s – ${cfg.projectName}",
|
|
1154
|
+
description: "Documentation for ${cfg.projectName}",
|
|
1155
|
+
},
|
|
1156
|
+
});
|
|
1157
|
+
`;
|
|
1158
|
+
}
|
|
1159
|
+
function nuxtDocsServerTemplate(cfg) {
|
|
1160
|
+
return `\
|
|
1161
|
+
import { createDocsServer } from "@farming-labs/nuxt/server";
|
|
1162
|
+
import config from "../../docs.config";
|
|
1163
|
+
|
|
1164
|
+
const contentFiles = import.meta.glob("/${cfg.entry ?? "docs"}/**/*.{md,mdx}", {
|
|
1165
|
+
query: "?raw",
|
|
1166
|
+
import: "default",
|
|
1167
|
+
eager: true,
|
|
1168
|
+
}) as Record<string, string>;
|
|
1169
|
+
|
|
1170
|
+
export const docsServer = createDocsServer({
|
|
1171
|
+
...config,
|
|
1172
|
+
_preloadedContent: contentFiles,
|
|
1173
|
+
});
|
|
1174
|
+
`;
|
|
1175
|
+
}
|
|
1176
|
+
function nuxtServerApiDocsGetTemplate() {
|
|
1177
|
+
return `\
|
|
1178
|
+
import { getRequestURL } from "h3";
|
|
1179
|
+
import { docsServer } from "../utils/docs-server";
|
|
1180
|
+
|
|
1181
|
+
export default defineEventHandler((event) => {
|
|
1182
|
+
const url = getRequestURL(event);
|
|
1183
|
+
const request = new Request(url.href, {
|
|
1184
|
+
method: event.method,
|
|
1185
|
+
headers: event.headers,
|
|
1186
|
+
});
|
|
1187
|
+
return docsServer.GET({ request });
|
|
1188
|
+
});
|
|
1189
|
+
`;
|
|
1190
|
+
}
|
|
1191
|
+
function nuxtServerApiDocsPostTemplate() {
|
|
1192
|
+
return `\
|
|
1193
|
+
import { getRequestURL, readRawBody } from "h3";
|
|
1194
|
+
import { docsServer } from "../utils/docs-server";
|
|
1195
|
+
|
|
1196
|
+
export default defineEventHandler(async (event) => {
|
|
1197
|
+
const url = getRequestURL(event);
|
|
1198
|
+
const body = await readRawBody(event);
|
|
1199
|
+
const request = new Request(url.href, {
|
|
1200
|
+
method: "POST",
|
|
1201
|
+
headers: event.headers,
|
|
1202
|
+
body: body ?? undefined,
|
|
1203
|
+
});
|
|
1204
|
+
return docsServer.POST({ request });
|
|
1205
|
+
});
|
|
1206
|
+
`;
|
|
1207
|
+
}
|
|
1208
|
+
function nuxtServerApiDocsLoadTemplate() {
|
|
1209
|
+
return `\
|
|
1210
|
+
import { getQuery } from "h3";
|
|
1211
|
+
import { docsServer } from "../../utils/docs-server";
|
|
1212
|
+
|
|
1213
|
+
export default defineEventHandler(async (event) => {
|
|
1214
|
+
const query = getQuery(event);
|
|
1215
|
+
const pathname = (query.pathname as string) ?? "/docs";
|
|
1216
|
+
return docsServer.load(pathname);
|
|
1217
|
+
});
|
|
1218
|
+
`;
|
|
1219
|
+
}
|
|
1220
|
+
function nuxtDocsPageTemplate(cfg) {
|
|
1221
|
+
return `\
|
|
1222
|
+
<script setup lang="ts">
|
|
1223
|
+
import { DocsLayout, DocsContent } from "@farming-labs/nuxt-theme";
|
|
1224
|
+
import config from "${cfg.useAlias ? "~/docs.config" : "../../docs.config"}";
|
|
1225
|
+
|
|
1226
|
+
const route = useRoute();
|
|
1227
|
+
const pathname = computed(() => route.path);
|
|
1228
|
+
|
|
1229
|
+
const { data, error } = await useAsyncData(\`docs-\${pathname.value}\`, () =>
|
|
1230
|
+
$fetch("/api/docs/load", {
|
|
1231
|
+
query: { pathname: pathname.value },
|
|
1232
|
+
})
|
|
1233
|
+
);
|
|
1234
|
+
|
|
1235
|
+
if (error.value) {
|
|
1236
|
+
throw createError({
|
|
1237
|
+
statusCode: 404,
|
|
1238
|
+
statusMessage: "Page not found",
|
|
1239
|
+
});
|
|
1240
|
+
}
|
|
1241
|
+
<\/script>
|
|
1242
|
+
|
|
1243
|
+
<template>
|
|
1244
|
+
<div v-if="data" class="fd-docs-wrapper">
|
|
1245
|
+
<DocsLayout :tree="data.tree" :config="config">
|
|
1246
|
+
<DocsContent :data="data" :config="config" />
|
|
1247
|
+
</DocsLayout>
|
|
1248
|
+
</div>
|
|
1249
|
+
</template>
|
|
1250
|
+
`;
|
|
1251
|
+
}
|
|
1252
|
+
function nuxtConfigTemplate(cfg) {
|
|
1253
|
+
return `\
|
|
1254
|
+
export default defineNuxtConfig({
|
|
1255
|
+
compatibilityDate: "2024-11-01",
|
|
1256
|
+
|
|
1257
|
+
css: ["@farming-labs/nuxt-theme/${getThemeInfo(cfg.theme).nuxtCssTheme}/css"],
|
|
1258
|
+
|
|
1259
|
+
vite: {
|
|
1260
|
+
optimizeDeps: {
|
|
1261
|
+
include: ["@farming-labs/docs", "@farming-labs/nuxt", "@farming-labs/nuxt-theme"],
|
|
1262
|
+
},
|
|
1263
|
+
},
|
|
1264
|
+
|
|
1265
|
+
nitro: {
|
|
1266
|
+
moduleSideEffects: ["@farming-labs/nuxt/server"],
|
|
1267
|
+
},
|
|
1268
|
+
});
|
|
1269
|
+
`;
|
|
1270
|
+
}
|
|
1271
|
+
function nuxtWelcomePageTemplate(cfg) {
|
|
1272
|
+
return `\
|
|
1273
|
+
---
|
|
1274
|
+
order: 1
|
|
1275
|
+
title: Documentation
|
|
1276
|
+
description: Welcome to ${cfg.projectName} documentation
|
|
1277
|
+
icon: book
|
|
1278
|
+
---
|
|
1279
|
+
|
|
1280
|
+
# Welcome to ${cfg.projectName}
|
|
1281
|
+
|
|
1282
|
+
Get started with our documentation. Browse the pages on the left to learn more.
|
|
1283
|
+
|
|
1284
|
+
## Overview
|
|
1285
|
+
|
|
1286
|
+
This documentation was generated by \`@farming-labs/docs\`. Edit the markdown files in \`${cfg.entry}/\` to customize.
|
|
1287
|
+
|
|
1288
|
+
## Features
|
|
1289
|
+
|
|
1290
|
+
- **Markdown Support** — Write docs with standard Markdown
|
|
1291
|
+
- **Syntax Highlighting** — Code blocks with automatic highlighting
|
|
1292
|
+
- **Dark Mode** — Built-in theme switching
|
|
1293
|
+
- **Search** — Full-text search across all pages (⌘K)
|
|
1294
|
+
- **Responsive** — Works on any screen size
|
|
1295
|
+
|
|
1296
|
+
---
|
|
1297
|
+
|
|
1298
|
+
## Next Steps
|
|
1299
|
+
|
|
1300
|
+
Start by reading the [Installation](/${cfg.entry}/installation) guide, then follow the [Quickstart](/${cfg.entry}/quickstart) to build something.
|
|
1301
|
+
`;
|
|
1302
|
+
}
|
|
1303
|
+
function nuxtInstallationPageTemplate(cfg) {
|
|
1304
|
+
const t = getThemeInfo(cfg.theme);
|
|
1305
|
+
return `\
|
|
1306
|
+
---
|
|
1307
|
+
order: 3
|
|
1308
|
+
title: Installation
|
|
1309
|
+
description: How to install and set up ${cfg.projectName}
|
|
1310
|
+
icon: terminal
|
|
1311
|
+
---
|
|
1312
|
+
|
|
1313
|
+
# Installation
|
|
1314
|
+
|
|
1315
|
+
Follow these steps to install and configure ${cfg.projectName}.
|
|
1316
|
+
|
|
1317
|
+
## Prerequisites
|
|
1318
|
+
|
|
1319
|
+
- Node.js 18+
|
|
1320
|
+
- A package manager (pnpm, npm, or yarn)
|
|
1321
|
+
|
|
1322
|
+
## Install Dependencies
|
|
1323
|
+
|
|
1324
|
+
\`\`\`bash
|
|
1325
|
+
pnpm add @farming-labs/docs @farming-labs/nuxt @farming-labs/nuxt-theme
|
|
1326
|
+
\`\`\`
|
|
1327
|
+
|
|
1328
|
+
## Configuration
|
|
1329
|
+
|
|
1330
|
+
Your project includes a \`docs.config.ts\` at the root:
|
|
1331
|
+
|
|
1332
|
+
\`\`\`ts title="docs.config.ts"
|
|
1333
|
+
import { defineDocs } from "@farming-labs/docs";
|
|
1334
|
+
import { ${t.factory} } from "${t.nuxtImport}";
|
|
1335
|
+
|
|
1336
|
+
export default defineDocs({
|
|
1337
|
+
entry: "${cfg.entry}",
|
|
1338
|
+
contentDir: "${cfg.entry}",
|
|
1339
|
+
theme: ${t.factory}({
|
|
1340
|
+
ui: { colors: { primary: "#6366f1" } },
|
|
1341
|
+
}),
|
|
1342
|
+
});
|
|
1343
|
+
\`\`\`
|
|
1344
|
+
|
|
1345
|
+
## Project Structure
|
|
1346
|
+
|
|
1347
|
+
\`\`\`
|
|
1348
|
+
${cfg.entry}/ # Markdown content
|
|
1349
|
+
page.md
|
|
1350
|
+
installation/page.md
|
|
1351
|
+
quickstart/page.md
|
|
1352
|
+
server/
|
|
1353
|
+
utils/docs-server.ts # createDocsServer + preloaded content
|
|
1354
|
+
api/docs/
|
|
1355
|
+
load.get.ts # Page data API
|
|
1356
|
+
docs.get.ts # Search API
|
|
1357
|
+
docs.post.ts # AI chat API
|
|
1358
|
+
pages/
|
|
1359
|
+
${cfg.entry}/[[...slug]].vue # Docs catch-all page
|
|
1360
|
+
docs.config.ts
|
|
1361
|
+
nuxt.config.ts
|
|
1362
|
+
\`\`\`
|
|
1363
|
+
|
|
1364
|
+
## What's Next?
|
|
1365
|
+
|
|
1366
|
+
Head to the [Quickstart](/${cfg.entry}/quickstart) guide to start writing your first page.
|
|
1367
|
+
`;
|
|
1368
|
+
}
|
|
1369
|
+
function nuxtQuickstartPageTemplate(cfg) {
|
|
1370
|
+
const t = getThemeInfo(cfg.theme);
|
|
1371
|
+
return `\
|
|
1372
|
+
---
|
|
1373
|
+
order: 2
|
|
1374
|
+
title: Quickstart
|
|
1375
|
+
description: Get up and running in minutes
|
|
1376
|
+
icon: rocket
|
|
1377
|
+
---
|
|
1378
|
+
|
|
1379
|
+
# Quickstart
|
|
1380
|
+
|
|
1381
|
+
This guide walks you through creating your first documentation page.
|
|
1382
|
+
|
|
1383
|
+
## Creating a Page
|
|
1384
|
+
|
|
1385
|
+
Create a new folder under \`${cfg.entry}/\` with a \`page.md\` file:
|
|
1386
|
+
|
|
1387
|
+
\`\`\`bash
|
|
1388
|
+
mkdir -p ${cfg.entry}/my-page
|
|
1389
|
+
\`\`\`
|
|
1390
|
+
|
|
1391
|
+
Then create \`${cfg.entry}/my-page/page.md\`:
|
|
1392
|
+
|
|
1393
|
+
\`\`\`md
|
|
1394
|
+
---
|
|
1395
|
+
title: "My Page"
|
|
1396
|
+
description: "A custom documentation page"
|
|
1397
|
+
---
|
|
1398
|
+
|
|
1399
|
+
# My Page
|
|
1400
|
+
|
|
1401
|
+
Write your content here using **Markdown**.
|
|
1402
|
+
\`\`\`
|
|
1403
|
+
|
|
1404
|
+
Your page is now available at \`/${cfg.entry}/my-page\`.
|
|
1405
|
+
|
|
1406
|
+
## Customizing the Theme
|
|
1407
|
+
|
|
1408
|
+
Edit \`docs.config.ts\` to change colors and typography:
|
|
1409
|
+
|
|
1410
|
+
\`\`\`ts
|
|
1411
|
+
theme: ${t.factory}({
|
|
1412
|
+
ui: {
|
|
1413
|
+
colors: { primary: "#22c55e" },
|
|
1414
|
+
},
|
|
1415
|
+
}),
|
|
1416
|
+
\`\`\`
|
|
1417
|
+
|
|
1418
|
+
## Deploying
|
|
1419
|
+
|
|
1420
|
+
Build your docs for production:
|
|
1421
|
+
|
|
1422
|
+
\`\`\`bash
|
|
1423
|
+
pnpm build
|
|
1424
|
+
\`\`\`
|
|
1425
|
+
|
|
1426
|
+
Deploy to Vercel, Netlify, or any Node.js hosting platform.
|
|
1427
|
+
`;
|
|
1428
|
+
}
|
|
1429
|
+
function nuxtGlobalCssTemplate(theme) {
|
|
1430
|
+
return `\
|
|
1431
|
+
@import "@farming-labs/nuxt-theme/${theme}/css";
|
|
1432
|
+
`;
|
|
1433
|
+
}
|
|
1434
|
+
function nuxtCssImportLine(theme) {
|
|
1435
|
+
return `@import "@farming-labs/nuxt-theme/${theme}/css";`;
|
|
1436
|
+
}
|
|
1437
|
+
function injectNuxtCssImport(existingContent, theme) {
|
|
1438
|
+
const importLine = nuxtCssImportLine(theme);
|
|
1439
|
+
if (existingContent.includes(importLine)) return null;
|
|
1440
|
+
const lines = existingContent.split("\n");
|
|
1441
|
+
const lastImportIdx = lines.reduce((acc, l, i) => l.trimStart().startsWith("@import") ? i : acc, -1);
|
|
1442
|
+
if (lastImportIdx >= 0) lines.splice(lastImportIdx + 1, 0, importLine);
|
|
1443
|
+
else lines.unshift(importLine);
|
|
1444
|
+
return lines.join("\n");
|
|
1445
|
+
}
|
|
771
1446
|
|
|
772
1447
|
//#endregion
|
|
773
1448
|
//#region src/cli/init.ts
|
|
@@ -776,21 +1451,34 @@ async function init() {
|
|
|
776
1451
|
p.intro(pc.bgCyan(pc.black(" @farming-labs/docs ")));
|
|
777
1452
|
let framework = detectFramework(cwd);
|
|
778
1453
|
if (framework) {
|
|
779
|
-
const frameworkName = framework === "nextjs" ? "Next.js" : "SvelteKit";
|
|
1454
|
+
const frameworkName = framework === "nextjs" ? "Next.js" : framework === "sveltekit" ? "SvelteKit" : framework === "astro" ? "Astro" : "Nuxt";
|
|
780
1455
|
p.log.success(`Detected framework: ${pc.cyan(frameworkName)}`);
|
|
781
1456
|
} else {
|
|
782
1457
|
p.log.warn("Could not auto-detect a framework from " + pc.cyan("package.json") + ".");
|
|
783
1458
|
const picked = await p.select({
|
|
784
1459
|
message: "Which framework are you using?",
|
|
785
|
-
options: [
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
1460
|
+
options: [
|
|
1461
|
+
{
|
|
1462
|
+
value: "nextjs",
|
|
1463
|
+
label: "Next.js",
|
|
1464
|
+
hint: "React framework with App Router"
|
|
1465
|
+
},
|
|
1466
|
+
{
|
|
1467
|
+
value: "sveltekit",
|
|
1468
|
+
label: "SvelteKit",
|
|
1469
|
+
hint: "Svelte framework with file-based routing"
|
|
1470
|
+
},
|
|
1471
|
+
{
|
|
1472
|
+
value: "astro",
|
|
1473
|
+
label: "Astro",
|
|
1474
|
+
hint: "Content-focused framework with island architecture"
|
|
1475
|
+
},
|
|
1476
|
+
{
|
|
1477
|
+
value: "nuxt",
|
|
1478
|
+
label: "Nuxt",
|
|
1479
|
+
hint: "Vue 3 framework with file-based routing and Nitro server"
|
|
1480
|
+
}
|
|
1481
|
+
]
|
|
794
1482
|
});
|
|
795
1483
|
if (p.isCancel(picked)) {
|
|
796
1484
|
p.outro(pc.red("Init cancelled."));
|
|
@@ -815,6 +1503,11 @@ async function init() {
|
|
|
815
1503
|
value: "pixel-border",
|
|
816
1504
|
label: "Pixel Border",
|
|
817
1505
|
hint: "Rounded borders, pixel-perfect spacing, refined sidebar"
|
|
1506
|
+
},
|
|
1507
|
+
{
|
|
1508
|
+
value: "colorful",
|
|
1509
|
+
label: "Colorful",
|
|
1510
|
+
hint: "Fumadocs-style neutral theme with description support"
|
|
818
1511
|
}
|
|
819
1512
|
]
|
|
820
1513
|
});
|
|
@@ -822,7 +1515,7 @@ async function init() {
|
|
|
822
1515
|
p.outro(pc.red("Init cancelled."));
|
|
823
1516
|
process.exit(0);
|
|
824
1517
|
}
|
|
825
|
-
const aliasHint = framework === "nextjs" ? `Uses ${pc.cyan("@/")} prefix (requires tsconfig paths)` : `Uses ${pc.cyan("$lib/")} prefix (SvelteKit built-in)`;
|
|
1518
|
+
const aliasHint = framework === "nextjs" ? `Uses ${pc.cyan("@/")} prefix (requires tsconfig paths)` : framework === "sveltekit" ? `Uses ${pc.cyan("$lib/")} prefix (SvelteKit built-in)` : framework === "nuxt" ? `Uses ${pc.cyan("~/")} prefix (Nuxt built-in)` : `Uses ${pc.cyan("@/")} prefix (requires tsconfig paths)`;
|
|
826
1519
|
const useAlias = await p.confirm({
|
|
827
1520
|
message: `Use path aliases for imports? ${pc.dim(aliasHint)}`,
|
|
828
1521
|
initialValue: false
|
|
@@ -831,6 +1524,37 @@ async function init() {
|
|
|
831
1524
|
p.outro(pc.red("Init cancelled."));
|
|
832
1525
|
process.exit(0);
|
|
833
1526
|
}
|
|
1527
|
+
let astroAdapter;
|
|
1528
|
+
if (framework === "astro") {
|
|
1529
|
+
const adapter = await p.select({
|
|
1530
|
+
message: "Where will you deploy?",
|
|
1531
|
+
options: [
|
|
1532
|
+
{
|
|
1533
|
+
value: "vercel",
|
|
1534
|
+
label: "Vercel",
|
|
1535
|
+
hint: "Recommended for most projects"
|
|
1536
|
+
},
|
|
1537
|
+
{
|
|
1538
|
+
value: "netlify",
|
|
1539
|
+
label: "Netlify"
|
|
1540
|
+
},
|
|
1541
|
+
{
|
|
1542
|
+
value: "cloudflare",
|
|
1543
|
+
label: "Cloudflare Pages"
|
|
1544
|
+
},
|
|
1545
|
+
{
|
|
1546
|
+
value: "node",
|
|
1547
|
+
label: "Node.js / Docker",
|
|
1548
|
+
hint: "Self-hosted standalone server"
|
|
1549
|
+
}
|
|
1550
|
+
]
|
|
1551
|
+
});
|
|
1552
|
+
if (p.isCancel(adapter)) {
|
|
1553
|
+
p.outro(pc.red("Init cancelled."));
|
|
1554
|
+
process.exit(0);
|
|
1555
|
+
}
|
|
1556
|
+
astroAdapter = adapter;
|
|
1557
|
+
}
|
|
834
1558
|
const entry = await p.text({
|
|
835
1559
|
message: "Where should your docs live?",
|
|
836
1560
|
placeholder: "docs",
|
|
@@ -848,7 +1572,7 @@ async function init() {
|
|
|
848
1572
|
const entryPath = entry;
|
|
849
1573
|
const detectedCssFiles = detectGlobalCssFiles(cwd);
|
|
850
1574
|
let globalCssRelPath;
|
|
851
|
-
const defaultCssPath = framework === "sveltekit" ? "src/app.css" : "app/globals.css";
|
|
1575
|
+
const defaultCssPath = framework === "sveltekit" ? "src/app.css" : framework === "astro" ? "src/styles/global.css" : framework === "nuxt" ? "assets/css/main.css" : "app/globals.css";
|
|
852
1576
|
if (detectedCssFiles.length === 1) {
|
|
853
1577
|
globalCssRelPath = detectedCssFiles[0];
|
|
854
1578
|
p.log.info(`Found global CSS at ${pc.cyan(globalCssRelPath)}`);
|
|
@@ -888,7 +1612,8 @@ async function init() {
|
|
|
888
1612
|
theme,
|
|
889
1613
|
projectName: pkgJson.name || "My Project",
|
|
890
1614
|
framework,
|
|
891
|
-
useAlias
|
|
1615
|
+
useAlias,
|
|
1616
|
+
astroAdapter
|
|
892
1617
|
};
|
|
893
1618
|
const s = p.spinner();
|
|
894
1619
|
s.start("Scaffolding docs files");
|
|
@@ -899,6 +1624,8 @@ async function init() {
|
|
|
899
1624
|
else skipped.push(rel);
|
|
900
1625
|
}
|
|
901
1626
|
if (framework === "sveltekit") scaffoldSvelteKit(cwd, cfg, globalCssRelPath, write, skipped, written);
|
|
1627
|
+
else if (framework === "astro") scaffoldAstro(cwd, cfg, globalCssRelPath, write, skipped, written);
|
|
1628
|
+
else if (framework === "nuxt") scaffoldNuxt(cwd, cfg, globalCssRelPath, write, skipped, written);
|
|
902
1629
|
else scaffoldNextJs(cwd, cfg, globalCssRelPath, write, skipped, written);
|
|
903
1630
|
s.stop("Files scaffolded");
|
|
904
1631
|
if (written.length > 0) p.log.success(`Created ${written.length} file${written.length > 1 ? "s" : ""}:\n` + written.map((f) => ` ${pc.green("+")} ${f}`).join("\n"));
|
|
@@ -909,6 +1636,10 @@ async function init() {
|
|
|
909
1636
|
s2.start("Installing dependencies");
|
|
910
1637
|
try {
|
|
911
1638
|
if (framework === "sveltekit") exec(`${installCommand(pm)} @farming-labs/docs @farming-labs/svelte @farming-labs/svelte-theme`, cwd);
|
|
1639
|
+
else if (framework === "astro") {
|
|
1640
|
+
const adapterPkg = getAstroAdapterPkg(cfg.astroAdapter ?? "vercel");
|
|
1641
|
+
exec(`${installCommand(pm)} @farming-labs/docs @farming-labs/astro @farming-labs/astro-theme ${adapterPkg}`, cwd);
|
|
1642
|
+
} else if (framework === "nuxt") exec(`${installCommand(pm)} @farming-labs/docs @farming-labs/nuxt @farming-labs/nuxt-theme`, cwd);
|
|
912
1643
|
else {
|
|
913
1644
|
exec(`${installCommand(pm)} @farming-labs/docs @farming-labs/next @farming-labs/theme`, cwd);
|
|
914
1645
|
const devDeps = [
|
|
@@ -948,6 +1679,14 @@ async function init() {
|
|
|
948
1679
|
cmd: "npx",
|
|
949
1680
|
args: ["vite", "dev"],
|
|
950
1681
|
waitFor: "ready"
|
|
1682
|
+
} : framework === "astro" ? {
|
|
1683
|
+
cmd: "npx",
|
|
1684
|
+
args: ["astro", "dev"],
|
|
1685
|
+
waitFor: "ready"
|
|
1686
|
+
} : framework === "nuxt" ? {
|
|
1687
|
+
cmd: "npx",
|
|
1688
|
+
args: ["nuxt", "dev"],
|
|
1689
|
+
waitFor: "Local"
|
|
951
1690
|
} : {
|
|
952
1691
|
cmd: "npx",
|
|
953
1692
|
args: [
|
|
@@ -957,7 +1696,7 @@ async function init() {
|
|
|
957
1696
|
],
|
|
958
1697
|
waitFor: "Ready"
|
|
959
1698
|
};
|
|
960
|
-
const defaultPort = framework === "sveltekit" ? "5173" : "3000";
|
|
1699
|
+
const defaultPort = framework === "sveltekit" ? "5173" : framework === "astro" ? "4321" : framework === "nuxt" ? "3000" : "3000";
|
|
961
1700
|
try {
|
|
962
1701
|
const child = await spawnAndWaitFor(devCommand.cmd, devCommand.args, cwd, devCommand.waitFor, 6e4);
|
|
963
1702
|
const url = `http://localhost:${defaultPort}/${entryPath}`;
|
|
@@ -976,7 +1715,7 @@ async function init() {
|
|
|
976
1715
|
});
|
|
977
1716
|
});
|
|
978
1717
|
} catch (err) {
|
|
979
|
-
const manualCmd = framework === "sveltekit" ? "npx vite dev" : "npx next dev --webpack";
|
|
1718
|
+
const manualCmd = framework === "sveltekit" ? "npx vite dev" : framework === "astro" ? "npx astro dev" : framework === "nuxt" ? "npx nuxt dev" : "npx next dev --webpack";
|
|
980
1719
|
p.log.error(`Could not start dev server. Try running manually:
|
|
981
1720
|
${pc.cyan(manualCmd)}`);
|
|
982
1721
|
p.outro(pc.yellow("Setup complete. Start the server manually."));
|
|
@@ -1024,6 +1763,7 @@ function scaffoldSvelteKit(cwd, cfg, globalCssRelPath, write, skipped, written)
|
|
|
1024
1763
|
fumadocs: "fumadocs",
|
|
1025
1764
|
darksharp: "darksharp",
|
|
1026
1765
|
"pixel-border": "pixel-border",
|
|
1766
|
+
colorful: "colorful",
|
|
1027
1767
|
default: "fumadocs"
|
|
1028
1768
|
}[cfg.theme] || "fumadocs";
|
|
1029
1769
|
if (existingGlobalCss) {
|
|
@@ -1037,6 +1777,61 @@ function scaffoldSvelteKit(cwd, cfg, globalCssRelPath, write, skipped, written)
|
|
|
1037
1777
|
write(`${cfg.entry}/installation/page.md`, svelteInstallationPageTemplate(cfg));
|
|
1038
1778
|
write(`${cfg.entry}/quickstart/page.md`, svelteQuickstartPageTemplate(cfg));
|
|
1039
1779
|
}
|
|
1780
|
+
function scaffoldAstro(cwd, cfg, globalCssRelPath, write, skipped, written) {
|
|
1781
|
+
write("src/lib/docs.config.ts", astroDocsConfigTemplate(cfg));
|
|
1782
|
+
write("src/lib/docs.server.ts", astroDocsServerTemplate(cfg));
|
|
1783
|
+
if (!fileExists(path.join(cwd, "astro.config.mjs")) && !fileExists(path.join(cwd, "astro.config.ts"))) write("astro.config.mjs", astroConfigTemplate(cfg.astroAdapter ?? "vercel"));
|
|
1784
|
+
write(`src/pages/${cfg.entry}/index.astro`, astroDocsIndexTemplate(cfg));
|
|
1785
|
+
write(`src/pages/${cfg.entry}/[...slug].astro`, astroDocsPageTemplate(cfg));
|
|
1786
|
+
write(`src/pages/api/${cfg.entry}.ts`, astroApiRouteTemplate(cfg));
|
|
1787
|
+
const globalCssAbsPath = path.join(cwd, globalCssRelPath);
|
|
1788
|
+
const existingGlobalCss = readFileSafe(globalCssAbsPath);
|
|
1789
|
+
const cssTheme = {
|
|
1790
|
+
fumadocs: "fumadocs",
|
|
1791
|
+
darksharp: "darksharp",
|
|
1792
|
+
"pixel-border": "pixel-border",
|
|
1793
|
+
colorful: "colorful",
|
|
1794
|
+
default: "fumadocs"
|
|
1795
|
+
}[cfg.theme] || "fumadocs";
|
|
1796
|
+
if (existingGlobalCss) {
|
|
1797
|
+
const injected = injectAstroCssImport(existingGlobalCss, cssTheme);
|
|
1798
|
+
if (injected) {
|
|
1799
|
+
writeFileSafe(globalCssAbsPath, injected, true);
|
|
1800
|
+
written.push(globalCssRelPath + " (updated)");
|
|
1801
|
+
} else skipped.push(globalCssRelPath + " (already configured)");
|
|
1802
|
+
} else write(globalCssRelPath, astroGlobalCssTemplate(cssTheme));
|
|
1803
|
+
write(`${cfg.entry}/page.md`, astroWelcomePageTemplate(cfg));
|
|
1804
|
+
write(`${cfg.entry}/installation/page.md`, astroInstallationPageTemplate(cfg));
|
|
1805
|
+
write(`${cfg.entry}/quickstart/page.md`, astroQuickstartPageTemplate(cfg));
|
|
1806
|
+
}
|
|
1807
|
+
function scaffoldNuxt(cwd, cfg, globalCssRelPath, write, skipped, written) {
|
|
1808
|
+
write("docs.config.ts", nuxtDocsConfigTemplate(cfg));
|
|
1809
|
+
write("server/utils/docs-server.ts", nuxtDocsServerTemplate(cfg));
|
|
1810
|
+
write("server/api/docs.get.ts", nuxtServerApiDocsGetTemplate());
|
|
1811
|
+
write("server/api/docs.post.ts", nuxtServerApiDocsPostTemplate());
|
|
1812
|
+
write("server/api/docs/load.get.ts", nuxtServerApiDocsLoadTemplate());
|
|
1813
|
+
write(`pages/${cfg.entry}/[[...slug]].vue`, nuxtDocsPageTemplate(cfg));
|
|
1814
|
+
path.join(cwd, "nuxt.config.ts");
|
|
1815
|
+
if (!fileExists(path.join(cwd, "nuxt.config.ts")) && !fileExists(path.join(cwd, "nuxt.config.js"))) write("nuxt.config.ts", nuxtConfigTemplate(cfg));
|
|
1816
|
+
const cssTheme = {
|
|
1817
|
+
fumadocs: "fumadocs",
|
|
1818
|
+
darksharp: "darksharp",
|
|
1819
|
+
"pixel-border": "pixel-border",
|
|
1820
|
+
default: "fumadocs"
|
|
1821
|
+
}[cfg.theme] || "fumadocs";
|
|
1822
|
+
const globalCssAbsPath = path.join(cwd, globalCssRelPath);
|
|
1823
|
+
const existingGlobalCss = readFileSafe(globalCssAbsPath);
|
|
1824
|
+
if (existingGlobalCss) {
|
|
1825
|
+
const injected = injectNuxtCssImport(existingGlobalCss, cssTheme);
|
|
1826
|
+
if (injected) {
|
|
1827
|
+
writeFileSafe(globalCssAbsPath, injected, true);
|
|
1828
|
+
written.push(globalCssRelPath + " (updated)");
|
|
1829
|
+
} else skipped.push(globalCssRelPath + " (already configured)");
|
|
1830
|
+
} else write(globalCssRelPath, nuxtGlobalCssTemplate(cssTheme));
|
|
1831
|
+
write(`${cfg.entry}/page.md`, nuxtWelcomePageTemplate(cfg));
|
|
1832
|
+
write(`${cfg.entry}/installation/page.md`, nuxtInstallationPageTemplate(cfg));
|
|
1833
|
+
write(`${cfg.entry}/quickstart/page.md`, nuxtQuickstartPageTemplate(cfg));
|
|
1834
|
+
}
|
|
1040
1835
|
|
|
1041
1836
|
//#endregion
|
|
1042
1837
|
//#region src/cli/index.ts
|
|
@@ -1063,7 +1858,7 @@ ${pc.dim("Commands:")}
|
|
|
1063
1858
|
${pc.cyan("init")} Scaffold docs in your project (default)
|
|
1064
1859
|
|
|
1065
1860
|
${pc.dim("Supported frameworks:")}
|
|
1066
|
-
Next.js, SvelteKit
|
|
1861
|
+
Next.js, SvelteKit, Astro, Nuxt
|
|
1067
1862
|
|
|
1068
1863
|
${pc.dim("Options:")}
|
|
1069
1864
|
${pc.cyan("-h, --help")} Show this help message
|
package/dist/index.d.mts
CHANGED
|
@@ -137,6 +137,13 @@ interface UIConfig {
|
|
|
137
137
|
toc?: {
|
|
138
138
|
enabled?: boolean;
|
|
139
139
|
depth?: number;
|
|
140
|
+
/**
|
|
141
|
+
* Visual style of the TOC indicator.
|
|
142
|
+
* - `"default"` — highlight active link text color only
|
|
143
|
+
* - `"directional"` — animated thumb bar that tracks active headings (fumadocs style)
|
|
144
|
+
* @default "default"
|
|
145
|
+
*/
|
|
146
|
+
style?: "default" | "directional";
|
|
140
147
|
};
|
|
141
148
|
header?: {
|
|
142
149
|
height?: number;
|
|
@@ -533,19 +540,44 @@ interface AIConfig {
|
|
|
533
540
|
*/
|
|
534
541
|
floatingStyle?: "panel" | "modal" | "popover" | "full-modal";
|
|
535
542
|
/**
|
|
536
|
-
* Custom trigger component for the floating chat button.
|
|
543
|
+
* Custom trigger component for the floating chat button (Next.js only).
|
|
537
544
|
* Only used when `mode` is `"floating"`.
|
|
538
545
|
*
|
|
539
|
-
*
|
|
540
|
-
*
|
|
546
|
+
* The click handler is attached automatically by the wrapper.
|
|
547
|
+
*
|
|
548
|
+
* - **Next.js**: Pass a JSX element via this config option.
|
|
549
|
+
* - **SvelteKit**: Use the `aiTrigger` snippet on `<DocsLayout>`.
|
|
550
|
+
* - **Nuxt / Vue**: Use the `ai-trigger` slot on `<DocsLayout>`.
|
|
551
|
+
* - **Astro**: Use `<MyTrigger slot="ai-trigger" />` on `<DocsLayout>`.
|
|
541
552
|
*
|
|
542
553
|
* @example
|
|
543
554
|
* ```tsx
|
|
544
|
-
*
|
|
545
|
-
*
|
|
546
|
-
*
|
|
547
|
-
*
|
|
548
|
-
*
|
|
555
|
+
* // Next.js — pass JSX directly in config
|
|
556
|
+
* triggerComponent: <button className="my-chat-btn">Ask AI</button>,
|
|
557
|
+
* ```
|
|
558
|
+
*
|
|
559
|
+
* ```svelte
|
|
560
|
+
* <!-- SvelteKit — use snippet in layout -->
|
|
561
|
+
* <DocsLayout {tree} {config}>
|
|
562
|
+
* {#snippet aiTrigger()}<AskAITrigger />{/snippet}
|
|
563
|
+
* {@render children()}
|
|
564
|
+
* </DocsLayout>
|
|
565
|
+
* ```
|
|
566
|
+
*
|
|
567
|
+
* ```vue
|
|
568
|
+
* <!-- Nuxt / Vue — use named slot in layout -->
|
|
569
|
+
* <DocsLayout :tree="tree" :config="config">
|
|
570
|
+
* <template #ai-trigger><AskAITrigger /></template>
|
|
571
|
+
* <DocsContent />
|
|
572
|
+
* </DocsLayout>
|
|
573
|
+
* ```
|
|
574
|
+
*
|
|
575
|
+
* ```astro
|
|
576
|
+
* <!-- Astro — use named slot in layout -->
|
|
577
|
+
* <DocsLayout tree={tree} config={config}>
|
|
578
|
+
* <AskAITrigger slot="ai-trigger" />
|
|
579
|
+
* <DocsContent />
|
|
580
|
+
* </DocsLayout>
|
|
549
581
|
* ```
|
|
550
582
|
*/
|
|
551
583
|
triggerComponent?: unknown;
|