create-zudo-doc 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (212) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +146 -0
  3. package/bin/create-zudo-doc.js +2 -0
  4. package/dist/api.d.ts +20 -0
  5. package/dist/api.js +13 -0
  6. package/dist/claude-md-gen.d.ts +2 -0
  7. package/dist/claude-md-gen.js +113 -0
  8. package/dist/cli.d.ts +39 -0
  9. package/dist/cli.js +157 -0
  10. package/dist/compose.d.ts +95 -0
  11. package/dist/compose.js +206 -0
  12. package/dist/constants.d.ts +20 -0
  13. package/dist/constants.js +224 -0
  14. package/dist/features/body-foot-util.d.ts +10 -0
  15. package/dist/features/body-foot-util.js +12 -0
  16. package/dist/features/claude-resources.d.ts +2 -0
  17. package/dist/features/claude-resources.js +6 -0
  18. package/dist/features/design-token-panel.d.ts +14 -0
  19. package/dist/features/design-token-panel.js +27 -0
  20. package/dist/features/doc-history.d.ts +9 -0
  21. package/dist/features/doc-history.js +11 -0
  22. package/dist/features/doc-tags.d.ts +19 -0
  23. package/dist/features/doc-tags.js +33 -0
  24. package/dist/features/footer-taglist.d.ts +14 -0
  25. package/dist/features/footer-taglist.js +17 -0
  26. package/dist/features/footer.d.ts +8 -0
  27. package/dist/features/footer.js +10 -0
  28. package/dist/features/i18n.d.ts +22 -0
  29. package/dist/features/i18n.js +41 -0
  30. package/dist/features/image-enlarge.d.ts +11 -0
  31. package/dist/features/image-enlarge.js +13 -0
  32. package/dist/features/index.d.ts +15 -0
  33. package/dist/features/index.js +53 -0
  34. package/dist/features/llms-txt.d.ts +11 -0
  35. package/dist/features/llms-txt.js +13 -0
  36. package/dist/features/search.d.ts +9 -0
  37. package/dist/features/search.js +11 -0
  38. package/dist/features/sidebar-resizer.d.ts +14 -0
  39. package/dist/features/sidebar-resizer.js +16 -0
  40. package/dist/features/sidebar-toggle.d.ts +13 -0
  41. package/dist/features/sidebar-toggle.js +15 -0
  42. package/dist/features/tag-governance.d.ts +14 -0
  43. package/dist/features/tag-governance.js +16 -0
  44. package/dist/features/tauri-dev.d.ts +2 -0
  45. package/dist/features/tauri-dev.js +25 -0
  46. package/dist/features/tauri.d.ts +11 -0
  47. package/dist/features/tauri.js +52 -0
  48. package/dist/features/versioning.d.ts +27 -0
  49. package/dist/features/versioning.js +43 -0
  50. package/dist/index.d.ts +1 -0
  51. package/dist/index.js +150 -0
  52. package/dist/preset.d.ts +37 -0
  53. package/dist/preset.js +156 -0
  54. package/dist/prompts.d.ts +32 -0
  55. package/dist/prompts.js +248 -0
  56. package/dist/scaffold.d.ts +4 -0
  57. package/dist/scaffold.js +344 -0
  58. package/dist/settings-gen.d.ts +2 -0
  59. package/dist/settings-gen.js +237 -0
  60. package/dist/utils.d.ts +8 -0
  61. package/dist/utils.js +34 -0
  62. package/dist/zfb-config-gen.d.ts +19 -0
  63. package/dist/zfb-config-gen.js +222 -0
  64. package/package.json +65 -0
  65. package/templates/base/.htmlvalidate.json +5 -0
  66. package/templates/base/.zfb/doc-history-meta.json +1 -0
  67. package/templates/base/pages/404.tsx +55 -0
  68. package/templates/base/pages/_data.ts +179 -0
  69. package/templates/base/pages/_mdx-components.ts +249 -0
  70. package/templates/base/pages/docs/[...slug].tsx +448 -0
  71. package/templates/base/pages/index.tsx +158 -0
  72. package/templates/base/pages/lib/_body-end-islands.tsx +201 -0
  73. package/templates/base/pages/lib/_category-nav.tsx +148 -0
  74. package/templates/base/pages/lib/_category-tree-nav.tsx +104 -0
  75. package/templates/base/pages/lib/_compose-meta-title.ts +29 -0
  76. package/templates/base/pages/lib/_details.tsx +30 -0
  77. package/templates/base/pages/lib/_doc-history-area.tsx +178 -0
  78. package/templates/base/pages/lib/_doc-metainfo-area.tsx +100 -0
  79. package/templates/base/pages/lib/_doc-tags-area.tsx +89 -0
  80. package/templates/base/pages/lib/_extract-headings.ts +81 -0
  81. package/templates/base/pages/lib/_footer-with-defaults.tsx +234 -0
  82. package/templates/base/pages/lib/_frontmatter-preview-data.ts +53 -0
  83. package/templates/base/pages/lib/_head-with-defaults.tsx +113 -0
  84. package/templates/base/pages/lib/_header-with-defaults.tsx +386 -0
  85. package/templates/base/pages/lib/_inline-version-switcher.tsx +84 -0
  86. package/templates/base/pages/lib/_math-block.tsx +63 -0
  87. package/templates/base/pages/lib/_nav-source-docs.ts +68 -0
  88. package/templates/base/pages/lib/_preset-generator.tsx +81 -0
  89. package/templates/base/pages/lib/_search-widget-script.ts +388 -0
  90. package/templates/base/pages/lib/_search-widget.tsx +196 -0
  91. package/templates/base/pages/lib/_sidebar-with-defaults.tsx +176 -0
  92. package/templates/base/pages/lib/_site-tree-nav.tsx +128 -0
  93. package/templates/base/pages/lib/locale-merge.ts +58 -0
  94. package/templates/base/pages/lib/route-enumerators.ts +302 -0
  95. package/templates/base/pages/sitemap.xml.tsx +51 -0
  96. package/templates/base/plugins/connect-adapter.mjs +144 -0
  97. package/templates/base/plugins/copy-public-plugin.mjs +50 -0
  98. package/templates/base/plugins/search-index-plugin.mjs +54 -0
  99. package/templates/base/scripts/run-b4push.sh +102 -0
  100. package/templates/base/src/components/ai-chat-modal.tsx +15 -0
  101. package/templates/base/src/components/client-router-bootstrap.tsx +14 -0
  102. package/templates/base/src/components/content/component-map.ts +25 -0
  103. package/templates/base/src/components/content/content-blockquote.tsx +16 -0
  104. package/templates/base/src/components/content/content-code.tsx +117 -0
  105. package/templates/base/src/components/content/content-link.tsx +83 -0
  106. package/templates/base/src/components/content/content-ol.tsx +19 -0
  107. package/templates/base/src/components/content/content-paragraph.tsx +10 -0
  108. package/templates/base/src/components/content/content-strong.tsx +16 -0
  109. package/templates/base/src/components/content/content-table.tsx +18 -0
  110. package/templates/base/src/components/content/content-ul.tsx +18 -0
  111. package/templates/base/src/components/content/heading-h2.tsx +26 -0
  112. package/templates/base/src/components/content/heading-h3.tsx +26 -0
  113. package/templates/base/src/components/content/heading-h4.tsx +26 -0
  114. package/templates/base/src/components/design-token-panel-bootstrap.tsx +15 -0
  115. package/templates/base/src/components/desktop-sidebar-toggle.tsx +15 -0
  116. package/templates/base/src/components/doc-history.tsx +18 -0
  117. package/templates/base/src/components/html-preview/highlighted-code.tsx +74 -0
  118. package/templates/base/src/components/html-preview/html-preview.tsx +108 -0
  119. package/templates/base/src/components/html-preview/preflight.ts +112 -0
  120. package/templates/base/src/components/html-preview/preview-base.tsx +159 -0
  121. package/templates/base/src/components/image-enlarge.tsx +19 -0
  122. package/templates/base/src/components/mobile-toc.tsx +94 -0
  123. package/templates/base/src/components/preset-generator.tsx +14 -0
  124. package/templates/base/src/components/sidebar-toggle.tsx +98 -0
  125. package/templates/base/src/components/sidebar-tree.tsx +543 -0
  126. package/templates/base/src/components/site-tree-nav.tsx +233 -0
  127. package/templates/base/src/components/theme-toggle.tsx +93 -0
  128. package/templates/base/src/components/toc.tsx +63 -0
  129. package/templates/base/src/components/tree-nav-shared.tsx +71 -0
  130. package/templates/base/src/config/color-scheme-utils.ts +182 -0
  131. package/templates/base/src/config/color-schemes.ts +128 -0
  132. package/templates/base/src/config/frontmatter-preview-defaults.ts +24 -0
  133. package/templates/base/src/config/frontmatter-preview-renderers.tsx +46 -0
  134. package/templates/base/src/config/i18n.ts +225 -0
  135. package/templates/base/src/config/settings-types.ts +162 -0
  136. package/templates/base/src/config/sidebars.ts +66 -0
  137. package/templates/base/src/config/tag-vocabulary-types.ts +39 -0
  138. package/templates/base/src/config/tag-vocabulary.ts +20 -0
  139. package/templates/base/src/hooks/use-active-heading.ts +133 -0
  140. package/templates/base/src/plugins/docs-source-map.ts +103 -0
  141. package/templates/base/src/plugins/hast-utils.ts +10 -0
  142. package/templates/base/src/plugins/rehype-code-title.ts +50 -0
  143. package/templates/base/src/plugins/rehype-heading-links.ts +53 -0
  144. package/templates/base/src/plugins/rehype-image-enlarge.ts +113 -0
  145. package/templates/base/src/plugins/rehype-mermaid.ts +41 -0
  146. package/templates/base/src/plugins/rehype-strip-md-extension.ts +58 -0
  147. package/templates/base/src/plugins/remark-admonitions.ts +99 -0
  148. package/templates/base/src/plugins/remark-resolve-markdown-links.ts +127 -0
  149. package/templates/base/src/plugins/url-utils.ts +4 -0
  150. package/templates/base/src/styles/global.css +1066 -0
  151. package/templates/base/src/types/docs-entry.ts +39 -0
  152. package/templates/base/src/types/heading.ts +5 -0
  153. package/templates/base/src/types/locale.ts +10 -0
  154. package/templates/base/src/utils/base.ts +139 -0
  155. package/templates/base/src/utils/content-files.ts +106 -0
  156. package/templates/base/src/utils/dedent.ts +24 -0
  157. package/templates/base/src/utils/docs.ts +335 -0
  158. package/templates/base/src/utils/git-info.ts +70 -0
  159. package/templates/base/src/utils/github.ts +19 -0
  160. package/templates/base/src/utils/header-right-items.ts +38 -0
  161. package/templates/base/src/utils/nav-scope.ts +63 -0
  162. package/templates/base/src/utils/sidebar.ts +104 -0
  163. package/templates/base/src/utils/slug.ts +10 -0
  164. package/templates/base/src/utils/smart-break.tsx +126 -0
  165. package/templates/base/src/utils/tags.ts +126 -0
  166. package/templates/base/tsconfig.json +36 -0
  167. package/templates/features/bodyFootUtil/files/src/utils/github.ts +19 -0
  168. package/templates/features/claudeResources/files/plugins/claude-resources-plugin.mjs +137 -0
  169. package/templates/features/claudeResources/files/src/integrations/claude-resources/__tests__/escape-for-mdx.test.ts +34 -0
  170. package/templates/features/claudeResources/files/src/integrations/claude-resources/__tests__/generate.test.ts +376 -0
  171. package/templates/features/claudeResources/files/src/integrations/claude-resources/escape-for-mdx.ts +93 -0
  172. package/templates/features/claudeResources/files/src/integrations/claude-resources/generate.ts +586 -0
  173. package/templates/features/designTokenPanel/files/src/components/design-token-panel-bootstrap.tsx +15 -0
  174. package/templates/features/designTokenPanel/files/src/config/design-token-panel-config.ts +99 -0
  175. package/templates/features/designTokenPanel/files/src/config/design-tokens-manifest.ts +177 -0
  176. package/templates/features/designTokenPanel/files/src/lib/design-token-panel-bootstrap.ts +50 -0
  177. package/templates/features/docHistory/files/plugins/doc-history-plugin.mjs +99 -0
  178. package/templates/features/docHistory/files/src/components/doc-history.tsx +598 -0
  179. package/templates/features/docHistory/files/src/types/doc-history.ts +23 -0
  180. package/templates/features/docHistory/files/src/utils/doc-history.ts +180 -0
  181. package/templates/features/docTags/files/pages/[locale]/docs/tags/[tag].tsx +116 -0
  182. package/templates/features/docTags/files/pages/[locale]/docs/tags/index.tsx +99 -0
  183. package/templates/features/docTags/files/pages/docs/tags/[tag].tsx +101 -0
  184. package/templates/features/docTags/files/pages/docs/tags/index.tsx +86 -0
  185. package/templates/features/i18n/files/pages/[locale]/docs/[...slug].tsx +467 -0
  186. package/templates/features/i18n/files/pages/[locale]/index.tsx +213 -0
  187. package/templates/features/imageEnlarge/files/src/components/image-enlarge.tsx +248 -0
  188. package/templates/features/llmsTxt/files/plugins/llms-txt-plugin.mjs +74 -0
  189. package/templates/features/sidebarResizer/files/src/scripts/sidebar-resizer.ts +185 -0
  190. package/templates/features/sidebarToggle/files/src/components/desktop-sidebar-toggle.tsx +126 -0
  191. package/templates/features/tagGovernance/files/scripts/tags-audit.ts +576 -0
  192. package/templates/features/tagGovernance/files/scripts/tags-suggest.ts +428 -0
  193. package/templates/features/tauri/files/src/components/find-bar.tsx +122 -0
  194. package/templates/features/tauri/files/src/components/find-in-page-init.tsx +53 -0
  195. package/templates/features/tauri/files/src/utils/find-in-page.ts +175 -0
  196. package/templates/features/tauri/files/src-tauri/Cargo.toml +14 -0
  197. package/templates/features/tauri/files/src-tauri/build.rs +3 -0
  198. package/templates/features/tauri/files/src-tauri/capabilities/default.json +11 -0
  199. package/templates/features/tauri/files/src-tauri/src/main.rs +250 -0
  200. package/templates/features/tauri/files/src-tauri/tauri.conf.json +25 -0
  201. package/templates/features/tauriDev/files/src-tauri-dev/Cargo.toml +15 -0
  202. package/templates/features/tauriDev/files/src-tauri-dev/build.rs +3 -0
  203. package/templates/features/tauriDev/files/src-tauri-dev/capabilities/default.json +7 -0
  204. package/templates/features/tauriDev/files/src-tauri-dev/frontend/index.html +187 -0
  205. package/templates/features/tauriDev/files/src-tauri-dev/icons/icon.png +0 -0
  206. package/templates/features/tauriDev/files/src-tauri-dev/src/main.rs +995 -0
  207. package/templates/features/tauriDev/files/src-tauri-dev/tauri.conf.json +22 -0
  208. package/templates/features/tauriDev/files/src-tauri-dev/test-launch.sh +65 -0
  209. package/templates/features/versioning/files/pages/[locale]/docs/versions.tsx +100 -0
  210. package/templates/features/versioning/files/pages/docs/versions.tsx +78 -0
  211. package/templates/features/versioning/files/pages/v/[version]/docs/[...slug].tsx +451 -0
  212. package/templates/features/versioning/files/pages/v/[version]/ja/docs/[...slug].tsx +490 -0
@@ -0,0 +1,37 @@
1
+ import type { PartialChoices } from "./prompts.js";
2
+ /**
3
+ * Header-right item shapes accepted in v1 of preset support. Mirrors
4
+ * `HeaderRightComponentItem` and `HeaderRightTriggerItem` from
5
+ * `src/config/settings-types.ts`. The wider `link`/`html` variants are
6
+ * intentionally rejected for now — they need free-text fields that pollute
7
+ * the JSON preset schema and the generator UI.
8
+ */
9
+ export type PresetHeaderRightComponentName = "theme-toggle" | "language-switcher" | "version-switcher" | "github-link" | "search";
10
+ export type PresetHeaderRightTriggerName = "design-token-panel" | "ai-chat";
11
+ export interface PresetHeaderRightComponentItem {
12
+ type: "component";
13
+ component: PresetHeaderRightComponentName;
14
+ }
15
+ export interface PresetHeaderRightTriggerItem {
16
+ type: "trigger";
17
+ trigger: PresetHeaderRightTriggerName;
18
+ }
19
+ export type PresetHeaderRightItem = PresetHeaderRightComponentItem | PresetHeaderRightTriggerItem;
20
+ export interface PresetJson {
21
+ projectName?: string;
22
+ defaultLang?: string;
23
+ colorSchemeMode?: "single" | "light-dark";
24
+ singleScheme?: string;
25
+ lightScheme?: string;
26
+ darkScheme?: string;
27
+ defaultMode?: "light" | "dark";
28
+ respectPrefersColorScheme?: boolean;
29
+ features?: string[];
30
+ githubUrl?: string;
31
+ cjkFriendly?: boolean;
32
+ packageManager?: "pnpm" | "npm" | "yarn" | "bun";
33
+ headerRightItems?: PresetHeaderRightItem[];
34
+ }
35
+ export declare function loadPreset(pathOrStdin: string): PartialChoices;
36
+ export declare function validatePreset(json: unknown): string | null;
37
+ export declare function presetToChoices(json: PresetJson): PartialChoices;
package/dist/preset.js ADDED
@@ -0,0 +1,156 @@
1
+ import fs from "fs";
2
+ import { FEATURES, SINGLE_SCHEMES, SUPPORTED_LANGS } from "./constants.js";
3
+ const VALID_HEADER_RIGHT_COMPONENTS = new Set([
4
+ "theme-toggle",
5
+ "language-switcher",
6
+ "version-switcher",
7
+ "github-link",
8
+ "search",
9
+ ]);
10
+ const VALID_HEADER_RIGHT_TRIGGERS = new Set([
11
+ "design-token-panel",
12
+ "ai-chat",
13
+ ]);
14
+ export function loadPreset(pathOrStdin) {
15
+ let raw;
16
+ if (pathOrStdin === "-") {
17
+ raw = fs.readFileSync(0, "utf8");
18
+ }
19
+ else {
20
+ raw = fs.readFileSync(pathOrStdin, "utf8");
21
+ }
22
+ const json = JSON.parse(raw);
23
+ const error = validatePreset(json);
24
+ if (error) {
25
+ throw new Error(error);
26
+ }
27
+ return presetToChoices(json);
28
+ }
29
+ const VALID_LANGS = new Set(SUPPORTED_LANGS.map((l) => l.value));
30
+ const VALID_SCHEMES = new Set(SINGLE_SCHEMES);
31
+ const VALID_PMS = new Set(["pnpm", "npm", "yarn", "bun"]);
32
+ export function validatePreset(json) {
33
+ if (json === null || typeof json !== "object" || Array.isArray(json)) {
34
+ return "Preset must be a JSON object";
35
+ }
36
+ const p = json;
37
+ if (p.features !== undefined && !Array.isArray(p.features)) {
38
+ return `"features" must be an array in preset`;
39
+ }
40
+ if (p.defaultLang && !VALID_LANGS.has(p.defaultLang)) {
41
+ return `Invalid language "${p.defaultLang}" in preset`;
42
+ }
43
+ if (p.colorSchemeMode && !["single", "light-dark"].includes(p.colorSchemeMode)) {
44
+ return `Invalid colorSchemeMode "${p.colorSchemeMode}" in preset`;
45
+ }
46
+ if (p.singleScheme && !VALID_SCHEMES.has(p.singleScheme)) {
47
+ return `Unknown color scheme "${p.singleScheme}" in preset`;
48
+ }
49
+ if (p.lightScheme && !VALID_SCHEMES.has(p.lightScheme)) {
50
+ return `Unknown light scheme "${p.lightScheme}" in preset`;
51
+ }
52
+ if (p.darkScheme && !VALID_SCHEMES.has(p.darkScheme)) {
53
+ return `Unknown dark scheme "${p.darkScheme}" in preset`;
54
+ }
55
+ if (p.defaultMode && !["light", "dark"].includes(p.defaultMode)) {
56
+ return `Invalid defaultMode "${p.defaultMode}" in preset`;
57
+ }
58
+ if (p.packageManager && !VALID_PMS.has(p.packageManager)) {
59
+ return `Invalid packageManager "${p.packageManager}" in preset`;
60
+ }
61
+ if (p.cjkFriendly !== undefined && typeof p.cjkFriendly !== "boolean") {
62
+ return `"cjkFriendly" must be a boolean in preset`;
63
+ }
64
+ if (p.headerRightItems !== undefined) {
65
+ if (!Array.isArray(p.headerRightItems)) {
66
+ return `"headerRightItems" must be an array in preset`;
67
+ }
68
+ for (let i = 0; i < p.headerRightItems.length; i++) {
69
+ const item = p.headerRightItems[i];
70
+ if (item === null || typeof item !== "object" || Array.isArray(item)) {
71
+ return `headerRightItems[${i}] must be an object`;
72
+ }
73
+ const t = item.type;
74
+ if (t === "link" || t === "html") {
75
+ return `headerRightItems[${i}] type "${t}" is not supported in presets (v1) — edit settings.ts after scaffold`;
76
+ }
77
+ if (t === "component") {
78
+ const component = item.component;
79
+ if (typeof component !== "string") {
80
+ return `headerRightItems[${i}].component must be a string`;
81
+ }
82
+ if (!VALID_HEADER_RIGHT_COMPONENTS.has(component)) {
83
+ return `headerRightItems[${i}] unknown component "${component}". Allowed: ${[
84
+ ...VALID_HEADER_RIGHT_COMPONENTS,
85
+ ].join(", ")}`;
86
+ }
87
+ }
88
+ else if (t === "trigger") {
89
+ const trigger = item.trigger;
90
+ if (typeof trigger !== "string") {
91
+ return `headerRightItems[${i}].trigger must be a string`;
92
+ }
93
+ if (!VALID_HEADER_RIGHT_TRIGGERS.has(trigger)) {
94
+ return `headerRightItems[${i}] unknown trigger "${trigger}". Allowed: ${[
95
+ ...VALID_HEADER_RIGHT_TRIGGERS,
96
+ ].join(", ")}`;
97
+ }
98
+ }
99
+ else {
100
+ return `headerRightItems[${i}] must have type "component" or "trigger" (got ${JSON.stringify(t)})`;
101
+ }
102
+ }
103
+ }
104
+ // Cross-field validation
105
+ if (p.colorSchemeMode === "single" && (p.lightScheme || p.darkScheme)) {
106
+ return `lightScheme/darkScheme are only valid with colorSchemeMode "light-dark"`;
107
+ }
108
+ if (p.colorSchemeMode === "light-dark" && p.singleScheme) {
109
+ return `singleScheme is only valid with colorSchemeMode "single"`;
110
+ }
111
+ return null;
112
+ }
113
+ const KNOWN_FEATURES = new Set(FEATURES.map((f) => f.value));
114
+ export function presetToChoices(json) {
115
+ const choices = {};
116
+ if (json.projectName)
117
+ choices.projectName = json.projectName;
118
+ if (json.defaultLang)
119
+ choices.defaultLang = json.defaultLang;
120
+ if (json.colorSchemeMode)
121
+ choices.colorSchemeMode = json.colorSchemeMode;
122
+ if (json.singleScheme)
123
+ choices.singleScheme = json.singleScheme;
124
+ if (json.lightScheme)
125
+ choices.lightScheme = json.lightScheme;
126
+ if (json.darkScheme)
127
+ choices.darkScheme = json.darkScheme;
128
+ if (json.defaultMode)
129
+ choices.defaultMode = json.defaultMode;
130
+ if (json.respectPrefersColorScheme !== undefined) {
131
+ choices.respectPrefersColorScheme = json.respectPrefersColorScheme;
132
+ }
133
+ if (json.packageManager)
134
+ choices.packageManager = json.packageManager;
135
+ if (json.githubUrl !== undefined)
136
+ choices.githubUrl = json.githubUrl;
137
+ if (json.cjkFriendly !== undefined)
138
+ choices.cjkFriendly = json.cjkFriendly;
139
+ if (json.headerRightItems !== undefined) {
140
+ choices.headerRightItems = json.headerRightItems;
141
+ }
142
+ if (json.features) {
143
+ // Warn about unrecognized feature names
144
+ for (const name of json.features) {
145
+ if (!KNOWN_FEATURES.has(name)) {
146
+ console.warn(`Warning: unknown feature "${name}" in preset — ignored`);
147
+ }
148
+ }
149
+ const featureMap = {};
150
+ for (const f of FEATURES) {
151
+ featureMap[f.value] = json.features.includes(f.value);
152
+ }
153
+ choices.features = featureMap;
154
+ }
155
+ return choices;
156
+ }
@@ -0,0 +1,32 @@
1
+ import type { PresetHeaderRightItem } from "./preset.js";
2
+ export interface UserChoices {
3
+ projectName: string;
4
+ defaultLang: string;
5
+ colorSchemeMode: "single" | "light-dark";
6
+ singleScheme?: string;
7
+ lightScheme?: string;
8
+ darkScheme?: string;
9
+ respectPrefersColorScheme?: boolean;
10
+ defaultMode?: "light" | "dark";
11
+ features: string[];
12
+ githubUrl?: string;
13
+ cjkFriendly?: boolean;
14
+ packageManager: "pnpm" | "npm" | "yarn" | "bun";
15
+ headerRightItems?: PresetHeaderRightItem[];
16
+ }
17
+ export interface PartialChoices {
18
+ projectName?: string;
19
+ defaultLang?: string;
20
+ colorSchemeMode?: "single" | "light-dark";
21
+ singleScheme?: string;
22
+ lightScheme?: string;
23
+ darkScheme?: string;
24
+ respectPrefersColorScheme?: boolean;
25
+ defaultMode?: "light" | "dark";
26
+ features?: Partial<Record<string, boolean>>;
27
+ githubUrl?: string;
28
+ cjkFriendly?: boolean;
29
+ packageManager?: "pnpm" | "npm" | "yarn" | "bun";
30
+ headerRightItems?: PresetHeaderRightItem[];
31
+ }
32
+ export declare function runPrompts(prefilled?: PartialChoices): Promise<UserChoices>;
@@ -0,0 +1,248 @@
1
+ import * as p from "@clack/prompts";
2
+ import { LIGHT_DARK_PAIRINGS, SINGLE_SCHEMES, FEATURES, SUPPORTED_LANGS } from "./constants.js";
3
+ export async function runPrompts(prefilled = {}) {
4
+ // 1. Project name
5
+ let projectName;
6
+ if (prefilled.projectName) {
7
+ projectName = prefilled.projectName;
8
+ }
9
+ else {
10
+ const result = await p.text({
11
+ message: "What is your project name?",
12
+ placeholder: "my-docs",
13
+ defaultValue: "my-docs",
14
+ validate(value) {
15
+ if (!value.trim())
16
+ return "Project name is required";
17
+ if (/^[./]|\.\./.test(value))
18
+ return "Project name must not contain path traversal characters";
19
+ if (/[<>:"|?*\\]/.test(value))
20
+ return "Project name contains invalid characters";
21
+ },
22
+ });
23
+ if (p.isCancel(result))
24
+ process.exit(0);
25
+ projectName = result;
26
+ }
27
+ // 2. Default language
28
+ let defaultLang;
29
+ if (prefilled.defaultLang) {
30
+ defaultLang = prefilled.defaultLang;
31
+ }
32
+ else {
33
+ const result = await p.select({
34
+ message: "Default language:",
35
+ options: SUPPORTED_LANGS.map((l) => ({
36
+ value: l.value,
37
+ label: `${l.label} (${l.value})`,
38
+ })),
39
+ initialValue: "en",
40
+ });
41
+ if (p.isCancel(result))
42
+ process.exit(0);
43
+ defaultLang = result;
44
+ }
45
+ // 3. Color scheme mode
46
+ let colorSchemeMode;
47
+ if (prefilled.colorSchemeMode) {
48
+ colorSchemeMode = prefilled.colorSchemeMode;
49
+ }
50
+ else {
51
+ const result = await p.select({
52
+ message: "Color scheme mode:",
53
+ options: [
54
+ {
55
+ value: "light-dark",
56
+ label: "Light & Dark (toggle)",
57
+ hint: "Users can switch between light and dark themes",
58
+ },
59
+ {
60
+ value: "single",
61
+ label: "Single scheme",
62
+ hint: "One color scheme for the entire site",
63
+ },
64
+ ],
65
+ });
66
+ if (p.isCancel(result))
67
+ process.exit(0);
68
+ colorSchemeMode = result;
69
+ }
70
+ let singleScheme;
71
+ let lightScheme;
72
+ let darkScheme;
73
+ let respectPrefersColorScheme = prefilled.respectPrefersColorScheme ?? true;
74
+ let defaultMode = prefilled.defaultMode ?? "dark";
75
+ if (colorSchemeMode === "single") {
76
+ if (prefilled.singleScheme) {
77
+ singleScheme = prefilled.singleScheme;
78
+ }
79
+ else {
80
+ const scheme = await p.select({
81
+ message: "Choose a color scheme:",
82
+ options: SINGLE_SCHEMES.map((s) => ({ value: s, label: s })),
83
+ });
84
+ if (p.isCancel(scheme))
85
+ process.exit(0);
86
+ singleScheme = scheme;
87
+ }
88
+ }
89
+ else {
90
+ if (prefilled.lightScheme && prefilled.darkScheme) {
91
+ lightScheme = prefilled.lightScheme;
92
+ darkScheme = prefilled.darkScheme;
93
+ }
94
+ else {
95
+ const pairingChoice = await p.select({
96
+ message: "Choose a light/dark pairing:",
97
+ options: [
98
+ ...LIGHT_DARK_PAIRINGS.map((pair) => ({
99
+ value: pair.label,
100
+ label: `${pair.light} + ${pair.dark}`,
101
+ hint: pair.label,
102
+ })),
103
+ {
104
+ value: "custom",
105
+ label: "Pick individually",
106
+ hint: "Choose light and dark schemes separately",
107
+ },
108
+ ],
109
+ });
110
+ if (p.isCancel(pairingChoice))
111
+ process.exit(0);
112
+ if (pairingChoice === "custom") {
113
+ const lightSchemes = SINGLE_SCHEMES.filter((s) => ["Light", "Latte", "Dawn"].some((k) => s.includes(k)));
114
+ const darkSchemes = SINGLE_SCHEMES.filter((s) => !["Light", "Latte", "Dawn"].some((k) => s.includes(k)));
115
+ const light = await p.select({
116
+ message: "Choose light scheme:",
117
+ options: lightSchemes.map((s) => ({ value: s, label: s })),
118
+ });
119
+ if (p.isCancel(light))
120
+ process.exit(0);
121
+ lightScheme = light;
122
+ const dark = await p.select({
123
+ message: "Choose dark scheme:",
124
+ options: darkSchemes.map((s) => ({ value: s, label: s })),
125
+ });
126
+ if (p.isCancel(dark))
127
+ process.exit(0);
128
+ darkScheme = dark;
129
+ }
130
+ else {
131
+ const pairing = LIGHT_DARK_PAIRINGS.find((pair) => pair.label === pairingChoice);
132
+ if (pairing) {
133
+ lightScheme = pairing.light;
134
+ darkScheme = pairing.dark;
135
+ }
136
+ }
137
+ }
138
+ // Default mode
139
+ if (prefilled.defaultMode === undefined) {
140
+ const modeResult = await p.select({
141
+ message: "Default color mode:",
142
+ options: [
143
+ {
144
+ value: "dark",
145
+ label: "Dark",
146
+ hint: "Start in dark mode",
147
+ },
148
+ {
149
+ value: "light",
150
+ label: "Light",
151
+ hint: "Start in light mode",
152
+ },
153
+ ],
154
+ });
155
+ if (p.isCancel(modeResult))
156
+ process.exit(0);
157
+ defaultMode = modeResult;
158
+ }
159
+ // Respect system preference
160
+ if (prefilled.respectPrefersColorScheme === undefined) {
161
+ const respect = await p.confirm({
162
+ message: "Respect system color scheme preference?",
163
+ initialValue: true,
164
+ });
165
+ if (p.isCancel(respect))
166
+ process.exit(0);
167
+ respectPrefersColorScheme = respect;
168
+ }
169
+ }
170
+ // 4. Features
171
+ let features;
172
+ if (prefilled.features) {
173
+ // Build features from explicit overrides + defaults
174
+ features = FEATURES.filter((f) => {
175
+ if (f.value in prefilled.features) {
176
+ return prefilled.features[f.value];
177
+ }
178
+ return f.default;
179
+ }).map((f) => f.value);
180
+ }
181
+ else {
182
+ const result = await p.multiselect({
183
+ message: "Include extra features:",
184
+ options: FEATURES.map((f) => ({
185
+ value: f.value,
186
+ label: f.label,
187
+ hint: f.hint,
188
+ })),
189
+ initialValues: FEATURES.filter((f) => f.default).map((f) => f.value),
190
+ required: false,
191
+ });
192
+ if (p.isCancel(result))
193
+ process.exit(0);
194
+ features = result;
195
+ }
196
+ // 5. GitHub URL (drives header GitHub icon + view-source link)
197
+ let githubUrl = prefilled.githubUrl;
198
+ if (githubUrl === undefined) {
199
+ const result = await p.text({
200
+ message: "GitHub repository URL (optional, leave blank to disable):",
201
+ placeholder: "https://github.com/you/your-repo",
202
+ defaultValue: "",
203
+ validate(value) {
204
+ if (!value)
205
+ return;
206
+ if (!/^https?:\/\//.test(value))
207
+ return "URL must start with http(s)://";
208
+ },
209
+ });
210
+ if (p.isCancel(result))
211
+ process.exit(0);
212
+ githubUrl = result;
213
+ }
214
+ // 6. Package manager
215
+ let packageManager;
216
+ if (prefilled.packageManager) {
217
+ packageManager = prefilled.packageManager;
218
+ }
219
+ else {
220
+ const result = await p.select({
221
+ message: "Package manager:",
222
+ options: [
223
+ { value: "pnpm", label: "pnpm", hint: "Recommended" },
224
+ { value: "npm", label: "npm" },
225
+ { value: "yarn", label: "yarn" },
226
+ { value: "bun", label: "bun" },
227
+ ],
228
+ });
229
+ if (p.isCancel(result))
230
+ process.exit(0);
231
+ packageManager = result;
232
+ }
233
+ return {
234
+ projectName,
235
+ defaultLang,
236
+ colorSchemeMode,
237
+ singleScheme,
238
+ lightScheme,
239
+ darkScheme,
240
+ respectPrefersColorScheme,
241
+ defaultMode,
242
+ features,
243
+ githubUrl,
244
+ cjkFriendly: prefilled.cjkFriendly,
245
+ packageManager,
246
+ headerRightItems: prefilled.headerRightItems,
247
+ };
248
+ }
@@ -0,0 +1,4 @@
1
+ import type { UserChoices } from "./prompts.js";
2
+ import { getSecondaryLang } from "./utils.js";
3
+ export { getSecondaryLang };
4
+ export declare function scaffold(choices: UserChoices): Promise<void>;