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
|
@@ -11,29 +11,14 @@
|
|
|
11
11
|
// params: { locale: string; tag: string }
|
|
12
12
|
// props: { tagInfo: TagInfo }
|
|
13
13
|
//
|
|
14
|
+
// Tag collection + rendering are shared with the default-locale route via
|
|
15
|
+
// pages/lib/_tag-pages.tsx (#2010) — this file owns only the param shape.
|
|
14
16
|
// Fallback strategy: see pages/lib/locale-merge.ts for full details.
|
|
15
|
-
// Locale docs take priority; base docs fill in missing slugs.
|
|
16
|
-
// Build tag map; emit one route per (locale, tag) pair.
|
|
17
17
|
|
|
18
|
-
import { mergeLocaleDocs } from "../../../lib/locale-merge";
|
|
19
|
-
import { loadDocs } from "../../../_data";
|
|
20
|
-
import { collectTags } from "@/utils/tags";
|
|
21
|
-
import type { TagInfo } from "@/utils/tags";
|
|
22
|
-
import { toRouteSlug } from "@/utils/slug";
|
|
23
|
-
import { t } from "@/config/i18n";
|
|
24
|
-
import { withBase, docsUrl } from "@/utils/base";
|
|
25
18
|
import { settings } from "@/config/settings";
|
|
26
|
-
import {
|
|
27
|
-
import { Breadcrumb } from "@takazudo/zudo-doc/breadcrumb";
|
|
28
|
-
import type { BreadcrumbItem } from "@takazudo/zudo-doc/breadcrumb";
|
|
29
|
-
import { DocCardGrid } from "@takazudo/zudo-doc/nav-indexing";
|
|
19
|
+
import type { TagInfo } from "@/utils/tags";
|
|
30
20
|
import type { JSX } from "preact";
|
|
31
|
-
import {
|
|
32
|
-
import { HeaderWithDefaults } from "../../../lib/_header-with-defaults";
|
|
33
|
-
import { HeadWithDefaults } from "../../../lib/_head-with-defaults";
|
|
34
|
-
import { composeMetaTitle } from "../../../lib/_compose-meta-title";
|
|
35
|
-
import { DocHistoryArea } from "../../../lib/_doc-history-area";
|
|
36
|
-
import { BodyEndIslands } from "../../../lib/_body-end-islands";
|
|
21
|
+
import { collectTagMapForLocale, TagDetailPageView } from "../../../lib/_tag-pages";
|
|
37
22
|
|
|
38
23
|
export const frontmatter = { title: "Tag" };
|
|
39
24
|
|
|
@@ -48,18 +33,7 @@ export function paths(): Array<{
|
|
|
48
33
|
}> = [];
|
|
49
34
|
|
|
50
35
|
for (const locale of Object.keys(settings.locales)) {
|
|
51
|
-
const
|
|
52
|
-
baseDocs: loadDocs("docs").filter((d) => !d.data.draft),
|
|
53
|
-
localeDocs: loadDocs(`docs-${locale}`).filter((d) => !d.data.draft),
|
|
54
|
-
applyDefaultLocaleOnlyFilter: true,
|
|
55
|
-
});
|
|
56
|
-
// category_no_page index files build no route — drop them AFTER the merge
|
|
57
|
-
// so a locale override carrying the flag first wins the merge (suppressing
|
|
58
|
-
// the base doc); pre-merge filtering would drop it from localeSlugSet and
|
|
59
|
-
// the unflagged base doc would resurface as a card linking to a locale
|
|
60
|
-
// route the docs route never builds.
|
|
61
|
-
const docs = mergedDocs.filter((d) => !d.data.category_no_page);
|
|
62
|
-
const tagMap = collectTags(docs, (id, data) => data.slug ?? toRouteSlug(id));
|
|
36
|
+
const tagMap = collectTagMapForLocale(locale);
|
|
63
37
|
|
|
64
38
|
for (const [tag, tagInfo] of tagMap.entries()) {
|
|
65
39
|
result.push({
|
|
@@ -81,47 +55,5 @@ export default function LocaleDocTagPage({
|
|
|
81
55
|
params,
|
|
82
56
|
tagInfo,
|
|
83
57
|
}: PageProps): JSX.Element {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const countText =
|
|
87
|
-
tagInfo.count === 1
|
|
88
|
-
? t("doc.pageCountSingle", locale).replace("{count}", String(tagInfo.count))
|
|
89
|
-
: t("doc.pageCount", locale).replace("{count}", String(tagInfo.count));
|
|
90
|
-
|
|
91
|
-
const pageTitle = `${t("doc.taggedWith", locale)}: ${tag}`;
|
|
92
|
-
|
|
93
|
-
const breadcrumbItems: BreadcrumbItem[] = [
|
|
94
|
-
{ label: "Docs" },
|
|
95
|
-
{
|
|
96
|
-
label: t("doc.allTags", locale),
|
|
97
|
-
href: withBase(`/${locale}/docs/tags`),
|
|
98
|
-
},
|
|
99
|
-
{ label: tag },
|
|
100
|
-
];
|
|
101
|
-
|
|
102
|
-
const cardItems = tagInfo.docs.map((doc) => ({
|
|
103
|
-
href: docsUrl(doc.slug, locale),
|
|
104
|
-
title: doc.title,
|
|
105
|
-
description: doc.description,
|
|
106
|
-
}));
|
|
107
|
-
|
|
108
|
-
return (
|
|
109
|
-
<DocLayoutWithDefaults
|
|
110
|
-
title={composeMetaTitle(pageTitle)}
|
|
111
|
-
head={<HeadWithDefaults title={pageTitle} />}
|
|
112
|
-
lang={locale}
|
|
113
|
-
noindex={settings.noindex}
|
|
114
|
-
hideSidebar={true}
|
|
115
|
-
hideToc={true}
|
|
116
|
-
headerOverride={<HeaderWithDefaults lang={locale} currentPath={withBase(`/${locale}/docs/tags/${tag}`)} />}
|
|
117
|
-
breadcrumbOverride={<Breadcrumb items={breadcrumbItems} />}
|
|
118
|
-
footerOverride={<FooterWithDefaults lang={locale} />}
|
|
119
|
-
bodyEndComponents={<BodyEndIslands basePath={settings.base ?? "/"} />}
|
|
120
|
-
>
|
|
121
|
-
<h1 class="text-heading font-bold mb-vsp-xs">{pageTitle}</h1>
|
|
122
|
-
<p class="text-muted mb-vsp-lg">{countText}</p>
|
|
123
|
-
<DocCardGrid ariaLabel={pageTitle} items={cardItems} />
|
|
124
|
-
<DocHistoryArea slug={`tags/${tag}`} locale={locale} />
|
|
125
|
-
</DocLayoutWithDefaults>
|
|
126
|
-
);
|
|
58
|
+
return <TagDetailPageView locale={params.locale} tag={params.tag} tagInfo={tagInfo} />;
|
|
127
59
|
}
|
|
@@ -3,36 +3,21 @@
|
|
|
3
3
|
// Page module for the locale-prefixed "All Tags" index route.
|
|
4
4
|
//
|
|
5
5
|
// Non-default-locale "All Tags" index page. paths() emits one route per
|
|
6
|
-
// locale defined in settings.locales (
|
|
7
|
-
// handled by pages/docs/tags/index.tsx). The component recomputes the tag
|
|
6
|
+
// locale defined in settings.locales (the default locale has no prefix — it
|
|
7
|
+
// is handled by pages/docs/tags/index.tsx). The component recomputes the tag
|
|
8
8
|
// map at render time using a locale-doc + base-doc fallback strategy
|
|
9
9
|
// (see pages/lib/locale-merge.ts for the merge logic).
|
|
10
10
|
//
|
|
11
|
-
//
|
|
11
|
+
// Tag collection + rendering are shared with the default-locale route via
|
|
12
|
+
// pages/lib/_tag-pages.tsx (#2010).
|
|
12
13
|
//
|
|
13
14
|
// paths() contract (zfb ADR-004 — synchronous):
|
|
14
15
|
// params: { locale: string }
|
|
15
16
|
// props: (none — tag map computed at render time)
|
|
16
17
|
|
|
17
|
-
import { mergeLocaleDocs } from "../../../lib/locale-merge";
|
|
18
|
-
import { loadDocs } from "../../../_data";
|
|
19
|
-
import { collectTags } from "@/utils/tags";
|
|
20
|
-
import { toRouteSlug } from "@/utils/slug";
|
|
21
|
-
import { t } from "@/config/i18n";
|
|
22
|
-
import { withBase } from "@/utils/base";
|
|
23
18
|
import { settings } from "@/config/settings";
|
|
24
|
-
import { DocLayoutWithDefaults } from "@takazudo/zudo-doc/doclayout";
|
|
25
|
-
import { Breadcrumb } from "@takazudo/zudo-doc/breadcrumb";
|
|
26
|
-
import type { BreadcrumbItem } from "@takazudo/zudo-doc/breadcrumb";
|
|
27
|
-
import { TagNav } from "@takazudo/zudo-doc/nav-indexing";
|
|
28
|
-
import type { TagItem, TagNavLabels } from "@takazudo/zudo-doc/nav-indexing";
|
|
29
19
|
import type { JSX } from "preact";
|
|
30
|
-
import {
|
|
31
|
-
import { HeaderWithDefaults } from "../../../lib/_header-with-defaults";
|
|
32
|
-
import { HeadWithDefaults } from "../../../lib/_head-with-defaults";
|
|
33
|
-
import { composeMetaTitle } from "../../../lib/_compose-meta-title";
|
|
34
|
-
import { DocHistoryArea } from "../../../lib/_doc-history-area";
|
|
35
|
-
import { BodyEndIslands } from "../../../lib/_body-end-islands";
|
|
20
|
+
import { TagsIndexPageView } from "../../../lib/_tag-pages";
|
|
36
21
|
|
|
37
22
|
export const frontmatter = { title: "All Tags" };
|
|
38
23
|
|
|
@@ -50,61 +35,5 @@ interface PageProps {
|
|
|
50
35
|
export default function LocaleTagsIndexPage({
|
|
51
36
|
params,
|
|
52
37
|
}: PageProps): JSX.Element {
|
|
53
|
-
|
|
54
|
-
const pageTitle = t("doc.allTags", locale);
|
|
55
|
-
|
|
56
|
-
const { docs: mergedDocs } = mergeLocaleDocs({
|
|
57
|
-
baseDocs: loadDocs("docs").filter((d) => !d.data.draft),
|
|
58
|
-
localeDocs: loadDocs(`docs-${locale}`).filter((d) => !d.data.draft),
|
|
59
|
-
applyDefaultLocaleOnlyFilter: true,
|
|
60
|
-
});
|
|
61
|
-
// category_no_page index files build no route — drop them AFTER the merge
|
|
62
|
-
// so a locale override carrying the flag first wins the merge (suppressing
|
|
63
|
-
// the base doc); pre-merge filtering would drop it from localeSlugSet and
|
|
64
|
-
// the unflagged base doc would resurface as a card linking to a locale
|
|
65
|
-
// route the docs route never builds.
|
|
66
|
-
const docs = mergedDocs.filter((d) => !d.data.category_no_page);
|
|
67
|
-
const tagMap = collectTags(docs, (id, data) => data.slug ?? toRouteSlug(id));
|
|
68
|
-
|
|
69
|
-
const labels: TagNavLabels = {
|
|
70
|
-
tags: t("doc.tags", locale),
|
|
71
|
-
taggedWith: t("doc.taggedWith", locale),
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
// Sort alphabetically using the page locale — matches documented tag-nav sort order.
|
|
75
|
-
const tags: TagItem[] = [...tagMap.values()]
|
|
76
|
-
.sort((a, b) => a.tag.localeCompare(b.tag, locale))
|
|
77
|
-
.map((info) => ({
|
|
78
|
-
tag: info.tag,
|
|
79
|
-
count: info.count,
|
|
80
|
-
href: withBase(`/${locale}/docs/tags/${info.tag}`),
|
|
81
|
-
}));
|
|
82
|
-
|
|
83
|
-
const breadcrumbItems: BreadcrumbItem[] = [
|
|
84
|
-
{ label: "Docs" },
|
|
85
|
-
{ label: pageTitle },
|
|
86
|
-
];
|
|
87
|
-
|
|
88
|
-
return (
|
|
89
|
-
<DocLayoutWithDefaults
|
|
90
|
-
title={composeMetaTitle(pageTitle)}
|
|
91
|
-
head={<HeadWithDefaults title={pageTitle} />}
|
|
92
|
-
lang={locale}
|
|
93
|
-
noindex={settings.noindex}
|
|
94
|
-
hideSidebar={true}
|
|
95
|
-
hideToc={true}
|
|
96
|
-
headerOverride={<HeaderWithDefaults lang={locale} currentPath={withBase(`/${locale}/docs/tags`)} />}
|
|
97
|
-
breadcrumbOverride={<Breadcrumb items={breadcrumbItems} />}
|
|
98
|
-
footerOverride={<FooterWithDefaults lang={locale} />}
|
|
99
|
-
bodyEndComponents={<BodyEndIslands basePath={settings.base ?? "/"} />}
|
|
100
|
-
>
|
|
101
|
-
<h1 class="text-heading font-bold mb-vsp-lg">{pageTitle}</h1>
|
|
102
|
-
{!settings.docTags || tags.length === 0 ? (
|
|
103
|
-
<p class="text-muted">{t("doc.noTags", locale)}</p>
|
|
104
|
-
) : (
|
|
105
|
-
<TagNav variant="all" tags={tags} labels={labels} />
|
|
106
|
-
)}
|
|
107
|
-
<DocHistoryArea slug="tags" locale={locale} />
|
|
108
|
-
</DocLayoutWithDefaults>
|
|
109
|
-
);
|
|
38
|
+
return <TagsIndexPageView locale={params.locale} />;
|
|
110
39
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/** @jsxImportSource preact */
|
|
3
3
|
// Page module for the default-locale per-tag detail route.
|
|
4
4
|
//
|
|
5
|
-
// Default-locale
|
|
5
|
+
// Default-locale per-tag detail page. paths() enumerates one route per
|
|
6
6
|
// unique tag in the "docs" collection and passes the resolved TagInfo as a
|
|
7
7
|
// prop so the component has zero extra collection reads at render time.
|
|
8
8
|
//
|
|
@@ -10,29 +10,13 @@
|
|
|
10
10
|
// params: { tag: string }
|
|
11
11
|
// props: { tagInfo: TagInfo }
|
|
12
12
|
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
// render: DocCardGrid with pre-resolved TagInfo.docs items
|
|
13
|
+
// Tag collection + rendering are shared with the locale-prefixed route via
|
|
14
|
+
// pages/lib/_tag-pages.tsx (#2010) — this file owns only the param shape.
|
|
16
15
|
|
|
17
|
-
import {
|
|
18
|
-
import { collectTags } from "@/utils/tags";
|
|
16
|
+
import { defaultLocale } from "@/config/i18n";
|
|
19
17
|
import type { TagInfo } from "@/utils/tags";
|
|
20
|
-
import { toRouteSlug } from "@/utils/slug";
|
|
21
|
-
import { t, defaultLocale } from "@/config/i18n";
|
|
22
|
-
import { settings } from "@/config/settings";
|
|
23
|
-
import { withBase, docsUrl } from "@/utils/base";
|
|
24
|
-
import { DocLayoutWithDefaults } from "@takazudo/zudo-doc/doclayout";
|
|
25
|
-
import { Breadcrumb } from "@takazudo/zudo-doc/breadcrumb";
|
|
26
|
-
import type { BreadcrumbItem } from "@takazudo/zudo-doc/breadcrumb";
|
|
27
|
-
import { DocCardGrid } from "@takazudo/zudo-doc/nav-indexing";
|
|
28
18
|
import type { JSX } from "preact";
|
|
29
|
-
import {
|
|
30
|
-
import { FooterWithDefaults } from "../../lib/_footer-with-defaults";
|
|
31
|
-
import { HeaderWithDefaults } from "../../lib/_header-with-defaults";
|
|
32
|
-
import { HeadWithDefaults } from "../../lib/_head-with-defaults";
|
|
33
|
-
import { composeMetaTitle } from "../../lib/_compose-meta-title";
|
|
34
|
-
import { DocHistoryArea } from "../../lib/_doc-history-area";
|
|
35
|
-
import { BodyEndIslands } from "../../lib/_body-end-islands";
|
|
19
|
+
import { collectTagMapForLocale, TagDetailPageView } from "../../lib/_tag-pages";
|
|
36
20
|
|
|
37
21
|
export const frontmatter = { title: "Tag" };
|
|
38
22
|
|
|
@@ -41,14 +25,7 @@ export function paths(): Array<{
|
|
|
41
25
|
params: { tag: string };
|
|
42
26
|
props: { tagInfo: TagInfo };
|
|
43
27
|
}> {
|
|
44
|
-
const
|
|
45
|
-
// category_no_page index.mdx builds no route — drop it so a tag it carries
|
|
46
|
-
// doesn't render a DocCard linking to a non-existent /docs/<cat>/ page.
|
|
47
|
-
const docs = allDocs.filter(
|
|
48
|
-
(doc) =>
|
|
49
|
-
!doc.data.unlisted && !doc.data.draft && !doc.data.category_no_page,
|
|
50
|
-
);
|
|
51
|
-
const tagMap = collectTags(docs, (id, data) => data.slug ?? toRouteSlug(id));
|
|
28
|
+
const tagMap = collectTagMapForLocale(defaultLocale);
|
|
52
29
|
|
|
53
30
|
return [...tagMap.entries()].map(([tag, tagInfo]) => ({
|
|
54
31
|
params: { tag },
|
|
@@ -62,44 +39,5 @@ interface PageProps {
|
|
|
62
39
|
}
|
|
63
40
|
|
|
64
41
|
export default function DocTagPage({ params, tagInfo }: PageProps): JSX.Element {
|
|
65
|
-
|
|
66
|
-
const locale = defaultLocale;
|
|
67
|
-
|
|
68
|
-
const countText =
|
|
69
|
-
tagInfo.count === 1
|
|
70
|
-
? t("doc.pageCountSingle", locale).replace("{count}", String(tagInfo.count))
|
|
71
|
-
: t("doc.pageCount", locale).replace("{count}", String(tagInfo.count));
|
|
72
|
-
|
|
73
|
-
const pageTitle = `${t("doc.taggedWith", locale)}: ${tag}`;
|
|
74
|
-
|
|
75
|
-
const breadcrumbItems: BreadcrumbItem[] = [
|
|
76
|
-
{ label: "Docs" },
|
|
77
|
-
{ label: t("doc.allTags", locale), href: withBase("/docs/tags") },
|
|
78
|
-
{ label: tag },
|
|
79
|
-
];
|
|
80
|
-
|
|
81
|
-
const cardItems = tagInfo.docs.map((doc) => ({
|
|
82
|
-
href: docsUrl(doc.slug, locale),
|
|
83
|
-
title: doc.title,
|
|
84
|
-
description: doc.description,
|
|
85
|
-
}));
|
|
86
|
-
|
|
87
|
-
return (
|
|
88
|
-
<DocLayoutWithDefaults
|
|
89
|
-
title={composeMetaTitle(pageTitle)}
|
|
90
|
-
head={<HeadWithDefaults title={pageTitle} />}
|
|
91
|
-
noindex={settings.noindex}
|
|
92
|
-
hideSidebar={true}
|
|
93
|
-
hideToc={true}
|
|
94
|
-
headerOverride={<HeaderWithDefaults lang={locale} currentPath={withBase(`/docs/tags/${tag}`)} />}
|
|
95
|
-
breadcrumbOverride={<Breadcrumb items={breadcrumbItems} />}
|
|
96
|
-
footerOverride={<FooterWithDefaults lang={locale} />}
|
|
97
|
-
bodyEndComponents={<BodyEndIslands basePath={settings.base ?? "/"} />}
|
|
98
|
-
>
|
|
99
|
-
<h1 class="text-heading font-bold mb-vsp-xs">{pageTitle}</h1>
|
|
100
|
-
<p class="text-muted mb-vsp-lg">{countText}</p>
|
|
101
|
-
<DocCardGrid ariaLabel={pageTitle} items={cardItems} />
|
|
102
|
-
<DocHistoryArea slug={`tags/${tag}`} locale={locale} />
|
|
103
|
-
</DocLayoutWithDefaults>
|
|
104
|
-
);
|
|
42
|
+
return <TagDetailPageView locale={defaultLocale} tag={params.tag} tagInfo={tagInfo} />;
|
|
105
43
|
}
|
|
@@ -2,89 +2,19 @@
|
|
|
2
2
|
/** @jsxImportSource preact */
|
|
3
3
|
// Page module for the default-locale "All Tags" index route.
|
|
4
4
|
//
|
|
5
|
-
// Default-locale
|
|
5
|
+
// Default-locale "All Tags" index page. Collects every tag across the
|
|
6
6
|
// "docs" collection, sorts them alphabetically, and renders a full tag cloud
|
|
7
7
|
// via the v2 TagNav component. No dynamic params — single static route.
|
|
8
8
|
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
// → collectTags() builds { tag → { count, docs[] } }
|
|
12
|
-
// → sort by tag preserves sort parity with Astro original
|
|
13
|
-
// → TagNav variant="all" renders the chip cloud
|
|
9
|
+
// Tag collection + rendering are shared with the locale-prefixed route via
|
|
10
|
+
// pages/lib/_tag-pages.tsx (#2010).
|
|
14
11
|
|
|
15
|
-
import {
|
|
16
|
-
import { collectTags } from "@/utils/tags";
|
|
17
|
-
import { toRouteSlug } from "@/utils/slug";
|
|
18
|
-
import { t, defaultLocale } from "@/config/i18n";
|
|
19
|
-
import { withBase } from "@/utils/base";
|
|
20
|
-
import { settings } from "@/config/settings";
|
|
21
|
-
import { DocLayoutWithDefaults } from "@takazudo/zudo-doc/doclayout";
|
|
22
|
-
import { Breadcrumb } from "@takazudo/zudo-doc/breadcrumb";
|
|
23
|
-
import type { BreadcrumbItem } from "@takazudo/zudo-doc/breadcrumb";
|
|
24
|
-
import { TagNav } from "@takazudo/zudo-doc/nav-indexing";
|
|
25
|
-
import type { TagItem, TagNavLabels } from "@takazudo/zudo-doc/nav-indexing";
|
|
12
|
+
import { defaultLocale } from "@/config/i18n";
|
|
26
13
|
import type { JSX } from "preact";
|
|
27
|
-
import {
|
|
28
|
-
import { FooterWithDefaults } from "../../lib/_footer-with-defaults";
|
|
29
|
-
import { HeaderWithDefaults } from "../../lib/_header-with-defaults";
|
|
30
|
-
import { HeadWithDefaults } from "../../lib/_head-with-defaults";
|
|
31
|
-
import { composeMetaTitle } from "../../lib/_compose-meta-title";
|
|
32
|
-
import { DocHistoryArea } from "../../lib/_doc-history-area";
|
|
33
|
-
import { BodyEndIslands } from "../../lib/_body-end-islands";
|
|
14
|
+
import { TagsIndexPageView } from "../../lib/_tag-pages";
|
|
34
15
|
|
|
35
16
|
export const frontmatter = { title: "All Tags" };
|
|
36
17
|
|
|
37
18
|
export default function DocsTagsIndexPage(): JSX.Element {
|
|
38
|
-
|
|
39
|
-
const pageTitle = t("doc.allTags", locale);
|
|
40
|
-
|
|
41
|
-
const allDocs = bridgeDocsEntries(getCollection<ZfbDocsData>("docs"), "docs");
|
|
42
|
-
// category_no_page index.mdx builds no route — drop it so a tag it carries
|
|
43
|
-
// doesn't inflate the tag list with a card linking to a non-existent page.
|
|
44
|
-
const docs = allDocs.filter(
|
|
45
|
-
(doc) =>
|
|
46
|
-
!doc.data.unlisted && !doc.data.draft && !doc.data.category_no_page,
|
|
47
|
-
);
|
|
48
|
-
const tagMap = collectTags(docs, (id, data) => data.slug ?? toRouteSlug(id));
|
|
49
|
-
|
|
50
|
-
const labels: TagNavLabels = {
|
|
51
|
-
tags: t("doc.tags", locale),
|
|
52
|
-
taggedWith: t("doc.taggedWith", locale),
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
// Sort alphabetically — matches documented tag-nav sort order.
|
|
56
|
-
const tags: TagItem[] = [...tagMap.values()]
|
|
57
|
-
.sort((a, b) => a.tag.localeCompare(b.tag, locale))
|
|
58
|
-
.map((info) => ({
|
|
59
|
-
tag: info.tag,
|
|
60
|
-
count: info.count,
|
|
61
|
-
href: withBase(`/docs/tags/${info.tag}`),
|
|
62
|
-
}));
|
|
63
|
-
|
|
64
|
-
const breadcrumbItems: BreadcrumbItem[] = [
|
|
65
|
-
{ label: "Docs" },
|
|
66
|
-
{ label: pageTitle },
|
|
67
|
-
];
|
|
68
|
-
|
|
69
|
-
return (
|
|
70
|
-
<DocLayoutWithDefaults
|
|
71
|
-
title={composeMetaTitle(pageTitle)}
|
|
72
|
-
head={<HeadWithDefaults title={pageTitle} />}
|
|
73
|
-
noindex={settings.noindex}
|
|
74
|
-
hideSidebar={true}
|
|
75
|
-
hideToc={true}
|
|
76
|
-
headerOverride={<HeaderWithDefaults lang={locale} currentPath={withBase("/docs/tags")} />}
|
|
77
|
-
breadcrumbOverride={<Breadcrumb items={breadcrumbItems} />}
|
|
78
|
-
footerOverride={<FooterWithDefaults lang={locale} />}
|
|
79
|
-
bodyEndComponents={<BodyEndIslands basePath={settings.base ?? "/"} />}
|
|
80
|
-
>
|
|
81
|
-
<h1 class="text-heading font-bold mb-vsp-lg">{pageTitle}</h1>
|
|
82
|
-
{!settings.docTags || tags.length === 0 ? (
|
|
83
|
-
<p class="text-muted">{t("doc.noTags", locale)}</p>
|
|
84
|
-
) : (
|
|
85
|
-
<TagNav variant="all" tags={tags} labels={labels} />
|
|
86
|
-
)}
|
|
87
|
-
<DocHistoryArea slug="tags" locale={locale} />
|
|
88
|
-
</DocLayoutWithDefaults>
|
|
89
|
-
);
|
|
19
|
+
return <TagsIndexPageView locale={defaultLocale} />;
|
|
90
20
|
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/** @jsxRuntime automatic */
|
|
2
|
+
/** @jsxImportSource preact */
|
|
3
|
+
// Shared data + renderers for the doc-tags pages (#2010).
|
|
4
|
+
//
|
|
5
|
+
// Collapses the per-locale page pairs:
|
|
6
|
+
// pages/docs/tags/[tag].tsx + pages/[locale]/docs/tags/[tag].tsx
|
|
7
|
+
// pages/docs/tags/index.tsx + pages/[locale]/docs/tags/index.tsx
|
|
8
|
+
// into locale-parameterized helpers. The page files stay thin shells that own
|
|
9
|
+
// only their paths() param shapes; URL prefixes and the default-vs-locale
|
|
10
|
+
// data path branch live here.
|
|
11
|
+
//
|
|
12
|
+
// Data-path branch (kept exactly as the original pages had it):
|
|
13
|
+
// - Default locale: the "docs" collection directly, filtered
|
|
14
|
+
// unlisted/draft/category_no_page before tag collection.
|
|
15
|
+
// - Non-default locale: locale-first merge with base fallback
|
|
16
|
+
// (see locale-merge.ts) — draft-filtered inputs, unlisted dropped by the
|
|
17
|
+
// merge default, category_no_page filtered AFTER the merge so a locale
|
|
18
|
+
// override carrying the flag first wins the merge (suppressing the base
|
|
19
|
+
// doc); pre-merge filtering would drop it from localeSlugSet and the
|
|
20
|
+
// unflagged base doc would resurface as a card linking to a locale route
|
|
21
|
+
// the docs route never builds.
|
|
22
|
+
|
|
23
|
+
import { collectTags } from "@/utils/tags";
|
|
24
|
+
import type { TagInfo } from "@/utils/tags";
|
|
25
|
+
import { toRouteSlug } from "@/utils/slug";
|
|
26
|
+
import { t, defaultLocale } from "@/config/i18n";
|
|
27
|
+
import { settings } from "@/config/settings";
|
|
28
|
+
import { withBase, docsUrl } from "@/utils/base";
|
|
29
|
+
import { DocLayoutWithDefaults } from "@takazudo/zudo-doc/doclayout";
|
|
30
|
+
import { Breadcrumb } from "@takazudo/zudo-doc/breadcrumb";
|
|
31
|
+
import type { BreadcrumbItem } from "@takazudo/zudo-doc/breadcrumb";
|
|
32
|
+
import { DocCardGrid, TagNav } from "@takazudo/zudo-doc/nav-indexing";
|
|
33
|
+
import type { TagItem, TagNavLabels } from "@takazudo/zudo-doc/nav-indexing";
|
|
34
|
+
import type { JSX } from "preact";
|
|
35
|
+
import { FooterWithDefaults } from "./_footer-with-defaults";
|
|
36
|
+
import { HeaderWithDefaults } from "./_header-with-defaults";
|
|
37
|
+
import { HeadWithDefaults } from "./_head-with-defaults";
|
|
38
|
+
import { composeMetaTitle } from "./_compose-meta-title";
|
|
39
|
+
import { DocHistoryArea } from "./_doc-history-area";
|
|
40
|
+
import { BodyEndIslands } from "./_body-end-islands";
|
|
41
|
+
import { stableDocs, memoizeDerived } from "./_nav-source-cache";
|
|
42
|
+
import { mergeLocaleDocs } from "./locale-merge";
|
|
43
|
+
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
// Tag collection
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Build the { tag → TagInfo } map for one locale, preserving each original
|
|
50
|
+
* page's exact data path (see the module-header branch notes).
|
|
51
|
+
*
|
|
52
|
+
* Memoized on the snapshot-anchored stableDocs identity (same pattern as
|
|
53
|
+
* _nav-source-cache) so the collection bridging and tag aggregation run once
|
|
54
|
+
* per locale per build rather than once per built tag page.
|
|
55
|
+
*/
|
|
56
|
+
export function collectTagMapForLocale(locale: string): Map<string, TagInfo> {
|
|
57
|
+
if (locale === defaultLocale) {
|
|
58
|
+
const baseDocs = stableDocs("docs");
|
|
59
|
+
return memoizeDerived([baseDocs], "tagMap;default", () => {
|
|
60
|
+
// category_no_page index.mdx builds no route — drop it so a tag it carries
|
|
61
|
+
// doesn't render a DocCard linking to a non-existent /docs/<cat>/ page.
|
|
62
|
+
const docs = baseDocs.filter(
|
|
63
|
+
(doc) =>
|
|
64
|
+
!doc.data.unlisted && !doc.data.draft && !doc.data.category_no_page,
|
|
65
|
+
);
|
|
66
|
+
return collectTags(docs, (id, data) => data.slug ?? toRouteSlug(id));
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const baseDocs = stableDocs("docs");
|
|
71
|
+
const localeDocs = stableDocs(`docs-${locale}`);
|
|
72
|
+
return memoizeDerived([baseDocs, localeDocs], `tagMap;${locale}`, () => {
|
|
73
|
+
const { docs: mergedDocs } = mergeLocaleDocs({
|
|
74
|
+
baseDocs: baseDocs.filter((d) => !d.data.draft),
|
|
75
|
+
localeDocs: localeDocs.filter((d) => !d.data.draft),
|
|
76
|
+
applyDefaultLocaleOnlyFilter: true,
|
|
77
|
+
});
|
|
78
|
+
const docs = mergedDocs.filter((d) => !d.data.category_no_page);
|
|
79
|
+
return collectTags(docs, (id, data) => data.slug ?? toRouteSlug(id));
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// ---------------------------------------------------------------------------
|
|
84
|
+
// Shared renderers
|
|
85
|
+
// ---------------------------------------------------------------------------
|
|
86
|
+
|
|
87
|
+
/** URL prefix for a locale: "" for the default locale, "/{locale}" otherwise. */
|
|
88
|
+
function localePrefix(locale: string): string {
|
|
89
|
+
return locale === defaultLocale ? "" : `/${locale}`;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Per-tag detail page (chip target). */
|
|
93
|
+
export function TagDetailPageView({
|
|
94
|
+
locale,
|
|
95
|
+
tag,
|
|
96
|
+
tagInfo,
|
|
97
|
+
}: {
|
|
98
|
+
locale: string;
|
|
99
|
+
tag: string;
|
|
100
|
+
tagInfo: TagInfo;
|
|
101
|
+
}): JSX.Element {
|
|
102
|
+
const isDefault = locale === defaultLocale;
|
|
103
|
+
const prefix = localePrefix(locale);
|
|
104
|
+
|
|
105
|
+
const countText =
|
|
106
|
+
tagInfo.count === 1
|
|
107
|
+
? t("doc.pageCountSingle", locale).replace("{count}", String(tagInfo.count))
|
|
108
|
+
: t("doc.pageCount", locale).replace("{count}", String(tagInfo.count));
|
|
109
|
+
|
|
110
|
+
const pageTitle = `${t("doc.taggedWith", locale)}: ${tag}`;
|
|
111
|
+
|
|
112
|
+
const breadcrumbItems: BreadcrumbItem[] = [
|
|
113
|
+
{ label: "Docs" },
|
|
114
|
+
{ label: t("doc.allTags", locale), href: withBase(`${prefix}/docs/tags`) },
|
|
115
|
+
{ label: tag },
|
|
116
|
+
];
|
|
117
|
+
|
|
118
|
+
const cardItems = tagInfo.docs.map((doc) => ({
|
|
119
|
+
href: docsUrl(doc.slug, locale),
|
|
120
|
+
title: doc.title,
|
|
121
|
+
description: doc.description,
|
|
122
|
+
}));
|
|
123
|
+
|
|
124
|
+
return (
|
|
125
|
+
<DocLayoutWithDefaults
|
|
126
|
+
title={composeMetaTitle(pageTitle)}
|
|
127
|
+
head={<HeadWithDefaults title={pageTitle} />}
|
|
128
|
+
// The original default-locale page omitted `lang` entirely; passing
|
|
129
|
+
// undefined relies on Preact treating an undefined prop as absent.
|
|
130
|
+
lang={isDefault ? undefined : locale}
|
|
131
|
+
noindex={settings.noindex}
|
|
132
|
+
hideSidebar={true}
|
|
133
|
+
hideToc={true}
|
|
134
|
+
// Tag segment URL-encoded — emitted href/path sites only; route params
|
|
135
|
+
// stay raw (e.g. "type:guide" → "type%3Aguide").
|
|
136
|
+
headerOverride={<HeaderWithDefaults lang={locale} currentPath={withBase(`${prefix}/docs/tags/${encodeURIComponent(tag)}`)} />}
|
|
137
|
+
breadcrumbOverride={<Breadcrumb items={breadcrumbItems} />}
|
|
138
|
+
footerOverride={<FooterWithDefaults lang={locale} />}
|
|
139
|
+
bodyEndComponents={<BodyEndIslands basePath={settings.base ?? "/"} />}
|
|
140
|
+
>
|
|
141
|
+
<h1 class="text-heading font-bold mb-vsp-xs">{pageTitle}</h1>
|
|
142
|
+
<p class="text-muted mb-vsp-lg">{countText}</p>
|
|
143
|
+
<DocCardGrid ariaLabel={pageTitle} items={cardItems} />
|
|
144
|
+
<DocHistoryArea slug={`tags/${tag}`} locale={locale} />
|
|
145
|
+
</DocLayoutWithDefaults>
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** "All Tags" index page — computes the tag map at render time (matching the
|
|
150
|
+
* original pages, which had no props from paths()). */
|
|
151
|
+
export function TagsIndexPageView({ locale }: { locale: string }): JSX.Element {
|
|
152
|
+
const isDefault = locale === defaultLocale;
|
|
153
|
+
const prefix = localePrefix(locale);
|
|
154
|
+
const pageTitle = t("doc.allTags", locale);
|
|
155
|
+
|
|
156
|
+
const tagMap = collectTagMapForLocale(locale);
|
|
157
|
+
|
|
158
|
+
const labels: TagNavLabels = {
|
|
159
|
+
tags: t("doc.tags", locale),
|
|
160
|
+
taggedWith: t("doc.taggedWith", locale),
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
// Sort alphabetically using the page locale — matches documented tag-nav sort order.
|
|
164
|
+
const tags: TagItem[] = [...tagMap.values()]
|
|
165
|
+
.sort((a, b) => a.tag.localeCompare(b.tag, locale))
|
|
166
|
+
.map((info) => ({
|
|
167
|
+
tag: info.tag,
|
|
168
|
+
count: info.count,
|
|
169
|
+
// Tag segment URL-encoded — href sites only; route params stay raw.
|
|
170
|
+
href: withBase(`${prefix}/docs/tags/${encodeURIComponent(info.tag)}`),
|
|
171
|
+
}));
|
|
172
|
+
|
|
173
|
+
const breadcrumbItems: BreadcrumbItem[] = [
|
|
174
|
+
{ label: "Docs" },
|
|
175
|
+
{ label: pageTitle },
|
|
176
|
+
];
|
|
177
|
+
|
|
178
|
+
return (
|
|
179
|
+
<DocLayoutWithDefaults
|
|
180
|
+
title={composeMetaTitle(pageTitle)}
|
|
181
|
+
head={<HeadWithDefaults title={pageTitle} />}
|
|
182
|
+
// Same undefined-≡-absent reliance as TagDetailPageView above.
|
|
183
|
+
lang={isDefault ? undefined : locale}
|
|
184
|
+
noindex={settings.noindex}
|
|
185
|
+
hideSidebar={true}
|
|
186
|
+
hideToc={true}
|
|
187
|
+
headerOverride={<HeaderWithDefaults lang={locale} currentPath={withBase(`${prefix}/docs/tags`)} />}
|
|
188
|
+
breadcrumbOverride={<Breadcrumb items={breadcrumbItems} />}
|
|
189
|
+
footerOverride={<FooterWithDefaults lang={locale} />}
|
|
190
|
+
bodyEndComponents={<BodyEndIslands basePath={settings.base ?? "/"} />}
|
|
191
|
+
>
|
|
192
|
+
<h1 class="text-heading font-bold mb-vsp-lg">{pageTitle}</h1>
|
|
193
|
+
{!settings.docTags || tags.length === 0 ? (
|
|
194
|
+
<p class="text-muted">{t("doc.noTags", locale)}</p>
|
|
195
|
+
) : (
|
|
196
|
+
<TagNav variant="all" tags={tags} labels={labels} />
|
|
197
|
+
)}
|
|
198
|
+
<DocHistoryArea slug="tags" locale={locale} />
|
|
199
|
+
</DocLayoutWithDefaults>
|
|
200
|
+
);
|
|
201
|
+
}
|