@takazudo/zudo-doc 5.5.2 → 5.6.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 +36 -0
- package/README.md +39 -0
- package/dist/chrome/derive.d.ts +46 -0
- package/dist/chrome/derive.js +6 -2
- package/dist/config-assertions/index.d.ts +31 -0
- package/dist/config-assertions/index.js +24 -0
- package/dist/config.d.ts +23 -2
- package/dist/config.js +3 -0
- package/dist/current-path/index.d.ts +27 -0
- package/dist/current-path/index.js +11 -0
- package/dist/design-token-panel-bootstrap.d.ts +89 -23
- package/dist/design-token-panel-bootstrap.js +19 -6
- package/dist/doc-page-props/index.d.ts +5 -67
- package/dist/doc-route-entries/index.d.ts +10 -95
- package/dist/doc-route-entries/index.js +1 -78
- package/dist/doc-route-paths/index.d.ts +1 -1
- package/dist/head-with-defaults/index.d.ts +3 -1
- package/dist/head-with-defaults/index.js +76 -4
- package/dist/header/nav-active.d.ts +28 -0
- package/dist/header/nav-active.js +2 -1
- package/dist/header/nav-overflow-script.js +30 -17
- package/dist/header-with-defaults/index.js +11 -2
- package/dist/i18n-version/language-switcher.d.ts +6 -0
- package/dist/i18n-version/language-switcher.js +3 -1
- package/dist/i18n-version/version-switcher.d.ts +6 -0
- package/dist/i18n-version/version-switcher.js +3 -1
- package/dist/nav-source-docs/index.d.ts +7 -11
- package/dist/plugins/route-pages-candidates.d.ts +19 -0
- package/dist/plugins/route-pages-candidates.js +17 -0
- package/dist/plugins/routes.d.ts +46 -0
- package/dist/plugins/routes.js +72 -18
- package/dist/preset.d.ts +12 -1
- package/dist/preset.js +2 -0
- package/dist/route-context/index.js +2 -2
- package/dist/routes/_chrome.d.ts +1 -1
- package/dist/routes/_chrome.js +4 -0
- package/dist/routes/_context.d.ts +3 -3
- package/dist/routes/_design-token-panel-bootstrap.d.ts +18 -0
- package/dist/routes/_design-token-panel-bootstrap.js +11 -0
- package/dist/routes/_docs-helpers.d.ts +1 -36
- package/dist/routes/_docs-helpers.js +0 -138
- package/dist/safelist.css +1 -1
- package/dist/search-widget-script/generated-script.d.ts +8 -0
- package/dist/search-widget-script/generated-script.js +465 -0
- package/dist/search-widget-script/index.d.ts +1 -18
- package/dist/search-widget-script/index.js +1 -443
- package/dist/settings.d.ts +82 -1
- package/dist/sidebar-tree/category-meta.d.ts +9 -0
- package/dist/sidebar-tree/category-meta.js +21 -12
- package/dist/sidebar-tree-island/index.d.ts +8 -1
- package/dist/sidebar-tree-island/index.js +16 -14
- package/dist/site-schema/doc-route-entries.d.ts +89 -0
- package/dist/site-schema/doc-route-entries.js +83 -0
- package/dist/site-schema/index.d.ts +17 -0
- package/dist/site-schema/index.js +46 -0
- package/dist/site-schema/nav-tree.d.ts +28 -0
- package/dist/site-schema/nav-tree.js +138 -0
- package/dist/site-schema/types.d.ts +97 -0
- package/dist/site-schema/types.js +0 -0
- package/dist/theme/theme-pack-provider.d.ts +34 -3
- package/dist/theme/theme-pack-provider.js +30 -2
- package/eject/header/nav-active.ts +13 -1
- package/eject/header/nav-overflow-script.ts +30 -17
- package/eject/sidebar-tree-island/index.tsx +44 -20
- package/package.json +22 -12
- package/routes-src/_chrome.tsx +21 -9
- package/routes-src/_design-token-panel-bootstrap.tsx +63 -0
- package/routes-src/_docs-helpers.ts +18 -225
- package/routes-src/_virtual.d.ts +5 -2
- package/virtual-modules.d.ts +5 -2
package/dist/plugins/routes.d.ts
CHANGED
|
@@ -1,2 +1,48 @@
|
|
|
1
|
+
/** One injected route: a zfb route pattern + the package entrypoint specifier
|
|
2
|
+
* that renders it, with optional zfb `injectRoute` opts. */
|
|
3
|
+
interface RouteSpec {
|
|
4
|
+
pattern: string;
|
|
5
|
+
entrypoint: string;
|
|
6
|
+
opts?: {
|
|
7
|
+
prerender?: boolean;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Whether this route counts toward the DTP shadow diagnostic's denominator
|
|
11
|
+
* (#3434). REQUIRED, deliberately — a newly added route must state its
|
|
12
|
+
* membership, so forgetting one is a type error instead of the silent
|
|
13
|
+
* miss #3434 *is*.
|
|
14
|
+
*
|
|
15
|
+
* The name is scoped to the DIAGNOSTIC, not to the route's own nature,
|
|
16
|
+
* because that is all the flag actually asserts. In particular it is NOT
|
|
17
|
+
* `rendersPanel`: `/404` genuinely DOES render the configured DTP bootstrap
|
|
18
|
+
* (`routes/404.tsx` passes `bodyEndComponents={<BodyEndIslands …/>}`, and
|
|
19
|
+
* `routes/_chrome.tsx` feeds that chrome the configured wrapper), so a
|
|
20
|
+
* `rendersPanel: false` tag on it would be a false claim in the source. It
|
|
21
|
+
* is likewise not `kind: "doc-content"` — the counted set includes the
|
|
22
|
+
* locale home, the tag pages and the version pages.
|
|
23
|
+
*
|
|
24
|
+
* `false` for the four routes a reader never browses as documentation:
|
|
25
|
+
* `/sitemap.xml` and `/robots.txt` cannot render an HTML panel at all (they
|
|
26
|
+
* would hold the check at "not fully shadowed" forever), `/api/ai-chat` is a
|
|
27
|
+
* JSON endpoint, and `/404` is an error page — losing the panel there says
|
|
28
|
+
* nothing about whether the site's docs still have one. The never-injected
|
|
29
|
+
* `/` (see the note in `deriveRoutes`) is absent from the catalog entirely
|
|
30
|
+
* and so cannot be counted either.
|
|
31
|
+
*/
|
|
32
|
+
includedInDtpShadowDiagnostic: boolean;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The DTP shadow diagnostic's warn/silent decision, extracted from `setup()`
|
|
36
|
+
* so the vacuity guard below is directly unit-testable (#3434).
|
|
37
|
+
*
|
|
38
|
+
* Returns `true` only when there is at least one reader-facing route AND every
|
|
39
|
+
* one of them is shadowed. The emptiness check is the whole reason this is a
|
|
40
|
+
* named function: `[].every(…)` is vacuously `true`, so an empty denominator
|
|
41
|
+
* would otherwise fire the warning for every host. That state is unreachable
|
|
42
|
+
* through `deriveRoutes` today (`/docs/[[...slug]]` is always emitted and
|
|
43
|
+
* always counted), which is exactly why it needs a test that calls this
|
|
44
|
+
* directly — a build-driven test cannot construct it.
|
|
45
|
+
*/
|
|
46
|
+
export declare function shouldWarnDtpFullyShadowed(routes: ReadonlyArray<Pick<RouteSpec, "pattern" | "includedInDtpShadowDiagnostic">>, isShadowed: (pattern: string) => boolean): boolean;
|
|
1
47
|
declare const plugin: import("@takazudo/zfb").ZfbPlugin;
|
|
2
48
|
export default plugin;
|
package/dist/plugins/routes.js
CHANGED
|
@@ -1,46 +1,61 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
|
-
import { existsSync, statSync, cpSync, rmSync, mkdirSync } from "node:fs";
|
|
2
|
+
import { existsSync, statSync, readFileSync, cpSync, rmSync, mkdirSync } from "node:fs";
|
|
3
3
|
import { dirname, basename, join } from "node:path";
|
|
4
4
|
import { definePlugin } from "@takazudo/zfb/plugins";
|
|
5
5
|
import {
|
|
6
6
|
loadThemePackRegistry,
|
|
7
7
|
resolveEnabledPacks
|
|
8
8
|
} from "../theme-packs-registry/index.js";
|
|
9
|
+
import { derivePagesCandidates } from "./route-pages-candidates.js";
|
|
10
|
+
function shouldWarnDtpFullyShadowed(routes, isShadowed) {
|
|
11
|
+
const counted = routes.filter((route) => route.includedInDtpShadowDiagnostic);
|
|
12
|
+
if (counted.length === 0) return false;
|
|
13
|
+
return counted.every((route) => isShadowed(route.pattern));
|
|
14
|
+
}
|
|
15
|
+
function isExactDefaultReExport(source, entrypoint) {
|
|
16
|
+
const withoutComments = source.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "");
|
|
17
|
+
const specifier = entrypoint.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
18
|
+
const reExportPattern = new RegExp(
|
|
19
|
+
`export\\s*\\{[^}]*\\bdefault\\b(?!\\s+as\\s)[^}]*\\}\\s*from\\s*(["'])${specifier}\\1`
|
|
20
|
+
);
|
|
21
|
+
return reExportPattern.test(withoutComments);
|
|
22
|
+
}
|
|
9
23
|
function deriveRoutes(settings) {
|
|
10
24
|
const routes = [];
|
|
11
25
|
const localeCodes = Object.keys(settings.locales ?? {});
|
|
12
26
|
const hasVersions = Array.isArray(settings.versions) && settings.versions.length > 0;
|
|
13
27
|
const docTags = settings.docTags === true;
|
|
14
28
|
const aiAssistant = settings.aiAssistant === true;
|
|
15
|
-
routes.push({ pattern: "/404", entrypoint: "@takazudo/zudo-doc/routes/404" });
|
|
16
|
-
routes.push({ pattern: "/sitemap.xml", entrypoint: "@takazudo/zudo-doc/routes/sitemap.xml" });
|
|
17
|
-
routes.push({ pattern: "/robots.txt", entrypoint: "@takazudo/zudo-doc/routes/robots.txt" });
|
|
18
|
-
routes.push({ pattern: "/docs/[[...slug]]", entrypoint: "@takazudo/zudo-doc/routes/docs-slug" });
|
|
29
|
+
routes.push({ pattern: "/404", entrypoint: "@takazudo/zudo-doc/routes/404", includedInDtpShadowDiagnostic: false });
|
|
30
|
+
routes.push({ pattern: "/sitemap.xml", entrypoint: "@takazudo/zudo-doc/routes/sitemap.xml", includedInDtpShadowDiagnostic: false });
|
|
31
|
+
routes.push({ pattern: "/robots.txt", entrypoint: "@takazudo/zudo-doc/routes/robots.txt", includedInDtpShadowDiagnostic: false });
|
|
32
|
+
routes.push({ pattern: "/docs/[[...slug]]", entrypoint: "@takazudo/zudo-doc/routes/docs-slug", includedInDtpShadowDiagnostic: true });
|
|
19
33
|
if (docTags) {
|
|
20
|
-
routes.push({ pattern: "/docs/tags", entrypoint: "@takazudo/zudo-doc/routes/docs-tags-index" });
|
|
21
|
-
routes.push({ pattern: "/docs/tags/[tag]", entrypoint: "@takazudo/zudo-doc/routes/docs-tags-tag" });
|
|
34
|
+
routes.push({ pattern: "/docs/tags", entrypoint: "@takazudo/zudo-doc/routes/docs-tags-index", includedInDtpShadowDiagnostic: true });
|
|
35
|
+
routes.push({ pattern: "/docs/tags/[tag]", entrypoint: "@takazudo/zudo-doc/routes/docs-tags-tag", includedInDtpShadowDiagnostic: true });
|
|
22
36
|
}
|
|
23
37
|
if (aiAssistant) {
|
|
24
38
|
routes.push({
|
|
25
39
|
pattern: "/api/ai-chat",
|
|
26
40
|
entrypoint: "@takazudo/zudo-doc/routes/api-ai-chat",
|
|
27
|
-
opts: { prerender: false }
|
|
41
|
+
opts: { prerender: false },
|
|
42
|
+
includedInDtpShadowDiagnostic: false
|
|
28
43
|
});
|
|
29
44
|
}
|
|
30
45
|
if (hasVersions) {
|
|
31
|
-
routes.push({ pattern: "/docs/versions", entrypoint: "@takazudo/zudo-doc/routes/docs-versions" });
|
|
32
|
-
routes.push({ pattern: "/v/[version]/docs/[[...slug]]", entrypoint: "@takazudo/zudo-doc/routes/v-docs-slug" });
|
|
33
|
-
routes.push({ pattern: "/v/[version]/[locale]/docs/[[...slug]]", entrypoint: "@takazudo/zudo-doc/routes/v-locale-docs-slug" });
|
|
46
|
+
routes.push({ pattern: "/docs/versions", entrypoint: "@takazudo/zudo-doc/routes/docs-versions", includedInDtpShadowDiagnostic: true });
|
|
47
|
+
routes.push({ pattern: "/v/[version]/docs/[[...slug]]", entrypoint: "@takazudo/zudo-doc/routes/v-docs-slug", includedInDtpShadowDiagnostic: true });
|
|
48
|
+
routes.push({ pattern: "/v/[version]/[locale]/docs/[[...slug]]", entrypoint: "@takazudo/zudo-doc/routes/v-locale-docs-slug", includedInDtpShadowDiagnostic: true });
|
|
34
49
|
}
|
|
35
50
|
if (localeCodes.length > 0) {
|
|
36
|
-
routes.push({ pattern: "/[locale]", entrypoint: "@takazudo/zudo-doc/routes/locale-index" });
|
|
37
|
-
routes.push({ pattern: "/[locale]/docs/[[...slug]]", entrypoint: "@takazudo/zudo-doc/routes/locale-docs-slug" });
|
|
51
|
+
routes.push({ pattern: "/[locale]", entrypoint: "@takazudo/zudo-doc/routes/locale-index", includedInDtpShadowDiagnostic: true });
|
|
52
|
+
routes.push({ pattern: "/[locale]/docs/[[...slug]]", entrypoint: "@takazudo/zudo-doc/routes/locale-docs-slug", includedInDtpShadowDiagnostic: true });
|
|
38
53
|
if (docTags) {
|
|
39
|
-
routes.push({ pattern: "/[locale]/docs/tags", entrypoint: "@takazudo/zudo-doc/routes/locale-docs-tags-index" });
|
|
40
|
-
routes.push({ pattern: "/[locale]/docs/tags/[tag]", entrypoint: "@takazudo/zudo-doc/routes/locale-docs-tags-tag" });
|
|
54
|
+
routes.push({ pattern: "/[locale]/docs/tags", entrypoint: "@takazudo/zudo-doc/routes/locale-docs-tags-index", includedInDtpShadowDiagnostic: true });
|
|
55
|
+
routes.push({ pattern: "/[locale]/docs/tags/[tag]", entrypoint: "@takazudo/zudo-doc/routes/locale-docs-tags-tag", includedInDtpShadowDiagnostic: true });
|
|
41
56
|
}
|
|
42
57
|
if (hasVersions) {
|
|
43
|
-
routes.push({ pattern: "/[locale]/docs/versions", entrypoint: "@takazudo/zudo-doc/routes/locale-docs-versions" });
|
|
58
|
+
routes.push({ pattern: "/[locale]/docs/versions", entrypoint: "@takazudo/zudo-doc/routes/locale-docs-versions", includedInDtpShadowDiagnostic: true });
|
|
44
59
|
}
|
|
45
60
|
}
|
|
46
61
|
return routes;
|
|
@@ -74,6 +89,7 @@ const plugin = definePlugin({
|
|
|
74
89
|
const translations = options.translations ?? {};
|
|
75
90
|
const tagVocabulary = options.tagVocabulary ?? [];
|
|
76
91
|
const colorSchemes = options.colorSchemes ?? null;
|
|
92
|
+
const derivedRoutes = deriveRoutes(settings);
|
|
77
93
|
const themePacksDir = new URL("../theme-packs/", import.meta.url);
|
|
78
94
|
const themePackRegistry = resolveEnabledPacks(
|
|
79
95
|
loadThemePackRegistry(themePacksDir),
|
|
@@ -120,6 +136,43 @@ const plugin = definePlugin({
|
|
|
120
136
|
` : `export { buildDesignTokenPanelConfig } from "@takazudo/zudo-doc/design-token-panel-config";
|
|
121
137
|
`
|
|
122
138
|
);
|
|
139
|
+
if (settings.designTokenPanel === true && designTokenPanelConfigAbsPath) {
|
|
140
|
+
const pagesDir = join(ctx.projectRoot, "pages");
|
|
141
|
+
const routesByPattern = new Map(derivedRoutes.map((route) => [route.pattern, route]));
|
|
142
|
+
const readerRoutesAllShadowed = shouldWarnDtpFullyShadowed(derivedRoutes, (pattern) => {
|
|
143
|
+
const route = routesByPattern.get(pattern);
|
|
144
|
+
return derivePagesCandidates(pattern).some((rel) => {
|
|
145
|
+
const abs = join(pagesDir, rel);
|
|
146
|
+
if (!existsSync(abs)) return false;
|
|
147
|
+
let source;
|
|
148
|
+
try {
|
|
149
|
+
source = readFileSync(abs, "utf8");
|
|
150
|
+
} catch {
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
153
|
+
if (route && isExactDefaultReExport(source, route.entrypoint)) {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
return true;
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
if (readerRoutesAllShadowed) {
|
|
160
|
+
let chromeBindingsSource;
|
|
161
|
+
if (chromeBindingsAbsPath !== void 0) {
|
|
162
|
+
try {
|
|
163
|
+
chromeBindingsSource = readFileSync(chromeBindingsAbsPath, "utf8");
|
|
164
|
+
} catch {
|
|
165
|
+
chromeBindingsSource = void 0;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
const workaroundLikelyApplied = chromeBindingsSource !== void 0 && chromeBindingsSource.includes("DesignTokenPanelBootstrap");
|
|
169
|
+
if (!workaroundLikelyApplied) {
|
|
170
|
+
ctx.logger.warn(
|
|
171
|
+
'zudo-doc: settings.designTokenPanelConfigModule is set, but every reader-facing injected route\'s URL is shadowed by a kept user pages/ file \u2014 the configured Design Token Panel builder can never apply on any documentation page a reader browses on this site (zudolab/zudo-doc#3420). Thread your builder through chromeBindings.DesignTokenPanelBootstrap instead \u2014 that binding wins everywhere, including stub-rendered pages (see the designTokenPanelConfigModule docblock in settings.ts). If you already did this via a chromeBindingsModule that composes the bootstrap indirectly (never spelling "DesignTokenPanelBootstrap" literally in the resolved file), this warning is safe to ignore. A pages/ file that cleanly re-exports a shadowed route\'s own entrypoint (`export { default, paths, frontmatter } from "@takazudo/zudo-doc/routes/\u2026"`) does not count as a real shadow either \u2014 but that check is also a best-effort text scan, not module evaluation, so a file that reaches the same entrypoint some other way may still trigger this warning even though it is safe.'
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
123
176
|
const require2 = createRequire(import.meta.url);
|
|
124
177
|
let stagedRoutesDir;
|
|
125
178
|
const ensureStaged = (routesSrcDir) => {
|
|
@@ -131,7 +184,7 @@ const plugin = definePlugin({
|
|
|
131
184
|
stagedRoutesDir = dest;
|
|
132
185
|
return dest;
|
|
133
186
|
};
|
|
134
|
-
for (const route of
|
|
187
|
+
for (const route of derivedRoutes) {
|
|
135
188
|
let resolvedEntrypoint;
|
|
136
189
|
try {
|
|
137
190
|
const compiledPath = require2.resolve(route.entrypoint);
|
|
@@ -159,5 +212,6 @@ const plugin = definePlugin({
|
|
|
159
212
|
});
|
|
160
213
|
var routes_default = plugin;
|
|
161
214
|
export {
|
|
162
|
-
routes_default as default
|
|
215
|
+
routes_default as default,
|
|
216
|
+
shouldWarnDtpFullyShadowed
|
|
163
217
|
};
|
package/dist/preset.d.ts
CHANGED
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
*/
|
|
35
35
|
import { z } from "zod";
|
|
36
36
|
import type { ColorScheme } from "./color-scheme-utils.js";
|
|
37
|
-
import type { TagVocabularyEntry } from "./settings.js";
|
|
37
|
+
import type { TagVocabularyEntry, FaviconConfig } from "./settings.js";
|
|
38
38
|
import type { DirectiveSpec } from "@takazudo/zfb/config";
|
|
39
39
|
/** A single locale's content directory (`settings.locales[code]`). */
|
|
40
40
|
export interface PresetLocaleConfig {
|
|
@@ -76,6 +76,17 @@ export interface PresetSettings {
|
|
|
76
76
|
base: string;
|
|
77
77
|
siteName: string;
|
|
78
78
|
siteDescription: string;
|
|
79
|
+
/**
|
|
80
|
+
* Home-hero logo. `zudoDocPreset()` doesn't otherwise consume this field —
|
|
81
|
+
* rendering happens in `home-page/index.tsx` against the full `Settings`
|
|
82
|
+
* object — it is carried here only so `assertNoEmptyStringFaviconOrLogo`
|
|
83
|
+
* (`config-assertions/index.ts`) can validate a direct `zudoDocPreset()`
|
|
84
|
+
* call the same way `zudoDoc()` does (#3474).
|
|
85
|
+
*/
|
|
86
|
+
logo?: string | false;
|
|
87
|
+
/** Favicon links. Same rationale as {@link PresetSettings.logo} — carried
|
|
88
|
+
* only for `assertNoEmptyStringFaviconOrLogo` (#3474). */
|
|
89
|
+
favicon?: string | FaviconConfig | false;
|
|
79
90
|
siteUrl: string;
|
|
80
91
|
trailingSlash: boolean;
|
|
81
92
|
minifyHtml?: boolean;
|
package/dist/preset.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { assertNoCommaInVersionSlugs } from "./version-availability/index.js";
|
|
3
|
+
import { assertNoEmptyStringFaviconOrLogo } from "./config-assertions/index.js";
|
|
3
4
|
function zudoDocPreset({
|
|
4
5
|
settings,
|
|
5
6
|
buildDocsSchema,
|
|
@@ -9,6 +10,7 @@ function zudoDocPreset({
|
|
|
9
10
|
colorSchemes
|
|
10
11
|
}) {
|
|
11
12
|
assertNoCommaInVersionSlugs(settings.versions);
|
|
13
|
+
assertNoEmptyStringFaviconOrLogo(settings);
|
|
12
14
|
const docsSchemaJson = z.toJSONSchema(buildDocsSchema());
|
|
13
15
|
return {
|
|
14
16
|
collections: buildCollections(settings, docsSchemaJson),
|
|
@@ -16,8 +16,8 @@ import {
|
|
|
16
16
|
import {
|
|
17
17
|
createRouteEnumerators
|
|
18
18
|
} from "../route-enumerators/index.js";
|
|
19
|
+
import { stableDocs as defaultStableDocs } from "../routes/_docs-helpers.js";
|
|
19
20
|
import {
|
|
20
|
-
stableDocs as defaultStableDocs,
|
|
21
21
|
isNavVisible,
|
|
22
22
|
buildNavTree,
|
|
23
23
|
buildBreadcrumbs,
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
groupSatelliteNodes,
|
|
26
26
|
findNode,
|
|
27
27
|
firstRoutedHref
|
|
28
|
-
} from "../
|
|
28
|
+
} from "../site-schema/nav-tree.js";
|
|
29
29
|
function createRouteContext(payload, options = {}) {
|
|
30
30
|
const settings = payload.settings;
|
|
31
31
|
const translations = payload.translations;
|
package/dist/routes/_chrome.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DocNavNode } from "
|
|
1
|
+
import type { DocNavNode } from "../site-schema/types.js";
|
|
2
2
|
export declare const composeMetaTitle: (title: string) => string, HeadWithDefaults: (props: import("../head-with-defaults/index.js").HeadWithDefaultsProps) => import("preact").JSX.Element, HeaderWithDefaults: (props: import("../header-with-defaults/index.js").HeaderWithDefaultsProps) => import("preact").JSX.Element, FooterWithDefaults: (props: {
|
|
3
3
|
lang?: string;
|
|
4
4
|
}) => import("preact").VNode, SidebarWithDefaults: (props: import("../sidebar-with-defaults/index.js").SidebarWithDefaultsProps) => import("preact").JSX.Element, renderDocPage: (props: import("../doc-page-props/index.js").DocPageBaseProps, opts: import("../doc-page-renderer/index.js").RenderDocPageOptions) => import("preact").JSX.Element, VersionsPageView: (props: import("../versions-page/index.js").VersionsPageViewProps) => import("preact").JSX.Element, collectTagMapForLocale: (locale: string) => Map<string, import("../tag-pages/index.js").TagInfo>, TagDetailPageView: (props: {
|
package/dist/routes/_chrome.js
CHANGED
|
@@ -3,7 +3,11 @@ import { createChrome } from "../chrome/index.js";
|
|
|
3
3
|
import { DocHistory } from "../doc-history/index.js";
|
|
4
4
|
import { defineChromeBindings } from "@takazudo/zudo-doc/chrome-bindings";
|
|
5
5
|
import { chromeBindings } from "virtual:zudo-doc-chrome-bindings";
|
|
6
|
+
import { ConfiguredDesignTokenPanelBootstrap } from "./_design-token-panel-bootstrap.js";
|
|
6
7
|
const chrome = createChrome(routeCtx, {
|
|
8
|
+
...defineChromeBindings({
|
|
9
|
+
DesignTokenPanelBootstrap: ConfiguredDesignTokenPanelBootstrap
|
|
10
|
+
}),
|
|
7
11
|
...chromeBindings,
|
|
8
12
|
...defineChromeBindings({ DocHistory })
|
|
9
13
|
});
|
|
@@ -17,7 +17,7 @@ export declare const themePackRegistry: ThemePackRegistry | null;
|
|
|
17
17
|
export declare const i18n: import("../factory-context/index.js").FactoryI18n, defaultLocale: string, locales: readonly string[], getLocaleConfig: (locale: string) => {
|
|
18
18
|
label: string;
|
|
19
19
|
dir: string;
|
|
20
|
-
} | undefined, getLocaleLabel: (locale: string) => string, t: (key: string, locale?: string) => string, urlHelpers: import("../url-helpers/index.js").UrlHelpers, withBase: (path: string) => string, stripBase: (path: string) => string, docsUrl: (slug: string, lang?: string) => string, versionedDocsUrl: (slug: string, versionSlug: string, lang?: string) => string, navHref: (path: string, lang: string | undefined, currentVersion: string | undefined, versioned?: boolean) => string, isDefaultLocaleOnlyPath: (path: string) => boolean, absoluteUrl: (pageUrl: string) => string | undefined, isExternal: (href: string) => boolean, resolveHref: (href: string) => string, buildLocaleLinks: (currentPath: string, currentLang: string) => import("../url-helpers/index.js").LocaleLink[], getCategoryOrder: () => string[], getNavSectionForSlug: (slug: string) => string | undefined, getNavSubtree: (tree: import("./
|
|
20
|
+
} | undefined, getLocaleLabel: (locale: string) => string, t: (key: string, locale?: string) => string, urlHelpers: import("../url-helpers/index.js").UrlHelpers, withBase: (path: string) => string, stripBase: (path: string) => string, docsUrl: (slug: string, lang?: string) => string, versionedDocsUrl: (slug: string, versionSlug: string, lang?: string) => string, navHref: (path: string, lang: string | undefined, currentVersion: string | undefined, versioned?: boolean) => string, isDefaultLocaleOnlyPath: (path: string) => boolean, absoluteUrl: (pageUrl: string) => string | undefined, isExternal: (href: string) => boolean, resolveHref: (href: string) => string, buildLocaleLinks: (currentPath: string, currentLang: string) => import("../url-helpers/index.js").LocaleLink[], getCategoryOrder: () => string[], getNavSectionForSlug: (slug: string) => string | undefined, getNavSubtree: (tree: import("./_chrome.js").DocNavNode[], categoryMatch?: string) => import("./_chrome.js").DocNavNode[], extractHeadings: (body: string) => import("../extract-headings/index.js").HeadingItem[], resolveTagBound: (raw: string) => import("../tag-helpers/index.js").ResolvedTag, collectTags: (entries: ReadonlyArray<{
|
|
21
21
|
slug: string;
|
|
22
22
|
data: {
|
|
23
23
|
slug?: string;
|
|
@@ -27,6 +27,6 @@ export declare const i18n: import("../factory-context/index.js").FactoryI18n, de
|
|
|
27
27
|
};
|
|
28
28
|
}>, slugFn: (entrySlug: string, data: {
|
|
29
29
|
slug?: string;
|
|
30
|
-
}) => string) => Map<string, import("./_context.js").TagInfo>, resolveNavSource: (lang: string, currentVersion: string | undefined, options?: import("../nav-source-docs/index.js").NavSourceOptions) => import("../nav-source-docs/index.js").NavSourceDocs, resolveVersionedLocaleSource: (versionSlug: string, versionDocsDir: string | undefined, lang: string, localeDir: string | undefined, options?: import("../nav-source-docs/index.js").NavSourceOptions) => import("../nav-source-docs/index.js").NavSourceDocs, loadNavSourceDocs: (lang: string, currentVersion: string | undefined) => import("../nav-source-docs/index.js").NavSourceDocs, buildDocRouteEntries: (args: import("../doc-route-entries/index.js").
|
|
30
|
+
}) => string) => Map<string, import("./_context.js").TagInfo>, resolveNavSource: (lang: string, currentVersion: string | undefined, options?: import("../nav-source-docs/index.js").NavSourceOptions) => import("../nav-source-docs/index.js").NavSourceDocs, resolveVersionedLocaleSource: (versionSlug: string, versionDocsDir: string | undefined, lang: string, localeDir: string | undefined, options?: import("../nav-source-docs/index.js").NavSourceOptions) => import("../nav-source-docs/index.js").NavSourceDocs, loadNavSourceDocs: (lang: string, currentVersion: string | undefined) => import("../nav-source-docs/index.js").NavSourceDocs, buildDocRouteEntries: (args: import("../site-schema/doc-route-entries.js").BuildDocRouteEntriesArgs<import("../doc-page-props/index.js").DocPageEntry>) => import("../site-schema/doc-route-entries.js").DocRouteEntry<import("../doc-page-props/index.js").DocPageEntry>[], enumerateDocsRoutes: (locale: string) => string[], enumerateTagsRoutes: (locale: string) => string[], enumerateVersionedRoutes: (version: import("../route-enumerators/index.js").VersionConfigForEnum, locale: string) => string[], enumerateAllRoutes: () => Map<string, string>, buildNavTree: (docs: import("../doc-page-props/index.js").DocPageEntry[], locale: string, categoryMeta: Map<string, import("../sidebar-tree/types.js").CategoryMeta> | undefined, buildHref: import("../factory-context/index.js").RouteHrefBuilder, options?: {
|
|
31
31
|
buildHref?: import("../factory-context/index.js").RouteHrefBuilder;
|
|
32
|
-
}) => import("./
|
|
32
|
+
}) => import("./_chrome.js").DocNavNode[], groupSatelliteNodes: (tree: import("./_chrome.js").DocNavNode[], prefixes: string[]) => import("./_chrome.js").DocNavNode[], findNode: (nodes: import("./_chrome.js").DocNavNode[], slug: string) => import("./_chrome.js").DocNavNode | undefined, firstRoutedHref: (node: import("./_chrome.js").DocNavNode) => string | undefined, collectAutoIndexNodes: (nodes: import("./_chrome.js").DocNavNode[]) => import("./_chrome.js").DocNavNode[], isNavVisible: (doc: import("../doc-page-props/index.js").DocPageEntry) => boolean, stableDocs: (collectionName: string) => import("../doc-page-props/index.js").DocPageEntry[], toRouteSlug: (entrySlug: string) => string, toSlugParams: (routeSlug: string) => string[];
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** @jsxRuntime automatic */
|
|
2
|
+
/** @jsxImportSource preact */
|
|
3
|
+
import type { JSX } from "preact";
|
|
4
|
+
/**
|
|
5
|
+
* The design-token-panel island injected routes mount instead of the package
|
|
6
|
+
* default: identical behavior, except the mode-scoped `PanelConfig` builder is
|
|
7
|
+
* the one the routes plugin resolved — the host's
|
|
8
|
+
* `settings.designTokenPanelConfigModule` when set, the package default
|
|
9
|
+
* otherwise.
|
|
10
|
+
*
|
|
11
|
+
* Renders `null` on both SSR and client (the panel self-mounts as a side
|
|
12
|
+
* effect of `bootstrapDesignTokenPanel`), matching the package default's
|
|
13
|
+
* non-`ssrFallback` `Island({ when: "load" })` shape.
|
|
14
|
+
*/
|
|
15
|
+
export declare function ConfiguredDesignTokenPanelBootstrap(): JSX.Element | null;
|
|
16
|
+
export declare namespace ConfiguredDesignTokenPanelBootstrap {
|
|
17
|
+
var displayName: string;
|
|
18
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { runDesignTokenPanelBootstrapOnce } from "../design-token-panel-bootstrap.js";
|
|
3
|
+
import { buildDesignTokenPanelConfig } from "virtual:zudo-doc-design-token-panel-config";
|
|
4
|
+
function ConfiguredDesignTokenPanelBootstrap() {
|
|
5
|
+
runDesignTokenPanelBootstrapOnce(buildDesignTokenPanelConfig, "configured");
|
|
6
|
+
return null;
|
|
7
|
+
}
|
|
8
|
+
ConfiguredDesignTokenPanelBootstrap.displayName = "ConfiguredDesignTokenPanelBootstrap";
|
|
9
|
+
export {
|
|
10
|
+
ConfiguredDesignTokenPanelBootstrap
|
|
11
|
+
};
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { DocNavNode, DocPageEntry } from "../doc-page-props/index.js";
|
|
3
|
-
export type { CategoryMeta, DocNavNode, DocPageEntry };
|
|
1
|
+
import type { DocPageEntry } from "../doc-page-props/index.js";
|
|
4
2
|
/**
|
|
5
3
|
* Identity-stable, draft-filtered `DocPageEntry[]` for a collection. Returns the
|
|
6
4
|
* SAME array instance on every call within one build (anchored on the snapshot
|
|
@@ -8,36 +6,3 @@ export type { CategoryMeta, DocNavNode, DocPageEntry };
|
|
|
8
6
|
* deliberately unmemoized. Passed as `stableDocs` to `createNavSourceDocs`.
|
|
9
7
|
*/
|
|
10
8
|
export declare function stableDocs(collectionName: string): DocPageEntry[];
|
|
11
|
-
/** Filter predicate: true when a doc should appear in navigation. */
|
|
12
|
-
export declare function isNavVisible(doc: DocPageEntry): boolean;
|
|
13
|
-
/** A docs-href builder: `(slug, locale) => url`. */
|
|
14
|
-
export type BuildHref = (slug: string, locale: string) => string;
|
|
15
|
-
export interface BuildNavTreeOptions {
|
|
16
|
-
buildHref?: BuildHref;
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Build a recursive navigation tree from a flat doc collection. Delegates tree
|
|
20
|
-
* construction to the shared `buildSidebarTree`; keeps the host-side concerns
|
|
21
|
-
* (DocNavNode shape, root-index node synthesis). `buildHref` parameterizes the
|
|
22
|
-
* href space (default: the injected `docsUrl`). Unlike the host copy this drops
|
|
23
|
-
* the LRU / identity caches — the snapshot-anchored `stableDocs` already makes
|
|
24
|
-
* the input arrays identity-stable so the factory-level `memoizeDerived` short-
|
|
25
|
-
* circuits per build.
|
|
26
|
-
*/
|
|
27
|
-
export declare function buildNavTree(docs: DocPageEntry[], locale: string, categoryMeta: Map<string, CategoryMeta> | undefined, buildHref: BuildHref, options?: BuildNavTreeOptions): DocNavNode[];
|
|
28
|
-
/** Group "satellite" nodes (slug-prefix siblings) under their primary node. */
|
|
29
|
-
export declare function groupSatelliteNodes(tree: DocNavNode[], prefixes: string[]): DocNavNode[];
|
|
30
|
-
/** Find a node by slug anywhere in the tree. */
|
|
31
|
-
export declare function findNode(nodes: DocNavNode[], slug: string): DocNavNode | undefined;
|
|
32
|
-
/** Href of the first routed descendant, walking children depth-first. */
|
|
33
|
-
export declare function firstRoutedHref(node: DocNavNode): string | undefined;
|
|
34
|
-
/** Collect all category nodes that have children but no page (no index.mdx). */
|
|
35
|
-
export declare function collectAutoIndexNodes(nodes: DocNavNode[]): DocNavNode[];
|
|
36
|
-
export interface BreadcrumbItem {
|
|
37
|
-
label: string;
|
|
38
|
-
href?: string;
|
|
39
|
-
}
|
|
40
|
-
/** Build breadcrumb trail by walking the nav tree. `homeHref` is the locale
|
|
41
|
-
* docs root (injected). `hrefFor` optionally remaps intermediate crumbs into
|
|
42
|
-
* a versioned URL space. */
|
|
43
|
-
export declare function buildBreadcrumbs(tree: DocNavNode[], slug: string, homeHref: string, hrefFor?: (slug: string) => string): BreadcrumbItem[];
|
|
@@ -2,10 +2,6 @@ import {
|
|
|
2
2
|
getCollection,
|
|
3
3
|
getContentSnapshot
|
|
4
4
|
} from "@takazudo/zfb/content";
|
|
5
|
-
import {
|
|
6
|
-
buildSidebarTree
|
|
7
|
-
} from "../sidebar-tree/index.js";
|
|
8
|
-
import { toRouteSlug } from "../slug/index.js";
|
|
9
5
|
function snapshotAnchor(name) {
|
|
10
6
|
return getContentSnapshot()?.collections[name];
|
|
11
7
|
}
|
|
@@ -22,140 +18,6 @@ function stableDocs(collectionName) {
|
|
|
22
18
|
docsByAnchor.set(anchor, built);
|
|
23
19
|
return built;
|
|
24
20
|
}
|
|
25
|
-
function isNavVisible(doc) {
|
|
26
|
-
return !doc.data.unlisted && !doc.data.standalone;
|
|
27
|
-
}
|
|
28
|
-
function toNavNode(node) {
|
|
29
|
-
return {
|
|
30
|
-
slug: node.id,
|
|
31
|
-
label: node.label,
|
|
32
|
-
description: node.description,
|
|
33
|
-
position: node.sidebar_position ?? 999,
|
|
34
|
-
href: node.href,
|
|
35
|
-
hasPage: node.hasPage,
|
|
36
|
-
children: node.children.map(toNavNode),
|
|
37
|
-
sortOrder: node.sortOrder ?? "asc"
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
function findRootIndexDoc(docs) {
|
|
41
|
-
let found;
|
|
42
|
-
for (const d of docs) {
|
|
43
|
-
const slug = d.data.slug ?? toRouteSlug(d.slug);
|
|
44
|
-
if (slug === "") found = d;
|
|
45
|
-
}
|
|
46
|
-
return found;
|
|
47
|
-
}
|
|
48
|
-
function toRootNavNode(doc, locale, buildHref, categoryMeta) {
|
|
49
|
-
const meta = categoryMeta?.get("");
|
|
50
|
-
const noPage = doc.data.category_no_page ?? meta?.noPage;
|
|
51
|
-
const sortOrder = doc.data.category_sort_order ?? meta?.sortOrder ?? "asc";
|
|
52
|
-
return {
|
|
53
|
-
slug: "",
|
|
54
|
-
label: doc.data.sidebar_label ?? doc.data.title ?? meta?.label ?? "",
|
|
55
|
-
description: doc.data.description ?? meta?.description,
|
|
56
|
-
position: doc.data.sidebar_position ?? meta?.position ?? 999,
|
|
57
|
-
href: noPage ? void 0 : buildHref("", locale),
|
|
58
|
-
hasPage: noPage !== true,
|
|
59
|
-
children: [],
|
|
60
|
-
sortOrder
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
function buildNavTree(docs, locale, categoryMeta, buildHref, options) {
|
|
64
|
-
const href = options?.buildHref ?? buildHref;
|
|
65
|
-
const sidebarTree = buildSidebarTree(
|
|
66
|
-
docs,
|
|
67
|
-
locale,
|
|
68
|
-
{
|
|
69
|
-
categoryMeta,
|
|
70
|
-
buildHref: (slug, loc) => href(slug, loc),
|
|
71
|
-
// Host call sites own visibility; disable the builder's default filter so
|
|
72
|
-
// breadcrumb (unfiltered) and nav (pre-filtered) paths are unchanged.
|
|
73
|
-
isNavVisible: () => true
|
|
74
|
-
}
|
|
75
|
-
);
|
|
76
|
-
const result = sidebarTree.map(toNavNode);
|
|
77
|
-
const rootDoc = findRootIndexDoc(docs);
|
|
78
|
-
if (rootDoc) {
|
|
79
|
-
result.push(toRootNavNode(rootDoc, locale, href, categoryMeta));
|
|
80
|
-
result.sort((a, b) => {
|
|
81
|
-
const posCompare = a.position - b.position;
|
|
82
|
-
if (posCompare !== 0) return posCompare;
|
|
83
|
-
return a.slug.localeCompare(b.slug);
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
return result;
|
|
87
|
-
}
|
|
88
|
-
function groupSatelliteNodes(tree, prefixes) {
|
|
89
|
-
const result = [...tree];
|
|
90
|
-
for (const prefix of prefixes) {
|
|
91
|
-
const primaryIdx = result.findIndex((n) => n.slug === prefix);
|
|
92
|
-
if (primaryIdx < 0) continue;
|
|
93
|
-
const primary = result[primaryIdx];
|
|
94
|
-
if (!primary) continue;
|
|
95
|
-
const satelliteIdxs = [];
|
|
96
|
-
for (let i = 0; i < result.length; i++) {
|
|
97
|
-
const node = result[i];
|
|
98
|
-
if (node && i !== primaryIdx && node.slug.startsWith(`${prefix}-`)) {
|
|
99
|
-
satelliteIdxs.push(i);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
if (satelliteIdxs.length === 0) continue;
|
|
103
|
-
const extraChildren = [];
|
|
104
|
-
for (const idx of satelliteIdxs) {
|
|
105
|
-
const node = result[idx];
|
|
106
|
-
if (node) extraChildren.push(node);
|
|
107
|
-
}
|
|
108
|
-
result[primaryIdx] = { ...primary, children: [...primary.children, ...extraChildren] };
|
|
109
|
-
for (const idx of satelliteIdxs.reverse()) result.splice(idx, 1);
|
|
110
|
-
}
|
|
111
|
-
return result;
|
|
112
|
-
}
|
|
113
|
-
function findNode(nodes, slug) {
|
|
114
|
-
for (const node of nodes) {
|
|
115
|
-
if (node.slug === slug) return node;
|
|
116
|
-
const found = findNode(node.children, slug);
|
|
117
|
-
if (found) return found;
|
|
118
|
-
}
|
|
119
|
-
return void 0;
|
|
120
|
-
}
|
|
121
|
-
function firstRoutedHref(node) {
|
|
122
|
-
for (const child of node.children) {
|
|
123
|
-
if (child.hasPage && child.href) return child.href;
|
|
124
|
-
const nested = firstRoutedHref(child);
|
|
125
|
-
if (nested) return nested;
|
|
126
|
-
}
|
|
127
|
-
return void 0;
|
|
128
|
-
}
|
|
129
|
-
function collectAutoIndexNodes(nodes) {
|
|
130
|
-
const result = [];
|
|
131
|
-
for (const node of nodes) {
|
|
132
|
-
if (!node.hasPage && node.children.length > 0 && node.href) result.push(node);
|
|
133
|
-
result.push(...collectAutoIndexNodes(node.children));
|
|
134
|
-
}
|
|
135
|
-
return result;
|
|
136
|
-
}
|
|
137
|
-
function buildBreadcrumbs(tree, slug, homeHref, hrefFor) {
|
|
138
|
-
const parts = slug.split("/");
|
|
139
|
-
const crumbs = [{ label: "", href: homeHref }];
|
|
140
|
-
let nodes = tree;
|
|
141
|
-
for (let i = 0; i < parts.length; i++) {
|
|
142
|
-
const partialSlug = parts.slice(0, i + 1).join("/");
|
|
143
|
-
const node = nodes.find((n) => n.slug === partialSlug);
|
|
144
|
-
if (!node) break;
|
|
145
|
-
const isLast = i === parts.length - 1;
|
|
146
|
-
const href = isLast ? void 0 : hrefFor && node.href !== void 0 ? hrefFor(node.slug) : node.href;
|
|
147
|
-
crumbs.push({ label: node.label, href });
|
|
148
|
-
nodes = node.children;
|
|
149
|
-
}
|
|
150
|
-
return crumbs;
|
|
151
|
-
}
|
|
152
21
|
export {
|
|
153
|
-
buildBreadcrumbs,
|
|
154
|
-
buildNavTree,
|
|
155
|
-
collectAutoIndexNodes,
|
|
156
|
-
findNode,
|
|
157
|
-
firstRoutedHref,
|
|
158
|
-
groupSatelliteNodes,
|
|
159
|
-
isNavVisible,
|
|
160
22
|
stableDocs
|
|
161
23
|
};
|