create-zudo-doc 0.2.21 → 0.2.22
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/features/image-enlarge.d.ts +10 -2
- package/dist/features/image-enlarge.js +10 -2
- package/dist/scaffold.js +20 -22
- 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/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/_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/_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/pages/robots.txt.tsx +2 -26
- package/templates/base/src/components/ai-chat-modal.tsx +9 -8
- 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/components/site-tree-nav.tsx +6 -220
- 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/z-index-tokens.ts +5 -4
- package/templates/base/src/styles/global.css +5 -579
- 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/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/plugins/connect-adapter.mjs +0 -169
- 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/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/llmsTxt/files/plugins/llms-txt-plugin.mjs +0 -93
|
@@ -1,292 +1,58 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
// with the
|
|
4
|
-
//
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
// appear in the sitemap even though they're hidden from nav.
|
|
14
|
-
// - toRouteSlug() is applied to all entry ids so category index pages
|
|
15
|
-
// (e.g. "getting-started/index" → "getting-started") get correct URLs.
|
|
16
|
-
// - Auto-generated category index pages (categories without index.mdx) are
|
|
17
|
-
// emitted by building the nav tree and calling collectAutoIndexNodes.
|
|
18
|
-
|
|
19
|
-
import { loadDocs } from "../_data";
|
|
20
|
-
import { mergeLocaleDocs } from "./locale-merge";
|
|
21
|
-
import { resolveNavSource, resolveVersionedLocaleSource } from "./_nav-source-docs";
|
|
1
|
+
// Thin stub — route-enumerators moved to the package (epic #2344, S6).
|
|
2
|
+
// Calls `createRouteEnumerators(ctx)` from @takazudo/zudo-doc/route-enumerators
|
|
3
|
+
// with the host singletons injected, then re-exports the resulting enumeration
|
|
4
|
+
// functions so all existing call sites continue to work unchanged.
|
|
5
|
+
|
|
6
|
+
import { createRouteEnumerators } from "@takazudo/zudo-doc/route-enumerators";
|
|
7
|
+
import type {
|
|
8
|
+
DocsEntryForTags,
|
|
9
|
+
TagInfoForEnum,
|
|
10
|
+
DocPageEntry,
|
|
11
|
+
DocNavNode,
|
|
12
|
+
} from "@takazudo/zudo-doc/route-enumerators";
|
|
22
13
|
import { settings } from "@/config/settings";
|
|
23
14
|
import { defaultLocale, type Locale } from "@/config/i18n";
|
|
24
|
-
import
|
|
25
|
-
import type
|
|
26
|
-
import { docsUrl, versionedDocsUrl, withBase } from "@/utils/base";
|
|
15
|
+
import { docsUrl, versionedDocsUrl, withBase, isDefaultLocaleOnlyPath } from "@/utils/base";
|
|
16
|
+
import { buildNavTree, collectAutoIndexNodes, type CategoryMeta } from "@/utils/docs";
|
|
27
17
|
import { collectTags } from "@/utils/tags";
|
|
28
18
|
import { toRouteSlug } from "@/utils/slug";
|
|
29
|
-
import {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
} from "
|
|
33
|
-
|
|
34
|
-
// ---------------------------------------------------------------------------
|
|
35
|
-
// enumerateDocsRoutes
|
|
36
|
-
// ---------------------------------------------------------------------------
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Enumerate all doc page URLs for a locale.
|
|
40
|
-
*
|
|
41
|
-
* For the default locale: loads the "docs" collection directly.
|
|
42
|
-
* For non-default locales: inlines a locale-first merge — locale docs take
|
|
43
|
-
* priority; base EN docs fill in slugs not covered by the locale collection,
|
|
44
|
-
* with default-locale-only paths excluded. A nav-tree pass then adds
|
|
45
|
-
* auto-generated category index pages.
|
|
46
|
-
*
|
|
47
|
-
* Applies toRouteSlug so "category/index" entries become "category/" URLs.
|
|
48
|
-
* Returns deduplicated URL strings with base prefix and trailing slash.
|
|
49
|
-
*/
|
|
50
|
-
export function enumerateDocsRoutes(locale: string): string[] {
|
|
51
|
-
const urls: string[] = [];
|
|
52
|
-
|
|
53
|
-
// Identity-stable nav source — same instances the doc routes use, so the
|
|
54
|
-
// nav-tree fast-path applies here too (#1902).
|
|
55
|
-
const { docs: allDocs, navDocs, categoryMeta } = resolveNavSource(
|
|
56
|
-
locale as Locale,
|
|
57
|
-
undefined,
|
|
58
|
-
{ applyDefaultLocaleOnlyFilter: true, keepUnlisted: true },
|
|
59
|
-
);
|
|
60
|
-
const tree = buildNavTree(navDocs, locale as Locale, categoryMeta);
|
|
61
|
-
|
|
62
|
-
for (const doc of allDocs) {
|
|
63
|
-
// A `category_no_page` index.mdx is metadata-only — no route, so no sitemap
|
|
64
|
-
// URL. Same exclusion the doc-route paths() apply (zfb retains every .mdx
|
|
65
|
-
// as a collection entry, so the skip must be explicit).
|
|
66
|
-
if (doc.data.category_no_page === true) continue;
|
|
67
|
-
// Canonical route slug via the one shared rule (@/utils/slug). `doc.id` is
|
|
68
|
-
// already `toRouteSlug(doc.slug)` (bridged through stripIndexSuffix in
|
|
69
|
-
// pages/_data.ts), so a bare root index.mdx is "" here → `/docs/` — the
|
|
70
|
-
// canonical root URL (#1891). The `toRouteSlug` fallback is a redundant
|
|
71
|
-
// safety re-application of the same rule (idempotent on the already-
|
|
72
|
-
// stripped id); kept so this enumerator's slug derivation reads as a
|
|
73
|
-
// single explicit call to the canonical helper.
|
|
74
|
-
urls.push(docsUrl(doc.data.slug ?? toRouteSlug(doc.id), locale as Locale));
|
|
75
|
-
}
|
|
76
|
-
for (const node of collectAutoIndexNodes(tree)) {
|
|
77
|
-
urls.push(docsUrl(node.slug, locale as Locale));
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return [...new Set(urls)];
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// ---------------------------------------------------------------------------
|
|
84
|
-
// enumerateTagsRoutes
|
|
85
|
-
// ---------------------------------------------------------------------------
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Enumerate tag-index and per-tag URLs for a locale.
|
|
89
|
-
*
|
|
90
|
-
* Uses the same tag map as the tag pages (unlisted + draft excluded) so the
|
|
91
|
-
* sitemap lists exactly the same tag pages that get built.
|
|
92
|
-
*
|
|
93
|
-
* Returns:
|
|
94
|
-
* - /docs/tags/ (or /{locale}/docs/tags/)
|
|
95
|
-
* - /docs/tags/{tag}/ (or /{locale}/docs/tags/{tag}/) for each unique tag
|
|
96
|
-
*/
|
|
97
|
-
export function enumerateTagsRoutes(locale: string): string[] {
|
|
98
|
-
if (!settings.docTags) return [];
|
|
99
|
-
|
|
100
|
-
const urls: string[] = [];
|
|
101
|
-
|
|
102
|
-
const tagsBase =
|
|
103
|
-
locale === defaultLocale ? "/docs/tags" : `/${locale}/docs/tags`;
|
|
104
|
-
urls.push(withBase(tagsBase));
|
|
105
|
-
|
|
106
|
-
// Collect tags from the same merged doc set the tag pages use.
|
|
107
|
-
// Filter unlisted + draft + category_no_page — mirrors the tag [tag].tsx
|
|
108
|
-
// pages so the sitemap lists exactly the tag pages that get built (a
|
|
109
|
-
// category_no_page index has no route, so a tag it carries must not coin a
|
|
110
|
-
// tag page that links back to it). The category_no_page drop happens AFTER
|
|
111
|
-
// the locale merge so a locale override carrying the flag first wins the
|
|
112
|
-
// merge — pre-merge filtering would let the unflagged base doc resurface.
|
|
113
|
-
let docs: DocsEntry[];
|
|
114
|
-
if (locale === defaultLocale) {
|
|
115
|
-
docs = loadDocs("docs").filter(
|
|
116
|
-
(d) => !d.data.unlisted && !d.data.draft && !d.data.category_no_page,
|
|
117
|
-
);
|
|
118
|
-
} else {
|
|
119
|
-
const result = mergeLocaleDocs({
|
|
120
|
-
baseDocs: loadDocs("docs").filter((d) => !d.data.draft),
|
|
121
|
-
localeDocs: loadDocs(`docs-${locale}`).filter((d) => !d.data.draft),
|
|
122
|
-
applyDefaultLocaleOnlyFilter: true,
|
|
123
|
-
});
|
|
124
|
-
docs = result.docs.filter((d) => !d.data.category_no_page);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const tagMap = collectTags(docs, (id, data) => data.slug ?? toRouteSlug(id));
|
|
128
|
-
|
|
129
|
-
for (const tag of tagMap.keys()) {
|
|
130
|
-
// Tag segment URL-encoded — these URLs feed the sitemap, which must
|
|
131
|
-
// carry well-formed encoded URLs (e.g. "type:guide" → "type%3Aguide").
|
|
132
|
-
// Route params (the page paths() functions) stay raw.
|
|
133
|
-
const encoded = encodeURIComponent(tag);
|
|
134
|
-
const tagPath =
|
|
135
|
-
locale === defaultLocale
|
|
136
|
-
? `/docs/tags/${encoded}`
|
|
137
|
-
: `/${locale}/docs/tags/${encoded}`;
|
|
138
|
-
urls.push(withBase(tagPath));
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
return urls;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// ---------------------------------------------------------------------------
|
|
145
|
-
// enumerateVersionedRoutes
|
|
146
|
-
// ---------------------------------------------------------------------------
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Enumerate doc URLs for a single (version, locale) combination.
|
|
150
|
-
*
|
|
151
|
-
* For the default locale: loads `docs-v-${version.slug}`.
|
|
152
|
-
* For non-default locales: locale-first merge — locale-specific collection
|
|
153
|
-
* takes priority; base EN collection fills in pages not yet translated.
|
|
154
|
-
* If the locale collection doesn't exist for this version, all pages fall
|
|
155
|
-
* back to the EN base (matching the page module's behaviour).
|
|
156
|
-
*
|
|
157
|
-
* Returns versioned URLs like /v/{version}/docs/{slug}/ or
|
|
158
|
-
* /v/{version}/{locale}/docs/{slug}/.
|
|
159
|
-
*/
|
|
160
|
-
export function enumerateVersionedRoutes(
|
|
161
|
-
version: VersionConfig,
|
|
162
|
-
locale: string,
|
|
163
|
-
): string[] {
|
|
164
|
-
const urls: string[] = [];
|
|
165
|
-
|
|
166
|
-
if (locale === defaultLocale) {
|
|
167
|
-
// Versioned EN base — identity-stable source (#1902).
|
|
168
|
-
const { docs: allDocs, navDocs, categoryMeta } = resolveNavSource(
|
|
169
|
-
"en",
|
|
170
|
-
version.slug,
|
|
171
|
-
);
|
|
172
|
-
const tree = buildNavTree(navDocs, "en", categoryMeta);
|
|
173
|
-
|
|
174
|
-
for (const doc of allDocs) {
|
|
175
|
-
// category_no_page index.mdx → no route, no sitemap URL (see paths()).
|
|
176
|
-
if (doc.data.category_no_page === true) continue;
|
|
177
|
-
const slug = doc.data.slug ?? toRouteSlug(doc.id);
|
|
178
|
-
urls.push(versionedDocsUrl(slug, version.slug));
|
|
179
|
-
}
|
|
180
|
-
for (const node of collectAutoIndexNodes(tree)) {
|
|
181
|
-
urls.push(versionedDocsUrl(node.slug, version.slug));
|
|
182
|
-
}
|
|
183
|
-
} else {
|
|
184
|
-
const localeDir = version.locales?.[locale]?.dir;
|
|
19
|
+
import type { DocsEntry } from "@/types/docs-entry";
|
|
20
|
+
import { loadDocs } from "../_data";
|
|
21
|
+
import { resolveNavSource, resolveVersionedLocaleSource } from "./_nav-source-docs";
|
|
22
|
+
import { mergeLocaleDocs } from "./locale-merge";
|
|
185
23
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
24
|
+
export const {
|
|
25
|
+
enumerateDocsRoutes,
|
|
26
|
+
enumerateTagsRoutes,
|
|
27
|
+
enumerateVersionedRoutes,
|
|
28
|
+
enumerateAllRoutes,
|
|
29
|
+
} = createRouteEnumerators({
|
|
30
|
+
defaultLocale,
|
|
31
|
+
getLocaleKeys: () => Object.keys(settings.locales),
|
|
32
|
+
getVersions: () => settings.versions,
|
|
33
|
+
getDocTags: () => settings.docTags,
|
|
34
|
+
docsUrl,
|
|
35
|
+
versionedDocsUrl,
|
|
36
|
+
withBase,
|
|
37
|
+
loadDocs,
|
|
38
|
+
isDefaultLocaleOnlyPath,
|
|
39
|
+
// The factory describes collectTags / buildNavTree with the package's minimal
|
|
40
|
+
// structural slots (DocsEntryForTags / DocPageEntry / Map<string, unknown> /
|
|
41
|
+
// TagInfoForEnum). The host helpers are typed against the concrete project
|
|
42
|
+
// types (DocsEntry / NavNode / the Locale union / TagInfo) but are runtime-
|
|
43
|
+
// identical, so the stub adapts them with thin casting wrappers at the
|
|
44
|
+
// injection boundary where the host owns the type knowledge.
|
|
45
|
+
collectTags: (docs: DocsEntryForTags[], slugFn): Map<string, TagInfoForEnum> =>
|
|
46
|
+
collectTags(docs as unknown as DocsEntry[], slugFn),
|
|
47
|
+
toRouteSlug,
|
|
48
|
+
buildNavTree: (docs: DocPageEntry[], locale: string, categoryMeta: Map<string, unknown>) =>
|
|
49
|
+
buildNavTree(
|
|
50
|
+
docs as unknown as DocsEntry[],
|
|
191
51
|
locale as Locale,
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
if (doc.data.category_no_page === true) continue;
|
|
200
|
-
const slug = doc.data.slug ?? toRouteSlug(doc.id);
|
|
201
|
-
urls.push(versionedDocsUrl(slug, version.slug, locale as Locale));
|
|
202
|
-
}
|
|
203
|
-
for (const node of collectAutoIndexNodes(tree)) {
|
|
204
|
-
urls.push(versionedDocsUrl(node.slug, version.slug, locale as Locale));
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
return [...new Set(urls)];
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// ---------------------------------------------------------------------------
|
|
212
|
-
// enumerateAllRoutes
|
|
213
|
-
// ---------------------------------------------------------------------------
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Compose all route enumerators into a deduped Map<url, lastmod>.
|
|
217
|
-
*
|
|
218
|
-
* Covers:
|
|
219
|
-
* - Site root
|
|
220
|
-
* - Default-locale docs + tags
|
|
221
|
-
* - Per-locale homepages, docs, and tags
|
|
222
|
-
* - Versioned EN docs (for each version in settings.versions)
|
|
223
|
-
* - Versioned locale docs (for each locale in settings.locales)
|
|
224
|
-
*
|
|
225
|
-
* The map keys are absolute paths (with settings.base prefix + trailing
|
|
226
|
-
* slash). The sitemap renderer prefixes each with settings.siteUrl.
|
|
227
|
-
*/
|
|
228
|
-
export function enumerateAllRoutes(): Map<string, string> {
|
|
229
|
-
const today = new Date().toISOString().split("T")[0] ?? "";
|
|
230
|
-
const routes = new Map<string, string>();
|
|
231
|
-
|
|
232
|
-
function add(url: string): void {
|
|
233
|
-
if (!routes.has(url)) {
|
|
234
|
-
routes.set(url, today);
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// Site root
|
|
239
|
-
add(withBase("/"));
|
|
240
|
-
|
|
241
|
-
// Default locale docs
|
|
242
|
-
for (const url of enumerateDocsRoutes(defaultLocale)) {
|
|
243
|
-
add(url);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
// Default locale tags
|
|
247
|
-
for (const url of enumerateTagsRoutes(defaultLocale)) {
|
|
248
|
-
add(url);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// Non-default locales
|
|
252
|
-
for (const locale of Object.keys(settings.locales)) {
|
|
253
|
-
add(withBase(`/${locale}`));
|
|
254
|
-
|
|
255
|
-
for (const url of enumerateDocsRoutes(locale)) {
|
|
256
|
-
add(url);
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
for (const url of enumerateTagsRoutes(locale)) {
|
|
260
|
-
add(url);
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// Versions listing pages — /docs/versions/ and /{locale}/docs/versions/.
|
|
265
|
-
// These static utility pages are built by pages/docs/versions.tsx and
|
|
266
|
-
// pages/[locale]/docs/versions.tsx whenever versioning is configured.
|
|
267
|
-
// They are not part of any content collection so they are added explicitly.
|
|
268
|
-
if (settings.versions) {
|
|
269
|
-
add(withBase("/docs/versions"));
|
|
270
|
-
for (const locale of Object.keys(settings.locales)) {
|
|
271
|
-
add(withBase(`/${locale}/docs/versions`));
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
// Versioned docs
|
|
276
|
-
if (settings.versions) {
|
|
277
|
-
for (const version of settings.versions as VersionConfig[]) {
|
|
278
|
-
for (const url of enumerateVersionedRoutes(version, defaultLocale)) {
|
|
279
|
-
add(url);
|
|
280
|
-
}
|
|
281
|
-
// Non-default locales always have versioned pages (they fall back to EN
|
|
282
|
-
// when a locale-specific collection is not configured).
|
|
283
|
-
for (const locale of Object.keys(settings.locales)) {
|
|
284
|
-
for (const url of enumerateVersionedRoutes(version, locale)) {
|
|
285
|
-
add(url);
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
return routes;
|
|
292
|
-
}
|
|
52
|
+
categoryMeta as Map<string, CategoryMeta>,
|
|
53
|
+
) as DocNavNode[],
|
|
54
|
+
collectAutoIndexNodes,
|
|
55
|
+
resolveNavSource,
|
|
56
|
+
resolveVersionedLocaleSource,
|
|
57
|
+
mergeLocaleDocs,
|
|
58
|
+
});
|
|
@@ -1,29 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
//
|
|
3
|
-
// Filename → output extension mapping (zfb convention): the
|
|
4
|
-
// second-to-last `.`-separated segment of the stem becomes the output
|
|
5
|
-
// extension, so `robots.txt.tsx` builds `dist/robots.txt`. The
|
|
6
|
-
// explicit `contentType` export pins the dev-server Content-Type
|
|
7
|
-
// header to `text/plain` regardless of the filename hint.
|
|
8
|
-
|
|
1
|
+
import { renderRobots } from "@takazudo/zudo-doc/robots";
|
|
9
2
|
import { settings } from "@/config/settings";
|
|
10
3
|
|
|
11
|
-
export const frontmatter = { title: "Robots" };
|
|
12
4
|
export const contentType = "text/plain";
|
|
13
|
-
|
|
14
|
-
export default function Robots(): string {
|
|
15
|
-
if (settings.noindex) {
|
|
16
|
-
// noindex: disallow all crawlers. Omit Sitemap: — advertising a sitemap
|
|
17
|
-
// while disallowing all crawlers is contradictory.
|
|
18
|
-
return `User-agent: *\nDisallow: /\n`;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const siteUrlBase = (settings.siteUrl ?? "").replace(/\/$/, "");
|
|
22
|
-
const hasSitemapLine = siteUrlBase !== "" && settings.sitemap;
|
|
23
|
-
|
|
24
|
-
const sitemapLine = hasSitemapLine
|
|
25
|
-
? `Sitemap: ${siteUrlBase}/sitemap.xml\n`
|
|
26
|
-
: "";
|
|
27
|
-
|
|
28
|
-
return `User-agent: *\nAllow: /\n${sitemapLine}`;
|
|
29
|
-
}
|
|
5
|
+
export default () => renderRobots(settings);
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
// W6A stub — no-op default export.
|
|
1
|
+
// W6A stub — no-op default + AiChatModal named exports.
|
|
4
2
|
//
|
|
5
|
-
// The
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
3
|
+
// The AiChatModal island now ships from the package
|
|
4
|
+
// (`@takazudo/zudo-doc/ai-chat-modal`); the unconditional
|
|
5
|
+
// `pages/lib/_body-end-islands.tsx` imports it directly from there. This
|
|
6
|
+
// stub exists only so any project-local code that references the
|
|
7
|
+
// `@/components/ai-chat-modal` path still resolves — it renders nothing.
|
|
8
|
+
// Replace this file to wire a project-specific modal.
|
|
10
9
|
import type { JSX } from "preact";
|
|
11
10
|
|
|
12
11
|
function AiChatModal(): JSX.Element | null {
|
|
@@ -15,3 +14,5 @@ function AiChatModal(): JSX.Element | null {
|
|
|
15
14
|
AiChatModal.displayName = "AiChatModal";
|
|
16
15
|
|
|
17
16
|
export default AiChatModal;
|
|
17
|
+
|
|
18
|
+
export { AiChatModal };
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
1
|
// W6A stub — no-op default + DocHistory named exports.
|
|
4
2
|
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
3
|
+
// The real DocHistory island now ships from the package
|
|
4
|
+
// (`@takazudo/zudo-doc/doc-history`); the unconditional
|
|
5
|
+
// `pages/lib/_doc-history-area.tsx` imports it directly from there. When
|
|
6
|
+
// the docHistory feature is enabled the feature template overwrites this
|
|
7
|
+
// file with a re-export shim pointing at the package island. Generated
|
|
8
|
+
// projects without the feature ship this no-op so any project-local code
|
|
9
|
+
// that references the `@/components/doc-history` path still resolves. The
|
|
10
|
+
// host module exposes `DocHistory` as a named export, so the stub mirrors
|
|
11
|
+
// both the default and named shapes to keep the import surface stable.
|
|
11
12
|
import type { JSX } from "preact";
|
|
12
13
|
|
|
13
14
|
function DocHistoryComponent(): JSX.Element | null {
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
// W6A stub — no-op default + ImageEnlargeSsrFallback named exports.
|
|
1
|
+
// W6A stub — no-op default + ImageEnlarge / ImageEnlargeSsrFallback exports.
|
|
4
2
|
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
3
|
+
// The real ImageEnlarge island and its SSR fallback now ship from the
|
|
4
|
+
// package (`@takazudo/zudo-doc/image-enlarge`); the unconditional
|
|
5
|
+
// `pages/lib/_body-end-islands.tsx` imports them directly from there. When
|
|
6
|
+
// the imageEnlarge feature is enabled the feature template overwrites this
|
|
7
|
+
// file with a re-export shim pointing at the package island. Generated
|
|
8
|
+
// projects without the feature ship this no-op so any project-local code
|
|
9
|
+
// that references the `@/components/image-enlarge` path still resolves (the
|
|
10
|
+
// body-end renderer references both the default and the SSR fallback).
|
|
10
11
|
import type { JSX } from "preact";
|
|
11
12
|
|
|
12
13
|
function ImageEnlarge(): JSX.Element | null {
|
|
@@ -16,6 +17,8 @@ ImageEnlarge.displayName = "ImageEnlarge";
|
|
|
16
17
|
|
|
17
18
|
export default ImageEnlarge;
|
|
18
19
|
|
|
20
|
+
export { ImageEnlarge };
|
|
21
|
+
|
|
19
22
|
export function ImageEnlargeSsrFallback(): JSX.Element | null {
|
|
20
23
|
return null;
|
|
21
24
|
}
|
|
@@ -1,170 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
// the global React namespace still resolve via @types/react.
|
|
8
|
-
import { useState, useEffect } from "preact/hooks";
|
|
9
|
-
// After zudolab/zudo-doc#1335 (E2 task 2 half B) the host components
|
|
10
|
-
// pull lifecycle event names from the v2 transitions module rather
|
|
11
|
-
// than hard-coding `astro:*` literals.
|
|
12
|
-
import { AFTER_NAVIGATE_EVENT } from "@takazudo/zudo-doc/transitions";
|
|
13
|
-
import SidebarTree from "@/components/sidebar-tree";
|
|
14
|
-
import type { NavNode } from "@/utils/docs";
|
|
15
|
-
import type { LocaleLink } from "@/types/locale";
|
|
16
|
-
// Types-only subpath (`./sidebar/types`) sidesteps the JSX type-graph
|
|
17
|
-
// pulled in by `./sidebar`'s runtime barrel.
|
|
18
|
-
import type { SidebarRootMenuItem } from "@takazudo/zudo-doc/sidebar/types";
|
|
19
|
-
|
|
20
|
-
const cx = (...classes: Array<string | false | null | undefined>) =>
|
|
21
|
-
classes.filter(Boolean).join(" ");
|
|
22
|
-
|
|
23
|
-
// Mobile drawer hosts the SidebarTree directly (rather than receiving it as
|
|
24
|
-
// JSX children) so the tree's data props ride across the SSR → hydrate
|
|
25
|
-
// boundary inside the Island marker's `data-props` attribute. zfb's
|
|
26
|
-
// `Island()` only serialises a child component's *own* props (excluding
|
|
27
|
-
// `children`); when SidebarTree was passed as `children`, its data was
|
|
28
|
-
// dropped during hydration and Preact wiped the SSR-rendered tree DOM.
|
|
29
|
-
// Mirroring the desktop `<Sidebar treeComponent={SidebarTree} ...>` shape
|
|
30
|
-
// keeps the data attached to the wrapping island. zudolab/zudo-doc#1355
|
|
31
|
-
// wave 13.5.
|
|
32
|
-
|
|
33
|
-
interface SidebarToggleProps {
|
|
34
|
-
nodes: NavNode[];
|
|
35
|
-
currentSlug?: string;
|
|
36
|
-
rootMenuItems?: SidebarRootMenuItem[];
|
|
37
|
-
backToMenuLabel?: string;
|
|
38
|
-
localeLinks?: LocaleLink[];
|
|
39
|
-
themeDefaultMode?: "light" | "dark";
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export default function SidebarToggle({
|
|
43
|
-
nodes,
|
|
44
|
-
currentSlug,
|
|
45
|
-
rootMenuItems,
|
|
46
|
-
backToMenuLabel,
|
|
47
|
-
localeLinks,
|
|
48
|
-
themeDefaultMode,
|
|
49
|
-
}: SidebarToggleProps) {
|
|
50
|
-
// Initial state must match SSR (`open=false`) so the hydration DOM
|
|
51
|
-
// matches the SSG output byte-for-byte. The backdrop and toggle-icon
|
|
52
|
-
// are rendered unconditionally below so the hydration tree has the
|
|
53
|
-
// same shape regardless of `open`, preventing Preact from re-mounting
|
|
54
|
-
// the subtree (which can drop click handlers on the hamburger button).
|
|
55
|
-
const [open, setOpen] = useState(false);
|
|
56
|
-
|
|
57
|
-
useEffect(() => {
|
|
58
|
-
if (open) {
|
|
59
|
-
document.body.style.overflow = "hidden";
|
|
60
|
-
} else {
|
|
61
|
-
document.body.style.overflow = "";
|
|
62
|
-
}
|
|
63
|
-
return () => {
|
|
64
|
-
document.body.style.overflow = "";
|
|
65
|
-
};
|
|
66
|
-
}, [open]);
|
|
67
|
-
|
|
68
|
-
// Close mobile sidebar on View Transition navigation
|
|
69
|
-
useEffect(() => {
|
|
70
|
-
function handleSwap() {
|
|
71
|
-
setOpen(false);
|
|
72
|
-
}
|
|
73
|
-
document.addEventListener(AFTER_NAVIGATE_EVENT, handleSwap);
|
|
74
|
-
return () => document.removeEventListener(AFTER_NAVIGATE_EVENT, handleSwap);
|
|
75
|
-
}, []);
|
|
76
|
-
|
|
77
|
-
return (
|
|
78
|
-
<>
|
|
79
|
-
{/* Hamburger button - visible only on mobile.
|
|
80
|
-
Both icons are always rendered so the SSR output has the same
|
|
81
|
-
DOM shape as the post-hydration tree. The closed-state icon is
|
|
82
|
-
hidden via `hidden` when open=true, and vice versa, so Preact's
|
|
83
|
-
hydration walk sees byte-stable markup and keeps the click
|
|
84
|
-
handler attached. */}
|
|
85
|
-
<button
|
|
86
|
-
type="button"
|
|
87
|
-
onClick={() => setOpen(!open)}
|
|
88
|
-
className="lg:hidden px-hsp-sm py-vsp-xs -ml-hsp-sm mr-hsp-sm text-muted hover:text-fg"
|
|
89
|
-
aria-label={open ? "Close sidebar" : "Open sidebar"}
|
|
90
|
-
aria-expanded={open}
|
|
91
|
-
>
|
|
92
|
-
{/* X icon — visible only when open */}
|
|
93
|
-
<svg
|
|
94
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
95
|
-
className={cx("h-icon-lg w-icon-lg", !open && "hidden")}
|
|
96
|
-
aria-hidden="true"
|
|
97
|
-
fill="none"
|
|
98
|
-
viewBox="0 0 24 24"
|
|
99
|
-
stroke="currentColor"
|
|
100
|
-
strokeWidth={2}
|
|
101
|
-
>
|
|
102
|
-
<path
|
|
103
|
-
strokeLinecap="round"
|
|
104
|
-
strokeLinejoin="round"
|
|
105
|
-
d="M6 18L18 6M6 6l12 12"
|
|
106
|
-
/>
|
|
107
|
-
</svg>
|
|
108
|
-
{/* Hamburger icon — visible only when closed */}
|
|
109
|
-
<svg
|
|
110
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
111
|
-
className={cx("h-icon-lg w-icon-lg", open && "hidden")}
|
|
112
|
-
aria-hidden="true"
|
|
113
|
-
fill="none"
|
|
114
|
-
viewBox="0 0 24 24"
|
|
115
|
-
stroke="currentColor"
|
|
116
|
-
strokeWidth={2}
|
|
117
|
-
>
|
|
118
|
-
<path
|
|
119
|
-
strokeLinecap="round"
|
|
120
|
-
strokeLinejoin="round"
|
|
121
|
-
d="M4 6h16M4 12h16M4 18h16"
|
|
122
|
-
/>
|
|
123
|
-
</svg>
|
|
124
|
-
</button>
|
|
125
|
-
|
|
126
|
-
{/* Backdrop overlay - mobile only.
|
|
127
|
-
Rendered unconditionally; CSS `hidden` toggles visibility so
|
|
128
|
-
the SSR DOM tree matches the hydrated tree (no subtree
|
|
129
|
-
mount/unmount across the hydration boundary).
|
|
130
|
-
`z-modal-backdrop` (50) intentionally sits ABOVE the header
|
|
131
|
-
(`z-toolbar`, 20): the open mobile drawer is a modal surface that
|
|
132
|
-
dims the whole viewport, header included. Closing is via tapping the
|
|
133
|
-
backdrop (onClick below), so the header hamburger being dimmed under
|
|
134
|
-
it is fine. */}
|
|
135
|
-
<div
|
|
136
|
-
className={cx("fixed inset-0 z-modal-backdrop bg-overlay/30 lg:hidden", !open && "hidden")}
|
|
137
|
-
aria-hidden={!open}
|
|
138
|
-
onClick={() => setOpen(false)}
|
|
139
|
-
/>
|
|
140
|
-
|
|
141
|
-
{/* Sidebar panel - mobile only (desktop sidebar is in doc-layout).
|
|
142
|
-
`inert` when closed: the panel is only visually hidden via
|
|
143
|
-
`-translate-x-full`, so without `inert` its links/filter/buttons
|
|
144
|
-
stay in the tab order and accessibility tree while off-screen
|
|
145
|
-
(zudolab/zudo-doc#2059). `inert={false}` serialises to no attribute,
|
|
146
|
-
so the SSR (open=false → `inert`) and initial client render stay
|
|
147
|
-
byte-stable for hydration. */}
|
|
148
|
-
<aside
|
|
149
|
-
inert={!open}
|
|
150
|
-
className={`
|
|
151
|
-
fixed top-[3.5rem] left-0 z-modal h-[calc(100vh-3.5rem)] w-[16rem] flex flex-col
|
|
152
|
-
border-r border-muted bg-bg transition-transform duration-200
|
|
153
|
-
lg:hidden
|
|
154
|
-
${open ? "translate-x-0" : "-translate-x-full"}
|
|
155
|
-
`}
|
|
156
|
-
>
|
|
157
|
-
<div className="flex-1 overflow-y-auto">
|
|
158
|
-
<SidebarTree
|
|
159
|
-
nodes={nodes}
|
|
160
|
-
currentSlug={currentSlug}
|
|
161
|
-
rootMenuItems={rootMenuItems}
|
|
162
|
-
backToMenuLabel={backToMenuLabel}
|
|
163
|
-
localeLinks={localeLinks}
|
|
164
|
-
themeDefaultMode={themeDefaultMode}
|
|
165
|
-
/>
|
|
166
|
-
</div>
|
|
167
|
-
</aside>
|
|
168
|
-
</>
|
|
169
|
-
);
|
|
170
|
-
}
|
|
1
|
+
// Thin re-export shim. SidebarToggle moved into the package
|
|
2
|
+
// (`@takazudo/zudo-doc/sidebar-toggle-island`) as part of the package-first
|
|
3
|
+
// migration (#2344, S2). Host code using `@/components/sidebar-toggle`
|
|
4
|
+
// still resolves correctly; the implementation lives in the package.
|
|
5
|
+
export { SidebarToggle } from "@takazudo/zudo-doc/sidebar-toggle-island";
|
|
6
|
+
export type { SidebarToggleProps } from "@takazudo/zudo-doc/sidebar-toggle-island";
|