@takazudo/zudo-doc 8.0.0 → 8.1.1
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 +40 -0
- package/README.md +2 -2
- package/dist/asset-index-page/body.js +9 -9
- package/dist/compiled.css +15 -8
- 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/diff-loader.d.ts +3 -0
- package/dist/diff-loader.js +13 -0
- package/dist/doc-history/index.js +6 -5
- 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/katex-loader.d.ts +3 -0
- package/dist/katex-loader.js +12 -0
- package/dist/math-block/index.js +4 -9
- package/dist/md-utils/index.d.ts +8 -2
- package/dist/md-utils/index.js +10 -3
- package/dist/nav-indexing/note-tray-index-parts/card-list.js +25 -21
- package/dist/nav-indexing/note-tray-index-parts/date-line.d.ts +3 -1
- package/dist/nav-indexing/note-tray-index-parts/date-line.js +17 -10
- package/dist/nav-indexing/note-tray-index-parts/index-list.js +4 -3
- package/dist/plugins/diff-loader.d.ts +4 -0
- package/dist/plugins/diff-loader.js +13 -0
- package/dist/plugins/katex-loader.d.ts +4 -0
- package/dist/plugins/katex-loader.js +13 -0
- package/dist/preset.d.ts +6 -2
- package/dist/preset.js +14 -1
- package/dist/settings-defaults.js +1 -0
- package/dist/settings.d.ts +21 -0
- package/dist/sidebar-tree-island/index.js +2 -6
- package/dist/site-tree-nav-island/index.js +11 -8
- package/dist/theme-packs/brutalist/pack.css +2 -2
- 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/dist/wind.json +0 -2
- package/eject/doc-history/index.tsx +13 -9
- package/eject/header/header.tsx +40 -0
- package/eject/sidebar-tree-island/index.tsx +2 -8
- package/eject/site-tree-nav-island/index.tsx +15 -8
- package/package.json +24 -8
|
@@ -3,11 +3,13 @@ import type { JSX } from "@takazudo/zfb/zudo-react/jsx-runtime";
|
|
|
3
3
|
import type { ResolvedDateFormats } from "../../settings.js";
|
|
4
4
|
import type { NoteTrayIndexItem } from "../note-tray-index.js";
|
|
5
5
|
import type { TagNavLabels } from "../types.js";
|
|
6
|
-
export declare function DateLine({ item, locale, updatedLabel, dateFormats, }: {
|
|
6
|
+
export declare function DateLine({ item, locale, updatedLabel, dateFormats, linked, }: {
|
|
7
7
|
item: NoteTrayIndexItem;
|
|
8
8
|
locale: string;
|
|
9
9
|
updatedLabel: string;
|
|
10
10
|
dateFormats?: ResolvedDateFormats;
|
|
11
|
+
/** Inside a `group` link: follow that link's hover/focus-visible accent. */
|
|
12
|
+
linked?: boolean;
|
|
11
13
|
}): JSX.Element | null;
|
|
12
14
|
export declare function ItemTags({ item, labels }: {
|
|
13
15
|
item: NoteTrayIndexItem;
|
|
@@ -5,18 +5,25 @@ function DateLine({
|
|
|
5
5
|
item,
|
|
6
6
|
locale,
|
|
7
7
|
updatedLabel,
|
|
8
|
-
dateFormats
|
|
8
|
+
dateFormats,
|
|
9
|
+
linked = false
|
|
9
10
|
}) {
|
|
10
11
|
if (!item.date && !item.updated) return null;
|
|
11
|
-
return /* @__PURE__ */ jsxs(
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
return /* @__PURE__ */ jsxs(
|
|
13
|
+
"span",
|
|
14
|
+
{
|
|
15
|
+
class: linked ? "tabular-nums text-caption text-muted group-hover:text-accent group-focus-visible:text-accent" : "tabular-nums text-caption text-muted",
|
|
16
|
+
children: [
|
|
17
|
+
item.date && /* @__PURE__ */ jsx("time", { datetime: item.date, children: formatDate(item.date, locale, dateFormats?.full) }),
|
|
18
|
+
item.date && item.updated && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: " \xB7 " }),
|
|
19
|
+
item.updated && /* @__PURE__ */ jsxs("span", { children: [
|
|
20
|
+
updatedLabel,
|
|
21
|
+
" ",
|
|
22
|
+
/* @__PURE__ */ jsx("time", { datetime: item.updated, children: formatDate(item.updated, locale, dateFormats?.full) })
|
|
23
|
+
] })
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
);
|
|
20
27
|
}
|
|
21
28
|
function ItemTags({ item, labels }) {
|
|
22
29
|
if (!labels || !item.tagLinks?.length) return null;
|
|
@@ -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-
|
|
8
|
+
const rankClass = item.href ? "whitespace-nowrap tabular-nums text-heading leading-none text-muted group-hover:text-accent group-focus-visible:text-accent" : "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 }),
|
|
@@ -20,7 +20,8 @@ function IndexList(props) {
|
|
|
20
20
|
item,
|
|
21
21
|
locale: props.locale,
|
|
22
22
|
updatedLabel: props.updatedLabel,
|
|
23
|
-
dateFormats: props.dateFormats
|
|
23
|
+
dateFormats: props.dateFormats,
|
|
24
|
+
linked: Boolean(item.href)
|
|
24
25
|
}
|
|
25
26
|
) })
|
|
26
27
|
] })
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const DIFF_LOADER_SPECIFIER = "@takazudo/zudo-doc/diff-loader";
|
|
2
|
+
const DISABLED_LOADER_SOURCE = 'throw new Error("diff is not bundled: docHistory is off, so this build shadows @takazudo/zudo-doc/diff-loader. To use the doc history Compare view, set docHistory: true and install diff.");\nexport {};\n';
|
|
3
|
+
const plugin = {
|
|
4
|
+
name: "diff-loader",
|
|
5
|
+
setup(ctx) {
|
|
6
|
+
ctx.addVirtualModule(DIFF_LOADER_SPECIFIER, () => DISABLED_LOADER_SOURCE);
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
var diff_loader_default = plugin;
|
|
10
|
+
export {
|
|
11
|
+
DIFF_LOADER_SPECIFIER,
|
|
12
|
+
diff_loader_default as default
|
|
13
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const KATEX_LOADER_SPECIFIER = "@takazudo/zudo-doc/katex-loader";
|
|
2
|
+
const DISABLED_LOADER_SOURCE = 'throw new Error("katex is not bundled: math is off, so this build shadows @takazudo/zudo-doc/katex-loader. To render <MathBlock>, set math: true and install katex.");\nexport {};\n';
|
|
3
|
+
const plugin = {
|
|
4
|
+
name: "katex-loader",
|
|
5
|
+
setup(ctx) {
|
|
6
|
+
ctx.addVirtualModule(KATEX_LOADER_SPECIFIER, () => DISABLED_LOADER_SOURCE);
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
var katex_loader_default = plugin;
|
|
10
|
+
export {
|
|
11
|
+
KATEX_LOADER_SPECIFIER,
|
|
12
|
+
katex_loader_default as default
|
|
13
|
+
};
|
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,13 +109,16 @@ 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;
|
|
115
118
|
trailingSlash: boolean;
|
|
116
119
|
minifyHtml?: boolean;
|
|
117
120
|
mermaid: boolean;
|
|
118
|
-
/** KaTeX math rendering; when off,
|
|
121
|
+
/** KaTeX math rendering; when off, `@takazudo/zudo-doc/katex-loader` is shadowed (bare `katex` is not). */
|
|
119
122
|
math?: boolean;
|
|
120
123
|
/** Enable transclusion of other Markdown/MDX files. */
|
|
121
124
|
transclude?: boolean;
|
|
@@ -128,6 +131,7 @@ export interface PresetSettings {
|
|
|
128
131
|
changelogs?: PresetChangelogConfig[] | false;
|
|
129
132
|
/** Metadata fields shown in the doc metadata area. */
|
|
130
133
|
docMetainfoFields?: Array<"created" | "updated" | "author">;
|
|
134
|
+
/** Per-page git history; when off, `@takazudo/zudo-doc/diff-loader` is shadowed (bare `diff` is not). */
|
|
131
135
|
docHistory?: boolean;
|
|
132
136
|
/** Whether the doc history dropdown UI and related artifacts are enabled. */
|
|
133
137
|
docHistoryUi?: boolean;
|
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);
|
|
@@ -337,7 +339,18 @@ function buildPlugins(settings, routeContext) {
|
|
|
337
339
|
// `design-token-panel-bootstrap` (#4261). Preset-level rather than inside
|
|
338
340
|
// the routes plugin because the bootstrap is reachable from chrome even
|
|
339
341
|
// when packageOwnedRoutes is off.
|
|
340
|
-
...resolvesBundleZdtp(settings) ? [] : [{ name: "@takazudo/zudo-doc/plugins/zdtp-loader", options: {} }]
|
|
342
|
+
...resolvesBundleZdtp(settings) ? [] : [{ name: "@takazudo/zudo-doc/plugins/zdtp-loader", options: {} }],
|
|
343
|
+
// math off → shadow math-block's `@takazudo/zudo-doc/katex-loader` with a
|
|
344
|
+
// throwing virtual module so a site without the optional katex peer gets no
|
|
345
|
+
// Rolldown UNRESOLVED_IMPORT warning (#4651). The bare `katex` is untouched.
|
|
346
|
+
...settings.math ? [] : [{ name: "@takazudo/zudo-doc/plugins/katex-loader", options: {} }],
|
|
347
|
+
// docHistory off → shadow doc-history's `@takazudo/zudo-doc/diff-loader`
|
|
348
|
+
// the same way (#4652). Gated on `docHistory`, NOT `docHistoryUi`: the
|
|
349
|
+
// dates-only mode (`docHistory: true, docHistoryUi: false`) keeps the doc
|
|
350
|
+
// history feature on, so the shadow stays out of every configuration where
|
|
351
|
+
// the Compare view is still part of the enabled feature. Bare `diff` is
|
|
352
|
+
// untouched.
|
|
353
|
+
...settings.docHistory ? [] : [{ name: "@takazudo/zudo-doc/plugins/diff-loader", options: {} }]
|
|
341
354
|
];
|
|
342
355
|
}
|
|
343
356
|
export {
|
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. */
|
|
@@ -508,9 +508,7 @@ function TrayItem({
|
|
|
508
508
|
rankDigits !== void 0 ? /* @__PURE__ */ jsx(
|
|
509
509
|
"span",
|
|
510
510
|
{
|
|
511
|
-
class:
|
|
512
|
-
() => `shrink-0 tabular-nums${active.value ? "" : " text-muted"}`
|
|
513
|
-
),
|
|
511
|
+
class: "shrink-0 tabular-nums",
|
|
514
512
|
children: computed(
|
|
515
513
|
() => item.value.rank === void 0 ? "" : String(item.value.rank).padStart(rankDigits, "0")
|
|
516
514
|
)
|
|
@@ -526,9 +524,7 @@ function TrayItem({
|
|
|
526
524
|
/* @__PURE__ */ jsx(Show, { when: computed(() => showDate && !!shortDate.value), children: () => /* @__PURE__ */ jsx(
|
|
527
525
|
"span",
|
|
528
526
|
{
|
|
529
|
-
class:
|
|
530
|
-
() => `shrink-0 tabular-nums${active.value ? "" : " text-muted"}`
|
|
531
|
-
),
|
|
527
|
+
class: "shrink-0 tabular-nums",
|
|
532
528
|
children: shortDate
|
|
533
529
|
}
|
|
534
530
|
) })
|
|
@@ -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
|
) }),
|
|
@@ -325,7 +328,7 @@ function NoteTrayRow({
|
|
|
325
328
|
{
|
|
326
329
|
href: computed(() => href.value ?? ""),
|
|
327
330
|
"data-note-tray-row": true,
|
|
328
|
-
class: "flex items-start gap-hsp-sm py-vsp-2xs text-small text-fg hover:text-accent hover:underline focus:underline focus-visible:text-accent",
|
|
331
|
+
class: "group flex items-start gap-hsp-sm py-vsp-2xs text-small text-fg hover:text-accent hover:underline focus:underline focus-visible:text-accent",
|
|
329
332
|
children: [
|
|
330
333
|
/* @__PURE__ */ jsx(
|
|
331
334
|
Show,
|
|
@@ -334,7 +337,7 @@ function NoteTrayRow({
|
|
|
334
337
|
fallback: () => /* @__PURE__ */ jsx(
|
|
335
338
|
"span",
|
|
336
339
|
{
|
|
337
|
-
class: "shrink-0 font-mono tabular-nums text-caption text-muted",
|
|
340
|
+
class: "shrink-0 font-mono tabular-nums text-caption text-muted group-hover:text-accent group-focus-visible:text-accent",
|
|
338
341
|
style: computed(() => ({ width: `${width.value}ch` })),
|
|
339
342
|
children: rankLabel
|
|
340
343
|
}
|
|
@@ -343,7 +346,7 @@ function NoteTrayRow({
|
|
|
343
346
|
"time",
|
|
344
347
|
{
|
|
345
348
|
datetime: computed(() => item.value.date ?? ""),
|
|
346
|
-
class: "shrink-0 font-mono tabular-nums text-caption text-muted",
|
|
349
|
+
class: "shrink-0 font-mono tabular-nums text-caption text-muted group-hover:text-accent group-focus-visible:text-accent",
|
|
347
350
|
children: computed(() => dateLabel.value ?? "")
|
|
348
351
|
}
|
|
349
352
|
)
|
|
@@ -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
|
) }),
|
|
@@ -387,8 +387,8 @@ html[data-theme-pack="brutalist"] .zd-content blockquote a {
|
|
|
387
387
|
font-weight: 500;
|
|
388
388
|
}
|
|
389
389
|
/* Card-style prose links (e.g. the note-tray IndexList rank/label/
|
|
390
|
-
description spans) put their own color on group-hover: utility
|
|
391
|
-
classes (group-hover:text-
|
|
390
|
+
description/date spans) put their own color on group-hover: utility
|
|
391
|
+
classes (group-hover:text-accent), which beats
|
|
392
392
|
the anchor's inherited `color` — so the anchor-level color below
|
|
393
393
|
never reached that text. Measured 2.63:1 (rgb(245 245 245) on
|
|
394
394
|
rgb(255 106 31), dark) / 4.06:1 (rgb(0 0 0) on rgb(194 65 12), light)
|
|
@@ -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/dist/wind.json
CHANGED
|
@@ -136,14 +136,12 @@
|
|
|
136
136
|
"grid-rows-subgrid",
|
|
137
137
|
"group",
|
|
138
138
|
"group-focus-visible:text-accent",
|
|
139
|
-
"group-focus-visible:text-fg",
|
|
140
139
|
"group-focus-visible:underline",
|
|
141
140
|
"group-focus-within:block",
|
|
142
141
|
"group-hover:bg-fg",
|
|
143
142
|
"group-hover:block",
|
|
144
143
|
"group-hover:text-accent",
|
|
145
144
|
"group-hover:text-bg",
|
|
146
|
-
"group-hover:text-fg",
|
|
147
145
|
"group-hover:underline",
|
|
148
146
|
"group-open:rotate-90",
|
|
149
147
|
"h-[0.5rem]",
|
|
@@ -180,16 +180,20 @@ async function getCachedDiff(
|
|
|
180
180
|
return hit;
|
|
181
181
|
}
|
|
182
182
|
// Lazy-load diff — only needed after History → Compare. This keeps the
|
|
183
|
-
// module out of the eager islands bundle. `diff` is an optional peer
|
|
184
|
-
//
|
|
185
|
-
//
|
|
186
|
-
//
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
183
|
+
// module out of the eager islands bundle. `diff` is an optional peer reached
|
|
184
|
+
// ONLY through the package-owned `@takazudo/zudo-doc/diff-loader` (#4652):
|
|
185
|
+
// with `docHistory` off the preset's `diff-loader` plugin shadows that
|
|
186
|
+
// specifier with a throwing virtual module, so the bundler never tries to
|
|
187
|
+
// resolve an absent `diff` (no UNRESOLVED_IMPORT); with `docHistory: true`
|
|
188
|
+
// and diff missing the loader resolves `diffLines` to `null` (#4209). The
|
|
189
|
+
// thrown error surfaces through DiffViewer's `.catch()` → diffError.
|
|
190
|
+
const diffLines = await import("@takazudo/zudo-doc/diff-loader").then(
|
|
191
|
+
(m) => m.diffLines,
|
|
192
|
+
() => null,
|
|
192
193
|
);
|
|
194
|
+
if (!diffLines) {
|
|
195
|
+
throw new Error('Compare requires the optional peer "diff": install it to use docHistory');
|
|
196
|
+
}
|
|
193
197
|
// The module import cannot be aborted; a replaced comparison must not do
|
|
194
198
|
// work or populate the cache after its owning scope has been disposed.
|
|
195
199
|
if (!isCurrent()) throw new Error("Comparison cancelled");
|
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
|
+
}
|
|
@@ -587,10 +587,7 @@ function TrayItem({
|
|
|
587
587
|
>
|
|
588
588
|
{rankDigits !== undefined ? (
|
|
589
589
|
<span
|
|
590
|
-
class=
|
|
591
|
-
() =>
|
|
592
|
-
`shrink-0 tabular-nums${active.value ? "" : " text-muted"}`,
|
|
593
|
-
)}
|
|
590
|
+
class="shrink-0 tabular-nums"
|
|
594
591
|
>
|
|
595
592
|
{computed(() =>
|
|
596
593
|
item.value.rank === undefined
|
|
@@ -606,10 +603,7 @@ function TrayItem({
|
|
|
606
603
|
<Show when={computed(() => showDate && !!shortDate.value)}>
|
|
607
604
|
{() => (
|
|
608
605
|
<span
|
|
609
|
-
class=
|
|
610
|
-
() =>
|
|
611
|
-
`shrink-0 tabular-nums${active.value ? "" : " text-muted"}`,
|
|
612
|
-
)}
|
|
606
|
+
class="shrink-0 tabular-nums"
|
|
613
607
|
>
|
|
614
608
|
{shortDate}
|
|
615
609
|
</span>
|