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
|
@@ -7,7 +7,9 @@ import { useState, useCallback, useEffect, useMemo, useRef } from "preact/hooks"
|
|
|
7
7
|
import type { NavNode } from "@/utils/docs";
|
|
8
8
|
import type { LocaleLink } from "@/types/locale";
|
|
9
9
|
import { INDENT, BASE_PAD, connectorLeft, ConnectorLines, CategoryLinkIcon } from "./tree-nav-shared";
|
|
10
|
-
|
|
10
|
+
// BARE ThemeToggle (#2012 E2) — this footer toggle renders inside the
|
|
11
|
+
// SidebarToggle island, so it must NOT bring its own island wrapper.
|
|
12
|
+
import { ThemeToggle } from "@takazudo/zudo-doc/theme-toggle";
|
|
11
13
|
import { smartBreakToHtml } from "@/utils/smart-break";
|
|
12
14
|
|
|
13
15
|
function ToggleChevron({ isExpanded, className }: { isExpanded: boolean; className?: string }) {
|
|
@@ -61,7 +63,9 @@ function findActiveSlug(nodes: NavNode[], pathname: string): string | undefined
|
|
|
61
63
|
for (const node of nodes) {
|
|
62
64
|
if (node.href && normalizePath(node.href) === pathname) return node.slug;
|
|
63
65
|
const found = findActiveSlug(node.children, pathname);
|
|
64
|
-
|
|
66
|
+
// "" is the canonical root-index slug (#1891) — a truthiness check
|
|
67
|
+
// would discard a legitimate root match.
|
|
68
|
+
if (found !== undefined) return found;
|
|
65
69
|
}
|
|
66
70
|
return undefined;
|
|
67
71
|
}
|
|
@@ -246,8 +250,10 @@ export default function SidebarTree({ nodes, currentSlug, rootMenuItems, backToM
|
|
|
246
250
|
}
|
|
247
251
|
|
|
248
252
|
// Top page: show only header nav links, no doc tree or filter.
|
|
249
|
-
// Derived from activeSlug (runtime-synced) so it stays correct across View
|
|
250
|
-
|
|
253
|
+
// Derived from activeSlug (runtime-synced) so it stays correct across View
|
|
254
|
+
// Transitions. Must be an undefined check, not truthiness: "" is the
|
|
255
|
+
// canonical root-index doc slug (#1891) and gets the full tree.
|
|
256
|
+
if (activeSlug === undefined && rootMenuItems) {
|
|
251
257
|
return (
|
|
252
258
|
<nav>
|
|
253
259
|
{rootMenuItems.map((item) => (
|
|
@@ -282,7 +288,7 @@ export default function SidebarTree({ nodes, currentSlug, rootMenuItems, backToM
|
|
|
282
288
|
type="text"
|
|
283
289
|
placeholder={filterPlaceholder}
|
|
284
290
|
value={query}
|
|
285
|
-
onChange={(e) => setQuery(e.
|
|
291
|
+
onChange={(e) => setQuery(e.currentTarget.value)}
|
|
286
292
|
className="bg-transparent text-small outline-none w-full text-fg placeholder:text-muted"
|
|
287
293
|
/>
|
|
288
294
|
</div>
|
|
@@ -1,107 +1,23 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
fill="none"
|
|
19
|
-
stroke="currentColor"
|
|
20
|
-
strokeWidth="2"
|
|
21
|
-
strokeLinecap="round"
|
|
22
|
-
strokeLinejoin="round"
|
|
23
|
-
>
|
|
24
|
-
<circle cx="12" cy="12" r="5" />
|
|
25
|
-
<line x1="12" y1="1" x2="12" y2="3" />
|
|
26
|
-
<line x1="12" y1="21" x2="12" y2="23" />
|
|
27
|
-
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64" />
|
|
28
|
-
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78" />
|
|
29
|
-
<line x1="1" y1="12" x2="3" y2="12" />
|
|
30
|
-
<line x1="21" y1="12" x2="23" y2="12" />
|
|
31
|
-
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36" />
|
|
32
|
-
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22" />
|
|
33
|
-
</svg>
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function MoonIcon() {
|
|
38
|
-
return (
|
|
39
|
-
<svg
|
|
40
|
-
aria-hidden="true"
|
|
41
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
42
|
-
width="20"
|
|
43
|
-
height="20"
|
|
44
|
-
viewBox="0 0 24 24"
|
|
45
|
-
fill="none"
|
|
46
|
-
stroke="currentColor"
|
|
47
|
-
strokeWidth="2"
|
|
48
|
-
strokeLinecap="round"
|
|
49
|
-
strokeLinejoin="round"
|
|
50
|
-
>
|
|
51
|
-
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" />
|
|
52
|
-
</svg>
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
interface ThemeToggleProps {
|
|
57
|
-
defaultMode?: "light" | "dark";
|
|
3
|
+
// Scanner-visible ThemeToggle shim. zfb's island scanner does not register
|
|
4
|
+
// "use client" modules located under node_modules (Takazudo/zudo-front-builder#999),
|
|
5
|
+
// so importing the package ThemeToggle straight into the server-rendered header
|
|
6
|
+
// emits an island marker with no matching registry entry — the toggle renders
|
|
7
|
+
// but never hydrates, on every page (zudolab/zudo-doc#2048). This thin
|
|
8
|
+
// project-source wrapper gives the scanner a local binding to register; it
|
|
9
|
+
// re-wraps the bare (non-island-wrapped) package component unchanged.
|
|
10
|
+
import type { JSX } from "preact";
|
|
11
|
+
import {
|
|
12
|
+
ThemeToggle as ZudoDocThemeToggle,
|
|
13
|
+
type ThemeToggleProps,
|
|
14
|
+
} from "@takazudo/zudo-doc/theme-toggle";
|
|
15
|
+
|
|
16
|
+
export function ThemeToggle(props: ThemeToggleProps): JSX.Element {
|
|
17
|
+
return <ZudoDocThemeToggle {...props} />;
|
|
58
18
|
}
|
|
19
|
+
ThemeToggle.displayName = "ThemeToggle";
|
|
59
20
|
|
|
60
|
-
export
|
|
61
|
-
// Initial state must match server render to avoid hydration mismatch.
|
|
62
|
-
// Actual theme is synced from DOM in useEffect below.
|
|
63
|
-
const [mode, setMode] = useState<"light" | "dark">(defaultMode);
|
|
64
|
-
|
|
65
|
-
useEffect(() => {
|
|
66
|
-
const actual =
|
|
67
|
-
(document.documentElement.getAttribute("data-theme") as
|
|
68
|
-
| "light"
|
|
69
|
-
| "dark") || defaultMode;
|
|
70
|
-
if (actual !== mode) {
|
|
71
|
-
setMode(actual);
|
|
72
|
-
}
|
|
73
|
-
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
|
74
|
-
|
|
75
|
-
function toggle() {
|
|
76
|
-
const next = mode === "dark" ? "light" : "dark";
|
|
77
|
-
setMode(next);
|
|
78
|
-
document.documentElement.setAttribute("data-theme", next);
|
|
79
|
-
document.documentElement.style.colorScheme = next;
|
|
80
|
-
localStorage.setItem(STORAGE_KEY, next);
|
|
81
|
-
// Clear both v1 and v2 tweak state so the new scheme's palette takes effect.
|
|
82
|
-
localStorage.removeItem("zudo-doc-tweak-state");
|
|
83
|
-
localStorage.removeItem("zudo-doc-tweak-state-v2");
|
|
84
|
-
window.dispatchEvent(new CustomEvent("color-scheme-changed"));
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const nextMode = mode === "dark" ? "light" : "dark";
|
|
21
|
+
export type { ThemeToggleProps };
|
|
88
22
|
|
|
89
|
-
|
|
90
|
-
<button
|
|
91
|
-
onClick={toggle}
|
|
92
|
-
aria-label={`Switch to ${nextMode} mode`}
|
|
93
|
-
className="text-muted hover:text-fg transition-colors p-hsp-sm focus-visible:outline-2 focus-visible:outline-accent focus-visible:outline-offset-2"
|
|
94
|
-
>
|
|
95
|
-
{mode === "dark" ? <SunIcon /> : <MoonIcon />}
|
|
96
|
-
</button>
|
|
97
|
-
);
|
|
98
|
-
}
|
|
99
|
-
// Pin the island marker name to "ThemeToggle" regardless of esbuild's
|
|
100
|
-
// identifier deduplication. Both this host component and the v2 package's
|
|
101
|
-
// ThemeToggleInner share the plain name "ThemeToggle"; when both land in the
|
|
102
|
-
// same SSR bundle esbuild renames one to "ThemeToggle2", making
|
|
103
|
-
// captureComponentName() emit "ThemeToggle2" — a name that has no entry in
|
|
104
|
-
// the island manifest. Setting displayName explicitly ensures Island() reads
|
|
105
|
-
// the attribute-level name (displayName is preferred over .name) and emits
|
|
106
|
-
// the correct data-zfb-island="ThemeToggle" marker. zudolab/zudo-doc#1446.
|
|
107
|
-
ThemeToggle.displayName = "ThemeToggle";
|
|
23
|
+
export default ThemeToggle;
|
|
@@ -11,6 +11,10 @@ export interface ColorScheme {
|
|
|
11
11
|
string, string, string, string, string, string, string, string,
|
|
12
12
|
string, string, string, string, string, string, string, string,
|
|
13
13
|
];
|
|
14
|
+
/** Optional Shiki theme for the zdtp panel's client-side code-block preview.
|
|
15
|
+
* Falls back to the panel config's DEFAULT_SHIKI_THEME when omitted.
|
|
16
|
+
* Static highlighting (syntect via zfb's Rust pipeline) is unaffected. */
|
|
17
|
+
shikiTheme?: string;
|
|
14
18
|
/** Optional semantic overrides — when omitted, defaults are used:
|
|
15
19
|
* surface=p0, muted=p8, accent=p5, accentHover=p14
|
|
16
20
|
* codeBg=p10, codeFg=p11, success=p2, danger=p1, warning=p3, info=p4
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { settings } from "./settings";
|
|
3
|
+
import { tagVocabulary } from "./tag-vocabulary";
|
|
4
|
+
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// Tags schema builder — governance-aware.
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Build the `tags` schema based on governance mode. `"strict"` tightens to a
|
|
11
|
+
* `z.enum` of every canonical id plus every alias (content still uses
|
|
12
|
+
* aliases verbatim — resolution happens at the aggregation layer, after
|
|
13
|
+
* parsing).
|
|
14
|
+
*/
|
|
15
|
+
function buildTagsSchema() {
|
|
16
|
+
const vocabularyActive =
|
|
17
|
+
settings.tagVocabulary && settings.tagGovernance === "strict";
|
|
18
|
+
if (!vocabularyActive) return z.array(z.string()).optional();
|
|
19
|
+
const allowed = new Set<string>();
|
|
20
|
+
for (const entry of tagVocabulary) {
|
|
21
|
+
allowed.add(entry.id);
|
|
22
|
+
for (const alias of entry.aliases ?? []) allowed.add(alias);
|
|
23
|
+
}
|
|
24
|
+
const allowedList = [...allowed];
|
|
25
|
+
if (allowedList.length === 0) return z.array(z.string()).optional();
|
|
26
|
+
const [first, ...rest] = allowedList;
|
|
27
|
+
return z
|
|
28
|
+
.array(z.enum([first, ...rest] as [string, ...string[]]))
|
|
29
|
+
.optional();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// Schema builder — single source of truth for the docs frontmatter shape.
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Build the docs frontmatter zod schema.
|
|
38
|
+
*
|
|
39
|
+
* Returns a single `z.object(...).passthrough()` that is reused for every
|
|
40
|
+
* docs collection (default + per-locale + per-version + per-version-per-locale).
|
|
41
|
+
* The `tags` field is governance-aware: `buildTagsSchema()` returns a plain
|
|
42
|
+
* `z.array(z.string())` when governance is off, or a restricted `z.enum`
|
|
43
|
+
* when `tagGovernance: "strict"` + `tagVocabulary` is configured.
|
|
44
|
+
*
|
|
45
|
+
* `.passthrough()` keeps custom frontmatter keys (e.g. `author`, `status`)
|
|
46
|
+
* available downstream — the frontmatter-preview UI relies on this to
|
|
47
|
+
* surface arbitrary keys without declaring each one here.
|
|
48
|
+
*/
|
|
49
|
+
export function buildDocsSchema() {
|
|
50
|
+
return z
|
|
51
|
+
.object({
|
|
52
|
+
title: z.string(),
|
|
53
|
+
description: z.string().optional(),
|
|
54
|
+
category: z.string().optional(),
|
|
55
|
+
sidebar_position: z.number().optional(),
|
|
56
|
+
sidebar_label: z.string().optional(),
|
|
57
|
+
tags: buildTagsSchema(),
|
|
58
|
+
search_exclude: z.boolean().optional(),
|
|
59
|
+
pagination_next: z.string().nullable().optional(),
|
|
60
|
+
pagination_prev: z.string().nullable().optional(),
|
|
61
|
+
draft: z.boolean().optional(),
|
|
62
|
+
unlisted: z.boolean().optional(),
|
|
63
|
+
hide_sidebar: z.boolean().optional(),
|
|
64
|
+
hide_toc: z.boolean().optional(),
|
|
65
|
+
doc_history: z.boolean().optional(),
|
|
66
|
+
standalone: z.boolean().optional(),
|
|
67
|
+
slug: z.string().optional(),
|
|
68
|
+
generated: z.boolean().optional(),
|
|
69
|
+
// Category metadata expressed as a directory index.mdx's frontmatter — the
|
|
70
|
+
// frontmatter form of `_category_.json`. `category_no_page` makes the index
|
|
71
|
+
// a non-linked sidebar header excluded from routes/sitemap/search;
|
|
72
|
+
// `category_sort_order` sets the child sort direction. Frontmatter wins
|
|
73
|
+
// over the sidecar.
|
|
74
|
+
category_no_page: z.boolean().optional(),
|
|
75
|
+
category_sort_order: z.enum(["asc", "desc"]).optional(),
|
|
76
|
+
})
|
|
77
|
+
.passthrough();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
// Inferred type — single source of truth for the docs data shape.
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* TypeScript type inferred from the docs frontmatter zod schema.
|
|
86
|
+
*
|
|
87
|
+
* Import this type instead of hand-writing the field list in `pages/_data.ts`
|
|
88
|
+
* (`ZfbDocsData`) or `src/types/docs-entry.ts` (`DocsEntry.data`).
|
|
89
|
+
*
|
|
90
|
+
* The `[key: string]: unknown` index signature from `.passthrough()` is
|
|
91
|
+
* naturally present via `z.infer` — custom frontmatter keys remain accessible
|
|
92
|
+
* downstream (e.g. frontmatter-preview) without extra casting.
|
|
93
|
+
*/
|
|
94
|
+
export type DocsData = z.infer<ReturnType<typeof buildDocsSchema>>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { settings } from "./settings";
|
|
2
|
+
import type { LocaleConfig } from "./settings-types";
|
|
2
3
|
|
|
3
4
|
// Collection name string used by zfb's content engine (`getCollection(...)`).
|
|
4
5
|
// Kept as a structural string-literal alias so callers don't have to redeclare
|
|
@@ -15,9 +16,9 @@ export const locales = [
|
|
|
15
16
|
] as const;
|
|
16
17
|
export type Locale = (typeof locales)[number];
|
|
17
18
|
|
|
18
|
-
/** Safely look up a locale in settings.locales. */
|
|
19
|
-
function getLocaleConfig(locale: string) {
|
|
20
|
-
return settings.locales[locale];
|
|
19
|
+
/** Safely look up a locale in settings.locales by string key. */
|
|
20
|
+
export function getLocaleConfig(locale: string): LocaleConfig | undefined {
|
|
21
|
+
return (settings.locales as Record<string, LocaleConfig | undefined>)[locale];
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
/** Get the content directory for a locale. */
|
|
@@ -70,6 +71,8 @@ const translations: Record<string, Record<string, string>> = {
|
|
|
70
71
|
"toc.title": "On this page",
|
|
71
72
|
"docs.browseAll": "Browse all documentation sections.",
|
|
72
73
|
"search.label": "Search",
|
|
74
|
+
"search.placeholder": "Type to search...",
|
|
75
|
+
"search.shortcutHint": "to open search from anywhere",
|
|
73
76
|
"search.resultCount": "{count} results",
|
|
74
77
|
"code.copy": "Copy code",
|
|
75
78
|
"code.copied": "Copied!",
|
|
@@ -128,6 +131,8 @@ const translations: Record<string, Record<string, string>> = {
|
|
|
128
131
|
"toc.title": "目次",
|
|
129
132
|
"docs.browseAll": "すべてのドキュメントセクションを閲覧",
|
|
130
133
|
"search.label": "検索",
|
|
134
|
+
"search.placeholder": "検索したい単語を入力",
|
|
135
|
+
"search.shortcutHint": "いつでも検索バーを開ける",
|
|
131
136
|
"search.resultCount": "{count} 件",
|
|
132
137
|
"code.copy": "コードをコピー",
|
|
133
138
|
"code.copied": "コピーしました!",
|
|
@@ -186,6 +191,8 @@ const translations: Record<string, Record<string, string>> = {
|
|
|
186
191
|
"toc.title": "Auf dieser Seite",
|
|
187
192
|
"docs.browseAll": "Alle Dokumentationsabschnitte durchsuchen.",
|
|
188
193
|
"search.label": "Suche",
|
|
194
|
+
"search.placeholder": "Suchbegriff eingeben...",
|
|
195
|
+
"search.shortcutHint": "Suche von überall öffnen",
|
|
189
196
|
"search.resultCount": "{count} Ergebnisse",
|
|
190
197
|
"code.copy": "Code kopieren",
|
|
191
198
|
"code.copied": "Kopiert!",
|
|
@@ -1002,6 +1002,20 @@ pre[class^="syntect-"] .line .highlighted-word {
|
|
|
1002
1002
|
html[data-sidebar-hidden] .zd-sidebar-content-wrapper {
|
|
1003
1003
|
margin-left: 0;
|
|
1004
1004
|
}
|
|
1005
|
+
|
|
1006
|
+
/* When hidden via the toggle, narrow the content band to the
|
|
1007
|
+
* hide_sidebar frontmatter width so it centers (the flex parent already
|
|
1008
|
+
* applies justify-content: center) instead of leaving a dead gap where
|
|
1009
|
+
* the sidebar was. 80rem must match the `max-w-[80rem]` hide_sidebar
|
|
1010
|
+
* branch in doc-layout.tsx. These rules are unlayered, so they win over
|
|
1011
|
+
* the Tailwind `max-w-[clamp(...)]` utility (utilities layer). (#2002) */
|
|
1012
|
+
.zd-doc-content-band {
|
|
1013
|
+
transition: max-width 200ms ease-in-out;
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
html[data-sidebar-hidden] .zd-doc-content-band {
|
|
1017
|
+
max-width: 80rem;
|
|
1018
|
+
}
|
|
1005
1019
|
}
|
|
1006
1020
|
|
|
1007
1021
|
/* Sidebar toggle button — left position uses CSS variable, needs global rule */
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { DocsData } from "@/config/docs-schema";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Concrete entry type for docs collections.
|
|
3
5
|
*
|
|
@@ -6,6 +8,9 @@
|
|
|
6
8
|
* but is defined locally now that the project runs on the zfb content
|
|
7
9
|
* engine — collection-name-specific generics are not exposed by zfb, so
|
|
8
10
|
* pages cast collection entries to this shape via `pages/_data.ts`.
|
|
11
|
+
*
|
|
12
|
+
* `data` is typed as `DocsData` — the `z.infer`-derived type from
|
|
13
|
+
* `src/config/docs-schema.ts` — so the field set is maintained in one place.
|
|
9
14
|
*/
|
|
10
15
|
// Structural shape of zfb's optional rendered-content payload for a doc
|
|
11
16
|
// entry (kept loose to stay engine-agnostic — pages do not rely on the
|
|
@@ -13,34 +18,11 @@
|
|
|
13
18
|
type RenderedContent = unknown;
|
|
14
19
|
export interface DocsEntry {
|
|
15
20
|
id: string;
|
|
21
|
+
/** zfb content engine slug (filename without `.md`/`.mdx`; used by toRouteSlug). */
|
|
22
|
+
slug: string;
|
|
16
23
|
body?: string;
|
|
17
24
|
collection: string;
|
|
18
|
-
data:
|
|
19
|
-
title: string;
|
|
20
|
-
description?: string;
|
|
21
|
-
category?: string;
|
|
22
|
-
sidebar_position?: number;
|
|
23
|
-
sidebar_label?: string;
|
|
24
|
-
tags?: string[];
|
|
25
|
-
search_exclude?: boolean;
|
|
26
|
-
pagination_next?: string | null;
|
|
27
|
-
pagination_prev?: string | null;
|
|
28
|
-
draft?: boolean;
|
|
29
|
-
unlisted?: boolean;
|
|
30
|
-
hide_sidebar?: boolean;
|
|
31
|
-
hide_toc?: boolean;
|
|
32
|
-
doc_history?: boolean;
|
|
33
|
-
standalone?: boolean;
|
|
34
|
-
slug?: string;
|
|
35
|
-
generated?: boolean;
|
|
36
|
-
/** Category metadata on a directory's index.mdx (frontmatter form of
|
|
37
|
-
* `_category_.json` `noPage`): non-linked sidebar header + excluded from
|
|
38
|
-
* routes/sitemap/search. Frontmatter wins over the sidecar. */
|
|
39
|
-
category_no_page?: boolean;
|
|
40
|
-
/** Frontmatter form of `_category_.json` `sortOrder` — child sort
|
|
41
|
-
* direction. Frontmatter wins over the sidecar. */
|
|
42
|
-
category_sort_order?: "asc" | "desc";
|
|
43
|
-
};
|
|
25
|
+
data: DocsData;
|
|
44
26
|
rendered?: RenderedContent;
|
|
45
27
|
filePath?: string;
|
|
46
28
|
}
|
|
@@ -37,8 +37,10 @@ export function withBase(path: string): string {
|
|
|
37
37
|
/** Strip the base prefix from a URL pathname. */
|
|
38
38
|
export function stripBase(path: string): string {
|
|
39
39
|
if (normalizedBase === "") return path;
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
// Require a segment boundary so base "/app" doesn't strip "/application/...".
|
|
41
|
+
if (path === normalizedBase) return "/";
|
|
42
|
+
return path.startsWith(`${normalizedBase}/`)
|
|
43
|
+
? path.slice(normalizedBase.length)
|
|
42
44
|
: path;
|
|
43
45
|
}
|
|
44
46
|
|
|
@@ -55,7 +57,7 @@ export function absoluteUrl(pageUrl: string): string | undefined {
|
|
|
55
57
|
}
|
|
56
58
|
|
|
57
59
|
/** Build a docs URL for the given slug and lang. */
|
|
58
|
-
export function docsUrl(slug: string, lang: Locale = defaultLocale): string {
|
|
60
|
+
export function docsUrl(slug: string, lang: Locale | string = defaultLocale): string {
|
|
59
61
|
const path = lang === defaultLocale ? `/docs/${slug}` : `/${lang}/docs/${slug}`;
|
|
60
62
|
return withBase(path);
|
|
61
63
|
}
|