create-zudo-doc 0.2.17 → 0.2.19

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.
@@ -2,10 +2,20 @@ import type { FeatureModule } from "../compose.js";
2
2
  /**
3
3
  * Dynamic page transition feature.
4
4
  *
5
- * When enabled, wires the SPA client-side router (ClientRouterBootstrap
6
- * island) and the page-loading overlay (PageLoadingOverlay, pure SSR) into
7
- * body-end-islands, and injects the View-Transitions CSS + page-loading
8
- * overlay CSS into global.css.
5
+ * When enabled:
6
+ * - Sets `enableClientRouter={settings.dynamicPageTransition}` on every
7
+ * `<DocLayoutWithDefaults>` render site the SSR `<ClientRouter />` render
8
+ * self-activates the SPA router on the client as a top-level module side
9
+ * effect (primary activation path).
10
+ * - Wires the ClientRouterBootstrap island and the PageLoadingOverlay (pure
11
+ * SSR) into body-end-islands — the island is now a redundant fallback;
12
+ * PageLoadingOverlay provides the loading spinner UI.
13
+ * - Injects `@import "@takazudo/zudo-doc/page-loading.css"` at the
14
+ * `@slot:global-css:imports` anchor (top of global.css, before rule blocks).
15
+ * - Injects the `--color-page-loading-overlay` token into `@theme` at the
16
+ * `@slot:global-css:theme-tokens` anchor.
17
+ * - Injects the View-Transitions CSS into global.css at
18
+ * `@slot:global-css:feature-styles`.
9
19
  *
10
20
  * Bug fix (#2265): the page-loading overlay CSS (.page-loading-overlay /
11
21
  * .page-loading-spinner / @keyframes page-loading-spin / [data-zd-nav-pending])
@@ -13,6 +23,12 @@ import type { FeatureModule } from "../compose.js";
13
23
  * the host global.css but had no corresponding injection for the template.
14
24
  * Gating this feature makes both the JS island and the CSS land together.
15
25
  *
26
+ * The page-loading CSS now ships as a package artifact
27
+ * `@takazudo/zudo-doc/page-loading.css` (Topic A, #2283) — the generator
28
+ * injects a gated `@import` instead of inline rule bodies. The
29
+ * `--color-page-loading-overlay` token is defined inline (inside `@theme`) so
30
+ * it lives alongside the other project tokens and can be overridden per-project.
31
+ *
16
32
  * The ClientRouterBootstrap component lives in
17
33
  * templates/features/dynamicPageTransition/files/src/components/ and is
18
34
  * byte-identical to the host src/components/client-router-bootstrap.tsx.
@@ -1,10 +1,20 @@
1
1
  /**
2
2
  * Dynamic page transition feature.
3
3
  *
4
- * When enabled, wires the SPA client-side router (ClientRouterBootstrap
5
- * island) and the page-loading overlay (PageLoadingOverlay, pure SSR) into
6
- * body-end-islands, and injects the View-Transitions CSS + page-loading
7
- * overlay CSS into global.css.
4
+ * When enabled:
5
+ * - Sets `enableClientRouter={settings.dynamicPageTransition}` on every
6
+ * `<DocLayoutWithDefaults>` render site the SSR `<ClientRouter />` render
7
+ * self-activates the SPA router on the client as a top-level module side
8
+ * effect (primary activation path).
9
+ * - Wires the ClientRouterBootstrap island and the PageLoadingOverlay (pure
10
+ * SSR) into body-end-islands — the island is now a redundant fallback;
11
+ * PageLoadingOverlay provides the loading spinner UI.
12
+ * - Injects `@import "@takazudo/zudo-doc/page-loading.css"` at the
13
+ * `@slot:global-css:imports` anchor (top of global.css, before rule blocks).
14
+ * - Injects the `--color-page-loading-overlay` token into `@theme` at the
15
+ * `@slot:global-css:theme-tokens` anchor.
16
+ * - Injects the View-Transitions CSS into global.css at
17
+ * `@slot:global-css:feature-styles`.
8
18
  *
9
19
  * Bug fix (#2265): the page-loading overlay CSS (.page-loading-overlay /
10
20
  * .page-loading-spinner / @keyframes page-loading-spin / [data-zd-nav-pending])
@@ -12,6 +22,12 @@
12
22
  * the host global.css but had no corresponding injection for the template.
13
23
  * Gating this feature makes both the JS island and the CSS land together.
14
24
  *
25
+ * The page-loading CSS now ships as a package artifact
26
+ * `@takazudo/zudo-doc/page-loading.css` (Topic A, #2283) — the generator
27
+ * injects a gated `@import` instead of inline rule bodies. The
28
+ * `--color-page-loading-overlay` token is defined inline (inside `@theme`) so
29
+ * it lives alongside the other project tokens and can be overridden per-project.
30
+ *
15
31
  * The ClientRouterBootstrap component lives in
16
32
  * templates/features/dynamicPageTransition/files/src/components/ and is
17
33
  * byte-identical to the host src/components/client-router-bootstrap.tsx.
@@ -64,7 +80,28 @@ import { PageLoadingOverlay } from "@takazudo/zudo-doc/page-loading";`,
64
80
  </>
65
81
  ) : null}`,
66
82
  },
67
- // 4. View-Transitions CSS (chrome extraction + cross-fade + reduced motion).
83
+ // 4. Page-loading CSS import gated at the top-of-file imports anchor.
84
+ // `@import` must precede rule blocks in CSS; the `@slot:global-css:imports`
85
+ // anchor sits immediately after the content.css import line so this lands
86
+ // in a legal position. The CSS itself (overlay, spinner, keyframes) now
87
+ // ships as a package artifact `@takazudo/zudo-doc/page-loading.css`
88
+ // (see #2283 — Topic A) instead of being duplicated inline here.
89
+ {
90
+ file: "src/styles/global.css",
91
+ anchor: "/* @slot:global-css:imports */",
92
+ position: "after",
93
+ content: `@import "@takazudo/zudo-doc/page-loading.css";`,
94
+ },
95
+ // 5. `--color-page-loading-overlay` token — injected inside `@theme`.
96
+ // Defined here so each scaffolded project can override it per-project.
97
+ // Uses the same `--color-overlay` base token as the dialog backdrops.
98
+ {
99
+ file: "src/styles/global.css",
100
+ anchor: "/* @slot:global-css:theme-tokens */",
101
+ position: "after",
102
+ content: `--color-page-loading-overlay: color-mix(in oklch, var(--color-overlay) 60%, transparent);`,
103
+ },
104
+ // 6. View-Transitions CSS (chrome extraction + cross-fade + reduced motion).
68
105
  // Injected AFTER `/* @slot:global-css:feature-styles */` in global.css.
69
106
  // These rules are required for SPA page transitions via ClientRouter.
70
107
  {
@@ -173,67 +210,6 @@ import { PageLoadingOverlay } from "@takazudo/zudo-doc/page-loading";`,
173
210
  ::view-transition-new(zfb-sidebar-toggle):only-child {
174
211
  animation: none;
175
212
  }
176
- }
177
-
178
- /* Page-loading overlay CSS — moved out of PageLoadingOverlay's inline
179
- * <style> block to avoid the <style>-inside-<body> HTML5 content-model
180
- * violation flagged by html-validate (same pattern as version-switcher
181
- * fix in zudolab/zudo-doc#1505; see W2A confirm zudolab/zudo-doc#1543). */
182
- .page-loading-overlay {
183
- position: fixed;
184
- inset: 0;
185
- /* Full-screen blocking load overlay — modal tier (was a raw z-index:9999).
186
- It sits below the transient \`drag\` tier (sidebar-resizer ghost), which is
187
- fine: a full page-load overlay and an active pointer-drag never coexist. */
188
- z-index: var(--z-index-modal);
189
- display: flex;
190
- align-items: center;
191
- justify-content: center;
192
- background: color-mix(in oklch, var(--color-overlay) 60%, transparent);
193
- opacity: 0;
194
- pointer-events: none;
195
- transition: opacity 150ms ease-out;
196
- }
197
-
198
- .page-loading-overlay[data-visible] {
199
- opacity: 1;
200
- }
201
-
202
- a[data-zd-nav-pending],
203
- button[data-zd-nav-pending] {
204
- color: var(--color-accent);
205
- }
206
-
207
- .page-loading-spinner {
208
- width: 48px;
209
- height: 48px;
210
- border: 5px solid var(--color-fg, #fff);
211
- border-bottom-color: transparent;
212
- border-radius: 50%;
213
- display: inline-block;
214
- box-sizing: border-box;
215
- animation: page-loading-spin 1s linear infinite;
216
- }
217
-
218
- @media (min-width: 1024px) {
219
- .page-loading-spinner {
220
- width: 64px;
221
- height: 64px;
222
- border-width: 6px;
223
- }
224
- }
225
-
226
- @keyframes page-loading-spin {
227
- 0% { transform: rotate(0deg); }
228
- 100% { transform: rotate(360deg); }
229
- }
230
-
231
- @media (prefers-reduced-motion: reduce) {
232
- .page-loading-spinner {
233
- animation: none;
234
- border-bottom-color: var(--color-fg, #fff);
235
- opacity: 0.5;
236
- }
237
213
  }`,
238
214
  },
239
215
  ],
package/dist/scaffold.js CHANGED
@@ -340,7 +340,8 @@ export async function scaffold(choices) {
340
340
  }
341
341
  function generatePackageJson(choices) {
342
342
  // Intentionally absent from scaffolded deps:
343
- // @takazudo/zudo-doc-md-plugins — zero references in generator templates/source
343
+ // @takazudo/zudo-doc-md-plugins — private fixture/parity-test asset; not published,
344
+ // not for app import. Zero references in generator templates/source.
344
345
  const deps = {
345
346
  // zfb engine — distributed as published npm packages (the prebuilt binary
346
347
  // ships via an optionalDependency of @takazudo/zfb-<platform>); pinned to
@@ -447,11 +448,11 @@ function generatePackageJson(choices) {
447
448
  // stability, multi-valued response headers (e.g. multiple Set-Cookie),
448
449
  // supplementary-plane CJK reading-time, plus CLI/server/runtime hardening
449
450
  // and render perf passes. No consumer-facing / CLI breaking change.
450
- "@takazudo/zfb": "0.1.0-next.55",
451
- "@takazudo/zfb-runtime": "0.1.0-next.55",
451
+ "@takazudo/zfb": "0.1.0-next.57",
452
+ "@takazudo/zfb-runtime": "0.1.0-next.57",
452
453
  // zfb-adapter-cloudflare — required for any route with `prerender = false`.
453
454
  // Pinned in lockstep with @takazudo/zfb.
454
- "@takazudo/zfb-adapter-cloudflare": "0.1.0-next.55",
455
+ "@takazudo/zfb-adapter-cloudflare": "0.1.0-next.57",
455
456
  // @takazudo/zudo-doc — published from this monorepo via
456
457
  // .github/workflows/publish-zudo-doc.yml. The pin here is bumped in
457
458
  // lockstep by scripts/release-create-zudo-doc.sh whenever zudo-doc's
@@ -463,7 +464,7 @@ function generatePackageJson(choices) {
463
464
  // ties this pin to packages/zudo-doc's version, so the lockstep release
464
465
  // bumps both together; do not cut a create-zudo-doc release until the
465
466
  // matching @takazudo/zudo-doc version (with content.css) is on npm.
466
- "@takazudo/zudo-doc": "^0.2.17",
467
+ "@takazudo/zudo-doc": "^0.2.19",
467
468
  // zod — used by the generated zfb.config.ts. zfb-config-gen emits
468
469
  // `import { z } from "zod"` for the content-collection schema +
469
470
  // `z.toJSONSchema(...)` conversion. Without this dep, the consumer
@@ -517,7 +518,7 @@ function generatePackageJson(choices) {
517
518
  // @takazudo/zudo-doc/integrations/doc-history which in turn imports
518
519
  // @takazudo/zudo-doc-history-server/git-history. Without this dep the
519
520
  // plugin host fails at init with ERR_MODULE_NOT_FOUND — W8A (#1739).
520
- deps["@takazudo/zudo-doc-history-server"] = "^0.2.17";
521
+ deps["@takazudo/zudo-doc-history-server"] = "^0.2.19";
521
522
  // W7A (#1736): doc-history-plugin.mjs spawns `tsx -e <inline-script>` to
522
523
  // run the v2 runtime in a TS-aware Node subprocess; without tsx the
523
524
  // plugin's preBuild step exits with ENOENT before zfb finishes config
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-zudo-doc",
3
- "version": "0.2.17",
3
+ "version": "0.2.19",
4
4
  "description": "Create a new zudo-doc documentation site",
5
5
  "license": "MIT",
6
6
  "author": "Takeshi Takatsudo",
@@ -44,6 +44,7 @@ export default function NotFoundPage(): JSX.Element {
44
44
  headerOverride={<HeaderWithDefaults lang={locale} />}
45
45
  footerOverride={<FooterWithDefaults lang={locale} />}
46
46
  bodyEndComponents={<BodyEndIslands basePath={settings.base ?? "/"} />}
47
+ enableClientRouter={settings.dynamicPageTransition}
47
48
  >
48
49
  <div class="min-h-[60vh] flex flex-col items-center justify-center px-hsp-2xl py-vsp-xl">
49
50
  <h1 class="text-display font-bold mb-vsp-md">404</h1>
@@ -73,6 +73,7 @@ export default function IndexPage(): JSX.Element {
73
73
  headerOverride={<HeaderWithDefaults lang={locale} currentPath={withBase("/")} />}
74
74
  footerOverride={<FooterWithDefaults lang={locale} />}
75
75
  bodyEndComponents={<BodyEndIslands basePath={settings.base ?? "/"} />}
76
+ enableClientRouter={settings.dynamicPageTransition}
76
77
  >
77
78
  {/* Hero: logo left, title+desc+links right, block centered */}
78
79
  <div class="flex justify-center mb-vsp-xl">
@@ -18,8 +18,14 @@ import { SidebarResizerInit } from "@takazudo/zudo-doc/sidebar-resizer";
18
18
 
19
19
  /**
20
20
  * The `bodyEndComponents` slot content shared by all four doc-route page
21
- * components: `BodyEndIslands` (modal overlays, client-router bootstrap,
22
- * image-enlarge) and the optional `SidebarResizerInit` drag handle.
21
+ * components: `BodyEndIslands` (modal overlays, optional client-router
22
+ * bootstrap when `dynamicPageTransition` is on, image-enlarge) and the
23
+ * optional `SidebarResizerInit` drag handle. Whether the client-router
24
+ * bootstrap island is included depends on `settings.dynamicPageTransition`
25
+ * (gated inside `BodyEndIslands`). The SSR `<ClientRouter />` mounted by
26
+ * `DocLayout` self-activates when `enableClientRouter` is `true`; the
27
+ * island here is redundant for that activation path and kept only for the
28
+ * `when="load"` hydration slot.
23
29
  */
24
30
  export function DocBodyEnd(): JSX.Element {
25
31
  return (
@@ -218,6 +218,7 @@ export function DocPageShell(props: DocPageShellProps): JSX.Element {
218
218
  afterSidebar={<SidebarPrepaint />}
219
219
  footerOverride={<FooterWithDefaults lang={locale} />}
220
220
  bodyEndComponents={<DocBodyEnd />}
221
+ enableClientRouter={settings.dynamicPageTransition}
221
222
  >
222
223
  {kind === "autoIndex" ? (
223
224
  /* Auto-index page: category without an index.mdx.
@@ -116,7 +116,7 @@ export function schemeToCssPairs(scheme: ColorScheme): [string, string][] {
116
116
  return [
117
117
  ["--zd-bg", resolveColor(scheme.background, p, p[0])],
118
118
  ["--zd-fg", resolveColor(scheme.foreground, p, p[15])],
119
- ["--zd-cursor", resolveColor(scheme.cursor, p, p[6])],
119
+ ["--zd-cursor", resolveColor(scheme.cursor, p, p[6])], // intentionally inert/vestigial: exposed in the design-token panel but no CSS rule consumes it (no caret-color wiring); mirrors shikiTheme's status
120
120
  ["--zd-sel-bg", resolveColor(scheme.selectionBg, p, resolveColor(scheme.background, p, p[0]))],
121
121
  ["--zd-sel-fg", resolveColor(scheme.selectionFg, p, resolveColor(scheme.foreground, p, p[15]))],
122
122
  ...p.map((color, i) => [`--zd-${i}`, color] as [string, string]),
@@ -81,8 +81,8 @@ export const colorSchemes: Record<string, ColorScheme> = {
81
81
  selectionBg: 11,
82
82
  selectionFg: 10,
83
83
  palette: [
84
- "#303030", "#dd3131", "#266538", "#a83838", // p0-3: dark surface, danger, success, warning
85
- "#3277c8", "#a35e0f", "#90a1b9", "#7a5218", // p4-7: info, accent, neutral, secondary
84
+ "#303030", "#a01515", "#1f5429", "#903030", // p0-3: dark surface, danger, success, warning — darkened for WCAG AA (#2298)
85
+ "#174fa0", "#7d470b", "#90a1b9", "#7a5218", // p4-7: info, accent, neutral, secondary — darkened for WCAG AA (#2298)
86
86
  "#6b6b6b", "#e2ddda", "#ece9e9", "#303030", // p8-11: muted, background, surface, text
87
87
  "#5b99dc", "#b89ee7", "#8590a0", "#654516", // p12-15: accent variant, decorative, hover, muted foreground
88
88
  ],
@@ -42,6 +42,7 @@
42
42
  above (line 11); the safelist import above generates the component utilities
43
43
  its headings/links/etc. depend on. */
44
44
  @import "@takazudo/zudo-doc/content.css";
45
+ /* @slot:global-css:imports */
45
46
 
46
47
  /* ========================================
47
48
  * Tailwind v4 content sources
@@ -269,6 +270,11 @@
269
270
  --text-scale-lg: 1.4rem; /* 22.4px */
270
271
  --text-scale-xl: 3rem; /* 48px */
271
272
  --text-scale-2xl: 3.75rem; /* 60px */
273
+
274
+ --default-transition-duration: 150ms; /* consumed by hash-link opacity fade */
275
+ --zd-transition-slow: 200ms; /* sidebar transform/visibility and content-band max-width */
276
+ --zd-transition-slower: 300ms; /* view-transition fade-in (contentFadeIn animation) */
277
+ --zd-header-h: 80px; /* sticky header height; consumed by scroll-margin-top on [id] anchors */
272
278
  }
273
279
 
274
280
  /* ========================================
@@ -276,7 +282,7 @@
276
282
  * ======================================== */
277
283
 
278
284
  [id] {
279
- scroll-margin-top: 80px;
285
+ scroll-margin-top: var(--zd-header-h);
280
286
  }
281
287
 
282
288
  body {
@@ -580,8 +586,8 @@ pre[class^="syntect-"] .line .highlighted-word {
580
586
  @media (min-width: 1024px) {
581
587
  #desktop-sidebar {
582
588
  transition:
583
- transform 200ms ease-in-out,
584
- visibility 200ms;
589
+ transform var(--zd-transition-slow) ease-in-out,
590
+ visibility var(--zd-transition-slow);
585
591
  }
586
592
 
587
593
  html[data-sidebar-hidden] #desktop-sidebar {
@@ -590,7 +596,7 @@ pre[class^="syntect-"] .line .highlighted-word {
590
596
  }
591
597
 
592
598
  .zd-sidebar-content-wrapper {
593
- transition: margin-left 200ms ease-in-out;
599
+ transition: margin-left var(--zd-transition-slow) ease-in-out;
594
600
  }
595
601
 
596
602
  html[data-sidebar-hidden] .zd-sidebar-content-wrapper {
@@ -604,7 +610,7 @@ pre[class^="syntect-"] .line .highlighted-word {
604
610
  * branch in doc-layout.tsx. These rules are unlayered, so they win over
605
611
  * the Tailwind `max-w-[clamp(...)]` utility (utilities layer). (#2002) */
606
612
  .zd-doc-content-band {
607
- transition: max-width 200ms ease-in-out;
613
+ transition: max-width var(--zd-transition-slow) ease-in-out;
608
614
  }
609
615
 
610
616
  html[data-sidebar-hidden] .zd-doc-content-band {
@@ -142,6 +142,7 @@ export function TagDetailPageView({
142
142
  breadcrumbOverride={<Breadcrumb items={breadcrumbItems} />}
143
143
  footerOverride={<FooterWithDefaults lang={locale} />}
144
144
  bodyEndComponents={<BodyEndIslands basePath={settings.base ?? "/"} />}
145
+ enableClientRouter={settings.dynamicPageTransition}
145
146
  >
146
147
  <h1 class="text-heading font-bold mb-vsp-xs">{pageTitle}</h1>
147
148
  <p class="text-muted mb-vsp-lg">{countText}</p>
@@ -198,6 +199,7 @@ export function TagsIndexPageView({ locale }: { locale: string }): JSX.Element {
198
199
  breadcrumbOverride={<Breadcrumb items={breadcrumbItems} />}
199
200
  footerOverride={<FooterWithDefaults lang={locale} />}
200
201
  bodyEndComponents={<BodyEndIslands basePath={settings.base ?? "/"} />}
202
+ enableClientRouter={settings.dynamicPageTransition}
201
203
  >
202
204
  <h1 class="text-heading font-bold mb-vsp-lg">{pageTitle}</h1>
203
205
  {!settings.docTags || tags.length === 0 ? (
@@ -51,6 +51,14 @@ import type { JSX } from "preact";
51
51
  * walks page → BodyEndIslands → ClientRouterBootstrap and includes the
52
52
  * client-router barrel in the per-island bundle, where the side-effect
53
53
  * import above can fire on the client.
54
+ *
55
+ * Note: the SSR `<ClientRouter />` mounted by `DocLayout` (via
56
+ * `enableClientRouter`) self-activates the SPA router when its head meta
57
+ * tags reach the browser. This host island is therefore a no-op for
58
+ * router activation — it is kept only for the `when="load"` hydration
59
+ * slot and bundle inclusion. The actual on/off gate is
60
+ * `enableClientRouter` on `<DocLayoutWithDefaults>`, set to
61
+ * `settings.dynamicPageTransition` at every call site.
54
62
  */
55
63
  function ClientRouterBootstrap(): JSX.Element | null {
56
64
  return null;
@@ -117,6 +117,7 @@ export default function LocaleIndexPage({ params }: PageArgs): JSX.Element {
117
117
  headerOverride={<HeaderWithDefaults lang={locale as Locale} currentPath={withBase(`/${locale}/`)} />}
118
118
  footerOverride={<FooterWithDefaults lang={locale} />}
119
119
  bodyEndComponents={<BodyEndIslands basePath={settings.base ?? "/"} />}
120
+ enableClientRouter={settings.dynamicPageTransition}
120
121
  >
121
122
  {/* Hero: logo left, title+desc+links right, block centered */}
122
123
  <div class="flex justify-center mb-vsp-xl">
@@ -73,6 +73,7 @@ export function VersionsPageView({ locale }: { locale: string }): JSX.Element {
73
73
  headerOverride={<HeaderWithDefaults lang={locale as Locale} currentPath={withBase(`${prefix}/docs/versions`)} />}
74
74
  footerOverride={<FooterWithDefaults lang={locale} />}
75
75
  bodyEndComponents={<BodyEndIslands basePath={settings.base ?? "/"} />}
76
+ enableClientRouter={settings.dynamicPageTransition}
76
77
  >
77
78
  <VersionsPageContent
78
79
  latestHref={latestHref}