@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/README.md +1 -1
- package/dist/client/appearance.js +1 -1
- package/dist/client/appearance.js.map +1 -1
- package/dist/client/search.js +14 -1
- package/dist/client/search.js.map +1 -1
- package/dist/components/MobileNavigationTabs.astro +40 -0
- package/dist/components/NavigationTree.astro +98 -0
- package/dist/icons/arrow-left.svg +1 -0
- package/dist/icons/arrow-right.svg +1 -0
- package/dist/icons/chevron-down.svg +1 -0
- package/dist/icons/chevron-right.svg +1 -0
- package/dist/icons/close.svg +1 -0
- package/dist/icons/contrast.svg +1 -0
- package/dist/icons/copy.svg +1 -0
- package/dist/icons/device-desktop.svg +1 -0
- package/dist/icons/menu.svg +1 -0
- package/dist/icons/moon.svg +1 -0
- package/dist/icons/search.svg +1 -0
- package/dist/icons/sun.svg +1 -0
- package/dist/index.d.ts +25 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +312 -35
- package/dist/index.js.map +1 -1
- package/dist/navigation-CC0dlAL8.js +78 -0
- package/dist/navigation-CC0dlAL8.js.map +1 -0
- package/dist/navigation.d.ts +21 -0
- package/dist/navigation.d.ts.map +1 -0
- package/dist/navigation.js +2 -0
- package/dist/overrides/Header.astro +49 -0
- package/dist/overrides/Sidebar.astro +42 -0
- package/dist/routes/DocsPage.astro +72 -43
- package/dist/styles.css +1223 -68
- package/package.json +9 -6
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:
|
|
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
|
-
},
|
|
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
|
-
|
|
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
|
|
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:
|
|
271
|
+
customCss: ["virtual:cookbook/theme.css", cssPath],
|
|
125
272
|
...options.config?.search?.enabled === false ? { pagefind: false } : {},
|
|
126
|
-
|
|
127
|
-
|
|
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: "
|
|
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("
|
|
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 === "
|
|
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
|
-
|
|
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:
|
|
247
|
-
const configId = "\0virtual:
|
|
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: "
|
|
524
|
+
name: "cookbook-theme",
|
|
250
525
|
resolveId(id) {
|
|
251
|
-
if (id === "virtual:
|
|
252
|
-
if (id === "virtual:
|
|
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,
|
|
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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"}
|