@takazudo/zudo-doc 2.5.1 → 3.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 (43) hide show
  1. package/CHANGELOG.md +1038 -0
  2. package/README.md +4 -0
  3. package/dist/chrome/derive.d.ts +4 -1
  4. package/dist/chrome/derive.js +30 -25
  5. package/dist/color-scheme-utils.d.ts +153 -102
  6. package/dist/color-scheme-utils.js +168 -97
  7. package/dist/content.css +5 -5
  8. package/dist/design-token-panel-bootstrap.d.ts +37 -16
  9. package/dist/design-token-panel-bootstrap.js +47 -19
  10. package/dist/doc-page-renderer/index.d.ts +1 -0
  11. package/dist/doc-page-renderer/index.js +2 -0
  12. package/dist/doc-page-shell/index.d.ts +2 -0
  13. package/dist/doc-page-shell/index.js +2 -0
  14. package/dist/doclayout/doc-layout.d.ts +9 -0
  15. package/dist/doclayout/doc-layout.js +2 -0
  16. package/dist/features.css +19 -0
  17. package/dist/home-page/index.d.ts +8 -0
  18. package/dist/home-page/index.js +3 -1
  19. package/dist/integrations/changelog/emit.d.ts +2 -0
  20. package/dist/integrations/changelog/emit.js +24 -0
  21. package/dist/integrations/changelog/generate.d.ts +2 -0
  22. package/dist/integrations/changelog/generate.js +24 -0
  23. package/dist/integrations/changelog/index.d.ts +5 -0
  24. package/dist/integrations/changelog/index.js +11 -0
  25. package/dist/integrations/changelog/load.d.ts +3 -0
  26. package/dist/integrations/changelog/load.js +79 -0
  27. package/dist/integrations/changelog/sanitize.d.ts +10 -0
  28. package/dist/integrations/changelog/sanitize.js +24 -0
  29. package/dist/integrations/changelog/types.d.ts +31 -0
  30. package/dist/integrations/changelog/types.js +0 -0
  31. package/dist/plugins/changelog.d.ts +3 -0
  32. package/dist/plugins/changelog.js +17 -0
  33. package/dist/preset.d.ts +7 -0
  34. package/dist/preset.js +8 -0
  35. package/dist/safelist.css +1 -1
  36. package/dist/settings.d.ts +11 -0
  37. package/dist/theme/design-token-serde.d.ts +74 -33
  38. package/dist/theme/design-token-serde.js +187 -94
  39. package/dist/theme/design-token-types.d.ts +6 -10
  40. package/dist/theme/index.d.ts +1 -1
  41. package/dist/theme-toggle/color-scheme-sync.d.ts +22 -12
  42. package/eject/theme-toggle/color-scheme-sync.ts +22 -12
  43. package/package.json +18 -9
@@ -1,27 +1,58 @@
1
- const SEMANTIC_DEFAULTS = {
2
- surface: 0,
3
- muted: 8,
4
- accent: 5,
5
- accentHover: 14,
6
- codeBg: 10,
7
- codeFg: 11,
8
- success: 2,
9
- danger: 1,
10
- warning: 3,
11
- info: 4,
12
- mermaidNodeBg: 9,
13
- mermaidText: 11,
14
- mermaidLine: 8,
15
- mermaidLabelBg: 10,
16
- mermaidNoteBg: 0,
17
- chatUserBg: 5,
18
- chatUserText: 9,
19
- chatAssistantBg: 9,
20
- chatAssistantText: 11,
21
- imageOverlayBg: 0,
22
- imageOverlayFg: 11,
23
- matchedKeywordBg: 3,
24
- matchedKeywordFg: 15
1
+ const STATE_ROLES = ["danger", "success", "warning", "info"];
2
+ const SEMANTIC_KEYS = [
3
+ "surface",
4
+ "muted",
5
+ "accent",
6
+ "accentHover",
7
+ "codeBg",
8
+ "codeFg",
9
+ "success",
10
+ "danger",
11
+ "warning",
12
+ "info",
13
+ "mermaidNodeBg",
14
+ "mermaidText",
15
+ "mermaidLine",
16
+ "mermaidLabelBg",
17
+ "mermaidNoteBg",
18
+ "chatUserBg",
19
+ "chatUserText",
20
+ "chatAssistantBg",
21
+ "chatAssistantText",
22
+ "imageOverlayBg",
23
+ "imageOverlayFg",
24
+ "matchedKeywordBg",
25
+ "matchedKeywordFg"
26
+ ];
27
+ const SEMANTIC_RAMP_DEFAULTS = {
28
+ // Re-pointed for the 5-base / 3-accent minimized ramp (#2602); mirrors the
29
+ // Default Dark reference wiring (surface/chatAssistantBg/imageOverlayBg merged
30
+ // onto bg=b4). Every index is < 5 (base) / < 3 (accent).
31
+ surface: { base: 4 },
32
+ muted: { base: 1 },
33
+ accent: { accent: 1 },
34
+ accentHover: { accent: 0 },
35
+ codeBg: { base: 3 },
36
+ codeFg: { base: 0 },
37
+ success: { state: "success" },
38
+ danger: { state: "danger" },
39
+ warning: { state: "warning" },
40
+ info: { state: "info" },
41
+ mermaidNodeBg: { base: 3 },
42
+ mermaidText: { base: 0 },
43
+ mermaidLine: { base: 1 },
44
+ mermaidLabelBg: { base: 3 },
45
+ mermaidNoteBg: { base: 2 },
46
+ chatUserBg: { accent: 1 },
47
+ chatUserText: { base: 4 },
48
+ chatAssistantBg: { base: 4 },
49
+ chatAssistantText: { base: 0 },
50
+ imageOverlayBg: { base: 4 },
51
+ imageOverlayFg: { base: 0 },
52
+ // Search-result <mark> highlight — amber fill with dark text (the classic
53
+ // highlighter look, matching the shipped schemes). Kept as raw OKLCH literals.
54
+ matchedKeywordBg: "oklch(0.700 0.158 62)",
55
+ matchedKeywordFg: "oklch(0.300 0.003 65)"
25
56
  };
26
57
  const SEMANTIC_CSS_NAMES = {
27
58
  surface: "--zd-surface",
@@ -48,74 +79,106 @@ const SEMANTIC_CSS_NAMES = {
48
79
  matchedKeywordBg: "--zd-matched-keyword-bg",
49
80
  matchedKeywordFg: "--zd-matched-keyword-fg"
50
81
  };
51
- function resolveColor(value, palette, fallback) {
52
- if (value === void 0) return fallback;
53
- if (typeof value === "number") return palette[value] ?? fallback;
54
- return value;
82
+ function resolveRampRef(ref, ramps) {
83
+ if (typeof ref === "string") return ref;
84
+ if ("base" in ref) {
85
+ const color = ramps.base[ref.base];
86
+ if (color === void 0) {
87
+ throw new RangeError(`RampRef {base:${ref.base}} out of range (base ramp has ${ramps.base.length} stops)`);
88
+ }
89
+ return color;
90
+ }
91
+ if ("accent" in ref) {
92
+ const color = ramps.accent[ref.accent];
93
+ if (color === void 0) {
94
+ throw new RangeError(`RampRef {accent:${ref.accent}} out of range (accent ramp has ${ramps.accent.length} stops)`);
95
+ }
96
+ return color;
97
+ }
98
+ return ramps.state[ref.state];
55
99
  }
56
100
  function resolveSemanticColors(scheme) {
57
- const p = scheme.palette;
58
- return {
59
- surface: resolveColor(scheme.semantic?.surface, p, p[0]),
60
- muted: resolveColor(scheme.semantic?.muted, p, p[8]),
61
- accent: resolveColor(scheme.semantic?.accent, p, p[5]),
62
- accentHover: resolveColor(scheme.semantic?.accentHover, p, p[14]),
63
- codeBg: resolveColor(scheme.semantic?.codeBg, p, p[10]),
64
- codeFg: resolveColor(scheme.semantic?.codeFg, p, p[11]),
65
- success: resolveColor(scheme.semantic?.success, p, p[2]),
66
- danger: resolveColor(scheme.semantic?.danger, p, p[1]),
67
- warning: resolveColor(scheme.semantic?.warning, p, p[3]),
68
- info: resolveColor(scheme.semantic?.info, p, p[4]),
69
- mermaidNodeBg: resolveColor(scheme.semantic?.mermaidNodeBg, p, p[9]),
70
- mermaidText: resolveColor(scheme.semantic?.mermaidText, p, p[11]),
71
- mermaidLine: resolveColor(scheme.semantic?.mermaidLine, p, p[8]),
72
- mermaidLabelBg: resolveColor(scheme.semantic?.mermaidLabelBg, p, p[10]),
73
- mermaidNoteBg: resolveColor(scheme.semantic?.mermaidNoteBg, p, p[0]),
74
- chatUserBg: resolveColor(scheme.semantic?.chatUserBg, p, p[5]),
75
- chatUserText: resolveColor(scheme.semantic?.chatUserText, p, p[9]),
76
- chatAssistantBg: resolveColor(scheme.semantic?.chatAssistantBg, p, p[9]),
77
- chatAssistantText: resolveColor(scheme.semantic?.chatAssistantText, p, p[11]),
78
- imageOverlayBg: resolveColor(scheme.semantic?.imageOverlayBg, p, p[0]),
79
- imageOverlayFg: resolveColor(scheme.semantic?.imageOverlayFg, p, p[11]),
80
- matchedKeywordBg: resolveColor(scheme.semantic?.matchedKeywordBg, p, p[3]),
81
- matchedKeywordFg: resolveColor(scheme.semantic?.matchedKeywordFg, p, p[15])
82
- };
101
+ const { ramps, map } = scheme;
102
+ const out = {};
103
+ for (const key of SEMANTIC_KEYS) {
104
+ out[key] = resolveRampRef(map.semantic[key], ramps);
105
+ }
106
+ return out;
83
107
  }
84
- function schemeToCssPairs(scheme) {
85
- const p = scheme.palette;
86
- const sem = resolveSemanticColors(scheme);
87
- return [
88
- ["--zd-bg", resolveColor(scheme.background, p, p[0])],
89
- ["--zd-fg", resolveColor(scheme.foreground, p, p[15])],
90
- ["--zd-cursor", resolveColor(scheme.cursor, p, p[6])],
91
- // intentionally inert/vestigial: exposed in the design-token panel but no CSS rule consumes it (no caret-color wiring); mirrors shikiTheme's status
92
- ["--zd-sel-bg", resolveColor(scheme.selectionBg, p, resolveColor(scheme.background, p, p[0]))],
93
- ["--zd-sel-fg", resolveColor(scheme.selectionFg, p, resolveColor(scheme.foreground, p, p[15]))],
94
- ...p.map((color, i) => [`--zd-${i}`, color]),
95
- ["--zd-surface", sem.surface],
96
- ["--zd-muted", sem.muted],
97
- ["--zd-accent", sem.accent],
98
- ["--zd-accent-hover", sem.accentHover],
99
- ["--zd-code-bg", sem.codeBg],
100
- ["--zd-code-fg", sem.codeFg],
101
- ["--zd-success", sem.success],
102
- ["--zd-danger", sem.danger],
103
- ["--zd-warning", sem.warning],
104
- ["--zd-info", sem.info],
105
- ["--zd-mermaid-node-bg", sem.mermaidNodeBg],
106
- ["--zd-mermaid-text", sem.mermaidText],
107
- ["--zd-mermaid-line", sem.mermaidLine],
108
- ["--zd-mermaid-label-bg", sem.mermaidLabelBg],
109
- ["--zd-mermaid-note-bg", sem.mermaidNoteBg],
110
- ["--zd-chat-user-bg", sem.chatUserBg],
111
- ["--zd-chat-user-text", sem.chatUserText],
112
- ["--zd-chat-assistant-bg", sem.chatAssistantBg],
113
- ["--zd-chat-assistant-text", sem.chatAssistantText],
114
- ["--zd-image-overlay-bg", sem.imageOverlayBg],
115
- ["--zd-image-overlay-fg", sem.imageOverlayFg],
116
- ["--zd-matched-keyword-bg", sem.matchedKeywordBg],
117
- ["--zd-matched-keyword-fg", sem.matchedKeywordFg]
108
+ function rampRefToPanelDefault(ref) {
109
+ if (typeof ref === "string") return ref;
110
+ if ("base" in ref) return `base:base-${ref.base}`;
111
+ if ("accent" in ref) return `accent:accent-${ref.accent}`;
112
+ return `state:state-${ref.state}`;
113
+ }
114
+ function buildSemanticTierItems(scheme) {
115
+ const { map } = scheme;
116
+ const items = [
117
+ {
118
+ id: "bg",
119
+ cssVar: "--zd-bg",
120
+ label: "bg",
121
+ default: rampRefToPanelDefault(map.bg),
122
+ type: { kind: "color", format: "oklch" }
123
+ },
124
+ {
125
+ id: "fg",
126
+ cssVar: "--zd-fg",
127
+ label: "fg",
128
+ default: rampRefToPanelDefault(map.fg),
129
+ type: { kind: "color", format: "oklch" }
130
+ },
131
+ {
132
+ id: "selection-bg",
133
+ cssVar: "--zd-selection-bg",
134
+ label: "selection-bg",
135
+ default: rampRefToPanelDefault(map.selectionBg),
136
+ type: { kind: "color", format: "oklch" }
137
+ },
138
+ {
139
+ id: "selection-fg",
140
+ cssVar: "--zd-selection-fg",
141
+ label: "selection-fg",
142
+ default: rampRefToPanelDefault(map.selectionFg),
143
+ type: { kind: "color", format: "oklch" }
144
+ }
118
145
  ];
146
+ for (const key of SEMANTIC_KEYS) {
147
+ items.push({
148
+ id: key,
149
+ cssVar: SEMANTIC_CSS_NAMES[key],
150
+ label: key,
151
+ default: rampRefToPanelDefault(map.semantic[key]),
152
+ type: { kind: "color", format: "oklch" }
153
+ });
154
+ }
155
+ return items;
156
+ }
157
+ function schemeToCssPairs(scheme, scope = "all") {
158
+ const { ramps, map } = scheme;
159
+ const pairs = [];
160
+ if (scope === "all" || scope === "roles") {
161
+ pairs.push(
162
+ ["--zd-bg", resolveRampRef(map.bg, ramps)],
163
+ ["--zd-fg", resolveRampRef(map.fg, ramps)],
164
+ ["--zd-selection-bg", resolveRampRef(map.selectionBg, ramps)],
165
+ ["--zd-selection-fg", resolveRampRef(map.selectionFg, ramps)]
166
+ );
167
+ }
168
+ if (scope === "all" || scope === "palette") {
169
+ ramps.base.forEach((color, i) => pairs.push([`--palette-base-${i}`, color]));
170
+ ramps.accent.forEach((color, i) => pairs.push([`--palette-accent-${i}`, color]));
171
+ for (const role of STATE_ROLES) {
172
+ pairs.push([`--palette-state-${role}`, ramps.state[role]]);
173
+ }
174
+ }
175
+ if (scope === "all" || scope === "roles") {
176
+ const sem = resolveSemanticColors(scheme);
177
+ for (const key of SEMANTIC_KEYS) {
178
+ pairs.push([SEMANTIC_CSS_NAMES[key], sem[key]]);
179
+ }
180
+ }
181
+ return pairs;
119
182
  }
120
183
  function generateCssCustomProperties(scheme) {
121
184
  const pairs = schemeToCssPairs(scheme);
@@ -123,15 +186,19 @@ function generateCssCustomProperties(scheme) {
123
186
  return lines.join("\n");
124
187
  }
125
188
  function generateLightDarkCssProperties(light, dark) {
126
- const lightPairs = schemeToCssPairs(light);
127
- const darkPairs = schemeToCssPairs(dark);
128
- if (lightPairs.length !== darkPairs.length) {
129
- throw new Error(`Light scheme has ${lightPairs.length} properties but dark scheme has ${darkPairs.length}`);
189
+ const palettePairs = schemeToCssPairs(light, "palette");
190
+ const lightRoles = schemeToCssPairs(light, "roles");
191
+ const darkRoles = schemeToCssPairs(dark, "roles");
192
+ if (lightRoles.length !== darkRoles.length) {
193
+ throw new Error(`Light scheme has ${lightRoles.length} role properties but dark scheme has ${darkRoles.length}`);
130
194
  }
131
195
  const lines = [":root {", " color-scheme: light dark;"];
132
- for (let i = 0; i < lightPairs.length; i++) {
133
- const lightPair = lightPairs[i];
134
- const darkPair = darkPairs[i];
196
+ for (const [prop, value] of palettePairs) {
197
+ lines.push(` ${prop}: ${value};`);
198
+ }
199
+ for (let i = 0; i < lightRoles.length; i++) {
200
+ const lightPair = lightRoles[i];
201
+ const darkPair = darkRoles[i];
135
202
  if (!lightPair || !darkPair) continue;
136
203
  const [prop, lightVal] = lightPair;
137
204
  const darkVal = darkPair[1];
@@ -142,10 +209,14 @@ function generateLightDarkCssProperties(light, dark) {
142
209
  }
143
210
  export {
144
211
  SEMANTIC_CSS_NAMES,
145
- SEMANTIC_DEFAULTS,
212
+ SEMANTIC_KEYS,
213
+ SEMANTIC_RAMP_DEFAULTS,
214
+ STATE_ROLES,
215
+ buildSemanticTierItems,
146
216
  generateCssCustomProperties,
147
217
  generateLightDarkCssProperties,
148
- resolveColor,
218
+ rampRefToPanelDefault,
219
+ resolveRampRef,
149
220
  resolveSemanticColors,
150
221
  schemeToCssPairs
151
222
  };
package/dist/content.css CHANGED
@@ -28,7 +28,7 @@
28
28
  * 2. DESIGN TOKENS — the consumer's `@theme` MUST define every custom property
29
29
  * consumed below:
30
30
  * --color-{fg,bg,muted,accent,accent-hover,code-bg,code-fg,info,success,
31
- * warning,danger,p5}
31
+ * warning,danger}
32
32
  * --spacing-{vsp-2xs,vsp-xs,vsp-sm,vsp-md,vsp-lg,vsp-xl,vsp-2xl,
33
33
  * hsp-2xs,hsp-xs,hsp-sm,hsp-md,hsp-lg,hsp-xl}
34
34
  * --text-{body,small} --font-mono --font-weight-{medium,semibold}
@@ -405,16 +405,16 @@
405
405
  content: "🚨";
406
406
  }
407
407
 
408
- /* github-alerts [!IMPORTANT] → magenta/accent-adjacent (p5 = magenta palette slot) */
408
+ /* github-alerts [!IMPORTANT] → shares the orange accent (--color-accent --zd-accent accent ramp); ❗ icon differentiates it from other admonitions */
409
409
  [data-admonition="important"],
410
410
  .admonition-important {
411
- border-left-color: var(--color-p5);
412
- background-color: color-mix(in srgb, var(--color-p5) 12%, var(--color-bg));
411
+ border-left-color: var(--color-accent);
412
+ background-color: color-mix(in srgb, var(--color-accent) 12%, var(--color-bg));
413
413
  }
414
414
 
415
415
  [data-admonition="important"] .admonition-title,
416
416
  .admonition-important .admonition-title {
417
- color: var(--color-p5);
417
+ color: var(--color-accent);
418
418
  }
419
419
 
420
420
  [data-admonition="important"] .admonition-title::before,
@@ -1,20 +1,28 @@
1
1
  /**
2
2
  * Design-token panel (zdtp) WIRING MECHANISM.
3
3
  *
4
- * A side-effect module that calls `configurePanel(panelConfig)` and wires
5
- * zdtp's lifecycle hooks to zfb's navigation events via
6
- * `setLifecycleAdapter()`. Projects import this with their own
7
- * `designTokenPanelConfig` object — the DATA stays project-side.
4
+ * A side-effect module that configures zdtp's panel and wires its lifecycle
5
+ * hooks to zfb's navigation events via `setLifecycleAdapter()`. Projects import
6
+ * this with their own PanelConfig DATA — which stays project-side.
8
7
  *
9
- * Usage (project-side `src/lib/design-token-panel-bootstrap.ts`):
8
+ * Two calling shapes (both supported):
10
9
  *
10
+ * // Mode-scoped builder (showcase host) — rebuilds the panel per light/dark
11
+ * // mode on every `color-scheme-changed` toggle:
11
12
  * import { bootstrapDesignTokenPanel } from "@takazudo/zudo-doc/design-token-panel-bootstrap";
13
+ * import { buildDesignTokenPanelConfig } from "@/config/design-token-panel-config";
14
+ * bootstrapDesignTokenPanel(buildDesignTokenPanelConfig);
15
+ *
16
+ * // Plain config (back-compat — generated projects on the old shape):
12
17
  * import { designTokenPanelConfig } from "@/config/design-token-panel-config";
13
18
  * bootstrapDesignTokenPanel(designTokenPanelConfig);
14
19
  *
20
+ * A plain-config caller gets NO toggle listener (a static config has nothing to
21
+ * rebuild), so existing generated projects keep working with zero changes.
22
+ *
15
23
  * Moved from the host's `src/lib/design-token-panel-bootstrap.ts` as part of
16
- * the package-first migration (S9a zudolab/zudo-doc#2333). The PanelConfig
17
- * DATA stays project-side.
24
+ * the package-first migration (S9a zudolab/zudo-doc#2333); mode-scoped rebuild
25
+ * wiring added in zudolab/zudo-doc#2610.
18
26
  *
19
27
  * CSS is pulled via `@import "@takazudo/zdtp/styles.css"` in the project's
20
28
  * `src/styles/global.css` so the panel chrome lands in the main page CSS
@@ -23,16 +31,29 @@
23
31
  * required pull point. See @takazudo/zdtp PORTABLE-CONTRACT.md §7.
24
32
  */
25
33
  import { type PanelConfig } from "@takazudo/zdtp";
34
+ /** Active color-scheme mode, read from `<html data-theme>`. */
35
+ type ColorSchemeMode = "light" | "dark";
26
36
  /**
27
- * Bootstrap zdtp for a project. Calls `configurePanel(panelConfig)`,
28
- * drains any pre-hydration click queue, and wires the zdtp lifecycle
29
- * adapter to zfb's navigation events so persisted token overrides are
30
- * re-applied on every soft navigation.
37
+ * A per-mode PanelConfig factory. Supplied by hosts that want the panel's
38
+ * defaults to follow the live light/dark mode (see `buildDesignTokenPanelConfig`
39
+ * in the host's `design-token-panel-config.ts`).
40
+ */
41
+ export type PanelConfigBuilder = (mode: ColorSchemeMode) => PanelConfig;
42
+ /**
43
+ * Bootstrap zdtp for a project. Configures the panel, drains any pre-hydration
44
+ * click queue, and wires the zdtp lifecycle adapter to zfb's navigation events
45
+ * so persisted token overrides re-apply on every soft navigation.
46
+ *
47
+ * When passed a `PanelConfigBuilder`, also wires a `color-scheme-changed`
48
+ * listener that rebuilds the panel per light/dark mode (see the toggle sequence
49
+ * below). When passed a plain `PanelConfig`, no toggle listener is registered.
31
50
  *
32
- * Call this once, as a side-effect import from the project's island
33
- * wrapper (`src/components/design-token-panel-bootstrap.tsx`).
51
+ * Call this once, as a side-effect import from the project's island wrapper
52
+ * (`src/components/design-token-panel-bootstrap.tsx`).
34
53
  *
35
- * @param panelConfig - The project's `PanelConfig` object (data stays
36
- * project-side in `src/config/design-token-panel-config.ts`).
54
+ * @param configOrBuilder - The project's `PanelConfig`, or a `(mode) =>
55
+ * PanelConfig` builder for mode-scoped rebuilds. DATA stays project-side in
56
+ * `src/config/design-token-panel-config.ts`.
37
57
  */
38
- export declare function bootstrapDesignTokenPanel(panelConfig: PanelConfig): void;
58
+ export declare function bootstrapDesignTokenPanel(configOrBuilder: PanelConfig | PanelConfigBuilder): void;
59
+ export {};
@@ -1,28 +1,56 @@
1
- import { configurePanel, setLifecycleAdapter } from "@takazudo/zdtp";
1
+ import {
2
+ configurePanel,
3
+ setLifecycleAdapter,
4
+ showDesignTokenPanel
5
+ } from "@takazudo/zdtp";
2
6
  import {
3
7
  BEFORE_NAVIGATE_EVENT,
4
8
  AFTER_NAVIGATE_EVENT
5
9
  } from "./transitions/page-events.js";
6
- function bootstrapDesignTokenPanel(panelConfig) {
7
- configurePanel(panelConfig);
8
- if (typeof window !== "undefined") {
9
- window.__zdtpReadyClicks?.();
10
+ const COLOR_SCHEME_CHANGED_EVENT = "color-scheme-changed";
11
+ function openStateKey(instancePrefix) {
12
+ return `${instancePrefix}-open`;
13
+ }
14
+ function readMode() {
15
+ return document.documentElement.getAttribute("data-theme") === "dark" ? "dark" : "light";
16
+ }
17
+ function bootstrapDesignTokenPanel(configOrBuilder) {
18
+ if (typeof window === "undefined" || typeof document === "undefined") {
19
+ return;
10
20
  }
11
- if (typeof document !== "undefined") {
12
- const adapter = {
13
- onBeforeSwap(cb) {
14
- const handler = () => cb();
15
- document.addEventListener(BEFORE_NAVIGATE_EVENT, handler);
16
- return () => document.removeEventListener(BEFORE_NAVIGATE_EVENT, handler);
17
- },
18
- onPageLoad(cb) {
19
- const handler = () => cb();
20
- document.addEventListener(AFTER_NAVIGATE_EVENT, handler);
21
- return () => document.removeEventListener(AFTER_NAVIGATE_EVENT, handler);
22
- }
23
- };
24
- setLifecycleAdapter(adapter);
21
+ const isBuilder = typeof configOrBuilder === "function";
22
+ const builder = isBuilder ? configOrBuilder : () => configOrBuilder;
23
+ let handle = configurePanel(builder(readMode()));
24
+ if (isBuilder) {
25
+ let pendingMode = readMode();
26
+ let timer = null;
27
+ window.addEventListener(COLOR_SCHEME_CHANGED_EVENT, () => {
28
+ pendingMode = readMode();
29
+ if (timer !== null) return;
30
+ timer = setTimeout(() => {
31
+ timer = null;
32
+ const mode = pendingMode;
33
+ const wasOpen = localStorage.getItem(openStateKey(handle.instanceId)) === "1";
34
+ handle.destroy();
35
+ handle = configurePanel(builder(mode));
36
+ if (wasOpen) showDesignTokenPanel();
37
+ }, 0);
38
+ });
25
39
  }
40
+ window.__zdtpReadyClicks?.();
41
+ const adapter = {
42
+ onBeforeSwap(cb) {
43
+ const handler = () => cb();
44
+ document.addEventListener(BEFORE_NAVIGATE_EVENT, handler);
45
+ return () => document.removeEventListener(BEFORE_NAVIGATE_EVENT, handler);
46
+ },
47
+ onPageLoad(cb) {
48
+ const handler = () => cb();
49
+ document.addEventListener(AFTER_NAVIGATE_EVENT, handler);
50
+ return () => document.removeEventListener(AFTER_NAVIGATE_EVENT, handler);
51
+ }
52
+ };
53
+ setLifecycleAdapter(adapter);
26
54
  }
27
55
  export {
28
56
  bootstrapDesignTokenPanel
@@ -82,6 +82,7 @@ export interface DocPageRendererDeps {
82
82
  sidebarPersistKey: string | undefined;
83
83
  hideSidebar?: boolean;
84
84
  hideToc?: boolean;
85
+ contentWide?: boolean;
85
86
  currentPath: string;
86
87
  currentVersion?: string;
87
88
  versionSwitcher: JSX.Element | undefined;
@@ -47,6 +47,7 @@ function createRenderDocPage(ctx) {
47
47
  const standalone = entryData?.standalone;
48
48
  const hideSidebar = entryData ? entryData.hide_sidebar || standalone : void 0;
49
49
  const hideToc = entryData ? entryData.hide_toc || standalone : void 0;
50
+ const contentWide = entryData ? entryData.wide : void 0;
50
51
  const sidebarPersistKey = hideSidebar ? void 0 : `sidebar-${locale}-${navSection ?? "default"}`;
51
52
  const ContentComponent = props.kind === "entry" ? props.entry.Content : null;
52
53
  return /* @__PURE__ */ jsx(
@@ -66,6 +67,7 @@ function createRenderDocPage(ctx) {
66
67
  sidebarPersistKey,
67
68
  hideSidebar,
68
69
  hideToc,
70
+ contentWide,
69
71
  currentPath,
70
72
  currentVersion: version?.slug,
71
73
  versionSwitcher: buildInlineVersionSwitcher(slug, locale, version?.slug),
@@ -52,6 +52,8 @@ export interface DocPageShellProps {
52
52
  hideSidebar?: boolean;
53
53
  /** Whether to hide the TOC (entry frontmatter). */
54
54
  hideToc?: boolean;
55
+ /** Whether to widen the content band to the wide layout (entry frontmatter `wide`). */
56
+ contentWide?: boolean;
55
57
  /** Path of THIS page used by Header/Sidebar to mark the active item. */
56
58
  currentPath: string;
57
59
  /** Version slug for Header/Sidebar active-state, or undefined on latest routes. */
@@ -50,6 +50,7 @@ function createDocPageShell(ctx) {
50
50
  sidebarPersistKey,
51
51
  hideSidebar,
52
52
  hideToc,
53
+ contentWide,
53
54
  currentPath,
54
55
  currentVersion,
55
56
  versionSwitcher,
@@ -86,6 +87,7 @@ function createDocPageShell(ctx) {
86
87
  noindex: settings.noindex,
87
88
  hideSidebar,
88
89
  hideToc,
90
+ contentWide,
89
91
  headings,
90
92
  canonical,
91
93
  sidebarPersistKey,
@@ -85,6 +85,15 @@ export interface DocLayoutProps extends DocLayoutHtmlAttrs {
85
85
  toc?: ComponentChildren;
86
86
  /** Hide the TOC (both desktop and mobile) regardless of slot value. */
87
87
  hideToc?: boolean;
88
+ /**
89
+ * Opt the content band into the **wide** layout. Sets `data-zd-wide` on
90
+ * `.zd-doc-content-band`, letting the reading column fill most of the
91
+ * viewport instead of the standard capped width (see the
92
+ * `.zd-doc-content-band[data-zd-wide]` rule in `features.css`). Mirrors the
93
+ * `wide` page frontmatter flag; also passed directly by route components
94
+ * (home page, etc.) that want a full-width grid. Defaults to `false`.
95
+ */
96
+ contentWide?: boolean;
88
97
  /** Optional footer rendered below the content. */
89
98
  footer?: ComponentChildren;
90
99
  /**
@@ -22,6 +22,7 @@ function DocLayout(props) {
22
22
  afterContent,
23
23
  toc,
24
24
  hideToc = false,
25
+ contentWide = false,
25
26
  footer,
26
27
  bodyEndComponents,
27
28
  bodyEndScripts,
@@ -72,6 +73,7 @@ function DocLayout(props) {
72
73
  {
73
74
  class: "zd-doc-content-band flex w-full gap-[clamp(1.5rem,3vw,4rem)]",
74
75
  ...!showSidebar ? { "data-zd-nosidebar": "" } : {},
76
+ ...contentWide ? { "data-zd-wide": "" } : {},
75
77
  children: [
76
78
  /* @__PURE__ */ jsxs("main", { class: "flex-1 min-w-0 px-hsp-xl py-vsp-xl lg:px-hsp-2xl lg:py-vsp-2xl", children: [
77
79
  breadcrumb,
package/dist/features.css CHANGED
@@ -335,6 +335,25 @@ pre[class^="syntect-"] .line .highlighted-word {
335
335
  max-width: 80rem;
336
336
  }
337
337
 
338
+ /* Wide band — opt-in full-width content layout (the `wide` frontmatter flag or
339
+ * the `contentWide` DocLayout prop set `data-zd-wide` on the band). Widens the
340
+ * reading column past the standard cap so grid-heavy / dashboard pages (e.g. the
341
+ * site home page) fill most of the viewport. Must beat BOTH capped variants:
342
+ * • the static hide_sidebar cap `.zd-doc-content-band[data-zd-nosidebar]`
343
+ * (specificity 0,2,0) — the first selector below is also 0,2,0 and wins by
344
+ * source order (it is placed after that rule);
345
+ * • the JS-toggle cap `html[data-sidebar-hidden] .zd-doc-content-band`
346
+ * (specificity 0,2,1) — the second selector below is 0,3,1 and wins on
347
+ * specificity.
348
+ * The literal clamp mirrors the established band-width pattern (see the
349
+ * `[data-zd-nosidebar]` 80rem literal and the `--zdc-content-max-width`
350
+ * default): fills up to ~92.5vw, floored at 50rem, capped at 120rem so
351
+ * ultra-wide monitors stay readable. Unlayered, so it beats Tailwind utilities. */
352
+ .zd-doc-content-band[data-zd-wide],
353
+ html[data-sidebar-hidden] .zd-doc-content-band[data-zd-wide] {
354
+ max-width: clamp(50rem, 92.5vw, 120rem);
355
+ }
356
+
338
357
  /* Sidebar toggle button — left position uses CSS variable, needs global rule */
339
358
  @media (min-width: 1024px) {
340
359
  .zd-desktop-sidebar-toggle {
@@ -33,6 +33,14 @@ export interface HomePageViewProps {
33
33
  /** Unique tag count for the current locale — gates the "all tags" section
34
34
  * together with `settings.docTags`. */
35
35
  tagCount: number;
36
+ /**
37
+ * Opt the home page into the **wide** content layout (full-viewport
38
+ * category grid instead of the standard capped reading column). Threaded to
39
+ * the underlying `DocLayoutWithDefaults` as `contentWide`. Defaults to
40
+ * `false` so downstream projects keep the narrower grid unless they opt in;
41
+ * this showcase passes `wide` from `pages/index.tsx`.
42
+ */
43
+ wide?: boolean;
36
44
  }
37
45
  /**
38
46
  * Create a `HomePageView` component from the unified {@link ChromeContext}
@@ -25,7 +25,8 @@ function createHomePageView(ctx) {
25
25
  extras,
26
26
  tree,
27
27
  categoryOrder,
28
- tagCount
28
+ tagCount,
29
+ wide
29
30
  }) {
30
31
  const prefix = locale === defaultLocale ? "" : `/${locale}`;
31
32
  const ctaNav = settings.headerNav[0] ?? null;
@@ -41,6 +42,7 @@ function createHomePageView(ctx) {
41
42
  noindex: settings.noindex,
42
43
  hideSidebar: true,
43
44
  hideToc: true,
45
+ contentWide: wide,
44
46
  sidebarOverride: /* @__PURE__ */ jsx(Fragment, {}),
45
47
  headerOverride: /* @__PURE__ */ jsx(HeaderWithDefaults, { lang: locale, currentPath: withBase(`${prefix}/`) }),
46
48
  footerOverride: /* @__PURE__ */ jsx(FooterWithDefaults, { lang: locale }),
@@ -0,0 +1,2 @@
1
+ import type { ChangelogEmitOptions, ChangelogEmitResult } from "./types.js";
2
+ export declare function emitChangelogs(options: ChangelogEmitOptions): ChangelogEmitResult;