create-zudo-doc 2.2.2 → 2.4.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/dist/scaffold.d.ts +1 -1
- package/dist/scaffold.js +10 -6
- package/package.json +1 -1
- package/templates/base/pages/index.tsx +24 -151
- package/templates/base/pages/lib/_chrome.ts +1 -0
- package/templates/base/src/config/color-schemes.ts +6 -5
- package/templates/features/claudeResources/files/src/integrations/claude-resources/__tests__/escape-for-mdx.test.ts +8 -0
- package/templates/features/claudeResources/files/src/integrations/claude-resources/escape-for-mdx.ts +6 -2
- package/templates/features/i18n/files/pages/[locale]/index.tsx +22 -165
package/dist/scaffold.d.ts
CHANGED
|
@@ -11,5 +11,5 @@ export { getSecondaryLang };
|
|
|
11
11
|
*
|
|
12
12
|
* Bumped in lockstep by scripts/release-create-zudo-doc.sh.
|
|
13
13
|
*/
|
|
14
|
-
export declare const ZUDO_DOC_PIN = "^2.
|
|
14
|
+
export declare const ZUDO_DOC_PIN = "^2.4.0";
|
|
15
15
|
export declare function scaffold(choices: UserChoices): Promise<void>;
|
package/dist/scaffold.js
CHANGED
|
@@ -18,7 +18,7 @@ export { getSecondaryLang };
|
|
|
18
18
|
*
|
|
19
19
|
* Bumped in lockstep by scripts/release-create-zudo-doc.sh.
|
|
20
20
|
*/
|
|
21
|
-
export const ZUDO_DOC_PIN = "^2.
|
|
21
|
+
export const ZUDO_DOC_PIN = "^2.4.0";
|
|
22
22
|
/**
|
|
23
23
|
* Files in `templates/base/**` that must never be copied into a generated
|
|
24
24
|
* project. Each entry is matched against the path relative to `templates/base/`
|
|
@@ -486,14 +486,18 @@ function generatePackageJson(choices) {
|
|
|
486
486
|
// zfb external-@import hoisting work. No consumer-facing / CLI change.
|
|
487
487
|
// next.72: routine toolchain bump from next.71, adopted in
|
|
488
488
|
// lockstep with the root package.json pins. No consumer-facing / CLI change.
|
|
489
|
-
// next.74
|
|
489
|
+
// next.74: routine toolchain bump from next.72 (next.73
|
|
490
490
|
// skipped), adopted in lockstep with the root package.json pins. No
|
|
491
491
|
// consumer-facing / CLI change.
|
|
492
|
-
|
|
493
|
-
|
|
492
|
+
// next.75 (current pin): toolchain bump from next.74 restoring Tailwind
|
|
493
|
+
// class-candidate scanning through symlinked project trees
|
|
494
|
+
// (zudolab/zudo-doc#2511), adopted in lockstep with the root package.json
|
|
495
|
+
// pins. No consumer-facing / CLI change.
|
|
496
|
+
"@takazudo/zfb": "0.1.0-next.75",
|
|
497
|
+
"@takazudo/zfb-runtime": "0.1.0-next.75",
|
|
494
498
|
// zfb-adapter-cloudflare — required for any route with `prerender = false`.
|
|
495
499
|
// Pinned in lockstep with @takazudo/zfb.
|
|
496
|
-
"@takazudo/zfb-adapter-cloudflare": "0.1.0-next.
|
|
500
|
+
"@takazudo/zfb-adapter-cloudflare": "0.1.0-next.75",
|
|
497
501
|
// @takazudo/zudo-doc — published from this monorepo via
|
|
498
502
|
// .github/workflows/publish-zudo-doc.yml. The pin here is bumped in
|
|
499
503
|
// lockstep by scripts/release-create-zudo-doc.sh whenever zudo-doc's
|
|
@@ -576,7 +580,7 @@ function generatePackageJson(choices) {
|
|
|
576
580
|
// @takazudo/zudo-doc/integrations/doc-history which in turn imports
|
|
577
581
|
// @takazudo/zudo-doc-history-server/git-history. Without this dep the
|
|
578
582
|
// plugin host fails at init with ERR_MODULE_NOT_FOUND — W8A (#1739).
|
|
579
|
-
deps["@takazudo/zudo-doc-history-server"] = "^2.
|
|
583
|
+
deps["@takazudo/zudo-doc-history-server"] = "^2.4.0";
|
|
580
584
|
// tsx is no longer needed here: the relocated package plugin imports the
|
|
581
585
|
// runner directly (no `tsx -e` spawn) since the package ships compiled
|
|
582
586
|
// dist/ — package-first migration #2321 (#2337).
|
package/package.json
CHANGED
|
@@ -3,166 +3,39 @@
|
|
|
3
3
|
// Page module for the site index route.
|
|
4
4
|
//
|
|
5
5
|
// Default-locale (EN) site index. Static route — no paths() export needed.
|
|
6
|
-
//
|
|
7
|
-
// tag
|
|
6
|
+
// Hands the resolved locale to the shared `prepareHomeData` factory (#2519)
|
|
7
|
+
// — which now owns the nav-tree / tag-count data-prep sequence — and passes
|
|
8
|
+
// the result to the shared HomePageView body (epic #2499, S4 #2503).
|
|
8
9
|
//
|
|
9
10
|
// Data flow:
|
|
10
|
-
//
|
|
11
|
-
// →
|
|
12
|
-
// →
|
|
13
|
-
//
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
} from "
|
|
22
|
-
import { resolveNavSource } from "./lib/_nav-source-docs";
|
|
23
|
-
import { getCategoryOrder } from "@/utils/nav-scope";
|
|
24
|
-
import { collectTags } from "@/utils/tags";
|
|
25
|
-
import { toRouteSlug } from "@/utils/slug";
|
|
26
|
-
import { DocLayoutWithDefaults } from "@takazudo/zudo-doc/doclayout";
|
|
11
|
+
// routeContext host RouteContext (settings + i18n + nav helpers)
|
|
12
|
+
// → prepareHomeData() nav tree, category order, tag count
|
|
13
|
+
// → HomePageView renders hero + SiteTreeNav grid + tag section
|
|
14
|
+
//
|
|
15
|
+
// Thin consumer of `HomePageView` (S3 #2502) and `prepareHomeData` (#2519):
|
|
16
|
+
// this file's only job is resolving the default locale — mirroring the
|
|
17
|
+
// package route's shape (`packages/zudo-doc/src/routes/index.tsx`). No
|
|
18
|
+
// `extras` here — the showcase's `@Takazudo` brand link (#1453) is
|
|
19
|
+
// project-specific and is not part of the generated project's hero.
|
|
20
|
+
|
|
21
|
+
import { routeContext } from "./lib/_route-context";
|
|
22
|
+
import { prepareHomeData } from "@takazudo/zudo-doc/home-page";
|
|
27
23
|
import type { JSX } from "preact";
|
|
28
|
-
import
|
|
29
|
-
import { Island } from "@takazudo/zfb";
|
|
30
|
-
import { SiteTreeNav } from "@takazudo/zudo-doc/site-tree-nav-island";
|
|
31
|
-
import {
|
|
32
|
-
FooterWithDefaults,
|
|
33
|
-
HeaderWithDefaults,
|
|
34
|
-
HeadWithDefaults,
|
|
35
|
-
composeMetaTitle,
|
|
36
|
-
} from "./lib/_chrome";
|
|
37
|
-
import { BodyEndIslands } from "./lib/_body-end-islands";
|
|
24
|
+
import { HomePageView } from "./lib/_chrome";
|
|
38
25
|
|
|
39
26
|
export const frontmatter = { title: "Home" };
|
|
40
27
|
|
|
41
28
|
export default function IndexPage(): JSX.Element {
|
|
42
|
-
const locale = defaultLocale;
|
|
43
|
-
|
|
44
|
-
// Identity-stable nav source (draft-filtered, unlisted retained). navDocs is
|
|
45
|
-
// pre-filtered (isNavVisible) and shared with the nav-tree fast-path.
|
|
46
|
-
const { navDocs, categoryMeta } = resolveNavSource(locale, undefined);
|
|
47
|
-
const tree = buildNavTree(navDocs, locale, categoryMeta);
|
|
48
|
-
const categoryOrder = getCategoryOrder();
|
|
49
|
-
const groupedTree = groupSatelliteNodes(tree, categoryOrder);
|
|
29
|
+
const locale = routeContext.defaultLocale;
|
|
50
30
|
|
|
51
|
-
|
|
52
|
-
// pages actually built (the tag routes exclude them too).
|
|
53
|
-
const tagCount = collectTags(
|
|
54
|
-
navDocs.filter((d) => !d.data.category_no_page),
|
|
55
|
-
(id, data) => data.slug ?? toRouteSlug(id),
|
|
56
|
-
).size;
|
|
57
|
-
|
|
58
|
-
const ctaNav = settings.headerNav[0] ?? null;
|
|
59
|
-
const overview = ctaNav ? withBase(ctaNav.path) : null;
|
|
60
|
-
const logoUrl = withBase("/img/logo.svg");
|
|
31
|
+
const { tree, categoryOrder, tagCount } = prepareHomeData(routeContext, locale);
|
|
61
32
|
|
|
62
33
|
return (
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
hideToc={true}
|
|
70
|
-
// Empty fragment suppresses DocLayoutWithDefaults' empty-data default
|
|
71
|
-
// Sidebar island — its marker never hydrates for published-package
|
|
72
|
-
// consumers (zfb#999) and zfb >= next.38 warns about it; the sidebar is
|
|
73
|
-
// hidden on this page anyway (zudolab/zudo-doc#2057).
|
|
74
|
-
sidebarOverride={<></>}
|
|
75
|
-
headerOverride={<HeaderWithDefaults lang={locale} currentPath={withBase("/")} />}
|
|
76
|
-
footerOverride={<FooterWithDefaults lang={locale} />}
|
|
77
|
-
bodyEndComponents={<BodyEndIslands basePath={settings.base ?? "/"} />}
|
|
78
|
-
enableClientRouter={settings.dynamicPageTransition}
|
|
79
|
-
>
|
|
80
|
-
{/* Hero: logo left, title+desc+links right, block centered */}
|
|
81
|
-
<div class="flex justify-center mb-vsp-xl">
|
|
82
|
-
<div class="flex flex-col items-center text-center gap-hsp-md lg:flex-row lg:text-left lg:gap-hsp-xl">
|
|
83
|
-
{/* Theme-adaptive logo: SVG used as a CSS mask over `bg-fg` so the
|
|
84
|
-
foreground color follows the active theme (white on dark, black on
|
|
85
|
-
light). The neighboring <h1>{settings.siteName}</h1> provides the
|
|
86
|
-
accessible name; mirrors zudolab/zudo-design-token-lint#65. */}
|
|
87
|
-
<div
|
|
88
|
-
class="w-[320px] max-w-full aspect-[1200/630] bg-fg shrink-0"
|
|
89
|
-
style={{
|
|
90
|
-
WebkitMask: `url(${logoUrl}) center/contain no-repeat`,
|
|
91
|
-
mask: `url(${logoUrl}) center/contain no-repeat`,
|
|
92
|
-
}}
|
|
93
|
-
aria-hidden="true"
|
|
94
|
-
/>
|
|
95
|
-
<div>
|
|
96
|
-
<h1 class="text-heading font-bold mb-vsp-2xs">{settings.siteName}</h1>
|
|
97
|
-
<p class="text-muted text-small mb-vsp-sm">{settings.siteDescription}</p>
|
|
98
|
-
<div class="flex items-center justify-center lg:justify-start gap-hsp-md text-small">
|
|
99
|
-
{overview && (
|
|
100
|
-
<>
|
|
101
|
-
<a href={overview} class="text-fg underline hover:text-accent">
|
|
102
|
-
{t("nav.overview", locale)}
|
|
103
|
-
</a>
|
|
104
|
-
<span class="text-muted">/</span>
|
|
105
|
-
</>
|
|
106
|
-
)}
|
|
107
|
-
{settings.githubUrl && (
|
|
108
|
-
<>
|
|
109
|
-
<a
|
|
110
|
-
href={settings.githubUrl as string}
|
|
111
|
-
class="inline-flex items-center gap-[0.3em] text-fg underline hover:text-accent"
|
|
112
|
-
target="_blank"
|
|
113
|
-
rel="noopener noreferrer"
|
|
114
|
-
>
|
|
115
|
-
<svg viewBox="0 0 16 16" aria-hidden="true" class="w-[1em] h-[1em] shrink-0">
|
|
116
|
-
<path
|
|
117
|
-
fill="currentColor"
|
|
118
|
-
d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"
|
|
119
|
-
/>
|
|
120
|
-
</svg>
|
|
121
|
-
GitHub
|
|
122
|
-
</a>
|
|
123
|
-
<span class="text-muted">/</span>
|
|
124
|
-
</>
|
|
125
|
-
)}
|
|
126
|
-
{/* @Takazudo link — established in #1453 (project-specific brand link).
|
|
127
|
-
The deploy was missing this trailing item, leaving a dangling "/" separator. */}
|
|
128
|
-
<a
|
|
129
|
-
href="https://x.com/Takazudo"
|
|
130
|
-
class="text-fg underline hover:text-accent"
|
|
131
|
-
target="_blank"
|
|
132
|
-
rel="noopener noreferrer"
|
|
133
|
-
>
|
|
134
|
-
@Takazudo
|
|
135
|
-
</a>
|
|
136
|
-
</div>
|
|
137
|
-
</div>
|
|
138
|
-
</div>
|
|
139
|
-
</div>
|
|
140
|
-
|
|
141
|
-
{/* Sitemap grid — restored to the original SiteTreeNav island (refs #1453).
|
|
142
|
-
The Astro reference used <Island when="idle"><SiteTreeNav ...></Island>.
|
|
143
|
-
DocsSitemap (vertical <details> list) was incorrect; SiteTreeNav gives
|
|
144
|
-
the responsive multi-column grid the reference renders. */}
|
|
145
|
-
{Island({
|
|
146
|
-
when: "idle",
|
|
147
|
-
children: (
|
|
148
|
-
<SiteTreeNav
|
|
149
|
-
tree={groupedTree}
|
|
150
|
-
categoryOrder={categoryOrder}
|
|
151
|
-
categoryIgnore={["inbox", "develop"]}
|
|
152
|
-
/>
|
|
153
|
-
),
|
|
154
|
-
}) as unknown as VNode}
|
|
155
|
-
|
|
156
|
-
{settings.docTags && tagCount > 0 && (
|
|
157
|
-
<section class="mt-vsp-xl">
|
|
158
|
-
<h2 class="text-title font-bold mb-vsp-md">
|
|
159
|
-
{t("doc.allTags", locale)}
|
|
160
|
-
</h2>
|
|
161
|
-
<a href={withBase("/docs/tags")} class="text-accent underline hover:text-accent-hover">
|
|
162
|
-
{t("doc.allTags", locale)}
|
|
163
|
-
</a>
|
|
164
|
-
</section>
|
|
165
|
-
)}
|
|
166
|
-
</DocLayoutWithDefaults>
|
|
34
|
+
<HomePageView
|
|
35
|
+
locale={locale}
|
|
36
|
+
tree={tree}
|
|
37
|
+
categoryOrder={categoryOrder}
|
|
38
|
+
tagCount={tagCount}
|
|
39
|
+
/>
|
|
167
40
|
);
|
|
168
41
|
}
|
|
@@ -88,15 +88,16 @@ export const colorSchemes: Record<string, ColorScheme> = {
|
|
|
88
88
|
],
|
|
89
89
|
semantic: {
|
|
90
90
|
surface: 10,
|
|
91
|
-
muted:
|
|
91
|
+
muted: "oklch(0.492 0.000 0.00)" /* upstream #6b6b6b (p8) → L-0.036 for AA (scheme-a11y #2489) */, // muted-vs-bg → 4.61:1
|
|
92
92
|
accent: 5,
|
|
93
|
-
accentHover:
|
|
93
|
+
accentHover: "oklch(0.492 0.027 257.67)" /* upstream #8590a0 (p14) → L-0.158, C-0.000 for AA (scheme-a11y #2489) */, // accent-hover-vs-bg → 4.61:1
|
|
94
94
|
codeBg: 10,
|
|
95
95
|
codeFg: 11,
|
|
96
96
|
success: 2,
|
|
97
97
|
danger: 1,
|
|
98
98
|
warning: 3,
|
|
99
99
|
info: 4,
|
|
100
|
+
mermaidNoteBg: "oklch(0.821 0.007 53.44)" /* derived bg-elevated from bg (p9) — default (p0) collided 1:1 with mermaidText/p11 (scheme-a11y #2489) */,
|
|
100
101
|
imageOverlayBg: 11,
|
|
101
102
|
imageOverlayFg: 10,
|
|
102
103
|
matchedKeywordBg: "oklch(0.959 0.109 102.63)" /* #fff59d */,
|
|
@@ -117,13 +118,13 @@ export const colorSchemes: Record<string, ColorScheme> = {
|
|
|
117
118
|
],
|
|
118
119
|
semantic: {
|
|
119
120
|
surface: 0,
|
|
120
|
-
muted:
|
|
121
|
+
muted: "oklch(0.657 0.000 0.00)" /* upstream #888888 (p8) → L+0.030 for AA (scheme-a11y #2489) */, // muted-vs-{bg,codeBg,chatAssistantBg} → 4.62:1
|
|
121
122
|
accent: 12,
|
|
122
123
|
accentHover: 14,
|
|
123
|
-
codeBg:
|
|
124
|
+
codeBg: "oklch(0.281 0.000 0.00)" /* upstream #383838 (p10) → L-0.060 toward bg for muted-vs-codeBg AA (rendered-bg #2510) */,
|
|
124
125
|
codeFg: 11,
|
|
125
126
|
success: 2,
|
|
126
|
-
danger: 1
|
|
127
|
+
danger: "oklch(0.662 0.143 16.99)" /* upstream #da6871 → L+0.006 for AA (scheme-a11y #2489) */, // admonition-danger → 4.61:1
|
|
127
128
|
warning: 3,
|
|
128
129
|
info: 4,
|
|
129
130
|
imageOverlayBg: 0,
|
|
@@ -31,4 +31,12 @@ describe("escapeForMdx", () => {
|
|
|
31
31
|
it("escapes self-closing non-allowlisted component tags", () => {
|
|
32
32
|
expect(escapeForMdx("<Component />")).toMatch(/<Component\s*\/>/);
|
|
33
33
|
});
|
|
34
|
+
|
|
35
|
+
it("escapes the compact self-closing form <Foo/> (no space before slash)", () => {
|
|
36
|
+
// Regression: the opening-tag regex only matches the spaced form <Foo />,
|
|
37
|
+
// so the compact <Foo/> needs the dedicated self-closing branch.
|
|
38
|
+
const out = escapeForMdx("<Foo/>");
|
|
39
|
+
expect(out).toBe("<Foo/>");
|
|
40
|
+
expect(out).not.toContain("<Foo/>");
|
|
41
|
+
});
|
|
34
42
|
});
|
package/templates/features/claudeResources/files/src/integrations/claude-resources/escape-for-mdx.ts
CHANGED
|
@@ -67,7 +67,11 @@ export function escapeForMdx(content: string): string {
|
|
|
67
67
|
return `</${name}>`;
|
|
68
68
|
},
|
|
69
69
|
)
|
|
70
|
-
// Escape self-closing tags
|
|
70
|
+
// Escape self-closing tags. The spaced form <Foo /> is already handled
|
|
71
|
+
// by the opening-tag regex above ((\s[^>]*)? matches " /", then > closes),
|
|
72
|
+
// but the COMPACT form <Foo/> (no space before the slash) is NOT — the
|
|
73
|
+
// name is consumed, (\s[^>]*)? matches empty, then the regex needs ">"
|
|
74
|
+
// and finds "/". So this branch is still required for the compact form.
|
|
71
75
|
.replace(
|
|
72
76
|
/<([A-Za-z][A-Za-z0-9_-]*)(\s[^>]*)?\s*\/>/g,
|
|
73
77
|
(match, name: string) => {
|
|
@@ -84,7 +88,7 @@ export function escapeForMdx(content: string): string {
|
|
|
84
88
|
// Restore inline code placeholders
|
|
85
89
|
escaped = escaped.replace(
|
|
86
90
|
new RegExp(`${inlinePlaceholder}(\\d+)\x00`, "g"),
|
|
87
|
-
(_, idx: string) => inlineCodes[Number(idx)],
|
|
91
|
+
(_, idx: string) => inlineCodes[Number(idx)] ?? "",
|
|
88
92
|
);
|
|
89
93
|
|
|
90
94
|
return escaped;
|
|
@@ -11,34 +11,24 @@
|
|
|
11
11
|
// props: { locale } — resolved locale passed to component
|
|
12
12
|
//
|
|
13
13
|
// Data flow (inside component — sync per ADR-004):
|
|
14
|
-
//
|
|
15
|
-
// →
|
|
16
|
-
// →
|
|
14
|
+
// routeContext host RouteContext (settings + i18n + nav helpers)
|
|
15
|
+
// → prepareHomeData() nav tree, category order, tag count
|
|
16
|
+
// → HomePageView renders hero + SiteTreeNav grid + tag section
|
|
17
|
+
//
|
|
18
|
+
// Thin consumer of `HomePageView` (S3 #2502) and `prepareHomeData` (#2519):
|
|
19
|
+
// this file's only job is `paths()` (a locale-routing concern) — mirroring
|
|
20
|
+
// the package route's shape (`packages/zudo-doc/src/routes/locale-index.tsx`).
|
|
21
|
+
// The locale-specific data prep — `resolveNavSource` with the locale-home
|
|
22
|
+
// filter options, `loadCategoryMeta`, and the locale-config guard — now lives
|
|
23
|
+
// in `prepareHomeData`. No `extras` here — the showcase's `@Takazudo` brand
|
|
24
|
+
// link (#1453) is project-specific and is not part of the generated
|
|
25
|
+
// project's hero.
|
|
17
26
|
|
|
18
27
|
import { settings } from "@/config/settings";
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
buildNavTree,
|
|
23
|
-
groupSatelliteNodes,
|
|
24
|
-
loadCategoryMeta,
|
|
25
|
-
} from "@/utils/docs";
|
|
26
|
-
import { getCategoryOrder } from "@/utils/nav-scope";
|
|
27
|
-
import { collectTags } from "@/utils/tags";
|
|
28
|
-
import { toRouteSlug } from "@/utils/slug";
|
|
29
|
-
import { DocLayoutWithDefaults } from "@takazudo/zudo-doc/doclayout";
|
|
28
|
+
import { routeContext } from "../lib/_route-context";
|
|
29
|
+
import { prepareHomeData } from "@takazudo/zudo-doc/home-page";
|
|
30
30
|
import type { JSX } from "preact";
|
|
31
|
-
import
|
|
32
|
-
import { Island } from "@takazudo/zfb";
|
|
33
|
-
import { SiteTreeNav } from "@takazudo/zudo-doc/site-tree-nav-island";
|
|
34
|
-
import { resolveNavSource } from "../lib/_nav-source-docs";
|
|
35
|
-
import {
|
|
36
|
-
FooterWithDefaults,
|
|
37
|
-
HeaderWithDefaults,
|
|
38
|
-
HeadWithDefaults,
|
|
39
|
-
composeMetaTitle,
|
|
40
|
-
} from "../lib/_chrome";
|
|
41
|
-
import { BodyEndIslands } from "../lib/_body-end-islands";
|
|
31
|
+
import { HomePageView } from "../lib/_chrome";
|
|
42
32
|
|
|
43
33
|
export const frontmatter = { title: "Home" };
|
|
44
34
|
|
|
@@ -69,147 +59,14 @@ interface PageArgs {
|
|
|
69
59
|
export default function LocaleIndexPage({ params }: PageArgs): JSX.Element {
|
|
70
60
|
const locale = params.locale;
|
|
71
61
|
|
|
72
|
-
|
|
73
|
-
// but the component can still be exercised with an unconfigured locale value
|
|
74
|
-
// (e.g. during testing or if the router dispatches an unexpected param).
|
|
75
|
-
// Fail loudly rather than silently serving EN content under a bogus prefix.
|
|
76
|
-
const cfg = getLocaleConfig(locale);
|
|
77
|
-
if (!cfg) {
|
|
78
|
-
throw new Error(`LocaleIndexPage: locale "${locale}" is not configured in settings.locales`);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Identity-stable, locale-first merge with EN fallback (shared `navDocs`
|
|
82
|
-
// instance). categoryMeta is intentionally locale-dir-only here — this page
|
|
83
|
-
// historically did NOT merge in base meta (unlike the locale doc route), so
|
|
84
|
-
// we keep that exact behavior to preserve output.
|
|
85
|
-
const { navDocs } = resolveNavSource(locale as Locale, undefined, {
|
|
86
|
-
applyDefaultLocaleOnlyFilter: true,
|
|
87
|
-
keepUnlisted: true,
|
|
88
|
-
});
|
|
89
|
-
const categoryMeta = loadCategoryMeta(cfg.dir);
|
|
90
|
-
|
|
91
|
-
const tree = buildNavTree(navDocs, locale as Locale, categoryMeta);
|
|
92
|
-
const categoryOrder = getCategoryOrder();
|
|
93
|
-
const groupedTree = groupSatelliteNodes(tree, categoryOrder);
|
|
94
|
-
|
|
95
|
-
// Drop category_no_page index files so the count matches the number of tag
|
|
96
|
-
// pages actually built (the tag routes exclude them too).
|
|
97
|
-
const tagCount = collectTags(
|
|
98
|
-
navDocs.filter((d) => !d.data.category_no_page),
|
|
99
|
-
(id, data) => data.slug ?? toRouteSlug(id),
|
|
100
|
-
).size;
|
|
101
|
-
|
|
102
|
-
const ctaNav = settings.headerNav[0] ?? null;
|
|
103
|
-
const overview = ctaNav ? withBase(`/${locale}${ctaNav.path}`) : null;
|
|
104
|
-
const logoUrl = withBase("/img/logo.svg");
|
|
62
|
+
const { tree, categoryOrder, tagCount } = prepareHomeData(routeContext, locale);
|
|
105
63
|
|
|
106
64
|
return (
|
|
107
|
-
<
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
hideToc={true}
|
|
114
|
-
// Empty fragment suppresses DocLayoutWithDefaults' empty-data default
|
|
115
|
-
// Sidebar island — its marker never hydrates for published-package
|
|
116
|
-
// consumers (zfb#999) and zfb >= next.38 warns about it; the sidebar is
|
|
117
|
-
// hidden on this page anyway (zudolab/zudo-doc#2057).
|
|
118
|
-
sidebarOverride={<></>}
|
|
119
|
-
headerOverride={<HeaderWithDefaults lang={locale as Locale} currentPath={withBase(`/${locale}/`)} />}
|
|
120
|
-
footerOverride={<FooterWithDefaults lang={locale} />}
|
|
121
|
-
bodyEndComponents={<BodyEndIslands basePath={settings.base ?? "/"} />}
|
|
122
|
-
enableClientRouter={settings.dynamicPageTransition}
|
|
123
|
-
>
|
|
124
|
-
{/* Hero: logo left, title+desc+links right, block centered */}
|
|
125
|
-
<div class="flex justify-center mb-vsp-xl">
|
|
126
|
-
<div class="flex flex-col items-center text-center gap-hsp-md lg:flex-row lg:text-left lg:gap-hsp-xl">
|
|
127
|
-
{/* Theme-adaptive logo: SVG used as a CSS mask over `bg-fg` so the
|
|
128
|
-
foreground color follows the active theme (white on dark, black on
|
|
129
|
-
light). The neighboring <h1>{settings.siteName}</h1> provides the
|
|
130
|
-
accessible name; mirrors zudolab/zudo-design-token-lint#65. */}
|
|
131
|
-
<div
|
|
132
|
-
class="w-[320px] max-w-full aspect-[1200/630] bg-fg shrink-0"
|
|
133
|
-
style={{
|
|
134
|
-
WebkitMask: `url(${logoUrl}) center/contain no-repeat`,
|
|
135
|
-
mask: `url(${logoUrl}) center/contain no-repeat`,
|
|
136
|
-
}}
|
|
137
|
-
aria-hidden="true"
|
|
138
|
-
/>
|
|
139
|
-
<div>
|
|
140
|
-
<h1 class="text-heading font-bold mb-vsp-2xs">{settings.siteName}</h1>
|
|
141
|
-
<p class="text-muted text-small mb-vsp-sm">{settings.siteDescription}</p>
|
|
142
|
-
<div class="flex items-center justify-center lg:justify-start gap-hsp-md text-small">
|
|
143
|
-
{overview && (
|
|
144
|
-
<>
|
|
145
|
-
<a href={overview} class="text-fg underline hover:text-accent">
|
|
146
|
-
{t("nav.overview", locale)}
|
|
147
|
-
</a>
|
|
148
|
-
<span class="text-muted">/</span>
|
|
149
|
-
</>
|
|
150
|
-
)}
|
|
151
|
-
{settings.githubUrl && (
|
|
152
|
-
<>
|
|
153
|
-
<a
|
|
154
|
-
href={settings.githubUrl as string}
|
|
155
|
-
class="inline-flex items-center gap-[0.3em] text-fg underline hover:text-accent"
|
|
156
|
-
target="_blank"
|
|
157
|
-
rel="noopener noreferrer"
|
|
158
|
-
>
|
|
159
|
-
<svg viewBox="0 0 16 16" aria-hidden="true" class="w-[1em] h-[1em] shrink-0">
|
|
160
|
-
<path
|
|
161
|
-
fill="currentColor"
|
|
162
|
-
d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"
|
|
163
|
-
/>
|
|
164
|
-
</svg>
|
|
165
|
-
GitHub
|
|
166
|
-
</a>
|
|
167
|
-
<span class="text-muted">/</span>
|
|
168
|
-
</>
|
|
169
|
-
)}
|
|
170
|
-
{/* @Takazudo link — ported from pages/index.tsx (refs #1453).
|
|
171
|
-
The locale home was missing this trailing item, leaving a
|
|
172
|
-
dangling "/" separator after GitHub. */}
|
|
173
|
-
<a
|
|
174
|
-
href="https://x.com/Takazudo"
|
|
175
|
-
class="text-fg underline hover:text-accent"
|
|
176
|
-
target="_blank"
|
|
177
|
-
rel="noopener noreferrer"
|
|
178
|
-
>
|
|
179
|
-
@Takazudo
|
|
180
|
-
</a>
|
|
181
|
-
</div>
|
|
182
|
-
</div>
|
|
183
|
-
</div>
|
|
184
|
-
</div>
|
|
185
|
-
|
|
186
|
-
{/* Sitemap grid — SiteTreeNav island mirrors the EN home (refs #1453).
|
|
187
|
-
The locale home was using DocsSitemap (vertical <details> list);
|
|
188
|
-
replaced with the same SiteTreeNav island used by pages/index.tsx. */}
|
|
189
|
-
{Island({
|
|
190
|
-
when: "idle",
|
|
191
|
-
children: (
|
|
192
|
-
<SiteTreeNav
|
|
193
|
-
tree={groupedTree}
|
|
194
|
-
categoryOrder={categoryOrder}
|
|
195
|
-
categoryIgnore={["inbox", "develop"]}
|
|
196
|
-
/>
|
|
197
|
-
),
|
|
198
|
-
}) as unknown as VNode}
|
|
199
|
-
|
|
200
|
-
{settings.docTags && tagCount > 0 && (
|
|
201
|
-
<section class="mt-vsp-xl">
|
|
202
|
-
<h2 class="text-title font-bold mb-vsp-md">
|
|
203
|
-
{t("doc.allTags", locale)}
|
|
204
|
-
</h2>
|
|
205
|
-
<a
|
|
206
|
-
href={withBase(`/${locale}/docs/tags`)}
|
|
207
|
-
class="text-accent underline hover:text-accent-hover"
|
|
208
|
-
>
|
|
209
|
-
{t("doc.allTags", locale)}
|
|
210
|
-
</a>
|
|
211
|
-
</section>
|
|
212
|
-
)}
|
|
213
|
-
</DocLayoutWithDefaults>
|
|
65
|
+
<HomePageView
|
|
66
|
+
locale={locale}
|
|
67
|
+
tree={tree}
|
|
68
|
+
categoryOrder={categoryOrder}
|
|
69
|
+
tagCount={tagCount}
|
|
70
|
+
/>
|
|
214
71
|
);
|
|
215
72
|
}
|