create-zudo-doc 3.1.0 → 3.3.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.
- package/dist/claude-md-gen.d.ts +8 -0
- package/dist/claude-md-gen.js +43 -26
- package/dist/compose.d.ts +14 -20
- package/dist/compose.js +15 -25
- package/dist/features/body-foot-util.d.ts +8 -4
- package/dist/features/body-foot-util.js +8 -4
- package/dist/features/claude-resources.d.ts +12 -0
- package/dist/features/claude-resources.js +13 -6
- package/dist/features/design-token-panel.d.ts +0 -12
- package/dist/features/design-token-panel.js +32 -93
- package/dist/features/doc-history.d.ts +18 -3
- package/dist/features/doc-history.js +45 -60
- package/dist/features/doc-tags.d.ts +9 -13
- package/dist/features/doc-tags.js +10 -26
- package/dist/features/dynamic-page-transition.d.ts +19 -30
- package/dist/features/dynamic-page-transition.js +21 -209
- package/dist/features/footer-taglist.d.ts +1 -1
- package/dist/features/footer-taglist.js +1 -1
- package/dist/features/footer.d.ts +3 -2
- package/dist/features/footer.js +3 -2
- package/dist/features/i18n.d.ts +13 -8
- package/dist/features/i18n.js +14 -9
- package/dist/features/image-enlarge.d.ts +7 -26
- package/dist/features/image-enlarge.js +7 -26
- package/dist/features/llms-txt.d.ts +3 -5
- package/dist/features/llms-txt.js +3 -5
- package/dist/features/search.d.ts +7 -3
- package/dist/features/search.js +7 -3
- package/dist/features/sidebar-resizer.d.ts +4 -8
- package/dist/features/sidebar-resizer.js +4 -8
- package/dist/features/sidebar-toggle.d.ts +7 -7
- package/dist/features/sidebar-toggle.js +7 -7
- package/dist/features/tag-governance.d.ts +14 -7
- package/dist/features/tag-governance.js +52 -8
- package/dist/features/tauri.d.ts +13 -10
- package/dist/features/tauri.js +16 -52
- package/dist/features/versioning.d.ts +12 -24
- package/dist/features/versioning.js +13 -39
- package/dist/index.js +2 -3
- package/dist/preset.d.ts +1 -0
- package/dist/preset.js +5 -0
- package/dist/prompts.d.ts +2 -0
- package/dist/prompts.js +1 -0
- package/dist/scaffold.d.ts +13 -6
- package/dist/scaffold.js +78 -59
- package/dist/utils.d.ts +10 -0
- package/dist/utils.js +14 -0
- package/dist/zfb-config-gen.d.ts +32 -20
- package/dist/zfb-config-gen.js +400 -53
- package/package.json +2 -2
- package/templates/base/pages/docs/[[...slug]].tsx +59 -0
- package/templates/base/pages/index.tsx +6 -41
- package/templates/base/scripts/setup-doc-skill.sh +261 -0
- package/templates/base/src/styles/global.css +15 -340
- package/templates/base/tsconfig.json +3 -26
- package/templates/features/i18n/files/pages/[locale]/docs/[[...slug]].tsx +88 -0
- package/templates/features/tagGovernance/files/scripts/tags-suggest.ts +3 -1
- package/dist/settings-gen.d.ts +0 -2
- package/dist/settings-gen.js +0 -319
- package/templates/base/.htmlvalidate.json +0 -5
- package/templates/base/.zfb/doc-history-meta.json +0 -1
- package/templates/base/pages/_data.ts +0 -160
- package/templates/base/pages/lib/_body-end-islands.tsx +0 -165
- package/templates/base/pages/lib/_chrome.ts +0 -167
- package/templates/base/pages/lib/_details.tsx +0 -29
- package/templates/base/pages/lib/_doc-route-entries.ts +0 -10
- package/templates/base/pages/lib/_extract-headings.ts +0 -37
- package/templates/base/pages/lib/_frontmatter-preview-data.ts +0 -27
- package/templates/base/pages/lib/_nav-source-cache.ts +0 -100
- package/templates/base/pages/lib/_nav-source-docs.ts +0 -17
- package/templates/base/pages/lib/_preset-generator.tsx +0 -81
- package/templates/base/pages/lib/_route-context.ts +0 -32
- package/templates/base/pages/lib/_search-widget.tsx +0 -17
- package/templates/base/pages/lib/doc-page-props.ts +0 -30
- package/templates/base/pages/lib/locale-merge.ts +0 -59
- package/templates/base/scripts/run-b4push.sh +0 -102
- package/templates/base/src/components/ai-chat-modal.tsx +0 -18
- package/templates/base/src/components/content/code-group.tsx +0 -3
- package/templates/base/src/components/content/content-admonition.tsx +0 -4
- package/templates/base/src/components/desktop-sidebar-toggle.tsx +0 -15
- package/templates/base/src/components/doc-history.tsx +0 -21
- package/templates/base/src/components/image-enlarge.tsx +0 -24
- package/templates/base/src/components/preset-generator.tsx +0 -14
- package/templates/base/src/components/sidebar-toggle.tsx +0 -6
- package/templates/base/src/components/sidebar-tree.tsx +0 -6
- package/templates/base/src/config/color-scheme-utils.ts +0 -69
- package/templates/base/src/config/color-schemes.ts +0 -165
- package/templates/base/src/config/docs-schema.ts +0 -95
- package/templates/base/src/config/frontmatter-preview-defaults.ts +0 -27
- package/templates/base/src/config/frontmatter-preview-renderers.tsx +0 -46
- package/templates/base/src/config/i18n.ts +0 -239
- package/templates/base/src/config/settings-types.ts +0 -45
- package/templates/base/src/config/sidebars.ts +0 -66
- package/templates/base/src/config/tag-vocabulary-types.ts +0 -4
- package/templates/base/src/config/tag-vocabulary.ts +0 -20
- package/templates/base/src/config/z-index-tokens.ts +0 -128
- package/templates/base/src/types/docs-entry.ts +0 -28
- package/templates/base/src/types/heading.ts +0 -5
- package/templates/base/src/types/locale.ts +0 -10
- package/templates/base/src/utils/base.ts +0 -164
- package/templates/base/src/utils/docs.ts +0 -446
- package/templates/base/src/utils/git-info.ts +0 -70
- package/templates/base/src/utils/github.ts +0 -22
- package/templates/base/src/utils/nav-scope.ts +0 -34
- package/templates/base/src/utils/sidebar.ts +0 -36
- package/templates/base/src/utils/slug.ts +0 -10
- package/templates/base/src/utils/smart-break.tsx +0 -12
- package/templates/base/src/utils/tags.ts +0 -83
- package/templates/base/zfb-shim.d.ts +0 -178
- package/templates/features/bodyFootUtil/files/src/utils/github.ts +0 -22
- package/templates/features/claudeResources/files/src/integrations/claude-resources/__tests__/escape-for-mdx.test.ts +0 -42
- package/templates/features/claudeResources/files/src/integrations/claude-resources/__tests__/generate.test.ts +0 -752
- package/templates/features/claudeResources/files/src/integrations/claude-resources/escape-for-mdx.ts +0 -97
- package/templates/features/claudeResources/files/src/integrations/claude-resources/generate.ts +0 -735
- package/templates/features/designTokenPanel/files/src/components/design-token-panel-bootstrap.tsx +0 -15
- package/templates/features/designTokenPanel/files/src/config/design-token-panel-config.ts +0 -435
- package/templates/features/designTokenPanel/files/src/config/design-tokens-manifest.ts +0 -174
- package/templates/features/designTokenPanel/files/src/lib/design-token-panel-bootstrap.ts +0 -30
- package/templates/features/docHistory/files/src/components/doc-history.tsx +0 -10
- package/templates/features/docHistory/files/src/types/doc-history.ts +0 -7
- package/templates/features/dynamicPageTransition/files/src/components/client-router-bootstrap.tsx +0 -72
- package/templates/features/i18n/files/pages/[locale]/index.tsx +0 -72
- package/templates/features/imageEnlarge/files/src/components/image-enlarge.tsx +0 -11
- package/templates/features/sidebarToggle/files/src/components/desktop-sidebar-toggle.tsx +0 -6
- package/templates/features/tauri/files/src/components/find-bar.tsx +0 -122
- package/templates/features/tauri/files/src/components/find-in-page-init.tsx +0 -59
- package/templates/features/tauri/files/src/utils/find-in-page.ts +0 -175
package/dist/zfb-config-gen.js
CHANGED
|
@@ -1,62 +1,409 @@
|
|
|
1
|
+
import { capitalize, getSecondaryLang, getLangLabel } from "./utils.js";
|
|
1
2
|
/**
|
|
2
|
-
* Programmatically generate zfb.config.ts
|
|
3
|
+
* Programmatically generate the ONE `zfb.config.ts` a scaffolded project
|
|
4
|
+
* ships (epic zudolab/zudo-doc#2651, minimal-scaffold Wave 6 #2660).
|
|
3
5
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* result into `defineConfig` and keeps only the project-owned shell fields
|
|
10
|
-
* (`framework`, `port`, `tailwind`, `base`).
|
|
6
|
+
* Replaces the former `settings-gen.ts` + `zfb-config-gen.ts` pair: there is
|
|
7
|
+
* no more `src/config/settings.ts` — every user choice becomes a field
|
|
8
|
+
* passed straight into `zudoDoc({ ... })` (`@takazudo/zudo-doc/config`),
|
|
9
|
+
* which merges it over the package's own documented defaults and returns a
|
|
10
|
+
* complete `ZfbConfig`.
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* `packages/zudo-doc/src/preset.ts` and the project's `settings.ts` instead.
|
|
12
|
+
* DIFF-FROM-DEFAULTS (locked, #2653 Decision 2): only fields whose resolved
|
|
13
|
+
* value differs from the matching `ZudoDocConfig` `@default` are emitted —
|
|
14
|
+
* `siteName` is the one field always emitted. `DEFAULT_MIRROR` below is a
|
|
15
|
+
* hand-kept copy of `packages/zudo-doc/src/config.ts`'s `DEFAULT_SETTINGS`
|
|
16
|
+
* for exactly the fields this generator ever sets. It has to be a local
|
|
17
|
+
* mirror (not an import) because `create-zudo-doc` does not depend on
|
|
18
|
+
* `@takazudo/zudo-doc` at generator-build time — the package is only ever a
|
|
19
|
+
* runtime dependency of the SCAFFOLDED project, never of the generator
|
|
20
|
+
* itself. Keep this mirror in sync by hand whenever `DEFAULT_SETTINGS`
|
|
21
|
+
* changes for one of the fields listed here.
|
|
23
22
|
*/
|
|
24
|
-
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// DEFAULT_MIRROR — see the file header. Only fields this generator can ever
|
|
25
|
+
// set need an entry; anything else is simply never emitted.
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
export const DEFAULT_MIRROR = {
|
|
28
|
+
colorScheme: "Default Dark",
|
|
29
|
+
colorMode: {
|
|
30
|
+
defaultMode: "dark",
|
|
31
|
+
lightScheme: "Default Light",
|
|
32
|
+
darkScheme: "Default Dark",
|
|
33
|
+
respectPrefersColorScheme: true,
|
|
34
|
+
},
|
|
35
|
+
siteName: "Docs",
|
|
36
|
+
minifyHtml: true,
|
|
37
|
+
defaultLocale: "en",
|
|
38
|
+
locales: {},
|
|
39
|
+
noindex: false,
|
|
40
|
+
githubUrl: false,
|
|
41
|
+
metaTags: {
|
|
42
|
+
description: true,
|
|
43
|
+
keywords: false,
|
|
44
|
+
ogImage: false,
|
|
45
|
+
ogSiteName: true,
|
|
46
|
+
twitterCard: false,
|
|
47
|
+
},
|
|
48
|
+
docTags: false,
|
|
49
|
+
tagGovernance: "off",
|
|
50
|
+
tagVocabulary: false,
|
|
51
|
+
llmsTxt: false,
|
|
52
|
+
cjkFriendly: false,
|
|
53
|
+
designTokenPanel: false,
|
|
54
|
+
sidebarResizer: false,
|
|
55
|
+
sidebarToggle: false,
|
|
56
|
+
imageEnlarge: false,
|
|
57
|
+
findInPage: false,
|
|
58
|
+
dynamicPageTransition: false,
|
|
59
|
+
docHistory: false,
|
|
60
|
+
bodyFootUtilArea: false,
|
|
61
|
+
versions: false,
|
|
62
|
+
claudeResources: false,
|
|
63
|
+
defaultLocaleOnlyPrefixes: [],
|
|
64
|
+
footer: false,
|
|
65
|
+
headerNav: [],
|
|
66
|
+
headerRightItems: [{ type: "component", component: "theme-toggle" }],
|
|
67
|
+
};
|
|
68
|
+
function raw(code) {
|
|
69
|
+
return { __rawCode: code };
|
|
70
|
+
}
|
|
71
|
+
function isRawCode(value) {
|
|
72
|
+
return (typeof value === "object" &&
|
|
73
|
+
value !== null &&
|
|
74
|
+
"__rawCode" in value);
|
|
75
|
+
}
|
|
76
|
+
function deepEqual(a, b) {
|
|
77
|
+
if (a === b)
|
|
78
|
+
return true;
|
|
79
|
+
if (typeof a !== typeof b)
|
|
80
|
+
return false;
|
|
81
|
+
if (Array.isArray(a) || Array.isArray(b)) {
|
|
82
|
+
if (!Array.isArray(a) || !Array.isArray(b))
|
|
83
|
+
return false;
|
|
84
|
+
if (a.length !== b.length)
|
|
85
|
+
return false;
|
|
86
|
+
return a.every((v, i) => deepEqual(v, b[i]));
|
|
87
|
+
}
|
|
88
|
+
if (a && b && typeof a === "object" && typeof b === "object") {
|
|
89
|
+
const ak = Object.keys(a);
|
|
90
|
+
const bk = Object.keys(b);
|
|
91
|
+
if (ak.length !== bk.length)
|
|
92
|
+
return false;
|
|
93
|
+
return ak.every((k) => deepEqual(a[k], b[k]));
|
|
94
|
+
}
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
const IDENT_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
98
|
+
function serializeValue(value, indent) {
|
|
99
|
+
const pad = " ".repeat(indent);
|
|
100
|
+
const padInner = " ".repeat(indent + 1);
|
|
101
|
+
if (isRawCode(value))
|
|
102
|
+
return value.__rawCode;
|
|
103
|
+
if (value === null)
|
|
104
|
+
return "null";
|
|
105
|
+
if (typeof value === "string")
|
|
106
|
+
return JSON.stringify(value);
|
|
107
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
108
|
+
return String(value);
|
|
109
|
+
}
|
|
110
|
+
if (Array.isArray(value)) {
|
|
111
|
+
if (value.length === 0)
|
|
112
|
+
return "[]";
|
|
113
|
+
const items = value
|
|
114
|
+
.map((v) => `${padInner}${serializeValue(v, indent + 1)}`)
|
|
115
|
+
.join(",\n");
|
|
116
|
+
return `[\n${items},\n${pad}]`;
|
|
117
|
+
}
|
|
118
|
+
if (typeof value === "object") {
|
|
119
|
+
const entries = Object.entries(value).filter(([, v]) => v !== undefined);
|
|
120
|
+
if (entries.length === 0)
|
|
121
|
+
return "{}";
|
|
122
|
+
const items = entries
|
|
123
|
+
.map(([k, v]) => {
|
|
124
|
+
const key = IDENT_RE.test(k) ? k : JSON.stringify(k);
|
|
125
|
+
return `${padInner}${key}: ${serializeValue(v, indent + 1)}`;
|
|
126
|
+
})
|
|
127
|
+
.join(",\n");
|
|
128
|
+
return `{\n${items},\n${pad}}`;
|
|
129
|
+
}
|
|
130
|
+
throw new Error(`zfb-config-gen: cannot serialize value ${String(value)}`);
|
|
131
|
+
}
|
|
132
|
+
// ---------------------------------------------------------------------------
|
|
133
|
+
// Desired-config builder — mirrors every user-choice → settings mapping the
|
|
134
|
+
// old settings-gen.ts had, but as a plain object instead of emitted lines.
|
|
135
|
+
// ---------------------------------------------------------------------------
|
|
136
|
+
function buildDesiredConfig(choices) {
|
|
137
|
+
const desired = {};
|
|
138
|
+
// siteName is ALWAYS emitted (locked spec — the one field you almost
|
|
139
|
+
// always set, and the clearest anchor in a near-empty config file).
|
|
140
|
+
desired.siteName = capitalize(choices.projectName.replace(/-/g, " "));
|
|
141
|
+
// ── Color scheme ──────────────────────────────────────────────────────
|
|
142
|
+
if (choices.colorSchemeMode === "single") {
|
|
143
|
+
desired.colorScheme = choices.singleScheme ?? "Default Dark";
|
|
144
|
+
desired.colorMode = false;
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
desired.colorScheme = choices.darkScheme ?? "Default Dark";
|
|
148
|
+
desired.colorMode = {
|
|
149
|
+
defaultMode: choices.defaultMode ?? "dark",
|
|
150
|
+
lightScheme: choices.lightScheme ?? "Default Light",
|
|
151
|
+
darkScheme: choices.darkScheme ?? "Default Dark",
|
|
152
|
+
respectPrefersColorScheme: choices.respectPrefersColorScheme ?? true,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
// ── i18n ──────────────────────────────────────────────────────────────
|
|
156
|
+
desired.defaultLocale = choices.defaultLang ?? "en";
|
|
157
|
+
if (choices.features.includes("i18n")) {
|
|
158
|
+
const secondaryLang = getSecondaryLang(choices.defaultLang);
|
|
159
|
+
desired.locales = {
|
|
160
|
+
[secondaryLang]: {
|
|
161
|
+
label: getLangLabel(secondaryLang),
|
|
162
|
+
dir: `src/content/docs-${secondaryLang}`,
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
desired.locales = {};
|
|
168
|
+
}
|
|
169
|
+
// ── Misc site fields ──────────────────────────────────────────────────
|
|
170
|
+
desired.minifyHtml = choices.minifyHtml ?? true;
|
|
171
|
+
desired.noindex = choices.features.includes("noindex");
|
|
172
|
+
const rawGithubUrl = (choices.githubUrl ?? "").trim();
|
|
173
|
+
desired.githubUrl = rawGithubUrl ? rawGithubUrl : false;
|
|
174
|
+
desired.cjkFriendly = choices.cjkFriendly ?? false;
|
|
175
|
+
// ── Meta tags ─────────────────────────────────────────────────────────
|
|
176
|
+
if (choices.metaTags) {
|
|
177
|
+
const mt = choices.metaTags;
|
|
178
|
+
desired.metaTags = {
|
|
179
|
+
description: mt.description !== undefined ? mt.description : true,
|
|
180
|
+
keywords: mt.keywords !== undefined ? mt.keywords : false,
|
|
181
|
+
ogImage: mt.ogImage !== undefined ? mt.ogImage : false,
|
|
182
|
+
ogSiteName: mt.ogSiteName !== undefined ? mt.ogSiteName : true,
|
|
183
|
+
...(mt.twitterCard
|
|
184
|
+
? {
|
|
185
|
+
twitterCard: mt.twitterCard,
|
|
186
|
+
...(mt.twitterSite ? { twitterSite: mt.twitterSite } : {}),
|
|
187
|
+
...(mt.twitterCreator
|
|
188
|
+
? { twitterCreator: mt.twitterCreator }
|
|
189
|
+
: {}),
|
|
190
|
+
}
|
|
191
|
+
: { twitterCard: false }),
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
// ── Tags / docs ───────────────────────────────────────────────────────
|
|
195
|
+
desired.docTags = choices.features.includes("docTags");
|
|
196
|
+
if (choices.features.includes("tagGovernance")) {
|
|
197
|
+
desired.tagGovernance = "warn";
|
|
198
|
+
desired.tagVocabulary = true;
|
|
199
|
+
// Wired to the src/config/tag-vocabulary.ts starter file the
|
|
200
|
+
// tagGovernance feature module emits (single source of truth shared
|
|
201
|
+
// with scripts/tags-audit.ts and scripts/tags-suggest.ts).
|
|
202
|
+
desired.tagVocabularyEntries = raw("tagVocabulary");
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
desired.tagGovernance = "off";
|
|
206
|
+
desired.tagVocabulary = false;
|
|
207
|
+
}
|
|
208
|
+
desired.llmsTxt = choices.features.includes("llmsTxt");
|
|
209
|
+
// ── Feature toggles ───────────────────────────────────────────────────
|
|
210
|
+
desired.designTokenPanel = choices.features.includes("designTokenPanel");
|
|
211
|
+
desired.sidebarResizer = choices.features.includes("sidebarResizer");
|
|
212
|
+
desired.sidebarToggle = choices.features.includes("sidebarToggle");
|
|
213
|
+
desired.imageEnlarge = choices.features.includes("imageEnlarge");
|
|
214
|
+
// findInPage rides the existing tauri feature (#2690) — the Cmd/Ctrl+F find
|
|
215
|
+
// bar only makes sense inside the Tauri desktop shell, so it has no CLI
|
|
216
|
+
// flag or prompt of its own; there is no separate "findInPage" feature
|
|
217
|
+
// module.
|
|
218
|
+
desired.findInPage = choices.features.includes("tauri");
|
|
219
|
+
desired.dynamicPageTransition = choices.features.includes("dynamicPageTransition");
|
|
220
|
+
desired.docHistory = choices.features.includes("docHistory");
|
|
221
|
+
if (choices.features.includes("bodyFootUtil")) {
|
|
222
|
+
desired.bodyFootUtilArea = {
|
|
223
|
+
docHistory: choices.features.includes("docHistory"),
|
|
224
|
+
viewSourceLink: Boolean(rawGithubUrl),
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
desired.bodyFootUtilArea = false;
|
|
229
|
+
}
|
|
230
|
+
desired.versions = choices.features.includes("versioning") ? [] : false;
|
|
231
|
+
if (choices.features.includes("claudeResources")) {
|
|
232
|
+
desired.claudeResources = { claudeDir: ".claude" };
|
|
233
|
+
desired.defaultLocaleOnlyPrefixes = [
|
|
234
|
+
"/docs/claude-md/",
|
|
235
|
+
"/docs/claude-skills/",
|
|
236
|
+
"/docs/claude-agents/",
|
|
237
|
+
"/docs/claude-commands/",
|
|
238
|
+
];
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
desired.claudeResources = false;
|
|
242
|
+
desired.defaultLocaleOnlyPrefixes = [];
|
|
243
|
+
}
|
|
244
|
+
// ── Footer ────────────────────────────────────────────────────────────
|
|
245
|
+
if (choices.features.includes("footerNavGroup") ||
|
|
246
|
+
choices.features.includes("footerCopyright") ||
|
|
247
|
+
choices.features.includes("footerTaglist")) {
|
|
248
|
+
const footer = {
|
|
249
|
+
links: choices.features.includes("footerNavGroup")
|
|
250
|
+
? [
|
|
251
|
+
{
|
|
252
|
+
title: "Docs",
|
|
253
|
+
items: [
|
|
254
|
+
{ label: "Getting Started", href: "/docs/getting-started" },
|
|
255
|
+
],
|
|
256
|
+
},
|
|
257
|
+
]
|
|
258
|
+
: [],
|
|
259
|
+
};
|
|
260
|
+
if (choices.features.includes("footerCopyright")) {
|
|
261
|
+
footer.copyright = `Copyright © ${new Date().getFullYear()} Your Name. Built with zudo-doc.`;
|
|
262
|
+
}
|
|
263
|
+
if (choices.features.includes("footerTaglist")) {
|
|
264
|
+
footer.taglist = { enabled: true, groupBy: "group" };
|
|
265
|
+
}
|
|
266
|
+
desired.footer = footer;
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
desired.footer = false;
|
|
270
|
+
}
|
|
271
|
+
// ── Header nav / header-right ────────────────────────────────────────
|
|
272
|
+
const headerNav = [
|
|
273
|
+
{
|
|
274
|
+
label: "Getting Started",
|
|
275
|
+
path: "/docs/getting-started",
|
|
276
|
+
categoryMatch: "getting-started",
|
|
277
|
+
},
|
|
278
|
+
];
|
|
279
|
+
// The "claude" categoryMatch is load-bearing beyond the header link — see
|
|
280
|
+
// the old settings-gen.ts note (preserved): getCategoryOrder() derives the
|
|
281
|
+
// satellite-grouping prefixes from headerNav.
|
|
282
|
+
if (choices.features.includes("claudeResources")) {
|
|
283
|
+
headerNav.push({
|
|
284
|
+
label: "Claude",
|
|
285
|
+
path: "/docs/claude",
|
|
286
|
+
categoryMatch: "claude",
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
if (choices.features.includes("changelog")) {
|
|
290
|
+
headerNav.push({
|
|
291
|
+
label: "Changelog",
|
|
292
|
+
path: "/docs/changelog",
|
|
293
|
+
categoryMatch: "changelog",
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
desired.headerNav = headerNav;
|
|
297
|
+
if (choices.headerRightItems !== undefined) {
|
|
298
|
+
// User-supplied override (including empty array) — emit verbatim, minus
|
|
299
|
+
// a defensive strip of "design-token-panel" when the feature is off.
|
|
300
|
+
desired.headerRightItems = choices.headerRightItems.filter((item) => !(item.type === "trigger" &&
|
|
301
|
+
item.trigger === "design-token-panel" &&
|
|
302
|
+
!choices.features.includes("designTokenPanel")));
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
const items = [];
|
|
306
|
+
if (choices.features.includes("designTokenPanel")) {
|
|
307
|
+
items.push({ type: "trigger", trigger: "design-token-panel" });
|
|
308
|
+
}
|
|
309
|
+
if (choices.features.includes("versioning")) {
|
|
310
|
+
items.push({ type: "component", component: "version-switcher" });
|
|
311
|
+
}
|
|
312
|
+
items.push({ type: "component", component: "github-link" });
|
|
313
|
+
items.push({ type: "component", component: "theme-toggle" });
|
|
314
|
+
if (choices.features.includes("search")) {
|
|
315
|
+
items.push({ type: "component", component: "search" });
|
|
316
|
+
}
|
|
317
|
+
if (choices.features.includes("i18n")) {
|
|
318
|
+
items.push({ type: "component", component: "language-switcher" });
|
|
319
|
+
}
|
|
320
|
+
desired.headerRightItems = items;
|
|
321
|
+
}
|
|
322
|
+
return desired;
|
|
323
|
+
}
|
|
324
|
+
// ---------------------------------------------------------------------------
|
|
325
|
+
// Field order — purely cosmetic (mirrors ZudoDocConfig's declaration order
|
|
326
|
+
// in packages/zudo-doc/src/config.ts so the emitted file reads like the
|
|
327
|
+
// documented reference). Any key produced by buildDesiredConfig() that is
|
|
328
|
+
// missing here is appended AFTER the ordered ones in ALPHABETICAL order (see
|
|
329
|
+
// orderDesiredKeys) — defensive: a newly-added desired key someone forgot to
|
|
330
|
+
// list here still emits deterministically instead of being silently dropped.
|
|
331
|
+
// ---------------------------------------------------------------------------
|
|
332
|
+
const FIELD_ORDER = [
|
|
333
|
+
"colorScheme",
|
|
334
|
+
"colorMode",
|
|
335
|
+
"siteName",
|
|
336
|
+
"defaultLocale",
|
|
337
|
+
"locales",
|
|
338
|
+
"noindex",
|
|
339
|
+
"githubUrl",
|
|
340
|
+
"metaTags",
|
|
341
|
+
"docTags",
|
|
342
|
+
"tagGovernance",
|
|
343
|
+
"tagVocabulary",
|
|
344
|
+
"tagVocabularyEntries",
|
|
345
|
+
"llmsTxt",
|
|
346
|
+
"cjkFriendly",
|
|
347
|
+
"designTokenPanel",
|
|
348
|
+
"sidebarResizer",
|
|
349
|
+
"sidebarToggle",
|
|
350
|
+
"imageEnlarge",
|
|
351
|
+
"findInPage",
|
|
352
|
+
"dynamicPageTransition",
|
|
353
|
+
"docHistory",
|
|
354
|
+
"bodyFootUtilArea",
|
|
355
|
+
"versions",
|
|
356
|
+
"claudeResources",
|
|
357
|
+
"defaultLocaleOnlyPrefixes",
|
|
358
|
+
"footer",
|
|
359
|
+
"headerNav",
|
|
360
|
+
"headerRightItems",
|
|
361
|
+
"minifyHtml",
|
|
362
|
+
];
|
|
363
|
+
/**
|
|
364
|
+
* Deterministic emission order for the keys of a `desired` config object:
|
|
365
|
+
* the keys present in `FIELD_ORDER` first (cosmetic reference order), then any
|
|
366
|
+
* leftover keys NOT in `FIELD_ORDER` appended in ALPHABETICAL order. The
|
|
367
|
+
* leftover branch exists so a key `buildDesiredConfig()` produces but nobody
|
|
368
|
+
* added to `FIELD_ORDER` is still emitted (deterministically) rather than
|
|
369
|
+
* silently dropped — matching what the `FIELD_ORDER` comment promises.
|
|
370
|
+
*/
|
|
371
|
+
export function orderDesiredKeys(desiredKeys) {
|
|
372
|
+
const inOrder = FIELD_ORDER.filter((k) => desiredKeys.includes(k));
|
|
373
|
+
const leftover = desiredKeys
|
|
374
|
+
.filter((k) => !FIELD_ORDER.includes(k))
|
|
375
|
+
.sort();
|
|
376
|
+
return [...inOrder, ...leftover];
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Generate the full `zfb.config.ts` source: `defineConfig(zudoDoc({ ... }))`
|
|
380
|
+
* with only the diff-from-defaults fields.
|
|
381
|
+
*/
|
|
382
|
+
export function generateZfbConfig(choices) {
|
|
383
|
+
const desired = buildDesiredConfig(choices);
|
|
384
|
+
const emittedEntries = [];
|
|
385
|
+
for (const key of orderDesiredKeys(Object.keys(desired))) {
|
|
386
|
+
const value = desired[key];
|
|
387
|
+
// siteName always emitted (locked spec); everything else diff-from-default.
|
|
388
|
+
// A leftover key not in DEFAULT_MIRROR has `DEFAULT_MIRROR[key] ===
|
|
389
|
+
// undefined`, so it never deep-equals a real value and always emits.
|
|
390
|
+
if (key !== "siteName" && deepEqual(value, DEFAULT_MIRROR[key]))
|
|
391
|
+
continue;
|
|
392
|
+
emittedEntries.push([key, value]);
|
|
393
|
+
}
|
|
25
394
|
const lines = [];
|
|
26
|
-
// --- Imports ---
|
|
27
395
|
lines.push(`import { defineConfig } from "zfb/config";`);
|
|
28
|
-
lines.push(`import {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
lines.push(`import { colorSchemes } from "./src/config/color-schemes";`);
|
|
33
|
-
lines.push(``);
|
|
34
|
-
// --- Directive vocabulary ---
|
|
35
|
-
// The seven canonical directives registered in pages/_mdx-components.ts.
|
|
36
|
-
// "details" routes to DetailsWrapper — a collapsible, NOT an admonition.
|
|
37
|
-
lines.push(`const directiveVocabulary = {`);
|
|
38
|
-
lines.push(` note: "Note",`);
|
|
39
|
-
lines.push(` tip: "Tip",`);
|
|
40
|
-
lines.push(` info: "Info",`);
|
|
41
|
-
lines.push(` warning: "Warning",`);
|
|
42
|
-
lines.push(` danger: "Danger",`);
|
|
43
|
-
lines.push(` caution: "Caution",`);
|
|
44
|
-
lines.push(` details: "Details",`);
|
|
45
|
-
lines.push(`};`);
|
|
46
|
-
lines.push(``);
|
|
47
|
-
// --- Export ---
|
|
48
|
-
lines.push(`export default defineConfig({`);
|
|
49
|
-
lines.push(` // ── Host-owned shell fields ──────────────────────────────────────────────`);
|
|
50
|
-
lines.push(` framework: "preact",`);
|
|
51
|
-
lines.push(` // Pin the dev/preview port — zfb defaults to 3000, but the generated`);
|
|
52
|
-
lines.push(` // CLAUDE.md and the Tauri dev wrappers assume 4321.`);
|
|
53
|
-
lines.push(` port: 4321,`);
|
|
54
|
-
lines.push(` tailwind: { enabled: true },`);
|
|
55
|
-
lines.push(` // Public URL prefix for <link rel="stylesheet"> and <script> tags.`);
|
|
56
|
-
lines.push(` base: settings.base,`);
|
|
396
|
+
lines.push(`import { zudoDoc } from "@takazudo/zudo-doc/config";`);
|
|
397
|
+
if (choices.features.includes("tagGovernance")) {
|
|
398
|
+
lines.push(`import { tagVocabulary } from "./src/config/tag-vocabulary";`);
|
|
399
|
+
}
|
|
57
400
|
lines.push(``);
|
|
58
|
-
lines.push(`
|
|
59
|
-
lines.push(`
|
|
60
|
-
|
|
401
|
+
lines.push(`export default defineConfig(`);
|
|
402
|
+
lines.push(` zudoDoc({`);
|
|
403
|
+
for (const [key, value] of emittedEntries) {
|
|
404
|
+
lines.push(` ${key}: ${serializeValue(value, 2)},`);
|
|
405
|
+
}
|
|
406
|
+
lines.push(` }),`);
|
|
407
|
+
lines.push(`);`);
|
|
61
408
|
return lines.join("\n") + "\n";
|
|
62
409
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-zudo-doc",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"description": "Create a new zudo-doc documentation site",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Takeshi Takatsudo",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"cli"
|
|
23
23
|
],
|
|
24
24
|
"engines": {
|
|
25
|
-
"node": ">=
|
|
25
|
+
"node": ">=22"
|
|
26
26
|
},
|
|
27
27
|
"publishConfig": {
|
|
28
28
|
"access": "public",
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/** @jsxRuntime automatic */
|
|
2
|
+
/** @jsxImportSource preact */
|
|
3
|
+
// Locked manifest (#2653 Decision 4): a SELF-CONTAINED doc-route stub —
|
|
4
|
+
// REQUIRED because the injected DYNAMIC `/docs/[[...slug]]` route 404s in
|
|
5
|
+
// `zfb dev` (real pre-existing gap in zfb's dev-mode dynamic-route rendering,
|
|
6
|
+
// distinct from the `/`-injection gap zfb#1227; empirically confirmed on
|
|
7
|
+
// #2653). This stub reconstructs the doc route from scratch using ONLY the
|
|
8
|
+
// three sanctioned package entrypoints — no `pages/lib`, no `@/config`:
|
|
9
|
+
// 1. the `virtual:zudo-doc-route-context` virtual module (serializable
|
|
10
|
+
// settings/translations/tagVocabulary/colorSchemes payload),
|
|
11
|
+
// 2. `@takazudo/zudo-doc/route-context` (`createRouteContext`), and
|
|
12
|
+
// 3. `@takazudo/zudo-doc/chrome` (`createChrome`).
|
|
13
|
+
// Makes `/docs/getting-started/` return 200 in BOTH `zfb dev` and `zfb build`
|
|
14
|
+
// (see the "TM negative guard" case in route-injection-build.slow.test.ts for
|
|
15
|
+
// the no-stub 404 proof this fixes).
|
|
16
|
+
//
|
|
17
|
+
// docHistory note: when the docHistory feature is selected, the generator
|
|
18
|
+
// patches this file to statically import DocHistory from
|
|
19
|
+
// "@takazudo/zudo-doc/doc-history" and pass it to createChrome's hostBindings
|
|
20
|
+
// (second) argument via defineChromeBindings({ DocHistory }) —
|
|
21
|
+
// DocHistory's chrome-derive default is a no-op stub (unlike
|
|
22
|
+
// DesignTokenPanelBootstrap, which the package auto-defaults), so without
|
|
23
|
+
// that patch the doc-history button never hydrates on this route.
|
|
24
|
+
|
|
25
|
+
import type { JSX } from "preact";
|
|
26
|
+
import { routeContext } from "virtual:zudo-doc-route-context";
|
|
27
|
+
import {
|
|
28
|
+
createRouteContext,
|
|
29
|
+
type RouteContextPayload,
|
|
30
|
+
} from "@takazudo/zudo-doc/route-context";
|
|
31
|
+
import { createChrome } from "@takazudo/zudo-doc/chrome";
|
|
32
|
+
|
|
33
|
+
const ctx = routeContext as unknown as RouteContextPayload;
|
|
34
|
+
const routeCtx = createRouteContext(ctx);
|
|
35
|
+
const { renderDocPage } = createChrome(routeCtx);
|
|
36
|
+
|
|
37
|
+
export const frontmatter = { title: "Docs" };
|
|
38
|
+
|
|
39
|
+
export function paths(): Array<{ params: { slug: string[] }; props: unknown }> {
|
|
40
|
+
const locale = routeCtx.defaultLocale;
|
|
41
|
+
const source = routeCtx.resolveNavSource(locale, undefined);
|
|
42
|
+
return routeCtx.buildDocRouteEntries({
|
|
43
|
+
source,
|
|
44
|
+
locale,
|
|
45
|
+
routeSig: `docs;${locale}`,
|
|
46
|
+
}).map((item) => ({
|
|
47
|
+
params: { slug: item.slugParams },
|
|
48
|
+
props: item.props,
|
|
49
|
+
}));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
type PageArgs = { params: { slug: string[] } } & Record<string, unknown>;
|
|
53
|
+
|
|
54
|
+
export default function DocsPage(props: PageArgs): JSX.Element {
|
|
55
|
+
return renderDocPage(props as never, {
|
|
56
|
+
locale: routeCtx.defaultLocale,
|
|
57
|
+
docHistoryContentDir: routeCtx.settings.docsDir,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
@@ -1,41 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
|
|
7
|
-
// — which now owns the nav-tree / tag-count data-prep sequence — and passes
|
|
8
|
-
// the result to the shared HomePageView body (epic #2499, S4 #2503).
|
|
9
|
-
//
|
|
10
|
-
// Data flow:
|
|
11
|
-
// routeContext host RouteContext (settings + i18n + nav helpers)
|
|
12
|
-
// → prepareHomeData() nav tree, category order, tag count
|
|
13
|
-
// → HomePageView renders hero + SiteTreeNav grid + tag section
|
|
14
|
-
//
|
|
15
|
-
// Thin consumer of `HomePageView` (S3 #2502) and `prepareHomeData` (#2519):
|
|
16
|
-
// this file's only job is resolving the default locale — mirroring the
|
|
17
|
-
// package route's shape (`packages/zudo-doc/src/routes/index.tsx`). No
|
|
18
|
-
// `extras` here — the showcase's `@Takazudo` brand link (#1453) is
|
|
19
|
-
// project-specific and is not part of the generated project's hero.
|
|
20
|
-
|
|
21
|
-
import { routeContext } from "./lib/_route-context";
|
|
22
|
-
import { prepareHomeData } from "@takazudo/zudo-doc/home-page";
|
|
23
|
-
import type { JSX } from "preact";
|
|
24
|
-
import { HomePageView } from "./lib/_chrome";
|
|
25
|
-
|
|
26
|
-
export const frontmatter = { title: "Home" };
|
|
27
|
-
|
|
28
|
-
export default function IndexPage(): JSX.Element {
|
|
29
|
-
const locale = routeContext.defaultLocale;
|
|
30
|
-
|
|
31
|
-
const { tree, categoryOrder, tagCount } = prepareHomeData(routeContext, locale);
|
|
32
|
-
|
|
33
|
-
return (
|
|
34
|
-
<HomePageView
|
|
35
|
-
locale={locale}
|
|
36
|
-
tree={tree}
|
|
37
|
-
categoryOrder={categoryOrder}
|
|
38
|
-
tagCount={tagCount}
|
|
39
|
-
/>
|
|
40
|
-
);
|
|
41
|
-
}
|
|
1
|
+
// Locked manifest (epic zudolab/zudo-doc#2651, Decision 4 on #2653): the home
|
|
2
|
+
// route is a 1-line re-export of the package-owned STATIC index route.
|
|
3
|
+
// Verified by the #2652 spike (Q2) to build, dev-render, and hydrate — a
|
|
4
|
+
// dynamic route (see pages/docs/[[...slug]].tsx) cannot use this form because
|
|
5
|
+
// `paths()` static-AST-extraction requires source, not compiled `dist/` JS.
|
|
6
|
+
export { default } from "@takazudo/zudo-doc/routes/index";
|