create-zudo-doc 0.2.0 → 0.2.2
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/api.js +4 -1
- package/dist/cli.js +4 -6
- package/dist/compose.d.ts +2 -3
- package/dist/compose.js +7 -4
- package/dist/features/tauri.d.ts +10 -5
- package/dist/features/tauri.js +49 -6
- package/dist/preset.js +11 -0
- package/dist/prompts.js +2 -6
- package/dist/scaffold.js +15 -9
- package/dist/settings-gen.js +9 -6
- package/dist/utils.d.ts +8 -0
- package/dist/utils.js +25 -0
- package/dist/zfb-config-gen.js +11 -50
- package/package.json +1 -1
- package/templates/base/pages/_data.ts +10 -23
- package/templates/base/pages/docs/[[...slug]].tsx +27 -168
- package/templates/base/pages/lib/_body-end-islands.tsx +3 -0
- package/templates/base/pages/lib/_doc-content-header.tsx +24 -4
- package/templates/base/pages/lib/_doc-history-area.tsx +21 -5
- package/templates/base/pages/lib/_doc-metainfo-area.tsx +22 -2
- package/templates/base/pages/lib/_doc-page-renderer.tsx +192 -0
- package/templates/base/pages/lib/_doc-page-shell.tsx +3 -2
- package/templates/base/pages/lib/_doc-route-entries.ts +188 -0
- package/templates/base/pages/lib/_doc-tags-area.tsx +7 -2
- package/templates/base/pages/lib/_footer-with-defaults.tsx +38 -27
- package/templates/base/pages/lib/_head-with-defaults.tsx +7 -10
- package/templates/base/pages/lib/_header-with-defaults.tsx +54 -89
- package/templates/base/pages/lib/_inline-version-switcher.tsx +5 -4
- package/templates/base/pages/lib/_nav-data-prep.ts +137 -0
- package/templates/base/pages/lib/_nav-source-docs.ts +10 -6
- package/templates/base/pages/lib/_search-widget-script.ts +32 -9
- package/templates/base/pages/lib/_sidebar-with-defaults.tsx +15 -60
- package/templates/base/pages/lib/locale-merge.ts +1 -1
- package/templates/base/pages/lib/route-enumerators.ts +11 -7
- package/templates/base/plugins/connect-adapter.mjs +30 -1
- package/templates/base/plugins/copy-public-plugin.mjs +10 -2
- package/templates/base/plugins/search-index-plugin.mjs +20 -8
- package/templates/base/src/components/ai-chat-modal.tsx +2 -0
- package/templates/base/src/components/doc-history.tsx +2 -0
- package/templates/base/src/components/image-enlarge.tsx +2 -0
- package/templates/base/src/components/sidebar-toggle.tsx +1 -1
- package/templates/base/src/components/sidebar-tree.tsx +11 -5
- package/templates/base/src/components/theme-toggle.tsx +18 -102
- package/templates/base/src/config/color-schemes.ts +4 -0
- package/templates/base/src/config/docs-schema.ts +94 -0
- package/templates/base/src/config/i18n.ts +10 -3
- package/templates/base/src/styles/global.css +14 -0
- package/templates/base/src/types/docs-entry.ts +8 -26
- package/templates/base/src/utils/base.ts +5 -3
- package/templates/base/src/utils/docs.ts +144 -169
- package/templates/base/zfb-shim.d.ts +167 -0
- package/templates/features/claudeResources/files/plugins/claude-resources-plugin.mjs +20 -110
- package/templates/features/claudeResources/files/src/integrations/claude-resources/generate.ts +62 -38
- package/templates/features/designTokenPanel/files/src/config/design-token-panel-config.ts +34 -8
- package/templates/features/docHistory/files/plugins/doc-history-plugin.mjs +27 -45
- package/templates/features/docHistory/files/src/components/doc-history.tsx +30 -8
- package/templates/features/docTags/files/pages/[locale]/docs/tags/[tag].tsx +6 -74
- package/templates/features/docTags/files/pages/[locale]/docs/tags/index.tsx +6 -77
- package/templates/features/docTags/files/pages/docs/tags/[tag].tsx +7 -69
- package/templates/features/docTags/files/pages/docs/tags/index.tsx +6 -76
- package/templates/features/docTags/files/pages/lib/_tag-pages.tsx +201 -0
- package/templates/features/i18n/files/pages/[locale]/docs/[[...slug]].tsx +41 -179
- package/templates/features/i18n/files/pages/[locale]/index.tsx +5 -5
- package/templates/features/imageEnlarge/files/src/components/image-enlarge.tsx +2 -0
- package/templates/features/llmsTxt/files/plugins/llms-txt-plugin.mjs +33 -21
- package/templates/features/sidebarToggle/files/src/components/desktop-sidebar-toggle.tsx +1 -1
- package/templates/features/tauri/files/src/components/find-in-page-init.tsx +9 -3
- package/templates/features/versioning/files/pages/[locale]/docs/versions.tsx +5 -59
- package/templates/features/versioning/files/pages/docs/versions.tsx +8 -66
- package/templates/features/versioning/files/pages/lib/_versions-page.tsx +79 -0
- package/templates/features/versioning/files/pages/v/[version]/[locale]/docs/[[...slug]].tsx +46 -191
- package/templates/features/versioning/files/pages/v/[version]/docs/[[...slug]].tsx +31 -173
- package/templates/base/src/components/content/heading-h3.tsx +0 -20
- package/templates/base/src/hooks/use-active-heading.ts +0 -133
- package/templates/base/src/plugins/docs-source-map.ts +0 -103
- package/templates/base/src/plugins/hast-utils.ts +0 -10
- package/templates/base/src/plugins/rehype-code-title.ts +0 -50
- package/templates/base/src/plugins/rehype-heading-links.ts +0 -53
- package/templates/base/src/plugins/rehype-mermaid.ts +0 -41
- package/templates/base/src/plugins/url-utils.ts +0 -4
- package/templates/base/src/utils/dedent.ts +0 -24
- package/templates/features/docHistory/files/src/utils/doc-history.ts +0 -180
- package/templates/features/sidebarResizer/files/src/scripts/sidebar-resizer.ts +0 -198
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/** @jsxRuntime automatic */
|
|
2
|
+
/** @jsxImportSource preact */
|
|
3
|
+
// Shared renderer for the documentation-versions pages (#2010).
|
|
4
|
+
//
|
|
5
|
+
// Collapses the per-locale page pair:
|
|
6
|
+
// pages/docs/versions.tsx + pages/[locale]/docs/versions.tsx
|
|
7
|
+
// into one locale-parameterized renderer. The page files stay thin shells
|
|
8
|
+
// that own only their paths() param shapes; URL prefixes and the
|
|
9
|
+
// default-vs-locale href shapes live here.
|
|
10
|
+
|
|
11
|
+
import { settings } from "@/config/settings";
|
|
12
|
+
import { defaultLocale, t, type Locale } from "@/config/i18n";
|
|
13
|
+
import { withBase } from "@/utils/base";
|
|
14
|
+
import { DocLayoutWithDefaults } from "@takazudo/zudo-doc/doclayout";
|
|
15
|
+
import { VersionsPageContent } from "@takazudo/zudo-doc/nav-indexing";
|
|
16
|
+
import type { VersionPageEntry, VersionsPageLabels } from "@takazudo/zudo-doc/nav-indexing";
|
|
17
|
+
import type { JSX } from "preact";
|
|
18
|
+
import { FooterWithDefaults } from "./_footer-with-defaults";
|
|
19
|
+
import { HeaderWithDefaults } from "./_header-with-defaults";
|
|
20
|
+
import { HeadWithDefaults } from "./_head-with-defaults";
|
|
21
|
+
import { composeMetaTitle } from "./_compose-meta-title";
|
|
22
|
+
import { BodyEndIslands } from "./_body-end-islands";
|
|
23
|
+
|
|
24
|
+
/** Versions index page for one locale. Lists the latest version and any past
|
|
25
|
+
* versions configured in settings.versions. */
|
|
26
|
+
export function VersionsPageView({ locale }: { locale: string }): JSX.Element {
|
|
27
|
+
const isDefault = locale === defaultLocale;
|
|
28
|
+
const prefix = isDefault ? "" : `/${locale}`;
|
|
29
|
+
const pageTitle = t("version.page.title", locale);
|
|
30
|
+
|
|
31
|
+
const labels: VersionsPageLabels = {
|
|
32
|
+
pageTitle,
|
|
33
|
+
latestTitle: t("version.page.latest.title", locale),
|
|
34
|
+
latestDescription: t("version.page.latest.description", locale),
|
|
35
|
+
latestLink: t("version.page.latest.link", locale),
|
|
36
|
+
pastTitle: t("version.page.past.title", locale),
|
|
37
|
+
pastDescription: t("version.page.past.description", locale),
|
|
38
|
+
unmaintained: t("version.page.unmaintained", locale),
|
|
39
|
+
unreleased: t("version.page.unreleased", locale),
|
|
40
|
+
versionCol: t("version.switcher.label", locale),
|
|
41
|
+
statusCol: t("version.page.status", locale),
|
|
42
|
+
docsCol: t("version.page.docs", locale),
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// Latest docs href — points to the default docs entry point
|
|
46
|
+
const latestHref = withBase(`${prefix}/docs/getting-started`);
|
|
47
|
+
|
|
48
|
+
// Past version entries from settings
|
|
49
|
+
const versions: VersionPageEntry[] = settings.versions
|
|
50
|
+
? settings.versions.map((v) => ({
|
|
51
|
+
slug: v.slug,
|
|
52
|
+
label: v.label ?? v.slug,
|
|
53
|
+
// Version prefix comes BEFORE the locale — the only routed shape is
|
|
54
|
+
// pages/v/[version]/{locale}/docs/...; /{locale}/v/... has no route.
|
|
55
|
+
docsHref: withBase(`/v/${v.slug}${prefix}/docs/getting-started/`),
|
|
56
|
+
banner: v.banner as "unmaintained" | "unreleased" | undefined,
|
|
57
|
+
}))
|
|
58
|
+
: [];
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<DocLayoutWithDefaults
|
|
62
|
+
title={composeMetaTitle(pageTitle)}
|
|
63
|
+
head={<HeadWithDefaults title={pageTitle} />}
|
|
64
|
+
lang={locale}
|
|
65
|
+
noindex={settings.noindex}
|
|
66
|
+
hideSidebar={true}
|
|
67
|
+
hideToc={true}
|
|
68
|
+
headerOverride={<HeaderWithDefaults lang={locale as Locale} currentPath={withBase(`${prefix}/docs/versions`)} />}
|
|
69
|
+
footerOverride={<FooterWithDefaults lang={locale} />}
|
|
70
|
+
bodyEndComponents={<BodyEndIslands basePath={settings.base ?? "/"} />}
|
|
71
|
+
>
|
|
72
|
+
<VersionsPageContent
|
|
73
|
+
latestHref={latestHref}
|
|
74
|
+
versions={versions}
|
|
75
|
+
labels={labels}
|
|
76
|
+
/>
|
|
77
|
+
</DocLayoutWithDefaults>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
@@ -19,30 +19,21 @@
|
|
|
19
19
|
//
|
|
20
20
|
// Prev/next hrefs are pre-resolved to the versioned locale URL form
|
|
21
21
|
// (e.g. /v/1.0/ja/docs/…) so the component needs no URL computation.
|
|
22
|
+
//
|
|
23
|
+
// Enumeration + per-entry derived data are built by the shared, memoized
|
|
24
|
+
// buildDocRouteEntries (#2010); rendering by the shared renderDocPage. This
|
|
25
|
+
// file owns only the route's nav source, its versioned-locale URL closure,
|
|
26
|
+
// and the param/prop shapes.
|
|
22
27
|
|
|
23
28
|
import { settings } from "@/config/settings";
|
|
24
29
|
import type { VersionConfig } from "@/config/settings";
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
buildNavTree,
|
|
29
|
-
buildBreadcrumbs,
|
|
30
|
-
collectAutoIndexNodes,
|
|
31
|
-
type NavNode,
|
|
32
|
-
} from "@/utils/docs";
|
|
33
|
-
import { getNavSectionForSlug, getNavSubtree } from "@/utils/nav-scope";
|
|
34
|
-
import { toRouteSlug, toSlugParams } from "@/utils/slug";
|
|
35
|
-
// Locale-aware MDX components factory — see `pages/_mdx-components.ts`.
|
|
36
|
-
import { createMdxComponents } from "../../../../_mdx-components";
|
|
30
|
+
import { type Locale } from "@/config/i18n";
|
|
31
|
+
import { versionedDocsUrl } from "@/utils/base";
|
|
37
32
|
import type { JSX } from "preact";
|
|
38
33
|
import { resolveVersionedLocaleSource } from "../../../../lib/_nav-source-docs";
|
|
39
|
-
import {
|
|
40
|
-
import
|
|
41
|
-
import {
|
|
42
|
-
import { buildInlineVersionSwitcher } from "../../../../lib/_inline-version-switcher";
|
|
43
|
-
import { DocContentHeader } from "../../../../lib/_doc-content-header";
|
|
44
|
-
import { DocPageShell } from "../../../../lib/_doc-page-shell";
|
|
45
|
-
import { resolveDocPrevNext, flattenSubtree, rewriteNavHref, remapNavChildHrefs } from "../../../../lib/_doc-route-paths";
|
|
34
|
+
import type { DocPageEntryProps, DocPageAutoIndexProps } from "../../../../lib/doc-page-props";
|
|
35
|
+
import { buildDocRouteEntries } from "../../../../lib/_doc-route-entries";
|
|
36
|
+
import { renderDocPage } from "../../../../lib/_doc-page-renderer";
|
|
46
37
|
|
|
47
38
|
export const frontmatter = { title: "Docs" };
|
|
48
39
|
|
|
@@ -50,8 +41,6 @@ export const frontmatter = { title: "Docs" };
|
|
|
50
41
|
// Types
|
|
51
42
|
// ---------------------------------------------------------------------------
|
|
52
43
|
|
|
53
|
-
// DocPageEntry, AutoIndexNode imported from pages/lib/doc-page-props.ts
|
|
54
|
-
|
|
55
44
|
/** Route-specific extra fields — present on both branches of the union. */
|
|
56
45
|
interface VersionedLocaleDocPageExtra {
|
|
57
46
|
/** The version config for the active version. */
|
|
@@ -102,87 +91,43 @@ export function paths(): Array<{
|
|
|
102
91
|
|
|
103
92
|
// Identity-stable, locale-first merge over the version's EN base. Reused
|
|
104
93
|
// across the route's per-page paths() invocations so buildNavTree's
|
|
105
|
-
// identity fast-path
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
// root index has entry.slug="index" (storage form) but route slug="" so
|
|
114
|
-
// d.id would diverge from the lookup key after the #1891 toRouteSlug flip.
|
|
115
|
-
const fallbackSlugs = new Set(
|
|
116
|
-
allDocs
|
|
117
|
-
.filter((d) => !localeSlugSet.has(d.data.slug ?? toRouteSlug(d.slug)))
|
|
118
|
-
.map((d) => d.data.slug ?? toRouteSlug(d.slug)),
|
|
94
|
+
// identity fast-path and the buildDocRouteEntries memo apply — see
|
|
95
|
+
// pages/lib/_nav-source-docs.ts (#1902).
|
|
96
|
+
const source = resolveVersionedLocaleSource(
|
|
97
|
+
version.slug,
|
|
98
|
+
version.docsDir,
|
|
99
|
+
locale as Locale,
|
|
100
|
+
localeDir,
|
|
101
|
+
{ applyDefaultLocaleOnlyFilter: true, keepUnlisted: true },
|
|
119
102
|
);
|
|
120
103
|
|
|
121
|
-
const tree = buildNavTree(navDocs, locale, categoryMeta);
|
|
122
|
-
|
|
123
104
|
// URL closure for THIS (version, locale) — every versioned-locale href
|
|
124
105
|
// (prev/next, breadcrumb crumbs, auto-index cards) is produced by this
|
|
125
106
|
// single function bound to the version slug + locale, resolved against
|
|
126
|
-
// this route's own
|
|
127
|
-
const urlFor = (s: string): string => versionedDocsUrl(s, version.slug, locale);
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
flattenSubtree(subtree),
|
|
145
|
-
slug,
|
|
146
|
-
entry.data,
|
|
147
|
-
);
|
|
148
|
-
|
|
149
|
-
result.push({
|
|
150
|
-
params: { version: version.slug, locale, slug: toSlugParams(slug) },
|
|
151
|
-
props: {
|
|
152
|
-
kind: "entry",
|
|
153
|
-
entry,
|
|
154
|
-
version,
|
|
155
|
-
contentDir: entryContentDir,
|
|
156
|
-
isFallback,
|
|
157
|
-
// #1916 #1: breadcrumb crumbs remapped to the versioned locale URL.
|
|
158
|
-
breadcrumbs: buildBreadcrumbs(tree, slug, locale, urlFor),
|
|
159
|
-
prev: rewriteNavHref(prevNode, urlFor),
|
|
160
|
-
next: rewriteNavHref(nextNode, urlFor),
|
|
161
|
-
headings: extractHeadings(entry.body ?? ""),
|
|
162
|
-
},
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// Auto-generated index pages for categories without index.mdx
|
|
167
|
-
for (const node of collectAutoIndexNodes(tree)) {
|
|
107
|
+
// this route's own tree (#1916).
|
|
108
|
+
const urlFor = (s: string): string => versionedDocsUrl(s, version.slug, locale as Locale);
|
|
109
|
+
|
|
110
|
+
for (const item of buildDocRouteEntries({
|
|
111
|
+
source,
|
|
112
|
+
locale: locale as Locale,
|
|
113
|
+
routeSig: `v-locale-docs;${version.slug};${locale}`,
|
|
114
|
+
urlFor,
|
|
115
|
+
})) {
|
|
116
|
+
// isFallback: page came from the version's base EN docs, not the
|
|
117
|
+
// locale collection. Always false for autoIndex items.
|
|
118
|
+
const extra: VersionedLocaleDocPageExtra = {
|
|
119
|
+
version,
|
|
120
|
+
contentDir: item.isFallback
|
|
121
|
+
? version.docsDir
|
|
122
|
+
: (localeDir ?? version.docsDir),
|
|
123
|
+
isFallback: item.isFallback,
|
|
124
|
+
};
|
|
168
125
|
result.push({
|
|
169
|
-
params: { version: version.slug, locale, slug:
|
|
170
|
-
props:
|
|
171
|
-
kind
|
|
172
|
-
|
|
173
|
-
...
|
|
174
|
-
// #1916 #2: child-card hrefs ALWAYS resolve to the versioned URL.
|
|
175
|
-
children: remapNavChildHrefs(node.children, urlFor) as NavNode[],
|
|
176
|
-
} as AutoIndexNode,
|
|
177
|
-
version,
|
|
178
|
-
contentDir: localeDir ?? version.docsDir,
|
|
179
|
-
isFallback: false,
|
|
180
|
-
// #1916 #1: breadcrumb crumbs remapped to the versioned locale URL.
|
|
181
|
-
breadcrumbs: buildBreadcrumbs(tree, node.slug, locale, urlFor),
|
|
182
|
-
prev: null,
|
|
183
|
-
next: null,
|
|
184
|
-
headings: [],
|
|
185
|
-
},
|
|
126
|
+
params: { version: version.slug, locale, slug: item.slugParams },
|
|
127
|
+
props:
|
|
128
|
+
item.props.kind === "entry"
|
|
129
|
+
? { ...item.props, ...extra }
|
|
130
|
+
: { ...item.props, ...extra },
|
|
186
131
|
});
|
|
187
132
|
}
|
|
188
133
|
}
|
|
@@ -198,99 +143,9 @@ export function paths(): Array<{
|
|
|
198
143
|
type PageArgs = DocPageProps & { params: { version: string; locale: string; slug: string[] } };
|
|
199
144
|
|
|
200
145
|
export default function VersionedLocaleDocsPage(props: PageArgs): JSX.Element {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
: (props.entry.data.slug ?? toRouteSlug(props.entry.slug));
|
|
207
|
-
|
|
208
|
-
const title = props.kind === "autoIndex" ? props.autoIndex.label : props.entry.data.title;
|
|
209
|
-
const description = props.kind === "autoIndex" ? props.autoIndex.description : props.entry.data.description;
|
|
210
|
-
|
|
211
|
-
// Locale-aware components bag — creates nav wrappers bound to the active
|
|
212
|
-
// locale so CategoryNav/CategoryTreeNav/SiteTreeNav query the right collection.
|
|
213
|
-
const components = createMdxComponents(locale);
|
|
214
|
-
|
|
215
|
-
// #1916 #2: child cards already carry versioned hrefs from paths(); just
|
|
216
|
-
// filter to renderable nodes here.
|
|
217
|
-
const autoIndexChildren = props.kind === "autoIndex"
|
|
218
|
-
? props.autoIndex.children.filter((c: NavNode) => c.hasPage || c.children.length > 0)
|
|
219
|
-
: [];
|
|
220
|
-
|
|
221
|
-
// Version banner: drives the `<VersionBanner>` element inside
|
|
222
|
-
// DocLayoutWithDefaults when `version.banner` is "unmaintained" or
|
|
223
|
-
// "unreleased". The banner links out to the latest version of the
|
|
224
|
-
// current page (slug-preserving — strips the /v/{version}/ prefix,
|
|
225
|
-
// keeps the /{locale}/ locale prefix).
|
|
226
|
-
const versionBannerType = version.banner ? version.banner : undefined;
|
|
227
|
-
const versionBannerLatestUrl = versionBannerType
|
|
228
|
-
? docsUrl(slug, locale)
|
|
229
|
-
: undefined;
|
|
230
|
-
const versionBannerLabels = versionBannerType
|
|
231
|
-
? {
|
|
232
|
-
message:
|
|
233
|
-
versionBannerType === "unmaintained"
|
|
234
|
-
? t("version.banner.unmaintained", locale)
|
|
235
|
-
: t("version.banner.unreleased", locale),
|
|
236
|
-
latestLink: t("version.banner.latestLink", locale),
|
|
237
|
-
}
|
|
238
|
-
: undefined;
|
|
239
|
-
|
|
240
|
-
// Canonical URL — versioned locale pages use the versioned locale URL as canonical.
|
|
241
|
-
const currentPath = versionedDocsUrl(slug, version.slug, locale);
|
|
242
|
-
const canonical = absoluteUrl(currentPath);
|
|
243
|
-
|
|
244
|
-
// Persist key: locale + nav-section so the sidebar DOM node is reused
|
|
245
|
-
// across same-locale + same-section navigations only. No sanitizer needed —
|
|
246
|
-
// both lang (BCP-47 locale string) and navSection (filesystem-derived
|
|
247
|
-
// kebab-case slug) come from controlled, trusted sources.
|
|
248
|
-
const navSection = getNavSectionForSlug(slug);
|
|
249
|
-
const hideSidebar = props.kind === "entry" ? props.entry.data.hide_sidebar : undefined;
|
|
250
|
-
const sidebarPersistKey = hideSidebar
|
|
251
|
-
? undefined
|
|
252
|
-
: `sidebar-${locale}-${navSection ?? "default"}`;
|
|
253
|
-
|
|
254
|
-
return (
|
|
255
|
-
<DocPageShell
|
|
256
|
-
kind={props.kind}
|
|
257
|
-
locale={locale}
|
|
258
|
-
slug={slug}
|
|
259
|
-
title={title}
|
|
260
|
-
description={description}
|
|
261
|
-
canonical={canonical}
|
|
262
|
-
breadcrumbs={breadcrumbs}
|
|
263
|
-
prev={prev}
|
|
264
|
-
next={next}
|
|
265
|
-
headings={headings}
|
|
266
|
-
navSection={navSection}
|
|
267
|
-
sidebarPersistKey={sidebarPersistKey}
|
|
268
|
-
hideSidebar={hideSidebar}
|
|
269
|
-
hideToc={props.kind === "entry" ? props.entry.data.hide_toc : undefined}
|
|
270
|
-
currentPath={currentPath}
|
|
271
|
-
currentVersion={version.slug}
|
|
272
|
-
versionSwitcher={buildInlineVersionSwitcher(slug, locale, version.slug)}
|
|
273
|
-
versionBanner={versionBannerType}
|
|
274
|
-
versionBannerLatestUrl={versionBannerLatestUrl}
|
|
275
|
-
versionBannerLabels={versionBannerLabels}
|
|
276
|
-
autoIndexLabel={props.kind === "autoIndex" ? props.autoIndex.label : undefined}
|
|
277
|
-
autoIndexChildren={autoIndexChildren}
|
|
278
|
-
// #1916 #6: add DocMetainfoArea for chrome parity with the other 3
|
|
279
|
-
// doc routes (its absence here was accidental drift, not intentional).
|
|
280
|
-
metainfoSlot={
|
|
281
|
-
props.kind === "autoIndex" ? <DocMetainfoArea slug={slug} locale={locale} /> : null
|
|
282
|
-
}
|
|
283
|
-
contentHeaderSlot={
|
|
284
|
-
props.kind === "entry" ? (
|
|
285
|
-
<DocContentHeader entry={props.entry} slug={slug} locale={locale} isFallback={isFallback} />
|
|
286
|
-
) : undefined
|
|
287
|
-
}
|
|
288
|
-
contentSlot={
|
|
289
|
-
props.kind === "entry" ? <props.entry.Content components={components} /> : undefined
|
|
290
|
-
}
|
|
291
|
-
// #1916 #5: doc-history hidden on versioned pages until versioned
|
|
292
|
-
// history is supported.
|
|
293
|
-
docHistorySlot={null}
|
|
294
|
-
/>
|
|
295
|
-
);
|
|
146
|
+
return renderDocPage(props, {
|
|
147
|
+
locale: props.params.locale as Locale,
|
|
148
|
+
version: props.version,
|
|
149
|
+
isFallback: props.isFallback,
|
|
150
|
+
});
|
|
296
151
|
}
|
|
@@ -19,30 +19,20 @@
|
|
|
19
19
|
//
|
|
20
20
|
// Version banner: if version.banner is set ("unmaintained" | "unreleased"),
|
|
21
21
|
// the DocLayoutWithDefaults version-banner prop drives the banner display.
|
|
22
|
+
//
|
|
23
|
+
// Enumeration + per-entry derived data are built by the shared, memoized
|
|
24
|
+
// buildDocRouteEntries (#2010); rendering by the shared renderDocPage. This
|
|
25
|
+
// file owns only the route's nav source, its versioned URL closure, and the
|
|
26
|
+
// param/prop shapes.
|
|
22
27
|
|
|
23
28
|
import { settings } from "@/config/settings";
|
|
24
29
|
import type { VersionConfig } from "@/config/settings";
|
|
25
|
-
import {
|
|
26
|
-
import { docsUrl, versionedDocsUrl, absoluteUrl } from "@/utils/base";
|
|
27
|
-
import {
|
|
28
|
-
buildNavTree,
|
|
29
|
-
buildBreadcrumbs,
|
|
30
|
-
collectAutoIndexNodes,
|
|
31
|
-
type NavNode,
|
|
32
|
-
} from "@/utils/docs";
|
|
33
|
-
import { getNavSectionForSlug, getNavSubtree } from "@/utils/nav-scope";
|
|
34
|
-
import { toRouteSlug, toSlugParams } from "@/utils/slug";
|
|
35
|
-
// Locale-aware MDX components factory — see `pages/_mdx-components.ts`.
|
|
36
|
-
import { createMdxComponents } from "../../../_mdx-components";
|
|
30
|
+
import { versionedDocsUrl } from "@/utils/base";
|
|
37
31
|
import type { JSX } from "preact";
|
|
38
32
|
import { resolveNavSource } from "../../../lib/_nav-source-docs";
|
|
39
|
-
import {
|
|
40
|
-
import
|
|
41
|
-
import {
|
|
42
|
-
import { buildInlineVersionSwitcher } from "../../../lib/_inline-version-switcher";
|
|
43
|
-
import { DocContentHeader } from "../../../lib/_doc-content-header";
|
|
44
|
-
import { DocPageShell } from "../../../lib/_doc-page-shell";
|
|
45
|
-
import { resolveDocPrevNext, flattenSubtree, rewriteNavHref, remapNavChildHrefs } from "../../../lib/_doc-route-paths";
|
|
33
|
+
import type { DocPageEntryProps, DocPageAutoIndexProps } from "../../../lib/doc-page-props";
|
|
34
|
+
import { buildDocRouteEntries } from "../../../lib/_doc-route-entries";
|
|
35
|
+
import { renderDocPage } from "../../../lib/_doc-page-renderer";
|
|
46
36
|
|
|
47
37
|
export const frontmatter = { title: "Docs" };
|
|
48
38
|
|
|
@@ -50,8 +40,6 @@ export const frontmatter = { title: "Docs" };
|
|
|
50
40
|
// Types
|
|
51
41
|
// ---------------------------------------------------------------------------
|
|
52
42
|
|
|
53
|
-
// DocPageEntry, AutoIndexNode imported from pages/lib/doc-page-props.ts
|
|
54
|
-
|
|
55
43
|
/** Route-specific extra fields — present on both branches of the union. */
|
|
56
44
|
interface VersionedDocPageExtra {
|
|
57
45
|
/** The version config for the active version. */
|
|
@@ -89,73 +77,31 @@ export function paths(): Array<{
|
|
|
89
77
|
for (const version of settings.versions) {
|
|
90
78
|
// Identity-stable nav source for this version (EN base, draft-filtered,
|
|
91
79
|
// unlisted retained). Reused across the route's per-page paths()
|
|
92
|
-
// invocations so buildNavTree's identity fast-path
|
|
93
|
-
// pages/lib/_nav-source-docs.ts
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const tree = buildNavTree(navDocs, "en", categoryMeta);
|
|
80
|
+
// invocations so buildNavTree's identity fast-path and the
|
|
81
|
+
// buildDocRouteEntries memo apply — see pages/lib/_nav-source-docs.ts
|
|
82
|
+
// (#1902). Versioned docs always use EN locale for the nav tree.
|
|
83
|
+
const source = resolveNavSource("en", version.slug);
|
|
97
84
|
|
|
98
85
|
// URL closure for THIS version — every versioned href (prev/next,
|
|
99
86
|
// breadcrumb crumbs, auto-index cards) is produced by this single
|
|
100
87
|
// function bound to the version slug. Because it is built per-version
|
|
101
|
-
// inside this loop, a latest-page pagination override
|
|
102
|
-
//
|
|
103
|
-
//
|
|
104
|
-
// closure (#1916).
|
|
88
|
+
// inside this loop, a latest-page pagination override is rewritten
|
|
89
|
+
// through the VERSIONED closure for this route only — it can never bleed
|
|
90
|
+
// into the latest route, which has no such closure (#1916).
|
|
105
91
|
const urlFor = (s: string): string => versionedDocsUrl(s, version.slug);
|
|
106
92
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const slug = entry.data.slug ?? toRouteSlug(entry.slug);
|
|
114
|
-
const navSection = getNavSectionForSlug(slug);
|
|
115
|
-
const subtree = getNavSubtree(tree, navSection);
|
|
116
|
-
|
|
117
|
-
// Prev/next + pagination overrides against THIS version's own `tree`,
|
|
118
|
-
// then hrefs rewritten to the versioned URL form via urlFor.
|
|
119
|
-
const { prev: prevNode, next: nextNode } = resolveDocPrevNext(
|
|
120
|
-
tree,
|
|
121
|
-
flattenSubtree(subtree),
|
|
122
|
-
slug,
|
|
123
|
-
entry.data,
|
|
124
|
-
);
|
|
125
|
-
|
|
126
|
-
result.push({
|
|
127
|
-
params: { version: version.slug, slug: toSlugParams(slug) },
|
|
128
|
-
props: {
|
|
129
|
-
kind: "entry",
|
|
130
|
-
entry,
|
|
131
|
-
version,
|
|
132
|
-
// #1916 #1: breadcrumb crumbs remapped to the versioned URL space.
|
|
133
|
-
breadcrumbs: buildBreadcrumbs(tree, slug, "en", urlFor),
|
|
134
|
-
prev: rewriteNavHref(prevNode, urlFor),
|
|
135
|
-
next: rewriteNavHref(nextNode, urlFor),
|
|
136
|
-
headings: extractHeadings(entry.body ?? ""),
|
|
137
|
-
},
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// Auto-generated index pages for categories without index.mdx
|
|
142
|
-
for (const node of collectAutoIndexNodes(tree)) {
|
|
93
|
+
for (const item of buildDocRouteEntries({
|
|
94
|
+
source,
|
|
95
|
+
locale: "en",
|
|
96
|
+
routeSig: `v-docs;${version.slug}`,
|
|
97
|
+
urlFor,
|
|
98
|
+
})) {
|
|
143
99
|
result.push({
|
|
144
|
-
params: { version: version.slug, slug:
|
|
145
|
-
props:
|
|
146
|
-
kind
|
|
147
|
-
|
|
148
|
-
...
|
|
149
|
-
// #1916 #2: child-card hrefs ALWAYS resolve to the versioned URL.
|
|
150
|
-
children: remapNavChildHrefs(node.children, urlFor) as NavNode[],
|
|
151
|
-
} as AutoIndexNode,
|
|
152
|
-
version,
|
|
153
|
-
// #1916 #1: breadcrumb crumbs remapped to the versioned URL space.
|
|
154
|
-
breadcrumbs: buildBreadcrumbs(tree, node.slug, "en", urlFor),
|
|
155
|
-
prev: null,
|
|
156
|
-
next: null,
|
|
157
|
-
headings: [],
|
|
158
|
-
},
|
|
100
|
+
params: { version: version.slug, slug: item.slugParams },
|
|
101
|
+
props:
|
|
102
|
+
item.props.kind === "entry"
|
|
103
|
+
? { ...item.props, version }
|
|
104
|
+
: { ...item.props, version },
|
|
159
105
|
});
|
|
160
106
|
}
|
|
161
107
|
}
|
|
@@ -170,96 +116,8 @@ export function paths(): Array<{
|
|
|
170
116
|
type PageArgs = DocPageProps & { params: { version: string; slug: string[] } };
|
|
171
117
|
|
|
172
118
|
export default function VersionedDocsPage(props: PageArgs): JSX.Element {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
? props.autoIndex.slug
|
|
178
|
-
: (props.entry.data.slug ?? toRouteSlug(props.entry.slug));
|
|
179
|
-
|
|
180
|
-
const title = props.kind === "autoIndex" ? props.autoIndex.label : props.entry.data.title;
|
|
181
|
-
const description = props.kind === "autoIndex" ? props.autoIndex.description : props.entry.data.description;
|
|
182
|
-
|
|
183
|
-
// Locale-aware components bag — creates nav wrappers bound to the active
|
|
184
|
-
// locale so CategoryNav/CategoryTreeNav/SiteTreeNav query the right collection.
|
|
185
|
-
const components = createMdxComponents(locale);
|
|
186
|
-
|
|
187
|
-
// #1916 #2: child cards already carry versioned hrefs from paths(); just
|
|
188
|
-
// filter to renderable nodes here.
|
|
189
|
-
const autoIndexChildren = props.kind === "autoIndex"
|
|
190
|
-
? props.autoIndex.children.filter((c: NavNode) => c.hasPage || c.children.length > 0)
|
|
191
|
-
: [];
|
|
192
|
-
|
|
193
|
-
// Version banner: drives the `<VersionBanner>` element inside
|
|
194
|
-
// DocLayoutWithDefaults when `version.banner` is "unmaintained" or
|
|
195
|
-
// "unreleased". The banner links out to the latest version of the
|
|
196
|
-
// current page (slug-preserving — strips the /v/{version}/ prefix).
|
|
197
|
-
const versionBannerType = version.banner ? version.banner : undefined;
|
|
198
|
-
const versionBannerLatestUrl = versionBannerType
|
|
199
|
-
? docsUrl(slug, locale)
|
|
200
|
-
: undefined;
|
|
201
|
-
const versionBannerLabels = versionBannerType
|
|
202
|
-
? {
|
|
203
|
-
message:
|
|
204
|
-
versionBannerType === "unmaintained"
|
|
205
|
-
? t("version.banner.unmaintained", locale)
|
|
206
|
-
: t("version.banner.unreleased", locale),
|
|
207
|
-
latestLink: t("version.banner.latestLink", locale),
|
|
208
|
-
}
|
|
209
|
-
: undefined;
|
|
210
|
-
|
|
211
|
-
// Canonical URL — versioned pages use the versioned URL as canonical.
|
|
212
|
-
const currentPath = versionedDocsUrl(slug, version.slug, locale);
|
|
213
|
-
const canonical = absoluteUrl(currentPath);
|
|
214
|
-
|
|
215
|
-
// Persist key: locale + nav-section so the sidebar DOM node is reused
|
|
216
|
-
// across same-locale + same-section navigations only. No sanitizer needed —
|
|
217
|
-
// both lang (BCP-47 locale string) and navSection (filesystem-derived
|
|
218
|
-
// kebab-case slug) come from controlled, trusted sources.
|
|
219
|
-
const navSection = getNavSectionForSlug(slug);
|
|
220
|
-
const hideSidebar = props.kind === "entry" ? props.entry.data.hide_sidebar : undefined;
|
|
221
|
-
const sidebarPersistKey = hideSidebar
|
|
222
|
-
? undefined
|
|
223
|
-
: `sidebar-${locale}-${navSection ?? "default"}`;
|
|
224
|
-
|
|
225
|
-
return (
|
|
226
|
-
<DocPageShell
|
|
227
|
-
kind={props.kind}
|
|
228
|
-
locale={locale}
|
|
229
|
-
slug={slug}
|
|
230
|
-
title={title}
|
|
231
|
-
description={description}
|
|
232
|
-
canonical={canonical}
|
|
233
|
-
breadcrumbs={breadcrumbs}
|
|
234
|
-
prev={prev}
|
|
235
|
-
next={next}
|
|
236
|
-
headings={headings}
|
|
237
|
-
navSection={navSection}
|
|
238
|
-
sidebarPersistKey={sidebarPersistKey}
|
|
239
|
-
hideSidebar={hideSidebar}
|
|
240
|
-
hideToc={props.kind === "entry" ? props.entry.data.hide_toc : undefined}
|
|
241
|
-
currentPath={currentPath}
|
|
242
|
-
currentVersion={version.slug}
|
|
243
|
-
versionSwitcher={buildInlineVersionSwitcher(slug, locale, version.slug)}
|
|
244
|
-
versionBanner={versionBannerType}
|
|
245
|
-
versionBannerLatestUrl={versionBannerLatestUrl}
|
|
246
|
-
versionBannerLabels={versionBannerLabels}
|
|
247
|
-
autoIndexLabel={props.kind === "autoIndex" ? props.autoIndex.label : undefined}
|
|
248
|
-
autoIndexChildren={autoIndexChildren}
|
|
249
|
-
metainfoSlot={
|
|
250
|
-
props.kind === "autoIndex" ? <DocMetainfoArea slug={slug} locale={locale} /> : null
|
|
251
|
-
}
|
|
252
|
-
contentHeaderSlot={
|
|
253
|
-
props.kind === "entry" ? (
|
|
254
|
-
<DocContentHeader entry={props.entry} slug={slug} locale={locale} />
|
|
255
|
-
) : undefined
|
|
256
|
-
}
|
|
257
|
-
contentSlot={
|
|
258
|
-
props.kind === "entry" ? <props.entry.Content components={components} /> : undefined
|
|
259
|
-
}
|
|
260
|
-
// #1916 #5: doc-history hidden on versioned pages until versioned
|
|
261
|
-
// history is supported.
|
|
262
|
-
docHistorySlot={null}
|
|
263
|
-
/>
|
|
264
|
-
);
|
|
119
|
+
return renderDocPage(props, {
|
|
120
|
+
locale: "en",
|
|
121
|
+
version: props.version,
|
|
122
|
+
});
|
|
265
123
|
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type { CSSProperties } from 'react';
|
|
2
|
-
|
|
3
|
-
type Props = React.ComponentPropsWithoutRef<'h3'>;
|
|
4
|
-
|
|
5
|
-
export function HeadingH3({ id, children, className, ...rest }: Props) {
|
|
6
|
-
return (
|
|
7
|
-
<h3
|
|
8
|
-
id={id}
|
|
9
|
-
className={`text-body font-bold leading-snug pt-vsp-xs border-t-[2px] border-transparent${className ? ` ${className}` : ''}`}
|
|
10
|
-
style={
|
|
11
|
-
{
|
|
12
|
-
borderImage: 'linear-gradient(to right, var(--color-muted), transparent) 1',
|
|
13
|
-
} as CSSProperties
|
|
14
|
-
}
|
|
15
|
-
{...rest}
|
|
16
|
-
>
|
|
17
|
-
{children}
|
|
18
|
-
</h3>
|
|
19
|
-
);
|
|
20
|
-
}
|