@takazudo/zudo-doc 4.2.1 → 4.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/CHANGELOG.md CHANGED
@@ -4,6 +4,26 @@ All notable changes to `@takazudo/zudo-doc` are documented in this file.
4
4
 
5
5
  The format is based on Keep a Changelog, and release notes are generated from the changelog MDX pages.
6
6
 
7
+ ## [4.3.0] - 2026-07-19
8
+
9
+ ### Features
10
+
11
+ - Syntax highlighting is now driven by semantic design tokens across document code fences and `HtmlPreview`. Browser previews lazily load the public zfb WASM highlighter, existing color schemes inherit compatible semantic aliases, and project-owned Shiki dependencies and theme-name configuration are no longer required (178f23321)
12
+ - Home pages can opt into the wide content layout with `home.wide`; the setting applies consistently to package-owned root and localized home routes (d068ac346)
13
+ - Doc history can exclude selected pages through configuration, with matching behavior threaded through rendering, history generation, package settings, and generated-project configuration (e18c2e528)
14
+ - The Hearth theme now provides complete admonition icon coverage (736c6c5e1)
15
+
16
+ ### Bug Fixes
17
+
18
+ - Frontmatter status pills now meet WCAG contrast requirements across every shipped theme pack, light/dark mode, and semantic role while preserving their tinted backgrounds (2986d87c4)
19
+ - The showcase now consumes the package-owned theme contract correctly and emits literal semantic z-index utilities (2ca79ca6b, 8fb517df6)
20
+ - Theme-pack font validation is stricter, and the generated setup skill resolves main-worktree paths reliably (f9dd94d53, 4c2a508bb)
21
+
22
+ ### Other Changes
23
+
24
+ - Expanded English and Japanese documentation for syntax-token migration, wide home layouts, doc-history exclusions, theme development, and network exposure caveats
25
+ - Added browser-level highlighting coverage, exact pill contrast checks, settings parity tests, and compatibility-contract guards
26
+
7
27
  ## [4.2.1] - 2026-07-19
8
28
 
9
29
  ### Other Changes
package/README.md CHANGED
@@ -18,12 +18,12 @@ This package provides the missing-by-design framework concerns:
18
18
  - **Head injection** (`./head`) — canonical, og:\*, twitter:\*, robots, preload hints, RSS link, sitemap link, and theme-color output.
19
19
  - **SSR-skip wrappers** (`./ssr-skip`) — `<AiChatModalIsland>`, `<ImageEnlargeIsland>`, `<DesignTokenTweakPanelIsland>`, `<MockInitIsland>` — wrap zfb's `<Island ssrFallback>` with the right fallback markup so doc pages don't have to re-implement the SSR-skip pattern.
20
20
 
21
- ## Optional peer dependency: shiki
21
+ ## Optional peer dependency: `@takazudo/zfb-md-wasm`
22
22
 
23
- `./html-preview-wrapper`'s `<HighlightedCode>` lazily `import("shiki")`s at runtime for client-side syntax highlighting. `shiki` is declared as an **optional peerDependency** — install it in your project if you use that subpath:
23
+ `./html-preview-wrapper`'s `<HighlightedCode>` lazily imports the package root and calls `highlightCode()` for client-side semantic syntax highlighting. `@takazudo/zfb-md-wasm` is declared as an **optional peerDependency** — install the same prerelease version as the rest of your zfb packages if you use that subpath:
24
24
 
25
25
  ```sh
26
- pnpm add shiki
26
+ pnpm add @takazudo/zfb-md-wasm
27
27
  ```
28
28
 
29
29
  Projects scaffolded by `create-zudo-doc` already include it. If you never render `<HtmlPreview>` / `<HighlightedCode>`, you can omit it.
@@ -74,9 +74,10 @@ export interface ModeMap {
74
74
  selectionBg: RampRef;
75
75
  selectionFg: RampRef;
76
76
  semantic: Record<SemanticKey, RampRef>;
77
- /** Syntax-specific overrides. The map is required, while omitted roles
78
- * inherit the aliases in `SYNTAX_SEMANTIC_ALIASES`. */
79
- syntax: Partial<Record<SyntaxSemanticKey, RampRef>>;
77
+ /** Optional syntax-specific overrides. An absent map and omitted roles
78
+ * inherit the aliases in `SYNTAX_SEMANTIC_ALIASES`, preserving schemes
79
+ * authored before syntax tokens existed. */
80
+ syntax?: Partial<Record<SyntaxSemanticKey, RampRef>>;
80
81
  }
81
82
  /** A complete color scheme — shared Tier-1 ramps + per-mode Tier-2 wiring. */
82
83
  export interface ColorScheme {
@@ -207,7 +207,7 @@ function resolveSyntaxPalette(scheme) {
207
207
  );
208
208
  const emergencyColor = tryResolveRampRef(emergencyRef, ramps) ?? "currentColor";
209
209
  for (const key of SYNTAX_SEMANTIC_KEYS) {
210
- const explicitRef = map.syntax[key];
210
+ const explicitRef = map.syntax?.[key];
211
211
  const explicitColor = tryResolveRampRef(explicitRef, ramps);
212
212
  const inheritedRef = map.semantic[SYNTAX_SEMANTIC_ALIASES[key]];
213
213
  const inheritedColor = tryResolveRampRef(inheritedRef, ramps);
@@ -343,7 +343,7 @@ const COMPONENT_TOKENS = [
343
343
  component: "sidebar",
344
344
  surface: "chrome",
345
345
  category: "typography",
346
- description: "Font family of the navigation sidebar \u2014 covers BOTH the desktop `#desktop-sidebar` rail and the mobile drawer, so one override styles both viewports and neither drifts onto a different face. Defaults to the `--zdc-chrome-font` seam (a no-op until redefined)."
346
+ description: "Font family of the navigation sidebar \u2014 covers BOTH the desktop `#desktop-sidebar` rail and the mobile drawer, so one override styles both viewports and neither drifts onto a different face. Defaults to the `--zdc-chrome-font` seam (a no-op until redefined). Verify granular MOBILE chrome-font overrides with `zfb build`/preview, not `pnpm dev`: the current zfb dev server strips island-root `data-*` attributes, so the mobile selector silently does not match."
347
347
  },
348
348
  {
349
349
  cssVar: "--zdc-toc-font",
@@ -353,7 +353,7 @@ const COMPONENT_TOKENS = [
353
353
  component: "toc",
354
354
  surface: "chrome",
355
355
  category: "typography",
356
- description: "Font family of the table of contents \u2014 covers BOTH the desktop right rail and the mobile collapsible TOC, so one override styles both viewports. Defaults to the `--zdc-chrome-font` seam (a no-op until redefined), which also keeps the mobile TOC on the chrome font rather than the prose font of the `.zd-content` it renders inside."
356
+ description: "Font family of the table of contents \u2014 covers BOTH the desktop right rail and the mobile collapsible TOC, so one override styles both viewports. Defaults to the `--zdc-chrome-font` seam (a no-op until redefined), which also keeps the mobile TOC on the chrome font rather than the prose font of the `.zd-content` it renders inside. Verify granular MOBILE chrome-font overrides with `zfb build`/preview, not `pnpm dev`: the current zfb dev server strips island-root `data-*` attributes, so the mobile selector silently does not match."
357
357
  }
358
358
  ];
359
359
  export {
package/dist/config.d.ts CHANGED
@@ -62,7 +62,7 @@ import type { ZfbConfig, BundleConfig } from "@takazudo/zfb/config";
62
62
  import type { ZodType } from "zod";
63
63
  import type { DirectiveVocabulary, PresetTranslations, PresetTagVocabularyEntry } from "./preset.js";
64
64
  import type { ColorScheme } from "./color-scheme-utils.js";
65
- import type { Settings, ColorModeConfig, LocaleConfig, MetaTagsConfig, SiteHeadConfig, TagPlacement, TagGovernanceMode, VersionConfig, FooterConfig, HeaderNavItem, HeaderRightItem, FrontmatterPreviewConfig, BodyFootUtilAreaConfig, HtmlPreviewConfig } from "./settings.js";
65
+ import type { Settings, ColorModeConfig, LocaleConfig, MetaTagsConfig, SiteHeadConfig, TagPlacement, TagGovernanceMode, VersionConfig, FooterConfig, HeaderNavItem, HeaderRightItem, HomeConfig, FrontmatterPreviewConfig, BodyFootUtilAreaConfig, HtmlPreviewConfig } from "./settings.js";
66
66
  /** The `settings.claudeResources` block (or `false` when disabled). */
67
67
  type ClaudeResourcesConfig = {
68
68
  claudeDir: string;
@@ -103,6 +103,12 @@ export interface ZudoDocConfig {
103
103
  * @default false
104
104
  */
105
105
  trailingSlash?: boolean;
106
+ /**
107
+ * Package-owned home-page layout. Set `wide: true` to let the category grid
108
+ * fill most of the viewport on both `/` and locale home routes.
109
+ * @default { wide: false }
110
+ */
111
+ home?: HomeConfig;
106
112
  /**
107
113
  * Minify production HTML output from `zfb build`.
108
114
  * @default true
@@ -300,6 +306,14 @@ export interface ZudoDocConfig {
300
306
  * @default false
301
307
  */
302
308
  docHistory?: boolean;
309
+ /**
310
+ * Glob patterns matched against the doc slug (path minus extension, `/index`
311
+ * stripped, root = `index`) that exclude matching pages from git-history
312
+ * capture entirely. Excluded pages have no dropdown JSON or
313
+ * Created/Updated/Author block; matching is locale/version-independent.
314
+ * @default []
315
+ */
316
+ docHistoryExclude?: string[];
303
317
  /**
304
318
  * Body-foot utility area (doc-history / view-source), or `false` to disable.
305
319
  * @default false
package/dist/config.js CHANGED
@@ -15,6 +15,7 @@ const DEFAULT_SETTINGS = {
15
15
  siteDescription: "",
16
16
  base: "/",
17
17
  trailingSlash: false,
18
+ home: { wide: false },
18
19
  minifyHtml: true,
19
20
  docsDir: "src/content/docs",
20
21
  defaultLocale: "en",
@@ -58,6 +59,7 @@ const DEFAULT_SETTINGS = {
58
59
  dynamicPageTransition: false,
59
60
  frontmatterPreview: false,
60
61
  docHistory: false,
62
+ docHistoryExclude: [],
61
63
  bodyFootUtilArea: false,
62
64
  htmlPreview: void 0,
63
65
  versions: false,
@@ -14,6 +14,7 @@ export interface DocHistoryMetaEntry {
14
14
  /** Settings subset read by the DocHistoryArea factory. */
15
15
  export interface DocHistoryAreaSettings {
16
16
  docHistory: boolean;
17
+ docHistoryExclude?: string[];
17
18
  bodyFootUtilArea: {
18
19
  viewSourceLink?: boolean;
19
20
  } | false | undefined;
@@ -1,5 +1,6 @@
1
1
  import { jsx, jsxs } from "preact/jsx-runtime";
2
2
  import { Island } from "@takazudo/zfb";
3
+ import { compileExclude } from "@takazudo/zudo-doc-history-server/exclude";
3
4
  import { BodyFootUtilArea } from "../body-foot-util/index.js";
4
5
  import { toHistorySlug } from "../slug/index.js";
5
6
  import { buildGitHubSourceUrl as buildGitHubSourceUrlBase } from "../github-helpers/index.js";
@@ -8,6 +9,7 @@ import { assertChromeContext } from "../chrome/assert-chrome-context.js";
8
9
  function createDocHistoryArea(ctx) {
9
10
  assertChromeContext(ctx, "createDocHistoryArea");
10
11
  const settings = ctx.settings;
12
+ const isHistoryExcluded = compileExclude(settings.docHistoryExclude ?? []);
11
13
  const defaultLocale = ctx.defaultLocale;
12
14
  const docHistoryMeta = ctx.hostBindings.docHistoryMeta ?? {};
13
15
  const t = ctx.t;
@@ -28,6 +30,7 @@ function createDocHistoryArea(ctx) {
28
30
  }) {
29
31
  if (!settings.docHistory) return null;
30
32
  const historySlug = toHistorySlug(slug);
33
+ if (isHistoryExcluded(historySlug)) return null;
31
34
  const effectiveHistoryLocale = isFallback ? defaultLocale : locale;
32
35
  const composedSlug = effectiveHistoryLocale === defaultLocale ? historySlug : `${effectiveHistoryLocale}/${historySlug}`;
33
36
  const meta = docHistoryMeta[composedSlug];
package/dist/features.css CHANGED
@@ -179,31 +179,10 @@ header[data-header] {
179
179
  --zfb-hi-hd: var(--zd-syntax-keyword);
180
180
  }
181
181
 
182
- /* HTML Preview remains on Shiki until #2742. Its dual-theme variables resolve
183
- * through color-scheme. These selectors intentionally exclude `.hi-root`,
184
- * whose colors come from the semantic bridge above. */
185
- [data-theme] .shiki,
186
- [data-theme] .shiki span {
187
- color: light-dark(var(--shiki-light), var(--shiki-dark));
188
- font-style: light-dark(
189
- var(--shiki-light-font-style, inherit),
190
- var(--shiki-dark-font-style, inherit)
191
- );
192
- }
193
-
194
- /* Background only on the <pre> wrapper — deliberately NOT on token spans. The
195
- * --shiki-*-bg vars are set inline on the <pre> and inherit down to spans;
196
- * painting them per-span would lay an opaque base background over the
197
- * translucent line-/word-highlight backgrounds that sit on the enclosing
198
- * .line span (see .line.highlighted below). */
199
- [data-theme] .shiki {
200
- background-color: light-dark(var(--shiki-light-bg), var(--shiki-dark-bg));
201
- }
202
-
203
- /* HtmlPreview component — Shiki code blocks
204
- * Token colors inherit from the global [data-theme] .shiki rule above.
205
- * These rules only adjust layout and background for the preview context. */
206
- .zd-html-preview-code pre.shiki {
182
+ /* HtmlPreview component zfb semantic code blocks. Token colors and the root
183
+ * surface resolve through the shared class-mode bridge above; these rules only
184
+ * adjust layout for the preview context. */
185
+ .zd-html-preview-code pre.hi-root {
207
186
  margin: 0;
208
187
  padding: var(--spacing-hsp-md);
209
188
  font-size: var(--text-caption);
@@ -211,7 +190,7 @@ header[data-header] {
211
190
  overflow-x: auto;
212
191
  }
213
192
 
214
- .zd-html-preview-code pre.shiki code {
193
+ .zd-html-preview-code pre.hi-root code {
215
194
  font-family: var(--font-mono);
216
195
  white-space: pre;
217
196
  }
@@ -266,9 +245,9 @@ pre.hi-root .line .highlighted-word {
266
245
  * zfb's :::code-group emits <CodeGroup tabs={[...]}> with one
267
246
  * <pre data-lang="…">{RAW text}</pre> child per fence. These <pre> elements
268
247
  * are NOT syntax-highlighted (the Rust pipeline doesn't highlight inside
269
- * code-group fences), so they get no `.hi-root` class. Apply explicit
270
- * code-block visual treatment via tokens to match the highlighted code blocks
271
- * surrounding them.
248
+ * code-group fences), so they get no `.hi-root` class.
249
+ * Apply explicit code-block visual treatment via tokens to match the
250
+ * highlighted code blocks surrounding them.
272
251
  * ======================================== */
273
252
 
274
253
  .code-group-panel pre[data-lang] {
@@ -0,0 +1,40 @@
1
+ import type { HighlightCodeOptions, HighlightCodeResult } from "@takazudo/zfb-md-wasm";
2
+ type HighlightModule = Pick<typeof import("@takazudo/zfb-md-wasm"), "highlightCode">;
3
+ export type HighlightModuleImporter = () => Promise<HighlightModule>;
4
+ export interface HtmlPreviewHighlightRuntime {
5
+ highlightCode(code: string, options: HighlightCodeOptions): Promise<HighlightCodeResult>;
6
+ }
7
+ /**
8
+ * Build the HTML Preview's lazy zfb highlighting adapter.
9
+ *
10
+ * The cached value is only the public package-root module import. A rejected
11
+ * import is evicted so a later source-panel mount can retry a transient chunk
12
+ * load. Calls to `highlightCode` are deliberately not cached: the upstream
13
+ * package owns WASM initialization and trap recovery, while the component owns
14
+ * request cancellation and stale-result protection.
15
+ */
16
+ export declare function createHighlightRuntime(importModule: HighlightModuleImporter): HtmlPreviewHighlightRuntime;
17
+ /**
18
+ * Return markup only when zfb produced a usable result.
19
+ *
20
+ * An unknown non-empty language is a supported outcome: zfb returns safely
21
+ * escaped `hi-root` markup plus a warning. Error diagnostics and `html: null`
22
+ * represent invalid options/internal failure and must retain the JSX-escaped
23
+ * fallback instead.
24
+ */
25
+ export declare function getUsableHighlightHtml(result: HighlightCodeResult): string | null;
26
+ export interface HighlightRequestOptions {
27
+ code: string;
28
+ language: string;
29
+ onSettled: (html: string | null) => void;
30
+ runtime?: HtmlPreviewHighlightRuntime;
31
+ }
32
+ /**
33
+ * Start one highlight request and return its effect cleanup.
34
+ *
35
+ * Rejections are expected at this boundary (missing optional peer, resource
36
+ * load failure, or a current-call WASM trap). They resolve the UI to its plain
37
+ * fallback. Cleanup suppresses both successful and failed late completions.
38
+ */
39
+ export declare function startHighlightRequest({ code, language, onSettled, runtime, }: HighlightRequestOptions): () => void;
40
+ export {};
@@ -0,0 +1,58 @@
1
+ function createHighlightRuntime(importModule) {
2
+ let modulePromise = null;
3
+ function loadModule() {
4
+ if (!modulePromise) {
5
+ const pending = importModule().catch((error) => {
6
+ if (modulePromise === pending) {
7
+ modulePromise = null;
8
+ }
9
+ throw error;
10
+ });
11
+ modulePromise = pending;
12
+ }
13
+ return modulePromise;
14
+ }
15
+ return {
16
+ async highlightCode(code, options) {
17
+ const { highlightCode } = await loadModule();
18
+ return highlightCode(code, options);
19
+ }
20
+ };
21
+ }
22
+ const defaultRuntime = createHighlightRuntime(
23
+ () => import("@takazudo/zfb-md-wasm")
24
+ );
25
+ function getUsableHighlightHtml(result) {
26
+ if (result.html == null || result.diagnostics.some((diagnostic) => diagnostic.severity === "error")) {
27
+ return null;
28
+ }
29
+ return result.html;
30
+ }
31
+ function startHighlightRequest({
32
+ code,
33
+ language,
34
+ onSettled,
35
+ runtime = defaultRuntime
36
+ }) {
37
+ let cancelled = false;
38
+ void Promise.resolve().then(() => runtime.highlightCode(code, { language })).then(
39
+ (result) => {
40
+ if (!cancelled) {
41
+ onSettled(getUsableHighlightHtml(result));
42
+ }
43
+ },
44
+ () => {
45
+ if (!cancelled) {
46
+ onSettled(null);
47
+ }
48
+ }
49
+ );
50
+ return () => {
51
+ cancelled = true;
52
+ };
53
+ }
54
+ export {
55
+ createHighlightRuntime,
56
+ getUsableHighlightHtml,
57
+ startHighlightRequest
58
+ };
@@ -6,8 +6,9 @@ export interface HighlightedCodeProps {
6
6
  language: string;
7
7
  }
8
8
  /**
9
- * Syntax-highlighted code block backed by Shiki. Falls back to a
10
- * plain `<pre><code>` block while Shiki is loading or if it fails.
9
+ * Syntax-highlighted code block backed by zfb's semantic-class WASM API.
10
+ * Falls back to a plain `<pre><code>` block while the runtime is loading or
11
+ * when the current request cannot produce safe markup.
11
12
  *
12
13
  * JSX port of src/components/html-preview/highlighted-code.tsx.
13
14
  */
@@ -1,41 +1,22 @@
1
1
  import { jsx } from "preact/jsx-runtime";
2
2
  import { useEffect, useState } from "preact/hooks";
3
- let highlighterPromise = null;
4
- function getHighlighter() {
5
- if (!highlighterPromise) {
6
- highlighterPromise = import("shiki").then(
7
- ({ createHighlighter }) => createHighlighter({
8
- themes: ["catppuccin-latte", "vitesse-dark"],
9
- langs: ["html", "css", "javascript"]
10
- })
11
- ).catch((err) => {
12
- highlighterPromise = null;
13
- throw err;
14
- });
15
- }
16
- return highlighterPromise;
17
- }
3
+ import { startHighlightRequest } from "./highlight-runtime.js";
18
4
  function HighlightedCode({
19
5
  code,
20
6
  language
21
7
  }) {
22
- const [html, setHtml] = useState(null);
8
+ const [highlighted, setHighlighted] = useState(null);
9
+ const html = highlighted?.code === code && highlighted.language === language ? highlighted.html : null;
23
10
  useEffect(() => {
24
- let cancelled = false;
25
- getHighlighter().then((highlighter) => {
26
- if (cancelled) return;
27
- const lang = highlighter.getLoadedLanguages().includes(language) ? language : "text";
28
- const result = highlighter.codeToHtml(code, {
29
- lang,
30
- themes: { light: "catppuccin-latte", dark: "vitesse-dark" },
31
- defaultColor: false
32
- });
33
- setHtml(result);
34
- }).catch(() => {
11
+ return startHighlightRequest({
12
+ code,
13
+ language,
14
+ onSettled(nextHtml) {
15
+ setHighlighted(
16
+ nextHtml == null ? null : { code, language, html: nextHtml }
17
+ );
18
+ }
35
19
  });
36
- return () => {
37
- cancelled = true;
38
- };
39
20
  }, [code, language]);
40
21
  if (!html) {
41
22
  return /* @__PURE__ */ jsx("pre", { class: "m-0 p-hsp-md bg-code-bg text-caption leading-relaxed overflow-x-auto", children: /* @__PURE__ */ jsx("code", { class: "font-mono whitespace-pre", children: code }) });
@@ -8,7 +8,7 @@ import { getBasePrefix } from "./plugin-utils.js";
8
8
  const plugin = {
9
9
  name: "doc-history",
10
10
  async preBuild(ctx) {
11
- const { docsDir, locales } = ctx.options;
11
+ const { docsDir, locales, exclude } = ctx.options;
12
12
  if (locales != null) {
13
13
  for (const [key, entry] of Object.entries(locales)) {
14
14
  if (entry == null || typeof entry !== "object" || typeof entry["dir"] !== "string" || entry["dir"].length === 0) {
@@ -18,10 +18,14 @@ const plugin = {
18
18
  }
19
19
  }
20
20
  }
21
+ if (exclude != null && (!Array.isArray(exclude) || exclude.some((pattern) => typeof pattern !== "string"))) {
22
+ throw new Error("[doc-history] invalid exclude: expected string[]");
23
+ }
21
24
  await runDocHistoryMetaStep({
22
25
  projectRoot: ctx.projectRoot,
23
26
  docsDir: typeof docsDir === "string" ? docsDir : "src/content/docs",
24
- locales: locales != null ? locales : void 0
27
+ locales: locales != null ? locales : void 0,
28
+ exclude
25
29
  });
26
30
  },
27
31
  async postBuild(ctx) {
@@ -11,6 +11,8 @@ export interface DocHistoryOptions {
11
11
  docsDir: string;
12
12
  /** Optional non-default locales, keyed by locale code (e.g. `{ ja: { dir: "src/content/docs-ja" } }`). */
13
13
  locales?: Record<string, DocHistoryLocaleConfig>;
14
+ /** Slug globs excluded from pre-build metadata and post-build history JSON. */
15
+ exclude?: string[];
14
16
  /**
15
17
  * Port the standalone `@takazudo/zudo-doc-history-server` listens on.
16
18
  * Defaults to `4322` to match the server's CLI default. Only used by
@@ -92,6 +92,11 @@ function buildGenerateCliArgs(options, outDir) {
92
92
  args.push("--locale", `${key}:${locale.dir}`);
93
93
  }
94
94
  }
95
+ if (options.exclude) {
96
+ for (const pattern of options.exclude) {
97
+ args.push("--exclude", pattern);
98
+ }
99
+ }
95
100
  if (options.maxEntries != null) {
96
101
  args.push("--max-entries", String(options.maxEntries));
97
102
  }
@@ -20,6 +20,8 @@ export interface RunDocHistoryMetaOptions {
20
20
  docsDir: string;
21
21
  /** Optional non-default locales, keyed by locale code. */
22
22
  locales?: Record<string, DocHistoryMetaLocaleConfig>;
23
+ /** Slug globs excluded from the emitted metadata manifest. */
24
+ exclude?: string[];
23
25
  /**
24
26
  * Optional versioned docs (e.g. legacy `1.0`). Each version produces
25
27
  * its own default-locale collection plus per-locale variants.
@@ -4,6 +4,7 @@ import {
4
4
  collectContentFiles,
5
5
  getAllFilesFirstLastMetaAsync
6
6
  } from "@takazudo/zudo-doc-history-server/git-history";
7
+ import { compileExclude } from "@takazudo/zudo-doc-history-server/exclude";
7
8
  const META_OUT_RELATIVE_DIR = ".zfb";
8
9
  const META_OUT_FILENAME = "doc-history-meta.json";
9
10
  function deriveSourceExt(filePath) {
@@ -31,9 +32,11 @@ async function runDocHistoryMetaStep(options) {
31
32
  }
32
33
  }
33
34
  const jobs = [];
35
+ const isExcluded = compileExclude(options.exclude ?? []);
34
36
  for (const [localeKey, contentDir] of dirEntries) {
35
37
  const files = collectContentFiles(contentDir);
36
38
  for (const { filePath, slug } of files) {
39
+ if (isExcluded(slug)) continue;
37
40
  const composedSlug = localeKey ? `${localeKey}/${slug}` : slug;
38
41
  jobs.push({ composedSlug, filePath });
39
42
  }
package/dist/preset.d.ts CHANGED
@@ -83,6 +83,7 @@ export interface PresetSettings {
83
83
  llmsTxt?: boolean;
84
84
  changelogs?: PresetChangelogConfig[] | false;
85
85
  docHistory?: boolean;
86
+ docHistoryExclude?: string[];
86
87
  claudeResources?: PresetClaudeResourcesConfig | false;
87
88
  /** "owner/repo" — when set, enables `#123` / SHA autolinks in markdown. Omit to disable entirely. */
88
89
  githubAutolinksRepo?: string;
package/dist/preset.js CHANGED
@@ -182,7 +182,8 @@ function buildPlugins(settings, routeContext) {
182
182
  options: {
183
183
  docsDir: settings.docsDir,
184
184
  locales: localeRecord,
185
- base: settings.base
185
+ base: settings.base,
186
+ exclude: settings.docHistoryExclude ?? []
186
187
  }
187
188
  }
188
189
  ] : [],
@@ -1,12 +1,21 @@
1
1
  import { jsx } from "preact/jsx-runtime";
2
- import { defaultLocale, routeCtx } from "./_context.js";
2
+ import { defaultLocale, routeCtx, settings } from "./_context.js";
3
3
  import { prepareHomeData } from "../home-page/prepare-home-data.js";
4
4
  import { HomePageView } from "./_chrome.js";
5
5
  const frontmatter = { title: "Home" };
6
6
  function IndexPage() {
7
7
  const locale = defaultLocale;
8
8
  const { tree, categoryOrder, tagCount } = prepareHomeData(routeCtx, locale);
9
- return /* @__PURE__ */ jsx(HomePageView, { locale, tree, categoryOrder, tagCount });
9
+ return /* @__PURE__ */ jsx(
10
+ HomePageView,
11
+ {
12
+ locale,
13
+ tree,
14
+ categoryOrder,
15
+ tagCount,
16
+ wide: settings.home?.wide ?? false
17
+ }
18
+ );
10
19
  }
11
20
  export {
12
21
  IndexPage as default,
@@ -12,7 +12,16 @@ function paths() {
12
12
  function LocaleIndexPage({ params }) {
13
13
  const locale = params.locale;
14
14
  const { tree, categoryOrder, tagCount } = prepareHomeData(routeCtx, locale);
15
- return /* @__PURE__ */ jsx(HomePageView, { locale, tree, categoryOrder, tagCount });
15
+ return /* @__PURE__ */ jsx(
16
+ HomePageView,
17
+ {
18
+ locale,
19
+ tree,
20
+ categoryOrder,
21
+ tagCount,
22
+ wide: settings.home?.wide ?? false
23
+ }
24
+ );
16
25
  }
17
26
  export {
18
27
  LocaleIndexPage as default,
package/dist/safelist.css CHANGED
@@ -1,2 +1,2 @@
1
1
  /* generated by gen-safelist.mjs — do not edit by hand */
2
- @source inline("-link -mb-px -ml-hsp-sm -noscript -open -translate-x-full 2xl:w-[24px] [&::-webkit-details-marker]:hidden [&_a]:text-accent [&_a]:underline [&_nav]:mb-0 [data-admonition] [data-kbd-shortcut] [data-switcher-launcher] [doc-history-meta] [doc-history] [doc-layout] [llms-txt] [zudo-doc] a a2 abbr about above absent absolute accent accent- accent:accent- across activated active actual added admonition admonition- admonition-body admonition-title admonition/callout after after-breadcrumb after-content after-navigate after-sidebar after-title against agent agents ai-chat ai-chat-md ai-chat-trigger alert align-top all allow-same-origin allow-scripts allowed alone already already-executed already-multiline already-picked also always an anchor and and/or animate-pulse animate-spin announce ansehen antialiased any anywhere anzeigen app appear application/json application/xml applied applies apply approach are area arg argument aria-atomic aria-busy aria-controls aria-current aria-disabled aria-expanded aria-haspopup aria-hidden aria-label aria-labelledby aria-live aria-orientation aria-pressed aria-selected aria-valuemax aria-valuemin aria-valuenow arm arms arrows article as asc aside aspect-[1200/630] aspect-square asset- assets assistant async at attach attribute attributes auf authored auto autogenerated available avoid await away b back backdrop:bg-bg/30 backdrop:bg-bg/80 backdrop:bg-overlay/60 backdrop:z-modal-backdrop background background-color backtick backticks baked banner bare base base- base64 base:base- based batch be bearbeiten because been before below best between bg bg-[#fff] bg-accent bg-bg bg-chat-assistant-bg bg-chat-user-bg bg-code-bg bg-fg bg-info/10 bg-info/5 bg-muted bg-overlay/30 bg-surface bg-surface/50 bg-transparent bg-warning/10 bg-warning/5 bi bigint bin binaries bind blank blanks block blockquote blocks blur body body-end-components body-end-scripts bold boolean bootstrap border border-accent border-b border-b-2 border-b-[5px] border-bg/30 border-collapse border-danger border-dashed border-fg border-image border-info/30 border-l border-l-0 border-l-[3px] border-left-width border-muted border-none border-r border-radius border-solid border-t border-t-[2px] border-t-[3px] border-transparent border-warning/30 border-width border-y both bottom-hsp-lg bottom-vsp-xl boundaries box-border br brackets brand breadcrumb:end breadcrumb:start break-words brown browser browsers btn budget bug build built built-in bundler but button buttons by bypassed byte-identical bytes cached call callable called caller calls can cancellation cannot canonical canvas caption card card-grid carry cases cat-nav- catch category catppuccin-latte caught caution center center/contain ch chains change changed changelog changelogs changes child choose chrome ci circle cite class class-less class-mode claude claude-agents claude-commands claude-md claude-skills cleaned clear clearing click client client-router client-side clip clobbering close closed closing code code-block-sr-announce code-group code-group-panel col col-resize colgroup collapses collapsible collision color color-scheme color-scheme-changed color-scheme-provider color-tweak colorization colors column comma command commands comment commercial commercial-font-denylist commit compare component component:github-link component:language-switcher component:search component:theme-toggle component:version-switcher composition compute computed concrete config configuration configure configured confuse connect const construction consumer consumes container containers containing contains content content-admonition content-layer content-link content-type content-wrapper:end content-wrapper:start contents context contract controller controls converts copied copy corners correct correctly corrupt could count covered covers cp crashes created cross-component crumb- cs css css-presence ctx cur current cursor-not-allowed cursor-pointer custom danger dark data data-active data-admonition data-base data-close-search data-current-locale data-default-locale data-doc-description data-doc-pager data-find-active data-find-match data-footer data-group-id data-header data-header-logo data-header-nav data-header-right data-kbd-shortcut data-language-switcher data-loading-index data-mermaid-enlarge-ready data-mermaid-rendered data-mermaid-src data-nav-active data-nav-item data-nav-item-dropdown data-nav-more data-nav-more-menu data-nav-more-toggle data-no-results data-open-search data-pan-active data-processed data-result-count-template data-search-count data-search-count-narrow data-search-dialog data-search-input data-search-placeholder data-search-results data-search-unavailable data-sidebar-hidden data-sidebar-resizer data-site-nav data-switcher-card data-switcher-launcher data-tab-btn data-tab-default data-tab-label data-tab-value data-tabs data-taglist-group data-testid data-theme data-theme-pack data-theme-pack-switcher data-theme/style data-trailing-slash data-variant data-version-banner data-version-latest data-version-menu data-version-rewire data-version-slug data-version-switcher data-version-toggle data-version-trigger-label data-zd-mobile-sidebar data-zd-mobile-toc data-zd-nosidebar data-zd-theme-pack-css data-zd-theme-pack-css-loading data-zd-toc data-zd-wide data-zfb-transition-persist dd decimal declaration declare declares decoration decoration-muted default default-transition-duration defaults del delegated delete dependency depth der desc description design design-token-panel design-token-trigger desktop desktop-sidebar desktop-sidebar-toggle desktop-sidebar-toggle-island destructive detach detached details determine deterministic develop dfn diagram diagrams dialog die dieser diff diff-line-added diff-line-content diff-line-empty diff-line-num diff-line-removed diff-row different dir directly directories directory disabled disabled:opacity-50 disabled:pointer-events-none disc display display:none dist distinct div dl do doc doc-card- doc-content-band doc-history doc-history-generate doc-history-panel doc-history-trigger doc-page doc-pager doc-prose doc-title docs docs- docs-v- document document-level documentation documented does dog double-registration draft drag draggable drawer drifts drop dropdown dropdown-child dropdown-parent dropdowns dt duplicate duration-150 duration-200 during dynamically e2e each ease-in-out edge einer eject ejectable ejectables ejected el element elements els else em embedded emit emitting empty empty/undefined en enable enabled end enlarged entire entities entries entry equal error escape escaped even eventually every exactly exceeds excerpt excludes exclusively existing exists exit expected export extends f factories failed fall fallback fallbacks falling falls false family fast feature fg field fields fieldset figcaption figure file fill fills finally find find-match find-match-active fire fires first fixed fixed-width fixtures flag flash flat flex flex-1 flex-col flex-wrap flip flipping flips flush-left focus focus-visible:outline-2 focus-visible:outline-accent focus-visible:outline-offset-2 focus-visible:underline focus:border-accent focus:outline-none focus:underline font font-bold font-face-parity font-family font-medium font-mono font-sans font-scale font-semibold font-size font-weight font-weight-bold font-weight-medium font-weight-normal font-weight-semibold font/woff2 fonts footer footer- for form format found fox free fresh from frontmatter frontmatter-preview frozen fs-extra full fully function further g gap-[0.3em] gap-[clamp(1.5rem,3vw,4rem)] gap-hsp-2xs gap-hsp-lg gap-hsp-md gap-hsp-sm gap-hsp-xl gap-hsp-xs gap-vsp-2xs gap-vsp-3xs gap-vsp-lg gap-vsp-md gap-vsp-xs gap-x-hsp-2xs gap-x-hsp-lg gap-x-hsp-md gap-x-hsp-sm gap-x-hsp-xs gap-y-vsp-2xs gap-y-vsp-lg gap-y-vsp-md gap-y-vsp-xs gaps gate geladen2026 generate generated generation genuine geometry get github github-dark github-link give go got gradient graph gray-matter grid grid-cols-1 grid-cols-2 group group-focus-visible:text-accent group-focus-visible:underline group-focus-within:block group-hover:bg-fg group-hover:block group-hover:text-accent group-hover:text-bg group-hover:underline group-open:rotate-90 guard h-10 h-40 h-[0.5rem] h-[0.625rem] h-[0.875rem] h-[1.125rem] h-[1.25rem] h-[1.575rem] h-[14px] h-[1em] h-[1lh] h-[2rem] h-[3.5rem] h-[3rem] h-[90vh] h-[calc(100%-3rem)] h-[calc(100vh-3.5rem)] h-dvh h-full h-icon-lg h-icon-md h-icon-sm h-icon-xs h1 h1s h2 h22013h4 h2s h3 h4 h5 h6 half hand-copied hand-editable handle handled handler handlers hardcoded has hash-link have head head-links head-scripts header header- header-call:end header-call:start header-right heading heading-h2 heading-h3 heading-h4 heading-rule headings height here hex hidden hierarchical highlight history hit home horizontal host hover:bg-[color-mix(in_srgb,var(--color-surface)_80%,var(--color-fg)_20%)] hover:bg-accent-hover hover:bg-accent/10 hover:bg-danger/10 hover:bg-surface hover:border-accent hover:border-accent-hover hover:border-fg hover:text-accent hover:text-accent-hover hover:text-fg hover:underline hr href hrefs hsp hsp-2xl hsp-2xs hsp-lg hsp-md hsp-sm hsp-xl hsp-xs html i i18n/theme. i2 i3 i4 icon icon-lg icon-md icon-sm icon-xs identical idle idx if iframe image image-enlarge image-overlay-inset image/png img implementation import important important-allowlist imports in inactive inbox includes incomplete independently index index2026 info inherit inherited initial initialised injected inline inline-block inline-flex inner input input-clear ins inserted-after-color-mode inserted-after-color-scheme inserted-first inset-0 inside install installation installed instance instanceof instead instructions intended intent internal interpolation into invalid inverse inversion invoke is issues it italic item item- items items-baseline items-center items-end items-start its itself javascript jumps justify-between justify-center justify-end justify-start katex kbd keep keeping keeps keyboard keyboard-shortcut keydown keys keystroke keyword keywords khroma known-token-names kopieren label landing language-switcher last:border-b-0 later latest launch layout lazy leading-normal leading-relaxed leading-snug leading-tight leaf- leak leaves left left-0 left:calc legend legitimate length lets letter-spacing lg lg:block lg:border lg:border-fg lg:border-solid lg:flex lg:flex-col lg:flex-row lg:gap-hsp-xl lg:grid-cols-3 lg:grid-cols-[repeat(auto-fit,minmax(12rem,1fr))] lg:h-[90vh] lg:hidden lg:justify-start lg:m-auto lg:max-h-[90vh] lg:max-w-[52.5rem] lg:ml-[var(--zd-sidebar-w)] lg:pt-vsp-2xl lg:px-hsp-2xl lg:py-vsp-2xl lg:text-left lg:w-[90vw] lg:w-[clamp(16rem,25%,22rem)] li li2 library license light light/dark like likely line line-height line/statement linger link link- links list list-disc list-none listener lists literal literals lives llms llms-txt load loaded loading local local-1 local-2 local-3 locale locales log longer longest-match look lostpointercapture lower luminance m m-0 m-auto m21 m6 machinery main major make malformed malicious manually maps mark marks match matches matching math math-display math-inline max max-h-[85vh] max-h-[90vh] max-h-full max-h-none max-w-[64rem] max-w-[85%] max-w-[85vw] max-w-[90vw] max-w-[calc(100vw-2rem)] max-w-[clamp(50rem,75vw,90rem)] max-w-full max-w-none max-w-sm max-width may mb-0 mb-vsp-2xs mb-vsp-lg mb-vsp-md mb-vsp-sm mb-vsp-xl mb-vsp-xs measures measuring mechanism menu mermaid message messages meta meta-knob meta-schema metadata migration min-h-0 min-h-[60vh] min-h-[calc(100vh-3.5rem)] min-h-screen min-w-0 min-w-[10rem] min-w-[3rem] min-w-[8rem] minifier minor mirror mirrors missing mit ml-auto ml-hsp-2xl ml-hsp-lg ml-hsp-sm ml-hsp-xl mobile mod modal modal-backdrop mode modify module monospace more most mounted mouseenter mouseleave move mr-hsp-sm ms mt-0 mt-vsp-2xl mt-vsp-2xs mt-vsp-3xs mt-vsp-lg mt-vsp-md mt-vsp-xl must mutates mutation mutations muted mx-auto my-vsp-lg my-vsp-md n name named names native nav nav-active nav-card- nav/doc navigating navigation navigations near needs neither nested neutral new newly-swapped next nicht no no-color-scheme no-data-theme-selector no-enlarge no-op no-repeat no-underline noch node node:buffer node:fs node:fs/promises node:module node:path node:url nodes nofollow noindex non-empty non-light-dark non-literal non-persisted none noopener noreferrer normal noscript not notable note notes now null number numeric object object-contain observe observer occurred of off ofl-required og:description og:image og:image:alt og:image:height og:image:width og:title og:type og:url oklch ol old older on once one only onto opacity-60 open open/close option or original other others out outgoing outline-none over overflow overflow-auto overflow-hidden overflow-x-auto overflow-y-auto overflow-y:auto override overrides overscroll-contain overwrite own owned p p-0 p-hsp-2xs p-hsp-lg p-hsp-md p-hsp-sm pack package package-owned packages packs padding page page-loading page-loading-overlay page-loading-spinner page-navigate-end page-title pages pages/. paint paint-and-read palette pan panel panels paren-balance-aware parent parse parsed parser parses part pass passed passes patch path paths pattern payload payload-budget pb-[50vh] pb-vsp-md pb-vsp-xl pb-vsp-xs per per-link permanently persisted pi pick picked picks picocolors pins pipelines pl-[1.25rem] pl-hsp-lg pl-hsp-sm pl-hsp-xl place placeholder placeholder:text-muted plain plural plus pnpm point pointer-events-none pointercancel pointerdown pointermove pointerup polite polygon polyline popover populates port position position:fixed pr-[4px] pr-hsp-lg pr-hsp-md pr-hsp-sm pr-hsp-xl pre pre-lowercased preact preact/compat preact/hooks preact/jsx-runtime preconnect prefix preload pres preserving preview preview-swatch-color previews2026 previously primary print produce produced produces producing production project project-owned project-root-relative properties property props prose provided proxy pt-[0.15rem] pt-[2px] pt-vsp-3xs pt-vsp-md pt-vsp-sm pt-vsp-xl pt-vsp-xs ptag- public purely px px-hsp-2xl px-hsp-2xs px-hsp-lg px-hsp-md px-hsp-sm px-hsp-xl px-hsp-xs py-0 py-[2px] py-[4px] py-[calc(var(--spacing-vsp-xs)+0.15rem)] py-hsp-2xs py-hsp-3xs py-hsp-sm py-hsp-xs py-vsp-2xs py-vsp-3xs py-vsp-lg py-vsp-md py-vsp-sm py-vsp-xl py-vsp-xs q query question quick r radius radius-full radius-lg rail ramp range rather raw re-encode/decode re-querying re-render re-renders re-run re-running re-selects reach reached reaches read reading real real-value received receives recorded recovers rect redefine redistribution ref- referenced references refetch refreshes regenerate regenerates regex registry reinit reinits rel relative release released reload relying rem remove removed render rendered renderer renderers renders reorder repaint repair repeated repeating replace replaced replacement replaces repopulate repository required requires reserved resize resize-x resolve resolved resolves responded response restore restores restyle result result-click results results-area retry return returns revision revisions rewrite rewrites right right- right-0 right-hsp-lg ring-2 ring-accent risking ro robots role roles root rotate-180 rotate-90 round round-trip rounded rounded-[0.75rem] rounded-bl-[0.25rem] rounded-bl-[1rem] rounded-bl-lg rounded-br-[0.25rem] rounded-br-[1rem] rounded-full rounded-lg rounded-md rounded-t-[1rem] rounds route router routes routes-src running runs runtime s safe safely safer same same-locale samp sans sans-serif scale scanned scanning scheme scoped scoping scored script script- script-eval script-evaluation script-injection scripts scroll scrollbar scrolled scrollend seam search search-index section section- see sehen select select-none selection-bg selection-fg selector self self-hosted self-start semantic semibold semver sentinel separator serialised serialize server server-rendered set sets setting setup shadow-[0_1px_3px_color-mix(in_srgb,var(--color-fg)_8%,transparent)] shadow-lg shadow-md shape share shared sharing shell shiki ship shipped ships short shortcut should show shown shrink-0 sidebar sidebar- sidebar-toggle-island sidebar-tree-island sidebar-w signal similarity simple single single-line single-object-literal singular site site-search site-tree-nav-island sitemap- sites size skill skills skipping skips slash slug slug-dir-parity sm:border sm:border-muted sm:flex-row sm:grid-cols-2 sm:h-auto sm:items-center sm:justify-between sm:max-h-[80vh] sm:max-w-[52rem] sm:mx-auto sm:my-[10vh] sm:rounded-lg small smooth snapshot snapshots so soft soft-nav solid some somehow source sources space-y-vsp-2xs spacing spacing-0 spacing-px span spans spec specifiers splitter spread spurious square sr-only src stable stack stale standalone start state state- state:state- status stay staying sticky still stock stop stored stray strict string strings strip stripe strips stroke-linecap stroke-linejoin stroke-width strong stronger style style-attribute styled styles stylesheet sub subagents subsequent substitute success successful summary sup supported surface surfaces survives svg swap swapped swaps switcher synchronous synchronously syntactically syntax t tab tab-item tab-panel tabindex table tablist tabpanel tabs tabs-container tabs-content tabs-nav tag tag- tag-item- tagged tags tags:audit take tbody td temp-element template temporary temporary-element terminal terms test-results tested text text-accent text-bg text-body text-caption text-center text-chat-assistant-text text-chat-user-text text-code-fg text-danger text-decoration text-display text-fg text-fg/60 text-heading text-info text-left text-micro text-muted text-muted/50 text-right text-scale-2xl text-scale-2xs text-scale-lg text-scale-md text-scale-sm text-scale-xl text-scale-xs text-small text-title text-warning text/css text/plain textarea tfoot th than that the thead their them theme theme-color theme-pack theme-pack-changed theme-packs theme-packs/index.json theme-toggle theme/token then there these they this those threw through throw tighten time tip title to toast toc toggle toggle-ai-chat toggle-design-token-panel toggles token tokens tolerates too toolbar tooltip top-0 top-[3.5rem] top-full top-level total touches tp tr tracked tracking-wide tracking-wider trade-off trailing transition transition-[background,color,border-color] transition-[left,color] transition-colors transition-transform translate-x-0 translated translations transparent treats tree tree-child- tree-item- tree-top- trigger trigger:ai-chat trigger:design-token-panel triggers true truncate truncated try turn twitter:card twitter:creator twitter:description twitter:image twitter:site twitter:title two type typeface typography u ul umschalten unavailable unbalanced unchanged und undefined under underline underlines understand unit-tested unknown unlike unlisted unmaintained unobserve unreadable unrelated unreleased unset unterminated until up up-to-date uppercase use used user uses usual utf-8 utf8 utilities utility v v2 val value value-reader values var variable variant verbatim version version- version-menu version-switcher versions vertical via video viewing viewport viewports virtual:zudo-doc-chrome-bindings virtual:zudo-doc-design-token-panel-config virtual:zudo-doc-route-context visible vitesse-dark vocabulary von vsp vsp-2xl vsp-2xs vsp-3xs vsp-lg vsp-md vsp-sm vsp-xl vsp-xs w w-1/2 w-10 w-48 w-72 w-[0.5rem] w-[0.625rem] w-[0.875rem] w-[1.125rem] w-[1.575rem] w-[1.5rem] w-[1.75rem] w-[14px] w-[16px] w-[16rem] w-[18px] w-[1em] w-[280px] w-[2rem] w-[320px] w-[90vw] w-[calc(100vw-2rem)] w-[var(--zd-sidebar-w)] w-dvw w-full w-icon-lg w-icon-md w-icon-sm w-icon-xs want warn warning was watching wbr wbr- we website weight went were what when where whereas whether which while whitespace-nowrap whitespace-pre whole wide wide-gamut width will wird wired with without word wordmark working worktrees would wrap wrapper wrappers written wrong wrote wurde xl:flex xl:hidden y-scrollbar yet you your z-dropdown z-local-1 z-modal z-modal-backdrop z-popover z-sidebar z-toolbar zd-content zd-desktop-sidebar-toggle zd-doc-content-band zd-enlarge-btn zd-enlarge-dialog zd-enlarge-dialog-close zd-enlargeable zd-html-preview-code zd-mermaid-dialog zd-mermaid-enlargeable zd-mermaid-tool-btn zd-mermaid-toolbar zd-mermaid-transform zd-mermaid-viewport zd-sidebar-content-wrapper zd-sidebar-open zd-theme-pack-dialog-title zfb zfb:after-swap zfb:before-preparation zod zoom zudo-design-tokens/v3 zudo-doc zudo-doc-design-token-panel-modal zudo-doc-design-tokens zudo-doc-sidebar-visible zudo-doc-sidebar-width zudo-doc-theme zudo-doc-theme-pack zudo-doc-tweak zum");
2
+ @source inline("-link -mb-px -ml-hsp-sm -noscript -open -translate-x-full 2xl:w-[24px] [&::-webkit-details-marker]:hidden [&_a]:text-accent [&_a]:underline [&_nav]:mb-0 [data-admonition] [data-kbd-shortcut] [data-switcher-launcher] [doc-history-meta] [doc-history] [doc-layout] [llms-txt] [zudo-doc] a a2 abbr about above absent absolute accent accent- accent:accent- across activated active actual added admonition admonition- admonition-body admonition-title admonition/callout after after-breadcrumb after-content after-navigate after-sidebar after-title against agent agents ai-chat ai-chat-md ai-chat-trigger alert align-top all allow-same-origin allow-scripts allowed alone already already-executed already-multiline already-picked also always an anchor and and/or animate-pulse animate-spin announce ansehen antialiased any anywhere anzeigen app appear application/json application/xml applied applies apply approach are area arg argument aria-atomic aria-busy aria-controls aria-current aria-disabled aria-expanded aria-haspopup aria-hidden aria-label aria-labelledby aria-live aria-orientation aria-pressed aria-selected aria-valuemax aria-valuemin aria-valuenow arm arms arrows article as asc aside aspect-[1200/630] aspect-square asset- assets assistant async at attach attribute attributes auf authored auto autogenerated available avoid await away b back backdrop:bg-bg/30 backdrop:bg-bg/80 backdrop:bg-overlay/60 backdrop:z-modal-backdrop background background-color backtick backticks baked banner bare base base- base64 base:base- based batch be bearbeiten because been before below best between bg bg-[#fff] bg-accent bg-bg bg-chat-assistant-bg bg-chat-user-bg bg-code-bg bg-fg bg-info/10 bg-info/5 bg-muted bg-overlay/30 bg-surface bg-surface/50 bg-transparent bg-warning/10 bg-warning/5 bi bigint bin binaries bind blank blanks block blockquote blocks blur body body-end-components body-end-scripts bold boolean bootstrap border border-accent border-b border-b-2 border-b-[5px] border-bg/30 border-collapse border-danger border-dashed border-fg border-image border-info/30 border-l border-l-0 border-l-[3px] border-left-width border-muted border-none border-r border-radius border-solid border-t border-t-[2px] border-t-[3px] border-transparent border-warning/30 border-width border-y both bottom-hsp-lg bottom-vsp-xl boundaries box-border br brackets brand breadcrumb:end breadcrumb:start break-words brown browser browsers btn budget bug build built built-in bundler but button buttons by bypassed byte-identical bytes cached call callable called caller calls can cancellation cannot canonical canvas caption card card-grid carry cases cat-nav- catch category caught caution center center/contain ch chains change changed changelog changelogs changes child choose chrome chrome-font ci circle cite class class-less class-mode claude claude-agents claude-commands claude-md claude-skills cleaned clear clearing click client client-router client-side clip clobbering close closed closing code code-block-sr-announce code-group code-group-panel col col-resize colgroup collapses collapsible collision color color-scheme color-scheme-changed color-scheme-provider color-tweak colorization colors column comma command commands comment commercial commercial-font-denylist commit compare component component:github-link component:language-switcher component:search component:theme-toggle component:version-switcher composition compute computed concrete config configuration configure configured confuse connect const construction consumer consumes container containers containing contains content content-admonition content-layer content-link content-type content-wrapper:end content-wrapper:start contents context contract controller controls converts copied copy corners correct correctly corrupt could count covered covers cp crashes created cross-component crumb- cs css css-presence ctx cur current cursor-not-allowed cursor-pointer custom danger dark data data-active data-admonition data-base data-close-search data-current-locale data-default-locale data-doc-description data-doc-pager data-find-active data-find-match data-footer data-group-id data-header data-header-logo data-header-nav data-header-right data-kbd-shortcut data-language-switcher data-loading-index data-mermaid-enlarge-ready data-mermaid-rendered data-mermaid-src data-nav-active data-nav-item data-nav-item-dropdown data-nav-more data-nav-more-menu data-nav-more-toggle data-no-results data-open-search data-pan-active data-processed data-result-count-template data-search-count data-search-count-narrow data-search-dialog data-search-input data-search-placeholder data-search-results data-search-unavailable data-sidebar-hidden data-sidebar-resizer data-site-nav data-switcher-card data-switcher-launcher data-tab-btn data-tab-default data-tab-label data-tab-value data-tabs data-taglist-group data-testid data-theme data-theme-pack data-theme-pack-switcher data-theme/style data-trailing-slash data-variant data-version-banner data-version-latest data-version-menu data-version-rewire data-version-slug data-version-switcher data-version-toggle data-version-trigger-label data-zd-mobile-sidebar data-zd-mobile-toc data-zd-nosidebar data-zd-theme-pack-css data-zd-theme-pack-css-loading data-zd-toc data-zd-wide data-zfb-transition-persist dd decimal declaration declare declares decoration decoration-muted default default-transition-duration defaults del delegated delete dependency depth der desc description design design-token-panel design-token-trigger desktop desktop-sidebar desktop-sidebar-toggle desktop-sidebar-toggle-island destructive detach detached details determine deterministic dev develop dfn diagram diagrams dialog die dieser diff diff-line-added diff-line-content diff-line-empty diff-line-num diff-line-removed diff-row different dir directly directories directory disabled disabled:opacity-50 disabled:pointer-events-none disc display display:none dist distinct div dl do doc doc-card- doc-content-band doc-history doc-history-generate doc-history-panel doc-history-trigger doc-page doc-pager doc-prose doc-title docs docs- docs-v- document document-level documentation documented does dog double-registration draft drag draggable drawer drifts drop dropdown dropdown-child dropdown-parent dropdowns dt duplicate duration-150 duration-200 during dynamically e2e each ease-in-out edge einer eject ejectable ejectables ejected el element elements els else em embedded emit emitting empty empty/undefined en enable enabled end enlarged entire entities entries entry equal error escape escaped even eventually every exactly exceeds excerpt excludes exclusively existing exists exit expected export extends f factories failed fall fallback fallbacks falling falls false family fast feature fg field fields fieldset figcaption figure file fill fills finally find find-match find-match-active fire fires first fixed fixed-width fixtures flag flash flat flex flex-1 flex-col flex-wrap flip flipping flips flush-left focus focus-visible:outline-2 focus-visible:outline-accent focus-visible:outline-offset-2 focus-visible:underline focus:border-accent focus:outline-none focus:underline font font-bold font-face-parity font-family font-file-missing font-medium font-mono font-sans font-scale font-semibold font-size font-weight font-weight-bold font-weight-medium font-weight-normal font-weight-semibold font/woff2 fonts footer footer- for form format found fox free fresh from frontmatter frontmatter-preview frozen fs-extra full fully function further g gap-[0.3em] gap-[clamp(1.5rem,3vw,4rem)] gap-hsp-2xs gap-hsp-lg gap-hsp-md gap-hsp-sm gap-hsp-xl gap-hsp-xs gap-vsp-2xs gap-vsp-3xs gap-vsp-lg gap-vsp-md gap-vsp-xs gap-x-hsp-2xs gap-x-hsp-lg gap-x-hsp-md gap-x-hsp-sm gap-x-hsp-xs gap-y-vsp-2xs gap-y-vsp-lg gap-y-vsp-md gap-y-vsp-xs gaps gate geladen2026 generate generated generation genuine geometry get github github-dark github-link give go got gradient granular graph gray-matter grid grid-cols-1 grid-cols-2 group group-focus-visible:text-accent group-focus-visible:underline group-focus-within:block group-hover:bg-fg group-hover:block group-hover:text-accent group-hover:text-bg group-hover:underline group-open:rotate-90 guard h-10 h-40 h-[0.5rem] h-[0.625rem] h-[0.875rem] h-[1.125rem] h-[1.25rem] h-[1.575rem] h-[14px] h-[1em] h-[1lh] h-[2rem] h-[3.5rem] h-[3rem] h-[90vh] h-[calc(100%-3rem)] h-[calc(100vh-3.5rem)] h-dvh h-full h-icon-lg h-icon-md h-icon-sm h-icon-xs h1 h1s h2 h22013h4 h2s h3 h4 h5 h6 half hand-copied hand-editable handle handled handler handlers hardcoded has hash-link have head head-links head-scripts header header- header-call:end header-call:start header-right heading heading-h2 heading-h3 heading-h4 heading-rule headings height here hex hidden hierarchical highlight history hit home horizontal host hover:bg-[color-mix(in_srgb,var(--color-surface)_80%,var(--color-fg)_20%)] hover:bg-accent-hover hover:bg-accent/10 hover:bg-danger/10 hover:bg-surface hover:border-accent hover:border-accent-hover hover:border-fg hover:text-accent hover:text-accent-hover hover:text-fg hover:underline hr href hrefs hsp hsp-2xl hsp-2xs hsp-lg hsp-md hsp-sm hsp-xl hsp-xs html i i18n/theme. i2 i3 i4 icon icon-lg icon-md icon-sm icon-xs identical idle idx if iframe image image-enlarge image-overlay-inset image/png img implementation import important important-allowlist imports in inactive inbox includes incomplete independently index index2026 info inherit inherited initial initialised injected inline inline-block inline-flex inner input input-clear ins inserted-after-color-mode inserted-after-color-scheme inserted-first inset-0 inside install installation installed instance instanceof instead instructions intended intent internal interpolation into invalid inverse inversion invoke is island-root issues it italic item item- items items-baseline items-center items-end items-start its itself javascript jumps justify-between justify-center justify-end justify-start katex kbd keep keeping keeps keyboard keyboard-shortcut keydown keys keystroke keyword keywords khroma known-token-names kopieren label landing language-switcher last:border-b-0 later latest launch layout lazy leading-normal leading-relaxed leading-snug leading-tight leaf- leak leaves left left-0 left:calc legend legitimate length lets letter-spacing lg lg:block lg:border lg:border-fg lg:border-solid lg:flex lg:flex-col lg:flex-row lg:gap-hsp-xl lg:grid-cols-3 lg:grid-cols-[repeat(auto-fit,minmax(12rem,1fr))] lg:h-[90vh] lg:hidden lg:justify-start lg:m-auto lg:max-h-[90vh] lg:max-w-[52.5rem] lg:ml-[var(--zd-sidebar-w)] lg:pt-vsp-2xl lg:px-hsp-2xl lg:py-vsp-2xl lg:text-left lg:w-[90vw] lg:w-[clamp(16rem,25%,22rem)] li li2 library license light light/dark like likely line line-height line/statement linger link link- links list list-disc list-none listener lists literal literals lives llms llms-txt load loaded loading local local-1 local-2 local-3 locale locales log longer longest-match look lostpointercapture lower luminance m m-0 m-auto m21 m6 machinery main major make malformed malicious manually maps mark marks match matches matching math math-display math-inline max max-h-[85vh] max-h-[90vh] max-h-full max-h-none max-w-[64rem] max-w-[85%] max-w-[85vw] max-w-[90vw] max-w-[calc(100vw-2rem)] max-w-[clamp(50rem,75vw,90rem)] max-w-full max-w-none max-w-sm max-width may mb-0 mb-vsp-2xs mb-vsp-lg mb-vsp-md mb-vsp-sm mb-vsp-xl mb-vsp-xs measures measuring mechanism menu mermaid message messages meta meta-knob meta-schema metadata migration min-h-0 min-h-[60vh] min-h-[calc(100vh-3.5rem)] min-h-screen min-w-0 min-w-[10rem] min-w-[3rem] min-w-[8rem] minifier minor mirror mirrors missing mit ml-auto ml-hsp-2xl ml-hsp-lg ml-hsp-sm ml-hsp-xl mobile mod modal modal-backdrop mode modify module monospace more most mounted mouseenter mouseleave move mr-hsp-sm ms mt-0 mt-vsp-2xl mt-vsp-2xs mt-vsp-3xs mt-vsp-lg mt-vsp-md mt-vsp-xl must mutates mutation mutations muted mx-auto my-vsp-lg my-vsp-md n name named names native nav nav-active nav-card- nav/doc navigating navigation navigations near needs neither nested neutral new newly-swapped next nicht no no-color-scheme no-data-theme-selector no-enlarge no-op no-repeat no-underline noch node node:buffer node:fs node:fs/promises node:module node:path node:url nodes nofollow noindex non-empty non-light-dark non-literal non-persisted none noopener noreferrer normal noscript not notable note notes now null number numeric object object-contain observe observer occurred of off ofl-required og:description og:image og:image:alt og:image:height og:image:width og:title og:type og:url oklch ol old older on once one only onto opacity-60 open open/close option or original other others out outgoing outline-none over overflow overflow-auto overflow-hidden overflow-x-auto overflow-y-auto overflow-y:auto override overrides overscroll-contain overwrite own owned p p-0 p-hsp-2xs p-hsp-lg p-hsp-md p-hsp-sm pack package package-owned packages packs padding page page-loading page-loading-overlay page-loading-spinner page-navigate-end page-title pages pages/. paint paint-and-read palette pan panel panels paren-balance-aware parent parse parsed parser parses part pass passed passes patch path paths pattern payload payload-budget pb-[50vh] pb-vsp-md pb-vsp-xl pb-vsp-xs per per-link permanently persisted pi pick picked picks picocolors pins pipelines pl-[1.25rem] pl-hsp-lg pl-hsp-sm pl-hsp-xl place placeholder placeholder:text-muted plain plural plus pnpm point pointer-events-none pointercancel pointerdown pointermove pointerup polite polygon polyline popover populates port position position:fixed pr-[4px] pr-hsp-lg pr-hsp-md pr-hsp-sm pr-hsp-xl pre pre-lowercased preact preact/compat preact/hooks preact/jsx-runtime preconnect prefix preload pres present preserving preview preview-swatch-color previews2026 previously primary print produce produced produces producing production project project-owned project-root-relative properties property props prose provided proxy pt-[0.15rem] pt-[2px] pt-vsp-3xs pt-vsp-md pt-vsp-sm pt-vsp-xl pt-vsp-xs ptag- public purely px px-hsp-2xl px-hsp-2xs px-hsp-lg px-hsp-md px-hsp-sm px-hsp-xl px-hsp-xs py-0 py-[2px] py-[4px] py-[calc(var(--spacing-vsp-xs)+0.15rem)] py-hsp-2xs py-hsp-3xs py-hsp-sm py-hsp-xs py-vsp-2xs py-vsp-3xs py-vsp-lg py-vsp-md py-vsp-sm py-vsp-xl py-vsp-xs q query question quick r radius radius-full radius-lg rail ramp range rather raw re-encode/decode re-querying re-render re-renders re-run re-running re-selects reach reached reaches read reading real real-value received receives recorded recovers rect redefine redistribution ref- referenced references refetch refreshes regenerate regenerates regex registry reinit reinits rel relative release released reload relying rem remove removed render rendered renderer renderers renders reorder repaint repair repeated repeating replace replaced replacement replaces repopulate repository required requires reserved resize resize-x resolve resolved resolves responded response restore restores restyle result result-click results results-area retry return returns revision revisions rewrite rewrites right right- right-0 right-hsp-lg ring-2 ring-accent risking ro robots role roles root rotate-180 rotate-90 round round-trip rounded rounded-[0.75rem] rounded-bl-[0.25rem] rounded-bl-[1rem] rounded-bl-lg rounded-br-[0.25rem] rounded-br-[1rem] rounded-full rounded-lg rounded-md rounded-t-[1rem] rounds route router routes routes-src running runs runtime s safe safely safer same same-locale samp sans sans-serif scale scanned scanning scheme scoped scoping scored script script- script-eval script-evaluation script-injection scripts scroll scrollbar scrolled scrollend seam search search-index section section- see sehen select select-none selection-bg selection-fg selector self self-hosted self-start semantic semibold semver sentinel separator serialised serialize server server-rendered set sets setting setup shadow-[0_1px_3px_color-mix(in_srgb,var(--color-fg)_8%,transparent)] shadow-lg shadow-md shape share shared sharing shell ship shipped ships short shortcut should show shown shrink-0 sidebar sidebar- sidebar-toggle-island sidebar-tree-island sidebar-w signal silently similarity simple single single-line single-object-literal singular site site-search site-tree-nav-island sitemap- sites size skill skills skipping skips slash slug slug-dir-parity sm:border sm:border-muted sm:flex-row sm:grid-cols-2 sm:h-auto sm:items-center sm:justify-between sm:max-h-[80vh] sm:max-w-[52rem] sm:mx-auto sm:my-[10vh] sm:rounded-lg small smooth snapshot snapshots so soft soft-nav solid some somehow source sources space-y-vsp-2xs spacing spacing-0 spacing-px span spans spec specifiers splitter spread spurious square sr-only src stable stack stale standalone start state state- state:state- status stay staying sticky still stock stop stored stray strict string strings strip stripe strips stroke-linecap stroke-linejoin stroke-width strong stronger style style-attribute styled styles stylesheet sub subagents subsequent substitute success successful summary sup supported surface surfaces survives svg swap swapped swaps switcher synchronous synchronously syntactically syntax t tab tab-item tab-panel tabindex table tablist tabpanel tabs tabs-container tabs-content tabs-nav tag tag- tag-item- tagged tags tags:audit take tbody td temp-element template temporary temporary-element terminal terms test-results tested text text-accent text-bg text-body text-caption text-center text-chat-assistant-text text-chat-user-text text-code-fg text-danger text-decoration text-display text-fg text-fg/60 text-heading text-info text-left text-micro text-muted text-muted/50 text-right text-scale-2xl text-scale-2xs text-scale-lg text-scale-md text-scale-sm text-scale-xl text-scale-xs text-small text-title text-warning text/css text/plain textarea tfoot th than that the thead their them theme theme-color theme-pack theme-pack-changed theme-packs theme-packs/index.json theme-toggle theme/token then there these they this those threw through throw tighten time tip title to toast toc toggle toggle-ai-chat toggle-design-token-panel toggles token tokens tolerates too toolbar tooltip top-0 top-[3.5rem] top-full top-level total touches tp tr tracked tracking-wide tracking-wider trade-off trailing transition transition-[background,color,border-color] transition-[left,color] transition-colors transition-transform translate-x-0 translated translations transparent treats tree tree-child- tree-item- tree-top- trigger trigger:ai-chat trigger:design-token-panel triggers true truncate truncated try turn twitter:card twitter:creator twitter:description twitter:image twitter:site twitter:title two type typeface typography u ul umschalten unavailable unbalanced unchanged und undefined under underline underlines understand unit-tested unknown unlike unlisted unmaintained unobserve unreadable unrelated unreleased unset unterminated until up up-to-date uppercase use used user uses usual utf-8 utf8 utilities utility v v2 val value value-reader values var variable variant verbatim version version- version-menu version-switcher versions vertical via video viewing viewport viewports virtual:zudo-doc-chrome-bindings virtual:zudo-doc-design-token-panel-config virtual:zudo-doc-route-context visible vocabulary von vsp vsp-2xl vsp-2xs vsp-3xs vsp-lg vsp-md vsp-sm vsp-xl vsp-xs w w-1/2 w-10 w-48 w-72 w-[0.5rem] w-[0.625rem] w-[0.875rem] w-[1.125rem] w-[1.575rem] w-[1.5rem] w-[1.75rem] w-[14px] w-[16px] w-[16rem] w-[18px] w-[1em] w-[280px] w-[2rem] w-[320px] w-[90vw] w-[calc(100vw-2rem)] w-[var(--zd-sidebar-w)] w-dvw w-full w-icon-lg w-icon-md w-icon-sm w-icon-xs want warn warning was watching wbr wbr- we website weight went were what when where whereas whether which while whitespace-nowrap whitespace-pre whole wide wide-gamut width will wird wired with without word wordmark working worktrees would wrap wrapper wrappers written wrong wrote wurde xl:flex xl:hidden y-scrollbar yet you your z-dropdown z-local-1 z-modal z-modal-backdrop z-popover z-sidebar z-toolbar zd-content zd-desktop-sidebar-toggle zd-doc-content-band zd-enlarge-btn zd-enlarge-dialog zd-enlarge-dialog-close zd-enlargeable zd-html-preview-code zd-mermaid-dialog zd-mermaid-enlargeable zd-mermaid-tool-btn zd-mermaid-toolbar zd-mermaid-transform zd-mermaid-viewport zd-sidebar-content-wrapper zd-sidebar-open zd-theme-pack-dialog-title zfb zfb:after-swap zfb:before-preparation zod zoom zudo-design-tokens/v3 zudo-doc zudo-doc-design-token-panel-modal zudo-doc-design-tokens zudo-doc-sidebar-visible zudo-doc-sidebar-width zudo-doc-theme zudo-doc-theme-pack zudo-doc-tweak zum");
@@ -154,6 +154,11 @@ export interface FrontmatterPreviewConfig {
154
154
  */
155
155
  extraIgnoreKeys?: string[];
156
156
  }
157
+ /** Home-page layout options used by the package-owned root and locale routes. */
158
+ export interface HomeConfig {
159
+ /** Widen the home content band for larger multi-column navigation grids. */
160
+ wide?: boolean;
161
+ }
157
162
  export type TagPlacement = "after-title" | "before-pager";
158
163
  export interface VersionConfig {
159
164
  /** Version identifier, used in URL path (e.g., "1.0", "v1") */
@@ -256,6 +261,8 @@ export interface Settings {
256
261
  siteDescription: string;
257
262
  base: string;
258
263
  trailingSlash: boolean;
264
+ /** Package-owned home-page layout. Narrow when omitted. */
265
+ home?: HomeConfig;
259
266
  /** Minify production HTML output from `zfb build`. Defaults to `true` when omitted. */
260
267
  minifyHtml?: boolean;
261
268
  docsDir: string;
@@ -310,6 +317,7 @@ export interface Settings {
310
317
  dynamicPageTransition: boolean;
311
318
  frontmatterPreview: FrontmatterPreviewConfig | false;
312
319
  docHistory: boolean;
320
+ docHistoryExclude: string[];
313
321
  bodyFootUtilArea: BodyFootUtilAreaConfig | false;
314
322
  htmlPreview: HtmlPreviewConfig | undefined;
315
323
  versions: VersionConfig[] | false;
@@ -292,9 +292,8 @@ html[data-theme-pack="hearth"] .zd-content blockquote {
292
292
  color: light-dark(oklch(0.38 0.052 42), oklch(0.83 0.032 70));
293
293
  }
294
294
 
295
- /* admonitions: soft-cornered, warm-shadowed, hearth icon swaps on
296
- the prototype's three variants (candle / coffee / fire); the other
297
- four variants keep the stock icons */
295
+ /* admonitions: soft-cornered, warm-shadowed, with a distinct icon
296
+ from the hearth and fireside vocabulary for every variant */
298
297
  html[data-theme-pack="hearth"] [data-admonition] {
299
298
  box-shadow: 0 8px 18px -14px light-dark(oklch(0.42 0.09 45 / 0.2), oklch(0.05 0.01 45 / 0.6));
300
299
  }
@@ -304,9 +303,21 @@ html[data-theme-pack="hearth"] [data-admonition="note"] .admonition-title::befor
304
303
  html[data-theme-pack="hearth"] [data-admonition="tip"] .admonition-title::before {
305
304
  content: "☕ ";
306
305
  }
306
+ html[data-theme-pack="hearth"] [data-admonition="info"] .admonition-title::before {
307
+ content: "📜 ";
308
+ }
307
309
  html[data-theme-pack="hearth"] [data-admonition="warning"] .admonition-title::before {
308
310
  content: "🔥 ";
309
311
  }
312
+ html[data-theme-pack="hearth"] [data-admonition="important"] .admonition-title::before {
313
+ content: "🔔 ";
314
+ }
315
+ html[data-theme-pack="hearth"] [data-admonition="danger"] .admonition-title::before {
316
+ content: "🧯 ";
317
+ }
318
+ html[data-theme-pack="hearth"] [data-admonition="caution"] .admonition-title::before {
319
+ content: "♨️ ";
320
+ }
310
321
 
311
322
  /* table: brick Fraunces header over an accent rule, warm row hover */
312
323
  html[data-theme-pack="hearth"] .zd-content th {
@@ -174,6 +174,25 @@ function checkFontFaceParity(cssContent, meta, issues) {
174
174
  }
175
175
  }
176
176
  }
177
+ function checkFontFileExistence(cssContent, fontFiles, issues) {
178
+ const availableFiles = new Set(fontFiles);
179
+ const urlRe = /url\(\s*(?:"([^"]*)"|'([^']*)'|([^)]*))\s*\)/gi;
180
+ for (const rule of parseTopLevelRules(cssContent)) {
181
+ if (!isFontFaceRule(rule)) continue;
182
+ let match;
183
+ while ((match = urlRe.exec(rule.body)) !== null) {
184
+ const url = (match[1] ?? match[2] ?? match[3] ?? "").trim();
185
+ if (!url.startsWith("./fonts/") || /[?#]/.test(url)) continue;
186
+ const basename = url.slice("./fonts/".length).split("/").pop();
187
+ if (!basename || availableFiles.has(basename)) continue;
188
+ issues.push({
189
+ rule: "font-file-missing",
190
+ severity: "error",
191
+ message: `@font-face references "${url}" but "${basename}" is not present in fonts/`
192
+ });
193
+ }
194
+ }
195
+ }
177
196
  function isPlainColorValue(value) {
178
197
  const v = value.trim();
179
198
  if (/var\(|light-dark\(/i.test(v)) return false;
@@ -206,7 +225,10 @@ function checkPreviewSwatches(meta, issues) {
206
225
  }
207
226
  }
208
227
  function checkCommercialDenylist(cssContent, meta, issues) {
209
- const scannedCss = (cssContent ?? "").replace(/\[data-theme-pack="[^"]*"\]/g, "");
228
+ const scannedCss = stripComments(cssContent ?? "").replace(
229
+ /\[data-theme-pack="[^"]*"\]/g,
230
+ ""
231
+ );
210
232
  const haystack = [
211
233
  scannedCss,
212
234
  meta.fonts.sans,
@@ -268,6 +290,7 @@ function validateThemePack(input) {
268
290
  checkImportantAllowlist(input.cssContent, issues);
269
291
  checkNoColorScheme(input.cssContent, issues);
270
292
  checkNoDataThemeSelector(input.cssContent, issues);
293
+ checkFontFileExistence(input.cssContent, input.fontFiles, issues);
271
294
  }
272
295
  if (meta) {
273
296
  checkFontFaceParity(input.cssContent, meta, issues);
package/dist/theme.css CHANGED
@@ -211,7 +211,7 @@
211
211
  * GENERATED:Z_INDEX block that used to live in every project's global.css is
212
212
  * now opt-in customization only, not a mandatory per-project artifact.
213
213
  * ======================================== */
214
- @theme {
214
+ @theme inline {
215
215
  --z-index-content: 0;
216
216
  --z-index-local-1: 1;
217
217
  --z-index-local-2: 2;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takazudo/zudo-doc",
3
- "version": "4.2.1",
3
+ "version": "4.3.0",
4
4
  "type": "module",
5
5
  "description": "zudo-doc framework primitives layer that sits on top of zfb's engine — sidebar, theme, TOC, breadcrumb, layouts, head injection, View Transitions, SSR-skip wrappers (per ADR-003).",
6
6
  "license": "MIT",
@@ -596,7 +596,6 @@
596
596
  "diff": "^8.0.0",
597
597
  "katex": "^0.16.0",
598
598
  "preact": "^10.29.1",
599
- "shiki": "^4.0.2",
600
599
  "zod": "^4.3.6"
601
600
  },
602
601
  "peerDependenciesMeta": {
@@ -609,9 +608,6 @@
609
608
  "@takazudo/zfb-md-wasm": {
610
609
  "optional": true
611
610
  },
612
- "shiki": {
613
- "optional": true
614
- },
615
611
  "katex": {
616
612
  "optional": true
617
613
  },
@@ -642,12 +638,11 @@
642
638
  "happy-dom": "^20.10.6",
643
639
  "preact": "^10.29.1",
644
640
  "preact-render-to-string": "^6.6.6",
645
- "shiki": "^4.0.2",
646
641
  "tsup": "^8.0.0",
647
642
  "typescript": "^5.0.0",
648
643
  "vitest": "^4.1.0",
649
644
  "zod": "^4.3.6",
650
- "@takazudo/zudo-doc-history-server": "4.2.1"
645
+ "@takazudo/zudo-doc-history-server": "4.3.0"
651
646
  },
652
647
  "scripts": {
653
648
  "build": "tsup && tsc -p tsconfig.build.json",
@@ -11,7 +11,7 @@
11
11
  // the result to the shared home body factory.
12
12
 
13
13
  import type { JSX } from "preact";
14
- import { defaultLocale, routeCtx } from "./_context.js";
14
+ import { defaultLocale, routeCtx, settings } from "./_context.js";
15
15
  import { prepareHomeData } from "@takazudo/zudo-doc/home-page";
16
16
  import { HomePageView } from "./_chrome.js";
17
17
 
@@ -23,6 +23,12 @@ export default function IndexPage(): JSX.Element {
23
23
  const { tree, categoryOrder, tagCount } = prepareHomeData(routeCtx, locale);
24
24
 
25
25
  return (
26
- <HomePageView locale={locale} tree={tree} categoryOrder={categoryOrder} tagCount={tagCount} />
26
+ <HomePageView
27
+ locale={locale}
28
+ tree={tree}
29
+ categoryOrder={categoryOrder}
30
+ tagCount={tagCount}
31
+ wide={settings.home?.wide ?? false}
32
+ />
27
33
  );
28
34
  }
@@ -37,6 +37,12 @@ export default function LocaleIndexPage({ params }: PageArgs): JSX.Element {
37
37
  const { tree, categoryOrder, tagCount } = prepareHomeData(routeCtx, locale);
38
38
 
39
39
  return (
40
- <HomePageView locale={locale} tree={tree} categoryOrder={categoryOrder} tagCount={tagCount} />
40
+ <HomePageView
41
+ locale={locale}
42
+ tree={tree}
43
+ categoryOrder={categoryOrder}
44
+ tagCount={tagCount}
45
+ wide={settings.home?.wide ?? false}
46
+ />
41
47
  );
42
48
  }