@tenphi/starlight 0.1.0 → 0.5.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/index.js CHANGED
@@ -1,39 +1,152 @@
1
1
  import { n as starlight, t as createStarlightCollection } from "./content-Cwk8rm6i.js";
2
+ import { a as resolveNavigationLayout } from "./navigation-CC0dlAL8.js";
2
3
  import { createRequire } from "node:module";
3
4
  import { existsSync } from "node:fs";
4
- import { cp, mkdir } from "node:fs/promises";
5
- import { dirname, join } from "node:path";
5
+ import { cp, mkdir, readFile } from "node:fs/promises";
6
+ import { dirname, extname, join } from "node:path";
6
7
  import { fileURLToPath } from "node:url";
7
8
  import { assertValidDocs, createDocsGraph } from "@tenphi/docs";
9
+ import { configure } from "@tenphi/tasty/core";
8
10
  import { tastyIntegration } from "@tenphi/tasty/ssr/astro";
9
11
  import { apcaContrast, glaze, okhslToLinearSrgb, relativeLuminanceFromLinearRgb, variantToOkhsl } from "@tenphi/glaze";
12
+ //#region src/theme/defaults.ts
13
+ const DEFAULT_THEME_TOKENS = {
14
+ $gap: "0.5rem",
15
+ $radius: "6px",
16
+ "$card-radius": "10px",
17
+ "$border-width": "1px",
18
+ "$outline-width": "2px",
19
+ "$outline-offset": "2px",
20
+ "$layout-width": "87.5rem",
21
+ "$content-width": "58rem",
22
+ "$sidebar-width": "17.5rem",
23
+ "$control-height": "2.5rem"
24
+ };
25
+ const BODY_FONT = "'Onest Variable', Onest, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif";
26
+ const DEFAULT_TYPOGRAPHY_PRESETS = {
27
+ body: {
28
+ fontFamily: BODY_FONT,
29
+ fontSize: "1rem",
30
+ lineHeight: 1.75,
31
+ letterSpacing: "0",
32
+ fontWeight: 400,
33
+ boldFontWeight: 650
34
+ },
35
+ heading: {
36
+ fontFamily: BODY_FONT,
37
+ fontSize: "1rem",
38
+ lineHeight: 1.2,
39
+ letterSpacing: "-0.018em",
40
+ fontWeight: 650,
41
+ boldFontWeight: 750
42
+ },
43
+ h1: heading("3rem", 1.08, "-0.035em"),
44
+ h2: heading("2rem", 1.15, "-0.025em"),
45
+ h3: heading("1.5rem", 1.2, "-0.015em"),
46
+ h4: heading("1.25rem", 1.25, "-0.01em"),
47
+ h5: heading("1.125rem", 1.3, "0"),
48
+ h6: heading("1rem", 1.35, "0"),
49
+ small: {
50
+ fontFamily: "var(--body-font-family)",
51
+ fontSize: "0.875rem",
52
+ lineHeight: 1.5,
53
+ letterSpacing: "0",
54
+ fontWeight: 400,
55
+ boldFontWeight: 700
56
+ },
57
+ code: {
58
+ fontFamily: "'JetBrains Mono Variable', 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace",
59
+ fontSize: "0.875rem",
60
+ lineHeight: 1.6,
61
+ letterSpacing: "0",
62
+ fontWeight: 400,
63
+ boldFontWeight: 700
64
+ }
65
+ };
66
+ function resolveThemeTokens(tokens = {}) {
67
+ return {
68
+ ...DEFAULT_THEME_TOKENS,
69
+ ...tokens
70
+ };
71
+ }
72
+ function resolveTypographyPresets(presets = {}) {
73
+ const body = DEFAULT_TYPOGRAPHY_PRESETS.body;
74
+ if (!body) throw new Error("The body typography preset is required.");
75
+ const names = /* @__PURE__ */ new Set([...Object.keys(DEFAULT_TYPOGRAPHY_PRESETS), ...Object.keys(presets)]);
76
+ return Object.fromEntries([...names].map((name) => [name, {
77
+ ...DEFAULT_TYPOGRAPHY_PRESETS[name] ?? body,
78
+ ...presets[name] ?? {}
79
+ }]));
80
+ }
81
+ function heading(fontSize, lineHeight, letterSpacing) {
82
+ return {
83
+ fontFamily: "var(--heading-font-family)",
84
+ fontSize,
85
+ lineHeight,
86
+ letterSpacing,
87
+ fontWeight: "var(--heading-font-weight)",
88
+ boldFontWeight: "var(--heading-bold-font-weight)"
89
+ };
90
+ }
91
+ //#endregion
10
92
  //#region src/theme/index.ts
11
93
  function resolveDocsTheme(theme = {}) {
12
94
  const brand = normalizeBrand(theme.brand);
13
95
  const authoredTarget = brand.contrast?.apca ?? 45;
14
96
  const normalTarget = Array.isArray(authoredTarget) ? authoredTarget[0] : authoredTarget;
15
97
  const highTarget = Array.isArray(authoredTarget) ? authoredTarget[1] : normalTarget + 15;
98
+ const glazeOptions = {
99
+ autoFlip: true,
100
+ ...theme.contrastLevel !== void 0 ? { contrastLevel: theme.contrastLevel } : {}
101
+ };
102
+ const surfaceFrom = theme.palette?.surface ?? "#ffffff";
16
103
  const surface = glaze.color({
17
- from: "#ffffff",
18
- mode: "auto"
104
+ from: surfaceFrom,
105
+ mode: "auto",
106
+ darkSaturation: .35
19
107
  });
108
+ const surface2 = glaze.color({
109
+ from: surfaceFrom,
110
+ base: surface,
111
+ tone: ["-2", "-4"],
112
+ mode: "auto",
113
+ darkSaturation: .35
114
+ }, glazeOptions);
115
+ const surface3 = glaze.color({
116
+ from: surfaceFrom,
117
+ base: surface,
118
+ tone: ["-4", "-8"],
119
+ mode: "auto",
120
+ darkSaturation: .35
121
+ }, glazeOptions);
122
+ const text = glaze.color({
123
+ from: theme.palette?.text ?? "#20232a",
124
+ base: surface,
125
+ role: "text",
126
+ contrast: { apca: [75, 90] },
127
+ mode: "auto"
128
+ }, glazeOptions);
129
+ const textSoft = glaze.color({
130
+ from: theme.palette?.textSoft ?? "#626875",
131
+ base: surface,
132
+ role: "text",
133
+ contrast: { apca: [60, 75] },
134
+ mode: "auto"
135
+ }, glazeOptions);
20
136
  const accentText = glaze.color({
21
137
  from: brand.from,
22
138
  base: surface,
23
139
  role: "text",
24
140
  contrast: { apca: authoredTarget },
25
141
  mode: "auto"
26
- }, {
27
- autoFlip: true,
28
- ...theme.contrastLevel !== void 0 ? { contrastLevel: theme.contrastLevel } : {}
29
- });
142
+ }, glazeOptions);
30
143
  const focus = glaze.color({
31
144
  from: brand.from,
32
145
  base: surface,
33
146
  role: "border",
34
147
  contrast: { apca: authoredTarget },
35
148
  mode: "auto"
36
- }, { autoFlip: true });
149
+ }, glazeOptions);
37
150
  const accentSurface = glaze.color({
38
151
  from: brand.from,
39
152
  mode: "fixed"
@@ -66,6 +179,10 @@ function resolveDocsTheme(theme = {}) {
66
179
  const outputOptions = { modes: { highContrast: true } };
67
180
  const colors = {
68
181
  surface: surface.json(outputOptions),
182
+ surface2: surface2.json(outputOptions),
183
+ surface3: surface3.json(outputOptions),
184
+ text: text.json(outputOptions),
185
+ textSoft: textSoft.json(outputOptions),
69
186
  accentText: accentText.json(outputOptions),
70
187
  accentSurface: accentSurface.json(outputOptions),
71
188
  accentSurfaceText: accentSurfaceText.json(outputOptions),
@@ -74,6 +191,8 @@ function resolveDocsTheme(theme = {}) {
74
191
  return {
75
192
  css: themeCss(colors, theme),
76
193
  colors,
194
+ tokens: resolveThemeTokens(theme.tokens),
195
+ presets: resolveTypographyPresets(theme.presets),
77
196
  contrast: scores,
78
197
  diagnostics
79
198
  };
@@ -90,16 +209,30 @@ function luminance(variant) {
90
209
  return relativeLuminanceFromLinearRgb(okhslToLinearSrgb(h, s, l, variant.pastel));
91
210
  }
92
211
  function themeCss(colors, theme) {
212
+ const tokens = resolveThemeTokens(theme.tokens);
213
+ const presets = resolveTypographyPresets(theme.presets);
214
+ const designDeclarations = [...Object.entries(tokens).map(([name, value]) => `${tokenProperty(name)}:${String(value)}`), ...Object.entries(presets).flatMap(([name, preset]) => Object.entries(preset).map(([property, value]) => `--${kebab(name)}-${kebab(property)}:${String(value)}`))].join(";");
93
215
  const declarations = (mode) => [
94
216
  `--td-surface:${colors.surface[mode]}`,
217
+ `--td-surface-2:${colors.surface2[mode]}`,
218
+ `--td-surface-3:${colors.surface3[mode]}`,
219
+ `--td-text:${colors.text[mode]}`,
220
+ `--td-text-soft:${colors.textSoft[mode]}`,
95
221
  `--td-accent-text:${colors.accentText[mode]}`,
96
222
  `--td-accent-surface:${colors.accentSurface[mode]}`,
97
223
  `--td-accent-surface-text:${colors.accentSurfaceText[mode]}`,
98
224
  `--td-focus:${colors.focus[mode]}`,
99
- ...Object.entries(theme.tokens ?? {}).map(([name, value]) => `${name}:${String(value)}`)
225
+ "--td-surface-2-hover:color-mix(in oklab,var(--td-text) 3%,var(--td-surface-2))",
226
+ "--td-surface-2-pressed:color-mix(in oklab,var(--td-text) 9%,var(--td-surface-2))",
227
+ "--td-surface-3-hover:color-mix(in oklab,var(--td-text) 3%,var(--td-surface-3))",
228
+ "--td-surface-3-pressed:color-mix(in oklab,var(--td-text) 9%,var(--td-surface-3))",
229
+ "--td-border:color-mix(in oklab,var(--td-text) 18%,var(--td-surface))",
230
+ "--td-border-strong:color-mix(in oklab,var(--td-text) 34%,var(--td-surface))",
231
+ "--td-shadow:color-mix(in oklab,var(--td-text) 16%,transparent)",
232
+ "--td-overlay:color-mix(in oklab,var(--td-text) 58%,transparent)"
100
233
  ].join(";");
101
234
  return [
102
- `:root{${declarations("dark")}}`,
235
+ `:root{${designDeclarations};${declarations("dark")}}`,
103
236
  `:root[data-theme=light]{${declarations("light")}}`,
104
237
  `@media(prefers-color-scheme:light){:root:not([data-theme]){${declarations("light")}}}`,
105
238
  `@media(prefers-contrast:more){:root{${declarations("darkContrast")}}:root[data-theme=light]{${declarations("lightContrast")}}@media(prefers-color-scheme:light){:root:not([data-theme]){${declarations("lightContrast")}}}}`,
@@ -107,36 +240,58 @@ function themeCss(colors, theme) {
107
240
  `:root[data-theme=light][data-contrast=more]{${declarations("lightContrast")}}`
108
241
  ].join("\n");
109
242
  }
243
+ function tokenProperty(name) {
244
+ if (name.startsWith("--")) return name;
245
+ return `--${name.replace(/^\$/, "")}`;
246
+ }
247
+ function kebab(value) {
248
+ return value.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/[^a-zA-Z0-9_-]/g, "-").toLowerCase();
249
+ }
110
250
  //#endregion
111
251
  //#region src/integration.ts
112
252
  const packageRequire = createRequire(import.meta.url);
113
253
  const starlightRoot = dirname(packageRequire.resolve("@astrojs/starlight"));
114
254
  const tastyStaticMiddleware = packageRequire.resolve("@tenphi/tasty/ssr/astro-middleware-static");
115
- function tastyDocs(options = {}) {
255
+ function cookbook(options = {}) {
116
256
  const docsTheme = resolveDocsTheme(options.config?.theme);
117
257
  if (docsTheme.diagnostics.some((diagnostic) => diagnostic.severity === "error")) throw new Error(docsTheme.diagnostics.map((diagnostic) => diagnostic.message).join("\n"));
258
+ configureTastyTheme(options.config?.theme, docsTheme);
118
259
  const cssPath = fileURLToPath(new URL("./styles.css", import.meta.url));
119
260
  const searchClientPath = fileURLToPath(new URL("./client/search.js", import.meta.url));
120
261
  const appearanceClientPath = fileURLToPath(new URL("./client/appearance.js", import.meta.url));
262
+ const components = {
263
+ Header: fileURLToPath(new URL("./overrides/Header.astro", import.meta.url)),
264
+ Sidebar: fileURLToPath(new URL("./overrides/Sidebar.astro", import.meta.url)),
265
+ ...options.config?.components?.overrides
266
+ };
267
+ const navigation = resolveNavigationLayout(options.config?.navigation);
121
268
  const inner = [tastyIntegration({ islands: false }), starlight({
122
269
  title: options.config?.site?.title ?? "Documentation",
123
270
  ...options.config?.site?.description ? { description: options.config.site.description } : {},
124
- customCss: ["virtual:tasty-docs/theme.css", cssPath],
271
+ customCss: ["virtual:cookbook/theme.css", cssPath],
125
272
  ...options.config?.search?.enabled === false ? { pagefind: false } : {},
126
- sidebar: [{
127
- label: "Documentation",
128
- items: [{ autogenerate: { directory: "" } }]
129
- }]
273
+ components,
274
+ sidebar: starlightSidebar(navigation)
130
275
  })];
131
276
  let projectRoot = options.root;
132
277
  let graphConfig = options.config;
133
278
  let graph;
134
279
  let usingStarlight = false;
280
+ async function loadGraph(refresh = false) {
281
+ if (!graph || refresh) {
282
+ graph = await createDocsGraph({
283
+ ...projectRoot ? { root: projectRoot } : {},
284
+ ...graphConfig ? { config: graphConfig } : {}
285
+ });
286
+ assertValidDocs(graph);
287
+ }
288
+ return graph;
289
+ }
135
290
  return {
136
- name: "tasty-docs",
291
+ name: "cookbook",
137
292
  hooks: {
138
293
  "astro:config:setup": async (context) => {
139
- if (context.config.integrations.some((integration) => integration.name === "@astrojs/starlight")) throw new Error("Tasty Docs already includes Starlight. Remove the direct @astrojs/starlight integration before continuing.");
294
+ if (context.config.integrations.some((integration) => integration.name === "@astrojs/starlight")) throw new Error("Cookbook already includes Starlight. Remove the direct @astrojs/starlight integration before continuing.");
140
295
  projectRoot ??= fileURLToPath(context.config.root);
141
296
  const base = options.config?.build?.base ?? context.config.base;
142
297
  graphConfig = {
@@ -158,7 +313,7 @@ function tastyDocs(options = {}) {
158
313
  site: graph?.config.site ?? options.config?.site ?? {},
159
314
  base: graph?.config.build.base ?? base,
160
315
  search: graph?.config.search.enabled ?? options.config?.search?.enabled ?? true
161
- }))],
316
+ }), navigation)],
162
317
  resolve: { alias: [{
163
318
  find: "@astrojs/starlight",
164
319
  replacement: starlightRoot
@@ -186,7 +341,7 @@ function tastyDocs(options = {}) {
186
341
  }
187
342
  const starlightIntegration = inner[1];
188
343
  if (starlightIntegration) {
189
- const selfIndex = context.config.integrations.findIndex((integration) => integration.name === "tasty-docs");
344
+ const selfIndex = context.config.integrations.findIndex((integration) => integration.name === "cookbook");
190
345
  context.config.integrations.splice(selfIndex + 1, 0, starlightIntegration);
191
346
  try {
192
347
  await callInner([starlightIntegration], "astro:config:setup", context);
@@ -199,14 +354,46 @@ function tastyDocs(options = {}) {
199
354
  "astro:config:done": async (context) => {
200
355
  await callInner(usingStarlight ? inner : inner.slice(0, 1), "astro:config:done", context);
201
356
  },
357
+ "astro:server:setup": async ({ server }) => {
358
+ let assets = docsAssetMap(await loadGraph());
359
+ server.middlewares.use(async (request, response, next) => {
360
+ if (request.method !== "GET" && request.method !== "HEAD") {
361
+ next();
362
+ return;
363
+ }
364
+ const pathname = requestPath(request.url);
365
+ if (!pathname.includes("/_tasty-assets/")) {
366
+ next();
367
+ return;
368
+ }
369
+ let asset = assets.get(pathname);
370
+ if (!asset) {
371
+ try {
372
+ assets = docsAssetMap(await loadGraph(true));
373
+ } catch {
374
+ next();
375
+ return;
376
+ }
377
+ asset = assets.get(pathname);
378
+ }
379
+ if (!asset?.sourcePath) {
380
+ next();
381
+ return;
382
+ }
383
+ try {
384
+ const body = await readFile(asset.sourcePath);
385
+ response.statusCode = 200;
386
+ response.setHeader("Content-Type", assetContentType(pathname));
387
+ response.setHeader("Content-Length", body.byteLength);
388
+ response.setHeader("Cache-Control", "no-cache");
389
+ response.end(request.method === "HEAD" ? void 0 : body);
390
+ } catch {
391
+ next();
392
+ }
393
+ });
394
+ },
202
395
  "astro:build:start": async (context) => {
203
- if (!graph) {
204
- graph = await createDocsGraph({
205
- ...projectRoot ? { root: projectRoot } : {},
206
- ...graphConfig ? { config: graphConfig } : {}
207
- });
208
- assertValidDocs(graph);
209
- }
396
+ await loadGraph();
210
397
  await callInner(usingStarlight ? inner : inner.slice(0, 1), "astro:build:start", context);
211
398
  },
212
399
  "astro:build:done": async (context) => {
@@ -233,6 +420,93 @@ function tastyDocs(options = {}) {
233
420
  }
234
421
  };
235
422
  }
423
+ function docsAssetMap(graph) {
424
+ return new Map(graph.assets.flatMap((asset) => asset.publicPath && asset.sourcePath ? [[asset.publicPath, asset]] : []));
425
+ }
426
+ function requestPath(url) {
427
+ try {
428
+ return decodeURIComponent(new URL(url ?? "/", "http://localhost").pathname);
429
+ } catch {
430
+ return "";
431
+ }
432
+ }
433
+ function assetContentType(pathname) {
434
+ switch (extname(pathname).toLowerCase()) {
435
+ case ".avif": return "image/avif";
436
+ case ".gif": return "image/gif";
437
+ case ".jpeg":
438
+ case ".jpg": return "image/jpeg";
439
+ case ".png": return "image/png";
440
+ case ".svg": return "image/svg+xml";
441
+ case ".webp": return "image/webp";
442
+ default: return "application/octet-stream";
443
+ }
444
+ }
445
+ function configureTastyTheme(theme, resolved) {
446
+ const tokens = Object.fromEntries(Object.entries(resolved.tokens).filter(([name]) => name.startsWith("$")));
447
+ Object.assign(tokens, {
448
+ "#surface": "var(--td-surface)",
449
+ "#surface-2": "var(--td-surface-2)",
450
+ "#surface-3": "var(--td-surface-3)",
451
+ "#text": "var(--td-text)",
452
+ "#text-soft": "var(--td-text-soft)",
453
+ "#border": "var(--td-border)",
454
+ "#border-strong": "var(--td-border-strong)",
455
+ "#accent-text": "var(--td-accent-text)",
456
+ "#accent-surface": "var(--td-accent-surface)",
457
+ "#accent-surface-text": "var(--td-accent-surface-text)",
458
+ "#focus": "var(--td-focus)"
459
+ });
460
+ const globalStyles = anatomyStyles(theme?.styles);
461
+ configure({
462
+ ...theme?.states ? { states: theme.states } : {},
463
+ units: {
464
+ x: "var(--gap)",
465
+ r: "var(--radius)",
466
+ cr: "var(--card-radius)",
467
+ bw: "var(--border-width)"
468
+ },
469
+ tokens,
470
+ presets: resolved.presets,
471
+ ...globalStyles ? { globalStyles } : {}
472
+ });
473
+ }
474
+ function anatomyStyles(styles) {
475
+ if (!styles) return void 0;
476
+ return Object.fromEntries(Object.entries(styles).filter((entry) => isRecord(entry[1])).map(([name, value]) => [`[data-tasty-anatomy="${name}"]`, value]));
477
+ }
478
+ function isRecord(value) {
479
+ return typeof value === "object" && value !== null && !Array.isArray(value);
480
+ }
481
+ function starlightSidebar(layout) {
482
+ const fallback = layout.items?.length ? layout.items.map(starlightSidebarItem) : [{ autogenerate: { directory: "" } }];
483
+ if (!layout.sectioned) return fallback;
484
+ return [...layout.fallbackSidebarGroup !== void 0 ? [{
485
+ label: "Documentation",
486
+ items: (layout.items ?? []).map(starlightSidebarItem)
487
+ }] : [], ...layout.tabs.flatMap((tab) => tab.items !== void 0 ? [{
488
+ label: tab.label,
489
+ items: tab.items.map(starlightSidebarItem)
490
+ }] : [])];
491
+ }
492
+ function starlightSidebarItem(item) {
493
+ if (typeof item === "string") return { slug: routeToSlug(item) };
494
+ if ("items" in item) return {
495
+ label: item.label,
496
+ items: item.items.map(starlightSidebarItem)
497
+ };
498
+ if ("autogenerate" in item) return {
499
+ label: item.label,
500
+ items: [{ autogenerate: { directory: routeToSlug(item.autogenerate.directory, false) } }]
501
+ };
502
+ return {
503
+ label: item.label,
504
+ link: item.link
505
+ };
506
+ }
507
+ function routeToSlug(route, rootAsIndex = true) {
508
+ return route.replace(/^\/+|\/+$/g, "") || (rootAsIndex ? "index" : "");
509
+ }
236
510
  function tastyStarlight(config) {
237
511
  return starlight(config);
238
512
  }
@@ -242,18 +516,21 @@ async function callInner(integrations, hook, context) {
242
516
  if (typeof handler === "function") await handler(context);
243
517
  }
244
518
  }
245
- function virtualDocsPlugin(css, getContent) {
246
- const themeId = "\0virtual:tasty-docs/theme.css";
247
- const configId = "\0virtual:tasty-docs/config";
519
+ function virtualDocsPlugin(css, getContent, layout) {
520
+ const themeId = "\0virtual:cookbook/theme.css";
521
+ const configId = "\0virtual:cookbook/config";
522
+ const layoutId = "\0virtual:cookbook/layout";
248
523
  return {
249
- name: "tasty-docs-theme",
524
+ name: "cookbook-theme",
250
525
  resolveId(id) {
251
- if (id === "virtual:tasty-docs/theme.css") return themeId;
252
- if (id === "virtual:tasty-docs/config") return configId;
526
+ if (id === "virtual:cookbook/theme.css") return themeId;
527
+ if (id === "virtual:cookbook/config") return configId;
528
+ if (id === "virtual:cookbook/layout") return layoutId;
253
529
  },
254
530
  load(id) {
255
531
  if (id === themeId) return css;
256
532
  if (id === configId) return `export const content = ${JSON.stringify(getContent())};`;
533
+ if (id === layoutId) return `export const layout = ${JSON.stringify(layout)};`;
257
534
  }
258
535
  };
259
536
  }
@@ -268,6 +545,6 @@ function hasContentConfig(srcDir) {
268
545
  ].some((path) => existsSync(join(source, path)));
269
546
  }
270
547
  //#endregion
271
- export { createStarlightCollection, tastyDocs as default, resolveDocsTheme, tastyStarlight };
548
+ export { DEFAULT_THEME_TOKENS, DEFAULT_TYPOGRAPHY_PRESETS, createStarlightCollection, cookbook as default, resolveDocsTheme, tastyStarlight };
272
549
 
273
550
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/theme/index.ts","../src/integration.ts"],"sourcesContent":["import {\n apcaContrast,\n glaze,\n okhslToLinearSrgb,\n relativeLuminanceFromLinearRgb,\n variantToOkhsl,\n type GlazeColorValue,\n type ResolvedColorVariant,\n} from \"@tenphi/glaze\";\nimport type { BrandConfig, DocsDiagnostic, ThemeConfig } from \"@tenphi/docs\";\n\nexport interface ResolvedDocsTheme {\n css: string;\n colors: {\n surface: Record<string, string>;\n accentText: Record<string, string>;\n accentSurface: Record<string, string>;\n accentSurfaceText: Record<string, string>;\n focus: Record<string, string>;\n };\n contrast: {\n light: number;\n dark: number;\n lightContrast: number;\n darkContrast: number;\n };\n diagnostics: DocsDiagnostic[];\n}\n\nexport function resolveDocsTheme(theme: ThemeConfig = {}): ResolvedDocsTheme {\n const brand = normalizeBrand(theme.brand);\n const authoredTarget = brand.contrast?.apca ?? 45;\n const normalTarget = Array.isArray(authoredTarget)\n ? authoredTarget[0]\n : authoredTarget;\n const highTarget = Array.isArray(authoredTarget)\n ? authoredTarget[1]\n : normalTarget + 15;\n const surface = glaze.color({ from: \"#ffffff\", mode: \"auto\" });\n const accentText = glaze.color(\n {\n from: brand.from,\n base: surface,\n role: \"text\",\n contrast: { apca: authoredTarget },\n mode: \"auto\",\n },\n {\n autoFlip: true,\n ...(theme.contrastLevel !== undefined\n ? { contrastLevel: theme.contrastLevel }\n : {}),\n },\n );\n const focus = glaze.color(\n {\n from: brand.from,\n base: surface,\n role: \"border\",\n contrast: { apca: authoredTarget },\n mode: \"auto\",\n },\n { autoFlip: true },\n );\n const accentSurface = glaze.color({ from: brand.from, mode: \"fixed\" });\n const accentSurfaceText = glaze.color({\n from: \"#ffffff\",\n base: accentSurface,\n role: \"text\",\n contrast: { apca: 60 },\n mode: \"auto\",\n });\n\n const resolvedSurface = surface.resolve();\n const resolvedAccent = accentText.resolve();\n const scores = {\n light: score(resolvedAccent.light, resolvedSurface.light),\n dark: score(resolvedAccent.dark, resolvedSurface.dark),\n lightContrast: score(\n resolvedAccent.lightContrast,\n resolvedSurface.lightContrast,\n ),\n darkContrast: score(\n resolvedAccent.darkContrast,\n resolvedSurface.darkContrast,\n ),\n };\n const diagnostics: DocsDiagnostic[] = [];\n for (const [scheme, measured] of Object.entries(scores)) {\n const required = scheme.includes(\"Contrast\") ? highTarget : normalTarget;\n if (measured + 0.05 < required) {\n diagnostics.push({\n code: \"DOCS_BRAND_CONTRAST_UNMET\",\n severity: \"error\",\n message: `Brand contrast in ${scheme} is Lc ${measured.toFixed(1)}; required Lc ${required}.`,\n hint: `Authored color: ${String(brand.from)}.`,\n });\n }\n }\n const outputOptions = { modes: { highContrast: true } } as const;\n const colors = {\n surface: surface.json(outputOptions),\n accentText: accentText.json(outputOptions),\n accentSurface: accentSurface.json(outputOptions),\n accentSurfaceText: accentSurfaceText.json(outputOptions),\n focus: focus.json(outputOptions),\n };\n return {\n css: themeCss(colors, theme),\n colors,\n contrast: scores,\n diagnostics,\n };\n}\n\nfunction normalizeBrand(\n brand: BrandConfig | undefined,\n): Exclude<BrandConfig, GlazeColorValue> & { from: GlazeColorValue } {\n if (typeof brand === \"object\" && brand !== null && \"from\" in brand)\n return brand;\n return { from: brand ?? \"#315efb\" };\n}\n\nfunction score(\n foreground: ResolvedColorVariant,\n background: ResolvedColorVariant,\n): number {\n return Math.abs(apcaContrast(luminance(foreground), luminance(background)));\n}\n\nfunction luminance(variant: ResolvedColorVariant): number {\n const { h, s, l } = variantToOkhsl(variant);\n return relativeLuminanceFromLinearRgb(\n okhslToLinearSrgb(h, s, l, variant.pastel),\n );\n}\n\nfunction themeCss(\n colors: ResolvedDocsTheme[\"colors\"],\n theme: ThemeConfig,\n): string {\n const declarations = (mode: string): string =>\n [\n `--td-surface:${colors.surface[mode]}`,\n `--td-accent-text:${colors.accentText[mode]}`,\n `--td-accent-surface:${colors.accentSurface[mode]}`,\n `--td-accent-surface-text:${colors.accentSurfaceText[mode]}`,\n `--td-focus:${colors.focus[mode]}`,\n ...Object.entries(theme.tokens ?? {}).map(\n ([name, value]) => `${name}:${String(value)}`,\n ),\n ].join(\";\");\n return [\n `:root{${declarations(\"dark\")}}`,\n `:root[data-theme=light]{${declarations(\"light\")}}`,\n `@media(prefers-color-scheme:light){:root:not([data-theme]){${declarations(\"light\")}}}`,\n `@media(prefers-contrast:more){:root{${declarations(\"darkContrast\")}}:root[data-theme=light]{${declarations(\"lightContrast\")}}@media(prefers-color-scheme:light){:root:not([data-theme]){${declarations(\"lightContrast\")}}}}`,\n `:root[data-contrast=more]{${declarations(\"darkContrast\")}}`,\n `:root[data-theme=light][data-contrast=more]{${declarations(\"lightContrast\")}}`,\n ].join(\"\\n\");\n}\n","import { existsSync } from \"node:fs\";\nimport { cp, mkdir } from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport starlight from \"./starlight-runtime.js\";\nimport {\n createDocsGraph,\n assertValidDocs,\n type DocsConfig,\n} from \"@tenphi/docs\";\nimport { tastyIntegration } from \"@tenphi/tasty/ssr/astro\";\nimport type { AstroIntegration, HookParameters } from \"astro\";\nimport { resolveDocsTheme } from \"./theme/index.js\";\n\nconst packageRequire = createRequire(import.meta.url);\nconst starlightRoot = dirname(packageRequire.resolve(\"@astrojs/starlight\"));\nconst tastyStaticMiddleware = packageRequire.resolve(\n \"@tenphi/tasty/ssr/astro-middleware-static\",\n);\n\nexport interface TastyDocsOptions {\n config?: DocsConfig;\n root?: string;\n}\n\nexport default function tastyDocs(\n options: TastyDocsOptions = {},\n): AstroIntegration {\n const docsTheme = resolveDocsTheme(options.config?.theme);\n if (\n docsTheme.diagnostics.some((diagnostic) => diagnostic.severity === \"error\")\n ) {\n throw new Error(\n docsTheme.diagnostics.map((diagnostic) => diagnostic.message).join(\"\\n\"),\n );\n }\n const cssPath = fileURLToPath(new URL(\"./styles.css\", import.meta.url));\n const searchClientPath = fileURLToPath(\n new URL(\"./client/search.js\", import.meta.url),\n );\n const appearanceClientPath = fileURLToPath(\n new URL(\"./client/appearance.js\", import.meta.url),\n );\n const inner = [\n tastyIntegration({ islands: false }),\n starlight({\n title: options.config?.site?.title ?? \"Documentation\",\n ...(options.config?.site?.description\n ? { description: options.config.site.description }\n : {}),\n customCss: [\"virtual:tasty-docs/theme.css\", cssPath],\n ...(options.config?.search?.enabled === false ? { pagefind: false } : {}),\n sidebar: [\n {\n label: \"Documentation\",\n items: [{ autogenerate: { directory: \"\" } }],\n },\n ],\n }),\n ] satisfies AstroIntegration[];\n let projectRoot = options.root;\n let graphConfig = options.config;\n let graph: Awaited<ReturnType<typeof createDocsGraph>> | undefined;\n let usingStarlight = false;\n\n return {\n name: \"tasty-docs\",\n hooks: {\n \"astro:config:setup\": async (context) => {\n if (\n context.config.integrations.some(\n (integration) => integration.name === \"@astrojs/starlight\",\n )\n ) {\n throw new Error(\n \"Tasty Docs already includes Starlight. Remove the direct @astrojs/starlight integration before continuing.\",\n );\n }\n projectRoot ??= fileURLToPath(context.config.root);\n const base = options.config?.build?.base ?? context.config.base;\n graphConfig = {\n ...options.config,\n build: { ...options.config?.build, base },\n };\n usingStarlight = hasContentConfig(context.config.srcDir);\n context.updateConfig({\n base,\n output: \"static\",\n vite: {\n ssr: {\n external: [\"@tenphi/docs\"],\n },\n plugins: [\n virtualDocsPlugin(docsTheme.css, () => ({\n entries: graph?.entries ?? [],\n routes: graph?.routes ?? [],\n site: graph?.config.site ?? options.config?.site ?? {},\n base: graph?.config.build.base ?? base,\n search:\n graph?.config.search.enabled ??\n options.config?.search?.enabled ??\n true,\n })),\n ],\n resolve: {\n alias: [\n {\n find: \"@astrojs/starlight\",\n replacement: starlightRoot,\n },\n {\n find: \"@tenphi/tasty/ssr/astro-middleware-static\",\n replacement: tastyStaticMiddleware,\n },\n ],\n },\n },\n });\n await callInner(inner.slice(0, 1), \"astro:config:setup\", context);\n\n if (!usingStarlight) {\n graph = await createDocsGraph({\n root: projectRoot,\n config: graphConfig,\n });\n assertValidDocs(graph);\n if (graph.config.search.enabled) {\n context.injectScript(\n \"page\",\n `import ${JSON.stringify(searchClientPath)};`,\n );\n }\n context.injectScript(\n \"page\",\n `import ${JSON.stringify(appearanceClientPath)};`,\n );\n context.injectRoute({\n pattern: \"[...route]\",\n entrypoint: new URL(\"./routes/DocsPage.astro\", import.meta.url),\n prerender: true,\n });\n return;\n }\n\n // Starlight inserts its own follow-up integrations immediately after\n // itself. Give it a temporary real position so Astro processes those\n // once, after this composite integration, rather than re-visiting us.\n const starlightIntegration = inner[1];\n if (starlightIntegration) {\n const selfIndex = context.config.integrations.findIndex(\n (integration) => integration.name === \"tasty-docs\",\n );\n context.config.integrations.splice(\n selfIndex + 1,\n 0,\n starlightIntegration,\n );\n try {\n await callInner(\n [starlightIntegration],\n \"astro:config:setup\",\n context,\n );\n } finally {\n const placeholderIndex =\n context.config.integrations.indexOf(starlightIntegration);\n if (placeholderIndex >= 0)\n context.config.integrations.splice(placeholderIndex, 1);\n }\n }\n },\n \"astro:config:done\": async (context) => {\n await callInner(\n usingStarlight ? inner : inner.slice(0, 1),\n \"astro:config:done\",\n context,\n );\n },\n \"astro:build:start\": async (context) => {\n if (!graph) {\n graph = await createDocsGraph({\n ...(projectRoot ? { root: projectRoot } : {}),\n ...(graphConfig ? { config: graphConfig } : {}),\n });\n assertValidDocs(graph);\n }\n await callInner(\n usingStarlight ? inner : inner.slice(0, 1),\n \"astro:build:start\",\n context,\n );\n },\n \"astro:build:done\": async (context) => {\n await callInner(\n usingStarlight ? inner : inner.slice(0, 1),\n \"astro:build:done\",\n context,\n );\n if (!graph) return;\n const output = fileURLToPath(context.dir);\n for (const asset of graph.assets) {\n if (!asset.sourcePath || !asset.publicPath) continue;\n const target = join(output, asset.publicPath.replace(/^\\//, \"\"));\n await mkdir(dirname(target), { recursive: true });\n await cp(asset.sourcePath, target);\n }\n if (!usingStarlight && graph.config.search.enabled) {\n const { close, createIndex } = await import(\"pagefind\");\n const created = await createIndex({\n rootSelector: \"[data-pagefind-body]\",\n });\n if (!created.index || created.errors.length > 0) {\n throw new Error(\n `Pagefind failed to start: ${created.errors.join(\"; \")}`,\n );\n }\n const indexed = await created.index.addDirectory({ path: output });\n if (indexed.errors.length > 0) {\n throw new Error(\n `Pagefind failed to index the site: ${indexed.errors.join(\"; \")}`,\n );\n }\n const written = await created.index.writeFiles({\n outputPath: join(output, \"pagefind\"),\n });\n await close();\n if (written.errors.length > 0) {\n throw new Error(\n `Pagefind failed to write the index: ${written.errors.join(\"; \")}`,\n );\n }\n }\n },\n },\n };\n}\n\nexport function tastyStarlight(\n config: Parameters<typeof starlight>[0],\n): AstroIntegration {\n return starlight(config);\n}\n\nasync function callInner<K extends keyof AstroIntegration[\"hooks\"]>(\n integrations: AstroIntegration[],\n hook: K,\n context: HookParameters<K>,\n): Promise<void> {\n for (const integration of integrations) {\n const handler = integration.hooks[hook];\n if (typeof handler === \"function\") {\n await (handler as (value: HookParameters<K>) => void | Promise<void>)(\n context,\n );\n }\n }\n}\n\nfunction virtualDocsPlugin(css: string, getContent: () => unknown) {\n const themeId = \"\\0virtual:tasty-docs/theme.css\";\n const configId = \"\\0virtual:tasty-docs/config\";\n return {\n name: \"tasty-docs-theme\",\n resolveId(id: string) {\n if (id === \"virtual:tasty-docs/theme.css\") return themeId;\n if (id === \"virtual:tasty-docs/config\") return configId;\n return undefined;\n },\n load(id: string) {\n if (id === themeId) return css;\n if (id === configId) {\n return `export const content = ${JSON.stringify(getContent())};`;\n }\n return undefined;\n },\n };\n}\n\nfunction hasContentConfig(srcDir: URL): boolean {\n const source = fileURLToPath(srcDir);\n return [\n \"content.config.ts\",\n \"content.config.mts\",\n \"content.config.js\",\n \"content.config.mjs\",\n \"content/config.ts\",\n ].some((path) => existsSync(join(source, path)));\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/theme/defaults.ts","../src/theme/index.ts","../src/integration.ts"],"sourcesContent":["import type {\n ThemeTokens,\n TypographyPreset,\n TypographyPresets,\n} from \"@tenphi/docs\";\n\nexport const DEFAULT_THEME_TOKENS = {\n $gap: \"0.5rem\",\n $radius: \"6px\",\n \"$card-radius\": \"10px\",\n \"$border-width\": \"1px\",\n \"$outline-width\": \"2px\",\n \"$outline-offset\": \"2px\",\n \"$layout-width\": \"87.5rem\",\n \"$content-width\": \"58rem\",\n \"$sidebar-width\": \"17.5rem\",\n \"$control-height\": \"2.5rem\",\n} satisfies ThemeTokens;\n\nconst BODY_FONT =\n \"'Onest Variable', Onest, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\";\nconst MONO_FONT =\n \"'JetBrains Mono Variable', 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace\";\n\nexport const DEFAULT_TYPOGRAPHY_PRESETS: Record<string, TypographyPreset> = {\n body: {\n fontFamily: BODY_FONT,\n fontSize: \"1rem\",\n lineHeight: 1.75,\n letterSpacing: \"0\",\n fontWeight: 400,\n boldFontWeight: 650,\n },\n heading: {\n fontFamily: BODY_FONT,\n fontSize: \"1rem\",\n lineHeight: 1.2,\n letterSpacing: \"-0.018em\",\n fontWeight: 650,\n boldFontWeight: 750,\n },\n h1: heading(\"3rem\", 1.08, \"-0.035em\"),\n h2: heading(\"2rem\", 1.15, \"-0.025em\"),\n h3: heading(\"1.5rem\", 1.2, \"-0.015em\"),\n h4: heading(\"1.25rem\", 1.25, \"-0.01em\"),\n h5: heading(\"1.125rem\", 1.3, \"0\"),\n h6: heading(\"1rem\", 1.35, \"0\"),\n small: {\n fontFamily: \"var(--body-font-family)\",\n fontSize: \"0.875rem\",\n lineHeight: 1.5,\n letterSpacing: \"0\",\n fontWeight: 400,\n boldFontWeight: 700,\n },\n code: {\n fontFamily: MONO_FONT,\n fontSize: \"0.875rem\",\n lineHeight: 1.6,\n letterSpacing: \"0\",\n fontWeight: 400,\n boldFontWeight: 700,\n },\n};\n\nexport function resolveThemeTokens(tokens: ThemeTokens = {}): ThemeTokens {\n return { ...DEFAULT_THEME_TOKENS, ...tokens };\n}\n\nexport function resolveTypographyPresets(\n presets: TypographyPresets = {},\n): Record<string, TypographyPreset> {\n const body = DEFAULT_TYPOGRAPHY_PRESETS.body;\n if (!body) throw new Error(\"The body typography preset is required.\");\n const names = new Set([\n ...Object.keys(DEFAULT_TYPOGRAPHY_PRESETS),\n ...Object.keys(presets),\n ]);\n return Object.fromEntries(\n [...names].map((name) => [\n name,\n {\n ...(DEFAULT_TYPOGRAPHY_PRESETS[name] ?? body),\n ...(presets[name] ?? {}),\n },\n ]),\n );\n}\n\nfunction heading(\n fontSize: string,\n lineHeight: number,\n letterSpacing: string,\n): TypographyPreset {\n return {\n fontFamily: \"var(--heading-font-family)\",\n fontSize,\n lineHeight,\n letterSpacing,\n fontWeight: \"var(--heading-font-weight)\",\n boldFontWeight: \"var(--heading-bold-font-weight)\",\n };\n}\n","import {\n apcaContrast,\n glaze,\n okhslToLinearSrgb,\n relativeLuminanceFromLinearRgb,\n variantToOkhsl,\n type GlazeColorValue,\n type ResolvedColorVariant,\n} from \"@tenphi/glaze\";\nimport type {\n BrandConfig,\n DocsDiagnostic,\n ThemeConfig,\n ThemeTokens,\n TypographyPreset,\n} from \"@tenphi/docs\";\nimport { resolveThemeTokens, resolveTypographyPresets } from \"./defaults.js\";\n\nexport interface ResolvedDocsTheme {\n css: string;\n colors: {\n surface: Record<string, string>;\n surface2: Record<string, string>;\n surface3: Record<string, string>;\n text: Record<string, string>;\n textSoft: Record<string, string>;\n accentText: Record<string, string>;\n accentSurface: Record<string, string>;\n accentSurfaceText: Record<string, string>;\n focus: Record<string, string>;\n };\n tokens: ThemeTokens;\n presets: Record<string, TypographyPreset>;\n contrast: {\n light: number;\n dark: number;\n lightContrast: number;\n darkContrast: number;\n };\n diagnostics: DocsDiagnostic[];\n}\n\nexport function resolveDocsTheme(theme: ThemeConfig = {}): ResolvedDocsTheme {\n const brand = normalizeBrand(theme.brand);\n const authoredTarget = brand.contrast?.apca ?? 45;\n const normalTarget = Array.isArray(authoredTarget)\n ? authoredTarget[0]\n : authoredTarget;\n const highTarget = Array.isArray(authoredTarget)\n ? authoredTarget[1]\n : normalTarget + 15;\n const glazeOptions = {\n autoFlip: true,\n ...(theme.contrastLevel !== undefined\n ? { contrastLevel: theme.contrastLevel }\n : {}),\n } as const;\n const surfaceFrom = theme.palette?.surface ?? \"#ffffff\";\n const surface = glaze.color({\n from: surfaceFrom,\n mode: \"auto\",\n // Near-white brand surfaces can carry a numerically large OKHSL\n // saturation that becomes vivid when tone-inverted. Preserve the authored\n // light surface, but keep dark chrome in the neutral-surface range.\n darkSaturation: 0.35,\n });\n const surface2 = glaze.color(\n {\n from: surfaceFrom,\n base: surface,\n tone: [\"-2\", \"-4\"],\n mode: \"auto\",\n darkSaturation: 0.35,\n },\n glazeOptions,\n );\n const surface3 = glaze.color(\n {\n from: surfaceFrom,\n base: surface,\n tone: [\"-4\", \"-8\"],\n mode: \"auto\",\n darkSaturation: 0.35,\n },\n glazeOptions,\n );\n const text = glaze.color(\n {\n from: theme.palette?.text ?? \"#20232a\",\n base: surface,\n role: \"text\",\n contrast: { apca: [75, 90] },\n mode: \"auto\",\n },\n glazeOptions,\n );\n const textSoft = glaze.color(\n {\n from: theme.palette?.textSoft ?? \"#626875\",\n base: surface,\n role: \"text\",\n contrast: { apca: [60, 75] },\n mode: \"auto\",\n },\n glazeOptions,\n );\n const accentText = glaze.color(\n {\n from: brand.from,\n base: surface,\n role: \"text\",\n contrast: { apca: authoredTarget },\n mode: \"auto\",\n },\n glazeOptions,\n );\n const focus = glaze.color(\n {\n from: brand.from,\n base: surface,\n role: \"border\",\n contrast: { apca: authoredTarget },\n mode: \"auto\",\n },\n glazeOptions,\n );\n const accentSurface = glaze.color({ from: brand.from, mode: \"fixed\" });\n const accentSurfaceText = glaze.color({\n from: \"#ffffff\",\n base: accentSurface,\n role: \"text\",\n contrast: { apca: 60 },\n mode: \"auto\",\n });\n\n const resolvedSurface = surface.resolve();\n const resolvedAccent = accentText.resolve();\n const scores = {\n light: score(resolvedAccent.light, resolvedSurface.light),\n dark: score(resolvedAccent.dark, resolvedSurface.dark),\n lightContrast: score(\n resolvedAccent.lightContrast,\n resolvedSurface.lightContrast,\n ),\n darkContrast: score(\n resolvedAccent.darkContrast,\n resolvedSurface.darkContrast,\n ),\n };\n const diagnostics: DocsDiagnostic[] = [];\n for (const [scheme, measured] of Object.entries(scores)) {\n const required = scheme.includes(\"Contrast\") ? highTarget : normalTarget;\n if (measured + 0.05 < required) {\n diagnostics.push({\n code: \"DOCS_BRAND_CONTRAST_UNMET\",\n severity: \"error\",\n message: `Brand contrast in ${scheme} is Lc ${measured.toFixed(1)}; required Lc ${required}.`,\n hint: `Authored color: ${String(brand.from)}.`,\n });\n }\n }\n const outputOptions = { modes: { highContrast: true } } as const;\n const colors = {\n surface: surface.json(outputOptions),\n surface2: surface2.json(outputOptions),\n surface3: surface3.json(outputOptions),\n text: text.json(outputOptions),\n textSoft: textSoft.json(outputOptions),\n accentText: accentText.json(outputOptions),\n accentSurface: accentSurface.json(outputOptions),\n accentSurfaceText: accentSurfaceText.json(outputOptions),\n focus: focus.json(outputOptions),\n };\n return {\n css: themeCss(colors, theme),\n colors,\n tokens: resolveThemeTokens(theme.tokens),\n presets: resolveTypographyPresets(theme.presets),\n contrast: scores,\n diagnostics,\n };\n}\n\nfunction normalizeBrand(\n brand: BrandConfig | undefined,\n): Exclude<BrandConfig, GlazeColorValue> & { from: GlazeColorValue } {\n if (typeof brand === \"object\" && brand !== null && \"from\" in brand)\n return brand;\n return { from: brand ?? \"#315efb\" };\n}\n\nfunction score(\n foreground: ResolvedColorVariant,\n background: ResolvedColorVariant,\n): number {\n return Math.abs(apcaContrast(luminance(foreground), luminance(background)));\n}\n\nfunction luminance(variant: ResolvedColorVariant): number {\n const { h, s, l } = variantToOkhsl(variant);\n return relativeLuminanceFromLinearRgb(\n okhslToLinearSrgb(h, s, l, variant.pastel),\n );\n}\n\nfunction themeCss(\n colors: ResolvedDocsTheme[\"colors\"],\n theme: ThemeConfig,\n): string {\n const tokens = resolveThemeTokens(theme.tokens);\n const presets = resolveTypographyPresets(theme.presets);\n const designDeclarations = [\n ...Object.entries(tokens).map(\n ([name, value]) => `${tokenProperty(name)}:${String(value)}`,\n ),\n ...Object.entries(presets).flatMap(([name, preset]) =>\n Object.entries(preset).map(\n ([property, value]) =>\n `--${kebab(name)}-${kebab(property)}:${String(value)}`,\n ),\n ),\n ].join(\";\");\n const declarations = (mode: string): string =>\n [\n `--td-surface:${colors.surface[mode]}`,\n `--td-surface-2:${colors.surface2[mode]}`,\n `--td-surface-3:${colors.surface3[mode]}`,\n `--td-text:${colors.text[mode]}`,\n `--td-text-soft:${colors.textSoft[mode]}`,\n `--td-accent-text:${colors.accentText[mode]}`,\n `--td-accent-surface:${colors.accentSurface[mode]}`,\n `--td-accent-surface-text:${colors.accentSurfaceText[mode]}`,\n `--td-focus:${colors.focus[mode]}`,\n \"--td-surface-2-hover:color-mix(in oklab,var(--td-text) 3%,var(--td-surface-2))\",\n \"--td-surface-2-pressed:color-mix(in oklab,var(--td-text) 9%,var(--td-surface-2))\",\n \"--td-surface-3-hover:color-mix(in oklab,var(--td-text) 3%,var(--td-surface-3))\",\n \"--td-surface-3-pressed:color-mix(in oklab,var(--td-text) 9%,var(--td-surface-3))\",\n \"--td-border:color-mix(in oklab,var(--td-text) 18%,var(--td-surface))\",\n \"--td-border-strong:color-mix(in oklab,var(--td-text) 34%,var(--td-surface))\",\n \"--td-shadow:color-mix(in oklab,var(--td-text) 16%,transparent)\",\n \"--td-overlay:color-mix(in oklab,var(--td-text) 58%,transparent)\",\n ].join(\";\");\n return [\n `:root{${designDeclarations};${declarations(\"dark\")}}`,\n `:root[data-theme=light]{${declarations(\"light\")}}`,\n `@media(prefers-color-scheme:light){:root:not([data-theme]){${declarations(\"light\")}}}`,\n `@media(prefers-contrast:more){:root{${declarations(\"darkContrast\")}}:root[data-theme=light]{${declarations(\"lightContrast\")}}@media(prefers-color-scheme:light){:root:not([data-theme]){${declarations(\"lightContrast\")}}}}`,\n `:root[data-contrast=more]{${declarations(\"darkContrast\")}}`,\n `:root[data-theme=light][data-contrast=more]{${declarations(\"lightContrast\")}}`,\n ].join(\"\\n\");\n}\n\nfunction tokenProperty(name: string): string {\n if (name.startsWith(\"--\")) return name;\n return `--${name.replace(/^\\$/, \"\")}`;\n}\n\nfunction kebab(value: string): string {\n return value\n .replace(/([a-z0-9])([A-Z])/g, \"$1-$2\")\n .replace(/[^a-zA-Z0-9_-]/g, \"-\")\n .toLowerCase();\n}\n","import { existsSync } from \"node:fs\";\nimport { cp, mkdir, readFile } from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\nimport { dirname, extname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport starlight from \"./starlight-runtime.js\";\nimport {\n createDocsGraph,\n assertValidDocs,\n type DocsConfig,\n type NavigationItem,\n} from \"@tenphi/docs\";\nimport {\n configure,\n type ConfigTokens,\n type Styles,\n type TypographyPreset,\n} from \"@tenphi/tasty/core\";\nimport { tastyIntegration } from \"@tenphi/tasty/ssr/astro\";\nimport type { AstroIntegration, HookParameters } from \"astro\";\nimport {\n resolveNavigationLayout,\n type ResolvedNavigationLayout,\n} from \"./navigation.js\";\nimport { resolveDocsTheme } from \"./theme/index.js\";\n\nconst packageRequire = createRequire(import.meta.url);\nconst starlightRoot = dirname(packageRequire.resolve(\"@astrojs/starlight\"));\nconst tastyStaticMiddleware = packageRequire.resolve(\n \"@tenphi/tasty/ssr/astro-middleware-static\",\n);\n\nexport interface CookbookOptions {\n config?: DocsConfig;\n root?: string;\n}\n\nexport default function cookbook(\n options: CookbookOptions = {},\n): AstroIntegration {\n const docsTheme = resolveDocsTheme(options.config?.theme);\n if (\n docsTheme.diagnostics.some((diagnostic) => diagnostic.severity === \"error\")\n ) {\n throw new Error(\n docsTheme.diagnostics.map((diagnostic) => diagnostic.message).join(\"\\n\"),\n );\n }\n configureTastyTheme(options.config?.theme, docsTheme);\n const cssPath = fileURLToPath(new URL(\"./styles.css\", import.meta.url));\n const searchClientPath = fileURLToPath(\n new URL(\"./client/search.js\", import.meta.url),\n );\n const appearanceClientPath = fileURLToPath(\n new URL(\"./client/appearance.js\", import.meta.url),\n );\n const headerPath = fileURLToPath(\n new URL(\"./overrides/Header.astro\", import.meta.url),\n );\n const sidebarPath = fileURLToPath(\n new URL(\"./overrides/Sidebar.astro\", import.meta.url),\n );\n const components = {\n Header: headerPath,\n Sidebar: sidebarPath,\n ...options.config?.components?.overrides,\n };\n const navigation = resolveNavigationLayout(options.config?.navigation);\n const inner = [\n tastyIntegration({ islands: false }),\n starlight({\n title: options.config?.site?.title ?? \"Documentation\",\n ...(options.config?.site?.description\n ? { description: options.config.site.description }\n : {}),\n customCss: [\"virtual:cookbook/theme.css\", cssPath],\n ...(options.config?.search?.enabled === false ? { pagefind: false } : {}),\n components,\n sidebar: starlightSidebar(navigation),\n }),\n ] satisfies AstroIntegration[];\n let projectRoot = options.root;\n let graphConfig = options.config;\n let graph: Awaited<ReturnType<typeof createDocsGraph>> | undefined;\n let usingStarlight = false;\n\n async function loadGraph(refresh = false) {\n if (!graph || refresh) {\n graph = await createDocsGraph({\n ...(projectRoot ? { root: projectRoot } : {}),\n ...(graphConfig ? { config: graphConfig } : {}),\n });\n assertValidDocs(graph);\n }\n return graph;\n }\n\n return {\n name: \"cookbook\",\n hooks: {\n \"astro:config:setup\": async (context) => {\n if (\n context.config.integrations.some(\n (integration) => integration.name === \"@astrojs/starlight\",\n )\n ) {\n throw new Error(\n \"Cookbook already includes Starlight. Remove the direct @astrojs/starlight integration before continuing.\",\n );\n }\n projectRoot ??= fileURLToPath(context.config.root);\n const base = options.config?.build?.base ?? context.config.base;\n graphConfig = {\n ...options.config,\n build: { ...options.config?.build, base },\n };\n usingStarlight = hasContentConfig(context.config.srcDir);\n context.updateConfig({\n base,\n output: \"static\",\n vite: {\n ssr: {\n external: [\"@tenphi/docs\"],\n },\n plugins: [\n virtualDocsPlugin(\n docsTheme.css,\n () => ({\n entries: graph?.entries ?? [],\n routes: graph?.routes ?? [],\n site: graph?.config.site ?? options.config?.site ?? {},\n base: graph?.config.build.base ?? base,\n search:\n graph?.config.search.enabled ??\n options.config?.search?.enabled ??\n true,\n }),\n navigation,\n ),\n ],\n resolve: {\n alias: [\n {\n find: \"@astrojs/starlight\",\n replacement: starlightRoot,\n },\n {\n find: \"@tenphi/tasty/ssr/astro-middleware-static\",\n replacement: tastyStaticMiddleware,\n },\n ],\n },\n },\n });\n await callInner(inner.slice(0, 1), \"astro:config:setup\", context);\n\n if (!usingStarlight) {\n graph = await createDocsGraph({\n root: projectRoot,\n config: graphConfig,\n });\n assertValidDocs(graph);\n if (graph.config.search.enabled) {\n context.injectScript(\n \"page\",\n `import ${JSON.stringify(searchClientPath)};`,\n );\n }\n context.injectScript(\n \"page\",\n `import ${JSON.stringify(appearanceClientPath)};`,\n );\n context.injectRoute({\n pattern: \"[...route]\",\n entrypoint: new URL(\"./routes/DocsPage.astro\", import.meta.url),\n prerender: true,\n });\n return;\n }\n\n // Starlight inserts its own follow-up integrations immediately after\n // itself. Give it a temporary real position so Astro processes those\n // once, after this composite integration, rather than re-visiting us.\n const starlightIntegration = inner[1];\n if (starlightIntegration) {\n const selfIndex = context.config.integrations.findIndex(\n (integration) => integration.name === \"cookbook\",\n );\n context.config.integrations.splice(\n selfIndex + 1,\n 0,\n starlightIntegration,\n );\n try {\n await callInner(\n [starlightIntegration],\n \"astro:config:setup\",\n context,\n );\n } finally {\n const placeholderIndex =\n context.config.integrations.indexOf(starlightIntegration);\n if (placeholderIndex >= 0)\n context.config.integrations.splice(placeholderIndex, 1);\n }\n }\n },\n \"astro:config:done\": async (context) => {\n await callInner(\n usingStarlight ? inner : inner.slice(0, 1),\n \"astro:config:done\",\n context,\n );\n },\n \"astro:server:setup\": async ({ server }) => {\n let assets = docsAssetMap(await loadGraph());\n server.middlewares.use(async (request, response, next) => {\n if (request.method !== \"GET\" && request.method !== \"HEAD\") {\n next();\n return;\n }\n const pathname = requestPath(request.url);\n if (!pathname.includes(\"/_tasty-assets/\")) {\n next();\n return;\n }\n let asset = assets.get(pathname);\n if (!asset) {\n try {\n assets = docsAssetMap(await loadGraph(true));\n } catch {\n next();\n return;\n }\n asset = assets.get(pathname);\n }\n if (!asset?.sourcePath) {\n next();\n return;\n }\n try {\n const body = await readFile(asset.sourcePath);\n response.statusCode = 200;\n response.setHeader(\"Content-Type\", assetContentType(pathname));\n response.setHeader(\"Content-Length\", body.byteLength);\n response.setHeader(\"Cache-Control\", \"no-cache\");\n response.end(request.method === \"HEAD\" ? undefined : body);\n } catch {\n next();\n }\n });\n },\n \"astro:build:start\": async (context) => {\n await loadGraph();\n await callInner(\n usingStarlight ? inner : inner.slice(0, 1),\n \"astro:build:start\",\n context,\n );\n },\n \"astro:build:done\": async (context) => {\n await callInner(\n usingStarlight ? inner : inner.slice(0, 1),\n \"astro:build:done\",\n context,\n );\n if (!graph) return;\n const output = fileURLToPath(context.dir);\n for (const asset of graph.assets) {\n if (!asset.sourcePath || !asset.publicPath) continue;\n const target = join(output, asset.publicPath.replace(/^\\//, \"\"));\n await mkdir(dirname(target), { recursive: true });\n await cp(asset.sourcePath, target);\n }\n if (!usingStarlight && graph.config.search.enabled) {\n const { close, createIndex } = await import(\"pagefind\");\n const created = await createIndex({\n rootSelector: \"[data-pagefind-body]\",\n });\n if (!created.index || created.errors.length > 0) {\n throw new Error(\n `Pagefind failed to start: ${created.errors.join(\"; \")}`,\n );\n }\n const indexed = await created.index.addDirectory({ path: output });\n if (indexed.errors.length > 0) {\n throw new Error(\n `Pagefind failed to index the site: ${indexed.errors.join(\"; \")}`,\n );\n }\n const written = await created.index.writeFiles({\n outputPath: join(output, \"pagefind\"),\n });\n await close();\n if (written.errors.length > 0) {\n throw new Error(\n `Pagefind failed to write the index: ${written.errors.join(\"; \")}`,\n );\n }\n }\n },\n },\n };\n}\n\nfunction docsAssetMap(graph: Awaited<ReturnType<typeof createDocsGraph>>) {\n return new Map(\n graph.assets.flatMap((asset) =>\n asset.publicPath && asset.sourcePath\n ? [[asset.publicPath, asset] as const]\n : [],\n ),\n );\n}\n\nfunction requestPath(url: string | undefined): string {\n try {\n return decodeURIComponent(new URL(url ?? \"/\", \"http://localhost\").pathname);\n } catch {\n return \"\";\n }\n}\n\nfunction assetContentType(pathname: string): string {\n switch (extname(pathname).toLowerCase()) {\n case \".avif\":\n return \"image/avif\";\n case \".gif\":\n return \"image/gif\";\n case \".jpeg\":\n case \".jpg\":\n return \"image/jpeg\";\n case \".png\":\n return \"image/png\";\n case \".svg\":\n return \"image/svg+xml\";\n case \".webp\":\n return \"image/webp\";\n default:\n return \"application/octet-stream\";\n }\n}\n\nfunction configureTastyTheme(\n theme: DocsConfig[\"theme\"],\n resolved: ReturnType<typeof resolveDocsTheme>,\n): void {\n const tokens = Object.fromEntries(\n Object.entries(resolved.tokens).filter(([name]) => name.startsWith(\"$\")),\n ) as ConfigTokens;\n Object.assign(tokens, {\n \"#surface\": \"var(--td-surface)\",\n \"#surface-2\": \"var(--td-surface-2)\",\n \"#surface-3\": \"var(--td-surface-3)\",\n \"#text\": \"var(--td-text)\",\n \"#text-soft\": \"var(--td-text-soft)\",\n \"#border\": \"var(--td-border)\",\n \"#border-strong\": \"var(--td-border-strong)\",\n \"#accent-text\": \"var(--td-accent-text)\",\n \"#accent-surface\": \"var(--td-accent-surface)\",\n \"#accent-surface-text\": \"var(--td-accent-surface-text)\",\n \"#focus\": \"var(--td-focus)\",\n } satisfies ConfigTokens);\n\n const globalStyles = anatomyStyles(theme?.styles);\n configure({\n ...(theme?.states ? { states: theme.states } : {}),\n units: {\n x: \"var(--gap)\",\n r: \"var(--radius)\",\n cr: \"var(--card-radius)\",\n bw: \"var(--border-width)\",\n },\n tokens,\n presets: resolved.presets as Record<string, TypographyPreset>,\n ...(globalStyles ? { globalStyles } : {}),\n });\n}\n\nfunction anatomyStyles(\n styles: Record<string, unknown> | undefined,\n): Record<string, Styles> | undefined {\n if (!styles) return undefined;\n return Object.fromEntries(\n Object.entries(styles)\n .filter((entry): entry is [string, Styles] => isRecord(entry[1]))\n .map(([name, value]) => [`[data-tasty-anatomy=\"${name}\"]`, value]),\n );\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction starlightSidebar(layout: ResolvedNavigationLayout): unknown[] {\n const fallback = layout.items?.length\n ? layout.items.map(starlightSidebarItem)\n : [{ autogenerate: { directory: \"\" } }];\n if (!layout.sectioned) return fallback;\n\n return [\n ...(layout.fallbackSidebarGroup !== undefined\n ? [\n {\n label: \"Documentation\",\n items: (layout.items ?? []).map(starlightSidebarItem),\n },\n ]\n : []),\n ...layout.tabs.flatMap((tab) =>\n tab.items !== undefined\n ? [{ label: tab.label, items: tab.items.map(starlightSidebarItem) }]\n : [],\n ),\n ];\n}\n\nfunction starlightSidebarItem(item: NavigationItem): unknown {\n if (typeof item === \"string\") return { slug: routeToSlug(item) };\n if (\"items\" in item) {\n return {\n label: item.label,\n items: item.items.map(starlightSidebarItem),\n };\n }\n if (\"autogenerate\" in item) {\n return {\n label: item.label,\n items: [\n {\n autogenerate: {\n directory: routeToSlug(item.autogenerate.directory, false),\n },\n },\n ],\n };\n }\n return { label: item.label, link: item.link };\n}\n\nfunction routeToSlug(route: string, rootAsIndex = true): string {\n const slug = route.replace(/^\\/+|\\/+$/g, \"\");\n return slug || (rootAsIndex ? \"index\" : \"\");\n}\n\nexport function tastyStarlight(\n config: Parameters<typeof starlight>[0],\n): AstroIntegration {\n return starlight(config);\n}\n\nasync function callInner<K extends keyof AstroIntegration[\"hooks\"]>(\n integrations: AstroIntegration[],\n hook: K,\n context: HookParameters<K>,\n): Promise<void> {\n for (const integration of integrations) {\n const handler = integration.hooks[hook];\n if (typeof handler === \"function\") {\n await (handler as (value: HookParameters<K>) => void | Promise<void>)(\n context,\n );\n }\n }\n}\n\nfunction virtualDocsPlugin(\n css: string,\n getContent: () => unknown,\n layout: ResolvedNavigationLayout,\n) {\n const themeId = \"\\0virtual:cookbook/theme.css\";\n const configId = \"\\0virtual:cookbook/config\";\n const layoutId = \"\\0virtual:cookbook/layout\";\n return {\n name: \"cookbook-theme\",\n resolveId(id: string) {\n if (id === \"virtual:cookbook/theme.css\") return themeId;\n if (id === \"virtual:cookbook/config\") return configId;\n if (id === \"virtual:cookbook/layout\") return layoutId;\n return undefined;\n },\n load(id: string) {\n if (id === themeId) return css;\n if (id === configId) {\n return `export const content = ${JSON.stringify(getContent())};`;\n }\n if (id === layoutId) {\n return `export const layout = ${JSON.stringify(layout)};`;\n }\n return undefined;\n },\n };\n}\n\nfunction hasContentConfig(srcDir: URL): boolean {\n const source = fileURLToPath(srcDir);\n return [\n \"content.config.ts\",\n \"content.config.mts\",\n \"content.config.js\",\n \"content.config.mjs\",\n \"content/config.ts\",\n ].some((path) => existsSync(join(source, path)));\n}\n"],"mappings":"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"}