@takazudo/zudo-doc 8.0.0 → 8.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/README.md +1 -1
- package/dist/compiled.css +15 -0
- package/dist/config-assertions/index.d.ts +13 -0
- package/dist/config-assertions/index.js +25 -0
- package/dist/config.d.ts +12 -1
- package/dist/config.js +2 -0
- package/dist/doclayout/doc-layout.js +5 -1
- package/dist/features.css +24 -0
- package/dist/header/header.d.ts +9 -0
- package/dist/header/header.js +21 -2
- package/dist/header-with-defaults/index.d.ts +3 -1
- package/dist/header-with-defaults/index.js +1 -0
- package/dist/home-page/index.js +1 -1
- package/dist/nav-indexing/note-tray-index-parts/index-list.js +2 -2
- package/dist/preset.d.ts +4 -1
- package/dist/preset.js +2 -0
- package/dist/settings-defaults.js +1 -0
- package/dist/settings.d.ts +21 -0
- package/dist/site-tree-nav-island/index.js +8 -5
- package/dist/transitions/persisted-focus-settle-bootstrap.d.ts +2 -0
- package/dist/transitions/persisted-focus-settle-bootstrap.js +22 -0
- package/dist/tree-nav-shared/index.d.ts +2 -0
- package/dist/tree-nav-shared/index.js +8 -1
- package/eject/header/header.tsx +40 -0
- package/eject/site-tree-nav-island/index.tsx +12 -5
- package/package.json +8 -8
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,22 @@ The format is based on Keep a Changelog, and release notes are generated from th
|
|
|
8
8
|
|
|
9
9
|
No unreleased changes.
|
|
10
10
|
|
|
11
|
+
## [8.1.0] - 2026-10-25
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
- Add the opt-in `headerBrand` setting (`false | { icon: string }`, default `false`): a decorative square icon painted with the text colour (CSS mask) before the site name in the header. `/`-prefixed paths receive the site `base` once, other URLs are used as-is, and an empty or missing `icon` (or `true`) throws at config resolution. The site name stays the link's accessible name, long names still ellipsize, and theme-pack leading emblems are hidden while an icon is set. (fb3358ca)
|
|
16
|
+
- Add a `data-zd-site-name` attribute to the home hero `<h1>` as a styling hook for the site name. (fb3358ca)
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
- With dynamic page transitions enabled, navigating from a footer link (or any focused link in persisted chrome) now finishes at the top of the destination page on current Chromium builds instead of staying near the footer. A package-owned inline head script settles the browser's queued focus reveal after the persisted DOM move and before the router applies its top, hash or history scroll. Focus, persistence, transitions and scroll restoration are unchanged. Sites that pin inline-script hashes in a Content Security Policy need to add the new script's hash. (524a440f)
|
|
21
|
+
- In `SiteTreeNav`, labels now always start a small gap after the end of their dashed branch. On wide viewports the double-width homepage branches used to run into the label text. (3e6e720f)
|
|
22
|
+
|
|
23
|
+
### Other Changes
|
|
24
|
+
|
|
25
|
+
- Requires zfb 5.1.2: the `@takazudo/zfb`, `zfb-runtime` and `zfb-md-wasm` peer floors move from `^5.0.1` to `^5.1.2`. zfb 5.1.0 adds an islands build guard: the build now fails if an emitted islands chunk imports the islands entry, because that import would 404 in production. zfb 5.1.1 is a fix release for Windows hosts (bare-package subpath aliases and `pnpm.cmd` spawning) and for projects built from a symlinked path. zfb 5.1.2 ships rebuilt native engine and WASM binaries with no change to the JavaScript API. Chunking is otherwise unchanged. Upgrade the zfb family (and `zfb-adapter-cloudflare` when used) to 5.1.2 together with this release. (6eef9416, 44d7684b)
|
|
26
|
+
|
|
11
27
|
## [8.0.0] - 2026-10-24
|
|
12
28
|
|
|
13
29
|
### Breaking Changes
|
package/README.md
CHANGED
|
@@ -109,7 +109,7 @@ If your project renders **semi-trusted or user-submitted** HTML in a preview, ov
|
|
|
109
109
|
|
|
110
110
|
**6.0.0** is the coordinated major release of `@takazudo/zudo-doc`,
|
|
111
111
|
`@takazudo/zudo-doc-history-server` and `create-zudo-doc`. The current workspace
|
|
112
|
-
targets the published **zfb 5.
|
|
112
|
+
targets the published **zfb 5.1.2** family (peer floor **^5.1.2**).
|
|
113
113
|
[Upstream #4097](https://github.com/Takazudo/zudo-front-builder/issues/4097) is
|
|
114
114
|
resolved; its strict published 4.3.1 consumer control passed 3/3 with no skips or
|
|
115
115
|
retries in the [source-bound verification](../../docs/findings/zfb-4.3.1/verification.md).
|
package/dist/compiled.css
CHANGED
|
@@ -1864,6 +1864,21 @@ nav[data-zd-toc], div[data-zd-mobile-toc] {
|
|
|
1864
1864
|
font-family: var(--zdc-toc-font, var(--zdc-chrome-font, var(--font-sans)));
|
|
1865
1865
|
}
|
|
1866
1866
|
|
|
1867
|
+
[data-header-brand-icon] {
|
|
1868
|
+
display: inline-block;
|
|
1869
|
+
width: 1.1em;
|
|
1870
|
+
height: 1.1em;
|
|
1871
|
+
vertical-align: -.2em;
|
|
1872
|
+
margin-inline-end: var(--spacing-hsp-sm);
|
|
1873
|
+
background-color: currentColor;
|
|
1874
|
+
-webkit-mask: var(--zd-header-brand-icon) center/contain no-repeat;
|
|
1875
|
+
mask: var(--zd-header-brand-icon) center/contain no-repeat;
|
|
1876
|
+
}
|
|
1877
|
+
|
|
1878
|
+
html[data-theme-pack] [data-header-logo][data-header-brand]:before {
|
|
1879
|
+
content: none;
|
|
1880
|
+
}
|
|
1881
|
+
|
|
1867
1882
|
button[data-zd-pending] {
|
|
1868
1883
|
opacity: .7;
|
|
1869
1884
|
pointer-events: none;
|
|
@@ -55,6 +55,19 @@ export interface EmptyStringFaviconOrLogoSubject {
|
|
|
55
55
|
* object is not an empty string).
|
|
56
56
|
*/
|
|
57
57
|
export declare function assertNoEmptyStringFaviconOrLogo(settings: EmptyStringFaviconOrLogoSubject): void;
|
|
58
|
+
/** Structural subset of `Settings` {@link assertValidHeaderBrand} reads. */
|
|
59
|
+
export interface HeaderBrandSubject {
|
|
60
|
+
headerBrand?: unknown;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Validate `headerBrand`: `undefined`, `false`, or `{ icon: <non-empty string> }`.
|
|
64
|
+
*
|
|
65
|
+
* The value is typed `false | HeaderBrandConfig`, but JavaScript callers and
|
|
66
|
+
* casted values can still pass `true`, a bare string, an array, or an object
|
|
67
|
+
* whose `icon` is missing/empty — each of which would render a broken mask in
|
|
68
|
+
* every page header. Fail loudly at config resolution, naming the field.
|
|
69
|
+
*/
|
|
70
|
+
export declare function assertValidHeaderBrand(settings: HeaderBrandSubject): void;
|
|
58
71
|
/** Structural subset of `Settings` the zdtp-bundling helpers read. */
|
|
59
72
|
export interface ZdtpBundlingSubject {
|
|
60
73
|
designTokenPanel?: boolean;
|
|
@@ -32,6 +32,30 @@ function assertNoEmptyStringFaviconOrLogo(settings) {
|
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
|
+
function assertValidHeaderBrand(settings) {
|
|
36
|
+
const value = settings.headerBrand;
|
|
37
|
+
if (value === void 0 || value === false) return;
|
|
38
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
39
|
+
throw new TypeError(
|
|
40
|
+
`Invalid headerBrand ${describeValue(value)}: pass false (or omit it) for no icon, or an object { icon: "/img/icon.svg" }.`
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
const icon = value.icon;
|
|
44
|
+
if (typeof icon !== "string" || icon === "") {
|
|
45
|
+
throw new TypeError(
|
|
46
|
+
`Invalid headerBrand.icon ${describeValue(icon)}: must be a non-empty string (a "/"-prefixed path, a data: URL, or an absolute URL).`
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function describeValue(value) {
|
|
51
|
+
if (value === void 0) return "undefined";
|
|
52
|
+
if (Array.isArray(value)) return "(array)";
|
|
53
|
+
try {
|
|
54
|
+
return JSON.stringify(value) ?? String(value);
|
|
55
|
+
} catch {
|
|
56
|
+
return String(value);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
35
59
|
function resolvesBundleZdtp(settings) {
|
|
36
60
|
return settings.bundleZdtp ?? settings.designTokenPanel === true;
|
|
37
61
|
}
|
|
@@ -92,6 +116,7 @@ function warnAmbiguousDropdownCategoryMatch(headerNav, logger = console) {
|
|
|
92
116
|
export {
|
|
93
117
|
assertAgentDocsConsistent,
|
|
94
118
|
assertNoEmptyStringFaviconOrLogo,
|
|
119
|
+
assertValidHeaderBrand,
|
|
95
120
|
assertValidSearchMaxBodyLength,
|
|
96
121
|
assertZdtpBundlingConsistent,
|
|
97
122
|
resolvesBundleZdtp,
|
package/dist/config.d.ts
CHANGED
|
@@ -70,7 +70,7 @@ import type { ZfbConfig, BundleConfig, WindConfig } from "@takazudo/zfb/config";
|
|
|
70
70
|
import type { ZodType } from "zod";
|
|
71
71
|
import type { DirectiveVocabulary, PresetTranslations, PresetTagVocabularyEntry } from "./preset.js";
|
|
72
72
|
import type { ColorScheme } from "./color-scheme-utils.js";
|
|
73
|
-
import type { Settings, ColorModeConfig, LocaleConfig, MetaTagsConfig, SiteHeadConfig, TagPlacement, TagGovernanceMode, VersionConfig, FooterConfig, HeaderNavItem, HeaderRightItem, HomeConfig, AssetViewerIndexingConfig, FrontmatterPreviewConfig, BodyFootUtilAreaConfig, HtmlPreviewConfig, FaviconConfig, DateFormatSetting } from "./settings.js";
|
|
73
|
+
import type { Settings, ColorModeConfig, LocaleConfig, MetaTagsConfig, SiteHeadConfig, TagPlacement, TagGovernanceMode, VersionConfig, FooterConfig, HeaderNavItem, HeaderRightItem, HomeConfig, AssetViewerIndexingConfig, FrontmatterPreviewConfig, BodyFootUtilAreaConfig, HtmlPreviewConfig, FaviconConfig, HeaderBrandConfig, DateFormatSetting } from "./settings.js";
|
|
74
74
|
/** The `settings.claudeResources` block (or `false` when disabled). */
|
|
75
75
|
type ClaudeResourcesConfig = {
|
|
76
76
|
claudeDir: string;
|
|
@@ -132,6 +132,17 @@ export interface ZudoDocConfig {
|
|
|
132
132
|
* @default undefined
|
|
133
133
|
*/
|
|
134
134
|
favicon?: string | FaviconConfig | false;
|
|
135
|
+
/**
|
|
136
|
+
* Header brand icon rendered before the site name in the header logo
|
|
137
|
+
* anchor, as a decorative `currentColor` CSS mask (`aria-hidden`; the
|
|
138
|
+
* anchor's accessible name stays `siteName`). `false` renders the site name
|
|
139
|
+
* alone. A `HeaderBrandConfig` (`{ icon }`) paints `icon`: a value starting
|
|
140
|
+
* with `/` is prefixed with `base`, anything else (`data:`, `https://…`) is
|
|
141
|
+
* used verbatim. `true`, arrays, other non-objects, and a missing,
|
|
142
|
+
* non-string or empty `icon` throw a `TypeError` at config resolution.
|
|
143
|
+
* @default false
|
|
144
|
+
*/
|
|
145
|
+
headerBrand?: false | HeaderBrandConfig;
|
|
135
146
|
/**
|
|
136
147
|
* Public URL sub-path prefix mounted in front of every absolute asset URL
|
|
137
148
|
* (e.g. `"/pj/my-site/"`). `"/"` = root-mounted.
|
package/dist/config.js
CHANGED
|
@@ -6,6 +6,7 @@ import { defaultColorSchemes } from "./color-schemes-defaults/index.js";
|
|
|
6
6
|
import { assertNoCommaInVersionSlugs } from "./version-availability/index.js";
|
|
7
7
|
import {
|
|
8
8
|
assertNoEmptyStringFaviconOrLogo,
|
|
9
|
+
assertValidHeaderBrand,
|
|
9
10
|
assertZdtpBundlingConsistent,
|
|
10
11
|
assertValidSearchMaxBodyLength,
|
|
11
12
|
assertAgentDocsConsistent
|
|
@@ -79,6 +80,7 @@ function zudoDoc(user = {}) {
|
|
|
79
80
|
);
|
|
80
81
|
assertNoCommaInVersionSlugs(settings.versions);
|
|
81
82
|
assertNoEmptyStringFaviconOrLogo(settings);
|
|
83
|
+
assertValidHeaderBrand(settings);
|
|
82
84
|
assertZdtpBundlingConsistent(settings);
|
|
83
85
|
assertValidSearchMaxBodyLength(settings.searchMaxBodyLength);
|
|
84
86
|
assertAgentDocsConsistent(settings);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx, jsxs } from "@takazudo/zfb/zudo-react/jsx-runtime";
|
|
2
2
|
import { ClientRouter } from "@takazudo/zfb-runtime";
|
|
3
3
|
import { buildChromeTransitionBootstrap } from "../transitions/chrome-transition-bootstrap.js";
|
|
4
|
+
import { buildPersistedFocusSettleBootstrap } from "../transitions/persisted-focus-settle-bootstrap.js";
|
|
4
5
|
const DESKTOP_SIDEBAR_ID = "desktop-sidebar";
|
|
5
6
|
function DocLayout(props) {
|
|
6
7
|
const {
|
|
@@ -71,7 +72,10 @@ function DocLayout(props) {
|
|
|
71
72
|
);
|
|
72
73
|
}
|
|
73
74
|
if (head !== void 0) headChildren.push(head);
|
|
74
|
-
if (enableClientRouter !== false)
|
|
75
|
+
if (enableClientRouter !== false) {
|
|
76
|
+
headChildren.push(/* @__PURE__ */ jsx("script", { rawHtml: buildChromeTransitionBootstrap() }));
|
|
77
|
+
headChildren.push(/* @__PURE__ */ jsx("script", { rawHtml: buildPersistedFocusSettleBootstrap() }));
|
|
78
|
+
}
|
|
75
79
|
return /* @__PURE__ */ jsxs("html", { ...htmlAttrs, children: [
|
|
76
80
|
/* @__PURE__ */ jsx("head", { children: headChildren }),
|
|
77
81
|
/* @__PURE__ */ jsxs("body", { class: "min-h-screen antialiased", children: [
|
package/dist/features.css
CHANGED
|
@@ -1026,6 +1026,30 @@ nav[data-zd-toc], div[data-zd-mobile-toc] {
|
|
|
1026
1026
|
|
|
1027
1027
|
/* END --zdc-* chrome component tokens */
|
|
1028
1028
|
|
|
1029
|
+
/* ======== Header brand icon (settings.headerBrand) ======== */
|
|
1030
|
+
|
|
1031
|
+
/* Decorative icon inside the site-name anchor. Sized in `em` so it follows a
|
|
1032
|
+
* theme pack's logo font-size inside the fixed-height header; painted as a
|
|
1033
|
+
* currentColor mask so it always matches the site-name ink. The anchor stays
|
|
1034
|
+
* a truncating flow box — the icon is an inline-block run-in, not a flex item. */
|
|
1035
|
+
[data-header-brand-icon] {
|
|
1036
|
+
display: inline-block;
|
|
1037
|
+
width: 1.1em;
|
|
1038
|
+
height: 1.1em;
|
|
1039
|
+
vertical-align: -0.2em;
|
|
1040
|
+
margin-inline-end: var(--spacing-hsp-sm);
|
|
1041
|
+
background-color: currentColor;
|
|
1042
|
+
-webkit-mask: var(--zd-header-brand-icon) center/contain no-repeat;
|
|
1043
|
+
mask: var(--zd-header-brand-icon) center/contain no-repeat;
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
/* A brand icon replaces a theme pack's decorative logo emblem rather than
|
|
1047
|
+
* doubling it. Specificity (0,3,2) beats every pack's `[data-header-logo]::before`
|
|
1048
|
+
* rule (0,2,2); `::after` marks are left alone. */
|
|
1049
|
+
html[data-theme-pack] [data-header-logo][data-header-brand]::before {
|
|
1050
|
+
content: none;
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1029
1053
|
button[data-zd-pending] {
|
|
1030
1054
|
opacity: 0.7;
|
|
1031
1055
|
pointer-events: none;
|
package/dist/header/header.d.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import type { Child } from "@takazudo/zfb/zudo-react";
|
|
3
3
|
import type { JSX } from "@takazudo/zfb/zudo-react/jsx-runtime";
|
|
4
4
|
import type { HeaderNavItem, HeaderRightComponentRegistry, HeaderRightItem, Locale } from "./types.js";
|
|
5
|
+
import type { HeaderBrandConfig } from "../settings.js";
|
|
5
6
|
/**
|
|
6
7
|
* Boundary helpers the host injects into `<Header>`. These are the URL
|
|
7
8
|
* builders the legacy header.tsx used to import from `@/utils/base` —
|
|
@@ -92,6 +93,14 @@ export interface HeaderProps {
|
|
|
92
93
|
persistKey: string;
|
|
93
94
|
/** Site-name string shown in the logo anchor (host `settings.siteName`). */
|
|
94
95
|
siteName: string;
|
|
96
|
+
/**
|
|
97
|
+
* Optional brand icon rendered before `siteName` inside the logo anchor
|
|
98
|
+
* (host `settings.headerBrand`). Omitted or `false` renders the anchor
|
|
99
|
+
* exactly as before. The icon is a decorative `currentColor` CSS mask; an
|
|
100
|
+
* `icon` starting with `/` goes through `urlHelpers.withBase()`, anything
|
|
101
|
+
* else is used verbatim.
|
|
102
|
+
*/
|
|
103
|
+
headerBrand?: false | HeaderBrandConfig;
|
|
95
104
|
/** Header-nav items in render order (host `settings.headerNav`). */
|
|
96
105
|
headerNav: HeaderNavItem[];
|
|
97
106
|
/**
|
package/dist/header/header.js
CHANGED
|
@@ -32,6 +32,7 @@ function Header(props) {
|
|
|
32
32
|
search,
|
|
33
33
|
persistKey,
|
|
34
34
|
siteName,
|
|
35
|
+
headerBrand,
|
|
35
36
|
headerNav,
|
|
36
37
|
headerRightItems,
|
|
37
38
|
headerRightComponents,
|
|
@@ -48,6 +49,8 @@ function Header(props) {
|
|
|
48
49
|
const pathWithoutVersion = stripCurrentVersionPrefix(pathWithoutBase, currentVersion);
|
|
49
50
|
const matchPath = pathForMatch(pathWithoutVersion, lang, i18n.defaultLocale);
|
|
50
51
|
const activeNavPath = computeActiveNavPath(headerNav, matchPath);
|
|
52
|
+
const brandIcon = headerBrand && typeof headerBrand.icon === "string" && headerBrand.icon !== "" ? headerBrand.icon : null;
|
|
53
|
+
const brandIconUrl = brandIcon === null ? null : brandIcon.startsWith("/") && !brandIcon.startsWith("//") ? urlHelpers.withBase(brandIcon) : brandIcon;
|
|
51
54
|
const rightItemDispatch = createRightItemDispatch(headerRightComponents);
|
|
52
55
|
const rightItems = headerRightItems.map((item, i) => ({
|
|
53
56
|
item,
|
|
@@ -98,14 +101,27 @@ function Header(props) {
|
|
|
98
101
|
// (mobile sidebar contents stay accessible to assistive tech
|
|
99
102
|
// even without the toggle island).
|
|
100
103
|
/* @__PURE__ */ jsx(SidebarSlotFallback, { children: sidebarSlot }),
|
|
101
|
-
/* @__PURE__ */
|
|
104
|
+
/* @__PURE__ */ jsxs(
|
|
102
105
|
"a",
|
|
103
106
|
{
|
|
104
107
|
href: urlHelpers.withBase(isNonDefaultLocale ? `/${lang}/` : "/"),
|
|
105
108
|
class: "min-w-0 truncate text-title font-bold text-fg hover:underline focus:underline",
|
|
106
109
|
title: siteName,
|
|
107
110
|
"data-header-logo": true,
|
|
108
|
-
|
|
111
|
+
"data-header-brand": brandIconUrl !== null ? true : void 0,
|
|
112
|
+
children: [
|
|
113
|
+
brandIconUrl !== null && // Painted by features.css as a currentColor mask so it follows the
|
|
114
|
+
// site-name ink; decorative, the anchor's name stays the site name.
|
|
115
|
+
/* @__PURE__ */ jsx(
|
|
116
|
+
"span",
|
|
117
|
+
{
|
|
118
|
+
"aria-hidden": "true",
|
|
119
|
+
"data-header-brand-icon": true,
|
|
120
|
+
style: { "--zd-header-brand-icon": cssUrl(brandIconUrl) }
|
|
121
|
+
}
|
|
122
|
+
),
|
|
123
|
+
siteName
|
|
124
|
+
]
|
|
109
125
|
}
|
|
110
126
|
),
|
|
111
127
|
/* @__PURE__ */ jsxs(
|
|
@@ -486,6 +502,9 @@ function renderRightItem(item, index, ctx, dispatch) {
|
|
|
486
502
|
}
|
|
487
503
|
return null;
|
|
488
504
|
}
|
|
505
|
+
function cssUrl(url) {
|
|
506
|
+
return `url("${url.replace(/[\\"]/g, "\\$&").replace(/[\n\r\f]/g, "\\a ")}")`;
|
|
507
|
+
}
|
|
489
508
|
export {
|
|
490
509
|
Header
|
|
491
510
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** @jsxRuntime automatic */
|
|
2
2
|
import type { JSX } from "@takazudo/zfb/zudo-react/jsx-runtime";
|
|
3
3
|
import type { ChromeContext } from "../factory-context/index.js";
|
|
4
|
-
import type { Settings } from "../settings.js";
|
|
4
|
+
import type { HeaderBrandConfig, Settings } from "../settings.js";
|
|
5
5
|
import type { SidebarNavNode } from "../sidebar/types.js";
|
|
6
6
|
export interface HeaderWithDefaultsProps {
|
|
7
7
|
/** Active locale; defaults to the configured defaultLocale. */
|
|
@@ -44,6 +44,8 @@ export interface HeaderVersionEntry {
|
|
|
44
44
|
/** Settings subset read by {@link createHeaderWithDefaults}. */
|
|
45
45
|
export interface HeaderWithDefaultsSettings {
|
|
46
46
|
siteName: string;
|
|
47
|
+
/** Optional header brand icon — forwarded verbatim to `<Header>`. */
|
|
48
|
+
headerBrand?: false | HeaderBrandConfig;
|
|
47
49
|
/** Site base path — fed to the language-switcher SPA re-wire config. */
|
|
48
50
|
base: string;
|
|
49
51
|
/** Trailing-slash policy — fed to the language-switcher SPA re-wire config. */
|
|
@@ -194,6 +194,7 @@ function createHeaderWithDefaults(ctx) {
|
|
|
194
194
|
languageSwitcher,
|
|
195
195
|
persistKey,
|
|
196
196
|
siteName: settings.siteName,
|
|
197
|
+
headerBrand: settings.headerBrand,
|
|
197
198
|
headerNav: settings.headerNav,
|
|
198
199
|
headerRightItems,
|
|
199
200
|
headerRightComponents: ctx.hostBindings.headerRightComponents,
|
package/dist/home-page/index.js
CHANGED
|
@@ -174,7 +174,7 @@ function createHomePageView(ctx) {
|
|
|
174
174
|
}
|
|
175
175
|
) : null,
|
|
176
176
|
/* @__PURE__ */ jsxs("div", { class: "zd-home-copy min-w-0 lg:flex-1", children: [
|
|
177
|
-
/* @__PURE__ */ jsx("h1", { class: "text-heading font-bold mb-vsp-2xs zd-wrap-anywhere", children: settings.siteName }),
|
|
177
|
+
/* @__PURE__ */ jsx("h1", { class: "text-heading font-bold mb-vsp-2xs zd-wrap-anywhere", "data-zd-site-name": true, children: settings.siteName }),
|
|
178
178
|
/* @__PURE__ */ jsx("p", { class: "text-muted text-small mb-vsp-sm", children: rawDescription }),
|
|
179
179
|
/* @__PURE__ */ jsx("div", { class: "zd-home-links flex flex-wrap items-center justify-center lg:justify-start gap-hsp-md text-small", children: rowContent })
|
|
180
180
|
] })
|
|
@@ -5,12 +5,12 @@ function IndexList(props) {
|
|
|
5
5
|
const width = rankWidth(props.items);
|
|
6
6
|
return /* @__PURE__ */ jsx("ol", { class: "zd-list-items-no-margin", children: props.items.map((item) => {
|
|
7
7
|
const rowClass = item.href ? "relative -mt-px first:mt-0 border-y border-muted hover:z-local-1 hover:border-accent focus-within:z-local-1 focus-within:border-accent" : "relative -mt-px first:mt-0 border-y border-muted";
|
|
8
|
-
const rankClass = item.href ? "tabular-nums text-heading leading-none text-muted group-hover:text-fg group-focus-visible:text-fg" : "tabular-nums text-heading leading-none text-muted";
|
|
8
|
+
const rankClass = item.href ? "whitespace-nowrap tabular-nums text-heading leading-none text-muted group-hover:text-fg group-focus-visible:text-fg" : "whitespace-nowrap tabular-nums text-heading leading-none text-muted";
|
|
9
9
|
const labelClass = item.href ? "font-medium text-fg group-hover:text-accent group-hover:underline group-focus-visible:text-accent group-focus-visible:underline" : "font-medium text-fg";
|
|
10
10
|
const detailClass = item.href ? "mt-vsp-2xs block text-small text-muted group-hover:text-accent group-hover:underline group-focus-visible:text-accent group-focus-visible:underline" : "mt-vsp-2xs block text-small text-muted";
|
|
11
11
|
const dateClass = item.href ? "mt-vsp-2xs block text-caption text-muted group-hover:text-accent group-hover:underline group-focus-visible:text-accent group-focus-visible:underline" : "mt-vsp-2xs block text-caption text-muted";
|
|
12
12
|
const rowContent = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
13
|
-
/* @__PURE__ */ jsx("span", { class: rankClass, style: { width: `${width}ch` }, children: item.rank === void 0 ? "" : String(item.rank).padStart(width, "0") }),
|
|
13
|
+
/* @__PURE__ */ jsx("span", { class: rankClass, style: { "min-width": `${width}ch` }, children: item.rank === void 0 ? "" : String(item.rank).padStart(width, "0") }),
|
|
14
14
|
/* @__PURE__ */ jsxs("span", { class: "min-w-0", children: [
|
|
15
15
|
/* @__PURE__ */ jsx("span", { class: labelClass, children: item.label }),
|
|
16
16
|
item.description && /* @__PURE__ */ jsx("span", { class: detailClass, children: item.description }),
|
package/dist/preset.d.ts
CHANGED
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
import { z } from "zod";
|
|
37
37
|
import type { DirectiveSpec, ZfbConfig } from "@takazudo/zfb/config";
|
|
38
38
|
import type { ColorScheme } from "./color-scheme-utils.js";
|
|
39
|
-
import type { AssetViewerIndexingConfig, TagVocabularyEntry, FaviconConfig, HomeConfig } from "./settings.js";
|
|
39
|
+
import type { AssetViewerIndexingConfig, TagVocabularyEntry, FaviconConfig, HeaderBrandConfig, HomeConfig } from "./settings.js";
|
|
40
40
|
/** A single locale's content directory (`settings.locales[code]`). */
|
|
41
41
|
export interface PresetLocaleConfig {
|
|
42
42
|
dir: string;
|
|
@@ -109,6 +109,9 @@ export interface PresetSettings {
|
|
|
109
109
|
/** Favicon links. Same rationale as {@link PresetSettings.logo} — carried
|
|
110
110
|
* only for `assertNoEmptyStringFaviconOrLogo` (#3474). */
|
|
111
111
|
favicon?: string | FaviconConfig | false;
|
|
112
|
+
/** Header brand icon. Same rationale as {@link PresetSettings.logo} — carried
|
|
113
|
+
* only for `assertValidHeaderBrand`; rendering happens in the header. */
|
|
114
|
+
headerBrand?: false | HeaderBrandConfig;
|
|
112
115
|
/** GitHub repository URL used by asset backlink metadata. */
|
|
113
116
|
githubUrl?: string | false;
|
|
114
117
|
siteUrl: string;
|
package/dist/preset.js
CHANGED
|
@@ -2,6 +2,7 @@ import { z } from "zod";
|
|
|
2
2
|
import { assertNoCommaInVersionSlugs } from "./version-availability/index.js";
|
|
3
3
|
import {
|
|
4
4
|
assertNoEmptyStringFaviconOrLogo,
|
|
5
|
+
assertValidHeaderBrand,
|
|
5
6
|
assertZdtpBundlingConsistent,
|
|
6
7
|
assertValidSearchMaxBodyLength,
|
|
7
8
|
assertAgentDocsConsistent,
|
|
@@ -19,6 +20,7 @@ function zudoDocPreset({
|
|
|
19
20
|
}) {
|
|
20
21
|
assertNoCommaInVersionSlugs(settings.versions);
|
|
21
22
|
assertNoEmptyStringFaviconOrLogo(settings);
|
|
23
|
+
assertValidHeaderBrand(settings);
|
|
22
24
|
assertZdtpBundlingConsistent(settings);
|
|
23
25
|
assertValidSearchMaxBodyLength(settings.searchMaxBodyLength);
|
|
24
26
|
assertAgentDocsConsistent(settings);
|
package/dist/settings.d.ts
CHANGED
|
@@ -260,6 +260,19 @@ export interface FaviconConfig {
|
|
|
260
260
|
png16?: string;
|
|
261
261
|
ico?: string;
|
|
262
262
|
}
|
|
263
|
+
/**
|
|
264
|
+
* Opt-in header brand icon rendered before the site name in the header logo
|
|
265
|
+
* anchor. The icon is painted as a `currentColor` CSS mask, so it follows the
|
|
266
|
+
* site-name ink in every color scheme and theme pack; it is decorative
|
|
267
|
+
* (`aria-hidden`) and the anchor's accessible name stays the site name.
|
|
268
|
+
*
|
|
269
|
+
* `icon` values starting with `/` are passed through `withBase()`; anything
|
|
270
|
+
* else (`data:`, `https://…`) is used verbatim. The value must be a non-empty
|
|
271
|
+
* string — anything else throws a `TypeError` at config resolution.
|
|
272
|
+
*/
|
|
273
|
+
export interface HeaderBrandConfig {
|
|
274
|
+
icon: string;
|
|
275
|
+
}
|
|
263
276
|
/**
|
|
264
277
|
* Site-wide custom `<head>` extras injected into every page via
|
|
265
278
|
* {@link HeadWithDefaults}. All fields are JSON-serializable (no VNodes or
|
|
@@ -341,6 +354,14 @@ export interface Settings {
|
|
|
341
354
|
* resolves to the current document — pass `false` or omit instead (#3471).
|
|
342
355
|
*/
|
|
343
356
|
favicon?: string | FaviconConfig | false;
|
|
357
|
+
/**
|
|
358
|
+
* Header brand icon shown before the site name in the header logo anchor.
|
|
359
|
+
* Omitted or `false` (the default) renders the site name alone, exactly as
|
|
360
|
+
* before; a {@link HeaderBrandConfig} renders its `icon` as a decorative
|
|
361
|
+
* `currentColor` mask. Invalid values (`true`, a non-object, an array, a
|
|
362
|
+
* missing/non-string/empty `icon`) throw a `TypeError` at config resolution.
|
|
363
|
+
*/
|
|
364
|
+
headerBrand?: false | HeaderBrandConfig;
|
|
344
365
|
base: string;
|
|
345
366
|
trailingSlash: boolean;
|
|
346
367
|
/** Package-owned home-page layout. Narrow when omitted. */
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
import {
|
|
10
10
|
INDENT,
|
|
11
11
|
connectorLeft,
|
|
12
|
+
connectorLabelStart,
|
|
12
13
|
ConnectorLines,
|
|
13
14
|
CategoryLinkIcon
|
|
14
15
|
} from "../tree-nav-shared/index.js";
|
|
@@ -24,9 +25,11 @@ import {
|
|
|
24
25
|
import { formatMonthDay } from "../format-date/index.js";
|
|
25
26
|
import { initialCategoryOpenState, toggleCategoryOpenState } from "./state.js";
|
|
26
27
|
const SITE_BASE_PAD = "clamp(0.5rem, 0.8vw, 1rem)";
|
|
28
|
+
const CONNECTOR_WIDTH_SCALE = 2;
|
|
29
|
+
const CONNECTOR_LABEL_GAP = "var(--spacing-hsp-xs)";
|
|
27
30
|
function padLeft(depth) {
|
|
28
31
|
if (depth === 0) return SITE_BASE_PAD;
|
|
29
|
-
return `calc(${depth} * ${INDENT} + 1.25rem + 5px)`;
|
|
32
|
+
return `max(calc(${depth} * ${INDENT} + 1.25rem + 5px), ${connectorLabelStart(depth, CONNECTOR_WIDTH_SCALE, CONNECTOR_LABEL_GAP)})`;
|
|
30
33
|
}
|
|
31
34
|
function reorderTree(tree, order) {
|
|
32
35
|
const map = new Map(tree.map((node) => [node.slug, node]));
|
|
@@ -158,7 +161,7 @@ function CategoryNode({
|
|
|
158
161
|
{
|
|
159
162
|
depth,
|
|
160
163
|
isLast: true,
|
|
161
|
-
widthScale:
|
|
164
|
+
widthScale: CONNECTOR_WIDTH_SCALE,
|
|
162
165
|
topPad: "calc(0.15rem + var(--spacing-vsp-xs))"
|
|
163
166
|
}
|
|
164
167
|
) }),
|
|
@@ -167,7 +170,7 @@ function CategoryNode({
|
|
|
167
170
|
{
|
|
168
171
|
depth,
|
|
169
172
|
isLast: false,
|
|
170
|
-
widthScale:
|
|
173
|
+
widthScale: CONNECTOR_WIDTH_SCALE,
|
|
171
174
|
topPad: "calc(0.15rem + var(--spacing-vsp-xs))"
|
|
172
175
|
}
|
|
173
176
|
) }),
|
|
@@ -370,7 +373,7 @@ function LeafNode({
|
|
|
370
373
|
{
|
|
371
374
|
depth,
|
|
372
375
|
isLast: true,
|
|
373
|
-
widthScale:
|
|
376
|
+
widthScale: CONNECTOR_WIDTH_SCALE,
|
|
374
377
|
topPad
|
|
375
378
|
}
|
|
376
379
|
) }),
|
|
@@ -379,7 +382,7 @@ function LeafNode({
|
|
|
379
382
|
{
|
|
380
383
|
depth,
|
|
381
384
|
isLast: false,
|
|
382
|
-
widthScale:
|
|
385
|
+
widthScale: CONNECTOR_WIDTH_SCALE,
|
|
383
386
|
topPad
|
|
384
387
|
}
|
|
385
388
|
) }),
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { BEFORE_SWAP_EVENT } from "./page-events.js";
|
|
2
|
+
function buildPersistedFocusSettleBootstrap() {
|
|
3
|
+
return `(function(){
|
|
4
|
+
if(document.__zdPersistedFocusSettle)return;
|
|
5
|
+
document.__zdPersistedFocusSettle=true;
|
|
6
|
+
document.addEventListener(${JSON.stringify(BEFORE_SWAP_EVENT)},function(ev){
|
|
7
|
+
if(typeof ev.swap!=="function")return;
|
|
8
|
+
var originalSwap=ev.swap;
|
|
9
|
+
var wrapped=function(){
|
|
10
|
+
var active=document.activeElement;
|
|
11
|
+
var retained=!!active&&typeof active.closest==="function"&&!!active.closest("[data-zfb-transition-persist]");
|
|
12
|
+
var result=originalSwap.apply(this,arguments);
|
|
13
|
+
if(retained&&active.isConnected&&document.activeElement===active)void document.documentElement.offsetHeight;
|
|
14
|
+
return result;
|
|
15
|
+
};
|
|
16
|
+
try{ev.swap=wrapped;}catch(e){}
|
|
17
|
+
});
|
|
18
|
+
})();`;
|
|
19
|
+
}
|
|
20
|
+
export {
|
|
21
|
+
buildPersistedFocusSettleBootstrap
|
|
22
|
+
};
|
|
@@ -4,6 +4,8 @@ export declare const CONNECTOR_OFFSET = "clamp(0.2rem, 0.3vw, 0.5rem)";
|
|
|
4
4
|
export declare const CONNECTOR_WIDTH = "clamp(0.4rem, 0.6vw, 1rem)";
|
|
5
5
|
export declare const BASE_PAD = "clamp(0.4rem, 0.8vw, 1.3rem)";
|
|
6
6
|
export declare function connectorLeft(depth: number): string;
|
|
7
|
+
/** Left edge a label needs so it starts `gap` after the horizontal connector's endpoint. */
|
|
8
|
+
export declare function connectorLabelStart(depth: number, widthScale: number, gap: string): string;
|
|
7
9
|
export declare function CategoryLinkIcon({ class: className }: {
|
|
8
10
|
class?: string;
|
|
9
11
|
}): import("@takazudo/zfb").Description;
|
|
@@ -6,6 +6,12 @@ const BASE_PAD = "clamp(0.4rem, 0.8vw, 1.3rem)";
|
|
|
6
6
|
function connectorLeft(depth) {
|
|
7
7
|
return `calc(${depth} * ${INDENT} + ${CONNECTOR_OFFSET})`;
|
|
8
8
|
}
|
|
9
|
+
function connectorWidth(widthScale) {
|
|
10
|
+
return widthScale === 1 ? CONNECTOR_WIDTH : `calc(${CONNECTOR_WIDTH} * ${widthScale})`;
|
|
11
|
+
}
|
|
12
|
+
function connectorLabelStart(depth, widthScale, gap) {
|
|
13
|
+
return `calc(${connectorLeft(depth)} + ${connectorWidth(widthScale)} + ${gap})`;
|
|
14
|
+
}
|
|
9
15
|
const CATEGORY_LINK_PATH = "M5.746 5.74 0 11.49l20.987 20.96C34.126 45.572 41.963 53.45 41.948 53.523c-.012.062-9.456 9.544-20.986 21.07L0 95.55l5.714 5.715c3.142 3.143 5.748 5.715 5.79 5.715s2.63-2.563 5.75-5.696l17.939-18.001c21.867-21.94 29.443-29.599 29.443-29.768 0-.114-.665-.804-5.084-5.275C51.872 40.47 11.71.125 11.565.036 11.525.01 8.906 2.578 5.746 5.74m38.345-.066c-3.132 3.13-5.696 5.71-5.696 5.732-.001.022 2.16 2.185 4.8 4.807 2.641 2.623 8.382 8.338 12.758 12.702 15.38 15.337 23.763 23.641 24.314 24.086.19.153.346.336.346.405 0 .07-1.738 1.847-3.887 3.976a17515 17515 0 0 0-20.35 20.264 19555 19555 0 0 1-17.223 17.158c-.416.409-.757.77-.757.8 0 .083 11.415 11.485 11.457 11.445.235-.22 53.542-53.528 53.542-53.543C103.395 53.472 49.891.02 49.837 0c-.028-.01-2.613 2.543-5.746 5.674";
|
|
10
16
|
function CategoryLinkIcon({ class: className }) {
|
|
11
17
|
return /* @__PURE__ */ jsx(
|
|
@@ -27,7 +33,7 @@ function ConnectorLines({
|
|
|
27
33
|
}) {
|
|
28
34
|
if (depth === 0) return null;
|
|
29
35
|
const left = connectorLeft(depth);
|
|
30
|
-
const width =
|
|
36
|
+
const width = connectorWidth(widthScale);
|
|
31
37
|
const firstLineMid = `calc(${topPad} + 0.5lh)`;
|
|
32
38
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
33
39
|
/* @__PURE__ */ jsx(
|
|
@@ -61,5 +67,6 @@ export {
|
|
|
61
67
|
CategoryLinkIcon,
|
|
62
68
|
ConnectorLines,
|
|
63
69
|
INDENT,
|
|
70
|
+
connectorLabelStart,
|
|
64
71
|
connectorLeft
|
|
65
72
|
};
|
package/eject/header/header.tsx
CHANGED
|
@@ -60,6 +60,7 @@ import type {
|
|
|
60
60
|
Locale,
|
|
61
61
|
} from "./types.js";
|
|
62
62
|
import { GitHub as GitHubIcon } from "../icons/index.js";
|
|
63
|
+
import type { HeaderBrandConfig } from "../settings.js";
|
|
63
64
|
|
|
64
65
|
/**
|
|
65
66
|
* Boundary helpers the host injects into `<Header>`. These are the URL
|
|
@@ -168,6 +169,15 @@ export interface HeaderProps {
|
|
|
168
169
|
/** Site-name string shown in the logo anchor (host `settings.siteName`). */
|
|
169
170
|
siteName: string;
|
|
170
171
|
|
|
172
|
+
/**
|
|
173
|
+
* Optional brand icon rendered before `siteName` inside the logo anchor
|
|
174
|
+
* (host `settings.headerBrand`). Omitted or `false` renders the anchor
|
|
175
|
+
* exactly as before. The icon is a decorative `currentColor` CSS mask; an
|
|
176
|
+
* `icon` starting with `/` goes through `urlHelpers.withBase()`, anything
|
|
177
|
+
* else is used verbatim.
|
|
178
|
+
*/
|
|
179
|
+
headerBrand?: false | HeaderBrandConfig;
|
|
180
|
+
|
|
171
181
|
/** Header-nav items in render order (host `settings.headerNav`). */
|
|
172
182
|
headerNav: HeaderNavItem[];
|
|
173
183
|
|
|
@@ -265,6 +275,7 @@ export function Header(props: HeaderProps): JSX.Element {
|
|
|
265
275
|
search,
|
|
266
276
|
persistKey,
|
|
267
277
|
siteName,
|
|
278
|
+
headerBrand,
|
|
268
279
|
headerNav,
|
|
269
280
|
headerRightItems,
|
|
270
281
|
headerRightComponents,
|
|
@@ -289,6 +300,16 @@ export function Header(props: HeaderProps): JSX.Element {
|
|
|
289
300
|
const matchPath = pathForMatch(pathWithoutVersion, lang, i18n.defaultLocale);
|
|
290
301
|
|
|
291
302
|
const activeNavPath = computeActiveNavPath(headerNav, matchPath);
|
|
303
|
+
// Direct `<Header>` consumers and raw route payloads bypass the config-time
|
|
304
|
+
// `assertValidHeaderBrand`, so a malformed value degrades to "no icon".
|
|
305
|
+
const brandIcon = headerBrand && typeof headerBrand.icon === "string" && headerBrand.icon !== ""
|
|
306
|
+
? headerBrand.icon
|
|
307
|
+
: null;
|
|
308
|
+
const brandIconUrl = brandIcon === null
|
|
309
|
+
? null
|
|
310
|
+
: brandIcon.startsWith("/") && !brandIcon.startsWith("//")
|
|
311
|
+
? urlHelpers.withBase(brandIcon)
|
|
312
|
+
: brandIcon;
|
|
292
313
|
const rightItemDispatch = createRightItemDispatch(headerRightComponents);
|
|
293
314
|
const rightItems = headerRightItems
|
|
294
315
|
.map((item, i) => ({
|
|
@@ -397,7 +418,17 @@ export function Header(props: HeaderProps): JSX.Element {
|
|
|
397
418
|
class="min-w-0 truncate text-title font-bold text-fg hover:underline focus:underline"
|
|
398
419
|
title={siteName}
|
|
399
420
|
data-header-logo
|
|
421
|
+
data-header-brand={brandIconUrl !== null ? true : undefined}
|
|
400
422
|
>
|
|
423
|
+
{brandIconUrl !== null && (
|
|
424
|
+
// Painted by features.css as a currentColor mask so it follows the
|
|
425
|
+
// site-name ink; decorative, the anchor's name stays the site name.
|
|
426
|
+
<span
|
|
427
|
+
aria-hidden="true"
|
|
428
|
+
data-header-brand-icon
|
|
429
|
+
style={{ "--zd-header-brand-icon": cssUrl(brandIconUrl) }}
|
|
430
|
+
/>
|
|
431
|
+
)}
|
|
401
432
|
{siteName}
|
|
402
433
|
</a>
|
|
403
434
|
|
|
@@ -908,3 +939,12 @@ function renderRightItem(
|
|
|
908
939
|
|
|
909
940
|
return null;
|
|
910
941
|
}
|
|
942
|
+
|
|
943
|
+
/**
|
|
944
|
+
* Serialize a URL as a quoted CSS `url()` token so paths with whitespace,
|
|
945
|
+
* parentheses or quotes survive inside the custom property. Kept local to
|
|
946
|
+
* this module because the header is ejectable (see `eject/index.ts`).
|
|
947
|
+
*/
|
|
948
|
+
function cssUrl(url: string): string {
|
|
949
|
+
return `url("${url.replace(/[\\"]/g, "\\$&").replace(/[\n\r\f]/g, "\\a ")}")`;
|
|
950
|
+
}
|
|
@@ -12,6 +12,7 @@ import type { ResolvedDateFormats } from "../settings.js";
|
|
|
12
12
|
import {
|
|
13
13
|
INDENT,
|
|
14
14
|
connectorLeft,
|
|
15
|
+
connectorLabelStart,
|
|
15
16
|
ConnectorLines,
|
|
16
17
|
CategoryLinkIcon,
|
|
17
18
|
} from "../tree-nav-shared/index.js";
|
|
@@ -30,9 +31,15 @@ import { initialCategoryOpenState, toggleCategoryOpenState } from "./state.js";
|
|
|
30
31
|
// site-tree-nav uses wider padding than the narrow sidebar
|
|
31
32
|
const SITE_BASE_PAD = "clamp(0.5rem, 0.8vw, 1rem)";
|
|
32
33
|
|
|
34
|
+
// The homepage draws its connectors at twice the sidebar width, so on wide
|
|
35
|
+
// viewports the branch endpoint passes the fixed label indent. The label starts
|
|
36
|
+
// at whichever is further right: that indent, or the endpoint plus a gap.
|
|
37
|
+
const CONNECTOR_WIDTH_SCALE = 2;
|
|
38
|
+
const CONNECTOR_LABEL_GAP = "var(--spacing-hsp-xs)";
|
|
39
|
+
|
|
33
40
|
function padLeft(depth: number): string {
|
|
34
41
|
if (depth === 0) return SITE_BASE_PAD;
|
|
35
|
-
return `calc(${depth} * ${INDENT} + 1.25rem + 5px)`;
|
|
42
|
+
return `max(calc(${depth} * ${INDENT} + 1.25rem + 5px), ${connectorLabelStart(depth, CONNECTOR_WIDTH_SCALE, CONNECTOR_LABEL_GAP)})`;
|
|
36
43
|
}
|
|
37
44
|
|
|
38
45
|
function reorderTree(tree: SidebarNavNode[], order: string[]): SidebarNavNode[] {
|
|
@@ -223,7 +230,7 @@ function CategoryNode({
|
|
|
223
230
|
<ConnectorLines
|
|
224
231
|
depth={depth}
|
|
225
232
|
isLast={true}
|
|
226
|
-
widthScale={
|
|
233
|
+
widthScale={CONNECTOR_WIDTH_SCALE}
|
|
227
234
|
topPad="calc(0.15rem + var(--spacing-vsp-xs))"
|
|
228
235
|
/>
|
|
229
236
|
)}
|
|
@@ -233,7 +240,7 @@ function CategoryNode({
|
|
|
233
240
|
<ConnectorLines
|
|
234
241
|
depth={depth}
|
|
235
242
|
isLast={false}
|
|
236
|
-
widthScale={
|
|
243
|
+
widthScale={CONNECTOR_WIDTH_SCALE}
|
|
237
244
|
topPad="calc(0.15rem + var(--spacing-vsp-xs))"
|
|
238
245
|
/>
|
|
239
246
|
)}
|
|
@@ -495,7 +502,7 @@ function LeafNode({
|
|
|
495
502
|
<ConnectorLines
|
|
496
503
|
depth={depth}
|
|
497
504
|
isLast={true}
|
|
498
|
-
widthScale={
|
|
505
|
+
widthScale={CONNECTOR_WIDTH_SCALE}
|
|
499
506
|
topPad={topPad}
|
|
500
507
|
/>
|
|
501
508
|
)}
|
|
@@ -505,7 +512,7 @@ function LeafNode({
|
|
|
505
512
|
<ConnectorLines
|
|
506
513
|
depth={depth}
|
|
507
514
|
isLast={false}
|
|
508
|
-
widthScale={
|
|
515
|
+
widthScale={CONNECTOR_WIDTH_SCALE}
|
|
509
516
|
topPad={topPad}
|
|
510
517
|
/>
|
|
511
518
|
)}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@takazudo/zudo-doc",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.1.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",
|
|
@@ -736,9 +736,9 @@
|
|
|
736
736
|
"peerDependencies": {
|
|
737
737
|
"@modelcontextprotocol/sdk": "1.32.2",
|
|
738
738
|
"@takazudo/zdtp": "^0.5.2 || ^0.6.0 || ^0.7.0 || ^0.8.0",
|
|
739
|
-
"@takazudo/zfb": "^5.
|
|
740
|
-
"@takazudo/zfb-md-wasm": "^5.
|
|
741
|
-
"@takazudo/zfb-runtime": "^5.
|
|
739
|
+
"@takazudo/zfb": "^5.1.2",
|
|
740
|
+
"@takazudo/zfb-md-wasm": "^5.1.2",
|
|
741
|
+
"@takazudo/zfb-runtime": "^5.1.2",
|
|
742
742
|
"@takazudo/zudo-doc-history-server": "^8.0.0",
|
|
743
743
|
"diff": "^8.0.0",
|
|
744
744
|
"katex": "^0.18.2 || ^0.19.0",
|
|
@@ -779,9 +779,9 @@
|
|
|
779
779
|
"devDependencies": {
|
|
780
780
|
"@modelcontextprotocol/sdk": "1.32.2",
|
|
781
781
|
"@takazudo/mdx-formatter": "1.3.0",
|
|
782
|
-
"@takazudo/zfb": "5.
|
|
783
|
-
"@takazudo/zfb-md-wasm": "5.
|
|
784
|
-
"@takazudo/zfb-runtime": "5.
|
|
782
|
+
"@takazudo/zfb": "5.1.2",
|
|
783
|
+
"@takazudo/zfb-md-wasm": "5.1.2",
|
|
784
|
+
"@takazudo/zfb-runtime": "5.1.2",
|
|
785
785
|
"@types/fs-extra": "^11.0.4",
|
|
786
786
|
"@types/minimist": "^1.2.5",
|
|
787
787
|
"@types/node": "^25.3.5",
|
|
@@ -791,7 +791,7 @@
|
|
|
791
791
|
"typescript": "^5.0.0",
|
|
792
792
|
"vitest": "^4.1.0",
|
|
793
793
|
"zod": "^4.3.6",
|
|
794
|
-
"@takazudo/zudo-doc-history-server": "8.
|
|
794
|
+
"@takazudo/zudo-doc-history-server": "8.1.0"
|
|
795
795
|
},
|
|
796
796
|
"scripts": {
|
|
797
797
|
"gen:search-widget-script": "node scripts/gen-search-widget-script.mjs",
|