create-zudo-doc 3.1.0 → 3.3.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/claude-md-gen.d.ts +8 -0
- package/dist/claude-md-gen.js +43 -26
- package/dist/compose.d.ts +14 -20
- package/dist/compose.js +15 -25
- package/dist/features/body-foot-util.d.ts +8 -4
- package/dist/features/body-foot-util.js +8 -4
- package/dist/features/claude-resources.d.ts +12 -0
- package/dist/features/claude-resources.js +13 -6
- package/dist/features/design-token-panel.d.ts +0 -12
- package/dist/features/design-token-panel.js +32 -93
- package/dist/features/doc-history.d.ts +18 -3
- package/dist/features/doc-history.js +45 -60
- package/dist/features/doc-tags.d.ts +9 -13
- package/dist/features/doc-tags.js +10 -26
- package/dist/features/dynamic-page-transition.d.ts +19 -30
- package/dist/features/dynamic-page-transition.js +21 -209
- package/dist/features/footer-taglist.d.ts +1 -1
- package/dist/features/footer-taglist.js +1 -1
- package/dist/features/footer.d.ts +3 -2
- package/dist/features/footer.js +3 -2
- package/dist/features/i18n.d.ts +13 -8
- package/dist/features/i18n.js +14 -9
- package/dist/features/image-enlarge.d.ts +7 -26
- package/dist/features/image-enlarge.js +7 -26
- package/dist/features/llms-txt.d.ts +3 -5
- package/dist/features/llms-txt.js +3 -5
- package/dist/features/search.d.ts +7 -3
- package/dist/features/search.js +7 -3
- package/dist/features/sidebar-resizer.d.ts +4 -8
- package/dist/features/sidebar-resizer.js +4 -8
- package/dist/features/sidebar-toggle.d.ts +7 -7
- package/dist/features/sidebar-toggle.js +7 -7
- package/dist/features/tag-governance.d.ts +14 -7
- package/dist/features/tag-governance.js +52 -8
- package/dist/features/tauri.d.ts +13 -10
- package/dist/features/tauri.js +16 -52
- package/dist/features/versioning.d.ts +12 -24
- package/dist/features/versioning.js +13 -39
- package/dist/index.js +2 -3
- package/dist/preset.d.ts +1 -0
- package/dist/preset.js +5 -0
- package/dist/prompts.d.ts +2 -0
- package/dist/prompts.js +1 -0
- package/dist/scaffold.d.ts +13 -6
- package/dist/scaffold.js +78 -59
- package/dist/utils.d.ts +10 -0
- package/dist/utils.js +14 -0
- package/dist/zfb-config-gen.d.ts +32 -20
- package/dist/zfb-config-gen.js +400 -53
- package/package.json +2 -2
- package/templates/base/pages/docs/[[...slug]].tsx +59 -0
- package/templates/base/pages/index.tsx +6 -41
- package/templates/base/scripts/setup-doc-skill.sh +261 -0
- package/templates/base/src/styles/global.css +15 -340
- package/templates/base/tsconfig.json +3 -26
- package/templates/features/i18n/files/pages/[locale]/docs/[[...slug]].tsx +88 -0
- package/templates/features/tagGovernance/files/scripts/tags-suggest.ts +3 -1
- package/dist/settings-gen.d.ts +0 -2
- package/dist/settings-gen.js +0 -319
- package/templates/base/.htmlvalidate.json +0 -5
- package/templates/base/.zfb/doc-history-meta.json +0 -1
- package/templates/base/pages/_data.ts +0 -160
- package/templates/base/pages/lib/_body-end-islands.tsx +0 -165
- package/templates/base/pages/lib/_chrome.ts +0 -167
- package/templates/base/pages/lib/_details.tsx +0 -29
- package/templates/base/pages/lib/_doc-route-entries.ts +0 -10
- package/templates/base/pages/lib/_extract-headings.ts +0 -37
- package/templates/base/pages/lib/_frontmatter-preview-data.ts +0 -27
- package/templates/base/pages/lib/_nav-source-cache.ts +0 -100
- package/templates/base/pages/lib/_nav-source-docs.ts +0 -17
- package/templates/base/pages/lib/_preset-generator.tsx +0 -81
- package/templates/base/pages/lib/_route-context.ts +0 -32
- package/templates/base/pages/lib/_search-widget.tsx +0 -17
- package/templates/base/pages/lib/doc-page-props.ts +0 -30
- package/templates/base/pages/lib/locale-merge.ts +0 -59
- package/templates/base/scripts/run-b4push.sh +0 -102
- package/templates/base/src/components/ai-chat-modal.tsx +0 -18
- package/templates/base/src/components/content/code-group.tsx +0 -3
- package/templates/base/src/components/content/content-admonition.tsx +0 -4
- package/templates/base/src/components/desktop-sidebar-toggle.tsx +0 -15
- package/templates/base/src/components/doc-history.tsx +0 -21
- package/templates/base/src/components/image-enlarge.tsx +0 -24
- package/templates/base/src/components/preset-generator.tsx +0 -14
- package/templates/base/src/components/sidebar-toggle.tsx +0 -6
- package/templates/base/src/components/sidebar-tree.tsx +0 -6
- package/templates/base/src/config/color-scheme-utils.ts +0 -69
- package/templates/base/src/config/color-schemes.ts +0 -165
- package/templates/base/src/config/docs-schema.ts +0 -95
- package/templates/base/src/config/frontmatter-preview-defaults.ts +0 -27
- package/templates/base/src/config/frontmatter-preview-renderers.tsx +0 -46
- package/templates/base/src/config/i18n.ts +0 -239
- package/templates/base/src/config/settings-types.ts +0 -45
- package/templates/base/src/config/sidebars.ts +0 -66
- package/templates/base/src/config/tag-vocabulary-types.ts +0 -4
- package/templates/base/src/config/tag-vocabulary.ts +0 -20
- package/templates/base/src/config/z-index-tokens.ts +0 -128
- package/templates/base/src/types/docs-entry.ts +0 -28
- package/templates/base/src/types/heading.ts +0 -5
- package/templates/base/src/types/locale.ts +0 -10
- package/templates/base/src/utils/base.ts +0 -164
- package/templates/base/src/utils/docs.ts +0 -446
- package/templates/base/src/utils/git-info.ts +0 -70
- package/templates/base/src/utils/github.ts +0 -22
- package/templates/base/src/utils/nav-scope.ts +0 -34
- package/templates/base/src/utils/sidebar.ts +0 -36
- package/templates/base/src/utils/slug.ts +0 -10
- package/templates/base/src/utils/smart-break.tsx +0 -12
- package/templates/base/src/utils/tags.ts +0 -83
- package/templates/base/zfb-shim.d.ts +0 -178
- package/templates/features/bodyFootUtil/files/src/utils/github.ts +0 -22
- package/templates/features/claudeResources/files/src/integrations/claude-resources/__tests__/escape-for-mdx.test.ts +0 -42
- package/templates/features/claudeResources/files/src/integrations/claude-resources/__tests__/generate.test.ts +0 -752
- package/templates/features/claudeResources/files/src/integrations/claude-resources/escape-for-mdx.ts +0 -97
- package/templates/features/claudeResources/files/src/integrations/claude-resources/generate.ts +0 -735
- package/templates/features/designTokenPanel/files/src/components/design-token-panel-bootstrap.tsx +0 -15
- package/templates/features/designTokenPanel/files/src/config/design-token-panel-config.ts +0 -435
- package/templates/features/designTokenPanel/files/src/config/design-tokens-manifest.ts +0 -174
- package/templates/features/designTokenPanel/files/src/lib/design-token-panel-bootstrap.ts +0 -30
- package/templates/features/docHistory/files/src/components/doc-history.tsx +0 -10
- package/templates/features/docHistory/files/src/types/doc-history.ts +0 -7
- package/templates/features/dynamicPageTransition/files/src/components/client-router-bootstrap.tsx +0 -72
- package/templates/features/i18n/files/pages/[locale]/index.tsx +0 -72
- package/templates/features/imageEnlarge/files/src/components/image-enlarge.tsx +0 -11
- package/templates/features/sidebarToggle/files/src/components/desktop-sidebar-toggle.tsx +0 -6
- package/templates/features/tauri/files/src/components/find-bar.tsx +0 -122
- package/templates/features/tauri/files/src/components/find-in-page-init.tsx +0 -59
- package/templates/features/tauri/files/src/utils/find-in-page.ts +0 -175
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
/** @jsxRuntime automatic */
|
|
2
|
-
/** @jsxImportSource preact */
|
|
3
|
-
// Host-side body-end islands helper.
|
|
4
|
-
//
|
|
5
|
-
// Wave 8 (Path A — super-epic #1333 / child epic #1355) drops the local
|
|
6
|
-
// SSR-skip wrapper functions in `@takazudo/zudo-doc/ssr-skip` and uses
|
|
7
|
-
// zfb's native `<Island ssrFallback={...}>` API directly with the real
|
|
8
|
-
// component constructors imported by the host.
|
|
9
|
-
//
|
|
10
|
-
// The previous indirection (page → wrapper → placeholder div) created an
|
|
11
|
-
// orphan-component bug: the real components were `"use client"` modules
|
|
12
|
-
// that no page module ever imported transitively, so zfb's island scanner
|
|
13
|
-
// never walked page → real-component, the manifest never bound the marker
|
|
14
|
-
// to the real constructor, and the bundle never contained the real
|
|
15
|
-
// component body. PR #150 to zfb fixed the marker-name alignment but the
|
|
16
|
-
// orphan problem stayed — see issue zudolab/zudo-doc#1355 Wave 7 report.
|
|
17
|
-
//
|
|
18
|
-
// This helper is the page → real-component import chain the scanner
|
|
19
|
-
// needs. Each island below is composed with zfb's `<Island>` wrapper,
|
|
20
|
-
// which emits `<div data-zfb-island-skip-ssr="<ComponentName>">…</div>`
|
|
21
|
-
// at SSR (zfb's `captureComponentName` derives the marker from
|
|
22
|
-
// `child.displayName ?? child.name`). Because the page imports this
|
|
23
|
-
// file, and this file imports the real components, the scanner walks
|
|
24
|
-
// page → helper → real component and registers the constructor under
|
|
25
|
-
// the SSR marker name.
|
|
26
|
-
//
|
|
27
|
-
// Pattern mirrors `_header-with-defaults.tsx`: the JSX-shim widens
|
|
28
|
-
// `Island`'s return type to `unknown`, so call-sites cast through
|
|
29
|
-
// `as unknown as VNode` at the boundary.
|
|
30
|
-
|
|
31
|
-
import type { VNode, JSX } from "preact";
|
|
32
|
-
import { Island } from "@takazudo/zfb";
|
|
33
|
-
import { settings } from "@/config/settings";
|
|
34
|
-
|
|
35
|
-
import { AiChatModal } from "@takazudo/zudo-doc/ai-chat-modal";
|
|
36
|
-
import { ImageEnlarge, ImageEnlargeSsrFallback } from "@takazudo/zudo-doc/image-enlarge";
|
|
37
|
-
import { MermaidEnlarge, MermaidEnlargeSsrFallback } from "@takazudo/zudo-doc/mermaid-enlarge";
|
|
38
|
-
// @slot:body-end-islands:imports
|
|
39
|
-
|
|
40
|
-
// AiChatModal, ImageEnlarge, MermaidEnlarge pin displayName internally in the
|
|
41
|
-
// package. Optional feature islands that still need explicit call-site pinning
|
|
42
|
-
// inject their displayName assignment at the slot below only when selected.
|
|
43
|
-
// @slot:body-end-islands:display-names
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Default sr-only label rendered as the AiChatModal SSR fallback. This
|
|
47
|
-
* mirrors the body-label string the deleted `AiChatModalIsland` wrapper
|
|
48
|
-
* produced verbatim so assistive tech can discover the chat entrypoint
|
|
49
|
-
* in the static HTML before JS hydration. English-only for now — the
|
|
50
|
-
* previous default was also English-only; pass `aiChatBodyLabel` to
|
|
51
|
-
* localise.
|
|
52
|
-
*/
|
|
53
|
-
const DEFAULT_AI_CHAT_BODY_LABEL = "Ask a question about the documentation.";
|
|
54
|
-
|
|
55
|
-
/** Props for {@link BodyEndIslands}. */
|
|
56
|
-
export interface BodyEndIslandsProps {
|
|
57
|
-
/** Base path the AI chat modal uses to construct API URLs. */
|
|
58
|
-
basePath: string;
|
|
59
|
-
/**
|
|
60
|
-
* Sr-only label rendered as the AiChatModal SSR fallback. Defaults to
|
|
61
|
-
* the English string. Pass a locale-translated string for non-default
|
|
62
|
-
* locales so screen readers announce the chat entrypoint correctly
|
|
63
|
-
* before hydration.
|
|
64
|
-
*/
|
|
65
|
-
aiChatBodyLabel?: string;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* The default body-end islands a doc page may mount: the AI chat modal
|
|
70
|
-
* (`<dialog>` overlay) and the image-enlarge dialog (mounted lazily based
|
|
71
|
-
* on viewport scan). Each is feature-gated — the AI chat modal (and its
|
|
72
|
-
* sr-only landmark heading) on `settings.aiAssistant`, and image-enlarge
|
|
73
|
-
* on `settings.imageEnlarge` — so a feature-off consumer ships neither the
|
|
74
|
-
* island marker nor a misleading landmark (zudolab/zudo-doc#2058).
|
|
75
|
-
*
|
|
76
|
-
* Optional feature islands (e.g. the design token panel bootstrap) are not
|
|
77
|
-
* listed here: they are injected at the body-end-islands composition
|
|
78
|
-
* anchors only when their feature is selected, so a feature-off scaffold
|
|
79
|
-
* carries no trace of them.
|
|
80
|
-
*
|
|
81
|
-
* Each island is wrapped in `<Island ssrFallback>` so the heavy
|
|
82
|
-
* component is NOT evaluated server-side — they depend on
|
|
83
|
-
* `dialog.showModal()`, `localStorage`, `ResizeObserver`, runtime
|
|
84
|
-
* fetch, etc. The hydration runtime swaps each placeholder on the
|
|
85
|
-
* client.
|
|
86
|
-
*
|
|
87
|
-
* When `settings.aiAssistant` is enabled, the
|
|
88
|
-
* `<h2 class="sr-only">AI Assistant</h2>` heading is emitted in the SSG
|
|
89
|
-
* output so screen readers and crawlers can discover the chat section
|
|
90
|
-
* landmark before JS hydration.
|
|
91
|
-
*/
|
|
92
|
-
export function BodyEndIslands({
|
|
93
|
-
basePath,
|
|
94
|
-
aiChatBodyLabel = DEFAULT_AI_CHAT_BODY_LABEL,
|
|
95
|
-
}: BodyEndIslandsProps): JSX.Element {
|
|
96
|
-
// Gated on `settings.aiAssistant` (zudolab/zudo-doc#2058): when the AI
|
|
97
|
-
// assistant feature is off, neither the AiChatModal island marker nor the
|
|
98
|
-
// sr-only "AI Assistant" landmark heading should reach the SSG output —
|
|
99
|
-
// otherwise feature-off consumers ship a dead island marker plus a
|
|
100
|
-
// misleading screen-reader landmark for a section that never hydrates.
|
|
101
|
-
// Same feature-gating pattern as the other optional body-end islands.
|
|
102
|
-
//
|
|
103
|
-
// KNOWN CAVEAT: zfb's island scanner walks the static `"use client"`
|
|
104
|
-
// import chain, so gating this JSX removes the SSR marker and heading but
|
|
105
|
-
// may NOT strip the AiChatModal bundle from the build output. Marker
|
|
106
|
-
// removal is the agreed first fix (#2058); bundle stripping is out of scope.
|
|
107
|
-
//
|
|
108
|
-
// The sr-only <p> fallback keeps the body label in static HTML for screen
|
|
109
|
-
// readers before JS hydration; sr-only keeps it invisible to sighted users.
|
|
110
|
-
const aiAssistant = settings.aiAssistant ? (
|
|
111
|
-
<>
|
|
112
|
-
{/* Emits the "AI Assistant" heading in the SSG output so screen
|
|
113
|
-
readers can discover the chat section landmark before JS
|
|
114
|
-
hydration. */}
|
|
115
|
-
<h2 class="sr-only">AI Assistant</h2>
|
|
116
|
-
{
|
|
117
|
-
Island({
|
|
118
|
-
ssrFallback: <p class="sr-only">{aiChatBodyLabel}</p>,
|
|
119
|
-
children: <AiChatModal basePath={basePath} />,
|
|
120
|
-
}) as unknown as VNode
|
|
121
|
-
}
|
|
122
|
-
</>
|
|
123
|
-
) : null;
|
|
124
|
-
|
|
125
|
-
// Gated on `settings.imageEnlarge` (zudolab/zudo-doc#2058). Same caveat as
|
|
126
|
-
// the AI assistant gating: removing this JSX drops the SSR dialog shell and
|
|
127
|
-
// island marker, but the bundle may persist via the static import scan.
|
|
128
|
-
//
|
|
129
|
-
// Wave 11 (zudolab/zudo-doc#1355): the SSR fallback is the empty, closed
|
|
130
|
-
// `<dialog class="zd-enlarge-dialog ...">` shell so the dist HTML carries
|
|
131
|
-
// one dialog from the start. Without this the smoke "exactly one
|
|
132
|
-
// zd-enlarge-dialog element" assertion sees zero (skip-ssr placeholders are
|
|
133
|
-
// empty divs) and the no-JS path has no dialog at all. Hydration replaces
|
|
134
|
-
// this shell with the real ImageEnlarge component when the page goes idle.
|
|
135
|
-
const imageEnlarge = settings.imageEnlarge
|
|
136
|
-
? (Island({
|
|
137
|
-
when: "idle",
|
|
138
|
-
ssrFallback: <ImageEnlargeSsrFallback />,
|
|
139
|
-
children: <ImageEnlarge />,
|
|
140
|
-
}) as unknown as VNode)
|
|
141
|
-
: null;
|
|
142
|
-
|
|
143
|
-
// Gated on `settings.mermaid`. Mirrors the imageEnlarge block: the SSR
|
|
144
|
-
// fallback is an empty, closed `<dialog class="zd-mermaid-dialog ...">` so
|
|
145
|
-
// the dist HTML carries one dialog from the start and hydration (when="idle")
|
|
146
|
-
// swaps in the real component. Unlike images (SSR-wrapped by the MDX paragraph
|
|
147
|
-
// override), mermaid renders client-side, so this island injects the enlarge
|
|
148
|
-
// button into each rendered diagram container itself.
|
|
149
|
-
const mermaidEnlarge = settings.mermaid
|
|
150
|
-
? (Island({
|
|
151
|
-
when: "idle",
|
|
152
|
-
ssrFallback: <MermaidEnlargeSsrFallback />,
|
|
153
|
-
children: <MermaidEnlarge />,
|
|
154
|
-
}) as unknown as VNode)
|
|
155
|
-
: null;
|
|
156
|
-
|
|
157
|
-
return (
|
|
158
|
-
<>
|
|
159
|
-
{aiAssistant}
|
|
160
|
-
{imageEnlarge}
|
|
161
|
-
{mermaidEnlarge}
|
|
162
|
-
{/* @slot:body-end-islands:extra-islands */}
|
|
163
|
-
</>
|
|
164
|
-
);
|
|
165
|
-
}
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
/** @jsxRuntime automatic */
|
|
2
|
-
/** @jsxImportSource preact */
|
|
3
|
-
// Host chrome adapter — THE single host adapter for the page-chrome surface
|
|
4
|
-
// (epic Collapse Wiring Shells #2420; HOSTCOLLAPSE #2427 collapsed the former
|
|
5
|
-
// per-component `pages/lib/_*` chrome shells into this one module).
|
|
6
|
-
//
|
|
7
|
-
// It builds the host's REAL bindings ONCE and threads them through the public
|
|
8
|
-
// `createChrome(routeContext, hostBindings)` builder, then re-exports the wired
|
|
9
|
-
// page-chrome barrel (renderDocPage, HeaderWithDefaults, FooterWithDefaults,
|
|
10
|
-
// HeadWithDefaults, composeMetaTitle, …). Every doc route + homepage chrome
|
|
11
|
-
// import resolves here.
|
|
12
|
-
//
|
|
13
|
-
// - the reconstructed route context comes from the retained, vitest-safe
|
|
14
|
-
// `./_route-context` seam (settings + i18n + URL/nav/slug helpers +
|
|
15
|
-
// nav-source resolvers + route enumerators), fed the host content bridge
|
|
16
|
-
// (`stableDocs`) so the content read + nav enumeration stay byte-identical;
|
|
17
|
-
// - the genuinely host-bound slots (`hostBindings`): the real SearchWidget,
|
|
18
|
-
// git-history manifest, sidebars config, frontmatter renderers/builder,
|
|
19
|
-
// footer tag loader + vocabulary, body-end islands, DocHistory island, and
|
|
20
|
-
// the showcase MDX content overrides (`mdxExtras`).
|
|
21
|
-
//
|
|
22
|
-
// Island-scanner contract (load-bearing): this module MUST keep the STATIC
|
|
23
|
-
// imports of DocHistory (`@takazudo/zudo-doc/doc-history`), BodyEndIslands
|
|
24
|
-
// (`./_body-end-islands`) and PresetGeneratorFallback (`./_preset-generator`).
|
|
25
|
-
// After the collapse the only page→island import chain is
|
|
26
|
-
// `pages/docs/*.tsx → _chrome.ts → {DocHistory, BodyEndIslands, PresetGenerator}`;
|
|
27
|
-
// if any of these became a type-only or dynamic import the zfb island scanner
|
|
28
|
-
// would stop walking it and the marker/bundle would silently drop.
|
|
29
|
-
|
|
30
|
-
import type { ComponentChildren } from "preact";
|
|
31
|
-
import type { ChromeHostBindings } from "@takazudo/zudo-doc/factory-context";
|
|
32
|
-
|
|
33
|
-
import { createChrome } from "@takazudo/zudo-doc/chrome";
|
|
34
|
-
|
|
35
|
-
import { settings } from "@/config/settings";
|
|
36
|
-
import { defaultLocale } from "@/config/i18n";
|
|
37
|
-
import { tagVocabulary } from "@/config/tag-vocabulary";
|
|
38
|
-
import sidebars from "@/config/sidebars";
|
|
39
|
-
import { frontmatterRenderers } from "@/config/frontmatter-preview-renderers";
|
|
40
|
-
import { collectTags } from "@/utils/tags";
|
|
41
|
-
import { toRouteSlug } from "@/utils/slug";
|
|
42
|
-
import type { DocsEntry } from "@/types/docs-entry";
|
|
43
|
-
|
|
44
|
-
import { routeContext } from "./_route-context";
|
|
45
|
-
import { stableDocs, memoizeDerived } from "./_nav-source-cache";
|
|
46
|
-
import { mergeLocaleDocs } from "./locale-merge";
|
|
47
|
-
import { SearchWidget } from "./_search-widget";
|
|
48
|
-
import { BodyEndIslands as BodyEndIslandsSeam } from "./_body-end-islands";
|
|
49
|
-
import { buildFrontmatterPreviewEntries } from "./_frontmatter-preview-data";
|
|
50
|
-
import { DetailsWrapper } from "./_details";
|
|
51
|
-
import { PresetGeneratorFallback } from "./_preset-generator";
|
|
52
|
-
import { DocHistory } from "@takazudo/zudo-doc/doc-history";
|
|
53
|
-
import { HtmlPreviewWrapper, type HtmlPreviewWrapperProps } from "@takazudo/zudo-doc/html-preview-wrapper";
|
|
54
|
-
// SSR author + date metadata — `#doc-history-meta` is the build-time manifest
|
|
55
|
-
// alias (esbuild-inlined, no fs). Static import is load-bearing for the island
|
|
56
|
-
// scanner chain noted above.
|
|
57
|
-
import docHistoryMeta from "#doc-history-meta";
|
|
58
|
-
|
|
59
|
-
// ---------------------------------------------------------------------------
|
|
60
|
-
// Footer tag loader (host-side; moved verbatim from the former
|
|
61
|
-
// _footer-with-defaults.tsx). Reads collections via
|
|
62
|
-
// stableDocs / memoizeDerived and aggregates tags per locale. Threaded as
|
|
63
|
-
// hostBindings.loadTagsForLocale.
|
|
64
|
-
// ---------------------------------------------------------------------------
|
|
65
|
-
|
|
66
|
-
function loadTagsForLocale(lang: string) {
|
|
67
|
-
if (lang === defaultLocale) {
|
|
68
|
-
const baseDocs = stableDocs("docs");
|
|
69
|
-
return memoizeDerived([baseDocs], "footerTaglist;default", () => {
|
|
70
|
-
const docs: DocsEntry[] = baseDocs.filter(
|
|
71
|
-
(d) => !d.data.draft && !d.data.unlisted && !d.data.category_no_page,
|
|
72
|
-
);
|
|
73
|
-
const tagMap = collectTags(docs, (id, data) => data.slug ?? toRouteSlug(id));
|
|
74
|
-
return [...tagMap.values()].sort((a, b) => a.tag.localeCompare(b.tag, lang));
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
const baseDocs = stableDocs("docs");
|
|
78
|
-
const localeDocs = stableDocs(`docs-${lang}`);
|
|
79
|
-
return memoizeDerived([baseDocs, localeDocs], `footerTaglist;${lang}`, () => {
|
|
80
|
-
const result = mergeLocaleDocs({
|
|
81
|
-
baseDocs: baseDocs.filter((d) => !d.data.draft),
|
|
82
|
-
localeDocs: localeDocs.filter((d) => !d.data.draft),
|
|
83
|
-
applyDefaultLocaleOnlyFilter: true,
|
|
84
|
-
});
|
|
85
|
-
const docs: DocsEntry[] = result.docs.filter((d) => !d.data.category_no_page);
|
|
86
|
-
const tagMap = collectTags(docs, (id, data) => data.slug ?? toRouteSlug(id));
|
|
87
|
-
return [...tagMap.values()].sort((a, b) => a.tag.localeCompare(b.tag, lang));
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// ---------------------------------------------------------------------------
|
|
92
|
-
// Showcase MDX content overrides (host-bound; identical to the former
|
|
93
|
-
// pages/_mdx-components.ts `extras` block — kept in lockstep). Threaded via
|
|
94
|
-
// hostBindings.mdxExtras; the package factory merges them over its defaults.
|
|
95
|
-
// ---------------------------------------------------------------------------
|
|
96
|
-
|
|
97
|
-
/** MDX-tag stub: renders nothing (Preact null-vnode path). */
|
|
98
|
-
const MdxStub = (_props: unknown) => null;
|
|
99
|
-
|
|
100
|
-
/** SSR pass-through for `<Island when=…>` — renders children, ignores `when`. */
|
|
101
|
-
function IslandWrapper(props: {
|
|
102
|
-
when?: "load" | "idle" | "visible" | "media";
|
|
103
|
-
children?: ComponentChildren;
|
|
104
|
-
}): ComponentChildren {
|
|
105
|
-
return props.children ?? null;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const HtmlPreviewWithGlobalConfig = (props: HtmlPreviewWrapperProps) =>
|
|
109
|
-
HtmlPreviewWrapper({ globalConfig: settings.htmlPreview ?? null, ...props });
|
|
110
|
-
|
|
111
|
-
const mdxExtras = {
|
|
112
|
-
HtmlPreview: HtmlPreviewWithGlobalConfig,
|
|
113
|
-
Details: DetailsWrapper,
|
|
114
|
-
SmartBreak: MdxStub,
|
|
115
|
-
Island: IslandWrapper,
|
|
116
|
-
PresetGenerator: PresetGeneratorFallback,
|
|
117
|
-
Avatar: MdxStub,
|
|
118
|
-
Button: MdxStub,
|
|
119
|
-
Card: MdxStub,
|
|
120
|
-
MyComponent: MdxStub,
|
|
121
|
-
PageLayout: MdxStub,
|
|
122
|
-
} as unknown as Record<string, (props: Record<string, unknown>) => unknown>;
|
|
123
|
-
|
|
124
|
-
// ---------------------------------------------------------------------------
|
|
125
|
-
// The host's real bindings (the 10 ChromeHostBindings slots).
|
|
126
|
-
// ---------------------------------------------------------------------------
|
|
127
|
-
|
|
128
|
-
const hostBindings: ChromeHostBindings = {
|
|
129
|
-
SearchWidget: SearchWidget as ChromeHostBindings["SearchWidget"],
|
|
130
|
-
docHistoryMeta: docHistoryMeta as Record<string, unknown>,
|
|
131
|
-
sidebarsConfig: sidebars as unknown as Record<string, unknown>,
|
|
132
|
-
frontmatterRenderers: frontmatterRenderers as unknown as ChromeHostBindings["frontmatterRenderers"],
|
|
133
|
-
buildFrontmatterPreviewEntries:
|
|
134
|
-
buildFrontmatterPreviewEntries as unknown as ChromeHostBindings["buildFrontmatterPreviewEntries"],
|
|
135
|
-
loadTagsForLocale: loadTagsForLocale as unknown as ChromeHostBindings["loadTagsForLocale"],
|
|
136
|
-
tagVocabulary,
|
|
137
|
-
BodyEndIslands: BodyEndIslandsSeam as unknown as ChromeHostBindings["BodyEndIslands"],
|
|
138
|
-
DocHistory: DocHistory as unknown as ChromeHostBindings["DocHistory"],
|
|
139
|
-
mdxExtras: mdxExtras as ChromeHostBindings["mdxExtras"],
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
// ---------------------------------------------------------------------------
|
|
143
|
-
// Build the wired page-chrome surface ONCE from the route context + real host
|
|
144
|
-
// bindings, and re-export the barrel. Every omitted slot falls back to the
|
|
145
|
-
// package stub (byte-identical to the injected package-routes path); each REAL
|
|
146
|
-
// slot above overrides it.
|
|
147
|
-
// ---------------------------------------------------------------------------
|
|
148
|
-
|
|
149
|
-
const chrome = createChrome(routeContext, hostBindings);
|
|
150
|
-
|
|
151
|
-
export type { RenderDocPageOptions } from "@takazudo/zudo-doc/doc-page-renderer";
|
|
152
|
-
|
|
153
|
-
export const {
|
|
154
|
-
composeMetaTitle,
|
|
155
|
-
HeadWithDefaults,
|
|
156
|
-
HeaderWithDefaults,
|
|
157
|
-
FooterWithDefaults,
|
|
158
|
-
SidebarWithDefaults,
|
|
159
|
-
renderDocPage,
|
|
160
|
-
VersionsPageView,
|
|
161
|
-
collectTagMapForLocale,
|
|
162
|
-
TagDetailPageView,
|
|
163
|
-
TagsIndexPageView,
|
|
164
|
-
SiteTreeNavWrapper,
|
|
165
|
-
BodyEndIslands,
|
|
166
|
-
HomePageView,
|
|
167
|
-
} = chrome;
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/** @jsxRuntime automatic */
|
|
2
|
-
/** @jsxImportSource preact */
|
|
3
|
-
// Host-side MDX wrapper for <Details> — trivial passthrough to the v2
|
|
4
|
-
// Details component.
|
|
5
|
-
//
|
|
6
|
-
// The v2 Details component accepts standard Preact children. MDX passes slot
|
|
7
|
-
// content as `children`, so the mapping is direct. The title prop (default
|
|
8
|
-
// "Details") is forwarded unchanged.
|
|
9
|
-
|
|
10
|
-
import type { ComponentChildren, VNode } from "preact";
|
|
11
|
-
import { Details as DetailsV2 } from "@takazudo/zudo-doc/details";
|
|
12
|
-
|
|
13
|
-
export interface DetailsWrapperProps {
|
|
14
|
-
/** Summary label shown in the <summary> element. Defaults to "Details". */
|
|
15
|
-
title?: string;
|
|
16
|
-
/** MDX slot content rendered inside the collapsed body. */
|
|
17
|
-
children?: ComponentChildren;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Passthrough wrapper for the v2 Details component.
|
|
22
|
-
*
|
|
23
|
-
* Used in pages/_mdx-components.ts as the Details binding so that MDX
|
|
24
|
-
* content using `<Details title="...">...</Details>` renders correctly
|
|
25
|
-
* on zfb routes.
|
|
26
|
-
*/
|
|
27
|
-
export function DetailsWrapper({ title, children }: DetailsWrapperProps): VNode {
|
|
28
|
-
return <DetailsV2 title={title}>{children}</DetailsV2>;
|
|
29
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
// Thin shim — the memoized doc-route-entry builder rides on the unified
|
|
2
|
-
// ChromeContext now (epic Collapse Wiring Shells #2420, FACTORIES #2424).
|
|
3
|
-
// `createRouteContext` (in _route-context.ts) assembles `buildDocRouteEntries`
|
|
4
|
-
// as part of the route context; this module just re-exports it so the doc-route
|
|
5
|
-
// page files keep importing it from here unchanged.
|
|
6
|
-
|
|
7
|
-
export type { DocRouteEntry, BuildDocRouteEntriesArgs } from "@takazudo/zudo-doc/doc-route-entries";
|
|
8
|
-
import { routeContext } from "./_route-context";
|
|
9
|
-
|
|
10
|
-
export const { buildDocRouteEntries } = routeContext;
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
// Thin showcase wrapper around @takazudo/zudo-doc/extract-headings.
|
|
2
|
-
// The package-side extractHeadings takes settings as explicit params (no
|
|
3
|
-
// project singleton import). This wrapper re-reads the project settings and
|
|
4
|
-
// passes them through so call sites in _doc-route-entries.ts continue to
|
|
5
|
-
// call extractHeadings(body) without change.
|
|
6
|
-
//
|
|
7
|
-
// Moved to the package as part of the package-first migration (#2321, S4 #2327).
|
|
8
|
-
|
|
9
|
-
import { settings } from "../../src/config/settings";
|
|
10
|
-
export type { HeadingIdStrategy, HeadingItem } from "@takazudo/zudo-doc/extract-headings";
|
|
11
|
-
export { slugify } from "@takazudo/zudo-doc/extract-headings";
|
|
12
|
-
import { extractHeadings as _extractHeadings } from "@takazudo/zudo-doc/extract-headings";
|
|
13
|
-
import type { HeadingItem, HeadingIdStrategy } from "@takazudo/zudo-doc/extract-headings";
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Extract TOC headings from a raw MDX/markdown body, using the project's
|
|
17
|
-
* configured `tocMinDepth`, `tocMaxDepth`, and `headingIdStrategy` from
|
|
18
|
-
* `src/config/settings`.
|
|
19
|
-
*
|
|
20
|
-
* Accepts the same optional `opts` overrides as the underlying package
|
|
21
|
-
* function (for tests that want to override the depth window or strategy
|
|
22
|
-
* without touching the global settings).
|
|
23
|
-
*/
|
|
24
|
-
export function extractHeadings(
|
|
25
|
-
body: string,
|
|
26
|
-
opts?: {
|
|
27
|
-
tocMinDepth?: number;
|
|
28
|
-
tocMaxDepth?: number;
|
|
29
|
-
strategy?: HeadingIdStrategy;
|
|
30
|
-
},
|
|
31
|
-
): HeadingItem[] {
|
|
32
|
-
return _extractHeadings(body, {
|
|
33
|
-
tocMinDepth: opts?.tocMinDepth ?? settings.tocMinDepth,
|
|
34
|
-
tocMaxDepth: opts?.tocMaxDepth ?? settings.tocMaxDepth,
|
|
35
|
-
strategy: opts?.strategy ?? settings.headingIdStrategy,
|
|
36
|
-
});
|
|
37
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
// Host-side filter helper that turns a doc entry's `data` (frontmatter)
|
|
2
|
-
// into the `entries` array expected by `<FrontmatterPreview>`.
|
|
3
|
-
//
|
|
4
|
-
// The v2 component (packages/zudo-doc/src/metainfo/frontmatter-preview.tsx)
|
|
5
|
-
// is a pure renderer — the caller is responsible for:
|
|
6
|
-
//
|
|
7
|
-
// 1. Honouring `settings.frontmatterPreview === false` (block hidden everywhere).
|
|
8
|
-
// 2. Removing schema-managed system keys (DEFAULT_FRONTMATTER_IGNORE_KEYS).
|
|
9
|
-
// 3. Applying the host's `ignoreKeys` (replaces the default list) or
|
|
10
|
-
// `extraIgnoreKeys` (adds to the default).
|
|
11
|
-
// 4. Skipping null/undefined values.
|
|
12
|
-
//
|
|
13
|
-
// Returning an empty array suppresses the block — the v2 component
|
|
14
|
-
// short-circuits with `null` when `entries` is empty.
|
|
15
|
-
//
|
|
16
|
-
// Custom per-key renderers (from `src/config/frontmatter-preview-renderers.tsx`)
|
|
17
|
-
// are wired by the page template directly on the `<FrontmatterPreview>` call site
|
|
18
|
-
// via the `renderers` prop. This helper only produces the filtered entries array.
|
|
19
|
-
|
|
20
|
-
import { createBuildFrontmatterPreviewEntries } from "@takazudo/zudo-doc/frontmatter-preview-data";
|
|
21
|
-
import { settings } from "@/config/settings";
|
|
22
|
-
import { DEFAULT_FRONTMATTER_IGNORE_KEYS } from "@/config/frontmatter-preview-defaults";
|
|
23
|
-
|
|
24
|
-
export const buildFrontmatterPreviewEntries = createBuildFrontmatterPreviewEntries({
|
|
25
|
-
frontmatterPreview: settings.frontmatterPreview,
|
|
26
|
-
defaultIgnoreKeys: DEFAULT_FRONTMATTER_IGNORE_KEYS,
|
|
27
|
-
});
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
// Snapshot-anchored memoization for nav-source arrays.
|
|
2
|
-
//
|
|
3
|
-
// WHY THIS EXISTS — build-time array-identity stabilization
|
|
4
|
-
// --------------------------------------------------------
|
|
5
|
-
// zfb's `getCollection(name)` returns a FRESH array of FRESH entry objects on
|
|
6
|
-
// every call (it `.map()`s over the underlying snapshot — see
|
|
7
|
-
// `node_modules/@takazudo/zfb/dist/content.js`). The doc-route `paths()`
|
|
8
|
-
// functions are re-invoked once per built page (e.g. ~123× for the EN docs
|
|
9
|
-
// route), and the per-page sidebar + header each re-derive their nav source
|
|
10
|
-
// independently. The net effect: `buildNavTree` is called ~2× the page count
|
|
11
|
-
// (~900 calls for 251 pages), and every call recomputed an O(n log n)
|
|
12
|
-
// stringify+sort cache key over the entire docs collection.
|
|
13
|
-
//
|
|
14
|
-
// The fix anchors identity on the ONE thing stable across the whole build:
|
|
15
|
-
// `getContentSnapshot().collections[name]` — the readonly snapshot array zfb
|
|
16
|
-
// installs once at worker boot (verified INSTALLED during `pnpm build`,
|
|
17
|
-
// collections `[docs, docs-ja, docs-v-*]`). We memoize the bridged +
|
|
18
|
-
// draft-filtered arrays on that anchor (WeakMap) so every repeat caller
|
|
19
|
-
// receives the SAME array instance. `buildNavTree`'s WeakMap fast-path
|
|
20
|
-
// (`src/utils/docs.ts`) then short-circuits the key computation on identity,
|
|
21
|
-
// collapsing ~900 key computations to the handful of distinct
|
|
22
|
-
// (snapshot, locale, version, options) inputs.
|
|
23
|
-
//
|
|
24
|
-
// FALLBACK (no snapshot): unit tests and direct Node invocations run the
|
|
25
|
-
// filesystem path with no installed snapshot. There is no stable anchor array
|
|
26
|
-
// to key on, AND the underlying `getCollection(name)` result can legitimately
|
|
27
|
-
// change between calls in that mode (e.g. a test swapping its mock for the same
|
|
28
|
-
// collection name). So we DELIBERATELY do not memoize the no-snapshot path —
|
|
29
|
-
// it computes fresh each call. The perf win targets the real build, where the
|
|
30
|
-
// snapshot is always installed; correctness wins in the fallback path.
|
|
31
|
-
//
|
|
32
|
-
// HMR intent preserved: a content edit produces a NEW snapshot object (new
|
|
33
|
-
// `collections[name]` array identity), so every memo here misses and
|
|
34
|
-
// recomputes — matching the old content-keyed cache's change detection.
|
|
35
|
-
//
|
|
36
|
-
// PACKAGE SPLIT (epic #2344, S6):
|
|
37
|
-
// `memoizeDerived` — the generic two-level WeakMap memo — is now in the
|
|
38
|
-
// package at @takazudo/zudo-doc/nav-source-cache (no zfb imports needed).
|
|
39
|
-
// `stableDocs` stays here because it imports `getCollection` /
|
|
40
|
-
// `getContentSnapshot` from "zfb/content", which is a virtual module
|
|
41
|
-
// provided by the zfb SSG build system at compile time — not an npm package.
|
|
42
|
-
|
|
43
|
-
import { getCollection, getContentSnapshot } from "zfb/content";
|
|
44
|
-
import { bridgeDocsEntries, type ZfbDocsData } from "../_data";
|
|
45
|
-
import type { DocPageEntry } from "./doc-page-props";
|
|
46
|
-
|
|
47
|
-
// Re-export memoizeDerived from the package (pure, no zfb dep).
|
|
48
|
-
export { memoizeDerived } from "@takazudo/zudo-doc/nav-source-cache";
|
|
49
|
-
|
|
50
|
-
// ---------------------------------------------------------------------------
|
|
51
|
-
// Snapshot anchor → stable bridged arrays
|
|
52
|
-
// ---------------------------------------------------------------------------
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* The stable per-build anchor array for a collection: the raw readonly
|
|
56
|
-
* snapshot array zfb installed once. Returns `undefined` when no snapshot is
|
|
57
|
-
* installed (filesystem-fallback path) so callers take the fresh, unmemoized
|
|
58
|
-
* branch.
|
|
59
|
-
*/
|
|
60
|
-
function snapshotAnchor(name: string): readonly unknown[] | undefined {
|
|
61
|
-
return getContentSnapshot()?.collections[name];
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Per-anchor-array memo of the bridged + draft-filtered entries. Keyed on the
|
|
65
|
-
// snapshot array identity so a new build snapshot invalidates automatically.
|
|
66
|
-
const bridgedByAnchor = new WeakMap<object, DocPageEntry[]>();
|
|
67
|
-
|
|
68
|
-
function buildBridged(collectionName: string): DocPageEntry[] {
|
|
69
|
-
const raw = getCollection<ZfbDocsData>(collectionName);
|
|
70
|
-
return bridgeDocsEntries(raw, collectionName).filter(
|
|
71
|
-
(d) => !d.data.draft,
|
|
72
|
-
);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Identity-stable, draft-filtered `DocPageEntry[]` for a collection.
|
|
77
|
-
*
|
|
78
|
-
* Returns the SAME array instance on every call within one build (anchored on
|
|
79
|
-
* the snapshot array), so downstream derived arrays — and ultimately
|
|
80
|
-
* `buildNavTree` — can rely on reference equality. The entries carry the full
|
|
81
|
-
* `DocPageEntry` shape (Content, body, module_specifier, id, collection) the
|
|
82
|
-
* route `paths()` props need.
|
|
83
|
-
*
|
|
84
|
-
* Passed as `stableDocs` to `createNavSourceDocs` in `_nav-source-docs.ts`.
|
|
85
|
-
*/
|
|
86
|
-
export function stableDocs(collectionName: string): DocPageEntry[] {
|
|
87
|
-
const anchor = snapshotAnchor(collectionName);
|
|
88
|
-
|
|
89
|
-
// No snapshot (fs-fallback / unit tests): compute fresh, do not memoize —
|
|
90
|
-
// see the no-snapshot rationale in the module header.
|
|
91
|
-
if (anchor === undefined) {
|
|
92
|
-
return buildBridged(collectionName);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const cached = bridgedByAnchor.get(anchor);
|
|
96
|
-
if (cached) return cached;
|
|
97
|
-
const built = buildBridged(collectionName);
|
|
98
|
-
bridgedByAnchor.set(anchor, built);
|
|
99
|
-
return built;
|
|
100
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
// Thin shim — nav-source resolvers ride on the unified ChromeContext now
|
|
2
|
-
// (epic Collapse Wiring Shells #2420, FACTORIES #2424). The reconstructed
|
|
3
|
-
// `createRouteContext` (in _route-context.ts) builds the identity-stable
|
|
4
|
-
// nav-source API as part of the route context; this module just re-exports the
|
|
5
|
-
// bindings so the existing call sites (route files, nav wrappers, _nav-data-prep,
|
|
6
|
-
// route-enumerators) keep importing them from here unchanged.
|
|
7
|
-
|
|
8
|
-
export type { NavSourceDocs, NavSourceOptions } from "@takazudo/zudo-doc/nav-source-docs";
|
|
9
|
-
import { routeContext } from "./_route-context";
|
|
10
|
-
|
|
11
|
-
export const {
|
|
12
|
-
resolveNavSource,
|
|
13
|
-
resolveVersionedLocaleSource,
|
|
14
|
-
loadNavSourceDocs,
|
|
15
|
-
stableMergeCategoryMeta,
|
|
16
|
-
stableNavDocs,
|
|
17
|
-
} = routeContext;
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
/** @jsxRuntime automatic */
|
|
2
|
-
/** @jsxImportSource preact */
|
|
3
|
-
// SSR fallback shell for the <PresetGenerator> interactive form.
|
|
4
|
-
//
|
|
5
|
-
// The real component (src/components/preset-generator.tsx) is a large
|
|
6
|
-
// client-only island. This file is imported transitively from page modules
|
|
7
|
-
// (pages/docs/[...slug].tsx → _mdx-components.ts → here), so zfb's island
|
|
8
|
-
// scanner walks the static import chain and registers PresetGenerator in the
|
|
9
|
-
// manifest. Without this import, the scanner never finds the component and
|
|
10
|
-
// client-side hydration never fires (orphan-component problem; same root
|
|
11
|
-
// cause fixed for body-end islands in _body-end-islands.tsx).
|
|
12
|
-
//
|
|
13
|
-
// The fallback renders all 8 section headings as static SSR HTML so:
|
|
14
|
-
// 1. Screen readers and search engines see the section structure (a11y/SEO).
|
|
15
|
-
// 2. Layout does not collapse to nothing while JS loads (no-JS layout).
|
|
16
|
-
// 3. The scanner traces this file → preset-generator.tsx via the Island child
|
|
17
|
-
// and registers PresetGenerator in the manifest for client-side mounting.
|
|
18
|
-
//
|
|
19
|
-
// Uses the canonical `<Island ssrFallback>` API (zfb) so the scanner can
|
|
20
|
-
// connect the import to the manifest entry and the hydration runtime can
|
|
21
|
-
// mount the real form into the skip-ssr placeholder on the client.
|
|
22
|
-
|
|
23
|
-
import type { VNode } from "preact";
|
|
24
|
-
import { HeadingH3 } from "@takazudo/zudo-doc/content";
|
|
25
|
-
import { Island } from "@takazudo/zfb";
|
|
26
|
-
import PresetGenerator from "@/components/preset-generator";
|
|
27
|
-
|
|
28
|
-
// Pin displayName so zfb's captureComponentName produces a stable marker
|
|
29
|
-
// name even after the SSR pipeline runs through a function-name-rewriting
|
|
30
|
-
// layer. Matches the data-zfb-island-skip-ssr attribute value the runtime
|
|
31
|
-
// queries. Mirrors the pattern in _body-end-islands.tsx.
|
|
32
|
-
(PresetGenerator as { displayName?: string }).displayName = "PresetGenerator";
|
|
33
|
-
|
|
34
|
-
// Heading text for each of the 8 sections — must match the original
|
|
35
|
-
// SectionHeading calls in src/components/preset-generator.tsx exactly
|
|
36
|
-
// so the SSR fallback and the real component render the same section labels.
|
|
37
|
-
// Order must mirror the JSX source order in preset-generator.tsx — do NOT
|
|
38
|
-
// sort alphabetically. The array drives the SSR fallback heading sequence
|
|
39
|
-
// shown to screen readers and visible before JS hydration.
|
|
40
|
-
const SECTION_HEADINGS = [
|
|
41
|
-
"Project Name",
|
|
42
|
-
"Default Language",
|
|
43
|
-
"Color Scheme Mode",
|
|
44
|
-
"Color Scheme",
|
|
45
|
-
"Features",
|
|
46
|
-
"Header right items",
|
|
47
|
-
"Markdown Options",
|
|
48
|
-
"Package Manager",
|
|
49
|
-
] as const;
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Static SSR fallback for the interactive PresetGenerator form.
|
|
53
|
-
*
|
|
54
|
-
* Renders all 8 section headings as static HTML for a11y/SEO and no-JS
|
|
55
|
-
* layout stability. Uses Island with ssrFallback so the zfb scanner traces
|
|
56
|
-
* this file → preset-generator.tsx and registers the real component in the
|
|
57
|
-
* island manifest for client-side mounting.
|
|
58
|
-
*/
|
|
59
|
-
export function PresetGeneratorFallback(): VNode {
|
|
60
|
-
const fallback = (
|
|
61
|
-
<div class="zd-preset-gen-fallback">
|
|
62
|
-
{SECTION_HEADINGS.map((heading) => (
|
|
63
|
-
<section key={heading}>
|
|
64
|
-
<HeadingH3>{heading}</HeadingH3>
|
|
65
|
-
</section>
|
|
66
|
-
))}
|
|
67
|
-
</div>
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
// Island with ssrFallback:
|
|
71
|
-
// - SSR emits the section headings as static HTML inside the skip-ssr div.
|
|
72
|
-
// - The scanner reads children.type = PresetGenerator → registers it in
|
|
73
|
-
// the manifest under "PresetGenerator".
|
|
74
|
-
// - The hydration runtime mounts the real interactive form into the
|
|
75
|
-
// skip-ssr placeholder on the client after load.
|
|
76
|
-
return Island({
|
|
77
|
-
when: "load",
|
|
78
|
-
ssrFallback: fallback,
|
|
79
|
-
children: <PresetGenerator />,
|
|
80
|
-
}) as unknown as VNode;
|
|
81
|
-
}
|