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,451 @@
|
|
|
1
|
+
/** @jsxRuntime automatic */
|
|
2
|
+
/** @jsxImportSource preact */
|
|
3
|
+
// Port of src/pages/v/[version]/docs/[...slug].astro → zfb page module.
|
|
4
|
+
//
|
|
5
|
+
// Versioned EN docs route. paths() enumerates one route per (version, slug)
|
|
6
|
+
// combination using the `docs-v-${version.slug}` collection for each version
|
|
7
|
+
// configured in settings.versions.
|
|
8
|
+
//
|
|
9
|
+
// paths() contract (zfb ADR-004 — synchronous):
|
|
10
|
+
// params: { version: string; slug: string[] }
|
|
11
|
+
// props: { entry, autoIndex, version, breadcrumbs, prev, next }
|
|
12
|
+
//
|
|
13
|
+
// Each version renders with its own nav tree (from the version's docsDir
|
|
14
|
+
// category metadata). Prev/next hrefs are pre-resolved to the versioned URL
|
|
15
|
+
// form (e.g. /v/1.0/docs/…) so the component needs no URL computation.
|
|
16
|
+
//
|
|
17
|
+
// Version banner: if version.banner is set ("unmaintained" | "unreleased"),
|
|
18
|
+
// the DocLayoutWithDefaults version-banner prop drives the banner display.
|
|
19
|
+
|
|
20
|
+
import { getCollection } from "zfb/content";
|
|
21
|
+
import type { CollectionEntry } from "zfb/content";
|
|
22
|
+
import type { DocsEntry } from "@/types/docs-entry";
|
|
23
|
+
import { settings } from "@/config/settings";
|
|
24
|
+
import type { VersionConfig } from "@/config/settings";
|
|
25
|
+
import { t } from "@/config/i18n";
|
|
26
|
+
import { docsUrl, versionedDocsUrl } from "@/utils/base";
|
|
27
|
+
import {
|
|
28
|
+
buildNavTree,
|
|
29
|
+
buildBreadcrumbs,
|
|
30
|
+
flattenTree,
|
|
31
|
+
findNode,
|
|
32
|
+
loadCategoryMeta,
|
|
33
|
+
collectAutoIndexNodes,
|
|
34
|
+
isNavVisible,
|
|
35
|
+
type NavNode,
|
|
36
|
+
type BreadcrumbItem,
|
|
37
|
+
} from "@/utils/docs";
|
|
38
|
+
import { getNavSectionForSlug, getNavSubtree } from "@/utils/nav-scope";
|
|
39
|
+
import { toRouteSlug } from "@/utils/slug";
|
|
40
|
+
import { DocLayoutWithDefaults } from "@takazudo/zudo-doc/doclayout";
|
|
41
|
+
import { Breadcrumb } from "@takazudo/zudo-doc/breadcrumb";
|
|
42
|
+
import { NavCardGrid } from "@takazudo/zudo-doc/nav-indexing";
|
|
43
|
+
import { FrontmatterPreview } from "@takazudo/zudo-doc/metainfo";
|
|
44
|
+
import { frontmatterRenderers } from "@/config/frontmatter-preview-renderers";
|
|
45
|
+
// Locale-aware MDX components factory — see `pages/_mdx-components.ts`.
|
|
46
|
+
import { createMdxComponents } from "../../../_mdx-components";
|
|
47
|
+
import type { JSX } from "preact";
|
|
48
|
+
import { bridgeEntries } from "../../../_data";
|
|
49
|
+
import { extractHeadings } from "../../../lib/_extract-headings";
|
|
50
|
+
import { FooterWithDefaults } from "../../../lib/_footer-with-defaults";
|
|
51
|
+
import { SidebarWithDefaults } from "../../../lib/_sidebar-with-defaults";
|
|
52
|
+
import { HeaderWithDefaults } from "../../../lib/_header-with-defaults";
|
|
53
|
+
import { HeadWithDefaults } from "../../../lib/_head-with-defaults";
|
|
54
|
+
import { DocHistoryArea } from "../../../lib/_doc-history-area";
|
|
55
|
+
import { DocMetainfoArea } from "../../../lib/_doc-metainfo-area";
|
|
56
|
+
import { DocTagsArea } from "../../../lib/_doc-tags-area";
|
|
57
|
+
import { BodyEndIslands } from "../../../lib/_body-end-islands";
|
|
58
|
+
import { buildFrontmatterPreviewEntries } from "../../../lib/_frontmatter-preview-data";
|
|
59
|
+
import { composeMetaTitle } from "../../../lib/_compose-meta-title";
|
|
60
|
+
import { buildInlineVersionSwitcher } from "../../../lib/_inline-version-switcher";
|
|
61
|
+
import DesktopSidebarToggle from "@/components/desktop-sidebar-toggle";
|
|
62
|
+
import { SidebarResizerInit } from "@takazudo/zudo-doc/sidebar-resizer";
|
|
63
|
+
import type { VNode } from "preact";
|
|
64
|
+
import { Island } from "@takazudo/zfb";
|
|
65
|
+
|
|
66
|
+
export const frontmatter = { title: "Docs" };
|
|
67
|
+
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
// Types
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
|
|
72
|
+
interface DocPageEntry extends DocsEntry {
|
|
73
|
+
Content: CollectionEntry<unknown>["Content"];
|
|
74
|
+
module_specifier: string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
interface AutoIndexNode extends NavNode {
|
|
78
|
+
children: NavNode[];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
interface DocPageProps {
|
|
82
|
+
entry: DocPageEntry | null;
|
|
83
|
+
autoIndex?: AutoIndexNode;
|
|
84
|
+
/** The version config for the active version. */
|
|
85
|
+
version: VersionConfig;
|
|
86
|
+
breadcrumbs: BreadcrumbItem[];
|
|
87
|
+
prev: NavNode | null;
|
|
88
|
+
next: NavNode | null;
|
|
89
|
+
/** Depth-2/3/4 headings extracted from the MDX body, for SSG TOC links. */
|
|
90
|
+
headings: ReturnType<typeof extractHeadings>;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
// paths() — synchronous (ADR-004)
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Emit one route per (version, slug) combination.
|
|
99
|
+
*
|
|
100
|
+
* For each version in settings.versions, loads docs from
|
|
101
|
+
* `docs-v-${version.slug}` and enumerates all pages plus
|
|
102
|
+
* auto-generated category index pages.
|
|
103
|
+
*
|
|
104
|
+
* Prev/next hrefs are pre-resolved to the versioned form.
|
|
105
|
+
*/
|
|
106
|
+
export function paths(): Array<{
|
|
107
|
+
params: { version: string; slug: string[] };
|
|
108
|
+
props: DocPageProps;
|
|
109
|
+
}> {
|
|
110
|
+
if (!settings.versions) return [];
|
|
111
|
+
|
|
112
|
+
const result: Array<{
|
|
113
|
+
params: { version: string; slug: string[] };
|
|
114
|
+
props: DocPageProps;
|
|
115
|
+
}> = [];
|
|
116
|
+
|
|
117
|
+
for (const version of settings.versions) {
|
|
118
|
+
const collectionName = `docs-v-${version.slug}`;
|
|
119
|
+
const allDocs = ((bridgeEntries(getCollection(collectionName), collectionName) as unknown as DocPageEntry[])).filter(
|
|
120
|
+
(doc) => !doc.data.draft,
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
const categoryMeta = loadCategoryMeta(version.docsDir);
|
|
124
|
+
const navDocs = allDocs.filter(isNavVisible);
|
|
125
|
+
// Versioned docs always use EN locale for nav tree
|
|
126
|
+
const tree = buildNavTree(navDocs as unknown as DocsEntry[], "en", categoryMeta);
|
|
127
|
+
|
|
128
|
+
// Regular doc pages
|
|
129
|
+
for (const entry of allDocs) {
|
|
130
|
+
const slug = entry.data.slug ?? toRouteSlug(entry.slug);
|
|
131
|
+
const navSection = getNavSectionForSlug(slug);
|
|
132
|
+
const subtree = getNavSubtree(tree, navSection);
|
|
133
|
+
const flat = flattenTree(subtree);
|
|
134
|
+
const idx = flat.findIndex((n) => n.slug === slug);
|
|
135
|
+
|
|
136
|
+
let prevNode = idx > 0 ? flat[idx - 1] ?? null : null;
|
|
137
|
+
let nextNode = idx >= 0 && idx < flat.length - 1 ? flat[idx + 1] ?? null : null;
|
|
138
|
+
|
|
139
|
+
if (entry.data.pagination_prev !== undefined) {
|
|
140
|
+
if (entry.data.pagination_prev === null) {
|
|
141
|
+
prevNode = null;
|
|
142
|
+
} else {
|
|
143
|
+
const found = findNode(tree, entry.data.pagination_prev);
|
|
144
|
+
prevNode = found ?? prevNode;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (entry.data.pagination_next !== undefined) {
|
|
148
|
+
if (entry.data.pagination_next === null) {
|
|
149
|
+
nextNode = null;
|
|
150
|
+
} else {
|
|
151
|
+
const found = findNode(tree, entry.data.pagination_next);
|
|
152
|
+
nextNode = found ?? nextNode;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
result.push({
|
|
157
|
+
params: { version: version.slug, slug: slug.split("/") },
|
|
158
|
+
props: {
|
|
159
|
+
entry,
|
|
160
|
+
version,
|
|
161
|
+
breadcrumbs: buildBreadcrumbs(tree, slug, "en"),
|
|
162
|
+
// Pre-resolve prev/next hrefs to versioned URLs
|
|
163
|
+
prev: prevNode
|
|
164
|
+
? { ...prevNode, href: versionedDocsUrl(prevNode.slug, version.slug) }
|
|
165
|
+
: null,
|
|
166
|
+
next: nextNode
|
|
167
|
+
? { ...nextNode, href: versionedDocsUrl(nextNode.slug, version.slug) }
|
|
168
|
+
: null,
|
|
169
|
+
headings: extractHeadings(entry.body ?? ""),
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Auto-generated index pages for categories without index.mdx
|
|
175
|
+
for (const node of collectAutoIndexNodes(tree)) {
|
|
176
|
+
result.push({
|
|
177
|
+
params: { version: version.slug, slug: node.slug.split("/") },
|
|
178
|
+
props: {
|
|
179
|
+
entry: null,
|
|
180
|
+
autoIndex: {
|
|
181
|
+
...node,
|
|
182
|
+
children: node.children.map((c: NavNode) => ({
|
|
183
|
+
...c,
|
|
184
|
+
href: c.href ?? versionedDocsUrl(c.slug, version.slug),
|
|
185
|
+
})) as NavNode[],
|
|
186
|
+
} as AutoIndexNode,
|
|
187
|
+
version,
|
|
188
|
+
breadcrumbs: buildBreadcrumbs(tree, node.slug, "en"),
|
|
189
|
+
prev: null,
|
|
190
|
+
next: null,
|
|
191
|
+
headings: [],
|
|
192
|
+
},
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return result;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// ---------------------------------------------------------------------------
|
|
201
|
+
// Page component
|
|
202
|
+
// ---------------------------------------------------------------------------
|
|
203
|
+
|
|
204
|
+
interface PageArgs {
|
|
205
|
+
params: { version: string; slug: string[] };
|
|
206
|
+
entry: DocPageProps["entry"];
|
|
207
|
+
autoIndex?: DocPageProps["autoIndex"];
|
|
208
|
+
version: DocPageProps["version"];
|
|
209
|
+
breadcrumbs: DocPageProps["breadcrumbs"];
|
|
210
|
+
prev: DocPageProps["prev"];
|
|
211
|
+
next: DocPageProps["next"];
|
|
212
|
+
headings: DocPageProps["headings"];
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export default function VersionedDocsPage({ entry, autoIndex, version, breadcrumbs, prev, next, headings }: PageArgs): JSX.Element {
|
|
216
|
+
const locale = "en";
|
|
217
|
+
|
|
218
|
+
const slug = autoIndex
|
|
219
|
+
? autoIndex.slug
|
|
220
|
+
: (entry!.data.slug ?? toRouteSlug(entry!.slug));
|
|
221
|
+
|
|
222
|
+
const title = autoIndex ? autoIndex.label : entry!.data.title;
|
|
223
|
+
const description = autoIndex ? autoIndex.description : entry!.data.description;
|
|
224
|
+
|
|
225
|
+
// Locale-aware components bag — creates nav wrappers bound to the active
|
|
226
|
+
// locale so CategoryNav/CategoryTreeNav/SiteTreeNav query the right collection.
|
|
227
|
+
const components = createMdxComponents(locale);
|
|
228
|
+
|
|
229
|
+
const autoIndexChildren = autoIndex
|
|
230
|
+
? autoIndex.children.filter((c: NavNode) => c.hasPage || c.children.length > 0)
|
|
231
|
+
: [];
|
|
232
|
+
|
|
233
|
+
// Version banner: drives the `<VersionBanner>` element inside
|
|
234
|
+
// DocLayoutWithDefaults when `version.banner` is "unmaintained" or
|
|
235
|
+
// "unreleased". The banner links out to the latest version of the
|
|
236
|
+
// current page (slug-preserving — strips the /v/{version}/ prefix).
|
|
237
|
+
const versionBannerType = version.banner ? version.banner : undefined;
|
|
238
|
+
const versionBannerLatestUrl = versionBannerType
|
|
239
|
+
? docsUrl(slug, locale)
|
|
240
|
+
: undefined;
|
|
241
|
+
const versionBannerLabels = versionBannerType
|
|
242
|
+
? {
|
|
243
|
+
message:
|
|
244
|
+
versionBannerType === "unmaintained"
|
|
245
|
+
? t("version.banner.unmaintained", locale)
|
|
246
|
+
: t("version.banner.unreleased", locale),
|
|
247
|
+
latestLink: t("version.banner.latestLink", locale),
|
|
248
|
+
}
|
|
249
|
+
: undefined;
|
|
250
|
+
|
|
251
|
+
// Canonical URL — versioned pages use the versioned URL as canonical.
|
|
252
|
+
const pageUrl = versionedDocsUrl(slug, version.slug, locale);
|
|
253
|
+
const canonical = settings.siteUrl
|
|
254
|
+
? settings.siteUrl.replace(/\/$/, "") + pageUrl
|
|
255
|
+
: undefined;
|
|
256
|
+
|
|
257
|
+
// Persist key: locale + nav-section so the sidebar DOM node is reused
|
|
258
|
+
// across same-locale + same-section navigations only. No sanitizer needed —
|
|
259
|
+
// both lang (BCP-47 locale string) and navSection (filesystem-derived
|
|
260
|
+
// kebab-case slug) come from controlled, trusted sources.
|
|
261
|
+
const navSection = getNavSectionForSlug(slug);
|
|
262
|
+
const hideSidebar = entry?.data?.hide_sidebar;
|
|
263
|
+
const sidebarPersistKey = hideSidebar
|
|
264
|
+
? undefined
|
|
265
|
+
: `sidebar-${locale}-${navSection ?? "default"}`;
|
|
266
|
+
|
|
267
|
+
return (
|
|
268
|
+
<DocLayoutWithDefaults
|
|
269
|
+
title={composeMetaTitle(title)}
|
|
270
|
+
description={description}
|
|
271
|
+
head={<HeadWithDefaults title={title} description={description} canonical={canonical} />}
|
|
272
|
+
lang={locale}
|
|
273
|
+
noindex={settings.noindex}
|
|
274
|
+
hideSidebar={hideSidebar}
|
|
275
|
+
hideToc={entry?.data?.hide_toc}
|
|
276
|
+
headings={headings}
|
|
277
|
+
canonical={canonical}
|
|
278
|
+
sidebarPersistKey={sidebarPersistKey}
|
|
279
|
+
versionBanner={versionBannerType ?? false}
|
|
280
|
+
versionBannerLatestUrl={versionBannerLatestUrl}
|
|
281
|
+
versionBannerLabels={versionBannerLabels}
|
|
282
|
+
headerOverride={
|
|
283
|
+
<HeaderWithDefaults
|
|
284
|
+
lang={locale}
|
|
285
|
+
currentSlug={slug}
|
|
286
|
+
navSection={getNavSectionForSlug(slug)}
|
|
287
|
+
currentVersion={version.slug}
|
|
288
|
+
currentPath={versionedDocsUrl(slug, version.slug, locale)}
|
|
289
|
+
/>
|
|
290
|
+
}
|
|
291
|
+
breadcrumbOverride={
|
|
292
|
+
breadcrumbs.length > 0 ? (
|
|
293
|
+
<Breadcrumb
|
|
294
|
+
items={breadcrumbs}
|
|
295
|
+
rightSlot={buildInlineVersionSwitcher(slug, locale, version.slug)}
|
|
296
|
+
/>
|
|
297
|
+
) : undefined
|
|
298
|
+
}
|
|
299
|
+
sidebarOverride={
|
|
300
|
+
<SidebarWithDefaults
|
|
301
|
+
currentSlug={slug}
|
|
302
|
+
lang={locale}
|
|
303
|
+
navSection={getNavSectionForSlug(slug)}
|
|
304
|
+
currentVersion={version.slug}
|
|
305
|
+
currentPath={versionedDocsUrl(slug, version.slug, locale)}
|
|
306
|
+
/>
|
|
307
|
+
}
|
|
308
|
+
afterSidebar={
|
|
309
|
+
settings.sidebarToggle ? (
|
|
310
|
+
<>
|
|
311
|
+
<script dangerouslySetInnerHTML={{
|
|
312
|
+
__html: `(function(){try{if(localStorage.getItem('zudo-doc-sidebar-visible')==='false'){document.documentElement.setAttribute('data-sidebar-hidden','');}}catch(e){}})();`,
|
|
313
|
+
}} />
|
|
314
|
+
{Island({
|
|
315
|
+
when: "load",
|
|
316
|
+
children: <DesktopSidebarToggle />,
|
|
317
|
+
}) as unknown as VNode}
|
|
318
|
+
</>
|
|
319
|
+
) : undefined
|
|
320
|
+
}
|
|
321
|
+
footerOverride={<FooterWithDefaults lang={locale} />}
|
|
322
|
+
bodyEndComponents={
|
|
323
|
+
<>
|
|
324
|
+
<BodyEndIslands basePath={settings.base ?? "/"} />
|
|
325
|
+
{settings.sidebarResizer && <SidebarResizerInit />}
|
|
326
|
+
</>
|
|
327
|
+
}
|
|
328
|
+
>
|
|
329
|
+
{autoIndex ? (
|
|
330
|
+
/* Auto-index page: category without an index.mdx.
|
|
331
|
+
Fragment (not <div>) so children become direct children of
|
|
332
|
+
<article class="zd-content">, picking up the flow-space rule
|
|
333
|
+
(.zd-content > :where(* + *) { margin-top: var(--flow-space) }).
|
|
334
|
+
Wrapping in <div> would make h1/description p children-of-children
|
|
335
|
+
and the flow gap (~24px) would never apply — see #1460. */
|
|
336
|
+
<>
|
|
337
|
+
<h1 class="text-heading font-bold mb-vsp-xs">{autoIndex.label}</h1>
|
|
338
|
+
|
|
339
|
+
{/* Build-time date block — chrome parity (#1461). Auto-index pages
|
|
340
|
+
previously rendered without doc-meta; reference site shows it on
|
|
341
|
+
every docs page. The component returns null when no manifest
|
|
342
|
+
entry exists for this slug. */}
|
|
343
|
+
<DocMetainfoArea slug={slug} locale={locale} />
|
|
344
|
+
|
|
345
|
+
{autoIndex.description && (
|
|
346
|
+
<p class="mb-vsp-lg text-title text-muted">
|
|
347
|
+
{autoIndex.description}
|
|
348
|
+
</p>
|
|
349
|
+
)}
|
|
350
|
+
<NavCardGrid children={autoIndexChildren} />
|
|
351
|
+
</>
|
|
352
|
+
) : (
|
|
353
|
+
/* Regular doc page. Fragment (not <div>) for the same reason as
|
|
354
|
+
the auto-index branch above — see #1460. */
|
|
355
|
+
<>
|
|
356
|
+
<h1 class="text-heading font-bold mb-vsp-xs">{entry!.data.title}</h1>
|
|
357
|
+
|
|
358
|
+
{/* Build-time date block (Created / Updated / Author). Mirrors the
|
|
359
|
+
Astro `doc-metainfo.astro` placement — between <h1> and description.
|
|
360
|
+
Data from `.zfb/doc-history-meta.json` (esbuild-inlined, no fs). */}
|
|
361
|
+
<DocMetainfoArea slug={slug} locale={locale} />
|
|
362
|
+
|
|
363
|
+
{/* Page-level tag chips — mirroring doc-tags.astro placement (#1658). */}
|
|
364
|
+
<DocTagsArea slug={slug} locale={locale} tags={entry!.data.tags} />
|
|
365
|
+
|
|
366
|
+
{entry!.data.description && (
|
|
367
|
+
<p class="mb-vsp-lg text-title text-muted">
|
|
368
|
+
{entry!.data.description}
|
|
369
|
+
</p>
|
|
370
|
+
)}
|
|
371
|
+
|
|
372
|
+
{/* Frontmatter preview — non-system, custom keys only. Returns
|
|
373
|
+
null when the entries array is empty, so pages without
|
|
374
|
+
custom frontmatter emit nothing. */}
|
|
375
|
+
<FrontmatterPreview
|
|
376
|
+
entries={buildFrontmatterPreviewEntries(entry!.data)}
|
|
377
|
+
title={t("frontmatter.preview.title", locale)}
|
|
378
|
+
keyColLabel={t("frontmatter.preview.keyCol", locale)}
|
|
379
|
+
valueColLabel={t("frontmatter.preview.valueCol", locale)}
|
|
380
|
+
renderers={frontmatterRenderers}
|
|
381
|
+
data={entry!.data as Record<string, unknown>}
|
|
382
|
+
locale={locale}
|
|
383
|
+
/>
|
|
384
|
+
|
|
385
|
+
{entry && <entry.Content components={components} />}
|
|
386
|
+
|
|
387
|
+
{/* Prev / Next pagination — placed before the document utilities
|
|
388
|
+
section to match the Astro reference order: content → pager →
|
|
389
|
+
view-source / history. Fixes #1535. */}
|
|
390
|
+
<nav class="mt-vsp-2xl grid grid-cols-2 gap-hsp-xl">
|
|
391
|
+
{prev ? (
|
|
392
|
+
<a
|
|
393
|
+
href={prev.href}
|
|
394
|
+
class="group border border-muted rounded-lg p-hsp-lg hover:border-accent"
|
|
395
|
+
>
|
|
396
|
+
<div class="flex items-center gap-hsp-xs text-caption text-muted mb-vsp-2xs">
|
|
397
|
+
<svg
|
|
398
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
399
|
+
class="h-[1.125rem] w-[1.125rem]"
|
|
400
|
+
fill="none"
|
|
401
|
+
viewBox="0 0 24 24"
|
|
402
|
+
stroke="currentColor"
|
|
403
|
+
stroke-width="2"
|
|
404
|
+
>
|
|
405
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M15 19l-7-7 7-7" />
|
|
406
|
+
</svg>
|
|
407
|
+
<span class="no-underline">{t("nav.previous", locale)}</span>
|
|
408
|
+
</div>
|
|
409
|
+
<p class="text-small font-semibold underline group-hover:text-accent">
|
|
410
|
+
{prev.label}
|
|
411
|
+
</p>
|
|
412
|
+
</a>
|
|
413
|
+
) : (
|
|
414
|
+
<div />
|
|
415
|
+
)}
|
|
416
|
+
{next ? (
|
|
417
|
+
<a
|
|
418
|
+
href={next.href}
|
|
419
|
+
class="group border border-muted rounded-lg p-hsp-lg hover:border-accent text-right"
|
|
420
|
+
>
|
|
421
|
+
<div class="flex items-center justify-end gap-hsp-xs text-caption text-muted mb-vsp-2xs">
|
|
422
|
+
<span class="no-underline">{t("nav.next", locale)}</span>
|
|
423
|
+
<svg
|
|
424
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
425
|
+
class="h-[1.125rem] w-[1.125rem]"
|
|
426
|
+
fill="none"
|
|
427
|
+
viewBox="0 0 24 24"
|
|
428
|
+
stroke="currentColor"
|
|
429
|
+
stroke-width="2"
|
|
430
|
+
>
|
|
431
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7" />
|
|
432
|
+
</svg>
|
|
433
|
+
</div>
|
|
434
|
+
<p class="text-small font-semibold underline group-hover:text-accent">
|
|
435
|
+
{next.label}
|
|
436
|
+
</p>
|
|
437
|
+
</a>
|
|
438
|
+
) : (
|
|
439
|
+
<div />
|
|
440
|
+
)}
|
|
441
|
+
</nav>
|
|
442
|
+
|
|
443
|
+
{/* Document utilities (revision history) — gated on entry, matching regular slug page pattern */}
|
|
444
|
+
{entry && (
|
|
445
|
+
<DocHistoryArea slug={slug} locale={locale} />
|
|
446
|
+
)}
|
|
447
|
+
</>
|
|
448
|
+
)}
|
|
449
|
+
</DocLayoutWithDefaults>
|
|
450
|
+
);
|
|
451
|
+
}
|