create-zudo-doc 0.2.22 → 1.0.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.
Files changed (28) hide show
  1. package/dist/compose.d.ts +6 -3
  2. package/dist/compose.js +6 -4
  3. package/dist/features/image-enlarge.d.ts +15 -13
  4. package/dist/features/image-enlarge.js +16 -192
  5. package/dist/scaffold.d.ts +11 -0
  6. package/dist/scaffold.js +36 -7
  7. package/dist/settings-gen.js +4 -0
  8. package/package.json +1 -1
  9. package/templates/base/pages/_mdx-components.ts +64 -185
  10. package/templates/base/pages/index.tsx +1 -1
  11. package/templates/base/pages/lib/_extract-headings.ts +21 -295
  12. package/templates/base/pages/lib/_math-block.tsx +4 -63
  13. package/templates/base/src/components/content/code-group.tsx +3 -76
  14. package/templates/base/src/components/content/content-admonition.tsx +4 -56
  15. package/templates/base/src/config/settings-types.ts +34 -172
  16. package/templates/base/src/styles/global.css +35 -8
  17. package/templates/features/i18n/files/pages/[locale]/index.tsx +1 -1
  18. package/templates/base/pages/404.tsx +0 -61
  19. package/templates/base/pages/robots.txt.tsx +0 -5
  20. package/templates/base/pages/sitemap.xml.tsx +0 -59
  21. package/templates/base/plugins/copy-public-plugin.mjs +0 -58
  22. package/templates/base/src/components/site-tree-nav.tsx +0 -6
  23. package/templates/features/docTags/files/pages/[locale]/docs/tags/[tag].tsx +0 -59
  24. package/templates/features/docTags/files/pages/[locale]/docs/tags/index.tsx +0 -39
  25. package/templates/features/docTags/files/pages/docs/tags/[tag].tsx +0 -43
  26. package/templates/features/docTags/files/pages/docs/tags/index.tsx +0 -20
  27. package/templates/features/versioning/files/pages/[locale]/docs/versions.tsx +0 -48
  28. package/templates/features/versioning/files/pages/docs/versions.tsx +0 -20
@@ -1,63 +1,4 @@
1
- /** @jsxRuntime automatic */
2
- /** @jsxImportSource preact */
3
- // MathBlock server-rendered KaTeX component for MDX math expressions.
4
- //
5
- // Registered in pages/_mdx-components.ts as `MathBlock` so the MDX corpus
6
- // can reference it as <MathBlock latex="…" block />.
7
- //
8
- // Used by the math-equations.mdx content files (both EN and JA) which write
9
- // `<MathBlock>` JSX directly instead of `$$…$$` fences. The explicit JSX
10
- // form is required because the zfb Rust MDX→JSX emitter does not understand
11
- // remark-math `$$…$$` syntax — LaTeX identifiers like `\infty` become invalid
12
- // JSX expressions `{\infty}` that esbuild rejects (zudo-front-builder #93).
13
- // Using `<MathBlock>` directly keeps the LaTeX inside a string attribute,
14
- // which esbuild accepts cleanly.
15
- //
16
- // Rendering: katex.renderToString() is called at SSR time — no client JS.
17
- // `throwOnError: false` keeps a broken formula visible as an error span
18
- // rather than crashing the page.
19
-
20
- import katex from "katex";
21
- import type { VNode } from "preact";
22
-
23
- interface MathBlockProps {
24
- /** Raw LaTeX source string. */
25
- latex: string;
26
- /** When true, renders as a block (display) equation; otherwise inline. */
27
- block?: boolean;
28
- }
29
-
30
- /**
31
- * Server-rendered KaTeX math component.
32
- *
33
- * Block mode wraps the output in `<div class="math math-display">`;
34
- * inline mode uses `<span class="math math-inline">`. The class names
35
- * match the standard rehype-katex output so existing CSS (e.g. the
36
- * KaTeX stylesheet) still applies.
37
- */
38
- export function MathBlock({ latex, block = false }: MathBlockProps): VNode {
39
- const html = katex.renderToString(latex, {
40
- displayMode: block,
41
- // Never throw — malformed LaTeX renders a visible error span instead
42
- // of crashing the entire page build.
43
- throwOnError: false,
44
- });
45
-
46
- if (block) {
47
- return (
48
- <div
49
- class="math math-display"
50
- // eslint-disable-next-line react/no-danger
51
- dangerouslySetInnerHTML={{ __html: html }}
52
- />
53
- );
54
- }
55
-
56
- return (
57
- <span
58
- class="math math-inline"
59
- // eslint-disable-next-line react/no-danger
60
- dangerouslySetInnerHTML={{ __html: html }}
61
- />
62
- );
63
- }
1
+ // Re-export from the shared package — moved to @takazudo/zudo-doc/math-block
2
+ // as part of the package-first migration (epic #2321, S4 #2327).
3
+ export type { MathBlockProps } from "@takazudo/zudo-doc/math-block";
4
+ export { MathBlock } from "@takazudo/zudo-doc/math-block";
@@ -1,76 +1,3 @@
1
- import { Tabs } from "@takazudo/zudo-doc/code-syntax";
2
- import { TabItem } from "@takazudo/zudo-doc/tab-item";
3
-
4
- /**
5
- * Adapter for zfb's `:::code-group` directive (codeTabs Option A).
6
- *
7
- * zfb emits:
8
- * <CodeGroup tabs={["label1", "label2", ...]}>
9
- * <pre data-lang="ts">{RAW code text}</pre>
10
- * <pre data-lang="js">{RAW code text}</pre>
11
- * </CodeGroup>
12
- *
13
- * The existing <Tabs>/<TabItem> UI uses a children-based API, so this
14
- * component zips the `tabs` label array with the `<pre data-lang>` children
15
- * by index, wrapping each in a <TabItem> with the matching label.
16
- *
17
- * Code inside each <pre> is raw text (NOT syntect-highlighted — the Rust
18
- * pipeline does not run highlight inside code-group fences). We render
19
- * the <pre> inside a <TabItem> with explicit styling via Tailwind tokens
20
- * so it looks like a code block visually.
21
- *
22
- * TabsInit (the companion init script) is present in the layout
23
- * (packages/zudo-doc/src/doclayout/doc-layout-with-defaults.tsx line 433)
24
- * — we rely on it being there; no duplicate needed here.
25
- */
26
-
27
- type Props = {
28
- tabs?: string[];
29
- children?: React.ReactNode;
30
- [key: string]: unknown;
31
- };
32
-
33
- function toArray(children: React.ReactNode): React.ReactNode[] {
34
- if (!children) return [];
35
- if (Array.isArray(children)) return children;
36
- return [children];
37
- }
38
-
39
- export function CodeGroup({ tabs = [], children, name }: Props) {
40
- const childArray = toArray(children);
41
-
42
- // Zip tabs labels with pre children by index. Extra children beyond the
43
- // tabs array (shouldn't happen in normal zfb output) are ignored.
44
- const items = tabs.map((label, i) => {
45
- const child = childArray[i];
46
- return { label, child };
47
- });
48
-
49
- if (items.length === 0) {
50
- // Degenerate: no tabs — render children as-is.
51
- return <>{children}</>;
52
- }
53
-
54
- // zfb forwards `:::code-group{name="x"}` as the `name` prop; Tabs persists
55
- // the active tab per group via `groupId`.
56
- const groupId = typeof name === "string" ? name : undefined;
57
-
58
- return (
59
- <Tabs groupId={groupId}>
60
- {items.map(({ label, child }, i) => (
61
- // value is suffixed with the index so two fences sharing a label
62
- // (e.g. both titled "ts") get distinct stable tab identities; the
63
- // label stays the visible text.
64
- <TabItem
65
- key={`${label}-${i}`}
66
- label={label}
67
- value={`${label}-${i}`}
68
- default={i === 0 ? true : undefined}
69
- >
70
- {/* Raw-code <pre> from zfb: apply code-block visual treatment via tokens */}
71
- <div class="code-group-panel">{child}</div>
72
- </TabItem>
73
- ))}
74
- </Tabs>
75
- );
76
- }
1
+ // Re-export from the shared package — moved to @takazudo/zudo-doc/code-group
2
+ // as part of the package-first migration (epic #2321, S4 #2327).
3
+ export { CodeGroup } from "@takazudo/zudo-doc/code-group";
@@ -1,56 +1,4 @@
1
- /** @jsxRuntime automatic */
2
- /** @jsxImportSource preact */
3
- // Real Preact bindings for the admonition MDX tags (Note/Tip/Info/Warning/
4
- // Danger/Caution/Important). Replaces the former literal-VNode
5
- // `makeAdmonitionStub` in pages/_mdx-components.ts with a proper typed
6
- // component — restoring the first-class admonition components the Astro-era
7
- // theme shipped (zudolab/zudo-doc#1456), now on the zfb pipeline.
8
- //
9
- // These tags arrive from two zfb features: the `directives` map emits them from
10
- // `:::note` directives, and `githubAlerts` emits Important/Caution from
11
- // `[!IMPORTANT]`/`[!CAUTION]` blockquotes. The JSX form `<Note title="…">` is
12
- // also authored directly in MDX. All three paths render through here.
13
- //
14
- // Markup contract — KEEP STABLE. The structure below
15
- // <div data-admonition="<variant>" class="admonition admonition-<variant>">
16
- // <p class="admonition-title">…</p>
17
- // <div class="admonition-body">…</div>
18
- // </div>
19
- // is the hook both the design-system CSS (`.admonition-<variant>` rules in
20
- // src/styles/global.css) and the e2e smoke spec (e2e/smoke-admonitions.spec.ts)
21
- // target. The per-variant color + icon live in CSS keyed off `data-admonition`,
22
- // so this component stays presentation-agnostic.
23
- import type { ComponentChildren, VNode } from "preact";
24
-
25
- export type AdmonitionVariant =
26
- | "note"
27
- | "tip"
28
- | "info"
29
- | "warning"
30
- | "danger"
31
- | "caution"
32
- | "important";
33
-
34
- export interface AdmonitionProps {
35
- /** Custom title; falls back to the capitalized variant name (e.g. "Note"). */
36
- title?: string;
37
- children?: ComponentChildren;
38
- }
39
-
40
- /**
41
- * Build the admonition component for a single variant. The title row is always
42
- * rendered — defaulting to the capitalized variant name when the author gives
43
- * no `title` — matching the Astro reference where every callout shows a title.
44
- */
45
- export function makeAdmonition(variant: AdmonitionVariant) {
46
- const defaultTitle = variant.charAt(0).toUpperCase() + variant.slice(1);
47
- return function Admonition({ title, children }: AdmonitionProps): VNode {
48
- const heading = title && title.length > 0 ? title : defaultTitle;
49
- return (
50
- <div data-admonition={variant} class={`admonition admonition-${variant}`}>
51
- <p class="admonition-title">{heading}</p>
52
- <div class="admonition-body">{children}</div>
53
- </div>
54
- );
55
- };
56
- }
1
+ // Re-export from the shared package — moved to @takazudo/zudo-doc/content-admonition
2
+ // as part of the package-first migration (epic #2321, S4 #2327).
3
+ export type { AdmonitionVariant, AdmonitionProps } from "@takazudo/zudo-doc/content-admonition";
4
+ export { makeAdmonition } from "@takazudo/zudo-doc/content-admonition";
@@ -1,181 +1,43 @@
1
- export interface HeaderNavChildItem {
2
- label: string;
3
- labelKey?: string;
4
- path: string;
5
- categoryMatch?: string;
6
- }
7
-
8
- export interface HeaderNavItem extends HeaderNavChildItem {
9
- children?: HeaderNavChildItem[];
10
- }
11
-
12
- export type HeaderRightComponentName =
13
- | "theme-toggle"
14
- | "language-switcher"
15
- | "version-switcher"
16
- | "github-link"
17
- | "search";
1
+ // Re-export most types from the shared package — moved to @takazudo/zudo-doc/settings
2
+ // as part of the package-first migration (epic #2321, S4 #2327).
3
+ // HeaderRightTriggerName and HeaderRightTriggerItem are defined locally rather than
4
+ // re-exported from the package because the designTokenPanel feature injects its
5
+ // extra trigger-name variant into HeaderRightTriggerName via the @slot anchor; the
6
+ // package unconditionally includes both trigger names but the base template
7
+ // ships only "ai-chat", and the feature overlay adds the panel trigger variant
8
+ // via the compose engine. HeaderRightTriggerItem references the local
9
+ // HeaderRightTriggerName, so it stays local too.
10
+ export type {
11
+ TagGovernanceMode,
12
+ TagVocabularyEntry,
13
+ HeaderNavChildItem,
14
+ HeaderNavItem,
15
+ HeaderRightComponentName,
16
+ HeaderRightComponentItem,
17
+ HeaderRightLinkItem,
18
+ HeaderRightHtmlItem,
19
+ HeaderRightItem,
20
+ BodyFootUtilAreaConfig,
21
+ ColorModeConfig,
22
+ LocaleConfig,
23
+ FooterLinkItem,
24
+ FooterLinkColumn,
25
+ FooterTaglistLocaleConfig,
26
+ FooterTaglistConfig,
27
+ FooterConfig,
28
+ HtmlPreviewConfig,
29
+ FrontmatterPreviewConfig,
30
+ TagPlacement,
31
+ VersionConfig,
32
+ MetaTagsConfig,
33
+ Settings,
34
+ } from "@takazudo/zudo-doc/settings";
18
35
 
19
36
  // @slot:settings-types:trigger-names:start
20
37
  export type HeaderRightTriggerName = "ai-chat";
21
38
  // @slot:settings-types:trigger-names:end
22
39
 
23
- export interface HeaderRightComponentItem {
24
- type: "component";
25
- component: HeaderRightComponentName;
26
- }
27
-
28
40
  export interface HeaderRightTriggerItem {
29
41
  type: "trigger";
30
42
  trigger: HeaderRightTriggerName;
31
43
  }
32
-
33
- export interface HeaderRightLinkItem {
34
- type: "link";
35
- href: string;
36
- label?: string;
37
- ariaLabel?: string;
38
- icon?: "github";
39
- }
40
-
41
- export interface HeaderRightHtmlItem {
42
- type: "html";
43
- html: string;
44
- }
45
-
46
- export type HeaderRightItem =
47
- | HeaderRightComponentItem
48
- | HeaderRightTriggerItem
49
- | HeaderRightLinkItem
50
- | HeaderRightHtmlItem;
51
-
52
- export interface BodyFootUtilAreaConfig {
53
- docHistory?: boolean;
54
- viewSourceLink?: boolean;
55
- }
56
-
57
- export interface ColorModeConfig {
58
- defaultMode: "light" | "dark";
59
- lightScheme: string;
60
- darkScheme: string;
61
- respectPrefersColorScheme: boolean;
62
- }
63
-
64
- export interface LocaleConfig {
65
- label: string;
66
- dir: string;
67
- }
68
-
69
- export interface FooterLinkItem {
70
- label: string;
71
- href: string;
72
- locales?: Record<string, { label: string }>;
73
- }
74
-
75
- export interface FooterLinkColumn {
76
- title: string;
77
- items: FooterLinkItem[];
78
- locales?: Record<string, { title: string }>;
79
- }
80
-
81
- /**
82
- * Per-locale overrides for the footer taglist labels.
83
- *
84
- * `title` — overrides `taglist.title` on this locale.
85
- * `groupTitles` — per-group title overrides keyed by vocabulary `group`.
86
- */
87
- export interface FooterTaglistLocaleConfig {
88
- title?: string;
89
- groupTitles?: Record<string, string>;
90
- }
91
-
92
- /**
93
- * Opt-in footer tag index.
94
- *
95
- * Renders one or more columns of tag links inside the existing footer grid.
96
- * Off by default: when `enabled: false` (or the field is omitted entirely),
97
- * the footer renders unchanged.
98
- *
99
- * - `groupBy: "group"` — one column per vocabulary `group`, in the order the
100
- * groups first appear in `tag-vocabulary.ts`. Each column's title comes from
101
- * `groupTitles[group]`, falling back to a capitalised version of the group
102
- * name.
103
- * - `groupBy: "flat"` — a single column titled `title` listing every tag
104
- * alphabetically. This is also the fallback used when the vocabulary is
105
- * inactive (`tagVocabulary: false` or `tagGovernance: "off"`).
106
- */
107
- export interface FooterTaglistConfig {
108
- enabled: boolean;
109
- /** Column title used in flat mode (and as fallback for ungrouped tags). */
110
- title?: string;
111
- /** Default `"group"` when the vocabulary is active, otherwise forced to `"flat"`. */
112
- groupBy?: "group" | "flat";
113
- /** English (default-locale) group titles, e.g. `{ type: "By type" }`. */
114
- groupTitles?: Record<string, string>;
115
- /** Locale-specific overrides for `title` and `groupTitles`. */
116
- locales?: Record<string, FooterTaglistLocaleConfig>;
117
- }
118
-
119
- export interface FooterConfig {
120
- links: FooterLinkColumn[];
121
- /** Copyright text displayed at the bottom of the footer. HTML is supported. */
122
- copyright?: string;
123
- /** Opt-in footer tag index. Off by default. */
124
- taglist?: FooterTaglistConfig;
125
- }
126
-
127
- export interface HtmlPreviewConfig {
128
- /** Raw HTML injected into <head> (links, meta, fonts) */
129
- head?: string;
130
- /** CSS injected as <style> after preflight */
131
- css?: string;
132
- /** JS injected as <script> before </body> */
133
- js?: string;
134
- }
135
-
136
- export interface FrontmatterPreviewConfig {
137
- /**
138
- * Completely replaces the default ignore list.
139
- * When set, `extraIgnoreKeys` is ignored.
140
- */
141
- ignoreKeys?: string[];
142
- /**
143
- * Additional keys to ignore on top of the defaults.
144
- * Has no effect when `ignoreKeys` is also set.
145
- */
146
- extraIgnoreKeys?: string[];
147
- }
148
-
149
- export type TagPlacement = "after-title" | "before-pager";
150
-
151
- export type { TagGovernanceMode, TagVocabularyEntry } from "./tag-vocabulary-types";
152
-
153
- export interface VersionConfig {
154
- /** Version identifier, used in URL path (e.g., "1.0", "v1") */
155
- slug: string;
156
- /** Display label (e.g., "1.0.0", "Version 1") */
157
- label: string;
158
- /** Content directory for this version's English docs */
159
- docsDir: string;
160
- /** Per-locale content directories for this version */
161
- locales?: Record<string, { dir: string }>;
162
- /** Banner text shown on versioned pages (e.g., "unmaintained", "unreleased") */
163
- banner?: "unmaintained" | "unreleased" | false;
164
- }
165
-
166
- export interface MetaTagsConfig {
167
- /** Emit <meta name="description">. Default true. */
168
- description: boolean;
169
- /** Emit <meta name="keywords"> with a comma-separated string. false = omit. Default false. */
170
- keywords: string | false;
171
- /** og:image (and twitter:image) path. false = omit. Default false. Showcase: '/img/ogp.png'. */
172
- ogImage: string | false;
173
- /** Emit og:site_name. Default true (preserves current og:site_name). */
174
- ogSiteName: boolean;
175
- /** TwitterCard type. false = omit entire twitter:card block. Default false. Showcase: 'summary_large_image'. */
176
- twitterCard: "summary" | "summary_large_image" | false;
177
- /** twitter:site handle (e.g. '@yourbrand'). Optional. */
178
- twitterSite?: string;
179
- /** twitter:creator handle. Optional. */
180
- twitterCreator?: string;
181
- }
@@ -89,6 +89,27 @@
89
89
  * ======================================== */
90
90
 
91
91
  @theme {
92
+ /* ========================================
93
+ * Project tight-token color reset
94
+ *
95
+ * Wipes all Tailwind default color tokens (`--color-*`) so only
96
+ * project-defined palette and semantic tokens remain. This enforces the
97
+ * tight-token policy: "NEVER use Tailwind default colors" (per Color Rules
98
+ * in src/CLAUDE.md). Project color tokens (defined below) are added back
99
+ * after this reset.
100
+ *
101
+ * The upstream split-import fix (zfb#159 / 9e37551, shipped in f68a9ba)
102
+ * eliminated the original leak cause (zfb no longer prepends the full
103
+ * @import "tailwindcss" bundle). The reset is retained as an explicit
104
+ * design guardrail — it prevents accidental default palette bleed from any
105
+ * future upstream change and keeps the project's color surface intentional.
106
+ *
107
+ * NOT reset: `--spacing` (the base spacing scale, default 0.25rem).
108
+ * Tailwind spacing utilities compute as calc(var(--spacing) * N); wiping
109
+ * `--spacing` collapses them to zero (observed in Wave 4 Sub-7 #1403).
110
+ * ======================================== */
111
+ --color-*: initial;
112
+
92
113
  /* ========================================
93
114
  * Colors — Three-tier token system
94
115
  * ======================================== */
@@ -130,13 +151,19 @@
130
151
  --color-info: var(--zd-info);
131
152
  /* Overlay is intentionally theme-independent (always dark, not scheme-driven) */
132
153
  --color-overlay: #000;
154
+ /* The page-loading overlay scrim token is feature-gated: the dynamicPageTransition
155
+ feature injects it into @slot:global-css:theme-tokens when enabled, so it is
156
+ intentionally absent from this base @theme block (the host showcase global.css
157
+ carries it inline only because the host is fully featured). Do not re-add it here. */
133
158
  --color-image-overlay-bg: var(--zd-image-overlay-bg);
134
159
  --color-image-overlay-fg: var(--zd-image-overlay-fg);
135
- --color-mermaid-node-bg: var(--zd-mermaid-node-bg);
136
- --color-mermaid-text: var(--zd-mermaid-text);
137
- --color-mermaid-line: var(--zd-mermaid-line);
138
- --color-mermaid-label-bg: var(--zd-mermaid-label-bg);
139
- --color-mermaid-note-bg: var(--zd-mermaid-note-bg);
160
+ /* --color-mermaid-* aliases removed: mermaid-init-script.ts reads --zd-mermaid-* directly;
161
+ these @theme registrations were unused (no Tailwind utility references). --zd-mermaid-*
162
+ injection in color-scheme-utils.ts is preserved and remains the live source. */
163
+ --color-chat-user-bg: var(--zd-chat-user-bg);
164
+ --color-chat-user-text: var(--zd-chat-user-text);
165
+ --color-chat-assistant-bg: var(--zd-chat-assistant-bg);
166
+ --color-chat-assistant-text: var(--zd-chat-assistant-text);
140
167
  --color-matched-keyword-bg: var(--zd-matched-keyword-bg);
141
168
  --color-matched-keyword-fg: var(--zd-matched-keyword-fg);
142
169
  /* @slot:global-css:theme-tokens */
@@ -196,7 +223,7 @@
196
223
  --text-caption: var(--text-scale-xs); /* labels, timestamps */
197
224
  --text-small: var(--text-scale-sm); /* secondary text, nav items */
198
225
  --text-body: var(--text-scale-md); /* paragraphs, default */
199
- --text-title: var(--text-scale-lg); /* card titles, section labels */
226
+ --text-title: var(--text-scale-lg); /* card titles, section labels */
200
227
  --text-heading: var(--text-scale-xl); /* page headings */
201
228
  --text-display: var(--text-scale-2xl); /* hero text */
202
229
 
@@ -263,7 +290,7 @@
263
290
  /* GENERATED:Z_INDEX_END */
264
291
 
265
292
  :root {
266
- /* Default responsive range; sidebar-resizer.ts allows 192–448px for explicit resizing */
293
+ /* Default responsive range; sidebar-resizer.ts allows 192–448px for explicit resizing. */
267
294
  --zd-sidebar-w: clamp(14rem, 20vw, 22rem);
268
295
 
269
296
  /* ── Tier 1: Abstract font-size scale (raw values — NOT for direct component use) ── */
@@ -276,7 +303,7 @@
276
303
  --text-scale-xl: 3rem; /* 48px */
277
304
  --text-scale-2xl: 3.75rem; /* 60px */
278
305
 
279
- --default-transition-duration: 150ms; /* consumed by hash-link opacity fade */
306
+ --default-transition-duration: 150ms; /* consumed by image-enlarge and hash-link opacity fade */
280
307
  --zd-transition-slow: 200ms; /* sidebar transform/visibility and content-band max-width */
281
308
  --zd-transition-slower: 300ms; /* view-transition fade-in (contentFadeIn animation) */
282
309
  --zd-header-h: 80px; /* sticky header height; consumed by scroll-margin-top on [id] anchors */
@@ -30,7 +30,7 @@ import { DocLayoutWithDefaults } from "@takazudo/zudo-doc/doclayout";
30
30
  import type { JSX } from "preact";
31
31
  import type { VNode } from "preact";
32
32
  import { Island } from "@takazudo/zfb";
33
- import SiteTreeNav from "@/components/site-tree-nav";
33
+ import { SiteTreeNav } from "@takazudo/zudo-doc/site-tree-nav-island";
34
34
  import { resolveNavSource } from "../lib/_nav-source-docs";
35
35
  import { FooterWithDefaults } from "../lib/_footer-with-defaults";
36
36
  import { HeaderWithDefaults } from "../lib/_header-with-defaults";
@@ -1,61 +0,0 @@
1
- /** @jsxRuntime automatic */
2
- /** @jsxImportSource preact */
3
- // Page module for the 404 route.
4
- //
5
- // The 404 page is a static route with no dynamic params. zfb emits it as
6
- // dist/404.html so the host platform (Cloudflare Pages, Netlify, etc.) can
7
- // serve it for unmatched requests. No paths() export needed.
8
- //
9
- // The original Astro page rendered the full html/head/body inline without
10
- // DocLayout because the 404 page intentionally has no sidebar/TOC/header.
11
- // This port wraps via DocLayoutWithDefaults with hideSidebar/hideToc plus
12
- // a noindex meta so search engines do not index it.
13
-
14
- import { defaultLocale } from "@/config/i18n";
15
- import { settings } from "@/config/settings";
16
- import { withBase } from "@/utils/base";
17
- import { DocLayoutWithDefaults } from "@takazudo/zudo-doc/doclayout";
18
- import type { JSX } from "preact";
19
- import { FooterWithDefaults } from "./lib/_footer-with-defaults";
20
- import { HeaderWithDefaults } from "./lib/_header-with-defaults";
21
- import { HeadWithDefaults } from "./lib/_head-with-defaults";
22
- import { composeMetaTitle } from "./lib/_compose-meta-title";
23
- import { BodyEndIslands } from "./lib/_body-end-islands";
24
-
25
- export const frontmatter = { title: "404" };
26
-
27
- export default function NotFoundPage(): JSX.Element {
28
- const locale = defaultLocale;
29
- const title = "Page Not Found";
30
-
31
- return (
32
- <DocLayoutWithDefaults
33
- title={composeMetaTitle(title)}
34
- head={<HeadWithDefaults title={title} />}
35
- lang={locale}
36
- noindex={true}
37
- hideSidebar={true}
38
- hideToc={true}
39
- // Empty fragment suppresses DocLayoutWithDefaults' empty-data default
40
- // Sidebar island — its marker never hydrates for published-package
41
- // consumers (zfb#999) and zfb >= next.38 warns about it; the sidebar is
42
- // hidden on this page anyway (zudolab/zudo-doc#2057).
43
- sidebarOverride={<></>}
44
- headerOverride={<HeaderWithDefaults lang={locale} />}
45
- footerOverride={<FooterWithDefaults lang={locale} />}
46
- bodyEndComponents={<BodyEndIslands basePath={settings.base ?? "/"} />}
47
- enableClientRouter={settings.dynamicPageTransition}
48
- >
49
- <div class="min-h-[60vh] flex flex-col items-center justify-center px-hsp-2xl py-vsp-xl">
50
- <h1 class="text-display font-bold mb-vsp-md">404</h1>
51
- <p class="text-title text-muted mb-vsp-xl">Page not found.</p>
52
- <a
53
- href={withBase("/")}
54
- class="bg-accent px-hsp-lg py-vsp-xs font-medium text-bg hover:bg-accent-hover"
55
- >
56
- Back to Home
57
- </a>
58
- </div>
59
- </DocLayoutWithDefaults>
60
- );
61
- }
@@ -1,5 +0,0 @@
1
- import { renderRobots } from "@takazudo/zudo-doc/robots";
2
- import { settings } from "@/config/settings";
3
-
4
- export const contentType = "text/plain";
5
- export default () => renderRobots(settings);
@@ -1,59 +0,0 @@
1
- // Port of `src/integrations/sitemap.ts` onto zfb's pages-style filename
2
- // convention.
3
- //
4
- // Filename → output extension mapping (zfb convention): the
5
- // second-to-last `.`-separated segment of the stem becomes the output
6
- // extension, so `sitemap.xml.tsx` builds `dist/sitemap.xml`. The
7
- // explicit `contentType` export pins the dev-server `Content-Type`
8
- // header to `application/xml` regardless of the filename hint.
9
- //
10
- // URL enumeration is delegated to `pages/lib/route-enumerators.ts` so
11
- // the sitemap cannot drift from the actual routes the page modules build.
12
- // Previously the sitemap walked raw collection slugs directly and missed:
13
- // (a) tag pages (b) JA fallback URLs
14
- // (c) versioned JA routes (d) wrong URL pattern for versioned-locale pages
15
- // (e) emitted /index/ suffix on category pages (closes #690)
16
-
17
- import { settings } from "@/config/settings";
18
- import { enumerateAllRoutes } from "./lib/route-enumerators";
19
-
20
- export const frontmatter = { title: "Sitemap" };
21
- export const contentType = "application/xml";
22
-
23
- function escapeXml(str: string): string {
24
- return str
25
- .replace(/&/g, "&amp;")
26
- .replace(/</g, "&lt;")
27
- .replace(/>/g, "&gt;")
28
- .replace(/"/g, "&quot;")
29
- .replace(/'/g, "&apos;");
30
- }
31
-
32
- export default function Sitemap(): string {
33
- // When sitemap is disabled, return an empty urlset so the route still
34
- // resolves (returns XML, not 404) but contains no URLs.
35
- if (!settings.sitemap) {
36
- return `<?xml version="1.0" encoding="UTF-8"?>
37
- <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
38
- </urlset>`;
39
- }
40
-
41
- const routeMap = enumerateAllRoutes();
42
- const siteUrlBase = (settings.siteUrl ?? "").replace(/\/$/, "");
43
-
44
- const urlEntries = [...routeMap.entries()]
45
- .sort(([a], [b]) => a.localeCompare(b))
46
- .map(
47
- ([url, lastmod]) => ` <url>
48
- <loc>${escapeXml(siteUrlBase + url)}</loc>
49
- <lastmod>${lastmod}</lastmod>
50
- </url>`,
51
- )
52
- .join("\n");
53
-
54
- return `<?xml version="1.0" encoding="UTF-8"?>
55
- <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
56
- ${urlEntries}
57
- </urlset>
58
- `;
59
- }