create-zudo-doc 0.2.21 → 0.2.22

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 (71) hide show
  1. package/dist/features/image-enlarge.d.ts +10 -2
  2. package/dist/features/image-enlarge.js +10 -2
  3. package/dist/scaffold.js +20 -22
  4. package/dist/zfb-config-gen.d.ts +16 -10
  5. package/dist/zfb-config-gen.js +34 -239
  6. package/package.json +1 -1
  7. package/templates/base/pages/lib/_body-end-islands.tsx +6 -13
  8. package/templates/base/pages/lib/_category-nav.tsx +30 -115
  9. package/templates/base/pages/lib/_category-tree-nav.tsx +38 -65
  10. package/templates/base/pages/lib/_compose-meta-title.ts +2 -6
  11. package/templates/base/pages/lib/_doc-body-end.tsx +3 -35
  12. package/templates/base/pages/lib/_doc-content-header.tsx +10 -111
  13. package/templates/base/pages/lib/_doc-history-area.tsx +19 -211
  14. package/templates/base/pages/lib/_doc-metainfo-area.tsx +10 -113
  15. package/templates/base/pages/lib/_doc-page-renderer.tsx +22 -183
  16. package/templates/base/pages/lib/_doc-page-shell.tsx +17 -251
  17. package/templates/base/pages/lib/_doc-pager.tsx +4 -74
  18. package/templates/base/pages/lib/_doc-route-entries.ts +43 -177
  19. package/templates/base/pages/lib/_doc-route-paths.ts +16 -101
  20. package/templates/base/pages/lib/_doc-tags-area.tsx +14 -77
  21. package/templates/base/pages/lib/_footer-with-defaults.tsx +37 -225
  22. package/templates/base/pages/lib/_frontmatter-preview-data.ts +5 -31
  23. package/templates/base/pages/lib/_head-with-defaults.tsx +13 -138
  24. package/templates/base/pages/lib/_header-with-defaults.tsx +24 -324
  25. package/templates/base/pages/lib/_inline-version-switcher.tsx +16 -78
  26. package/templates/base/pages/lib/_nav-data-prep.ts +32 -51
  27. package/templates/base/pages/lib/_nav-source-cache.ts +12 -57
  28. package/templates/base/pages/lib/_nav-source-docs.ts +33 -233
  29. package/templates/base/pages/lib/_search-widget-script.ts +2 -470
  30. package/templates/base/pages/lib/_search-widget.tsx +9 -195
  31. package/templates/base/pages/lib/_sidebar-prepaint.tsx +6 -59
  32. package/templates/base/pages/lib/_sidebar-with-defaults.tsx +16 -118
  33. package/templates/base/pages/lib/_site-tree-nav.tsx +29 -80
  34. package/templates/base/pages/lib/doc-page-props.ts +26 -44
  35. package/templates/base/pages/lib/locale-merge.ts +32 -145
  36. package/templates/base/pages/lib/route-enumerators.ts +52 -286
  37. package/templates/base/pages/robots.txt.tsx +2 -26
  38. package/templates/base/src/components/ai-chat-modal.tsx +9 -8
  39. package/templates/base/src/components/doc-history.tsx +9 -8
  40. package/templates/base/src/components/image-enlarge.tsx +11 -8
  41. package/templates/base/src/components/sidebar-toggle.tsx +6 -170
  42. package/templates/base/src/components/sidebar-tree.tsx +6 -548
  43. package/templates/base/src/components/site-tree-nav.tsx +6 -220
  44. package/templates/base/src/config/color-scheme-utils.ts +34 -158
  45. package/templates/base/src/config/i18n.ts +9 -0
  46. package/templates/base/src/config/z-index-tokens.ts +5 -4
  47. package/templates/base/src/styles/global.css +5 -579
  48. package/templates/base/src/utils/base.ts +1 -1
  49. package/templates/base/src/utils/docs.ts +47 -16
  50. package/templates/base/src/utils/github.ts +12 -9
  51. package/templates/base/src/utils/nav-scope.ts +13 -42
  52. package/templates/base/src/utils/sidebar.ts +18 -86
  53. package/templates/base/src/utils/slug.ts +10 -53
  54. package/templates/base/src/utils/smart-break.tsx +12 -120
  55. package/templates/base/src/utils/tags.ts +25 -68
  56. package/templates/features/bodyFootUtil/files/src/utils/github.ts +12 -9
  57. package/templates/features/designTokenPanel/files/src/lib/design-token-panel-bootstrap.ts +13 -39
  58. package/templates/features/docHistory/files/src/components/doc-history.tsx +8 -636
  59. package/templates/features/docHistory/files/src/types/doc-history.ts +7 -23
  60. package/templates/features/docTags/files/pages/lib/_tag-pages.tsx +35 -201
  61. package/templates/features/imageEnlarge/files/src/components/image-enlarge.tsx +8 -269
  62. package/templates/features/sidebarToggle/files/src/components/desktop-sidebar-toggle.tsx +6 -99
  63. package/templates/features/tagGovernance/files/scripts/tags-audit.ts +67 -515
  64. package/templates/features/versioning/files/pages/lib/_versions-page.tsx +21 -73
  65. package/templates/base/plugins/connect-adapter.mjs +0 -169
  66. package/templates/base/plugins/search-index-plugin.mjs +0 -66
  67. package/templates/base/scripts/gen-z-index.mjs +0 -157
  68. package/templates/base/src/components/mermaid-enlarge.tsx +0 -490
  69. package/templates/features/claudeResources/files/plugins/claude-resources-plugin.mjs +0 -47
  70. package/templates/features/docHistory/files/plugins/doc-history-plugin.mjs +0 -111
  71. package/templates/features/llmsTxt/files/plugins/llms-txt-plugin.mjs +0 -93
@@ -5,8 +5,9 @@ import type { FeatureModule } from "../compose.js";
5
5
  * W7A (#1736): post-cutover, the image-enlarge island is mounted by the
6
6
  * pages/lib body-end wrapper (always present; runtime-gated via the
7
7
  * always-loaded stub-or-real ImageEnlarge component). Image-enlarge CSS
8
- * lives unconditionally in `templates/base/src/styles/global.css` the
9
- * selectors only activate when the runtime mounts the .zd-enlarge-btn.
8
+ * lives unconditionally in `@takazudo/zudo-doc/features.css` (moved from
9
+ * `global.css` in S3 #2348) — the selectors only activate when the runtime
10
+ * mounts the .zd-enlarge-btn.
10
11
  *
11
12
  * S2 (#1825): after zfb next.18 removed the built-in imageEnlarge Rust
12
13
  * feature, the server-side figure/button emission is re-implemented via an
@@ -18,5 +19,12 @@ import type { FeatureModule } from "../compose.js";
18
19
  * When imageEnlarge is OFF, none of these are injected, so the override is
19
20
  * absent and paragraphs render plain (the Rust built-in is gone — "off" must
20
21
  * mean no wrapping at all).
22
+ *
23
+ * S3 (#2348): the ImageEnlarge island and its SSR fallback moved from
24
+ * src/components/image-enlarge.tsx into @takazudo/zudo-doc/image-enlarge.
25
+ * The pages/lib/_body-end-islands.tsx template now imports them from the
26
+ * package, so the local component file overlay was removed from
27
+ * templates/features/imageEnlarge/files/. No file-copy injections remain
28
+ * in this feature module — only _mdx-components.ts injections.
21
29
  */
22
30
  export declare const imageEnlargeFeature: FeatureModule;
@@ -4,8 +4,9 @@
4
4
  * W7A (#1736): post-cutover, the image-enlarge island is mounted by the
5
5
  * pages/lib body-end wrapper (always present; runtime-gated via the
6
6
  * always-loaded stub-or-real ImageEnlarge component). Image-enlarge CSS
7
- * lives unconditionally in `templates/base/src/styles/global.css` the
8
- * selectors only activate when the runtime mounts the .zd-enlarge-btn.
7
+ * lives unconditionally in `@takazudo/zudo-doc/features.css` (moved from
8
+ * `global.css` in S3 #2348) — the selectors only activate when the runtime
9
+ * mounts the .zd-enlarge-btn.
9
10
  *
10
11
  * S2 (#1825): after zfb next.18 removed the built-in imageEnlarge Rust
11
12
  * feature, the server-side figure/button emission is re-implemented via an
@@ -17,6 +18,13 @@
17
18
  * When imageEnlarge is OFF, none of these are injected, so the override is
18
19
  * absent and paragraphs render plain (the Rust built-in is gone — "off" must
19
20
  * mean no wrapping at all).
21
+ *
22
+ * S3 (#2348): the ImageEnlarge island and its SSR fallback moved from
23
+ * src/components/image-enlarge.tsx into @takazudo/zudo-doc/image-enlarge.
24
+ * The pages/lib/_body-end-islands.tsx template now imports them from the
25
+ * package, so the local component file overlay was removed from
26
+ * templates/features/imageEnlarge/files/. No file-copy injections remain
27
+ * in this feature module — only _mdx-components.ts injections.
20
28
  */
21
29
  export const imageEnlargeFeature = () => ({
22
30
  name: "imageEnlarge",
package/dist/scaffold.js CHANGED
@@ -448,11 +448,11 @@ function generatePackageJson(choices) {
448
448
  // stability, multi-valued response headers (e.g. multiple Set-Cookie),
449
449
  // supplementary-plane CJK reading-time, plus CLI/server/runtime hardening
450
450
  // and render perf passes. No consumer-facing / CLI breaking change.
451
- "@takazudo/zfb": "0.1.0-next.59",
452
- "@takazudo/zfb-runtime": "0.1.0-next.59",
451
+ "@takazudo/zfb": "0.1.0-next.62",
452
+ "@takazudo/zfb-runtime": "0.1.0-next.62",
453
453
  // zfb-adapter-cloudflare — required for any route with `prerender = false`.
454
454
  // Pinned in lockstep with @takazudo/zfb.
455
- "@takazudo/zfb-adapter-cloudflare": "0.1.0-next.59",
455
+ "@takazudo/zfb-adapter-cloudflare": "0.1.0-next.62",
456
456
  // @takazudo/zudo-doc — published from this monorepo via
457
457
  // .github/workflows/publish-zudo-doc.yml. The pin here is bumped in
458
458
  // lockstep by scripts/release-create-zudo-doc.sh whenever zudo-doc's
@@ -464,7 +464,7 @@ function generatePackageJson(choices) {
464
464
  // ties this pin to packages/zudo-doc's version, so the lockstep release
465
465
  // bumps both together; do not cut a create-zudo-doc release until the
466
466
  // matching @takazudo/zudo-doc version (with content.css) is on npm.
467
- "@takazudo/zudo-doc": "^0.2.21",
467
+ "@takazudo/zudo-doc": "^0.2.22",
468
468
  // zod — used by the generated zfb.config.ts. zfb-config-gen emits
469
469
  // `import { z } from "zod"` for the content-collection schema +
470
470
  // `z.toJSONSchema(...)` conversion. Without this dep, the consumer
@@ -514,27 +514,22 @@ function generatePackageJson(choices) {
514
514
  deps["diff"] = "^8.0.3";
515
515
  // @takazudo/zudo-doc has @takazudo/zudo-doc-history-server as an optional
516
516
  // peer dep. When docHistory is selected the zfb plugin
517
- // (plugins/doc-history-plugin.mjs) eagerly imports
517
+ // (@takazudo/zudo-doc/plugins/doc-history) eagerly imports
518
518
  // @takazudo/zudo-doc/integrations/doc-history which in turn imports
519
519
  // @takazudo/zudo-doc-history-server/git-history. Without this dep the
520
520
  // plugin host fails at init with ERR_MODULE_NOT_FOUND — W8A (#1739).
521
- deps["@takazudo/zudo-doc-history-server"] = "^0.2.21";
522
- // W7A (#1736): doc-history-plugin.mjs spawns `tsx -e <inline-script>` to
523
- // run the v2 runtime in a TS-aware Node subprocess; without tsx the
524
- // plugin's preBuild step exits with ENOENT before zfb finishes config
525
- // load.
526
- devDeps["tsx"] = "^4.21.0";
527
- }
528
- if (choices.features.includes("claudeResources")) {
529
- // W7A (#1736): claude-resources-plugin.mjs spawns `tsx -e <inline-script>`
530
- // for the same reason as doc-history (TS-aware Node subprocess wrapping
531
- // the v2 runner).
532
- devDeps["tsx"] = "^4.21.0";
521
+ deps["@takazudo/zudo-doc-history-server"] = "^0.2.22";
522
+ // tsx is no longer needed here: the relocated package plugin imports the
523
+ // runner directly (no `tsx -e` spawn) since the package ships compiled
524
+ // dist/ package-first migration #2321 (#2337).
533
525
  }
526
+ // claudeResources: tsx is no longer needed. The relocated package plugin
527
+ // (@takazudo/zudo-doc/plugins/claude-resources) imports the runner directly
528
+ // since the package ships compiled dist/ — package-first migration #2321 (#2337).
534
529
  if (choices.features.includes("designTokenPanel")) {
535
530
  // @takazudo/zdtp requires preact >= 10.29.1 — see the preact floor comment
536
531
  // above (~line 382) for why the floor is set there and the coupling this creates.
537
- deps["@takazudo/zdtp"] = "0.2.3";
532
+ deps["@takazudo/zdtp"] = "0.3.3";
538
533
  }
539
534
  if (choices.features.includes("tagGovernance")) {
540
535
  // gray-matter is already in `deps` unconditionally (base template uses it),
@@ -561,12 +556,15 @@ function generatePackageJson(choices) {
561
556
  // Z-index token codegen (#2148): regenerate the GENERATED:Z_INDEX @theme
562
557
  // block in src/styles/global.css from src/config/z-index-tokens.ts, and a
563
558
  // drift check for pre-push/CI. Both ship in base — the z-index token system
564
- // is part of every scaffold.
565
- "gen:z-index": "node scripts/gen-z-index.mjs",
566
- "check:z-index": "node scripts/gen-z-index.mjs --check",
559
+ // is part of every scaffold. Bin provided by @takazudo/zudo-doc (S9b #2334).
560
+ "gen:z-index": "gen-z-index",
561
+ "check:z-index": "gen-z-index --check",
567
562
  };
568
563
  if (choices.features.includes("tagGovernance")) {
569
- scripts["tags:audit"] = "tsx scripts/tags-audit.ts";
564
+ // tags-audit bin is provided by @takazudo/zudo-doc (S9b #2334);
565
+ // tsx is still required as a devDep because the bin's runner imports
566
+ // the project's TypeScript config files at runtime via tsx.
567
+ scripts["tags:audit"] = "tags-audit";
570
568
  scripts["tags:suggest"] = "tsx scripts/tags-suggest.ts";
571
569
  }
572
570
  if (choices.features.includes("skillSymlinker")) {
@@ -2,18 +2,24 @@ import type { UserChoices } from "./prompts.js";
2
2
  /**
3
3
  * Programmatically generate zfb.config.ts from user choices.
4
4
  *
5
- * W7A (#1736): emits zfb plugins in the host's INLINE-OBJECT shape
6
- * `{ name: "./plugins/<plugin>.mjs", options: {...} }` — not the
7
- * pre-cutover factory-import pattern (`import { fooPlugin } from
8
- * "./src/integrations/foo"`). Inline functions are not supported by zfb's
9
- * plugin runtime (see `@takazudo/zfb/plugins` source); plugins MUST be
10
- * authored as standalone `.mjs` modules referenced from `zfb.config.ts`
11
- * by `name`. The plugin source files are shipped by the base/feature
12
- * templates under `plugins/<plugin>.mjs` and `templates/features/<feature>/
13
- * files/plugins/<plugin>.mjs`.
5
+ * S5b (#2329): collapsed to the thin preset-based shape that mirrors the
6
+ * showcase `zfb.config.ts` after S5a. All collection wiring, plugin
7
+ * descriptors, markdown features, codeHighlight, resolveMarkdownLinks, and
8
+ * trailingSlash are now owned by `zudoDocPreset()` in
9
+ * `@takazudo/zudo-doc/preset`. The generated config spreads the preset
10
+ * result into `defineConfig` and keeps only the project-owned shell fields
11
+ * (`framework`, `port`, `tailwind`, `base`).
14
12
  *
15
13
  * Replaces the former astro-config-gen.ts + content-config-gen.ts pair.
16
14
  * In the zfb world, content-collection schemas live inside zfb.config.ts
17
15
  * itself — there is no separate content.config.ts.
16
+ *
17
+ * `_choices` is intentionally unused: post-S5b the emitted config is a
18
+ * CONSTANT. All feature variation is driven by `settings.*` (read at
19
+ * zfb-load time inside `zudoDocPreset()`), so the generated file is byte
20
+ * identical for every feature combination. The parameter is retained only
21
+ * for call-site compatibility (`scaffold.ts` passes `choices`). Do NOT add
22
+ * feature-gated branches here — wire new feature behaviour into
23
+ * `packages/zudo-doc/src/preset.ts` and the project's `settings.ts` instead.
18
24
  */
19
- export declare function generateZfbConfig(choices: UserChoices): string;
25
+ export declare function generateZfbConfig(_choices: UserChoices): string;
@@ -1,265 +1,60 @@
1
1
  /**
2
2
  * Programmatically generate zfb.config.ts from user choices.
3
3
  *
4
- * W7A (#1736): emits zfb plugins in the host's INLINE-OBJECT shape
5
- * `{ name: "./plugins/<plugin>.mjs", options: {...} }` — not the
6
- * pre-cutover factory-import pattern (`import { fooPlugin } from
7
- * "./src/integrations/foo"`). Inline functions are not supported by zfb's
8
- * plugin runtime (see `@takazudo/zfb/plugins` source); plugins MUST be
9
- * authored as standalone `.mjs` modules referenced from `zfb.config.ts`
10
- * by `name`. The plugin source files are shipped by the base/feature
11
- * templates under `plugins/<plugin>.mjs` and `templates/features/<feature>/
12
- * files/plugins/<plugin>.mjs`.
4
+ * S5b (#2329): collapsed to the thin preset-based shape that mirrors the
5
+ * showcase `zfb.config.ts` after S5a. All collection wiring, plugin
6
+ * descriptors, markdown features, codeHighlight, resolveMarkdownLinks, and
7
+ * trailingSlash are now owned by `zudoDocPreset()` in
8
+ * `@takazudo/zudo-doc/preset`. The generated config spreads the preset
9
+ * result into `defineConfig` and keeps only the project-owned shell fields
10
+ * (`framework`, `port`, `tailwind`, `base`).
13
11
  *
14
12
  * Replaces the former astro-config-gen.ts + content-config-gen.ts pair.
15
13
  * In the zfb world, content-collection schemas live inside zfb.config.ts
16
14
  * itself — there is no separate content.config.ts.
15
+ *
16
+ * `_choices` is intentionally unused: post-S5b the emitted config is a
17
+ * CONSTANT. All feature variation is driven by `settings.*` (read at
18
+ * zfb-load time inside `zudoDocPreset()`), so the generated file is byte
19
+ * identical for every feature combination. The parameter is retained only
20
+ * for call-site compatibility (`scaffold.ts` passes `choices`). Do NOT add
21
+ * feature-gated branches here — wire new feature behaviour into
22
+ * `packages/zudo-doc/src/preset.ts` and the project's `settings.ts` instead.
17
23
  */
18
- export function generateZfbConfig(choices) {
19
- const hasDocHistory = choices.features.includes("docHistory");
20
- const hasLlmsTxt = choices.features.includes("llmsTxt");
21
- const hasClaudeResources = choices.features.includes("claudeResources");
24
+ export function generateZfbConfig(_choices) {
22
25
  const lines = [];
23
26
  // --- Imports ---
24
- lines.push(`import { z } from "zod";`);
25
27
  lines.push(`import { defineConfig } from "zfb/config";`);
28
+ lines.push(`import { zudoDocPreset } from "@takazudo/zudo-doc/preset";`);
26
29
  lines.push(`import { settings } from "./src/config/settings";`);
27
30
  lines.push(`import { buildDocsSchema } from "./src/config/docs-schema";`);
28
31
  lines.push(``);
29
- // --- Schema definition — delegated to the single source of truth ---
30
- // buildDocsSchema() lives in src/config/docs-schema.ts and is shared by
31
- // pages/_data.ts (ZfbDocsData alias) and src/types/docs-entry.ts (DocsData).
32
- // tagGovernance projects: docs-schema.ts reads settings + tagVocabulary
33
- // internally, so the generated zfb.config.ts needs no extra import or
34
- // inline buildTagsSchema — the schema builder encapsulates all of that.
35
- lines.push(`const docsSchema = buildDocsSchema();`);
36
- lines.push(``);
37
- lines.push(`const docsSchemaJson = z.toJSONSchema(docsSchema) as Record<string, unknown>;`);
38
- lines.push(``);
39
- // --- Collection type ---
40
- lines.push(`interface CollectionEntryShape {`);
41
- lines.push(` name: string;`);
42
- lines.push(` path: string;`);
43
- lines.push(` schema: Record<string, unknown>;`);
44
- lines.push(`}`);
45
- lines.push(``);
46
- // --- Collections array ---
47
- lines.push(`const collections: CollectionEntryShape[] = [];`);
48
- lines.push(``);
49
- lines.push(`collections.push({ name: "docs", path: settings.docsDir, schema: docsSchemaJson });`);
50
- lines.push(``);
51
- // Locale collections — empty loop when locales is {} (i18n disabled).
52
- lines.push(`for (const [code, config] of Object.entries(settings.locales)) {`);
53
- lines.push(` collections.push({ name: \`docs-\${code}\`, path: config.dir, schema: docsSchemaJson });`);
54
- lines.push(`}`);
55
- lines.push(``);
56
- // Version collections — outer `if` short-circuits when versions is false.
57
- lines.push(`if (settings.versions) {`);
58
- lines.push(` for (const version of settings.versions) {`);
59
- lines.push(` collections.push({`);
60
- lines.push(` name: \`docs-v-\${version.slug}\`,`);
61
- lines.push(` path: version.docsDir,`);
62
- lines.push(` schema: docsSchemaJson,`);
63
- lines.push(` });`);
64
- lines.push(` if (version.locales) {`);
65
- lines.push(` for (const [code, config] of Object.entries(version.locales)) {`);
66
- lines.push(` collections.push({`);
67
- lines.push(` name: \`docs-v-\${version.slug}-\${code}\`,`);
68
- lines.push(` path: config.dir,`);
69
- lines.push(` schema: docsSchemaJson,`);
70
- lines.push(` });`);
71
- lines.push(` }`);
72
- lines.push(` }`);
73
- lines.push(` }`);
74
- lines.push(`}`);
75
- lines.push(``);
76
- // --- Locale helpers used by integrationPlugins (always emitted because
77
- // search-index + copy-public are always-on; locale-shaped data is
78
- // consumed by search-index even when there's only the default locale).
79
- lines.push(`const localeArray = Object.entries(settings.locales).map(([code, locale]) => ({`);
80
- lines.push(` code,`);
81
- lines.push(` dir: locale.dir,`);
82
- lines.push(`}));`);
83
- lines.push(`const localeRecord = Object.fromEntries(`);
84
- lines.push(` Object.entries(settings.locales).map(([code, locale]) => [code, { dir: locale.dir }]),`);
85
- lines.push(`);`);
86
- lines.push(``);
87
- // --- Plugins — inline-object shape matches host. Each entry's `name`
88
- // is a relative path to a `.mjs` plugin module shipped by the
89
- // base/feature templates. zfb's plugin runtime resolves the module
90
- // and dispatches lifecycle hooks (preBuild / postBuild / devMiddleware)
91
- // on its default export. ---
92
- lines.push(`const integrationPlugins = [`);
93
- if (hasClaudeResources) {
94
- lines.push(` ...(settings.claudeResources`);
95
- lines.push(` ? [`);
96
- lines.push(` {`);
97
- lines.push(` name: "./plugins/claude-resources-plugin.mjs",`);
98
- lines.push(` options: {`);
99
- lines.push(` claudeDir: settings.claudeResources.claudeDir,`);
100
- lines.push(` projectRoot: settings.claudeResources.projectRoot,`);
101
- lines.push(` docsDir: settings.docsDir,`);
102
- lines.push(` },`);
103
- lines.push(` },`);
104
- lines.push(` ]`);
105
- lines.push(` : []),`);
106
- }
107
- if (hasDocHistory) {
108
- lines.push(` ...(settings.docHistory`);
109
- lines.push(` ? [`);
110
- lines.push(` {`);
111
- lines.push(` name: "./plugins/doc-history-plugin.mjs",`);
112
- lines.push(` options: {`);
113
- lines.push(` docsDir: settings.docsDir,`);
114
- lines.push(` locales: localeRecord,`);
115
- lines.push(` base: settings.base,`);
116
- lines.push(` },`);
117
- lines.push(` },`);
118
- lines.push(` ]`);
119
- lines.push(` : []),`);
120
- }
121
- // search-index is always-on (matches host) — emits dist/search-index.json
122
- // even when no <Search /> widget mounts; ~few-KB cost is acceptable and
123
- // keeps the dev-middleware route registered for the always-mounted
124
- // search widget in pages/lib/_header-with-defaults.tsx.
125
- lines.push(` {`);
126
- lines.push(` name: "./plugins/search-index-plugin.mjs",`);
127
- lines.push(` options: {`);
128
- lines.push(` docsDir: settings.docsDir,`);
129
- lines.push(` locales: localeRecord,`);
130
- lines.push(` base: settings.base,`);
131
- lines.push(` },`);
132
- lines.push(` },`);
133
- if (hasLlmsTxt) {
134
- lines.push(` ...(settings.llmsTxt`);
135
- lines.push(` ? [`);
136
- lines.push(` {`);
137
- lines.push(` name: "./plugins/llms-txt-plugin.mjs",`);
138
- lines.push(` options: {`);
139
- lines.push(` siteName: settings.siteName,`);
140
- lines.push(` siteDescription: settings.siteDescription,`);
141
- lines.push(` base: settings.base,`);
142
- lines.push(` siteUrl: settings.siteUrl,`);
143
- lines.push(` defaultLocaleDir: settings.docsDir,`);
144
- lines.push(` locales: localeArray,`);
145
- lines.push(` },`);
146
- lines.push(` },`);
147
- lines.push(` ]`);
148
- lines.push(` : []),`);
149
- }
150
- // copy-public is always-on (matches host) — workaround for upstream zfb
151
- // gap where `zfb build` does not copy `public/` to dist/. Empty/missing
152
- // public/ is a no-op, so the cost to projects without public/ is zero.
153
- lines.push(` {`);
154
- lines.push(` name: "./plugins/copy-public-plugin.mjs",`);
155
- lines.push(` options: {`);
156
- lines.push(` publicDir: "public",`);
157
- lines.push(` },`);
158
- lines.push(` },`);
159
- lines.push(`];`);
32
+ // --- Directive vocabulary ---
33
+ // The seven canonical directives registered in pages/_mdx-components.ts.
34
+ // "details" routes to DetailsWrapper a collapsible, NOT an admonition.
35
+ lines.push(`const directiveVocabulary = {`);
36
+ lines.push(` note: "Note",`);
37
+ lines.push(` tip: "Tip",`);
38
+ lines.push(` info: "Info",`);
39
+ lines.push(` warning: "Warning",`);
40
+ lines.push(` danger: "Danger",`);
41
+ lines.push(` caution: "Caution",`);
42
+ lines.push(` details: "Details",`);
43
+ lines.push(`};`);
160
44
  lines.push(``);
161
45
  // --- Export ---
162
46
  lines.push(`export default defineConfig({`);
47
+ lines.push(` // ── Host-owned shell fields ──────────────────────────────────────────────`);
163
48
  lines.push(` framework: "preact",`);
164
49
  lines.push(` // Pin the dev/preview port — zfb defaults to 3000, but the generated`);
165
50
  lines.push(` // CLAUDE.md and the Tauri dev wrappers assume 4321.`);
166
51
  lines.push(` port: 4321,`);
167
52
  lines.push(` tailwind: { enabled: true },`);
168
- lines.push(` collections,`);
169
- lines.push(` stripMdExt: true,`);
170
- lines.push(` resolveMarkdownLinks: {`);
171
- lines.push(` enabled: true,`);
172
- lines.push(` dirs: [`);
173
- lines.push(` { dir: settings.docsDir, routePrefix: "/docs/" },`);
174
- lines.push(` ...Object.entries(settings.locales).map(([code, locale]) => ({`);
175
- lines.push(` dir: locale.dir,`);
176
- lines.push(` routePrefix: \`/\${code}/docs/\`,`);
177
- lines.push(` })),`);
178
- lines.push(` // Versioned collections: each version's EN dir + per-locale dirs.`);
179
- lines.push(` ...(settings.versions`);
180
- lines.push(` ? settings.versions.flatMap((version) => [`);
181
- lines.push(` { dir: version.docsDir, routePrefix: \`/v/\${version.slug}/docs/\` },`);
182
- lines.push(` ...Object.entries(version.locales ?? {}).map(([code, locale]) => ({`);
183
- lines.push(` dir: locale.dir,`);
184
- lines.push(` routePrefix: \`/v/\${version.slug}/\${code}/docs/\`,`);
185
- lines.push(` })),`);
186
- lines.push(` ])`);
187
- lines.push(` : []),`);
188
- lines.push(` ],`);
189
- lines.push(` onBrokenLinks: "warn",`);
190
- lines.push(` },`);
53
+ lines.push(` // Public URL prefix for <link rel="stylesheet"> and <script> tags.`);
191
54
  lines.push(` base: settings.base,`);
192
- lines.push(` trailingSlash: settings.trailingSlash,`);
193
- // codeHighlight — dual-theme syntect output so CSS can resolve tokens via
194
- // light-dark(var(--shiki-light), var(--shiki-dark)) and code blocks follow
195
- // the active light/dark toggle with no client JS. Theme names are syntect
196
- // built-ins shipped with zfb (not Shiki names). Matches the host config.
197
- lines.push(` codeHighlight: {`);
198
- lines.push(` themeLight: "base16-ocean.light",`);
199
- lines.push(` themeDark: "base16-ocean.dark",`);
200
- lines.push(` },`);
201
- // markdown.features block — mirrors the zfb next.13 opt-in model.
202
- //
203
- // Value-shape rule (empirically verified against the next.13 Rust loader):
204
- // object-typed features (githubAutolinks, codeEnrichment, imageDimensions,
205
- // linkValidation) REJECT the `true` shorthand and must be given an options
206
- // object (`{}` or fields). Boolean-OR-object features (githubAlerts,
207
- // readingTime, codeTabs, mermaid, headingMarkerToc) accept `true`.
208
- // (directives is object-typed — it takes a `name → component` map, not `true`.)
209
- // Note: imageEnlarge was formerly a Boolean-OR-object feature here, but
210
- // next.18 hard-removed it from the Rust config schema — it is now
211
- // re-implemented in userland via an MDX p-override in pages/_mdx-components.ts
212
- // (gated on settings.imageEnlarge). Do NOT add imageEnlarge back here.
213
- //
214
- // Intentionally omitted features (known-blocked at zfb next.13):
215
- // - tocExport: injects indented `export const toc = [...]` that MDX
216
- // parses as content, breaking esbuild with "Expected }" across the
217
- // whole corpus. Re-enable when the upstream Rust pass emits the
218
- // export at column 0. (Filed as zudolab/zudo-doc#1814.)
219
- // - ruby: the `^{...}` annotation syntax 500s the SSR render at next.13.
220
- // A registered stub cannot fix it — the error is inside zfb's Rust
221
- // ruby pass. Re-enable when the upstream crate is fixed. (#1815.)
222
- // - transclude: `:::include{file="..."}` 500s SSR (no registered
223
- // <include> renderer); `![[...]]` wikilink form is a no-op.
224
- // Re-enable when a transclude renderer is wired.
225
- //
226
- // githubAutolinks is omitted intentionally: the showcase hardcodes
227
- // `repo: "zudolab/zudo-doc"` but a scaffolded project belongs to a
228
- // different repo. Users can add `githubAutolinks: { repo: "owner/repo" }`
229
- // to their zfb.config.ts after scaffolding.
230
- lines.push(` markdown: {`);
231
- lines.push(` features: {`);
232
- lines.push(` // Former-Core features (were always-on before zfb next.12).`);
233
- lines.push(` // imageEnlarge was a former-Core feature but was hard-removed in zfb`);
234
- lines.push(` // next.18 — it is now re-implemented via an MDX p-override.`);
235
- lines.push(` // Admonitions recipe: register the :::name directive vocabulary`);
236
- lines.push(` // (note/tip/info/warning/danger/caution/details) → components.`);
237
- lines.push(` directives: {`);
238
- lines.push(` note: "Note",`);
239
- lines.push(` tip: "Tip",`);
240
- lines.push(` info: "Info",`);
241
- lines.push(` warning: "Warning",`);
242
- lines.push(` danger: "Danger",`);
243
- lines.push(` caution: "Caution",`);
244
- lines.push(` details: "Details", // collapsible — routes to DetailsWrapper`);
245
- lines.push(` },`);
246
- lines.push(` mermaid: true,`);
247
- lines.push(` headingMarkerToc: true,`);
248
- lines.push(` // Safe opt-in features.`);
249
- lines.push(` githubAlerts: true,`);
250
- lines.push(` readingTime: true,`);
251
- lines.push(` codeEnrichment: {},`);
252
- lines.push(` codeTabs: true,`);
253
- lines.push(` imageDimensions: {},`);
254
- lines.push(` // warn-only link validation — failOnBroken: false never fails the build.`);
255
- lines.push(` linkValidation: { failOnBroken: false },`);
256
- lines.push(` // Heading-ID (anchor) strategy — single source of truth in`);
257
- lines.push(` // settings.headingIdStrategy, also mirrored by the host TOC builder`);
258
- lines.push(` // (pages/lib/_extract-headings.ts) so TOC anchors match rendered ids.`);
259
- lines.push(` headingIds: { strategy: settings.headingIdStrategy },`);
260
- lines.push(` },`);
261
- lines.push(` },`);
262
- lines.push(` plugins: integrationPlugins,`);
55
+ lines.push(``);
56
+ lines.push(` // ── Preset-owned fields (content collections, plugins, markdown, …) ────────`);
57
+ lines.push(` ...zudoDocPreset({ settings, buildDocsSchema, directiveVocabulary }),`);
263
58
  lines.push(`});`);
264
59
  return lines.join("\n") + "\n";
265
60
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-zudo-doc",
3
- "version": "0.2.21",
3
+ "version": "0.2.22",
4
4
  "description": "Create a new zudo-doc documentation site",
5
5
  "license": "MIT",
6
6
  "author": "Takeshi Takatsudo",
@@ -32,21 +32,14 @@ import type { VNode, JSX } from "preact";
32
32
  import { Island } from "@takazudo/zfb";
33
33
  import { settings } from "@/config/settings";
34
34
 
35
- import AiChatModal from "@/components/ai-chat-modal";
36
- import ImageEnlarge, { ImageEnlargeSsrFallback } from "@/components/image-enlarge";
37
- import MermaidEnlarge, { MermaidEnlargeSsrFallback } from "@/components/mermaid-enlarge";
35
+ import { AiChatModal } from "@takazudo/zudo-doc/ai-chat-modal";
36
+ import { ImageEnlarge, ImageEnlargeSsrFallback } from "@takazudo/zudo-doc/image-enlarge";
37
+ import { MermaidEnlarge, MermaidEnlargeSsrFallback } from "@takazudo/zudo-doc/mermaid-enlarge";
38
38
  // @slot:body-end-islands:imports
39
39
 
40
- // Set explicit `displayName` on each default-exported island so zfb's
41
- // `captureComponentName` produces a stable marker even after the SSR
42
- // pipeline runs the components through a function-name-rewriting layer.
43
- // The marker must match the third-arg literal that zfb's scanner records
44
- // for the same source-level identifier (zfb PR #150). esbuild preserves
45
- // function names by default, but the explicit assignment is a
46
- // belt-and-braces guard for production minification regressions.
47
- (AiChatModal as { displayName?: string }).displayName = "AiChatModal";
48
- (ImageEnlarge as { displayName?: string }).displayName = "ImageEnlarge";
49
- (MermaidEnlarge as { displayName?: string }).displayName = "MermaidEnlarge";
40
+ // AiChatModal, ImageEnlarge, MermaidEnlarge pin displayName internally in the
41
+ // package. Optional feature islands that still need explicit call-site pinning
42
+ // inject their displayName assignment at the slot below only when selected.
50
43
  // @slot:body-end-islands:display-names
51
44
 
52
45
  /**