@tenphi/starlight 0.6.1 → 0.7.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
@@ -2,7 +2,7 @@ import { n as starlight, t as createStarlightCollection } from "./content-Cwk8rm
2
2
  import { a as resolveNavigationLayout } from "./navigation-CkQXI2Zb.js";
3
3
  import { createRequire } from "node:module";
4
4
  import { existsSync } from "node:fs";
5
- import { cp, mkdir, readFile } from "node:fs/promises";
5
+ import { cp, mkdir, readFile, readdir, unlink, writeFile } from "node:fs/promises";
6
6
  import { dirname, extname, join } from "node:path";
7
7
  import { fileURLToPath, pathToFileURL } from "node:url";
8
8
  import { COOKBOOK_COMPONENT_NAMES, assertValidDocs, createDocsGraph } from "@tenphi/docs";
@@ -109,80 +109,39 @@ function resolveDocsTheme(theme = {}) {
109
109
  ...theme.contrastLevel !== void 0 ? { contrastLevel: theme.contrastLevel } : {}
110
110
  };
111
111
  const surfaceFrom = theme.palette?.surface ?? "#ffffff";
112
- const surface = glaze.color({
112
+ const resolvedSurfaceSeed = glaze.color({
113
113
  from: surfaceFrom,
114
114
  mode: "auto",
115
115
  darkSaturation: .35
116
- });
117
- const surface2 = glaze.color({
118
- from: surfaceFrom,
119
- base: surface,
120
- tone: "-2",
121
- mode: "auto",
122
- saturationFactor: .9,
123
- darkSaturation: .325
124
- }, glazeOptions);
125
- const surface3 = glaze.color({
126
- from: surfaceFrom,
127
- base: surface2,
128
- tone: "-2",
129
- mode: "auto",
130
- saturationFactor: .8,
131
- darkSaturation: .3
132
- }, glazeOptions);
133
- const text = glaze.color({
134
- from: theme.palette?.text ?? "#20232a",
135
- base: surface,
136
- role: "text",
137
- contrast: { apca: [75, 90] },
138
- mode: "auto"
139
- }, glazeOptions);
140
- const textSoft = glaze.color({
141
- from: theme.palette?.textSoft ?? "#626875",
142
- base: surface,
143
- role: "text",
144
- contrast: { apca: [60, 75] },
145
- mode: "auto"
146
- }, glazeOptions);
147
- const accentText = glaze.color({
148
- from: brand.from,
149
- base: surface,
150
- role: "text",
151
- contrast: { apca: authoredTarget },
152
- mode: "auto"
153
- }, glazeOptions);
154
- const focus = glaze.color({
155
- from: brand.from,
156
- base: surface,
157
- role: "border",
158
- contrast: { apca: authoredTarget },
159
- mode: "auto"
160
- }, glazeOptions);
161
- const accentSurface = glaze.color({
162
- from: brand.from,
163
- mode: "fixed"
164
- });
165
- const accentSurfaceText = glaze.color({
166
- from: "#ffffff",
167
- base: accentSurface,
168
- role: "text",
169
- contrast: { apca: 60 },
170
- mode: "auto"
171
- });
172
- const resolvedSurface = surface.resolve();
173
- const resolvedAccent = accentText.resolve();
174
- const shadowTheme = glaze({
175
- hue: variantToOkhsl(resolvedSurface.light).h,
176
- saturation: variantToOkhsl(resolvedSurface.light).s * 100,
177
- darkHue: variantToOkhsl(resolvedSurface.dark).h,
178
- darkSaturation: variantToOkhsl(resolvedSurface.dark).s * 100
116
+ }).resolve();
117
+ const lightSurface = variantToOkhsl(resolvedSurfaceSeed.light);
118
+ const darkSurface = variantToOkhsl(resolvedSurfaceSeed.dark);
119
+ const colorTheme = glaze({
120
+ hue: lightSurface.h,
121
+ saturation: lightSurface.s * 100,
122
+ darkHue: darkSurface.h,
123
+ darkSaturation: Math.min(100, darkSurface.s * 100 / .35)
179
124
  }, void 0, glazeOptions);
180
- shadowTheme.colors({
125
+ colorTheme.colors({
181
126
  surface: {
182
127
  from: surfaceFrom,
183
128
  mode: "auto",
184
129
  darkSaturation: .35
185
130
  },
131
+ "surface-2": {
132
+ base: "surface",
133
+ tone: "-2",
134
+ mode: "auto",
135
+ saturation: .75,
136
+ darkSaturation: .275
137
+ },
138
+ "surface-3": {
139
+ base: "surface-2",
140
+ tone: "-2",
141
+ mode: "auto",
142
+ saturation: .65,
143
+ darkSaturation: .25
144
+ },
186
145
  text: {
187
146
  from: theme.palette?.text ?? "#20232a",
188
147
  base: "surface",
@@ -190,14 +149,176 @@ function resolveDocsTheme(theme = {}) {
190
149
  contrast: { apca: [75, 90] },
191
150
  mode: "auto"
192
151
  },
152
+ "text-soft": {
153
+ from: theme.palette?.textSoft ?? "#626875",
154
+ base: "surface",
155
+ role: "text",
156
+ contrast: { apca: [60, 75] },
157
+ mode: "auto"
158
+ },
159
+ "text-muted": mix("surface", "text", 66),
160
+ "surface-2-hover": mix("surface-2", "text", [3, 6]),
161
+ "surface-2-pressed": mix("surface-2", "text", [9, 14]),
162
+ "surface-3-hover": mix("surface-3", "text", [3, 6]),
163
+ "surface-3-pressed": mix("surface-3", "text", [9, 14]),
164
+ "accent-text": {
165
+ from: brand.from,
166
+ base: "surface",
167
+ role: "text",
168
+ contrast: { apca: [normalTarget, highTarget] },
169
+ mode: "auto"
170
+ },
171
+ focus: {
172
+ from: brand.from,
173
+ base: "surface",
174
+ role: "border",
175
+ contrast: { apca: [normalTarget, highTarget] },
176
+ mode: "auto"
177
+ },
178
+ "accent-surface": {
179
+ from: brand.from,
180
+ mode: "fixed"
181
+ },
182
+ "accent-surface-text": {
183
+ from: "#ffffff",
184
+ base: "accent-surface",
185
+ role: "text",
186
+ contrast: { apca: [60, 75] },
187
+ mode: "auto"
188
+ },
189
+ "accent-surface-subtle": mix("surface", "accent-surface", [12, 18]),
190
+ "accent-surface-2-subtle": mix("surface-2", "accent-surface", [12, 18]),
193
191
  shadow: {
194
192
  type: "shadow",
195
193
  bg: "surface",
196
194
  fg: "text",
197
195
  intensity: [12, 20],
198
196
  tuning: { alphaMax: .28 }
197
+ },
198
+ overlay: {
199
+ type: "mix",
200
+ base: "surface",
201
+ target: "text",
202
+ value: [58, 68],
203
+ blend: "transparent"
204
+ },
205
+ clear: {
206
+ from: "#ffffff",
207
+ mode: "fixed",
208
+ opacity: 0
209
+ },
210
+ ...statusColors("orange", "#d97706"),
211
+ ...statusColors("green", "#16a34a"),
212
+ ...statusColors("blue", "#2563eb"),
213
+ ...statusColors("purple", "#9333ea"),
214
+ ...statusColors("red", "#dc2626")
215
+ });
216
+ const resolvedBrandSeed = glaze.color({
217
+ from: brand.from,
218
+ mode: "fixed"
219
+ }).resolve();
220
+ const lightBrand = variantToOkhsl(resolvedBrandSeed.light);
221
+ const darkBrand = variantToOkhsl(resolvedBrandSeed.dark);
222
+ const borderTheme = glaze({
223
+ hue: lightBrand.h,
224
+ saturation: lightBrand.s * 100,
225
+ darkHue: darkBrand.h,
226
+ darkSaturation: darkBrand.s * 100
227
+ }, void 0, glazeOptions);
228
+ borderTheme.colors({
229
+ surface: {
230
+ from: surfaceFrom,
231
+ mode: "auto",
232
+ darkSaturation: .35
233
+ },
234
+ border: {
235
+ base: "surface",
236
+ tone: ["-9", "-22"],
237
+ saturation: .205,
238
+ mode: "auto"
239
+ },
240
+ "border-strong": {
241
+ base: "surface",
242
+ tone: ["-20", "-38"],
243
+ saturation: .205,
244
+ mode: "auto"
199
245
  }
200
246
  });
247
+ const syntaxTheme = glaze(210, 90, glazeOptions);
248
+ syntaxTheme.colors({
249
+ bg: {
250
+ tone: 100,
251
+ saturation: .1
252
+ },
253
+ text: {
254
+ base: "bg",
255
+ tone: 0,
256
+ contrast: { wcag: ["AA", "AAA"] },
257
+ saturation: 0
258
+ },
259
+ comment: {
260
+ base: "bg",
261
+ contrast: { wcag: ["AA", "AAA"] },
262
+ saturation: .01,
263
+ hue: 210
264
+ },
265
+ punctuation: {
266
+ base: "bg",
267
+ contrast: { wcag: [6, "AAA"] },
268
+ saturation: .01,
269
+ hue: 210
270
+ },
271
+ keyword: {
272
+ base: "bg",
273
+ contrast: { wcag: ["AA", "AAA"] },
274
+ saturation: 80
275
+ },
276
+ string: {
277
+ base: "bg",
278
+ contrast: { wcag: ["AA", "AAA"] },
279
+ saturation: 80,
280
+ hue: 15
281
+ },
282
+ token: {
283
+ base: "bg",
284
+ contrast: { wcag: ["AA", "AAA"] },
285
+ saturation: 80,
286
+ hue: 125
287
+ },
288
+ property: {
289
+ base: "bg",
290
+ contrast: { wcag: ["AA", "AAA"] },
291
+ saturation: 80,
292
+ hue: 155
293
+ },
294
+ number: {
295
+ base: "bg",
296
+ contrast: { wcag: ["AA", "AAA"] },
297
+ saturation: 80,
298
+ hue: 70
299
+ },
300
+ function: {
301
+ base: "bg",
302
+ contrast: { wcag: ["AA", "AAA"] },
303
+ saturation: 80,
304
+ hue: 210
305
+ },
306
+ value: {
307
+ base: "bg",
308
+ contrast: { wcag: ["AA", "AAA"] },
309
+ saturation: 80,
310
+ hue: 210
311
+ },
312
+ operator: {
313
+ base: "bg",
314
+ contrast: { wcag: ["AA", "AAA"] },
315
+ saturation: 80,
316
+ hue: 340
317
+ }
318
+ });
319
+ const resolvedColors = colorTheme.resolve();
320
+ const resolvedSurface = requiredResolvedColor(resolvedColors, "surface");
321
+ const resolvedAccent = requiredResolvedColor(resolvedColors, "accent-text");
201
322
  const scores = {
202
323
  light: score(resolvedAccent.light, resolvedSurface.light),
203
324
  dark: score(resolvedAccent.dark, resolvedSurface.dark),
@@ -215,20 +336,39 @@ function resolveDocsTheme(theme = {}) {
215
336
  });
216
337
  }
217
338
  const outputOptions = { modes: { highContrast: true } };
218
- const shadow = shadowTheme.json(outputOptions).shadow;
219
- if (!shadow) throw new Error("The Glaze shadow token failed to resolve.");
339
+ const tastyOptions = {
340
+ ...outputOptions,
341
+ states: {
342
+ dark: "theme=dark | (@media(prefers-color-scheme: dark) & :not([data-theme]))",
343
+ highContrast: "contrast=more | (@media(prefers-contrast: more) & :not([data-contrast]))"
344
+ }
345
+ };
346
+ const resolvedPalette = colorTheme.json(outputOptions);
347
+ const colorTokens = colorTheme.tasty(tastyOptions);
348
+ const borderTokens = borderTheme.tasty(tastyOptions);
349
+ const syntaxTokens = glaze.palette({ syntax: syntaxTheme }).tasty({
350
+ ...tastyOptions,
351
+ prefix: true,
352
+ primary: false
353
+ });
220
354
  return {
221
355
  colors: {
222
- surface: surface.json(outputOptions),
223
- surface2: surface2.json(outputOptions),
224
- surface3: surface3.json(outputOptions),
225
- text: text.json(outputOptions),
226
- textSoft: textSoft.json(outputOptions),
227
- accentText: accentText.json(outputOptions),
228
- accentSurface: accentSurface.json(outputOptions),
229
- accentSurfaceText: accentSurfaceText.json(outputOptions),
230
- focus: focus.json(outputOptions),
231
- shadow
356
+ surface: requiredJsonColor(resolvedPalette, "surface"),
357
+ surface2: requiredJsonColor(resolvedPalette, "surface-2"),
358
+ surface3: requiredJsonColor(resolvedPalette, "surface-3"),
359
+ text: requiredJsonColor(resolvedPalette, "text"),
360
+ textSoft: requiredJsonColor(resolvedPalette, "text-soft"),
361
+ accentText: requiredJsonColor(resolvedPalette, "accent-text"),
362
+ accentSurface: requiredJsonColor(resolvedPalette, "accent-surface"),
363
+ accentSurfaceText: requiredJsonColor(resolvedPalette, "accent-surface-text"),
364
+ focus: requiredJsonColor(resolvedPalette, "focus"),
365
+ shadow: requiredJsonColor(resolvedPalette, "shadow")
366
+ },
367
+ colorTokens: {
368
+ ...colorTokens,
369
+ "#border": requiredJsonColor(borderTokens, "#border"),
370
+ "#border-strong": requiredJsonColor(borderTokens, "#border-strong"),
371
+ ...syntaxTokens
232
372
  },
233
373
  tokens: resolveThemeTokens(theme.tokens),
234
374
  presets: resolveTypographyPresets(theme.presets),
@@ -236,6 +376,44 @@ function resolveDocsTheme(theme = {}) {
236
376
  diagnostics
237
377
  };
238
378
  }
379
+ function mix(base, target, value, space = "okhsl") {
380
+ return {
381
+ type: "mix",
382
+ base,
383
+ target,
384
+ value,
385
+ space
386
+ };
387
+ }
388
+ function statusColors(name, from) {
389
+ return {
390
+ [name]: {
391
+ from,
392
+ base: "surface",
393
+ role: "border",
394
+ contrast: { apca: [30, 45] },
395
+ mode: "auto"
396
+ },
397
+ [`${name}-text`]: {
398
+ from,
399
+ base: "surface",
400
+ role: "text",
401
+ contrast: { apca: [60, 75] },
402
+ mode: "auto"
403
+ },
404
+ [`${name}-surface`]: mix("surface", name, [12, 18], "srgb")
405
+ };
406
+ }
407
+ function requiredResolvedColor(colors, name) {
408
+ const color = colors.get(name);
409
+ if (!color) throw new Error(`The Glaze ${name} color failed to resolve.`);
410
+ return color;
411
+ }
412
+ function requiredJsonColor(colors, name) {
413
+ const color = colors[name];
414
+ if (!color) throw new Error(`The Glaze ${name} token failed to export.`);
415
+ return color;
416
+ }
239
417
  function normalizeBrand(brand) {
240
418
  if (typeof brand === "object" && brand !== null && "from" in brand) return brand;
241
419
  return { from: brand ?? "#315efb" };
@@ -248,6 +426,183 @@ function luminance(variant) {
248
426
  return relativeLuminanceFromLinearRgb(okhslToLinearSrgb(h, s, l, variant.pastel));
249
427
  }
250
428
  //#endregion
429
+ //#region src/theme/shiki-theme.ts
430
+ const comment = "var(--syntax-comment-color)";
431
+ const punctuation = "var(--syntax-punctuation-color)";
432
+ const keyword = "var(--syntax-keyword-color)";
433
+ const string = "var(--syntax-string-color)";
434
+ const token = "var(--syntax-token-color)";
435
+ const property = "var(--syntax-property-color)";
436
+ const number = "var(--syntax-number-color)";
437
+ const func = "var(--syntax-function-color)";
438
+ const value = "var(--syntax-value-color)";
439
+ const operator = "var(--syntax-operator-color)";
440
+ const foreground = "var(--syntax-text-color)";
441
+ const background = "var(--syntax-bg-color)";
442
+ /**
443
+ * Shiki performs the grammatical classification, while every emitted color
444
+ * remains a reference to a Glaze-generated token owned by Tasty.
445
+ */
446
+ const tastyCodeTheme = {
447
+ name: "tasty-code",
448
+ type: "light",
449
+ fg: foreground,
450
+ bg: background,
451
+ colors: {
452
+ "editor.background": background,
453
+ "editor.foreground": foreground
454
+ },
455
+ settings: [
456
+ {
457
+ scope: [
458
+ "comment",
459
+ "comment.line",
460
+ "comment.block",
461
+ "punctuation.definition.comment"
462
+ ],
463
+ settings: {
464
+ foreground: comment,
465
+ fontStyle: "italic"
466
+ }
467
+ },
468
+ {
469
+ scope: [
470
+ "keyword",
471
+ "keyword.control",
472
+ "keyword.other",
473
+ "storage.type",
474
+ "storage.modifier",
475
+ "keyword.control.at-rule.tasty",
476
+ "keyword.control.at-rule.media.tasty",
477
+ "keyword.control.at-rule.media-type.tasty",
478
+ "keyword.control.at-rule.starting.tasty",
479
+ "keyword.control.state-alias.tasty"
480
+ ],
481
+ settings: { foreground: keyword }
482
+ },
483
+ {
484
+ scope: [
485
+ "string",
486
+ "string.quoted",
487
+ "string.template",
488
+ "string.quoted.attribute-value.tasty",
489
+ "string.unquoted.attribute-value.tasty"
490
+ ],
491
+ settings: { foreground: string }
492
+ },
493
+ {
494
+ scope: [
495
+ "support.constant.color.tasty-token",
496
+ "support.constant.color.tasty-token.builtin",
497
+ "constant.other.color.tasty-token",
498
+ "constant.other.color.tasty",
499
+ "constant.other.color.hex",
500
+ "constant.other.color.rgb-value"
501
+ ],
502
+ settings: { foreground: token }
503
+ },
504
+ {
505
+ scope: [
506
+ "constant.numeric",
507
+ "constant.numeric.tasty",
508
+ "constant.numeric.custom-unit.tasty",
509
+ "constant.numeric.css-with-unit",
510
+ "constant.numeric.bare.tasty",
511
+ "constant.numeric.css",
512
+ "constant.numeric.keyframe-step.tasty",
513
+ "constant.language.boolean.tasty"
514
+ ],
515
+ settings: { foreground: number }
516
+ },
517
+ {
518
+ scope: ["support.type.property-name.tasty", "variable.other.constant.tasty"],
519
+ settings: { foreground: property }
520
+ },
521
+ {
522
+ scope: ["variable", "variable.other"],
523
+ settings: { foreground }
524
+ },
525
+ {
526
+ scope: [
527
+ "entity.name.function",
528
+ "support.function",
529
+ "support.function.misc.css",
530
+ "entity.name.tag",
531
+ "entity.name.tag.tsx",
532
+ "entity.name.type.tasty",
533
+ "entity.name.tag.tasty"
534
+ ],
535
+ settings: { foreground: func }
536
+ },
537
+ {
538
+ scope: [
539
+ "support.constant.property-value.tasty",
540
+ "support.constant.property-value.tasty-display",
541
+ "support.constant.property-value.tasty-directional",
542
+ "support.constant.property-value.tasty-preset",
543
+ "support.constant.property-value.tasty-shape",
544
+ "support.constant.property-value.tasty-scrollbar",
545
+ "support.constant.property-value.tasty-state",
546
+ "support.constant.property-value.tasty-cursor",
547
+ "support.constant.property-value.tasty-overflow",
548
+ "support.constant.property-value.tasty-position",
549
+ "support.constant.property-value.tasty-flex",
550
+ "support.constant.property-value.tasty-font",
551
+ "support.constant.property-value.tasty-text",
552
+ "support.constant.property-value.tasty-alignment",
553
+ "support.constant.property-value.tasty-border-style",
554
+ "support.constant.property-value.tasty-whitespace",
555
+ "support.constant.property-value.tasty-global",
556
+ "support.constant.property-value.tasty-transition",
557
+ "support.constant.property-value.css-syntax",
558
+ "entity.other.attribute-name",
559
+ "entity.other.attribute-name.tasty",
560
+ "entity.other.attribute-name.pseudo-class.tasty",
561
+ "entity.other.attribute-name.pseudo-class.css",
562
+ "entity.other.attribute-name.class.tasty",
563
+ "entity.other.attribute-name.pseudo-element.css",
564
+ "punctuation.definition.entity.css"
565
+ ],
566
+ settings: { foreground: value }
567
+ },
568
+ {
569
+ scope: [
570
+ "keyword.operator",
571
+ "keyword.operator.logical.tasty",
572
+ "keyword.operator.arithmetic.css",
573
+ "keyword.operator.assignment",
574
+ "keyword.operator.selector-affix.tasty",
575
+ "keyword.operator.attribute-selector.tasty",
576
+ "keyword.operator.comparison.tasty"
577
+ ],
578
+ settings: { foreground: operator }
579
+ },
580
+ {
581
+ scope: [
582
+ "punctuation.definition.string",
583
+ "punctuation.separator",
584
+ "punctuation.definition.block",
585
+ "punctuation.definition.array",
586
+ "punctuation.section",
587
+ "punctuation.definition.auto-calc",
588
+ "punctuation.definition.attribute-selector",
589
+ "punctuation.definition.pseudo-class",
590
+ "punctuation.definition.fallback",
591
+ "meta.brace"
592
+ ],
593
+ settings: { foreground: punctuation }
594
+ },
595
+ {
596
+ scope: ["keyword.control.at-rule", "entity.name.tag.class.css"],
597
+ settings: { foreground: keyword }
598
+ },
599
+ {
600
+ scope: ["support.type.property-name.css", "meta.property-name.css"],
601
+ settings: { foreground: property }
602
+ }
603
+ ]
604
+ };
605
+ //#endregion
251
606
  //#region src/theme/tasty-config.ts
252
607
  const TASTY_UNITS = {
253
608
  x: "var(--gap)",
@@ -255,42 +610,11 @@ const TASTY_UNITS = {
255
610
  cr: "var(--card-radius)",
256
611
  bw: "var(--border-width)"
257
612
  };
258
- const LIGHT = "theme=light | (@media(prefers-color-scheme: light) & :not([data-theme]))";
259
- const HIGH_CONTRAST = "contrast=more | (@media(prefers-contrast: more) & :not([data-contrast]))";
260
613
  function tastyTokens(theme) {
261
614
  const tokens = Object.fromEntries(Object.entries(theme.tokens).filter(([name]) => name.startsWith("$")));
262
- Object.assign(tokens, {
263
- "#surface": colorStates(theme.colors.surface),
264
- "#surface-2": colorStates(theme.colors.surface2),
265
- "#surface-3": colorStates(theme.colors.surface3),
266
- "#surface-2-hover": mix("#text", 3, "#surface-2"),
267
- "#surface-2-pressed": mix("#text", 9, "#surface-2"),
268
- "#surface-3-hover": mix("#text", 3, "#surface-3"),
269
- "#surface-3-pressed": mix("#text", 9, "#surface-3"),
270
- "#text": colorStates(theme.colors.text),
271
- "#text-soft": colorStates(theme.colors.textSoft),
272
- "#border": mix("#text", 18, "#surface"),
273
- "#border-strong": mix("#text", 34, "#surface"),
274
- "#accent-text": colorStates(theme.colors.accentText),
275
- "#accent-surface": colorStates(theme.colors.accentSurface),
276
- "#accent-surface-text": colorStates(theme.colors.accentSurfaceText),
277
- "#focus": colorStates(theme.colors.focus),
278
- "#shadow": colorStates(theme.colors.shadow),
279
- "#overlay": mix("#text", 58, "transparent")
280
- });
615
+ Object.assign(tokens, theme.colorTokens);
281
616
  return tokens;
282
617
  }
283
- function colorStates(colors) {
284
- return {
285
- "": colors.dark,
286
- [LIGHT]: colors.light,
287
- [HIGH_CONTRAST]: colors.darkContrast,
288
- [`(${LIGHT}) & (${HIGH_CONTRAST})`]: colors.lightContrast
289
- };
290
- }
291
- function mix(foreground, percentage, background) {
292
- return `color-mix(in oklab, ${foreground} ${percentage}%, ${background})`;
293
- }
294
618
  //#endregion
295
619
  //#region src/components/component-styles.ts
296
620
  const sharedConfiguration = globalThis;
@@ -379,6 +703,7 @@ function cookbook(options = {}) {
379
703
  usingContentCollection = hasContentConfig(context.config.srcDir);
380
704
  const starlightIntegration = starlight({
381
705
  title: options.config?.site?.title ?? "Documentation",
706
+ expressiveCode: false,
382
707
  ...options.config?.site?.description ? { description: options.config.site.description } : {},
383
708
  ...options.config?.search?.enabled === false ? { pagefind: false } : {},
384
709
  ...!usingContentCollection ? { disable404Route: true } : {},
@@ -392,13 +717,24 @@ function cookbook(options = {}) {
392
717
  ];
393
718
  let markdownRuntime = {
394
719
  image: context.config.image,
395
- markdown: context.config.markdown,
720
+ markdown: {
721
+ ...context.config.markdown,
722
+ syntaxHighlight: "shiki",
723
+ shikiConfig: {
724
+ ...context.config.markdown.shikiConfig,
725
+ theme: tastyCodeTheme
726
+ }
727
+ },
396
728
  srcDir: context.config.srcDir
397
729
  };
398
730
  let markdownRenderer;
399
731
  context.updateConfig({
400
732
  base,
401
733
  output: "static",
734
+ markdown: {
735
+ syntaxHighlight: "shiki",
736
+ shikiConfig: { theme: tastyCodeTheme }
737
+ },
402
738
  vite: {
403
739
  ssr: { external: [
404
740
  "@tenphi/docs",
@@ -406,7 +742,7 @@ function cookbook(options = {}) {
406
742
  "react-dom",
407
743
  "react-dom/server"
408
744
  ] },
409
- plugins: [virtualDocsPlugin(async () => {
745
+ plugins: [stripStarlightStylesPlugin(starlightRoot), virtualDocsPlugin(async () => {
410
746
  const loaded = await loadGraph();
411
747
  return {
412
748
  entries: usingContentCollection ? loaded.entries : await Promise.all(loaded.entries.map(async (entry) => {
@@ -489,7 +825,14 @@ function cookbook(options = {}) {
489
825
  hooks: { "astro:config:setup": ({ config }) => {
490
826
  markdownRuntime = {
491
827
  image: config.image,
492
- markdown: config.markdown,
828
+ markdown: {
829
+ ...config.markdown,
830
+ syntaxHighlight: "shiki",
831
+ shikiConfig: {
832
+ ...config.markdown.shikiConfig,
833
+ theme: tastyCodeTheme
834
+ }
835
+ },
493
836
  srcDir: config.srcDir
494
837
  };
495
838
  } }
@@ -542,8 +885,19 @@ function cookbook(options = {}) {
542
885
  },
543
886
  "astro:build:done": async (context) => {
544
887
  await callInner(inner, "astro:build:done", context);
545
- if (!graph) return;
546
888
  const output = fileURLToPath(context.dir);
889
+ for (const relativePath of await readdir(output, { recursive: true })) {
890
+ if (extname(relativePath) !== ".html") continue;
891
+ const path = join(output, relativePath);
892
+ const html = await readFile(path, "utf8");
893
+ const sanitized = html.replace(/\s*<link\b(?=[^>]*rel="stylesheet")(?=[^>]*href="data:text\/css,")[^>]*>/g, "").replace(/\s*<style>\s*<\/style>/g, "").replace(/\sstyle="--sl-icon-size:\s*([^;\"]+);?"/g, " width=\"$1\" height=\"$1\"").replace(/\sstyle="--depth:\s*([^;\"]+);?"/g, " data-depth=\"$1\"").replace(/(<kbd\b[^>]*)\sstyle="display:\s*none;?"([^>]*>)/g, "$1$2").replace(/(<dialog\b[^>]*)\sstyle="padding:\s*0;?"([^>]*>)/g, "$1$2");
894
+ if (sanitized !== html) await writeFile(path, sanitized);
895
+ }
896
+ const pagefindOutput = join(output, "pagefind");
897
+ if (existsSync(pagefindOutput)) {
898
+ for (const name of await readdir(pagefindOutput)) if (extname(name) === ".css") await unlink(join(pagefindOutput, name));
899
+ }
900
+ if (!graph) return;
547
901
  for (const asset of graph.assets) {
548
902
  if (!asset.sourcePath || !asset.publicPath) continue;
549
903
  const target = join(output, asset.publicPath.replace(/^\//, ""));
@@ -554,6 +908,32 @@ function cookbook(options = {}) {
554
908
  }
555
909
  };
556
910
  }
911
+ function stripStarlightStylesPlugin(root) {
912
+ const normalizedRoot = root.replaceAll("\\", "/");
913
+ const emptyPrintId = "\0cookbook:empty-starlight-print";
914
+ return {
915
+ name: "cookbook-strip-starlight-css",
916
+ enforce: "pre",
917
+ resolveId(source, importer) {
918
+ if (importer?.replaceAll("\\", "/").startsWith(`${normalizedRoot}/`) && source.endsWith("/style/print.css?url&no-inline")) return emptyPrintId;
919
+ },
920
+ load(id) {
921
+ if (id === emptyPrintId) return "export default \"data:text/css,\";";
922
+ },
923
+ transform(code, id) {
924
+ const normalizedId = id.replaceAll("\\", "/");
925
+ if (!normalizedId.startsWith(`${normalizedRoot}/`)) return void 0;
926
+ const [pathname, query = ""] = normalizedId.split("?", 2);
927
+ const isStylesheet = pathname?.endsWith(".css");
928
+ const isAstroStyle = pathname?.endsWith(".astro") && query.includes("type=style");
929
+ if (!isStylesheet && !isAstroStyle) return void 0;
930
+ return {
931
+ code: "",
932
+ map: null
933
+ };
934
+ }
935
+ };
936
+ }
557
937
  function starlightContentUrl(route, srcDir) {
558
938
  const slug = route === "/" ? "index" : route.replace(/^\/+|\/+$/g, "");
559
939
  return new URL(`content/docs/${slug}.md`, srcDir);