create-zudo-doc 0.2.21 → 1.0.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/dist/compose.d.ts +6 -3
- package/dist/compose.js +6 -4
- package/dist/features/image-enlarge.d.ts +22 -12
- package/dist/features/image-enlarge.js +23 -191
- package/dist/scaffold.d.ts +11 -0
- package/dist/scaffold.js +51 -24
- package/dist/settings-gen.js +4 -0
- package/dist/zfb-config-gen.d.ts +16 -10
- package/dist/zfb-config-gen.js +34 -239
- package/package.json +1 -1
- package/templates/base/pages/_mdx-components.ts +64 -185
- package/templates/base/pages/index.tsx +1 -1
- package/templates/base/pages/lib/_body-end-islands.tsx +6 -13
- package/templates/base/pages/lib/_category-nav.tsx +30 -115
- package/templates/base/pages/lib/_category-tree-nav.tsx +38 -65
- package/templates/base/pages/lib/_compose-meta-title.ts +2 -6
- package/templates/base/pages/lib/_doc-body-end.tsx +3 -35
- package/templates/base/pages/lib/_doc-content-header.tsx +10 -111
- package/templates/base/pages/lib/_doc-history-area.tsx +19 -211
- package/templates/base/pages/lib/_doc-metainfo-area.tsx +10 -113
- package/templates/base/pages/lib/_doc-page-renderer.tsx +22 -183
- package/templates/base/pages/lib/_doc-page-shell.tsx +17 -251
- package/templates/base/pages/lib/_doc-pager.tsx +4 -74
- package/templates/base/pages/lib/_doc-route-entries.ts +43 -177
- package/templates/base/pages/lib/_doc-route-paths.ts +16 -101
- package/templates/base/pages/lib/_doc-tags-area.tsx +14 -77
- package/templates/base/pages/lib/_extract-headings.ts +21 -295
- package/templates/base/pages/lib/_footer-with-defaults.tsx +37 -225
- package/templates/base/pages/lib/_frontmatter-preview-data.ts +5 -31
- package/templates/base/pages/lib/_head-with-defaults.tsx +13 -138
- package/templates/base/pages/lib/_header-with-defaults.tsx +24 -324
- package/templates/base/pages/lib/_inline-version-switcher.tsx +16 -78
- package/templates/base/pages/lib/_math-block.tsx +4 -63
- package/templates/base/pages/lib/_nav-data-prep.ts +32 -51
- package/templates/base/pages/lib/_nav-source-cache.ts +12 -57
- package/templates/base/pages/lib/_nav-source-docs.ts +33 -233
- package/templates/base/pages/lib/_search-widget-script.ts +2 -470
- package/templates/base/pages/lib/_search-widget.tsx +9 -195
- package/templates/base/pages/lib/_sidebar-prepaint.tsx +6 -59
- package/templates/base/pages/lib/_sidebar-with-defaults.tsx +16 -118
- package/templates/base/pages/lib/_site-tree-nav.tsx +29 -80
- package/templates/base/pages/lib/doc-page-props.ts +26 -44
- package/templates/base/pages/lib/locale-merge.ts +32 -145
- package/templates/base/pages/lib/route-enumerators.ts +52 -286
- package/templates/base/src/components/ai-chat-modal.tsx +9 -8
- package/templates/base/src/components/content/code-group.tsx +3 -76
- package/templates/base/src/components/content/content-admonition.tsx +4 -56
- package/templates/base/src/components/doc-history.tsx +9 -8
- package/templates/base/src/components/image-enlarge.tsx +11 -8
- package/templates/base/src/components/sidebar-toggle.tsx +6 -170
- package/templates/base/src/components/sidebar-tree.tsx +6 -548
- package/templates/base/src/config/color-scheme-utils.ts +34 -158
- package/templates/base/src/config/i18n.ts +9 -0
- package/templates/base/src/config/settings-types.ts +34 -172
- package/templates/base/src/config/z-index-tokens.ts +5 -4
- package/templates/base/src/styles/global.css +40 -587
- package/templates/base/src/utils/base.ts +1 -1
- package/templates/base/src/utils/docs.ts +47 -16
- package/templates/base/src/utils/github.ts +12 -9
- package/templates/base/src/utils/nav-scope.ts +13 -42
- package/templates/base/src/utils/sidebar.ts +18 -86
- package/templates/base/src/utils/slug.ts +10 -53
- package/templates/base/src/utils/smart-break.tsx +12 -120
- package/templates/base/src/utils/tags.ts +25 -68
- package/templates/features/bodyFootUtil/files/src/utils/github.ts +12 -9
- package/templates/features/designTokenPanel/files/src/lib/design-token-panel-bootstrap.ts +13 -39
- package/templates/features/docHistory/files/src/components/doc-history.tsx +8 -636
- package/templates/features/docHistory/files/src/types/doc-history.ts +7 -23
- package/templates/features/docTags/files/pages/lib/_tag-pages.tsx +35 -201
- package/templates/features/i18n/files/pages/[locale]/index.tsx +1 -1
- package/templates/features/imageEnlarge/files/src/components/image-enlarge.tsx +8 -269
- package/templates/features/sidebarToggle/files/src/components/desktop-sidebar-toggle.tsx +6 -99
- package/templates/features/tagGovernance/files/scripts/tags-audit.ts +67 -515
- package/templates/features/versioning/files/pages/lib/_versions-page.tsx +21 -73
- package/templates/base/pages/404.tsx +0 -61
- package/templates/base/pages/robots.txt.tsx +0 -29
- package/templates/base/pages/sitemap.xml.tsx +0 -59
- package/templates/base/plugins/connect-adapter.mjs +0 -169
- package/templates/base/plugins/copy-public-plugin.mjs +0 -58
- package/templates/base/plugins/search-index-plugin.mjs +0 -66
- package/templates/base/scripts/gen-z-index.mjs +0 -157
- package/templates/base/src/components/mermaid-enlarge.tsx +0 -490
- package/templates/base/src/components/site-tree-nav.tsx +0 -220
- package/templates/features/claudeResources/files/plugins/claude-resources-plugin.mjs +0 -47
- package/templates/features/docHistory/files/plugins/doc-history-plugin.mjs +0 -111
- package/templates/features/docTags/files/pages/[locale]/docs/tags/[tag].tsx +0 -59
- package/templates/features/docTags/files/pages/[locale]/docs/tags/index.tsx +0 -39
- package/templates/features/docTags/files/pages/docs/tags/[tag].tsx +0 -43
- package/templates/features/docTags/files/pages/docs/tags/index.tsx +0 -20
- package/templates/features/llmsTxt/files/plugins/llms-txt-plugin.mjs +0 -93
- package/templates/features/versioning/files/pages/[locale]/docs/versions.tsx +0 -48
- package/templates/features/versioning/files/pages/docs/versions.tsx +0 -20
|
@@ -1,57 +1,6 @@
|
|
|
1
1
|
/** @jsxRuntime automatic */
|
|
2
2
|
/** @jsxImportSource preact */
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// Header data-prep utilities — builds the resolved header config from user
|
|
6
|
-
// settings + page context: header nav, active-path state, mobile SidebarToggle
|
|
7
|
-
// island (hamburger + slide-in panel) with the full sidebar tree for doc routes,
|
|
8
|
-
// and feeds everything into the v2 <Header> shell.
|
|
9
|
-
//
|
|
10
|
-
// Why this wrapper exists: the v2 Header shell is intentionally
|
|
11
|
-
// framework-agnostic — it accepts slot props (sidebarToggle, themeToggle,
|
|
12
|
-
// etc.) but does not import host helpers (@/config/*, @/utils/*) so the
|
|
13
|
-
// package can be published independently. The data prep stays on the host
|
|
14
|
-
// side. Without this wrapper the zfb doc pages fall through to the
|
|
15
|
-
// DocLayoutWithDefaults minimal default (a bare <header> with only
|
|
16
|
-
// <ThemeToggle>) — the full logo + nav + mobile-sidebar markup is absent
|
|
17
|
-
// from the SSG output, breaking crawlers, screen readers, and no-JS users.
|
|
18
|
-
//
|
|
19
|
-
// Mobile sidebar strategy:
|
|
20
|
-
// - The v2 <Header> accepts a `sidebarToggle` slot that holds the
|
|
21
|
-
// complete mobile sidebar widget: hamburger button + backdrop overlay +
|
|
22
|
-
// slide-in <aside> panel (all rendered by <SidebarToggle>).
|
|
23
|
-
// - This wrapper ALWAYS builds the sidebarToggle (refs #1453:
|
|
24
|
-
// SidebarToggle is rendered unconditionally on every page; the host CSS
|
|
25
|
-
// hides it on pages with hide_sidebar). When `navSection` is defined the
|
|
26
|
-
// panel gets the full section tree; when undefined (home, 404, tags,
|
|
27
|
-
// versions) nodes=[] so the panel shows only rootMenuItems.
|
|
28
|
-
// - The bare package ThemeToggle (wrapped in Island below) is always passed
|
|
29
|
-
// to Header.themeToggle so the ThemeToggle island marker appears in the
|
|
30
|
-
// header on every page — matching the documented header contract.
|
|
31
|
-
//
|
|
32
|
-
// Locale switcher strategy (refs #1453):
|
|
33
|
-
// - This wrapper always renders <LanguageSwitcher /> in the right-items row
|
|
34
|
-
// when multiple locales are configured. Builds locale links from
|
|
35
|
-
// buildLocaleLinks() and passes a <LanguageSwitcher> as the
|
|
36
|
-
// languageSwitcher slot prop.
|
|
37
|
-
// - Header only renders the slot when settings.locales has > 1 entry, so
|
|
38
|
-
// single-locale projects are unaffected.
|
|
39
|
-
|
|
40
|
-
import type { VNode, JSX } from "preact";
|
|
41
|
-
import { Island } from "@takazudo/zfb";
|
|
42
|
-
import { Header } from "@takazudo/zudo-doc/header";
|
|
43
|
-
import {
|
|
44
|
-
LanguageSwitcher,
|
|
45
|
-
VersionSwitcher,
|
|
46
|
-
type VersionSwitcherLabels,
|
|
47
|
-
} from "@takazudo/zudo-doc/i18n-version";
|
|
48
|
-
// The bare (non-island-wrapped) package ThemeToggle, imported straight from
|
|
49
|
-
// the npm subpath: zfb >= 0.1.0-next.39 scans "use client" modules under
|
|
50
|
-
// node_modules (zfb#999/#1001), so the marker registers without the former
|
|
51
|
-
// project-source shim (#2048/#2057). This header composes its own Island
|
|
52
|
-
// below, avoiding nesting an island inside an island.
|
|
53
|
-
import { ThemeToggle } from "@takazudo/zudo-doc/theme-toggle";
|
|
54
|
-
import SidebarToggle from "@/components/sidebar-toggle";
|
|
3
|
+
// Host thin-stub — see @takazudo/zudo-doc/header-with-defaults (epic #2344, S5).
|
|
55
4
|
import { settings } from "@/config/settings";
|
|
56
5
|
import { defaultLocale, locales, t, type Locale } from "@/config/i18n";
|
|
57
6
|
import { buildGitHubRepoUrl } from "@/utils/github";
|
|
@@ -62,7 +11,7 @@ import {
|
|
|
62
11
|
versionedDocsUrl,
|
|
63
12
|
withBase,
|
|
64
13
|
} from "@/utils/base";
|
|
65
|
-
import {
|
|
14
|
+
import { createHeaderWithDefaults } from "@takazudo/zudo-doc/header-with-defaults";
|
|
66
15
|
import { SearchWidget } from "./_search-widget";
|
|
67
16
|
import {
|
|
68
17
|
buildRootMenuItems,
|
|
@@ -71,275 +20,26 @@ import {
|
|
|
71
20
|
getThemeDefaultMode,
|
|
72
21
|
} from "./_nav-data-prep";
|
|
73
22
|
|
|
74
|
-
|
|
75
|
-
// Component
|
|
76
|
-
// ---------------------------------------------------------------------------
|
|
77
|
-
|
|
78
|
-
export interface HeaderWithDefaultsProps {
|
|
79
|
-
/** Active locale; defaults to the configured defaultLocale. */
|
|
80
|
-
lang?: Locale | string;
|
|
81
|
-
/**
|
|
82
|
-
* Current page URL path (as the layout passes from Astro.url.pathname or
|
|
83
|
-
* the zfb equivalent). Used by the Header to compute the active nav item
|
|
84
|
-
* and by the mobile sidebar footer locale-switcher links.
|
|
85
|
-
*/
|
|
86
|
-
currentPath?: string;
|
|
87
|
-
/** Active version slug, when rendering inside /v/{version}/... routes. */
|
|
88
|
-
currentVersion?: string;
|
|
89
|
-
/**
|
|
90
|
-
* Slug of the active doc page — forwarded to SidebarTree so it can
|
|
91
|
-
* highlight the current entry. Required when navSection is set.
|
|
92
|
-
*/
|
|
93
|
-
currentSlug?: string;
|
|
94
|
-
/**
|
|
95
|
-
* Header-nav category matcher used to scope the sidebar tree (e.g.
|
|
96
|
-
* "guides"). When provided the mobile sidebar toggle is wired with the
|
|
97
|
-
* full sidebar tree for this section. When omitted (404, index, tags,
|
|
98
|
-
* versions pages) no mobile sidebar toggle is included in the header.
|
|
99
|
-
*/
|
|
100
|
-
navSection?: string;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Default-bearing host wrapper around v2's <Header> shell.
|
|
105
|
-
*
|
|
106
|
-
* Handles:
|
|
107
|
-
* 1. Logo, main nav with active-path highlight — delegated to <Header>.
|
|
108
|
-
* 2. ThemeToggle island in the right items row — passed as themeToggle slot.
|
|
109
|
-
* 3. Mobile SidebarToggle island (hamburger + slide-in aside + tree) —
|
|
110
|
-
* built from the same nav data as SidebarWithDefaults and passed as
|
|
111
|
-
* the sidebarToggle slot when navSection is defined.
|
|
112
|
-
*/
|
|
113
|
-
export function HeaderWithDefaults(
|
|
114
|
-
props: HeaderWithDefaultsProps,
|
|
115
|
-
): JSX.Element {
|
|
116
|
-
const {
|
|
117
|
-
lang: langProp = defaultLocale,
|
|
118
|
-
currentPath = "",
|
|
119
|
-
currentVersion,
|
|
120
|
-
currentSlug,
|
|
121
|
-
navSection,
|
|
122
|
-
} = props;
|
|
123
|
-
// Route params arrive as `string`; cast to Locale since keys of settings.locales
|
|
124
|
-
// are always valid locale codes. The prop accepts `Locale | string` so callers
|
|
125
|
-
// without a Locale variable don't need to cast (e.g. _tag-pages.tsx).
|
|
126
|
-
const lang = langProp as Locale;
|
|
127
|
-
|
|
128
|
-
// Root-menu items, locale links, sidebar nodes, and theme mode — all
|
|
129
|
-
// delegated to the shared _nav-data-prep helpers so header and sidebar
|
|
130
|
-
// wrappers stay in sync without duplicating the logic.
|
|
131
|
-
const rootMenuItems = buildRootMenuItems(lang, currentVersion);
|
|
132
|
-
|
|
133
|
-
// Build the mobile sidebar toggle unconditionally — SidebarToggle is rendered
|
|
134
|
-
// on every page (refs #1453); the host CSS hides it where unneeded. When navSection is
|
|
135
|
-
// defined the panel gets the full section tree; when undefined (home, 404,
|
|
136
|
-
// tags, versions) nodes=[] so the panel shows only rootMenuItems + locale
|
|
137
|
-
// links (the basic nav menu without a doc tree).
|
|
138
|
-
const backToMenuLabel = t("nav.backToMenu", lang);
|
|
139
|
-
|
|
140
|
-
// Locale-switcher links in the mobile sidebar footer — only when
|
|
141
|
-
// multiple locales are configured (mirrors _sidebar-with-defaults.tsx).
|
|
142
|
-
const localeLinks = buildLocaleLinksForNav(currentPath, lang, locales.length);
|
|
143
|
-
|
|
144
|
-
const themeDefaultMode = getThemeDefaultMode();
|
|
145
|
-
|
|
146
|
-
const sidebarNodes = buildSidebarNodes(lang, navSection, currentVersion);
|
|
147
|
-
|
|
148
|
-
// Wrap SidebarToggle (hamburger button + slide-in aside + SidebarTree) in
|
|
149
|
-
// Island so the SSG output carries the full tree HTML AND the
|
|
150
|
-
// data-zfb-island="SidebarToggle" marker for client-side hydration.
|
|
151
|
-
// Island.captureComponentName reads SidebarToggle.name → "SidebarToggle".
|
|
152
|
-
//
|
|
153
|
-
// SidebarTree's data props (nodes, currentSlug, rootMenuItems, …) are
|
|
154
|
-
// passed to SidebarToggle directly rather than as JSX children so they
|
|
155
|
-
// ride across the SSR → hydrate boundary in the Island marker's
|
|
156
|
-
// `data-props` attribute. Island only serialises a wrapped child
|
|
157
|
-
// component's *own* props (excluding `children`); when SidebarTree was
|
|
158
|
-
// nested as a JSX child its data was dropped during hydration and
|
|
159
|
-
// SidebarToggle re-rendered with `children=undefined`, wiping the SSR
|
|
160
|
-
// tree DOM. zudolab/zudo-doc#1355 wave 13.5.
|
|
161
|
-
//
|
|
162
|
-
// C4 — media-gated hydration. zfb only supports load|idle|visible
|
|
163
|
-
// strategies (no "media" strategy; matchMedia inside the component is too
|
|
164
|
-
// late — props are already emitted, bundle already downloaded).
|
|
165
|
-
// Upstream feature request: Takazudo/zudo-front-builder#969.
|
|
166
|
-
//
|
|
167
|
-
// Best achievable downstream: when="visible" + all SidebarToggle children
|
|
168
|
-
// are lg:hidden, so on desktop the Island wrapper div has zero rendered
|
|
169
|
-
// dimensions. IntersectionObserver fires isIntersecting=false on desktop
|
|
170
|
-
// (zero-size element) → Preact hydrate() is never called. On mobile (and
|
|
171
|
-
// on desktop→mobile resize) the children become visible, the element gains
|
|
172
|
-
// size, IO fires isIntersecting=true, and hydration completes normally.
|
|
173
|
-
//
|
|
174
|
-
// Residual: data-props JSON (~2.4 KB) is still emitted in the SSR HTML on
|
|
175
|
-
// every page regardless of viewport, because it is serialised at build time
|
|
176
|
-
// and not gated by media. Eliminating it requires a zfb "media" hydration
|
|
177
|
-
// strategy — tracked in Takazudo/zudo-front-builder#969.
|
|
178
|
-
const sidebarToggle = Island({
|
|
179
|
-
when: "visible",
|
|
180
|
-
children: (
|
|
181
|
-
<SidebarToggle
|
|
182
|
-
nodes={sidebarNodes}
|
|
183
|
-
currentSlug={currentSlug}
|
|
184
|
-
rootMenuItems={rootMenuItems}
|
|
185
|
-
backToMenuLabel={backToMenuLabel}
|
|
186
|
-
localeLinks={localeLinks}
|
|
187
|
-
themeDefaultMode={themeDefaultMode}
|
|
188
|
-
/>
|
|
189
|
-
),
|
|
190
|
-
}) as unknown as VNode;
|
|
191
|
-
|
|
192
|
-
// Wrap the bare ThemeToggle in Island({when:"load"}) so the SSG
|
|
193
|
-
// output emits a data-zfb-island="ThemeToggle" marker the hydration
|
|
194
|
-
// runtime can find — matching the documented header contract.
|
|
195
|
-
const themeToggle = Island({
|
|
196
|
-
when: "load",
|
|
197
|
-
children: <ThemeToggle defaultMode={themeDefaultMode} />,
|
|
198
|
-
}) as unknown as VNode;
|
|
199
|
-
|
|
200
|
-
// Locale-aware search widget. Renders the full dialog markup in SSR
|
|
201
|
-
// so the placeholder text ("Type to search..." / 「検索したい単語を入力」)
|
|
202
|
-
// and keyboard-shortcut hint appear in the static HTML on every page.
|
|
203
|
-
// Strings are derived from the host's t() helper so locale switching works.
|
|
204
|
-
const searchWidget = (
|
|
205
|
-
<SearchWidget
|
|
206
|
-
placeholderText={t("search.placeholder", lang)}
|
|
207
|
-
shortcutHint={t("search.shortcutHint", lang)}
|
|
208
|
-
resultCountTemplate={t("search.resultCount", lang)}
|
|
209
|
-
searchLabel={t("search.label", lang)}
|
|
210
|
-
/>
|
|
211
|
-
);
|
|
23
|
+
export type { HeaderWithDefaultsProps } from "@takazudo/zudo-doc/header-with-defaults";
|
|
212
24
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
// and must produce real per-version root URLs.
|
|
235
|
-
const latestUrl = currentSlug != null
|
|
236
|
-
? docsUrl(currentSlug, lang)
|
|
237
|
-
: versionsPageUrl;
|
|
238
|
-
|
|
239
|
-
// Per-version URLs for the current page. When there is no slug in scope
|
|
240
|
-
// (e.g. on the versions page itself) all entries point to the versions
|
|
241
|
-
// index — matching the documented version-switcher contract.
|
|
242
|
-
const versionUrls: Record<string, string> = {};
|
|
243
|
-
for (const v of settings.versions) {
|
|
244
|
-
versionUrls[v.slug] = currentSlug != null
|
|
245
|
-
? versionedDocsUrl(currentSlug, v.slug, lang)
|
|
246
|
-
: versionsPageUrl;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
const labels: VersionSwitcherLabels = {
|
|
250
|
-
latest: t("version.latest", lang),
|
|
251
|
-
switcher: t("version.switcher.label", lang),
|
|
252
|
-
unavailable: t("version.switcher.unavailable", lang),
|
|
253
|
-
allVersions: t("version.switcher.allVersions", lang),
|
|
254
|
-
};
|
|
255
|
-
|
|
256
|
-
versionSwitcher = (
|
|
257
|
-
<VersionSwitcher
|
|
258
|
-
versions={settings.versions.map((v) => ({
|
|
259
|
-
slug: v.slug,
|
|
260
|
-
label: v.label ?? v.slug,
|
|
261
|
-
}))}
|
|
262
|
-
currentVersion={currentVersion}
|
|
263
|
-
latestUrl={latestUrl}
|
|
264
|
-
versionsPageUrl={versionsPageUrl}
|
|
265
|
-
versionUrls={versionUrls}
|
|
266
|
-
labels={labels}
|
|
267
|
-
idSuffix="header"
|
|
268
|
-
/>
|
|
269
|
-
) as unknown as VNode;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
// Build locale-switcher for the header right-items row (refs #1453).
|
|
273
|
-
// Renders <LanguageSwitcher /> when multiple locales are configured.
|
|
274
|
-
// Reuses the same localeLinks array built above for the mobile sidebar footer
|
|
275
|
-
// (buildLocaleLinks is pure, but one call is cleaner).
|
|
276
|
-
const languageSwitcher =
|
|
277
|
-
localeLinks != null ? (
|
|
278
|
-
<LanguageSwitcher
|
|
279
|
-
links={localeLinks}
|
|
280
|
-
/>
|
|
281
|
-
) as unknown as VNode : undefined;
|
|
282
|
-
|
|
283
|
-
// Locale-keyed persist key: same-locale swaps preserve the header's
|
|
284
|
-
// DOM-node identity; cross-locale swaps use a different key and the
|
|
285
|
-
// router replaces the header entirely (re-rendering locale-specific
|
|
286
|
-
// SSR content such as the LanguageSwitcher anchors). See #1546 + #1549.
|
|
287
|
-
const persistKey = `header-${lang}`;
|
|
288
|
-
|
|
289
|
-
// Compute the right-items flags from the host's settings. The v2
|
|
290
|
-
// `<Header>` no longer consults `@/config/settings` directly — see
|
|
291
|
-
// sub-issue #1729 — so the wrapper is responsible for translating
|
|
292
|
-
// host state into the prop bag the renderer expects. Boolean
|
|
293
|
-
// coercion mirrors the original filter predicates verbatim.
|
|
294
|
-
const headerRightItems = filterHeaderRightItems(
|
|
295
|
-
settings.headerRightItems ?? [],
|
|
296
|
-
{
|
|
297
|
-
designTokenPanel: Boolean(settings.designTokenPanel),
|
|
298
|
-
aiAssistant: Boolean(settings.aiAssistant),
|
|
299
|
-
colorMode: Boolean(settings.colorMode),
|
|
300
|
-
hasLocales: Object.keys(settings.locales).length > 0,
|
|
301
|
-
hasVersions: Boolean(settings.versions),
|
|
302
|
-
hasGithubUrl: Boolean(settings.githubUrl),
|
|
303
|
-
},
|
|
304
|
-
);
|
|
305
|
-
|
|
306
|
-
const githubRepoUrl = buildGitHubRepoUrl();
|
|
307
|
-
const githubLabel = t("header.github", lang);
|
|
308
|
-
|
|
309
|
-
return (
|
|
310
|
-
<Header
|
|
311
|
-
lang={lang}
|
|
312
|
-
currentPath={currentPath}
|
|
313
|
-
currentVersion={currentVersion}
|
|
314
|
-
activeCategory={navSection}
|
|
315
|
-
sidebarToggle={sidebarToggle}
|
|
316
|
-
themeToggle={themeToggle}
|
|
317
|
-
search={searchWidget}
|
|
318
|
-
versionSwitcher={versionSwitcher}
|
|
319
|
-
languageSwitcher={languageSwitcher}
|
|
320
|
-
persistKey={persistKey}
|
|
321
|
-
siteName={settings.siteName}
|
|
322
|
-
headerNav={settings.headerNav}
|
|
323
|
-
headerRightItems={headerRightItems}
|
|
324
|
-
colorModeEnabled={Boolean(settings.colorMode)}
|
|
325
|
-
hasLocales={locales.length > 1}
|
|
326
|
-
hasVersions={Boolean(settings.versions)}
|
|
327
|
-
githubRepoUrl={githubRepoUrl}
|
|
328
|
-
githubLabel={githubLabel}
|
|
329
|
-
urlHelpers={{
|
|
330
|
-
withBase,
|
|
331
|
-
stripBase,
|
|
332
|
-
// `navHref` from `@/utils/base` types the lang param as the
|
|
333
|
-
// host's literal-locale union; v2's `Locale` is `string`. Wrap
|
|
334
|
-
// so strictFunctionTypes accepts the assignment without losing
|
|
335
|
-
// the runtime call shape (sub-issue #1729 boundary widening).
|
|
336
|
-
navHref: (path, l, v) => navHref(path, l as Locale | undefined, v),
|
|
337
|
-
}}
|
|
338
|
-
i18n={{
|
|
339
|
-
defaultLocale,
|
|
340
|
-
locales,
|
|
341
|
-
t,
|
|
342
|
-
}}
|
|
343
|
-
/>
|
|
344
|
-
);
|
|
345
|
-
}
|
|
25
|
+
export const HeaderWithDefaults = createHeaderWithDefaults({
|
|
26
|
+
settings,
|
|
27
|
+
defaultLocale,
|
|
28
|
+
locales,
|
|
29
|
+
t: (key, lang) => t(key as Parameters<typeof t>[0], lang as Locale),
|
|
30
|
+
withBase,
|
|
31
|
+
stripBase,
|
|
32
|
+
docsUrl: (slug, lang) => docsUrl(slug, lang as Locale),
|
|
33
|
+
navHref: (path, lang, version) => navHref(path, lang as Locale | undefined, version),
|
|
34
|
+
versionedDocsUrl: (slug, versionSlug, lang) =>
|
|
35
|
+
versionedDocsUrl(slug, versionSlug, lang as Locale),
|
|
36
|
+
buildLocaleLinksForNav: (currentPath, lang, localeCount) =>
|
|
37
|
+
buildLocaleLinksForNav(currentPath, lang as Locale, localeCount),
|
|
38
|
+
buildRootMenuItems: (lang, currentVersion) =>
|
|
39
|
+
buildRootMenuItems(lang as Locale, currentVersion),
|
|
40
|
+
buildSidebarNodes: (lang, navSection, currentVersion) =>
|
|
41
|
+
buildSidebarNodes(lang as Locale, navSection, currentVersion),
|
|
42
|
+
getThemeDefaultMode,
|
|
43
|
+
buildGitHubRepoUrl,
|
|
44
|
+
SearchWidget,
|
|
45
|
+
});
|
|
@@ -1,85 +1,23 @@
|
|
|
1
1
|
/** @jsxRuntime automatic */
|
|
2
2
|
/** @jsxImportSource preact */
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
// <div class="mb-vsp-sm flex ... sm:justify-between [&_nav]:mb-0">
|
|
9
|
-
// <breadcrumb nav>
|
|
10
|
-
// <VersionSwitcher ... />
|
|
11
|
-
// </div>
|
|
12
|
-
//
|
|
13
|
-
// (Wave 2 parity sweep, zudolab/zudo-doc#1478; placement fix #1534.)
|
|
14
|
-
// The header already shows a VersionSwitcher via _header-with-defaults.tsx;
|
|
15
|
-
// this helper provides the pill for the breadcrumb's `rightSlot` prop so
|
|
16
|
-
// both the DOM position AND the flex-row layout match the reference.
|
|
17
|
-
//
|
|
18
|
-
// Gate: only returns a non-null element when settings.versions is a
|
|
19
|
-
// non-empty array. When versioning is disabled the caller gets undefined
|
|
20
|
-
// and <Breadcrumb> renders without a rightSlot (no wrapper div emitted).
|
|
3
|
+
// Thin stub — inline-version-switcher moved to the package (epic #2344, S8).
|
|
4
|
+
// Calls `createInlineVersionSwitcher(deps)` from
|
|
5
|
+
// @takazudo/zudo-doc/inline-version-switcher with host singletons injected,
|
|
6
|
+
// then re-exports the resulting builder so all existing call sites continue
|
|
7
|
+
// to work unchanged.
|
|
21
8
|
|
|
22
|
-
import
|
|
23
|
-
import {
|
|
24
|
-
VersionSwitcher,
|
|
25
|
-
type VersionSwitcherLabels,
|
|
26
|
-
} from "@takazudo/zudo-doc/i18n-version";
|
|
9
|
+
import { createInlineVersionSwitcher } from "@takazudo/zudo-doc/inline-version-switcher";
|
|
27
10
|
import { settings } from "@/config/settings";
|
|
28
|
-
import { defaultLocale, t
|
|
11
|
+
import { defaultLocale, t } from "@/config/i18n";
|
|
29
12
|
import { docsUrl, versionedDocsUrl, withBase } from "@/utils/base";
|
|
30
13
|
|
|
31
|
-
|
|
32
|
-
* Build an inline VersionSwitcher element for the `<Breadcrumb rightSlot>` prop.
|
|
33
|
-
*
|
|
34
|
-
* Returns `undefined` when versioning is not configured (callers can pass
|
|
35
|
-
* the return value directly as `rightSlot` — `<Breadcrumb>` renders the
|
|
36
|
-
* plain nav (no flex wrapper, no version pill) when `rightSlot` is
|
|
37
|
-
* `undefined`).
|
|
38
|
-
*
|
|
39
|
-
* @param slug - Slug of the current doc page (used to build per-version URLs).
|
|
40
|
-
* @param locale - Active locale string.
|
|
41
|
-
* @param currentVersion - Active version slug, or `undefined` on the "latest" route.
|
|
42
|
-
*/
|
|
43
|
-
export function buildInlineVersionSwitcher(
|
|
44
|
-
slug: string,
|
|
45
|
-
locale: Locale,
|
|
46
|
-
currentVersion?: string,
|
|
47
|
-
): JSX.Element | undefined {
|
|
48
|
-
if (!settings.versions || settings.versions.length === 0) return undefined;
|
|
14
|
+
export { type InlineVersionSwitcherVersionEntry } from "@takazudo/zudo-doc/inline-version-switcher";
|
|
49
15
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const versionUrls: Record<string, string> = {};
|
|
60
|
-
for (const v of settings.versions) {
|
|
61
|
-
versionUrls[v.slug] = versionedDocsUrl(slug, v.slug, locale);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const labels: VersionSwitcherLabels = {
|
|
65
|
-
latest: t("version.latest", locale),
|
|
66
|
-
switcher: t("version.switcher.label", locale),
|
|
67
|
-
unavailable: t("version.switcher.unavailable", locale),
|
|
68
|
-
allVersions: t("version.switcher.allVersions", locale),
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
return (
|
|
72
|
-
<VersionSwitcher
|
|
73
|
-
versions={settings.versions.map((v) => ({
|
|
74
|
-
slug: v.slug,
|
|
75
|
-
label: v.label ?? v.slug,
|
|
76
|
-
}))}
|
|
77
|
-
currentVersion={currentVersion}
|
|
78
|
-
latestUrl={latestUrl}
|
|
79
|
-
versionsPageUrl={versionsPageUrl}
|
|
80
|
-
versionUrls={versionUrls}
|
|
81
|
-
labels={labels}
|
|
82
|
-
idSuffix="inline"
|
|
83
|
-
/>
|
|
84
|
-
);
|
|
85
|
-
}
|
|
16
|
+
export const buildInlineVersionSwitcher = createInlineVersionSwitcher({
|
|
17
|
+
settings,
|
|
18
|
+
defaultLocale,
|
|
19
|
+
t,
|
|
20
|
+
docsUrl,
|
|
21
|
+
versionedDocsUrl,
|
|
22
|
+
withBase,
|
|
23
|
+
});
|
|
@@ -1,63 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
// Registered in pages/_mdx-components.ts as `MathBlock` so the MDX corpus
|
|
6
|
-
// can reference it as <MathBlock latex="…" block />.
|
|
7
|
-
//
|
|
8
|
-
// Used by the math-equations.mdx content files (both EN and JA) which write
|
|
9
|
-
// `<MathBlock>` JSX directly instead of `$$…$$` fences. The explicit JSX
|
|
10
|
-
// form is required because the zfb Rust MDX→JSX emitter does not understand
|
|
11
|
-
// remark-math `$$…$$` syntax — LaTeX identifiers like `\infty` become invalid
|
|
12
|
-
// JSX expressions `{\infty}` that esbuild rejects (zudo-front-builder #93).
|
|
13
|
-
// Using `<MathBlock>` directly keeps the LaTeX inside a string attribute,
|
|
14
|
-
// which esbuild accepts cleanly.
|
|
15
|
-
//
|
|
16
|
-
// Rendering: katex.renderToString() is called at SSR time — no client JS.
|
|
17
|
-
// `throwOnError: false` keeps a broken formula visible as an error span
|
|
18
|
-
// rather than crashing the page.
|
|
19
|
-
|
|
20
|
-
import katex from "katex";
|
|
21
|
-
import type { VNode } from "preact";
|
|
22
|
-
|
|
23
|
-
interface MathBlockProps {
|
|
24
|
-
/** Raw LaTeX source string. */
|
|
25
|
-
latex: string;
|
|
26
|
-
/** When true, renders as a block (display) equation; otherwise inline. */
|
|
27
|
-
block?: boolean;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Server-rendered KaTeX math component.
|
|
32
|
-
*
|
|
33
|
-
* Block mode wraps the output in `<div class="math math-display">`;
|
|
34
|
-
* inline mode uses `<span class="math math-inline">`. The class names
|
|
35
|
-
* match the standard rehype-katex output so existing CSS (e.g. the
|
|
36
|
-
* KaTeX stylesheet) still applies.
|
|
37
|
-
*/
|
|
38
|
-
export function MathBlock({ latex, block = false }: MathBlockProps): VNode {
|
|
39
|
-
const html = katex.renderToString(latex, {
|
|
40
|
-
displayMode: block,
|
|
41
|
-
// Never throw — malformed LaTeX renders a visible error span instead
|
|
42
|
-
// of crashing the entire page build.
|
|
43
|
-
throwOnError: false,
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
if (block) {
|
|
47
|
-
return (
|
|
48
|
-
<div
|
|
49
|
-
class="math math-display"
|
|
50
|
-
// eslint-disable-next-line react/no-danger
|
|
51
|
-
dangerouslySetInnerHTML={{ __html: html }}
|
|
52
|
-
/>
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return (
|
|
57
|
-
<span
|
|
58
|
-
class="math math-inline"
|
|
59
|
-
// eslint-disable-next-line react/no-danger
|
|
60
|
-
dangerouslySetInnerHTML={{ __html: html }}
|
|
61
|
-
/>
|
|
62
|
-
);
|
|
63
|
-
}
|
|
1
|
+
// Re-export from the shared package — moved to @takazudo/zudo-doc/math-block
|
|
2
|
+
// as part of the package-first migration (epic #2321, S4 #2327).
|
|
3
|
+
export type { MathBlockProps } from "@takazudo/zudo-doc/math-block";
|
|
4
|
+
export { MathBlock } from "@takazudo/zudo-doc/math-block";
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
//
|
|
2
|
-
// and
|
|
1
|
+
// Host thin-stub for nav data-prep utilities (epic #2344, S5).
|
|
2
|
+
// Imports core logic from @takazudo/zudo-doc and wires host singletons.
|
|
3
3
|
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
4
|
+
// Package exports the pure parameterized functions; this stub binds
|
|
5
|
+
// them to the host's `settings`, `i18n`, and `base` singletons so
|
|
6
|
+
// existing call sites (_header-with-defaults.tsx, _sidebar-with-defaults.tsx)
|
|
7
|
+
// are unchanged.
|
|
7
8
|
|
|
8
9
|
import { settings } from "@/config/settings";
|
|
9
10
|
import { t, type Locale } from "@/config/i18n";
|
|
@@ -15,6 +16,12 @@ import {
|
|
|
15
16
|
import { type NavNode } from "@/utils/docs";
|
|
16
17
|
import { buildSidebarForSection } from "@/utils/sidebar";
|
|
17
18
|
import { loadNavSourceDocs } from "./_nav-source-docs";
|
|
19
|
+
import {
|
|
20
|
+
remapVersionedHrefs as _remapVersionedHrefs,
|
|
21
|
+
buildRootMenuItems as _buildRootMenuItems,
|
|
22
|
+
buildLocaleLinksForNav as _buildLocaleLinksForNav,
|
|
23
|
+
getThemeDefaultMode as _getThemeDefaultMode,
|
|
24
|
+
} from "@takazudo/zudo-doc/nav-data-prep";
|
|
18
25
|
|
|
19
26
|
// ---------------------------------------------------------------------------
|
|
20
27
|
// remapVersionedHrefs
|
|
@@ -22,30 +29,18 @@ import { loadNavSourceDocs } from "./_nav-source-docs";
|
|
|
22
29
|
|
|
23
30
|
/**
|
|
24
31
|
* Walk the nav tree and rewrite each node's `href` to its versioned form.
|
|
25
|
-
*
|
|
26
|
-
* `buildNavTree` always emits hrefs via `docsUrl()`; when the active route
|
|
27
|
-
* lives under `/v/{version}/...` we need the same nodes pointing at the
|
|
28
|
-
* versioned URL so internal nav clicks stay inside the version. Skips
|
|
29
|
-
* nodes without an href (link-only or category placeholders).
|
|
30
32
|
*/
|
|
31
33
|
export function remapVersionedHrefs(
|
|
32
34
|
nodes: NavNode[],
|
|
33
35
|
version: string,
|
|
34
36
|
nodeLang: Locale,
|
|
35
37
|
): NavNode[] {
|
|
36
|
-
return
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
if (!node.href || node.slug.startsWith("__link__")) {
|
|
43
|
-
return children !== node.children ? { ...node, children } : node;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const newHref = versionedDocsUrl(node.slug, version, nodeLang);
|
|
47
|
-
return { ...node, href: newHref, children };
|
|
48
|
-
});
|
|
38
|
+
return _remapVersionedHrefs(
|
|
39
|
+
nodes,
|
|
40
|
+
version,
|
|
41
|
+
nodeLang,
|
|
42
|
+
(slug, v, lang) => versionedDocsUrl(slug, v, lang as Locale),
|
|
43
|
+
);
|
|
49
44
|
}
|
|
50
45
|
|
|
51
46
|
// ---------------------------------------------------------------------------
|
|
@@ -54,26 +49,18 @@ export function remapVersionedHrefs(
|
|
|
54
49
|
|
|
55
50
|
/**
|
|
56
51
|
* Root-menu items derived from settings.headerNav (mobile "back to menu" list).
|
|
57
|
-
*
|
|
58
|
-
* Used by both header and sidebar wrappers — the same nav data feeds both the
|
|
59
|
-
* mobile SidebarToggle (header) and the desktop SidebarTree (sidebar).
|
|
60
52
|
*/
|
|
61
53
|
export function buildRootMenuItems(
|
|
62
54
|
lang: Locale,
|
|
63
55
|
currentVersion?: string,
|
|
64
56
|
) {
|
|
65
|
-
return
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
? t(child.labelKey as Parameters<typeof t>[0], lang)
|
|
73
|
-
: child.label,
|
|
74
|
-
href: navHref(child.path, lang, currentVersion),
|
|
75
|
-
})),
|
|
76
|
-
}));
|
|
57
|
+
return _buildRootMenuItems(
|
|
58
|
+
lang,
|
|
59
|
+
currentVersion,
|
|
60
|
+
settings.headerNav,
|
|
61
|
+
(key, l) => t(key as Parameters<typeof t>[0], l as Locale),
|
|
62
|
+
(path, l, v) => navHref(path, l as Locale | undefined, v),
|
|
63
|
+
);
|
|
77
64
|
}
|
|
78
65
|
|
|
79
66
|
// ---------------------------------------------------------------------------
|
|
@@ -89,7 +76,12 @@ export function buildLocaleLinksForNav(
|
|
|
89
76
|
lang: Locale,
|
|
90
77
|
localeCount: number,
|
|
91
78
|
) {
|
|
92
|
-
return
|
|
79
|
+
return _buildLocaleLinksForNav(
|
|
80
|
+
currentPath,
|
|
81
|
+
lang,
|
|
82
|
+
localeCount,
|
|
83
|
+
(path, l) => buildLocaleLinks(path, l as Locale),
|
|
84
|
+
);
|
|
93
85
|
}
|
|
94
86
|
|
|
95
87
|
// ---------------------------------------------------------------------------
|
|
@@ -98,17 +90,6 @@ export function buildLocaleLinksForNav(
|
|
|
98
90
|
|
|
99
91
|
/**
|
|
100
92
|
* Build the resolved sidebar node list for a given section + version.
|
|
101
|
-
*
|
|
102
|
-
* Loads the nav source, filters to the active section, then optionally
|
|
103
|
-
* remaps hrefs for versioned routes.
|
|
104
|
-
*
|
|
105
|
-
* `emptyWhenUnsectioned` controls the `navSection === undefined` case —
|
|
106
|
-
* the two legacy call sites deliberately disagreed: the header's mobile
|
|
107
|
-
* drawer returned `[]` (root menu only), while the desktop sidebar fell
|
|
108
|
-
* through to `buildSidebarForSection(..., undefined)` = the FULL tree
|
|
109
|
-
* (pages whose slug matches no headerNav categoryMatch still get a
|
|
110
|
-
* sidebar). Collapsing both to `[]` shipped an empty desktop sidebar for
|
|
111
|
-
* unsectioned pages — keep the divergence explicit here.
|
|
112
93
|
*/
|
|
113
94
|
export function buildSidebarNodes(
|
|
114
95
|
lang: Locale,
|
|
@@ -133,5 +114,5 @@ export function buildSidebarNodes(
|
|
|
133
114
|
* Returns `undefined` when color mode is not configured (single-scheme projects).
|
|
134
115
|
*/
|
|
135
116
|
export function getThemeDefaultMode() {
|
|
136
|
-
return settings.colorMode
|
|
117
|
+
return _getThemeDefaultMode(settings.colorMode);
|
|
137
118
|
}
|