@takazudo/zudo-doc 5.13.0 → 5.14.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 (110) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/bin/run-parallel.mjs +272 -0
  3. package/bin/tags-suggest-runner.ts +7 -3
  4. package/dist/asset-components/asset-card.d.ts +10 -0
  5. package/dist/asset-components/asset-card.js +91 -0
  6. package/dist/asset-components/asset-code.d.ts +10 -0
  7. package/dist/asset-components/asset-code.js +93 -0
  8. package/dist/asset-components/index.d.ts +3 -0
  9. package/dist/asset-components/index.js +12 -0
  10. package/dist/asset-components/shared.d.ts +25 -0
  11. package/dist/asset-components/shared.js +89 -0
  12. package/dist/asset-index-page/index.d.ts +21 -0
  13. package/dist/asset-index-page/index.js +175 -0
  14. package/dist/asset-index-page/script.d.ts +2 -0
  15. package/dist/asset-index-page/script.js +4 -0
  16. package/dist/asset-page/index.d.ts +67 -0
  17. package/dist/asset-page/index.js +244 -0
  18. package/dist/asset-page/script.d.ts +2 -0
  19. package/dist/asset-page/script.js +4 -0
  20. package/dist/asset-path/index.d.ts +53 -0
  21. package/dist/asset-path/index.js +149 -0
  22. package/dist/chrome/derive.js +45 -9
  23. package/dist/chrome/index.d.ts +2 -0
  24. package/dist/chrome/index.js +7 -1
  25. package/dist/chrome-bindings.d.ts +4 -0
  26. package/dist/client-router/raw-link-attrs.d.ts +8 -0
  27. package/dist/client-router/raw-link-attrs.js +6 -0
  28. package/dist/compiled.css +135 -0
  29. package/dist/config.d.ts +13 -2
  30. package/dist/config.js +36 -1
  31. package/dist/content/content-link.d.ts +12 -0
  32. package/dist/content/content-link.js +43 -2
  33. package/dist/content/index.d.ts +1 -1
  34. package/dist/content/index.js +5 -1
  35. package/dist/doc-body-end-islands/index.d.ts +2 -0
  36. package/dist/doc-body-end-islands/index.js +3 -2
  37. package/dist/doclayout/doc-layout-with-defaults.d.ts +1 -1
  38. package/dist/doclayout/doc-layout-with-defaults.js +1 -1
  39. package/dist/eject/index.js +8 -0
  40. package/dist/factory-context/index.d.ts +3 -1
  41. package/dist/features.css +124 -3
  42. package/dist/frontmatter/index.d.ts +56 -0
  43. package/dist/frontmatter/index.js +61 -0
  44. package/dist/header/header.js +11 -1
  45. package/dist/header/nav-class-tokens.d.ts +2 -0
  46. package/dist/header/nav-class-tokens.js +8 -0
  47. package/dist/header/nav-overflow-generated-script.js +47 -2
  48. package/dist/header-with-defaults/index.d.ts +2 -0
  49. package/dist/header-with-defaults/index.js +3 -2
  50. package/dist/i18n-defaults/index.d.ts +3 -2
  51. package/dist/i18n-defaults/index.js +44 -0
  52. package/dist/icons/index.d.ts +9 -0
  53. package/dist/icons/index.js +246 -0
  54. package/dist/md-utils/index.js +1 -1
  55. package/dist/mdx-components/index.d.ts +4 -1
  56. package/dist/mdx-components/index.js +80 -7
  57. package/dist/plugins/internal/asset-viewer/build.d.ts +25 -0
  58. package/dist/plugins/internal/asset-viewer/build.js +118 -0
  59. package/dist/plugins/internal/asset-viewer/git-meta.d.ts +7 -0
  60. package/dist/plugins/internal/asset-viewer/git-meta.js +40 -0
  61. package/dist/plugins/internal/asset-viewer/highlight.d.ts +34 -0
  62. package/dist/plugins/internal/asset-viewer/highlight.js +181 -0
  63. package/dist/plugins/internal/asset-viewer/link-graph.d.ts +34 -0
  64. package/dist/plugins/internal/asset-viewer/link-graph.js +193 -0
  65. package/dist/plugins/internal/asset-viewer/probe.d.ts +13 -0
  66. package/dist/plugins/internal/asset-viewer/probe.js +322 -0
  67. package/dist/plugins/internal/asset-viewer/scan.d.ts +2 -0
  68. package/dist/plugins/internal/asset-viewer/scan.js +77 -0
  69. package/dist/plugins/internal/asset-viewer/sidecar.d.ts +6 -0
  70. package/dist/plugins/internal/asset-viewer/sidecar.js +34 -0
  71. package/dist/plugins/internal/asset-viewer/types.d.ts +22 -0
  72. package/dist/plugins/internal/asset-viewer/types.js +0 -0
  73. package/dist/plugins/internal/codex-resources/skills.js +1 -1
  74. package/dist/plugins/internal/llms-txt/load.d.ts +1 -1
  75. package/dist/plugins/internal/resource-docs-shared/mdx.d.ts +1 -2
  76. package/dist/plugins/internal/resource-docs-shared/mdx.js +1 -1
  77. package/dist/plugins/routes.js +146 -11
  78. package/dist/preset.d.ts +10 -0
  79. package/dist/preset.js +20 -3
  80. package/dist/route-context/index.js +18 -2
  81. package/dist/route-context-payload/index.d.ts +6 -2
  82. package/dist/route-context-payload/index.js +2 -1
  83. package/dist/route-context-payload/types.d.ts +37 -0
  84. package/dist/routes/_chrome.d.ts +1 -1
  85. package/dist/routes/_chrome.js +5 -1
  86. package/dist/routes/_context.d.ts +2 -0
  87. package/dist/routes/_context.js +2 -0
  88. package/dist/routes/files-path.d.ts +22 -0
  89. package/dist/routes/files-path.js +31 -0
  90. package/dist/safelist.css +1 -1
  91. package/dist/settings.d.ts +10 -0
  92. package/dist/sidebar-tree-island/index.js +2 -2
  93. package/dist/site-tree-nav-island/index.js +3 -3
  94. package/dist/tags-audit.js +1 -1
  95. package/eject/asset-components/asset-card.tsx +106 -0
  96. package/eject/asset-components/asset-code.tsx +127 -0
  97. package/eject/asset-components/index.ts +7 -0
  98. package/eject/asset-components/shared.tsx +113 -0
  99. package/eject/header/gen-nav-overflow-script.mjs +53 -4
  100. package/eject/header/header.tsx +11 -1
  101. package/eject/header/nav-class-tokens.ts +12 -0
  102. package/eject/header/nav-overflow-generated-script.ts +1 -1
  103. package/eject/sidebar-tree-island/index.tsx +3 -3
  104. package/eject/site-tree-nav-island/index.tsx +4 -4
  105. package/package.json +34 -14
  106. package/routes-src/_chrome.tsx +2 -0
  107. package/routes-src/_context.ts +2 -0
  108. package/routes-src/_virtual.d.ts +6 -0
  109. package/routes-src/files-path.tsx +43 -0
  110. package/virtual-modules.d.ts +6 -0
@@ -2,7 +2,10 @@ import { HeadingH2 } from "./heading-h2.js";
2
2
  import { HeadingH3 } from "./heading-h3.js";
3
3
  import { HeadingH4 } from "./heading-h4.js";
4
4
  import { ContentParagraph } from "./content-paragraph.js";
5
- import { ContentLink } from "./content-link.js";
5
+ import {
6
+ ContentLink,
7
+ createContentLink
8
+ } from "./content-link.js";
6
9
  import { ContentStrong } from "./content-strong.js";
7
10
  import { ContentBlockquote } from "./content-blockquote.js";
8
11
  import { ContentUl } from "./content-ul.js";
@@ -22,5 +25,6 @@ export {
22
25
  HeadingH2,
23
26
  HeadingH3,
24
27
  HeadingH4,
28
+ createContentLink,
25
29
  defaultComponents
26
30
  };
@@ -80,6 +80,8 @@ export interface BodyEndIslandsProps {
80
80
  * screen readers announce the chat entrypoint correctly before hydration.
81
81
  */
82
82
  aiChatBodyLabel?: string;
83
+ /** Force the ImageEnlarge island for a page-owned enlargeable image. */
84
+ forceImageEnlarge?: boolean;
83
85
  }
84
86
  /**
85
87
  * Build the package-default `BodyEndIslands` component bound to the host's
@@ -22,7 +22,8 @@ function createBodyEndIslands(deps) {
22
22
  });
23
23
  function BodyEndIslands({
24
24
  basePath,
25
- aiChatBodyLabel = DEFAULT_AI_CHAT_BODY_LABEL
25
+ aiChatBodyLabel = DEFAULT_AI_CHAT_BODY_LABEL,
26
+ forceImageEnlarge = false
26
27
  }) {
27
28
  const aiAssistant = settings.aiAssistant ? /* @__PURE__ */ jsxs(Fragment, { children: [
28
29
  /* @__PURE__ */ jsx("h2", { class: "sr-only", children: "AI Assistant" }),
@@ -31,7 +32,7 @@ function createBodyEndIslands(deps) {
31
32
  children: /* @__PURE__ */ jsx(AiChatModal, { basePath })
32
33
  })
33
34
  ] }) : null;
34
- const imageEnlarge = settings.imageEnlarge ? Island({
35
+ const imageEnlarge = settings.imageEnlarge || forceImageEnlarge ? Island({
35
36
  when: "idle",
36
37
  ssrFallback: /* @__PURE__ */ jsx(ImageEnlargeSsrFallback, {}),
37
38
  children: /* @__PURE__ */ jsx(ImageEnlarge, {})
@@ -18,7 +18,7 @@ export interface DocLayoutWithDefaultsProps extends Omit<DocLayoutProps, "header
18
18
  children: ComponentChildren;
19
19
  /** Replace the default site header. */
20
20
  headerOverride?: ComponentChildren;
21
- /** Replace the default sidebar contents. */
21
+ /** Replace the default sidebar contents; pass `false` to omit its landmark entirely. */
22
22
  sidebarOverride?: ComponentChildren;
23
23
  /** Replace the default desktop TOC. */
24
24
  tocOverride?: ComponentChildren;
@@ -106,7 +106,7 @@ function DocLayoutWithDefaults(props) {
106
106
  // pass it through `sidebarOverride` and apply their own
107
107
  // `<Island>` wrap (see `pages/lib/_sidebar-with-defaults.tsx`
108
108
  // in the host project).
109
- sidebarOverride ?? Island({
109
+ sidebarOverride === false ? void 0 : sidebarOverride ?? Island({
110
110
  when: "load",
111
111
  children: /* @__PURE__ */ jsx(Sidebar, { nodes: [] })
112
112
  })
@@ -2,6 +2,14 @@ import fs from "fs-extra";
2
2
  import path from "path";
3
3
  import pc from "picocolors";
4
4
  const EJECTABLE = {
5
+ "asset-components": {
6
+ packageSubpath: "@takazudo/zudo-doc/asset-components",
7
+ localDir: "src/components/zudo-doc/asset-components",
8
+ classification: {
9
+ kind: "nested",
10
+ remediation: "Set chromeBindings.mdxExtras.Asset and chromeBindings.mdxExtras.AssetCode to project-owned wrappers around the local createAssetCard and createAssetCode factories."
11
+ }
12
+ },
5
13
  header: {
6
14
  packageSubpath: "@takazudo/zudo-doc/header",
7
15
  localDir: "src/components/zudo-doc/header",
@@ -1,5 +1,5 @@
1
1
  import type { Settings } from "../settings.js";
2
- import type { ColorScheme, ThemePackRegistry } from "../route-context-payload/types.js";
2
+ import type { AssetManifest, ColorScheme, ThemePackRegistry } from "../route-context-payload/types.js";
3
3
  import type { UrlHelpers } from "../url-helpers/index.js";
4
4
  import type { NavSourceDocsAPI } from "../nav-source-docs/index.js";
5
5
  import type { DocRouteEntriesAPI } from "../doc-route-entries/index.js";
@@ -121,6 +121,8 @@ export interface RouteContext<S = Settings> extends UrlHelpers, NavSourceDocsAPI
121
121
  /** Resolved, enabled, ordered theme-pack registry (or `null`) — see
122
122
  * {@link RouteContextPayload.themePackRegistry}. */
123
123
  themePackRegistry: ThemePackRegistry | null;
124
+ /** Author-facing asset index, or `null` when the viewer is disabled. */
125
+ assetManifest: AssetManifest | null;
124
126
  /** The reconstructed i18n surface. */
125
127
  i18n: FactoryI18n;
126
128
  /** Default locale code (un-prefixed `/docs/...`). */
package/dist/features.css CHANGED
@@ -9,11 +9,11 @@
9
9
  *
10
10
  * ── Consumer contract ──────────────────────────────────────────────────────
11
11
  * The consumer's @theme MUST define the custom properties consumed below:
12
- * --color-{fg,muted,accent,surface,code-bg,code-fg,success,warning,
12
+ * --color-{bg,fg,muted,accent,surface,code-bg,code-fg,success,warning,
13
13
  * matched-keyword-bg,matched-keyword-fg}
14
- * --spacing-{hsp-sm,hsp-2xs,hsp-lg,hsp-md,hsp-xl,vsp-xs,vsp-2xs,vsp-md,
14
+ * --spacing-{hsp-sm,hsp-2xs,hsp-lg,hsp-md,hsp-xl,vsp-xs,vsp-2xs,vsp-md,vsp-lg,
15
15
  * icon-sm}
16
- * --z-index-local-1
16
+ * --z-index-{local-1,local-2}
17
17
  * --z-index-toolbar
18
18
  * --radius-{DEFAULT,lg}
19
19
  * --font-{mono,sans}
@@ -1049,3 +1049,124 @@ button[data-zd-pending] {
1049
1049
  opacity: 0.7;
1050
1050
  pointer-events: none;
1051
1051
  }
1052
+
1053
+ /* ======== Asset viewer ======== */
1054
+
1055
+ .zd-asset-page .zd-asset-code {
1056
+ counter-reset: line;
1057
+ }
1058
+
1059
+ .zd-asset-page .zd-asset-code .line {
1060
+ display: block;
1061
+ width: 100%;
1062
+ }
1063
+
1064
+ .zd-asset-page .zd-asset-code .line::before {
1065
+ counter-increment: line;
1066
+ content: counter(line);
1067
+ display: inline-block;
1068
+ box-sizing: border-box;
1069
+ width: var(--zd-asset-gutter, 4ch);
1070
+ padding-right: var(--spacing-hsp-lg);
1071
+ color: var(--color-muted);
1072
+ text-align: right;
1073
+ user-select: none;
1074
+ }
1075
+
1076
+ .zd-asset-page .zd-asset-code .line:target {
1077
+ background: color-mix(in srgb, var(--color-accent) 15%, transparent);
1078
+ box-shadow: inset 3px 0 0 var(--color-accent);
1079
+ }
1080
+
1081
+ .zd-asset-page .zd-asset-filebar {
1082
+ position: sticky;
1083
+ /* Match Header's fixed h-[3.5rem]; --zd-header-h intentionally includes
1084
+ * extra clearance for in-page anchor scrolling. */
1085
+ top: 3.5rem;
1086
+ z-index: var(--z-index-local-2);
1087
+ }
1088
+
1089
+ .zd-asset-page .zd-asset-code + .code-buttons {
1090
+ display: none;
1091
+ }
1092
+
1093
+ .zd-asset-page .zd-asset-stage.is-checker {
1094
+ background-color: var(--color-bg);
1095
+ background-image:
1096
+ linear-gradient(45deg, color-mix(in srgb, var(--color-muted) 10%, var(--color-bg)) 25%, transparent 25%),
1097
+ linear-gradient(-45deg, color-mix(in srgb, var(--color-muted) 10%, var(--color-bg)) 25%, transparent 25%),
1098
+ linear-gradient(45deg, transparent 75%, color-mix(in srgb, var(--color-muted) 10%, var(--color-bg)) 75%),
1099
+ linear-gradient(-45deg, transparent 75%, color-mix(in srgb, var(--color-muted) 10%, var(--color-bg)) 75%);
1100
+ background-position: 0 0, 0 var(--spacing-hsp-sm), var(--spacing-hsp-sm) calc(-1 * var(--spacing-hsp-sm)), calc(-1 * var(--spacing-hsp-sm)) 0;
1101
+ background-size: calc(2 * var(--spacing-hsp-sm)) calc(2 * var(--spacing-hsp-sm));
1102
+ }
1103
+
1104
+ .zd-asset-page .zd-asset-stage.is-dark {
1105
+ background: var(--color-code-bg);
1106
+ }
1107
+
1108
+ .zd-asset-page .zd-asset-stage.is-1to1 img {
1109
+ max-width: none;
1110
+ }
1111
+
1112
+ .zd-asset-page .zd-asset-media-grid {
1113
+ display: grid;
1114
+ gap: var(--spacing-vsp-lg);
1115
+ }
1116
+
1117
+ .zd-asset-page .zd-asset-media-rail {
1118
+ display: flex;
1119
+ flex-direction: column;
1120
+ align-items: start;
1121
+ gap: var(--spacing-vsp-md);
1122
+ }
1123
+
1124
+ .zd-asset-page .zd-asset-media-rail > * {
1125
+ width: 100%;
1126
+ }
1127
+
1128
+ @media (min-width: 1024px) {
1129
+ .zd-asset-page .zd-asset-media-grid {
1130
+ grid-template-columns: minmax(0, 1fr) 20rem;
1131
+ align-items: start;
1132
+ }
1133
+
1134
+ }
1135
+
1136
+ [data-zd-asset-tree]:where(ul),
1137
+ [data-zd-asset-tree] :where(ul) {
1138
+ margin: 0;
1139
+ padding: 0;
1140
+ list-style: none;
1141
+ }
1142
+
1143
+ [data-zd-asset-tree] :where(li) {
1144
+ margin: 0;
1145
+ }
1146
+
1147
+ [data-zd-asset-tree] :where(ul) {
1148
+ margin-left: var(--spacing-hsp-md);
1149
+ padding-left: var(--spacing-hsp-md);
1150
+ border-left: 1px solid color-mix(in srgb, currentColor 18%, transparent);
1151
+ }
1152
+
1153
+ [data-zd-asset-tree] :where(summary) {
1154
+ list-style: none;
1155
+ }
1156
+
1157
+ [data-zd-asset-tree] :where(summary)::-webkit-details-marker {
1158
+ display: none;
1159
+ }
1160
+
1161
+ [data-zd-asset-tree] :where(summary)::marker {
1162
+ content: "";
1163
+ }
1164
+
1165
+ [data-zd-asset-tree] details[open] > summary > svg:first-child {
1166
+ transform: rotate(90deg);
1167
+ }
1168
+
1169
+ [data-zd-asset-tree] details:not([open]) > summary > svg:nth-child(3),
1170
+ [data-zd-asset-tree] details[open] > summary > svg:nth-child(2) {
1171
+ display: none;
1172
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Frontmatter splitter — the package-owned replacement for `gray-matter`
3
+ * (zudolab/zudo-doc#3729).
4
+ *
5
+ * WHY THIS EXISTS: `gray-matter@4` parses YAML through `js-yaml@3`'s
6
+ * `safeLoad`, an API js-yaml 4 removed. That pinned every downstream consumer
7
+ * of this package to the 3.x line and forced them to carry a
8
+ * `js-yaml: ^3.15.1` override — narrow enough to keep gray-matter working,
9
+ * but a compatibility-constrained way to stay ahead of the advisories against
10
+ * older 3.x releases. Splitting the delimiters here and parsing the block with
11
+ * the maintained `yaml` package removes both from the dependency graph, so
12
+ * consumers can drop that override.
13
+ *
14
+ * Delimiter handling below is deliberately byte-for-byte gray-matter's, so
15
+ * existing content keeps parsing identically; each divergence is called out
16
+ * where it happens.
17
+ */
18
+ export interface ParsedFrontmatter {
19
+ /**
20
+ * The parsed frontmatter block, `{}` when there is none.
21
+ *
22
+ * Typed as a record to match gray-matter's own declaration, but a YAML
23
+ * document whose root is a scalar or array passes through unchanged, exactly
24
+ * as gray-matter did — call sites that care guard with an `isRecord` check.
25
+ */
26
+ data: Record<string, unknown>;
27
+ /** Everything after the closing fence, with one leading CRLF/LF removed. */
28
+ content: string;
29
+ }
30
+ /**
31
+ * Split `input` into frontmatter data and body content.
32
+ *
33
+ * Throws when the block is present but unparseable, which is gray-matter's
34
+ * behavior too — callers that tolerate malformed files already wrap this.
35
+ */
36
+ export declare function matter(input: string): ParsedFrontmatter;
37
+ /**
38
+ * Rebuild a document from body content plus frontmatter data — the inverse of
39
+ * {@link matter}, and the one writer this package needs (`tags-suggest` writes
40
+ * approved tags back into a doc file).
41
+ *
42
+ * Matches gray-matter's `stringify`: empty data emits no fence at all, and the
43
+ * body always ends with a newline. The one deliberate difference is that long
44
+ * scalars are NOT folded. js-yaml's 80-column default reflowed unrelated
45
+ * frontmatter — a long `description:` came back as a `>-` block — which is
46
+ * needless churn in a file the tool is only meant to add tags to.
47
+ *
48
+ * `version: "1.1"` applies to SERIALIZATION ONLY (parsing above stays 1.2
49
+ * core) and reproduces js-yaml 3's quoting: a string that a YAML 1.1 reader
50
+ * would resolve to something else gets quoted. Without it `date: "2026-08-22"`
51
+ * would be rewritten unquoted and `tags: ["yes"]` as bare `yes` — the exact
52
+ * interop hazard `src/content/docs/guides/frontmatter.mdx` tells authors to
53
+ * avoid, silently introduced into every file `tags-suggest --apply` touches.
54
+ * `directives: false` keeps the `%YAML 1.1` header out of the emitted block.
55
+ */
56
+ export declare function stringify(content: string, data: Record<string, unknown>): string;
@@ -0,0 +1,61 @@
1
+ import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
2
+ const OPEN = "---";
3
+ const CLOSE = "\n---";
4
+ const BOM = "\uFEFF";
5
+ const COMMENT_LINES = /^\s*#[^\n]+/gm;
6
+ function matter(input) {
7
+ const raw = input.startsWith(BOM) ? input.slice(BOM.length) : input;
8
+ if (!raw.startsWith(OPEN) || raw.charAt(OPEN.length) === "-") {
9
+ return { data: {}, content: raw };
10
+ }
11
+ let body = raw.slice(OPEN.length);
12
+ const firstBreak = body.search(/\r?\n/);
13
+ const rawLanguage = firstBreak === -1 ? body : body.slice(0, firstBreak);
14
+ const language = rawLanguage.trim().toLowerCase();
15
+ if (language) body = body.slice(rawLanguage.length);
16
+ let closeIndex = body.indexOf(CLOSE);
17
+ const unterminated = closeIndex === -1;
18
+ if (unterminated) closeIndex = body.length;
19
+ const block = body.slice(0, closeIndex).replace(/\r\n?/g, "\n");
20
+ let content;
21
+ if (unterminated) {
22
+ content = "";
23
+ } else {
24
+ content = body.slice(closeIndex + CLOSE.length);
25
+ if (content.startsWith("\r")) content = content.slice(1);
26
+ if (content.startsWith("\n")) content = content.slice(1);
27
+ }
28
+ if (block.replace(COMMENT_LINES, "").trim() === "") {
29
+ return { data: {}, content };
30
+ }
31
+ return { data: parseBlock(block, language), content };
32
+ }
33
+ function parseBlock(block, language) {
34
+ if (language === "json") {
35
+ return normalizeRoot(JSON.parse(block));
36
+ }
37
+ if (language !== "" && language !== "yaml" && language !== "yml") {
38
+ throw new Error(`Unsupported frontmatter language: "${language}"`);
39
+ }
40
+ return normalizeRoot(parseYaml(block, { merge: true }));
41
+ }
42
+ function normalizeRoot(value) {
43
+ return value ?? {};
44
+ }
45
+ function stringify(content, data) {
46
+ const block = stringifyYaml(data, {
47
+ lineWidth: 0,
48
+ version: "1.1",
49
+ directives: false
50
+ }).trim();
51
+ const fence = block === "{}" ? "" : `${OPEN}
52
+ ${block}
53
+ ${OPEN}
54
+ `;
55
+ return fence + (content.endsWith("\n") ? content : `${content}
56
+ `);
57
+ }
58
+ export {
59
+ matter,
60
+ stringify
61
+ };
@@ -11,6 +11,7 @@ import {
11
11
  NAV_CHEVRON_INACTIVE,
12
12
  NAV_CHILD_ACTIVE,
13
13
  NAV_CHILD_INACTIVE,
14
+ NAV_MORE_INACTIVE,
14
15
  NAV_TOP_ACTIVE,
15
16
  NAV_TOP_INACTIVE
16
17
  } from "./nav-class-tokens.js";
@@ -90,7 +91,16 @@ function Header(props) {
90
91
  "button",
91
92
  {
92
93
  type: "button",
93
- class: "px-hsp-md py-vsp-2xs text-small font-medium text-muted hover:text-accent hover:underline focus-visible:text-accent focus-visible:underline cursor-pointer",
94
+ class: [
95
+ "px-hsp-md",
96
+ "py-vsp-2xs",
97
+ "text-small",
98
+ "font-medium",
99
+ ...NAV_MORE_INACTIVE,
100
+ "hover:underline",
101
+ "focus-visible:underline",
102
+ "cursor-pointer"
103
+ ].join(" "),
94
104
  "data-nav-more-toggle": true,
95
105
  "aria-expanded": "false",
96
106
  children: "\xB7\xB7\xB7"
@@ -1,5 +1,7 @@
1
1
  export declare const NAV_TOP_ACTIVE: readonly string[];
2
2
  export declare const NAV_TOP_INACTIVE: readonly string[];
3
+ export declare const NAV_MORE_ACTIVE: readonly string[];
4
+ export declare const NAV_MORE_INACTIVE: readonly string[];
3
5
  export declare const NAV_CHEVRON_ACTIVE: readonly string[];
4
6
  export declare const NAV_CHEVRON_INACTIVE: readonly string[];
5
7
  export declare const NAV_CHILD_ACTIVE: readonly string[];
@@ -6,6 +6,12 @@ const NAV_TOP_INACTIVE = [
6
6
  "focus:underline",
7
7
  "focus:text-accent"
8
8
  ];
9
+ const NAV_MORE_ACTIVE = [...NAV_TOP_ACTIVE];
10
+ const NAV_MORE_INACTIVE = [
11
+ "text-muted",
12
+ "hover:text-accent",
13
+ "focus-visible:text-accent"
14
+ ];
9
15
  const NAV_CHEVRON_ACTIVE = ["text-bg"];
10
16
  const NAV_CHEVRON_INACTIVE = ["text-muted"];
11
17
  const NAV_CHILD_ACTIVE = ["font-bold", "text-accent"];
@@ -75,6 +81,8 @@ export {
75
81
  NAV_MENU_PARENT_ACTIVE_SUFFIX,
76
82
  NAV_MENU_PLAIN,
77
83
  NAV_MENU_PLAIN_ACTIVE_SUFFIX,
84
+ NAV_MORE_ACTIVE,
85
+ NAV_MORE_INACTIVE,
78
86
  NAV_TOP_ACTIVE,
79
87
  NAV_TOP_INACTIVE
80
88
  };
@@ -141,8 +141,26 @@ function buildNavOverflowScript() {
141
141
  var moreToggle = document.querySelector("[data-nav-more-toggle]");
142
142
  if (!nav || !moreContainer || !moreMenu || !moreToggle) return;
143
143
 
144
+ function setMoreActive(active) {
145
+ if (active) {
146
+ moreToggle.classList.add("bg-fg", "text-bg");
147
+ moreToggle.classList.remove("text-muted", "hover:text-accent", "focus-visible:text-accent");
148
+ } else {
149
+ moreToggle.classList.add("text-muted", "hover:text-accent", "focus-visible:text-accent");
150
+ moreToggle.classList.remove("bg-fg", "text-bg");
151
+ }
152
+ }
153
+
154
+ // The persisted header can be re-initialized with a different nav shape.
155
+ // Clear a prior page's transferred active state even when there are no
156
+ // items and update() will not be installed (#3758).
157
+ setMoreActive(false);
158
+
144
159
  var items = Array.from(nav.querySelectorAll(":scope > [data-nav-item]"));
145
- if (items.length === 0) return;
160
+ if (items.length === 0) {
161
+ moreContainer.style.display = "none";
162
+ return;
163
+ }
146
164
 
147
165
  var controller = new AbortController();
148
166
 
@@ -152,6 +170,7 @@ function buildNavOverflowScript() {
152
170
  moreMenu.innerHTML = "";
153
171
  moreMenu.classList.add("hidden");
154
172
  moreToggle.setAttribute("aria-expanded", "false");
173
+ setMoreActive(false);
155
174
 
156
175
  var itemWidths = items.map(function (el) { return el.offsetWidth; });
157
176
  var moreWidth = moreContainer.offsetWidth;
@@ -183,10 +202,21 @@ function buildNavOverflowScript() {
183
202
  cutoffIndex = i2 + 1;
184
203
  }
185
204
 
205
+ var hiddenHasActiveItem = false;
186
206
  for (var i3 = cutoffIndex; i3 < items.length; i3++) {
187
- items[i3].style.display = "none";
207
+ var hiddenItem = items[i3];
208
+ hiddenItem.style.display = "none";
209
+ var hiddenTopLink = hiddenItem.hasAttribute("data-nav-item-dropdown")
210
+ ? hiddenItem.querySelector(":scope > a")
211
+ : hiddenItem;
212
+ var hiddenActiveChild = hiddenItem.querySelector(":scope > div a[data-active]");
213
+ if ((hiddenTopLink && hiddenTopLink.getAttribute("aria-current") === "page") || hiddenActiveChild) {
214
+ hiddenHasActiveItem = true;
215
+ }
188
216
  }
217
+ setMoreActive(hiddenHasActiveItem);
189
218
 
219
+ var currentCloneAssigned = false;
190
220
  for (var i4 = cutoffIndex; i4 < items.length; i4++) {
191
221
  var el = items[i4];
192
222
  var isDropdown = el.hasAttribute("data-nav-item-dropdown");
@@ -194,6 +224,9 @@ function buildNavOverflowScript() {
194
224
  if (isDropdown) {
195
225
  var parentLink = el.querySelector(":scope > a");
196
226
  var childLinks = el.querySelectorAll(":scope > div a");
227
+ var hasActiveChild = Array.from(childLinks).some(function (child) {
228
+ return child.hasAttribute("data-active");
229
+ });
197
230
  if (parentLink) {
198
231
  var li = document.createElement("li");
199
232
  var a = document.createElement("a");
@@ -203,6 +236,10 @@ function buildNavOverflowScript() {
203
236
  a.className = "block px-hsp-md py-vsp-2xs text-small font-bold hover:bg-accent/10 hover:underline focus-visible:underline focus-visible:text-accent text-fg hover:text-accent";
204
237
  if (parentLink.getAttribute("aria-current") === "page") {
205
238
  a.className += " text-accent";
239
+ if (!hasActiveChild && !currentCloneAssigned) {
240
+ a.setAttribute("aria-current", "page");
241
+ currentCloneAssigned = true;
242
+ }
206
243
  }
207
244
  li.appendChild(a);
208
245
  moreMenu.appendChild(li);
@@ -216,6 +253,10 @@ function buildNavOverflowScript() {
216
253
  a.className = isChildActive
217
254
  ? "block pl-hsp-xl pr-hsp-md py-vsp-2xs text-small font-bold text-accent hover:bg-accent/10 hover:underline focus-visible:underline"
218
255
  : "block pl-hsp-xl pr-hsp-md py-vsp-2xs text-small text-fg hover:bg-accent/10 hover:text-accent hover:underline focus-visible:underline focus-visible:text-accent";
256
+ if (isChildActive && !currentCloneAssigned) {
257
+ a.setAttribute("aria-current", "page");
258
+ currentCloneAssigned = true;
259
+ }
219
260
  li.appendChild(a);
220
261
  moreMenu.appendChild(li);
221
262
  });
@@ -228,6 +269,10 @@ function buildNavOverflowScript() {
228
269
  a2.className = "block px-hsp-md py-vsp-2xs text-small hover:bg-accent/10 hover:underline focus-visible:underline focus-visible:text-accent text-fg hover:text-accent";
229
270
  if (anchor.getAttribute("aria-current") === "page") {
230
271
  a2.className += " font-bold text-accent";
272
+ if (!currentCloneAssigned) {
273
+ a2.setAttribute("aria-current", "page");
274
+ currentCloneAssigned = true;
275
+ }
231
276
  }
232
277
  li2.appendChild(a2);
233
278
  moreMenu.appendChild(li2);
@@ -14,6 +14,8 @@ export interface HeaderWithDefaultsProps {
14
14
  currentSlug?: string;
15
15
  /** Header-nav category matcher used to scope the sidebar tree. */
16
16
  navSection?: string;
17
+ /** Omit the mobile sidebar toggle and its drawer landmark. */
18
+ hideSidebarToggle?: boolean;
17
19
  }
18
20
  /** Version config entry subset the factory reads. */
19
21
  export interface HeaderVersionEntry {
@@ -36,7 +36,8 @@ function createHeaderWithDefaults(ctx) {
36
36
  currentPath = "",
37
37
  currentVersion,
38
38
  currentSlug,
39
- navSection
39
+ navSection,
40
+ hideSidebarToggle = false
40
41
  } = props;
41
42
  const lang = langProp;
42
43
  const rootMenuItems = buildRootMenuItems(lang, currentVersion);
@@ -44,7 +45,7 @@ function createHeaderWithDefaults(ctx) {
44
45
  const localeLinks = buildLocaleLinksForNav(currentPath, lang, locales.length);
45
46
  const themeDefaultMode = getThemeDefaultMode();
46
47
  const sidebarNodes = buildSidebarNodes(lang, navSection, currentVersion);
47
- const sidebarToggle = Island({
48
+ const sidebarToggle = hideSidebarToggle ? false : Island({
48
49
  when: "visible",
49
50
  children: /* @__PURE__ */ jsx(
50
51
  SidebarToggle,
@@ -5,8 +5,9 @@
5
5
  * `src/config/i18n.ts` `translations` export (epic zudolab/zudo-doc#2651,
6
6
  * S4 #2654) so a generated project needs no i18n config file of its own.
7
7
  *
8
- * Locale code → key → translated string. Fully populated for `en`, `ja`, and
9
- * `de`; the other locales in the generator's `SUPPORTED_LANGS` list
8
+ * Locale code → key → translated string. The `en` and `ja` tables carry the
9
+ * complete package surface; `de` remains the documented partial locale. The
10
+ * other locales in the generator's `SUPPORTED_LANGS` list
10
11
  * (zh-cn/zh-tw/ko/es/fr/pt) fall back to `en` at lookup time (the template's
11
12
  * `t()` helper does `translations[locale]?.[key] ?? translations[defaultLocale]?.[key] ?? key`)
12
13
  * rather than shipping their own fully-translated table here.
@@ -9,6 +9,7 @@ const defaultTranslations = {
9
9
  "nav.codex": "Codex",
10
10
  "nav.changelog": "Changelog",
11
11
  "nav.develop": "Develop",
12
+ "nav.assets": "Assets",
12
13
  "nav.previous": "Previous",
13
14
  "nav.next": "Next",
14
15
  "nav.overview": "Overview",
@@ -33,6 +34,27 @@ const defaultTranslations = {
33
34
  "doc.seeAllTags": "See all tags",
34
35
  "doc.created": "Created",
35
36
  "doc.updated": "Updated",
37
+ "asset.badge": "Asset",
38
+ "asset.crumb": "Assets",
39
+ "asset.indexBadge": "Index",
40
+ "asset.indexDescription": "Every file managed by the asset viewer. Open a file to see its viewer page, metadata, and the documents that reference it.",
41
+ "asset.fileCount": "{count} files",
42
+ "asset.fileCountSingle": "{count} file",
43
+ "asset.folderCount": "{count} folders",
44
+ "asset.folderCountSingle": "{count} folder",
45
+ "asset.expandAll": "Expand all",
46
+ "asset.collapseAll": "Collapse all",
47
+ "asset.indexEmpty": "No assets found.",
48
+ "asset.download": "Download",
49
+ "asset.copy": "Copy",
50
+ "asset.openRaw": "Open raw",
51
+ "asset.wrap": "Wrap",
52
+ "asset.lines": "{count} lines",
53
+ "asset.linkedFrom": "Linked from",
54
+ "asset.noPreview": "No preview is available for this file type. Download it and open it locally.",
55
+ "asset.viewFullFile": "View full file",
56
+ "asset.showingLines": "Showing {shown} of {total} lines",
57
+ "asset.truncated": "Preview truncated \u2014 download the file for the rest.",
36
58
  "doc.noTags": "No tags found.",
37
59
  "doc.pageCount": "{count} pages",
38
60
  "doc.pageCountSingle": "{count} page",
@@ -69,6 +91,7 @@ const defaultTranslations = {
69
91
  "nav.codex": "Codex",
70
92
  "nav.changelog": "\u5909\u66F4\u5C65\u6B74",
71
93
  "nav.develop": "\u958B\u767A",
94
+ "nav.assets": "\u30A2\u30BB\u30C3\u30C8",
72
95
  "nav.previous": "\u524D\u3078",
73
96
  "nav.next": "\u6B21\u3078",
74
97
  "nav.overview": "\u6982\u8981",
@@ -93,6 +116,27 @@ const defaultTranslations = {
93
116
  "doc.seeAllTags": "\u3059\u3079\u3066\u306E\u30BF\u30B0\u3092\u898B\u308B",
94
117
  "doc.created": "\u4F5C\u6210",
95
118
  "doc.updated": "\u66F4\u65B0",
119
+ "asset.badge": "\u30A2\u30BB\u30C3\u30C8",
120
+ "asset.crumb": "\u30A2\u30BB\u30C3\u30C8",
121
+ "asset.indexBadge": "\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9",
122
+ "asset.indexDescription": "\u30A2\u30BB\u30C3\u30C8\u30D3\u30E5\u30FC\u30A2\u30FC\u3067\u7BA1\u7406\u3055\u308C\u3066\u3044\u308B\u3059\u3079\u3066\u306E\u30D5\u30A1\u30A4\u30EB\u3067\u3059\u3002\u30D5\u30A1\u30A4\u30EB\u3092\u958B\u304F\u3068\u3001\u30D7\u30EC\u30D3\u30E5\u30FC\u3001\u30E1\u30BF\u30C7\u30FC\u30BF\u3001\u53C2\u7167\u5143\u306E\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u3092\u78BA\u8A8D\u3067\u304D\u307E\u3059\u3002",
123
+ "asset.fileCount": "{count} \u30D5\u30A1\u30A4\u30EB",
124
+ "asset.fileCountSingle": "{count} \u30D5\u30A1\u30A4\u30EB",
125
+ "asset.folderCount": "{count} \u30D5\u30A9\u30EB\u30C0\u30FC",
126
+ "asset.folderCountSingle": "{count} \u30D5\u30A9\u30EB\u30C0\u30FC",
127
+ "asset.expandAll": "\u3059\u3079\u3066\u5C55\u958B",
128
+ "asset.collapseAll": "\u3059\u3079\u3066\u6298\u308A\u305F\u305F\u3080",
129
+ "asset.indexEmpty": "\u30A2\u30BB\u30C3\u30C8\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3002",
130
+ "asset.download": "\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9",
131
+ "asset.copy": "\u30B3\u30D4\u30FC",
132
+ "asset.openRaw": "\u30D5\u30A1\u30A4\u30EB\u3092\u958B\u304F",
133
+ "asset.wrap": "\u6298\u308A\u8FD4\u3057",
134
+ "asset.lines": "{count} \u884C",
135
+ "asset.linkedFrom": "\u30EA\u30F3\u30AF\u5143",
136
+ "asset.noPreview": "\u3053\u306E\u30D5\u30A1\u30A4\u30EB\u5F62\u5F0F\u306F\u30D7\u30EC\u30D3\u30E5\u30FC\u3067\u304D\u307E\u305B\u3093\u3002\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\u3057\u3066\u30ED\u30FC\u30AB\u30EB\u3067\u958B\u3044\u3066\u304F\u3060\u3055\u3044\u3002",
137
+ "asset.viewFullFile": "\u30D5\u30A1\u30A4\u30EB\u5168\u4F53\u3092\u898B\u308B",
138
+ "asset.showingLines": "{total} \u884C\u4E2D {shown} \u884C\u3092\u8868\u793A",
139
+ "asset.truncated": "\u30D7\u30EC\u30D3\u30E5\u30FC\u306F\u7701\u7565\u3055\u308C\u3066\u3044\u307E\u3059\u3002\u5168\u4F53\u306F\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
96
140
  "doc.noTags": "\u30BF\u30B0\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3002",
97
141
  "doc.pageCount": "{count}\u30DA\u30FC\u30B8",
98
142
  "doc.pageCountSingle": "{count}\u30DA\u30FC\u30B8",
@@ -12,3 +12,12 @@ export declare function History({ className }: IconProps): VNode;
12
12
  export declare function Close({ className }: IconProps): VNode;
13
13
  export declare function ArrowLeft({ className }: IconProps): VNode;
14
14
  export declare function GitHub({ className }: IconProps): VNode;
15
+ export declare function Folder({ className }: IconProps): VNode;
16
+ export declare function FolderOpen({ className }: IconProps): VNode;
17
+ export declare function FileGeneric({ className }: IconProps): VNode;
18
+ export declare function FileCode({ className }: IconProps): VNode;
19
+ export declare function FileText({ className }: IconProps): VNode;
20
+ export declare function FileImage({ className }: IconProps): VNode;
21
+ export declare function FileVideo({ className }: IconProps): VNode;
22
+ export declare function FilePdf({ className }: IconProps): VNode;
23
+ export declare function FileArchive({ className }: IconProps): VNode;