create-zudo-doc 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +146 -0
- package/bin/create-zudo-doc.js +2 -0
- package/dist/api.d.ts +20 -0
- package/dist/api.js +13 -0
- package/dist/claude-md-gen.d.ts +2 -0
- package/dist/claude-md-gen.js +113 -0
- package/dist/cli.d.ts +39 -0
- package/dist/cli.js +157 -0
- package/dist/compose.d.ts +95 -0
- package/dist/compose.js +206 -0
- package/dist/constants.d.ts +20 -0
- package/dist/constants.js +224 -0
- package/dist/features/body-foot-util.d.ts +10 -0
- package/dist/features/body-foot-util.js +12 -0
- package/dist/features/claude-resources.d.ts +2 -0
- package/dist/features/claude-resources.js +6 -0
- package/dist/features/design-token-panel.d.ts +14 -0
- package/dist/features/design-token-panel.js +27 -0
- package/dist/features/doc-history.d.ts +9 -0
- package/dist/features/doc-history.js +11 -0
- package/dist/features/doc-tags.d.ts +19 -0
- package/dist/features/doc-tags.js +33 -0
- package/dist/features/footer-taglist.d.ts +14 -0
- package/dist/features/footer-taglist.js +17 -0
- package/dist/features/footer.d.ts +8 -0
- package/dist/features/footer.js +10 -0
- package/dist/features/i18n.d.ts +22 -0
- package/dist/features/i18n.js +41 -0
- package/dist/features/image-enlarge.d.ts +11 -0
- package/dist/features/image-enlarge.js +13 -0
- package/dist/features/index.d.ts +15 -0
- package/dist/features/index.js +53 -0
- package/dist/features/llms-txt.d.ts +11 -0
- package/dist/features/llms-txt.js +13 -0
- package/dist/features/search.d.ts +9 -0
- package/dist/features/search.js +11 -0
- package/dist/features/sidebar-resizer.d.ts +14 -0
- package/dist/features/sidebar-resizer.js +16 -0
- package/dist/features/sidebar-toggle.d.ts +13 -0
- package/dist/features/sidebar-toggle.js +15 -0
- package/dist/features/tag-governance.d.ts +14 -0
- package/dist/features/tag-governance.js +16 -0
- package/dist/features/tauri-dev.d.ts +2 -0
- package/dist/features/tauri-dev.js +25 -0
- package/dist/features/tauri.d.ts +11 -0
- package/dist/features/tauri.js +52 -0
- package/dist/features/versioning.d.ts +27 -0
- package/dist/features/versioning.js +43 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +150 -0
- package/dist/preset.d.ts +37 -0
- package/dist/preset.js +156 -0
- package/dist/prompts.d.ts +32 -0
- package/dist/prompts.js +248 -0
- package/dist/scaffold.d.ts +4 -0
- package/dist/scaffold.js +344 -0
- package/dist/settings-gen.d.ts +2 -0
- package/dist/settings-gen.js +237 -0
- package/dist/utils.d.ts +8 -0
- package/dist/utils.js +34 -0
- package/dist/zfb-config-gen.d.ts +19 -0
- package/dist/zfb-config-gen.js +222 -0
- package/package.json +65 -0
- package/templates/base/.htmlvalidate.json +5 -0
- package/templates/base/.zfb/doc-history-meta.json +1 -0
- package/templates/base/pages/404.tsx +55 -0
- package/templates/base/pages/_data.ts +179 -0
- package/templates/base/pages/_mdx-components.ts +249 -0
- package/templates/base/pages/docs/[...slug].tsx +448 -0
- package/templates/base/pages/index.tsx +158 -0
- package/templates/base/pages/lib/_body-end-islands.tsx +201 -0
- package/templates/base/pages/lib/_category-nav.tsx +148 -0
- package/templates/base/pages/lib/_category-tree-nav.tsx +104 -0
- package/templates/base/pages/lib/_compose-meta-title.ts +29 -0
- package/templates/base/pages/lib/_details.tsx +30 -0
- package/templates/base/pages/lib/_doc-history-area.tsx +178 -0
- package/templates/base/pages/lib/_doc-metainfo-area.tsx +100 -0
- package/templates/base/pages/lib/_doc-tags-area.tsx +89 -0
- package/templates/base/pages/lib/_extract-headings.ts +81 -0
- package/templates/base/pages/lib/_footer-with-defaults.tsx +234 -0
- package/templates/base/pages/lib/_frontmatter-preview-data.ts +53 -0
- package/templates/base/pages/lib/_head-with-defaults.tsx +113 -0
- package/templates/base/pages/lib/_header-with-defaults.tsx +386 -0
- package/templates/base/pages/lib/_inline-version-switcher.tsx +84 -0
- package/templates/base/pages/lib/_math-block.tsx +63 -0
- package/templates/base/pages/lib/_nav-source-docs.ts +68 -0
- package/templates/base/pages/lib/_preset-generator.tsx +81 -0
- package/templates/base/pages/lib/_search-widget-script.ts +388 -0
- package/templates/base/pages/lib/_search-widget.tsx +196 -0
- package/templates/base/pages/lib/_sidebar-with-defaults.tsx +176 -0
- package/templates/base/pages/lib/_site-tree-nav.tsx +128 -0
- package/templates/base/pages/lib/locale-merge.ts +58 -0
- package/templates/base/pages/lib/route-enumerators.ts +302 -0
- package/templates/base/pages/sitemap.xml.tsx +51 -0
- package/templates/base/plugins/connect-adapter.mjs +144 -0
- package/templates/base/plugins/copy-public-plugin.mjs +50 -0
- package/templates/base/plugins/search-index-plugin.mjs +54 -0
- package/templates/base/scripts/run-b4push.sh +102 -0
- package/templates/base/src/components/ai-chat-modal.tsx +15 -0
- package/templates/base/src/components/client-router-bootstrap.tsx +14 -0
- package/templates/base/src/components/content/component-map.ts +25 -0
- package/templates/base/src/components/content/content-blockquote.tsx +16 -0
- package/templates/base/src/components/content/content-code.tsx +117 -0
- package/templates/base/src/components/content/content-link.tsx +83 -0
- package/templates/base/src/components/content/content-ol.tsx +19 -0
- package/templates/base/src/components/content/content-paragraph.tsx +10 -0
- package/templates/base/src/components/content/content-strong.tsx +16 -0
- package/templates/base/src/components/content/content-table.tsx +18 -0
- package/templates/base/src/components/content/content-ul.tsx +18 -0
- package/templates/base/src/components/content/heading-h2.tsx +26 -0
- package/templates/base/src/components/content/heading-h3.tsx +26 -0
- package/templates/base/src/components/content/heading-h4.tsx +26 -0
- package/templates/base/src/components/design-token-panel-bootstrap.tsx +15 -0
- package/templates/base/src/components/desktop-sidebar-toggle.tsx +15 -0
- package/templates/base/src/components/doc-history.tsx +18 -0
- package/templates/base/src/components/html-preview/highlighted-code.tsx +74 -0
- package/templates/base/src/components/html-preview/html-preview.tsx +108 -0
- package/templates/base/src/components/html-preview/preflight.ts +112 -0
- package/templates/base/src/components/html-preview/preview-base.tsx +159 -0
- package/templates/base/src/components/image-enlarge.tsx +19 -0
- package/templates/base/src/components/mobile-toc.tsx +94 -0
- package/templates/base/src/components/preset-generator.tsx +14 -0
- package/templates/base/src/components/sidebar-toggle.tsx +98 -0
- package/templates/base/src/components/sidebar-tree.tsx +543 -0
- package/templates/base/src/components/site-tree-nav.tsx +233 -0
- package/templates/base/src/components/theme-toggle.tsx +93 -0
- package/templates/base/src/components/toc.tsx +63 -0
- package/templates/base/src/components/tree-nav-shared.tsx +71 -0
- package/templates/base/src/config/color-scheme-utils.ts +182 -0
- package/templates/base/src/config/color-schemes.ts +128 -0
- package/templates/base/src/config/frontmatter-preview-defaults.ts +24 -0
- package/templates/base/src/config/frontmatter-preview-renderers.tsx +46 -0
- package/templates/base/src/config/i18n.ts +225 -0
- package/templates/base/src/config/settings-types.ts +162 -0
- package/templates/base/src/config/sidebars.ts +66 -0
- package/templates/base/src/config/tag-vocabulary-types.ts +39 -0
- package/templates/base/src/config/tag-vocabulary.ts +20 -0
- package/templates/base/src/hooks/use-active-heading.ts +133 -0
- package/templates/base/src/plugins/docs-source-map.ts +103 -0
- package/templates/base/src/plugins/hast-utils.ts +10 -0
- package/templates/base/src/plugins/rehype-code-title.ts +50 -0
- package/templates/base/src/plugins/rehype-heading-links.ts +53 -0
- package/templates/base/src/plugins/rehype-image-enlarge.ts +113 -0
- package/templates/base/src/plugins/rehype-mermaid.ts +41 -0
- package/templates/base/src/plugins/rehype-strip-md-extension.ts +58 -0
- package/templates/base/src/plugins/remark-admonitions.ts +99 -0
- package/templates/base/src/plugins/remark-resolve-markdown-links.ts +127 -0
- package/templates/base/src/plugins/url-utils.ts +4 -0
- package/templates/base/src/styles/global.css +1066 -0
- package/templates/base/src/types/docs-entry.ts +39 -0
- package/templates/base/src/types/heading.ts +5 -0
- package/templates/base/src/types/locale.ts +10 -0
- package/templates/base/src/utils/base.ts +139 -0
- package/templates/base/src/utils/content-files.ts +106 -0
- package/templates/base/src/utils/dedent.ts +24 -0
- package/templates/base/src/utils/docs.ts +335 -0
- package/templates/base/src/utils/git-info.ts +70 -0
- package/templates/base/src/utils/github.ts +19 -0
- package/templates/base/src/utils/header-right-items.ts +38 -0
- package/templates/base/src/utils/nav-scope.ts +63 -0
- package/templates/base/src/utils/sidebar.ts +104 -0
- package/templates/base/src/utils/slug.ts +10 -0
- package/templates/base/src/utils/smart-break.tsx +126 -0
- package/templates/base/src/utils/tags.ts +126 -0
- package/templates/base/tsconfig.json +36 -0
- package/templates/features/bodyFootUtil/files/src/utils/github.ts +19 -0
- package/templates/features/claudeResources/files/plugins/claude-resources-plugin.mjs +137 -0
- package/templates/features/claudeResources/files/src/integrations/claude-resources/__tests__/escape-for-mdx.test.ts +34 -0
- package/templates/features/claudeResources/files/src/integrations/claude-resources/__tests__/generate.test.ts +376 -0
- package/templates/features/claudeResources/files/src/integrations/claude-resources/escape-for-mdx.ts +93 -0
- package/templates/features/claudeResources/files/src/integrations/claude-resources/generate.ts +586 -0
- package/templates/features/designTokenPanel/files/src/components/design-token-panel-bootstrap.tsx +15 -0
- package/templates/features/designTokenPanel/files/src/config/design-token-panel-config.ts +99 -0
- package/templates/features/designTokenPanel/files/src/config/design-tokens-manifest.ts +177 -0
- package/templates/features/designTokenPanel/files/src/lib/design-token-panel-bootstrap.ts +50 -0
- package/templates/features/docHistory/files/plugins/doc-history-plugin.mjs +99 -0
- package/templates/features/docHistory/files/src/components/doc-history.tsx +598 -0
- package/templates/features/docHistory/files/src/types/doc-history.ts +23 -0
- package/templates/features/docHistory/files/src/utils/doc-history.ts +180 -0
- package/templates/features/docTags/files/pages/[locale]/docs/tags/[tag].tsx +116 -0
- package/templates/features/docTags/files/pages/[locale]/docs/tags/index.tsx +99 -0
- package/templates/features/docTags/files/pages/docs/tags/[tag].tsx +101 -0
- package/templates/features/docTags/files/pages/docs/tags/index.tsx +86 -0
- package/templates/features/i18n/files/pages/[locale]/docs/[...slug].tsx +467 -0
- package/templates/features/i18n/files/pages/[locale]/index.tsx +213 -0
- package/templates/features/imageEnlarge/files/src/components/image-enlarge.tsx +248 -0
- package/templates/features/llmsTxt/files/plugins/llms-txt-plugin.mjs +74 -0
- package/templates/features/sidebarResizer/files/src/scripts/sidebar-resizer.ts +185 -0
- package/templates/features/sidebarToggle/files/src/components/desktop-sidebar-toggle.tsx +126 -0
- package/templates/features/tagGovernance/files/scripts/tags-audit.ts +576 -0
- package/templates/features/tagGovernance/files/scripts/tags-suggest.ts +428 -0
- package/templates/features/tauri/files/src/components/find-bar.tsx +122 -0
- package/templates/features/tauri/files/src/components/find-in-page-init.tsx +53 -0
- package/templates/features/tauri/files/src/utils/find-in-page.ts +175 -0
- package/templates/features/tauri/files/src-tauri/Cargo.toml +14 -0
- package/templates/features/tauri/files/src-tauri/build.rs +3 -0
- package/templates/features/tauri/files/src-tauri/capabilities/default.json +11 -0
- package/templates/features/tauri/files/src-tauri/src/main.rs +250 -0
- package/templates/features/tauri/files/src-tauri/tauri.conf.json +25 -0
- package/templates/features/tauriDev/files/src-tauri-dev/Cargo.toml +15 -0
- package/templates/features/tauriDev/files/src-tauri-dev/build.rs +3 -0
- package/templates/features/tauriDev/files/src-tauri-dev/capabilities/default.json +7 -0
- package/templates/features/tauriDev/files/src-tauri-dev/frontend/index.html +187 -0
- package/templates/features/tauriDev/files/src-tauri-dev/icons/icon.png +0 -0
- package/templates/features/tauriDev/files/src-tauri-dev/src/main.rs +995 -0
- package/templates/features/tauriDev/files/src-tauri-dev/tauri.conf.json +22 -0
- package/templates/features/tauriDev/files/src-tauri-dev/test-launch.sh +65 -0
- package/templates/features/versioning/files/pages/[locale]/docs/versions.tsx +100 -0
- package/templates/features/versioning/files/pages/docs/versions.tsx +78 -0
- package/templates/features/versioning/files/pages/v/[version]/docs/[...slug].tsx +451 -0
- package/templates/features/versioning/files/pages/v/[version]/ja/docs/[...slug].tsx +490 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/** @jsxRuntime automatic */
|
|
2
|
+
/** @jsxImportSource preact */
|
|
3
|
+
// SSR-friendly search widget for the zfb host header.
|
|
4
|
+
//
|
|
5
|
+
// Mirrors the Astro baseline `src/components/search.astro` (deleted in
|
|
6
|
+
// commit a4d9956) for the zfb host pages. The key SSR requirement is that
|
|
7
|
+
// the placeholder text ("Type to search..." / 「検索したい単語を入力」) and
|
|
8
|
+
// the keyboard-shortcut hint ("to open search from anywhere" /
|
|
9
|
+
// 「いつでも検索バーを開ける」) appear in the static HTML so no-JS users
|
|
10
|
+
// and crawlers can see them.
|
|
11
|
+
//
|
|
12
|
+
// Architecture:
|
|
13
|
+
// - Pure SSR markup for the dialog structure + placeholder text.
|
|
14
|
+
// - A `<site-search>` custom element wraps everything; the inline script
|
|
15
|
+
// at the bottom of this module registers the element and handles:
|
|
16
|
+
// * Dialog open / close (button click, backdrop click, Escape key)
|
|
17
|
+
// * Platform keyboard-shortcut label (⌘K / Ctrl+K) written into
|
|
18
|
+
// `[data-kbd-shortcut]` on first `connectedCallback`
|
|
19
|
+
// * Search-index loading + MiniSearch query dispatch (lazy-loaded
|
|
20
|
+
// after the user types the first character)
|
|
21
|
+
// - Locale-aware strings are passed as props from the caller so the
|
|
22
|
+
// Japanese placeholder / shortcut-hint copy appears in JA-locale SSR
|
|
23
|
+
// without JS execution.
|
|
24
|
+
//
|
|
25
|
+
// Coordination note: this file is inserted into the header via
|
|
26
|
+
// `_header-with-defaults.tsx`'s `search` slot prop. It is self-contained
|
|
27
|
+
// so B-10-2 (version-switcher) can touch the header file without conflict.
|
|
28
|
+
|
|
29
|
+
import type { JSX } from "preact";
|
|
30
|
+
import { withBase } from "@/utils/base";
|
|
31
|
+
import { SEARCH_WIDGET_SCRIPT } from "./_search-widget-script.js";
|
|
32
|
+
|
|
33
|
+
export interface SearchWidgetProps {
|
|
34
|
+
/** Locale-aware placeholder: "Type to search..." / 「検索したい単語を入力」 */
|
|
35
|
+
placeholderText: string;
|
|
36
|
+
/** Locale-aware shortcut hint: "to open search from anywhere" / 「いつでも検索バーを開ける」 */
|
|
37
|
+
shortcutHint: string;
|
|
38
|
+
/** Locale-aware result count template, e.g. "{count} results" */
|
|
39
|
+
resultCountTemplate: string;
|
|
40
|
+
/** Accessible label for the search trigger button */
|
|
41
|
+
searchLabel: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Search trigger button + dialog widget.
|
|
46
|
+
*
|
|
47
|
+
* Pure SSR — renders the full dialog markup including the placeholder text
|
|
48
|
+
* so static HTML contains the required copy even before JS runs.
|
|
49
|
+
* The `<site-search>` custom element registers itself via the inline script
|
|
50
|
+
* and activates interactive behaviour (open/close/keyboard shortcut/MiniSearch)
|
|
51
|
+
* only on the client.
|
|
52
|
+
*/
|
|
53
|
+
export function SearchWidget(props: SearchWidgetProps): JSX.Element {
|
|
54
|
+
const { placeholderText, shortcutHint, resultCountTemplate, searchLabel } = props;
|
|
55
|
+
const base = withBase("/");
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<>
|
|
59
|
+
{/* @ts-expect-error site-search is a custom element not in JSX intrinsics */}
|
|
60
|
+
<site-search
|
|
61
|
+
data-base={base}
|
|
62
|
+
data-result-count-template={resultCountTemplate}
|
|
63
|
+
>
|
|
64
|
+
{/* Header trigger button — search magnifier icon */}
|
|
65
|
+
<button
|
|
66
|
+
data-open-search
|
|
67
|
+
type="button"
|
|
68
|
+
class="flex items-center justify-center text-muted transition-colors hover:text-fg"
|
|
69
|
+
aria-label={searchLabel}
|
|
70
|
+
>
|
|
71
|
+
<svg
|
|
72
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
73
|
+
width="22"
|
|
74
|
+
height="22"
|
|
75
|
+
viewBox="0 0 24 24"
|
|
76
|
+
fill="none"
|
|
77
|
+
stroke="currentColor"
|
|
78
|
+
stroke-width="2"
|
|
79
|
+
stroke-linecap="round"
|
|
80
|
+
stroke-linejoin="round"
|
|
81
|
+
aria-hidden="true"
|
|
82
|
+
>
|
|
83
|
+
<circle cx="11" cy="11" r="8" />
|
|
84
|
+
<path d="m21 21-4.3-4.3" />
|
|
85
|
+
</svg>
|
|
86
|
+
</button>
|
|
87
|
+
|
|
88
|
+
{/* Search dialog — rendered in SSR so the placeholder text is in
|
|
89
|
+
static HTML for no-JS users and crawlers. The browser treats
|
|
90
|
+
it as a closed <dialog> until the custom element calls
|
|
91
|
+
showModal(). */}
|
|
92
|
+
<dialog
|
|
93
|
+
data-search-dialog
|
|
94
|
+
class="m-0 h-full w-full max-w-none border-none bg-transparent p-0 backdrop:bg-overlay/60 sm:mx-auto sm:my-[10vh] sm:h-auto sm:max-h-[80vh] sm:max-w-[52rem] sm:rounded-lg"
|
|
95
|
+
>
|
|
96
|
+
<div class="flex h-full flex-col overflow-hidden bg-surface sm:rounded-lg sm:border sm:border-muted">
|
|
97
|
+
{/* ── Dialog header (input row) ─────────────────────────── */}
|
|
98
|
+
<div class="flex items-center gap-hsp-sm border-b border-muted px-hsp-lg py-vsp-sm">
|
|
99
|
+
{/* Small search icon inside the input area */}
|
|
100
|
+
<svg
|
|
101
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
102
|
+
width="16"
|
|
103
|
+
height="16"
|
|
104
|
+
viewBox="0 0 24 24"
|
|
105
|
+
fill="none"
|
|
106
|
+
stroke="currentColor"
|
|
107
|
+
stroke-width="2"
|
|
108
|
+
stroke-linecap="round"
|
|
109
|
+
stroke-linejoin="round"
|
|
110
|
+
class="shrink-0 text-muted"
|
|
111
|
+
aria-hidden="true"
|
|
112
|
+
>
|
|
113
|
+
<circle cx="11" cy="11" r="8" />
|
|
114
|
+
<path d="m21 21-4.3-4.3" />
|
|
115
|
+
</svg>
|
|
116
|
+
<input
|
|
117
|
+
data-search-input
|
|
118
|
+
type="text"
|
|
119
|
+
placeholder={placeholderText}
|
|
120
|
+
class="w-full bg-transparent text-body text-fg outline-none placeholder:text-muted"
|
|
121
|
+
autocomplete="off"
|
|
122
|
+
spellcheck={false}
|
|
123
|
+
/>
|
|
124
|
+
{/* Wide-viewport hit count (hidden until results arrive) */}
|
|
125
|
+
<span
|
|
126
|
+
data-search-count
|
|
127
|
+
class="hidden shrink-0 text-caption text-muted"
|
|
128
|
+
aria-live="polite"
|
|
129
|
+
/>
|
|
130
|
+
<button
|
|
131
|
+
data-close-search
|
|
132
|
+
type="button"
|
|
133
|
+
class="shrink-0 text-muted hover:text-fg"
|
|
134
|
+
aria-label="Close search"
|
|
135
|
+
>
|
|
136
|
+
<svg
|
|
137
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
138
|
+
width="20"
|
|
139
|
+
height="20"
|
|
140
|
+
viewBox="0 0 24 24"
|
|
141
|
+
fill="none"
|
|
142
|
+
stroke="currentColor"
|
|
143
|
+
stroke-width="2"
|
|
144
|
+
stroke-linecap="round"
|
|
145
|
+
stroke-linejoin="round"
|
|
146
|
+
>
|
|
147
|
+
<path d="M18 6 6 18" />
|
|
148
|
+
<path d="m6 6 12 12" />
|
|
149
|
+
</svg>
|
|
150
|
+
</button>
|
|
151
|
+
</div>
|
|
152
|
+
|
|
153
|
+
{/* Narrow-viewport hit count (below header, hidden on sm+) */}
|
|
154
|
+
<span
|
|
155
|
+
data-search-count-narrow
|
|
156
|
+
class="hidden border-b border-muted px-hsp-lg py-vsp-xs text-caption text-muted"
|
|
157
|
+
aria-live="polite"
|
|
158
|
+
/>
|
|
159
|
+
|
|
160
|
+
{/* ── Results area ──────────────────────────────────────── */}
|
|
161
|
+
{/* aria-live="polite" so screen readers announce result changes */}
|
|
162
|
+
<div
|
|
163
|
+
class="flex-1 overflow-y-auto px-hsp-lg pb-vsp-md"
|
|
164
|
+
data-search-results
|
|
165
|
+
aria-live="polite"
|
|
166
|
+
>
|
|
167
|
+
{/* Placeholder text — always in SSR HTML so no-JS users and
|
|
168
|
+
crawlers see the placeholderText and shortcutHint strings
|
|
169
|
+
in the static page source. */}
|
|
170
|
+
<div class="text-small text-muted" data-search-placeholder>
|
|
171
|
+
<p>{placeholderText}</p>
|
|
172
|
+
<p class="mt-vsp-md text-caption">
|
|
173
|
+
{/* data-kbd-shortcut is populated by the custom element on
|
|
174
|
+
connectedCallback() with the platform shortcut string
|
|
175
|
+
(⌘K on Mac, Ctrl+K elsewhere). Empty in SSR. */}
|
|
176
|
+
<kbd
|
|
177
|
+
class="rounded border border-muted bg-bg px-hsp-2xs py-[2px] font-mono text-caption"
|
|
178
|
+
data-kbd-shortcut
|
|
179
|
+
/>{" "}
|
|
180
|
+
{shortcutHint}
|
|
181
|
+
</p>
|
|
182
|
+
</div>
|
|
183
|
+
</div>
|
|
184
|
+
</div>
|
|
185
|
+
</dialog>
|
|
186
|
+
{/* @ts-expect-error closing custom element tag */}
|
|
187
|
+
</site-search>
|
|
188
|
+
|
|
189
|
+
{/* Inline script registers the SiteSearch custom element. Emitted once
|
|
190
|
+
per page — the browser deduplicates same-id custom elements
|
|
191
|
+
automatically; the `customElements.define` call below guards against
|
|
192
|
+
double-registration with the `!customElements.get(...)` check. */}
|
|
193
|
+
<script dangerouslySetInnerHTML={{ __html: SEARCH_WIDGET_SCRIPT }} />
|
|
194
|
+
</>
|
|
195
|
+
);
|
|
196
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/** @jsxRuntime automatic */
|
|
2
|
+
/** @jsxImportSource preact */
|
|
3
|
+
// Locale-/version-aware Sidebar wrapper for the zfb doc pages.
|
|
4
|
+
//
|
|
5
|
+
// Mirrors the data-prep that lived in src/components/sidebar.astro
|
|
6
|
+
// (deleted in commit a4d9956): build root-menu items from
|
|
7
|
+
// settings.headerNav, load the locale's docs collection (with EN
|
|
8
|
+
// fallback for non-default locales), build the nav tree for the active
|
|
9
|
+
// section, optionally remap hrefs for versioned routes, and feed the
|
|
10
|
+
// result into the host's <SidebarTree> Preact island.
|
|
11
|
+
//
|
|
12
|
+
// Why this wrapper exists: the data prep is host-only (it imports
|
|
13
|
+
// @/config/* and @/utils/*), so it cannot live in the published v2
|
|
14
|
+
// package. Without this wrapper the zfb doc pages fall through to a
|
|
15
|
+
// <SidebarTree nodes={[]} /> default and the SSG output emits an empty
|
|
16
|
+
// `<div data-zfb-island="SidebarTree" data-when="load"></div>` marker.
|
|
17
|
+
|
|
18
|
+
import type { JSX } from "preact";
|
|
19
|
+
// `<Island>` wraps `<SidebarTree>` directly here (rather than going through
|
|
20
|
+
// the v2 `<Sidebar>` shell with `treeComponent`) so the zfb island bundle's
|
|
21
|
+
// hydrate pass targets the actual stateful tree component. Mirrors the
|
|
22
|
+
// mobile `<SidebarToggle>` shape in `pages/lib/_header-with-defaults.tsx`:
|
|
23
|
+
// the hydration target owns its own data props directly so they ride the
|
|
24
|
+
// SSR → hydrate boundary inside the Island marker's `data-props` attribute.
|
|
25
|
+
//
|
|
26
|
+
// Background: zfb's `Island.captureSerializableProps` runs `JSON.stringify`
|
|
27
|
+
// on the wrapped component's own props bag, which silently drops function
|
|
28
|
+
// values. With the previous `<Sidebar treeComponent={SidebarTree} ...>`
|
|
29
|
+
// shape the `treeComponent` function was dropped during serialisation, so
|
|
30
|
+
// at hydration the v2 Sidebar shell mounted with `treeComponent=undefined`,
|
|
31
|
+
// returned `null`, and Preact's `hydrate(null, element)` left the SSR-
|
|
32
|
+
// rendered tree DOM in place WITHOUT attaching the input's `onChange`
|
|
33
|
+
// handler — typing into the filter input had no DOM effect.
|
|
34
|
+
// zudolab/zudo-doc#1459 (Wave 1 #1445 wired the input but not the wiring
|
|
35
|
+
// path; this wave routes the hydration target so the wiring actually
|
|
36
|
+
// reaches the rendered tree).
|
|
37
|
+
import { Island } from "@takazudo/zfb";
|
|
38
|
+
import SidebarTree from "@/components/sidebar-tree";
|
|
39
|
+
import { settings } from "@/config/settings";
|
|
40
|
+
import { defaultLocale, locales, t, type Locale } from "@/config/i18n";
|
|
41
|
+
import { buildLocaleLinks, navHref, versionedDocsUrl } from "@/utils/base";
|
|
42
|
+
import {
|
|
43
|
+
isNavVisible,
|
|
44
|
+
type NavNode,
|
|
45
|
+
} from "@/utils/docs";
|
|
46
|
+
import { buildSidebarForSection } from "@/utils/sidebar";
|
|
47
|
+
import { loadNavSourceDocs } from "./_nav-source-docs";
|
|
48
|
+
|
|
49
|
+
export interface SidebarWithDefaultsProps {
|
|
50
|
+
/** Slug of the active doc page, used to highlight the current entry. */
|
|
51
|
+
currentSlug?: string;
|
|
52
|
+
/** Active locale; defaults to the configured defaultLocale. */
|
|
53
|
+
lang?: Locale;
|
|
54
|
+
/** Header-nav category matcher used to scope the tree (e.g. "guides"). */
|
|
55
|
+
navSection?: string;
|
|
56
|
+
/** Active version slug, when rendering inside `/v/{version}/...`. */
|
|
57
|
+
currentVersion?: string;
|
|
58
|
+
/**
|
|
59
|
+
* Current page URL path used to build the locale-switcher links shown in
|
|
60
|
+
* the mobile sidebar footer. The Astro template read this from
|
|
61
|
+
* `Astro.url.pathname`; in zfb the page module passes it explicitly.
|
|
62
|
+
*/
|
|
63
|
+
currentPath?: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Walk the nav tree and rewrite each node's `href` to its versioned form.
|
|
68
|
+
*
|
|
69
|
+
* `buildNavTree` always emits hrefs via `docsUrl()`; when the active route
|
|
70
|
+
* lives under `/v/{version}/...` we need the same nodes pointing at the
|
|
71
|
+
* versioned URL so internal nav clicks stay inside the version. Skips
|
|
72
|
+
* nodes without an href (link-only or category placeholders).
|
|
73
|
+
*/
|
|
74
|
+
function remapVersionedHrefs(
|
|
75
|
+
nodes: NavNode[],
|
|
76
|
+
version: string,
|
|
77
|
+
nodeLang: Locale,
|
|
78
|
+
): NavNode[] {
|
|
79
|
+
return nodes.map((node) => {
|
|
80
|
+
const children =
|
|
81
|
+
node.children.length > 0
|
|
82
|
+
? remapVersionedHrefs(node.children, version, nodeLang)
|
|
83
|
+
: node.children;
|
|
84
|
+
|
|
85
|
+
if (!node.href || node.slug.startsWith("__link__")) {
|
|
86
|
+
return children !== node.children ? { ...node, children } : node;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const newHref = versionedDocsUrl(node.slug, version, nodeLang);
|
|
90
|
+
return { ...node, href: newHref, children };
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Default-bearing host wrapper that performs the data prep the deleted
|
|
96
|
+
* `sidebar.astro` template did, then wraps the project's `<SidebarTree>`
|
|
97
|
+
* Preact island in `<Island when="load">` so the SSG output ships a
|
|
98
|
+
* populated `<div data-zfb-island="SidebarTree" data-when="load">…tree…
|
|
99
|
+
* </div>` marker for the hydration runtime to pick up.
|
|
100
|
+
*
|
|
101
|
+
* The v2 `<Sidebar>` shell is intentionally NOT used as the hydration
|
|
102
|
+
* target here. Its `treeComponent` prop is a function, and zfb's
|
|
103
|
+
* `Island.captureSerializableProps` drops function values during
|
|
104
|
+
* `JSON.stringify`, so a `<Sidebar treeComponent={SidebarTree} ...>`
|
|
105
|
+
* island would hydrate with `treeComponent=undefined` and the shell
|
|
106
|
+
* would return `null`, silently breaking the filter input's hydration
|
|
107
|
+
* (zudolab/zudo-doc#1459). Wrapping `<SidebarTree>` directly mirrors the
|
|
108
|
+
* mobile `<SidebarToggle>` shape (see `_header-with-defaults.tsx`) and
|
|
109
|
+
* keeps all data props serializable.
|
|
110
|
+
*/
|
|
111
|
+
export function SidebarWithDefaults(
|
|
112
|
+
props: SidebarWithDefaultsProps,
|
|
113
|
+
): JSX.Element {
|
|
114
|
+
const {
|
|
115
|
+
currentSlug,
|
|
116
|
+
lang = defaultLocale,
|
|
117
|
+
navSection,
|
|
118
|
+
currentVersion,
|
|
119
|
+
currentPath = "",
|
|
120
|
+
} = props;
|
|
121
|
+
|
|
122
|
+
// Root-menu items derived from headerNav (mobile back-to-menu list).
|
|
123
|
+
// The Astro template fed labelKey through `t(...)` and computed hrefs
|
|
124
|
+
// with `navHref()`; mirror that exactly so the rendered list stays
|
|
125
|
+
// identical between the A and B sites.
|
|
126
|
+
const rootMenuItems = settings.headerNav.map((item) => ({
|
|
127
|
+
label: item.labelKey
|
|
128
|
+
? t(item.labelKey as Parameters<typeof t>[0], lang)
|
|
129
|
+
: item.label,
|
|
130
|
+
href: navHref(item.path, lang, currentVersion),
|
|
131
|
+
children: item.children?.map((child) => ({
|
|
132
|
+
label: child.labelKey
|
|
133
|
+
? t(child.labelKey as Parameters<typeof t>[0], lang)
|
|
134
|
+
: child.label,
|
|
135
|
+
href: navHref(child.path, lang, currentVersion),
|
|
136
|
+
})),
|
|
137
|
+
}));
|
|
138
|
+
|
|
139
|
+
const backToMenuLabel = navSection ? t("nav.backToMenu", lang) : undefined;
|
|
140
|
+
|
|
141
|
+
const { docs, categoryMeta } = loadNavSourceDocs(lang, currentVersion);
|
|
142
|
+
const navDocs = docs.filter(isNavVisible);
|
|
143
|
+
const rawNodes = buildSidebarForSection(navDocs, lang, navSection, categoryMeta);
|
|
144
|
+
const nodes = currentVersion
|
|
145
|
+
? remapVersionedHrefs(rawNodes, currentVersion, lang)
|
|
146
|
+
: rawNodes;
|
|
147
|
+
|
|
148
|
+
// Locale-switcher links are only meaningful when more than one locale is
|
|
149
|
+
// configured — matches the Astro template's guard.
|
|
150
|
+
const localeLinks =
|
|
151
|
+
locales.length > 1 ? buildLocaleLinks(currentPath, lang) : undefined;
|
|
152
|
+
|
|
153
|
+
// Wrap <SidebarTree> directly in <Island when="load">. SSR emits the
|
|
154
|
+
// `data-zfb-island="SidebarTree"` marker around the rendered tree, with
|
|
155
|
+
// all data props serialised into `data-props` (every prop is plain data:
|
|
156
|
+
// arrays of objects + strings). At hydration the runtime finds the
|
|
157
|
+
// marker, looks up "SidebarTree" in the islands manifest (registered via
|
|
158
|
+
// the host's `"use client"` directive on `src/components/sidebar-tree.tsx`),
|
|
159
|
+
// and mounts the real component in-place — re-attaching the filter
|
|
160
|
+
// input's `onChange` handler to the existing SSR DOM.
|
|
161
|
+
return Island({
|
|
162
|
+
when: "load",
|
|
163
|
+
children: (
|
|
164
|
+
<SidebarTree
|
|
165
|
+
nodes={nodes}
|
|
166
|
+
currentSlug={currentSlug}
|
|
167
|
+
rootMenuItems={rootMenuItems}
|
|
168
|
+
backToMenuLabel={backToMenuLabel}
|
|
169
|
+
localeLinks={localeLinks}
|
|
170
|
+
themeDefaultMode={
|
|
171
|
+
settings.colorMode ? settings.colorMode.defaultMode : undefined
|
|
172
|
+
}
|
|
173
|
+
/>
|
|
174
|
+
),
|
|
175
|
+
}) as unknown as JSX.Element;
|
|
176
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/** @jsxRuntime automatic */
|
|
2
|
+
/** @jsxImportSource preact */
|
|
3
|
+
// Host-side MDX wrapper for <SiteTreeNav /> and <SiteTreeNavDemo />.
|
|
4
|
+
//
|
|
5
|
+
// The original Astro project had two files:
|
|
6
|
+
// - src/components/site-tree-nav.astro — interactive Preact island
|
|
7
|
+
// - src/components/site-tree-nav-demo.astro — Astro wrapper that loaded
|
|
8
|
+
// collection data and rendered the island
|
|
9
|
+
//
|
|
10
|
+
// Restored to use the interactive SiteTreeNav island (refs #1453):
|
|
11
|
+
// Both <SiteTreeNav> and <SiteTreeNavDemo> MDX tags are mapped to this
|
|
12
|
+
// wrapper which does the same data loading that site-tree-nav-demo.astro did:
|
|
13
|
+
//
|
|
14
|
+
// 1. Load the full docs collection for the active locale.
|
|
15
|
+
// 2. Build nav tree via buildNavTree().
|
|
16
|
+
// 3. Group satellite nodes via groupSatelliteNodes().
|
|
17
|
+
// 4. Wrap the interactive SiteTreeNav in Island({when:"idle"}) so the MDX
|
|
18
|
+
// page gets the same collapsible grid the reference renders at
|
|
19
|
+
// /docs/components/site-tree-nav/ (refs #1453/#1442).
|
|
20
|
+
//
|
|
21
|
+
// All data access is synchronous (ADR-004 zfb content snapshot contract).
|
|
22
|
+
// The `lang` prop is injected by createMdxComponents() in
|
|
23
|
+
// pages/_mdx-components.ts so locale routes get locale-aware nav data.
|
|
24
|
+
//
|
|
25
|
+
// categoryIgnore defaults to ["inbox", "develop"] — same as the original index page
|
|
26
|
+
// and site-tree-nav-demo.astro.
|
|
27
|
+
|
|
28
|
+
import type { JSX } from "preact";
|
|
29
|
+
import { Island } from "@takazudo/zfb";
|
|
30
|
+
import SiteTreeNav from "@/components/site-tree-nav";
|
|
31
|
+
import {
|
|
32
|
+
buildNavTree,
|
|
33
|
+
groupSatelliteNodes,
|
|
34
|
+
loadCategoryMeta,
|
|
35
|
+
isNavVisible,
|
|
36
|
+
} from "@/utils/docs";
|
|
37
|
+
import { settings } from "@/config/settings";
|
|
38
|
+
import { defaultLocale, type Locale } from "@/config/i18n";
|
|
39
|
+
import { isDefaultLocaleOnlyPath } from "@/utils/base";
|
|
40
|
+
import { getCategoryOrder } from "@/utils/nav-scope";
|
|
41
|
+
import { loadDocs } from "../_data";
|
|
42
|
+
|
|
43
|
+
export interface SiteTreeNavWrapperProps {
|
|
44
|
+
/**
|
|
45
|
+
* Active locale. Injected via createMdxComponents() closure.
|
|
46
|
+
* Defaults to defaultLocale when not provided.
|
|
47
|
+
*/
|
|
48
|
+
lang?: Locale | string;
|
|
49
|
+
/**
|
|
50
|
+
* Optional aria-label for the wrapping <nav> element.
|
|
51
|
+
* Forwarded to the v2 SiteTreeNavDemo component.
|
|
52
|
+
*/
|
|
53
|
+
ariaLabel?: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Load merged docs + categoryMeta for the given locale.
|
|
58
|
+
* Matches the locale-merge strategy used by _category-nav.tsx.
|
|
59
|
+
*/
|
|
60
|
+
function loadNavSource(
|
|
61
|
+
locale: string,
|
|
62
|
+
): { docs: ReturnType<typeof loadDocs>; categoryMeta: Map<string, import("@/utils/docs").CategoryMeta> } {
|
|
63
|
+
if (locale === defaultLocale) {
|
|
64
|
+
return {
|
|
65
|
+
docs: loadDocs("docs").filter((d) => !d.data.draft),
|
|
66
|
+
categoryMeta: loadCategoryMeta(settings.docsDir),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const localeDocs = loadDocs(`docs-${locale}`).filter((d) => !d.data.draft);
|
|
71
|
+
const baseDocs = loadDocs("docs").filter((d) => !d.data.draft);
|
|
72
|
+
const localeSlugSet = new Set(localeDocs.map((d) => d.data.slug ?? d.id));
|
|
73
|
+
const fallbackDocs = baseDocs
|
|
74
|
+
.filter((d) => !localeSlugSet.has(d.data.slug ?? d.id))
|
|
75
|
+
.filter((d) => {
|
|
76
|
+
const slug = d.data.slug ?? d.id;
|
|
77
|
+
return !isDefaultLocaleOnlyPath(`/docs/${slug}/`);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
const localeDir =
|
|
81
|
+
(settings.locales as Record<string, { dir?: string }>)[locale]?.dir ??
|
|
82
|
+
settings.docsDir;
|
|
83
|
+
const categoryMeta = new Map([
|
|
84
|
+
...loadCategoryMeta(settings.docsDir),
|
|
85
|
+
...loadCategoryMeta(localeDir),
|
|
86
|
+
]);
|
|
87
|
+
|
|
88
|
+
return { docs: [...localeDocs, ...fallbackDocs], categoryMeta };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* MDX wrapper shared by both <SiteTreeNav> and <SiteTreeNavDemo> tags.
|
|
93
|
+
*
|
|
94
|
+
* Builds the full site nav tree and renders it via the interactive SiteTreeNav
|
|
95
|
+
* island (wrapped in Island({when:"idle"})) — restoring byte-parity with the
|
|
96
|
+
* Astro reference at /docs/components/site-tree-nav/ (refs #1453/#1442).
|
|
97
|
+
*
|
|
98
|
+
* The island renders the collapsible multi-column grid the reference shows.
|
|
99
|
+
* SiteTreeNavDemo (static <details> list) is no longer used for MDX content.
|
|
100
|
+
*
|
|
101
|
+
* Returns null when the tree is empty after filtering.
|
|
102
|
+
*/
|
|
103
|
+
export function SiteTreeNavWrapper({
|
|
104
|
+
lang = defaultLocale,
|
|
105
|
+
ariaLabel,
|
|
106
|
+
}: SiteTreeNavWrapperProps): JSX.Element | null {
|
|
107
|
+
const locale = lang as Locale;
|
|
108
|
+
|
|
109
|
+
const { docs, categoryMeta } = loadNavSource(locale);
|
|
110
|
+
const navDocs = docs.filter(isNavVisible);
|
|
111
|
+
const tree = buildNavTree(navDocs, locale, categoryMeta);
|
|
112
|
+
const categoryOrder = getCategoryOrder();
|
|
113
|
+
const groupedTree = groupSatelliteNodes(tree, categoryOrder);
|
|
114
|
+
|
|
115
|
+
if (groupedTree.length === 0) return null;
|
|
116
|
+
|
|
117
|
+
return Island({
|
|
118
|
+
when: "idle",
|
|
119
|
+
children: (
|
|
120
|
+
<SiteTreeNav
|
|
121
|
+
tree={groupedTree}
|
|
122
|
+
categoryOrder={categoryOrder}
|
|
123
|
+
categoryIgnore={["inbox", "develop"]}
|
|
124
|
+
ariaLabel={ariaLabel}
|
|
125
|
+
/>
|
|
126
|
+
),
|
|
127
|
+
}) as unknown as JSX.Element;
|
|
128
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// Shared utility for merging locale docs with base-locale fallbacks.
|
|
2
|
+
//
|
|
3
|
+
// Used by the locale tag pages to replicate the locale-first + base-fallback
|
|
4
|
+
// strategy from the Astro src/components/tag-nav.astro non-default-locale
|
|
5
|
+
// branch. Extracted here to avoid duplicating the logic across multiple
|
|
6
|
+
// [locale] page modules.
|
|
7
|
+
//
|
|
8
|
+
// Strategy:
|
|
9
|
+
// 1. Load `docs-${locale}` collection.
|
|
10
|
+
// 2. Load base "docs" collection.
|
|
11
|
+
// 3. Merge: locale docs take priority; base docs fill in slugs not present
|
|
12
|
+
// in the locale collection.
|
|
13
|
+
// 4. Filter out drafts and unlisted pages.
|
|
14
|
+
//
|
|
15
|
+
// This is a zfb-only module (uses synchronous getCollection from zfb/content).
|
|
16
|
+
// Do not import from Astro page code.
|
|
17
|
+
|
|
18
|
+
import { loadDocs } from "../_data";
|
|
19
|
+
import type { DocsEntry } from "@/types/docs-entry";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Merge locale docs with base-locale fallbacks.
|
|
23
|
+
*
|
|
24
|
+
* Locale docs take priority; base docs fill in slugs not covered by the
|
|
25
|
+
* locale collection. Drafts and unlisted docs are filtered out.
|
|
26
|
+
*/
|
|
27
|
+
export function mergeLocaleDocs(locale: string): DocsEntry[] {
|
|
28
|
+
// zfb's CollectionEntry uses `slug`/`collection` only; @/utils/docs
|
|
29
|
+
// utilities expect Astro-style `id` and `collection` fields. Map them
|
|
30
|
+
// here so the rest of this module (and its callers) get the
|
|
31
|
+
// DocsEntry-shaped objects they assume. Bridging on read keeps the
|
|
32
|
+
// schema discrepancy contained to the I/O boundary.
|
|
33
|
+
// Use `loadDocs` so the Astro-compat `id`/`collection` augmentation
|
|
34
|
+
// (and the `index` slug stripping) stays in one place — the inline
|
|
35
|
+
// `id: e.slug` map dropped the `/index` suffix that
|
|
36
|
+
// `buildNavTree`/`buildBreadcrumbs` etc. assume Astro 5 strips, which
|
|
37
|
+
// produced ambiguous-URL collisions at paths()-expansion time.
|
|
38
|
+
const localeDocs = loadDocs(`docs-${locale}`);
|
|
39
|
+
const baseDocs = loadDocs("docs");
|
|
40
|
+
|
|
41
|
+
const filteredLocale = localeDocs.filter(
|
|
42
|
+
(d) => !d.data.draft && !d.data.unlisted,
|
|
43
|
+
);
|
|
44
|
+
const filteredBase = baseDocs.filter(
|
|
45
|
+
(d) => !d.data.draft && !d.data.unlisted,
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
const localeSlugSet = new Set(
|
|
49
|
+
filteredLocale.map((d) => d.data.slug ?? d.id),
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
return [
|
|
53
|
+
...filteredLocale,
|
|
54
|
+
...filteredBase.filter(
|
|
55
|
+
(d) => !localeSlugSet.has(d.data.slug ?? d.id),
|
|
56
|
+
),
|
|
57
|
+
];
|
|
58
|
+
}
|