@tenphi/starlight 0.6.0 → 0.6.1

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.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/theme/defaults.ts","../src/theme/index.ts","../src/theme/tasty-config.ts","../src/components/component-styles.ts","../src/components/tasty-states.js","../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.65,\n letterSpacing: \"-0.006em\",\n fontWeight: 420,\n boldFontWeight: 640,\n },\n heading: {\n fontFamily: BODY_FONT,\n fontSize: \"1rem\",\n lineHeight: 1.15,\n letterSpacing: \"-0.025em\",\n fontWeight: 640,\n boldFontWeight: 720,\n },\n h1: heading(\"clamp(2.5rem, 5vw, 3.25rem)\", 1.05, \"-0.045em\"),\n h2: heading(\"clamp(1.75rem, 3vw, 2.125rem)\", 1.1, \"-0.035em\"),\n h3: heading(\"1.5rem\", 1.15, \"-0.025em\"),\n h4: heading(\"1.25rem\", 1.2, \"-0.018em\"),\n h5: heading(\"1.125rem\", 1.25, \"-0.012em\"),\n h6: heading(\"1rem\", 1.3, \"-0.006em\"),\n navigation: {\n fontFamily: \"var(--body-font-family)\",\n fontSize: \"0.9375rem\",\n lineHeight: 1.4,\n letterSpacing: \"-0.006em\",\n fontWeight: 540,\n boldFontWeight: 650,\n },\n small: {\n fontFamily: \"var(--body-font-family)\",\n fontSize: \"0.875rem\",\n lineHeight: 1.45,\n letterSpacing: \"-0.002em\",\n fontWeight: 420,\n boldFontWeight: 650,\n },\n code: {\n fontFamily: MONO_FONT,\n fontSize: \"0.875rem\",\n lineHeight: 1.65,\n letterSpacing: \"0\",\n fontWeight: 400,\n boldFontWeight: 650,\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 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 shadow: 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 as the ramp moves away from white. Reduce\n // saturation along the light ramp and keep dark chrome nearly neutral.\n darkSaturation: 0.35,\n });\n const surface2 = glaze.color(\n {\n from: surfaceFrom,\n base: surface,\n tone: \"-2\",\n mode: \"auto\",\n saturationFactor: 0.9,\n darkSaturation: 0.325,\n },\n glazeOptions,\n );\n const surface3 = glaze.color(\n {\n from: surfaceFrom,\n base: surface2,\n tone: \"-2\",\n mode: \"auto\",\n saturationFactor: 0.8,\n darkSaturation: 0.3,\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 const resolvedSurface = surface.resolve();\n const resolvedAccent = accentText.resolve();\n const shadowTheme = glaze(\n {\n hue: variantToOkhsl(resolvedSurface.light).h,\n saturation: variantToOkhsl(resolvedSurface.light).s * 100,\n darkHue: variantToOkhsl(resolvedSurface.dark).h,\n darkSaturation: variantToOkhsl(resolvedSurface.dark).s * 100,\n },\n undefined,\n glazeOptions,\n );\n shadowTheme.colors({\n surface: {\n from: surfaceFrom,\n mode: \"auto\",\n darkSaturation: 0.35,\n },\n text: {\n from: theme.palette?.text ?? \"#20232a\",\n base: \"surface\",\n role: \"text\",\n contrast: { apca: [75, 90] },\n mode: \"auto\",\n },\n shadow: {\n type: \"shadow\",\n bg: \"surface\",\n fg: \"text\",\n intensity: [12, 20],\n tuning: { alphaMax: 0.28 },\n },\n });\n\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 shadow = shadowTheme.json(outputOptions).shadow;\n if (!shadow) throw new Error(\"The Glaze shadow token failed to resolve.\");\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 shadow,\n };\n return {\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","import type { ConfigTokens } from \"@tenphi/tasty/core\";\nimport type { ResolvedDocsTheme } from \"./index.js\";\n\nexport const TASTY_UNITS = {\n x: \"var(--gap)\",\n r: \"var(--radius)\",\n cr: \"var(--card-radius)\",\n bw: \"var(--border-width)\",\n} as const;\n\n// Token states are emitted on :root already. Keep these as ordinary state\n// selectors so Tasty attaches them to that root instead of generating an\n// impossible descendant `:root ... :root` selector.\nconst LIGHT =\n \"theme=light | (@media(prefers-color-scheme: light) & :not([data-theme]))\";\nconst HIGH_CONTRAST =\n \"contrast=more | (@media(prefers-contrast: more) & :not([data-contrast]))\";\n\nexport function tastyTokens(theme: ResolvedDocsTheme): ConfigTokens {\n const tokens = Object.fromEntries(\n Object.entries(theme.tokens).filter(([name]) => name.startsWith(\"$\")),\n ) as ConfigTokens;\n\n Object.assign(tokens, {\n \"#surface\": colorStates(theme.colors.surface),\n \"#surface-2\": colorStates(theme.colors.surface2),\n \"#surface-3\": colorStates(theme.colors.surface3),\n \"#surface-2-hover\": mix(\"#text\", 3, \"#surface-2\"),\n \"#surface-2-pressed\": mix(\"#text\", 9, \"#surface-2\"),\n \"#surface-3-hover\": mix(\"#text\", 3, \"#surface-3\"),\n \"#surface-3-pressed\": mix(\"#text\", 9, \"#surface-3\"),\n \"#text\": colorStates(theme.colors.text),\n \"#text-soft\": colorStates(theme.colors.textSoft),\n \"#border\": mix(\"#text\", 18, \"#surface\"),\n \"#border-strong\": mix(\"#text\", 34, \"#surface\"),\n \"#accent-text\": colorStates(theme.colors.accentText),\n \"#accent-surface\": colorStates(theme.colors.accentSurface),\n \"#accent-surface-text\": colorStates(theme.colors.accentSurfaceText),\n \"#focus\": colorStates(theme.colors.focus),\n \"#shadow\": colorStates(theme.colors.shadow),\n \"#overlay\": mix(\"#text\", 58, \"transparent\"),\n } satisfies ConfigTokens);\n\n return tokens;\n}\n\nfunction colorStates(colors: Record<string, string>) {\n return {\n \"\": colors.dark,\n [LIGHT]: colors.light,\n [HIGH_CONTRAST]: colors.darkContrast,\n [`(${LIGHT}) & (${HIGH_CONTRAST})`]: colors.lightContrast,\n };\n}\n\nfunction mix(foreground: string, percentage: number, background: string) {\n return `color-mix(in oklab, ${foreground} ${percentage}%, ${background})`;\n}\n","import { mergeStyles, type Styles } from \"@tenphi/tasty/core\";\nimport {\n COOKBOOK_COMPONENT_NAMES,\n type ComponentStyleConfig,\n type ComponentStylesConfig,\n type CookbookComponentName,\n} from \"@tenphi/docs\";\n\n// Astro can load the integration and renderer through separate module graphs.\n// Keep their component configuration on the shared process global.\nconst sharedConfiguration = globalThis as typeof globalThis & {\n __tenphiCookbookComponentStyles?: ComponentStylesConfig;\n};\nconst cookbookComponentNames = new Set<string>(COOKBOOK_COMPONENT_NAMES);\n\nexport function configureComponentStyles(\n styles: ComponentStylesConfig | undefined,\n): void {\n sharedConfiguration.__tenphiCookbookComponentStyles = styles ?? {};\n}\n\nexport function resolveComponentStyles(\n name: CookbookComponentName,\n defaults: Styles,\n): Styles {\n const configured = sharedConfiguration.__tenphiCookbookComponentStyles?.[\n name\n ] as ComponentStyleConfig | undefined;\n if (!configured) return defaults;\n if (isModeConfig(configured)) {\n const styles = configured.styles as Styles;\n return configured.mode === \"replace\"\n ? styles\n : mergeStyles(defaults, styles);\n }\n return mergeStyles(defaults, configured as Styles);\n}\n\nexport function resolveComponentStyleOverride(\n name: CookbookComponentName,\n): { mode: \"extend\" | \"replace\"; styles: Styles } | undefined {\n const configured = sharedConfiguration.__tenphiCookbookComponentStyles?.[\n name\n ] as ComponentStyleConfig | undefined;\n if (!configured) return undefined;\n if (isModeConfig(configured)) {\n return { mode: configured.mode, styles: configured.styles as Styles };\n }\n return { mode: \"extend\", styles: configured as Styles };\n}\n\n/** Preserve custom anatomy names from the pre-component style API. */\nexport function resolveLegacyAnatomyStyles(\n styles: ComponentStylesConfig | undefined,\n): Record<string, Styles> | undefined {\n if (!styles) return undefined;\n const entries = Object.entries(styles)\n .filter(\n (entry): entry is [string, ComponentStyleConfig] =>\n !cookbookComponentNames.has(entry[0]) && entry[1] !== undefined,\n )\n .map(([name, value]) => [\n `[data-tasty-anatomy=\"${name}\"]`,\n isModeConfig(value) ? value.styles : value,\n ]);\n return entries.length\n ? (Object.fromEntries(entries) as Record<string, Styles>)\n : undefined;\n}\n\nfunction isModeConfig(\n value: ComponentStyleConfig,\n): value is Extract<ComponentStyleConfig, { mode: string }> {\n return (\n \"mode\" in value &&\n (value.mode === \"extend\" || value.mode === \"replace\") &&\n \"styles\" in value\n );\n}\n","import { configure } from \"@tenphi/tasty\";\n\nexport const cookbookStates = {\n \"@mobile\": \"@media(w < 50rem)\",\n \"@desktop\": \"@media(w >= 50rem)\",\n \"@small\": \"@media(w <= 40rem)\",\n \"@shell-mobile\": \"@media(w <= 48rem)\",\n \"@shell-desktop\": \"@media(w > 48rem)\",\n \"@narrow-layout\": \"@media(w < 72rem)\",\n \"@medium-layout\": \"@media(w >= 50rem) & @media(w < 72rem)\",\n \"@reduced-motion\": \"@media(prefers-reduced-motion: reduce)\",\n};\n\nlet configured = false;\n\n/** Configure aliases in the renderer's Tasty module before styles are parsed. */\nexport function configureCookbookStates() {\n if (configured) return;\n configure({ states: cookbookStates });\n configured = true;\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, pathToFileURL } 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\";\nimport { TASTY_UNITS, tastyTokens } from \"./theme/tasty-config.js\";\nimport {\n configureComponentStyles,\n resolveLegacyAnatomyStyles,\n} from \"./components/component-styles.js\";\nimport { cookbookStates } from \"./components/tasty-states.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);\nconst tastyExtractStaticMiddleware = packageRequire.resolve(\n \"@tenphi/tasty/ssr/astro-middleware-extract-static\",\n);\nconst astroReactServer = packageRequire.resolve(\"@astrojs/react/server.js\");\nconst astroReactClient = packageRequire.resolve(\"@astrojs/react/client.js\");\nconst astroReactIntegration = packageRequire.resolve(\"@astrojs/react\");\nconst importNative = new Function(\"specifier\", \"return import(specifier)\") as (\n specifier: string,\n) => Promise<{ default: () => AstroIntegration }>;\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 configureComponentStyles(options.config?.theme?.styles);\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 mobileMenuFooterPath = fileURLToPath(\n new URL(\"./overrides/MobileMenuFooter.astro\", import.meta.url),\n );\n const themeSelectPath = fileURLToPath(\n new URL(\"./overrides/ThemeSelect.astro\", import.meta.url),\n );\n const components = {\n Header: headerPath,\n Sidebar: sidebarPath,\n MobileMenuFooter: mobileMenuFooterPath,\n ThemeSelect: themeSelectPath,\n ...options.config?.components?.overrides,\n };\n const navigation = resolveNavigationLayout(options.config?.navigation);\n // Tasty 3.6's integration shape is structurally compatible with Astro 7;\n // its published helper type still models `site` as URL-only.\n const tasty = tastyIntegration({\n islands: false,\n css: { mode: \"extract\" },\n }) as unknown as AstroIntegration;\n const starlightIntegration = starlight({\n title: options.config?.site?.title ?? \"Documentation\",\n ...(options.config?.site?.description\n ? { description: options.config.site.description }\n : {}),\n ...(options.config?.search?.enabled === false ? { pagefind: false } : {}),\n components,\n sidebar: starlightSidebar(navigation),\n });\n let inner: AstroIntegration[] = [tasty, starlightIntegration];\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 const react = (\n await importNative(pathToFileURL(astroReactIntegration).href)\n ).default();\n inner = [react, tasty, starlightIntegration];\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: [\n \"@tenphi/docs\",\n \"react\",\n \"react-dom\",\n \"react-dom/server\",\n ],\n },\n plugins: [\n virtualDocsPlugin(async () => {\n const loaded = await loadGraph();\n return {\n entries: loaded.entries,\n routes: loaded.routes,\n site: documentedSite(loaded),\n base: loaded.config.build.base,\n search: loaded.config.search.enabled,\n };\n }, navigation),\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 find: \"@tenphi/tasty/ssr/astro-middleware-extract-static\",\n replacement: tastyExtractStaticMiddleware,\n },\n {\n find: \"@astrojs/react/server.js\",\n replacement: astroReactServer,\n },\n {\n find: \"@astrojs/react/client.js\",\n replacement: astroReactClient,\n },\n ],\n },\n },\n });\n await callInner(inner.slice(0, 2), \"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 starlightWithPlugins = inner[2];\n if (starlightWithPlugins) {\n const selfIndex = context.config.integrations.findIndex(\n (integration) => integration.name === \"cookbook\",\n );\n context.config.integrations.splice(\n selfIndex + 1,\n 0,\n starlightWithPlugins,\n );\n try {\n await callInner(\n [starlightWithPlugins],\n \"astro:config:setup\",\n context,\n );\n } finally {\n const placeholderIndex =\n context.config.integrations.indexOf(starlightWithPlugins);\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, 2),\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, 2),\n \"astro:build:start\",\n context,\n );\n },\n \"astro:build:done\": async (context) => {\n await callInner(\n usingStarlight ? inner : inner.slice(0, 2),\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 documentedSite(\n graph: Awaited<ReturnType<typeof createDocsGraph>>,\n): Awaited<ReturnType<typeof createDocsGraph>>[\"config\"][\"site\"] {\n if (graph.config.site.version) return graph.config.site;\n const packages = new Set(\n graph.entries.flatMap((entry) =>\n entry.package?.resolved ? [entry.package.resolved] : [],\n ),\n );\n if (packages.size !== 1) return graph.config.site;\n const resolved = packages.values().next().value;\n if (!resolved) return graph.config.site;\n const separator = resolved.lastIndexOf(\"@\");\n if (separator <= 0 || separator === resolved.length - 1)\n return graph.config.site;\n return { ...graph.config.site, version: resolved.slice(separator + 1) };\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 = tastyTokens(resolved) as ConfigTokens;\n const globalStyles = resolveLegacyAnatomyStyles(theme?.styles);\n\n configure({\n states: {\n ...cookbookStates,\n ...theme?.states,\n },\n units: TASTY_UNITS,\n tokens,\n presets: resolved.presets as Record<string, TypographyPreset>,\n ...(globalStyles\n ? { globalStyles: globalStyles as Record<string, Styles> }\n : {}),\n });\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 getContent: () => unknown | Promise<unknown>,\n layout: ResolvedNavigationLayout,\n) {\n const configId = \"\\0virtual:cookbook/config\";\n const layoutId = \"\\0virtual:cookbook/layout\";\n return {\n name: \"cookbook-data\",\n resolveId(id: string) {\n if (id === \"virtual:cookbook/config\") return configId;\n if (id === \"virtual:cookbook/layout\") return layoutId;\n return undefined;\n },\n async load(id: string) {\n if (id === configId) {\n return `export const content = ${JSON.stringify(await 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":";;;;;;;;;;;;;AAMA,MAAa,uBAAuB;CAClC,MAAM;CACN,SAAS;CACT,gBAAgB;CAChB,iBAAiB;CACjB,kBAAkB;CAClB,mBAAmB;CACnB,iBAAiB;CACjB,kBAAkB;CAClB,kBAAkB;CAClB,mBAAmB;AACrB;AAEA,MAAM,YACJ;AAIF,MAAa,6BAA+D;CAC1E,MAAM;EACJ,YAAY;EACZ,UAAU;EACV,YAAY;EACZ,eAAe;EACf,YAAY;EACZ,gBAAgB;CAClB;CACA,SAAS;EACP,YAAY;EACZ,UAAU;EACV,YAAY;EACZ,eAAe;EACf,YAAY;EACZ,gBAAgB;CAClB;CACA,IAAI,QAAQ,+BAA+B,MAAM,UAAU;CAC3D,IAAI,QAAQ,iCAAiC,KAAK,UAAU;CAC5D,IAAI,QAAQ,UAAU,MAAM,UAAU;CACtC,IAAI,QAAQ,WAAW,KAAK,UAAU;CACtC,IAAI,QAAQ,YAAY,MAAM,UAAU;CACxC,IAAI,QAAQ,QAAQ,KAAK,UAAU;CACnC,YAAY;EACV,YAAY;EACZ,UAAU;EACV,YAAY;EACZ,eAAe;EACf,YAAY;EACZ,gBAAgB;CAClB;CACA,OAAO;EACL,YAAY;EACZ,UAAU;EACV,YAAY;EACZ,eAAe;EACf,YAAY;EACZ,gBAAgB;CAClB;CACA,MAAM;EACJ,YAAY;EACZ,UAAU;EACV,YAAY;EACZ,eAAe;EACf,YAAY;EACZ,gBAAgB;CAClB;AACF;AAEA,SAAgB,mBAAmB,SAAsB,CAAC,GAAgB;CACxE,OAAO;EAAE,GAAG;EAAsB,GAAG;CAAO;AAC9C;AAEA,SAAgB,yBACd,UAA6B,CAAC,GACI;CAClC,MAAM,OAAO,2BAA2B;CACxC,IAAI,CAAC,MAAM,MAAM,IAAI,MAAM,yCAAyC;CACpE,MAAM,wBAAQ,IAAI,IAAI,CACpB,GAAG,OAAO,KAAK,0BAA0B,GACzC,GAAG,OAAO,KAAK,OAAO,CACxB,CAAC;CACD,OAAO,OAAO,YACZ,CAAC,GAAG,KAAK,CAAC,CAAC,KAAK,SAAS,CACvB,MACA;EACE,GAAI,2BAA2B,SAAS;EACxC,GAAI,QAAQ,SAAS,CAAC;CACxB,CACF,CAAC,CACH;AACF;AAEA,SAAS,QACP,UACA,YACA,eACkB;CAClB,OAAO;EACL,YAAY;EACZ;EACA;EACA;EACA,YAAY;EACZ,gBAAgB;CAClB;AACF;;;ACpEA,SAAgB,iBAAiB,QAAqB,CAAC,GAAsB;CAC3E,MAAM,QAAQ,eAAe,MAAM,KAAK;CACxC,MAAM,iBAAiB,MAAM,UAAU,QAAQ;CAC/C,MAAM,eAAe,MAAM,QAAQ,cAAc,IAC7C,eAAe,KACf;CACJ,MAAM,aAAa,MAAM,QAAQ,cAAc,IAC3C,eAAe,KACf,eAAe;CACnB,MAAM,eAAe;EACnB,UAAU;EACV,GAAI,MAAM,kBAAkB,KAAA,IACxB,EAAE,eAAe,MAAM,cAAc,IACrC,CAAC;CACP;CACA,MAAM,cAAc,MAAM,SAAS,WAAW;CAC9C,MAAM,UAAU,MAAM,MAAM;EAC1B,MAAM;EACN,MAAM;EAIN,gBAAgB;CAClB,CAAC;CACD,MAAM,WAAW,MAAM,MACrB;EACE,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,kBAAkB;EAClB,gBAAgB;CAClB,GACA,YACF;CACA,MAAM,WAAW,MAAM,MACrB;EACE,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,kBAAkB;EAClB,gBAAgB;CAClB,GACA,YACF;CACA,MAAM,OAAO,MAAM,MACjB;EACE,MAAM,MAAM,SAAS,QAAQ;EAC7B,MAAM;EACN,MAAM;EACN,UAAU,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE;EAC3B,MAAM;CACR,GACA,YACF;CACA,MAAM,WAAW,MAAM,MACrB;EACE,MAAM,MAAM,SAAS,YAAY;EACjC,MAAM;EACN,MAAM;EACN,UAAU,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE;EAC3B,MAAM;CACR,GACA,YACF;CACA,MAAM,aAAa,MAAM,MACvB;EACE,MAAM,MAAM;EACZ,MAAM;EACN,MAAM;EACN,UAAU,EAAE,MAAM,eAAe;EACjC,MAAM;CACR,GACA,YACF;CACA,MAAM,QAAQ,MAAM,MAClB;EACE,MAAM,MAAM;EACZ,MAAM;EACN,MAAM;EACN,UAAU,EAAE,MAAM,eAAe;EACjC,MAAM;CACR,GACA,YACF;CACA,MAAM,gBAAgB,MAAM,MAAM;EAAE,MAAM,MAAM;EAAM,MAAM;CAAQ,CAAC;CACrE,MAAM,oBAAoB,MAAM,MAAM;EACpC,MAAM;EACN,MAAM;EACN,MAAM;EACN,UAAU,EAAE,MAAM,GAAG;EACrB,MAAM;CACR,CAAC;CACD,MAAM,kBAAkB,QAAQ,QAAQ;CACxC,MAAM,iBAAiB,WAAW,QAAQ;CAC1C,MAAM,cAAc,MAClB;EACE,KAAK,eAAe,gBAAgB,KAAK,CAAC,CAAC;EAC3C,YAAY,eAAe,gBAAgB,KAAK,CAAC,CAAC,IAAI;EACtD,SAAS,eAAe,gBAAgB,IAAI,CAAC,CAAC;EAC9C,gBAAgB,eAAe,gBAAgB,IAAI,CAAC,CAAC,IAAI;CAC3D,GACA,KAAA,GACA,YACF;CACA,YAAY,OAAO;EACjB,SAAS;GACP,MAAM;GACN,MAAM;GACN,gBAAgB;EAClB;EACA,MAAM;GACJ,MAAM,MAAM,SAAS,QAAQ;GAC7B,MAAM;GACN,MAAM;GACN,UAAU,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE;GAC3B,MAAM;EACR;EACA,QAAQ;GACN,MAAM;GACN,IAAI;GACJ,IAAI;GACJ,WAAW,CAAC,IAAI,EAAE;GAClB,QAAQ,EAAE,UAAU,IAAK;EAC3B;CACF,CAAC;CAED,MAAM,SAAS;EACb,OAAO,MAAM,eAAe,OAAO,gBAAgB,KAAK;EACxD,MAAM,MAAM,eAAe,MAAM,gBAAgB,IAAI;EACrD,eAAe,MACb,eAAe,eACf,gBAAgB,aAClB;EACA,cAAc,MACZ,eAAe,cACf,gBAAgB,YAClB;CACF;CACA,MAAM,cAAgC,CAAC;CACvC,KAAK,MAAM,CAAC,QAAQ,aAAa,OAAO,QAAQ,MAAM,GAAG;EACvD,MAAM,WAAW,OAAO,SAAS,UAAU,IAAI,aAAa;EAC5D,IAAI,WAAW,MAAO,UACpB,YAAY,KAAK;GACf,MAAM;GACN,UAAU;GACV,SAAS,qBAAqB,OAAO,SAAS,SAAS,QAAQ,CAAC,EAAE,gBAAgB,SAAS;GAC3F,MAAM,mBAAmB,OAAO,MAAM,IAAI,EAAE;EAC9C,CAAC;CAEL;CACA,MAAM,gBAAgB,EAAE,OAAO,EAAE,cAAc,KAAK,EAAE;CACtD,MAAM,SAAS,YAAY,KAAK,aAAa,CAAC,CAAC;CAC/C,IAAI,CAAC,QAAQ,MAAM,IAAI,MAAM,2CAA2C;CAaxE,OAAO;EACL,QAAA;GAZA,SAAS,QAAQ,KAAK,aAAa;GACnC,UAAU,SAAS,KAAK,aAAa;GACrC,UAAU,SAAS,KAAK,aAAa;GACrC,MAAM,KAAK,KAAK,aAAa;GAC7B,UAAU,SAAS,KAAK,aAAa;GACrC,YAAY,WAAW,KAAK,aAAa;GACzC,eAAe,cAAc,KAAK,aAAa;GAC/C,mBAAmB,kBAAkB,KAAK,aAAa;GACvD,OAAO,MAAM,KAAK,aAAa;GAC/B;EAGK;EACL,QAAQ,mBAAmB,MAAM,MAAM;EACvC,SAAS,yBAAyB,MAAM,OAAO;EAC/C,UAAU;EACV;CACF;AACF;AAEA,SAAS,eACP,OACmE;CACnE,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,UAAU,OAC3D,OAAO;CACT,OAAO,EAAE,MAAM,SAAS,UAAU;AACpC;AAEA,SAAS,MACP,YACA,YACQ;CACR,OAAO,KAAK,IAAI,aAAa,UAAU,UAAU,GAAG,UAAU,UAAU,CAAC,CAAC;AAC5E;AAEA,SAAS,UAAU,SAAuC;CACxD,MAAM,EAAE,GAAG,GAAG,MAAM,eAAe,OAAO;CAC1C,OAAO,+BACL,kBAAkB,GAAG,GAAG,GAAG,QAAQ,MAAM,CAC3C;AACF;;;AC3OA,MAAa,cAAc;CACzB,GAAG;CACH,GAAG;CACH,IAAI;CACJ,IAAI;AACN;AAKA,MAAM,QACJ;AACF,MAAM,gBACJ;AAEF,SAAgB,YAAY,OAAwC;CAClE,MAAM,SAAS,OAAO,YACpB,OAAO,QAAQ,MAAM,MAAM,CAAC,CAAC,QAAQ,CAAC,UAAU,KAAK,WAAW,GAAG,CAAC,CACtE;CAEA,OAAO,OAAO,QAAQ;EACpB,YAAY,YAAY,MAAM,OAAO,OAAO;EAC5C,cAAc,YAAY,MAAM,OAAO,QAAQ;EAC/C,cAAc,YAAY,MAAM,OAAO,QAAQ;EAC/C,oBAAoB,IAAI,SAAS,GAAG,YAAY;EAChD,sBAAsB,IAAI,SAAS,GAAG,YAAY;EAClD,oBAAoB,IAAI,SAAS,GAAG,YAAY;EAChD,sBAAsB,IAAI,SAAS,GAAG,YAAY;EAClD,SAAS,YAAY,MAAM,OAAO,IAAI;EACtC,cAAc,YAAY,MAAM,OAAO,QAAQ;EAC/C,WAAW,IAAI,SAAS,IAAI,UAAU;EACtC,kBAAkB,IAAI,SAAS,IAAI,UAAU;EAC7C,gBAAgB,YAAY,MAAM,OAAO,UAAU;EACnD,mBAAmB,YAAY,MAAM,OAAO,aAAa;EACzD,wBAAwB,YAAY,MAAM,OAAO,iBAAiB;EAClE,UAAU,YAAY,MAAM,OAAO,KAAK;EACxC,WAAW,YAAY,MAAM,OAAO,MAAM;EAC1C,YAAY,IAAI,SAAS,IAAI,aAAa;CAC5C,CAAwB;CAExB,OAAO;AACT;AAEA,SAAS,YAAY,QAAgC;CACnD,OAAO;EACL,IAAI,OAAO;GACV,QAAQ,OAAO;GACf,gBAAgB,OAAO;GACvB,IAAI,MAAM,OAAO,cAAc,KAAK,OAAO;CAC9C;AACF;AAEA,SAAS,IAAI,YAAoB,YAAoB,YAAoB;CACvE,OAAO,uBAAuB,WAAW,GAAG,WAAW,KAAK,WAAW;AACzE;;;AC/CA,MAAM,sBAAsB;AAG5B,MAAM,yBAAyB,IAAI,IAAY,wBAAwB;AAEvE,SAAgB,yBACd,QACM;CACN,oBAAoB,kCAAkC,UAAU,CAAC;AACnE;;AAiCA,SAAgB,2BACd,QACoC;CACpC,IAAI,CAAC,QAAQ,OAAO,KAAA;CACpB,MAAM,UAAU,OAAO,QAAQ,MAAM,CAAC,CACnC,QACE,UACC,CAAC,uBAAuB,IAAI,MAAM,EAAE,KAAK,MAAM,OAAO,KAAA,CAC1D,CAAC,CACA,KAAK,CAAC,MAAM,WAAW,CACtB,wBAAwB,KAAK,KAC7B,aAAa,KAAK,IAAI,MAAM,SAAS,KACvC,CAAC;CACH,OAAO,QAAQ,SACV,OAAO,YAAY,OAAO,IAC3B,KAAA;AACN;AAEA,SAAS,aACP,OAC0D;CAC1D,OACE,UAAU,UACT,MAAM,SAAS,YAAY,MAAM,SAAS,cAC3C,YAAY;AAEhB;;;AC5EA,MAAa,iBAAiB;CAC5B,WAAW;CACX,YAAY;CACZ,UAAU;CACV,iBAAiB;CACjB,kBAAkB;CAClB,kBAAkB;CAClB,kBAAkB;CAClB,mBAAmB;AACrB;;;ACqBA,MAAM,iBAAiB,cAAc,YAAY,GAAG;AACpD,MAAM,gBAAgB,QAAQ,eAAe,QAAQ,oBAAoB,CAAC;AAC1E,MAAM,wBAAwB,eAAe,QAC3C,2CACF;AACA,MAAM,+BAA+B,eAAe,QAClD,mDACF;AACA,MAAM,mBAAmB,eAAe,QAAQ,0BAA0B;AAC1E,MAAM,mBAAmB,eAAe,QAAQ,0BAA0B;AAC1E,MAAM,wBAAwB,eAAe,QAAQ,gBAAgB;AACrE,MAAM,eAAe,IAAI,SAAS,aAAa,0BAA0B;AASzE,SAAwB,SACtB,UAA2B,CAAC,GACV;CAClB,MAAM,YAAY,iBAAiB,QAAQ,QAAQ,KAAK;CACxD,IACE,UAAU,YAAY,MAAM,eAAe,WAAW,aAAa,OAAO,GAE1E,MAAM,IAAI,MACR,UAAU,YAAY,KAAK,eAAe,WAAW,OAAO,CAAC,CAAC,KAAK,IAAI,CACzE;CAEF,oBAAoB,QAAQ,QAAQ,OAAO,SAAS;CACpD,yBAAyB,QAAQ,QAAQ,OAAO,MAAM;CACtD,MAAM,mBAAmB,cACvB,IAAI,IAAI,sBAAsB,YAAY,GAAG,CAC/C;CACA,MAAM,uBAAuB,cAC3B,IAAI,IAAI,0BAA0B,YAAY,GAAG,CACnD;CAaA,MAAM,aAAa;EACjB,QAbiB,cACjB,IAAI,IAAI,4BAA4B,YAAY,GAAG,CAYlC;EACjB,SAXkB,cAClB,IAAI,IAAI,6BAA6B,YAAY,GAAG,CAUjC;EACnB,kBAT2B,cAC3B,IAAI,IAAI,sCAAsC,YAAY,GAAG,CAQxB;EACrC,aAPsB,cACtB,IAAI,IAAI,iCAAiC,YAAY,GAAG,CAM7B;EAC3B,GAAG,QAAQ,QAAQ,YAAY;CACjC;CACA,MAAM,aAAa,wBAAwB,QAAQ,QAAQ,UAAU;CAGrE,MAAM,QAAQ,iBAAiB;EAC7B,SAAS;EACT,KAAK,EAAE,MAAM,UAAU;CACzB,CAAC;CACD,MAAM,uBAAuB,UAAU;EACrC,OAAO,QAAQ,QAAQ,MAAM,SAAS;EACtC,GAAI,QAAQ,QAAQ,MAAM,cACtB,EAAE,aAAa,QAAQ,OAAO,KAAK,YAAY,IAC/C,CAAC;EACL,GAAI,QAAQ,QAAQ,QAAQ,YAAY,QAAQ,EAAE,UAAU,MAAM,IAAI,CAAC;EACvE;EACA,SAAS,iBAAiB,UAAU;CACtC,CAAC;CACD,IAAI,QAA4B,CAAC,OAAO,oBAAoB;CAC5D,IAAI,cAAc,QAAQ;CAC1B,IAAI,cAAc,QAAQ;CAC1B,IAAI;CACJ,IAAI,iBAAiB;CAErB,eAAe,UAAU,UAAU,OAAO;EACxC,IAAI,CAAC,SAAS,SAAS;GACrB,QAAQ,MAAM,gBAAgB;IAC5B,GAAI,cAAc,EAAE,MAAM,YAAY,IAAI,CAAC;IAC3C,GAAI,cAAc,EAAE,QAAQ,YAAY,IAAI,CAAC;GAC/C,CAAC;GACD,gBAAgB,KAAK;EACvB;EACA,OAAO;CACT;CAEA,OAAO;EACL,MAAM;EACN,OAAO;GACL,sBAAsB,OAAO,YAAY;IAIvC,QAAQ;MAFN,MAAM,aAAa,cAAc,qBAAqB,CAAC,CAAC,IAAI,EAAA,CAC5D,QACW;KAAG;KAAO;IAAoB;IAC3C,IACE,QAAQ,OAAO,aAAa,MACzB,gBAAgB,YAAY,SAAS,oBACxC,GAEA,MAAM,IAAI,MACR,0GACF;IAEF,gBAAgB,cAAc,QAAQ,OAAO,IAAI;IACjD,MAAM,OAAO,QAAQ,QAAQ,OAAO,QAAQ,QAAQ,OAAO;IAC3D,cAAc;KACZ,GAAG,QAAQ;KACX,OAAO;MAAE,GAAG,QAAQ,QAAQ;MAAO;KAAK;IAC1C;IACA,iBAAiB,iBAAiB,QAAQ,OAAO,MAAM;IACvD,QAAQ,aAAa;KACnB;KACA,QAAQ;KACR,MAAM;MACJ,KAAK,EACH,UAAU;OACR;OACA;OACA;OACA;MACF,EACF;MACA,SAAS,CACP,kBAAkB,YAAY;OAC5B,MAAM,SAAS,MAAM,UAAU;OAC/B,OAAO;QACL,SAAS,OAAO;QAChB,QAAQ,OAAO;QACf,MAAM,eAAe,MAAM;QAC3B,MAAM,OAAO,OAAO,MAAM;QAC1B,QAAQ,OAAO,OAAO,OAAO;OAC/B;MACF,GAAG,UAAU,CACf;MACA,SAAS,EACP,OAAO;OACL;QACE,MAAM;QACN,aAAa;OACf;OACA;QACE,MAAM;QACN,aAAa;OACf;OACA;QACE,MAAM;QACN,aAAa;OACf;OACA;QACE,MAAM;QACN,aAAa;OACf;OACA;QACE,MAAM;QACN,aAAa;OACf;MACF,EACF;KACF;IACF,CAAC;IACD,MAAM,UAAU,MAAM,MAAM,GAAG,CAAC,GAAG,sBAAsB,OAAO;IAEhE,IAAI,CAAC,gBAAgB;KACnB,QAAQ,MAAM,gBAAgB;MAC5B,MAAM;MACN,QAAQ;KACV,CAAC;KACD,gBAAgB,KAAK;KACrB,IAAI,MAAM,OAAO,OAAO,SACtB,QAAQ,aACN,QACA,UAAU,KAAK,UAAU,gBAAgB,EAAE,EAC7C;KAEF,QAAQ,aACN,QACA,UAAU,KAAK,UAAU,oBAAoB,EAAE,EACjD;KACA,QAAQ,YAAY;MAClB,SAAS;MACT,YAAY,IAAI,IAAI,2BAA2B,YAAY,GAAG;MAC9D,WAAW;KACb,CAAC;KACD;IACF;IAKA,MAAM,uBAAuB,MAAM;IACnC,IAAI,sBAAsB;KACxB,MAAM,YAAY,QAAQ,OAAO,aAAa,WAC3C,gBAAgB,YAAY,SAAS,UACxC;KACA,QAAQ,OAAO,aAAa,OAC1B,YAAY,GACZ,GACA,oBACF;KACA,IAAI;MACF,MAAM,UACJ,CAAC,oBAAoB,GACrB,sBACA,OACF;KACF,UAAU;MACR,MAAM,mBACJ,QAAQ,OAAO,aAAa,QAAQ,oBAAoB;MAC1D,IAAI,oBAAoB,GACtB,QAAQ,OAAO,aAAa,OAAO,kBAAkB,CAAC;KAC1D;IACF;GACF;GACA,qBAAqB,OAAO,YAAY;IACtC,MAAM,UACJ,iBAAiB,QAAQ,MAAM,MAAM,GAAG,CAAC,GACzC,qBACA,OACF;GACF;GACA,sBAAsB,OAAO,EAAE,aAAa;IAC1C,IAAI,SAAS,aAAa,MAAM,UAAU,CAAC;IAC3C,OAAO,YAAY,IAAI,OAAO,SAAS,UAAU,SAAS;KACxD,IAAI,QAAQ,WAAW,SAAS,QAAQ,WAAW,QAAQ;MACzD,KAAK;MACL;KACF;KACA,MAAM,WAAW,YAAY,QAAQ,GAAG;KACxC,IAAI,CAAC,SAAS,SAAS,iBAAiB,GAAG;MACzC,KAAK;MACL;KACF;KACA,IAAI,QAAQ,OAAO,IAAI,QAAQ;KAC/B,IAAI,CAAC,OAAO;MACV,IAAI;OACF,SAAS,aAAa,MAAM,UAAU,IAAI,CAAC;MAC7C,QAAQ;OACN,KAAK;OACL;MACF;MACA,QAAQ,OAAO,IAAI,QAAQ;KAC7B;KACA,IAAI,CAAC,OAAO,YAAY;MACtB,KAAK;MACL;KACF;KACA,IAAI;MACF,MAAM,OAAO,MAAM,SAAS,MAAM,UAAU;MAC5C,SAAS,aAAa;MACtB,SAAS,UAAU,gBAAgB,iBAAiB,QAAQ,CAAC;MAC7D,SAAS,UAAU,kBAAkB,KAAK,UAAU;MACpD,SAAS,UAAU,iBAAiB,UAAU;MAC9C,SAAS,IAAI,QAAQ,WAAW,SAAS,KAAA,IAAY,IAAI;KAC3D,QAAQ;MACN,KAAK;KACP;IACF,CAAC;GACH;GACA,qBAAqB,OAAO,YAAY;IACtC,MAAM,UAAU;IAChB,MAAM,UACJ,iBAAiB,QAAQ,MAAM,MAAM,GAAG,CAAC,GACzC,qBACA,OACF;GACF;GACA,oBAAoB,OAAO,YAAY;IACrC,MAAM,UACJ,iBAAiB,QAAQ,MAAM,MAAM,GAAG,CAAC,GACzC,oBACA,OACF;IACA,IAAI,CAAC,OAAO;IACZ,MAAM,SAAS,cAAc,QAAQ,GAAG;IACxC,KAAK,MAAM,SAAS,MAAM,QAAQ;KAChC,IAAI,CAAC,MAAM,cAAc,CAAC,MAAM,YAAY;KAC5C,MAAM,SAAS,KAAK,QAAQ,MAAM,WAAW,QAAQ,OAAO,EAAE,CAAC;KAC/D,MAAM,MAAM,QAAQ,MAAM,GAAG,EAAE,WAAW,KAAK,CAAC;KAChD,MAAM,GAAG,MAAM,YAAY,MAAM;IACnC;IACA,IAAI,CAAC,kBAAkB,MAAM,OAAO,OAAO,SAAS;KAClD,MAAM,EAAE,OAAO,gBAAgB,MAAM,OAAO;KAC5C,MAAM,UAAU,MAAM,YAAY,EAChC,cAAc,uBAChB,CAAC;KACD,IAAI,CAAC,QAAQ,SAAS,QAAQ,OAAO,SAAS,GAC5C,MAAM,IAAI,MACR,6BAA6B,QAAQ,OAAO,KAAK,IAAI,GACvD;KAEF,MAAM,UAAU,MAAM,QAAQ,MAAM,aAAa,EAAE,MAAM,OAAO,CAAC;KACjE,IAAI,QAAQ,OAAO,SAAS,GAC1B,MAAM,IAAI,MACR,sCAAsC,QAAQ,OAAO,KAAK,IAAI,GAChE;KAEF,MAAM,UAAU,MAAM,QAAQ,MAAM,WAAW,EAC7C,YAAY,KAAK,QAAQ,UAAU,EACrC,CAAC;KACD,MAAM,MAAM;KACZ,IAAI,QAAQ,OAAO,SAAS,GAC1B,MAAM,IAAI,MACR,uCAAuC,QAAQ,OAAO,KAAK,IAAI,GACjE;IAEJ;GACF;EACF;CACF;AACF;AAEA,SAAS,aAAa,OAAoD;CACxE,OAAO,IAAI,IACT,MAAM,OAAO,SAAS,UACpB,MAAM,cAAc,MAAM,aACtB,CAAC,CAAC,MAAM,YAAY,KAAK,CAAU,IACnC,CAAC,CACP,CACF;AACF;AAEA,SAAS,eACP,OAC+D;CAC/D,IAAI,MAAM,OAAO,KAAK,SAAS,OAAO,MAAM,OAAO;CACnD,MAAM,WAAW,IAAI,IACnB,MAAM,QAAQ,SAAS,UACrB,MAAM,SAAS,WAAW,CAAC,MAAM,QAAQ,QAAQ,IAAI,CAAC,CACxD,CACF;CACA,IAAI,SAAS,SAAS,GAAG,OAAO,MAAM,OAAO;CAC7C,MAAM,WAAW,SAAS,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC;CAC1C,IAAI,CAAC,UAAU,OAAO,MAAM,OAAO;CACnC,MAAM,YAAY,SAAS,YAAY,GAAG;CAC1C,IAAI,aAAa,KAAK,cAAc,SAAS,SAAS,GACpD,OAAO,MAAM,OAAO;CACtB,OAAO;EAAE,GAAG,MAAM,OAAO;EAAM,SAAS,SAAS,MAAM,YAAY,CAAC;CAAE;AACxE;AAEA,SAAS,YAAY,KAAiC;CACpD,IAAI;EACF,OAAO,mBAAmB,IAAI,IAAI,OAAO,KAAK,kBAAkB,CAAC,CAAC,QAAQ;CAC5E,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,iBAAiB,UAA0B;CAClD,QAAQ,QAAQ,QAAQ,CAAC,CAAC,YAAY,GAAtC;EACE,KAAK,SACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,KAAK;EACL,KAAK,QACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,KAAK,SACH,OAAO;EACT,SACE,OAAO;CACX;AACF;AAEA,SAAS,oBACP,OACA,UACM;CACN,MAAM,SAAS,YAAY,QAAQ;CACnC,MAAM,eAAe,2BAA2B,OAAO,MAAM;CAE7D,UAAU;EACR,QAAQ;GACN,GAAG;GACH,GAAG,OAAO;EACZ;EACA,OAAO;EACP;EACA,SAAS,SAAS;EAClB,GAAI,eACA,EAAgB,aAAuC,IACvD,CAAC;CACP,CAAC;AACH;AAEA,SAAS,iBAAiB,QAA6C;CACrE,MAAM,WAAW,OAAO,OAAO,SAC3B,OAAO,MAAM,IAAI,oBAAoB,IACrC,CAAC,EAAE,cAAc,EAAE,WAAW,GAAG,EAAE,CAAC;CACxC,IAAI,CAAC,OAAO,WAAW,OAAO;CAE9B,OAAO,CACL,GAAI,OAAO,yBAAyB,KAAA,IAChC,CACE;EACE,OAAO;EACP,QAAQ,OAAO,SAAS,CAAC,EAAA,CAAG,IAAI,oBAAoB;CACtD,CACF,IACA,CAAC,GACL,GAAG,OAAO,KAAK,SAAS,QACtB,IAAI,UAAU,KAAA,IACV,CAAC;EAAE,OAAO,IAAI;EAAO,OAAO,IAAI,MAAM,IAAI,oBAAoB;CAAE,CAAC,IACjE,CAAC,CACP,CACF;AACF;AAEA,SAAS,qBAAqB,MAA+B;CAC3D,IAAI,OAAO,SAAS,UAAU,OAAO,EAAE,MAAM,YAAY,IAAI,EAAE;CAC/D,IAAI,WAAW,MACb,OAAO;EACL,OAAO,KAAK;EACZ,OAAO,KAAK,MAAM,IAAI,oBAAoB;CAC5C;CAEF,IAAI,kBAAkB,MACpB,OAAO;EACL,OAAO,KAAK;EACZ,OAAO,CACL,EACE,cAAc,EACZ,WAAW,YAAY,KAAK,aAAa,WAAW,KAAK,EAC3D,EACF,CACF;CACF;CAEF,OAAO;EAAE,OAAO,KAAK;EAAO,MAAM,KAAK;CAAK;AAC9C;AAEA,SAAS,YAAY,OAAe,cAAc,MAAc;CAE9D,OADa,MAAM,QAAQ,cAAc,EAC/B,MAAM,cAAc,UAAU;AAC1C;AAEA,SAAgB,eACd,QACkB;CAClB,OAAO,UAAU,MAAM;AACzB;AAEA,eAAe,UACb,cACA,MACA,SACe;CACf,KAAK,MAAM,eAAe,cAAc;EACtC,MAAM,UAAU,YAAY,MAAM;EAClC,IAAI,OAAO,YAAY,YACrB,MAAO,QACL,OACF;CAEJ;AACF;AAEA,SAAS,kBACP,YACA,QACA;CACA,MAAM,WAAW;CACjB,MAAM,WAAW;CACjB,OAAO;EACL,MAAM;EACN,UAAU,IAAY;GACpB,IAAI,OAAO,2BAA2B,OAAO;GAC7C,IAAI,OAAO,2BAA2B,OAAO;EAE/C;EACA,MAAM,KAAK,IAAY;GACrB,IAAI,OAAO,UACT,OAAO,0BAA0B,KAAK,UAAU,MAAM,WAAW,CAAC,EAAE;GAEtE,IAAI,OAAO,UACT,OAAO,yBAAyB,KAAK,UAAU,MAAM,EAAE;EAG3D;CACF;AACF;AAEA,SAAS,iBAAiB,QAAsB;CAC9C,MAAM,SAAS,cAAc,MAAM;CACnC,OAAO;EACL;EACA;EACA;EACA;EACA;CACF,CAAC,CAAC,MAAM,SAAS,WAAW,KAAK,QAAQ,IAAI,CAAC,CAAC;AACjD"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/theme/defaults.ts","../src/theme/index.ts","../src/theme/tasty-config.ts","../src/components/component-styles.ts","../src/components/tasty-states.js","../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.65,\n letterSpacing: \"-0.006em\",\n fontWeight: 420,\n boldFontWeight: 640,\n },\n heading: {\n fontFamily: BODY_FONT,\n fontSize: \"1rem\",\n lineHeight: 1.15,\n letterSpacing: \"-0.025em\",\n fontWeight: 640,\n boldFontWeight: 720,\n },\n h1: heading(\"clamp(2.5rem, 5vw, 3.25rem)\", 1.05, \"-0.045em\"),\n h2: heading(\"clamp(1.75rem, 3vw, 2.125rem)\", 1.1, \"-0.035em\"),\n h3: heading(\"1.5rem\", 1.15, \"-0.025em\"),\n h4: heading(\"1.25rem\", 1.2, \"-0.018em\"),\n h5: heading(\"1.125rem\", 1.25, \"-0.012em\"),\n h6: heading(\"1rem\", 1.3, \"-0.006em\"),\n navigation: {\n fontFamily: \"var(--body-font-family)\",\n fontSize: \"0.9375rem\",\n lineHeight: 1.4,\n letterSpacing: \"-0.006em\",\n fontWeight: 540,\n boldFontWeight: 650,\n },\n small: {\n fontFamily: \"var(--body-font-family)\",\n fontSize: \"0.875rem\",\n lineHeight: 1.45,\n letterSpacing: \"-0.002em\",\n fontWeight: 420,\n boldFontWeight: 650,\n },\n code: {\n fontFamily: MONO_FONT,\n fontSize: \"0.875rem\",\n lineHeight: 1.65,\n letterSpacing: \"0\",\n fontWeight: 400,\n boldFontWeight: 650,\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 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 shadow: 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 as the ramp moves away from white. Reduce\n // saturation along the light ramp and keep dark chrome nearly neutral.\n darkSaturation: 0.35,\n });\n const surface2 = glaze.color(\n {\n from: surfaceFrom,\n base: surface,\n tone: \"-2\",\n mode: \"auto\",\n saturationFactor: 0.9,\n darkSaturation: 0.325,\n },\n glazeOptions,\n );\n const surface3 = glaze.color(\n {\n from: surfaceFrom,\n base: surface2,\n tone: \"-2\",\n mode: \"auto\",\n saturationFactor: 0.8,\n darkSaturation: 0.3,\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 const resolvedSurface = surface.resolve();\n const resolvedAccent = accentText.resolve();\n const shadowTheme = glaze(\n {\n hue: variantToOkhsl(resolvedSurface.light).h,\n saturation: variantToOkhsl(resolvedSurface.light).s * 100,\n darkHue: variantToOkhsl(resolvedSurface.dark).h,\n darkSaturation: variantToOkhsl(resolvedSurface.dark).s * 100,\n },\n undefined,\n glazeOptions,\n );\n shadowTheme.colors({\n surface: {\n from: surfaceFrom,\n mode: \"auto\",\n darkSaturation: 0.35,\n },\n text: {\n from: theme.palette?.text ?? \"#20232a\",\n base: \"surface\",\n role: \"text\",\n contrast: { apca: [75, 90] },\n mode: \"auto\",\n },\n shadow: {\n type: \"shadow\",\n bg: \"surface\",\n fg: \"text\",\n intensity: [12, 20],\n tuning: { alphaMax: 0.28 },\n },\n });\n\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 shadow = shadowTheme.json(outputOptions).shadow;\n if (!shadow) throw new Error(\"The Glaze shadow token failed to resolve.\");\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 shadow,\n };\n return {\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","import type { ConfigTokens } from \"@tenphi/tasty/core\";\nimport type { ResolvedDocsTheme } from \"./index.js\";\n\nexport const TASTY_UNITS = {\n x: \"var(--gap)\",\n r: \"var(--radius)\",\n cr: \"var(--card-radius)\",\n bw: \"var(--border-width)\",\n} as const;\n\n// Token states are emitted on :root already. Keep these as ordinary state\n// selectors so Tasty attaches them to that root instead of generating an\n// impossible descendant `:root ... :root` selector.\nconst LIGHT =\n \"theme=light | (@media(prefers-color-scheme: light) & :not([data-theme]))\";\nconst HIGH_CONTRAST =\n \"contrast=more | (@media(prefers-contrast: more) & :not([data-contrast]))\";\n\nexport function tastyTokens(theme: ResolvedDocsTheme): ConfigTokens {\n const tokens = Object.fromEntries(\n Object.entries(theme.tokens).filter(([name]) => name.startsWith(\"$\")),\n ) as ConfigTokens;\n\n Object.assign(tokens, {\n \"#surface\": colorStates(theme.colors.surface),\n \"#surface-2\": colorStates(theme.colors.surface2),\n \"#surface-3\": colorStates(theme.colors.surface3),\n \"#surface-2-hover\": mix(\"#text\", 3, \"#surface-2\"),\n \"#surface-2-pressed\": mix(\"#text\", 9, \"#surface-2\"),\n \"#surface-3-hover\": mix(\"#text\", 3, \"#surface-3\"),\n \"#surface-3-pressed\": mix(\"#text\", 9, \"#surface-3\"),\n \"#text\": colorStates(theme.colors.text),\n \"#text-soft\": colorStates(theme.colors.textSoft),\n \"#border\": mix(\"#text\", 18, \"#surface\"),\n \"#border-strong\": mix(\"#text\", 34, \"#surface\"),\n \"#accent-text\": colorStates(theme.colors.accentText),\n \"#accent-surface\": colorStates(theme.colors.accentSurface),\n \"#accent-surface-text\": colorStates(theme.colors.accentSurfaceText),\n \"#focus\": colorStates(theme.colors.focus),\n \"#shadow\": colorStates(theme.colors.shadow),\n \"#overlay\": mix(\"#text\", 58, \"transparent\"),\n } satisfies ConfigTokens);\n\n return tokens;\n}\n\nfunction colorStates(colors: Record<string, string>) {\n return {\n \"\": colors.dark,\n [LIGHT]: colors.light,\n [HIGH_CONTRAST]: colors.darkContrast,\n [`(${LIGHT}) & (${HIGH_CONTRAST})`]: colors.lightContrast,\n };\n}\n\nfunction mix(foreground: string, percentage: number, background: string) {\n return `color-mix(in oklab, ${foreground} ${percentage}%, ${background})`;\n}\n","import { mergeStyles, type Styles } from \"@tenphi/tasty/core\";\nimport {\n COOKBOOK_COMPONENT_NAMES,\n type ComponentStyleConfig,\n type ComponentStylesConfig,\n type CookbookComponentName,\n} from \"@tenphi/docs\";\n\n// Astro can load the integration and renderer through separate module graphs.\n// Keep their component configuration on the shared process global.\nconst sharedConfiguration = globalThis as typeof globalThis & {\n __tenphiCookbookComponentStyles?: ComponentStylesConfig;\n};\nconst cookbookComponentNames = new Set<string>(COOKBOOK_COMPONENT_NAMES);\n\nexport function configureComponentStyles(\n styles: ComponentStylesConfig | undefined,\n): void {\n sharedConfiguration.__tenphiCookbookComponentStyles = styles ?? {};\n}\n\nexport function resolveComponentStyles(\n name: CookbookComponentName,\n defaults: Styles,\n): Styles {\n const configured = sharedConfiguration.__tenphiCookbookComponentStyles?.[\n name\n ] as ComponentStyleConfig | undefined;\n if (!configured) return defaults;\n if (isModeConfig(configured)) {\n const styles = configured.styles as Styles;\n return configured.mode === \"replace\"\n ? styles\n : mergeStyles(defaults, styles);\n }\n return mergeStyles(defaults, configured as Styles);\n}\n\nexport function resolveComponentStyleOverride(\n name: CookbookComponentName,\n): { mode: \"extend\" | \"replace\"; styles: Styles } | undefined {\n const configured = sharedConfiguration.__tenphiCookbookComponentStyles?.[\n name\n ] as ComponentStyleConfig | undefined;\n if (!configured) return undefined;\n if (isModeConfig(configured)) {\n return { mode: configured.mode, styles: configured.styles as Styles };\n }\n return { mode: \"extend\", styles: configured as Styles };\n}\n\n/** Preserve custom anatomy names from the pre-component style API. */\nexport function resolveLegacyAnatomyStyles(\n styles: ComponentStylesConfig | undefined,\n): Record<string, Styles> | undefined {\n if (!styles) return undefined;\n const entries = Object.entries(styles)\n .filter(\n (entry): entry is [string, ComponentStyleConfig] =>\n !cookbookComponentNames.has(entry[0]) && entry[1] !== undefined,\n )\n .map(([name, value]) => [\n `[data-tasty-anatomy=\"${name}\"]`,\n isModeConfig(value) ? value.styles : value,\n ]);\n return entries.length\n ? (Object.fromEntries(entries) as Record<string, Styles>)\n : undefined;\n}\n\nfunction isModeConfig(\n value: ComponentStyleConfig,\n): value is Extract<ComponentStyleConfig, { mode: string }> {\n return (\n \"mode\" in value &&\n (value.mode === \"extend\" || value.mode === \"replace\") &&\n \"styles\" in value\n );\n}\n","import { configure } from \"@tenphi/tasty\";\n\nexport const cookbookStates = {\n \"@mobile\": \"@media(w < 50rem)\",\n \"@desktop\": \"@media(w >= 50rem)\",\n \"@small\": \"@media(w <= 40rem)\",\n \"@shell-mobile\": \"@media(w <= 48rem)\",\n \"@shell-desktop\": \"@media(w > 48rem)\",\n \"@narrow-layout\": \"@media(w < 72rem)\",\n \"@medium-layout\": \"@media(w >= 50rem) & @media(w < 72rem)\",\n \"@reduced-motion\": \"@media(prefers-reduced-motion: reduce)\",\n};\n\nlet configured = false;\n\n/** Configure aliases in the renderer's Tasty module before styles are parsed. */\nexport function configureCookbookStates() {\n if (configured) return;\n configure({ states: cookbookStates });\n configured = true;\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, pathToFileURL } 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\";\nimport { TASTY_UNITS, tastyTokens } from \"./theme/tasty-config.js\";\nimport {\n configureComponentStyles,\n resolveLegacyAnatomyStyles,\n} from \"./components/component-styles.js\";\nimport { cookbookStates } from \"./components/tasty-states.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);\nconst tastyExtractStaticMiddleware = packageRequire.resolve(\n \"@tenphi/tasty/ssr/astro-middleware-extract-static\",\n);\nconst astroReactServer = packageRequire.resolve(\"@astrojs/react/server.js\");\nconst astroReactClient = packageRequire.resolve(\"@astrojs/react/client.js\");\nconst astroReactIntegration = packageRequire.resolve(\"@astrojs/react\");\nconst importNative = new Function(\"specifier\", \"return import(specifier)\") as (\n specifier: string,\n) => Promise<{ default: () => AstroIntegration }>;\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 configureComponentStyles(options.config?.theme?.styles);\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 mobileMenuFooterPath = fileURLToPath(\n new URL(\"./overrides/MobileMenuFooter.astro\", import.meta.url),\n );\n const themeSelectPath = fileURLToPath(\n new URL(\"./overrides/ThemeSelect.astro\", import.meta.url),\n );\n const components = {\n Header: headerPath,\n Sidebar: sidebarPath,\n MobileMenuFooter: mobileMenuFooterPath,\n ThemeSelect: themeSelectPath,\n ...options.config?.components?.overrides,\n };\n const navigation = resolveNavigationLayout(options.config?.navigation);\n // Tasty 3.6's integration shape is structurally compatible with Astro 7;\n // its published helper type still models `site` as URL-only.\n const tasty = tastyIntegration({\n islands: false,\n css: { mode: \"extract\" },\n }) as unknown as AstroIntegration;\n let inner: AstroIntegration[] = [tasty];\n let projectRoot = options.root;\n let graphConfig = options.config;\n let graph: Awaited<ReturnType<typeof createDocsGraph>> | undefined;\n let usingContentCollection = 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 const react = (\n await importNative(pathToFileURL(astroReactIntegration).href)\n ).default();\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 usingContentCollection = hasContentConfig(context.config.srcDir);\n const starlightIntegration = starlight({\n title: options.config?.site?.title ?? \"Documentation\",\n ...(options.config?.site?.description\n ? { description: options.config.site.description }\n : {}),\n ...(options.config?.search?.enabled === false\n ? { pagefind: false }\n : {}),\n ...(!usingContentCollection ? { disable404Route: true } : {}),\n components,\n sidebar: usingContentCollection ? starlightSidebar(navigation) : [],\n });\n inner = [react, tasty, starlightIntegration];\n let markdownRuntime = {\n image: context.config.image,\n markdown: context.config.markdown,\n srcDir: context.config.srcDir,\n };\n let markdownRenderer: ReturnType<\n typeof markdownRuntime.markdown.processor.createRenderer\n >;\n context.updateConfig({\n base,\n output: \"static\",\n vite: {\n ssr: {\n external: [\n \"@tenphi/docs\",\n \"react\",\n \"react-dom\",\n \"react-dom/server\",\n ],\n },\n plugins: [\n virtualDocsPlugin(async () => {\n const loaded = await loadGraph();\n const entries = usingContentCollection\n ? loaded.entries\n : await Promise.all(\n loaded.entries.map(async (entry) => {\n const { image, markdown, srcDir } = markdownRuntime;\n markdownRenderer ??= markdown.processor.createRenderer({\n image,\n syntaxHighlight: markdown.syntaxHighlight,\n shikiConfig: markdown.shikiConfig,\n gfm: markdown.gfm,\n smartypants: markdown.smartypants,\n } as unknown as Parameters<\n typeof markdown.processor.createRenderer\n >[0]);\n const renderer = await markdownRenderer;\n const rendered = await renderer.render(\n entry.transformedBody,\n {\n frontmatter: entry.frontmatter,\n fileURL: starlightContentUrl(entry.route, srcDir),\n },\n );\n return {\n ...entry,\n rendered: {\n html: rendered.code,\n headings: rendered.metadata.headings,\n },\n };\n }),\n );\n return {\n entries,\n routes: loaded.routes,\n site: documentedSite(loaded),\n base: loaded.config.build.base,\n search: loaded.config.search.enabled,\n };\n }, navigation),\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 find: \"@tenphi/tasty/ssr/astro-middleware-extract-static\",\n replacement: tastyExtractStaticMiddleware,\n },\n {\n find: \"@astrojs/react/server.js\",\n replacement: astroReactServer,\n },\n {\n find: \"@astrojs/react/client.js\",\n replacement: astroReactClient,\n },\n ],\n },\n },\n });\n await callInner(inner.slice(0, 2), \"astro:config:setup\", context);\n\n if (!usingContentCollection) {\n graph = await createDocsGraph({\n root: projectRoot,\n config: graphConfig,\n });\n assertValidDocs(graph);\n context.injectRoute({\n pattern: \"[...route]\",\n entrypoint: new URL(\"./routes/DocsPage.astro\", import.meta.url),\n prerender: true,\n });\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 starlightWithPlugins = inner[2];\n if (starlightWithPlugins) {\n const selfIndex = context.config.integrations.findIndex(\n (integration) => integration.name === \"cookbook\",\n );\n context.config.integrations.splice(\n selfIndex + 1,\n 0,\n starlightWithPlugins,\n );\n try {\n await callInner(\n [starlightWithPlugins],\n \"astro:config:setup\",\n usingContentCollection\n ? context\n : withoutStarlightDocsRoute(context),\n );\n } finally {\n const placeholderIndex =\n context.config.integrations.indexOf(starlightWithPlugins);\n if (placeholderIndex >= 0)\n context.config.integrations.splice(placeholderIndex, 1);\n }\n }\n context.config.integrations.push({\n name: \"cookbook-markdown-renderer\",\n hooks: {\n \"astro:config:setup\": ({ config }) => {\n markdownRuntime = {\n image: config.image,\n markdown: config.markdown,\n srcDir: config.srcDir,\n };\n },\n },\n });\n },\n \"astro:config:done\": async (context) => {\n await callInner(inner, \"astro:config:done\", context);\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(inner, \"astro:build:start\", context);\n },\n \"astro:build:done\": async (context) => {\n await callInner(inner, \"astro:build:done\", context);\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 },\n },\n };\n}\n\nfunction starlightContentUrl(route: string, srcDir: URL): URL {\n const slug = route === \"/\" ? \"index\" : route.replace(/^\\/+|\\/+$/g, \"\");\n return new URL(`content/docs/${slug}.md`, srcDir);\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 documentedSite(\n graph: Awaited<ReturnType<typeof createDocsGraph>>,\n): Awaited<ReturnType<typeof createDocsGraph>>[\"config\"][\"site\"] {\n if (graph.config.site.version) return graph.config.site;\n const packages = new Set(\n graph.entries.flatMap((entry) =>\n entry.package?.resolved ? [entry.package.resolved] : [],\n ),\n );\n if (packages.size !== 1) return graph.config.site;\n const resolved = packages.values().next().value;\n if (!resolved) return graph.config.site;\n const separator = resolved.lastIndexOf(\"@\");\n if (separator <= 0 || separator === resolved.length - 1)\n return graph.config.site;\n return { ...graph.config.site, version: resolved.slice(separator + 1) };\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 = tastyTokens(resolved) as ConfigTokens;\n const globalStyles = resolveLegacyAnatomyStyles(theme?.styles);\n\n configure({\n states: {\n ...cookbookStates,\n ...theme?.states,\n },\n units: TASTY_UNITS,\n tokens,\n presets: resolved.presets as Record<string, TypographyPreset>,\n ...(globalStyles\n ? { globalStyles: globalStyles as Record<string, Styles> }\n : {}),\n });\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 withoutStarlightDocsRoute(\n context: HookParameters<\"astro:config:setup\">,\n): HookParameters<\"astro:config:setup\"> {\n return new Proxy(context, {\n get(target, property, receiver) {\n if (property !== \"injectRoute\") {\n return Reflect.get(target, property, receiver);\n }\n return (route: Parameters<typeof context.injectRoute>[0]) => {\n if (route.pattern !== \"[...slug]\") context.injectRoute(route);\n };\n },\n });\n}\n\nfunction virtualDocsPlugin(\n getContent: () => unknown | Promise<unknown>,\n layout: ResolvedNavigationLayout,\n) {\n const configId = \"\\0virtual:cookbook/config\";\n const layoutId = \"\\0virtual:cookbook/layout\";\n return {\n name: \"cookbook-data\",\n resolveId(id: string) {\n if (id === \"virtual:cookbook/config\") return configId;\n if (id === \"virtual:cookbook/layout\") return layoutId;\n return undefined;\n },\n async load(id: string) {\n if (id === configId) {\n return `export const content = ${JSON.stringify(await 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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"}
@@ -19,6 +19,45 @@ function navigationItemsForPath(layout, pathname) {
19
19
  const active = activeNavigationTab(layout.tabs, pathname);
20
20
  return active >= 0 && layout.tabs[active]?.items !== void 0 ? layout.tabs[active].items : layout.items;
21
21
  }
22
+ /** Build a manual Starlight sidebar for graph-backed custom pages. */
23
+ function starlightPageSidebar(layout, routes) {
24
+ const titles = new Map(routes.map((route) => [route.route, route.title]));
25
+ const labelFor = (route) => titles.get(normalizeNavigationPath(route)) ?? normalizeNavigationPath(route).split("/").filter(Boolean).at(-1) ?? "Home";
26
+ const generatedItems = (directory) => {
27
+ const root = normalizeNavigationPath(directory);
28
+ return routes.filter((route) => root === "/" || route.route === root || route.route.startsWith(`${root}/`)).map((route) => ({
29
+ label: route.title,
30
+ link: route.route
31
+ }));
32
+ };
33
+ const convert = (item) => {
34
+ if (typeof item === "string") return {
35
+ label: labelFor(item),
36
+ link: item
37
+ };
38
+ if ("items" in item) return {
39
+ label: item.label,
40
+ items: item.items.map(convert)
41
+ };
42
+ if ("autogenerate" in item) return {
43
+ label: item.label,
44
+ items: generatedItems(item.autogenerate.directory)
45
+ };
46
+ return item;
47
+ };
48
+ const fallback = layout.items?.length ? layout.items.map(convert) : routes.map((route) => ({
49
+ label: route.title,
50
+ link: route.route
51
+ }));
52
+ if (!layout.sectioned) return fallback;
53
+ return [...layout.fallbackSidebarGroup !== void 0 ? [{
54
+ label: "Documentation",
55
+ items: fallback
56
+ }] : [], ...layout.tabs.flatMap((tab) => tab.items !== void 0 ? [{
57
+ label: tab.label,
58
+ items: tab.items.map(convert)
59
+ }] : [])];
60
+ }
22
61
  /** Pick one tab, preferring its own URL before routes owned by its sidebar. */
23
62
  function activeNavigationTab(tabs, pathname) {
24
63
  const current = normalizeNavigationPath(pathname);
@@ -73,6 +112,6 @@ function directoryMatchScore(directory, current) {
73
112
  return current === target || current.startsWith(`${target}/`) ? 1e4 + target.length : -1;
74
113
  }
75
114
  //#endregion
76
- export { resolveNavigationLayout as a, normalizeNavigationPath as i, navigationItemsForPath as n, navigationPath as r, activeNavigationTab as t };
115
+ export { resolveNavigationLayout as a, normalizeNavigationPath as i, navigationItemsForPath as n, starlightPageSidebar as o, navigationPath as r, activeNavigationTab as t };
77
116
 
78
- //# sourceMappingURL=navigation-CC0dlAL8.js.map
117
+ //# sourceMappingURL=navigation-CkQXI2Zb.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navigation-CkQXI2Zb.js","names":[],"sources":["../src/navigation.ts"],"sourcesContent":["import type {\n DocsConfig,\n DocsRoute,\n NavigationItem,\n NavigationTab,\n} from \"@tenphi/docs\";\n\nexport interface ResolvedNavigationTab extends NavigationTab {\n /** Index of the tab's resolved Starlight sidebar group. */\n sidebarGroup?: number;\n}\n\nexport interface ResolvedNavigationLayout {\n fallbackSidebarGroup?: number;\n items?: NavigationItem[];\n tabs: ResolvedNavigationTab[];\n sectioned: boolean;\n}\n\nexport type StarlightPageSidebarItem =\n | { label: string; link: string }\n | { label: string; items: StarlightPageSidebarItem[] };\n\nexport function resolveNavigationLayout(\n navigation: DocsConfig[\"navigation\"],\n): ResolvedNavigationLayout {\n const items = Array.isArray(navigation) ? navigation : navigation?.items;\n const configuredTabs = Array.isArray(navigation)\n ? []\n : (navigation?.tabs ?? []);\n const fallbackSidebarGroup = items !== undefined ? 0 : undefined;\n let sidebarGroup = fallbackSidebarGroup === undefined ? 0 : 1;\n const tabs = configuredTabs.map((tab) => ({\n ...tab,\n ...(tab.items !== undefined ? { sidebarGroup: sidebarGroup++ } : {}),\n }));\n\n return {\n ...(fallbackSidebarGroup !== undefined ? { fallbackSidebarGroup } : {}),\n ...(items !== undefined ? { items } : {}),\n tabs,\n sectioned: tabs.some((tab) => tab.sidebarGroup !== undefined),\n };\n}\n\nexport function navigationItemsForPath(\n layout: ResolvedNavigationLayout,\n pathname: string,\n): NavigationItem[] | undefined {\n const active = activeNavigationTab(layout.tabs, pathname);\n return active >= 0 && layout.tabs[active]?.items !== undefined\n ? layout.tabs[active].items\n : layout.items;\n}\n\n/** Build a manual Starlight sidebar for graph-backed custom pages. */\nexport function starlightPageSidebar(\n layout: ResolvedNavigationLayout,\n routes: DocsRoute[],\n): StarlightPageSidebarItem[] {\n const titles = new Map(routes.map((route) => [route.route, route.title]));\n const labelFor = (route: string) =>\n titles.get(normalizeNavigationPath(route)) ??\n normalizeNavigationPath(route).split(\"/\").filter(Boolean).at(-1) ??\n \"Home\";\n const generatedItems = (directory: string) => {\n const root = normalizeNavigationPath(directory);\n return routes\n .filter(\n (route) =>\n root === \"/\" ||\n route.route === root ||\n route.route.startsWith(`${root}/`),\n )\n .map((route) => ({ label: route.title, link: route.route }));\n };\n const convert = (item: NavigationItem): StarlightPageSidebarItem => {\n if (typeof item === \"string\") {\n return { label: labelFor(item), link: item };\n }\n if (\"items\" in item) {\n return { label: item.label, items: item.items.map(convert) };\n }\n if (\"autogenerate\" in item) {\n return {\n label: item.label,\n items: generatedItems(item.autogenerate.directory),\n };\n }\n return item;\n };\n const fallback = layout.items?.length\n ? layout.items.map(convert)\n : routes.map((route) => ({ label: route.title, link: route.route }));\n if (!layout.sectioned) return fallback;\n\n return [\n ...(layout.fallbackSidebarGroup !== undefined\n ? [{ label: \"Documentation\", items: fallback }]\n : []),\n ...layout.tabs.flatMap((tab) =>\n tab.items !== undefined\n ? [{ label: tab.label, items: tab.items.map(convert) }]\n : [],\n ),\n ];\n}\n\n/** Pick one tab, preferring its own URL before routes owned by its sidebar. */\nexport function activeNavigationTab(\n tabs: NavigationTab[],\n pathname: string,\n): number {\n const current = normalizeNavigationPath(pathname);\n let winner = -1;\n let winningScore = -1;\n\n for (const [index, tab] of tabs.entries()) {\n const score = Math.max(\n linkMatchScore(tab.link, current, 30_000),\n navigationMatchScore(tab.items ?? [], current),\n );\n if (score > winningScore) {\n winner = index;\n winningScore = score;\n }\n }\n\n return winningScore >= 0 ? winner : -1;\n}\n\nexport function navigationPath(pathname: string, base = \"/\"): string {\n const normalizedBase = normalizeNavigationPath(base);\n const withoutBase =\n normalizedBase !== \"/\" &&\n (pathname === normalizedBase || pathname.startsWith(`${normalizedBase}/`))\n ? pathname.slice(normalizedBase.length) || \"/\"\n : pathname;\n return normalizeNavigationPath(withoutBase);\n}\n\nexport function normalizeNavigationPath(path: string): string {\n const clean = path.split(/[?#]/, 1)[0]?.replace(/\\\\/g, \"/\") ?? \"/\";\n const normalized = `/${clean.replace(/^\\/+|\\/+$/g, \"\")}`;\n return normalized === \"/\" ? normalized : normalized.replace(/\\/$/, \"\");\n}\n\nfunction navigationMatchScore(\n items: NavigationItem[],\n current: string,\n): number {\n let score = -1;\n for (const item of items) {\n if (typeof item === \"string\") {\n if (normalizeNavigationPath(item) === current)\n score = Math.max(score, 20_000);\n continue;\n }\n if (\"items\" in item) {\n score = Math.max(score, navigationMatchScore(item.items, current));\n continue;\n }\n if (\"autogenerate\" in item) {\n score = Math.max(\n score,\n directoryMatchScore(item.autogenerate.directory, current),\n );\n continue;\n }\n score = Math.max(score, linkMatchScore(item.link, current, 20_000));\n }\n return score;\n}\n\nfunction linkMatchScore(link: string, current: string, base: number): number {\n if (!link.startsWith(\"/\")) return -1;\n const target = normalizeNavigationPath(link);\n if (target === current) return base + 1_000 + target.length;\n if (target !== \"/\" && current.startsWith(`${target}/`)) {\n return base + target.length;\n }\n return -1;\n}\n\nfunction directoryMatchScore(directory: string, current: string): number {\n const target = normalizeNavigationPath(directory);\n if (target === \"/\") return 10_000;\n return current === target || current.startsWith(`${target}/`)\n ? 10_000 + target.length\n : -1;\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { DocsConfig, NavigationItem, NavigationTab } from "@tenphi/docs";
1
+ import { DocsConfig, DocsRoute, NavigationItem, NavigationTab } from "@tenphi/docs";
2
2
  //#region src/navigation.d.ts
3
3
  interface ResolvedNavigationTab extends NavigationTab {
4
4
  /** Index of the tab's resolved Starlight sidebar group. */
@@ -10,12 +10,21 @@ interface ResolvedNavigationLayout {
10
10
  tabs: ResolvedNavigationTab[];
11
11
  sectioned: boolean;
12
12
  }
13
+ type StarlightPageSidebarItem = {
14
+ label: string;
15
+ link: string;
16
+ } | {
17
+ label: string;
18
+ items: StarlightPageSidebarItem[];
19
+ };
13
20
  declare function resolveNavigationLayout(navigation: DocsConfig["navigation"]): ResolvedNavigationLayout;
14
21
  declare function navigationItemsForPath(layout: ResolvedNavigationLayout, pathname: string): NavigationItem[] | undefined;
22
+ /** Build a manual Starlight sidebar for graph-backed custom pages. */
23
+ declare function starlightPageSidebar(layout: ResolvedNavigationLayout, routes: DocsRoute[]): StarlightPageSidebarItem[];
15
24
  /** Pick one tab, preferring its own URL before routes owned by its sidebar. */
16
25
  declare function activeNavigationTab(tabs: NavigationTab[], pathname: string): number;
17
26
  declare function navigationPath(pathname: string, base?: string): string;
18
27
  declare function normalizeNavigationPath(path: string): string;
19
28
  //#endregion
20
- export { ResolvedNavigationLayout, ResolvedNavigationTab, activeNavigationTab, navigationItemsForPath, navigationPath, normalizeNavigationPath, resolveNavigationLayout };
29
+ export { ResolvedNavigationLayout, ResolvedNavigationTab, StarlightPageSidebarItem, activeNavigationTab, navigationItemsForPath, navigationPath, normalizeNavigationPath, resolveNavigationLayout, starlightPageSidebar };
21
30
  //# sourceMappingURL=navigation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"navigation.d.ts","names":[],"sources":["../src/navigation.ts"],"mappings":";;UAEiB,8BAA8B;;EAE7C;;UAGe;EACf;EACA,QAAQ;EACR,MAAM;EACN;;iBAGc,wBACd,YAAY,2BACX;iBAoBa,uBACd,QAAQ,0BACR,mBACC;;iBAQa,oBACd,MAAM,iBACN;iBAoBc,eAAe,kBAAkB;iBAUjC,wBAAwB"}
1
+ {"version":3,"file":"navigation.d.ts","names":[],"sources":["../src/navigation.ts"],"mappings":";;UAOiB,8BAA8B;;EAE7C;;UAGe;EACf;EACA,QAAQ;EACR,MAAM;EACN;;KAGU;EACN;EAAe;;EACf;EAAe,OAAO;;iBAEZ,wBACd,YAAY,2BACX;iBAoBa,uBACd,QAAQ,0BACR,mBACC;;iBAQa,qBACd,QAAQ,0BACR,QAAQ,cACP;;iBAkDa,oBACd,MAAM,iBACN;iBAoBc,eAAe,kBAAkB;iBAUjC,wBAAwB"}
@@ -1,2 +1,2 @@
1
- import { a as resolveNavigationLayout, i as normalizeNavigationPath, n as navigationItemsForPath, r as navigationPath, t as activeNavigationTab } from "./navigation-CC0dlAL8.js";
2
- export { activeNavigationTab, navigationItemsForPath, navigationPath, normalizeNavigationPath, resolveNavigationLayout };
1
+ import { a as resolveNavigationLayout, i as normalizeNavigationPath, n as navigationItemsForPath, o as starlightPageSidebar, r as navigationPath, t as activeNavigationTab } from "./navigation-CkQXI2Zb.js";
2
+ export { activeNavigationTab, navigationItemsForPath, navigationPath, normalizeNavigationPath, resolveNavigationLayout, starlightPageSidebar };
@@ -1,197 +1,54 @@
1
1
  ---
2
- import { createMarkdownProcessor } from "@astrojs/markdown-remark";
2
+ import StarlightPage from "@astrojs/starlight/components/StarlightPage.astro";
3
3
  import { content } from "virtual:cookbook/config";
4
4
  import { layout } from "virtual:cookbook/layout";
5
- import MobileNavigationTabs from "../components/MobileNavigationTabs.astro";
6
- import NavigationTree from "../components/NavigationTree.astro";
7
- import GlobalStyles from "../components/GlobalStyles.js";
8
- import PackageVersion from "../components/PackageVersion.astro";
9
- import {
10
- AppearanceControlRoot,
11
- DocsArticleRoot,
12
- DocsLayoutRoot,
13
- DocsSidebarRoot,
14
- SearchDialogRoot,
15
- SearchTriggerRoot,
16
- SkipLinkRoot,
17
- StandaloneHeaderRoot,
18
- TopNavigationRoot,
19
- VisuallyHiddenRoot,
20
- } from "../components/LayoutComponents.js";
21
- import { activeNavigationTab, navigationItemsForPath } from "../navigation.js";
22
- import "@fontsource-variable/onest/wght.css";
23
- import "@fontsource-variable/jetbrains-mono/wght.css";
5
+ import { starlightPageSidebar } from "../navigation.js";
24
6
 
25
7
  export const prerender = true;
26
8
 
27
- export async function getStaticPaths() {
28
- const processor = await createMarkdownProcessor();
29
- return Promise.all(
30
- content.entries.map(async (entry) => ({
9
+ export function getStaticPaths() {
10
+ return content.entries
11
+ .filter(
12
+ (entry) =>
13
+ import.meta.env.MODE !== "production" || !entry.frontmatter.draft,
14
+ )
15
+ .map((entry) => ({
31
16
  params: { route: entry.route === "/" ? undefined : entry.route.slice(1) },
32
- props: {
33
- entry,
34
- routes: content.routes,
35
- html: (await processor.render(entry.transformedBody)).code,
36
- site: content.site,
37
- base: content.base,
38
- search: content.search,
39
- },
40
- })),
41
- );
17
+ props: { entry, routes: content.routes },
18
+ }));
42
19
  }
43
20
 
44
- const { entry, routes, html, site, base, search } = Astro.props;
45
- const withBase = (route) =>
46
- `${base === "/" ? "" : `/${base.replace(/^\/+|\/+$/g, "")}`}${route}` || "/";
47
- const activeTab = activeNavigationTab(layout.tabs, entry.route);
48
- const navigationItems =
49
- navigationItemsForPath(layout, entry.route) ??
50
- routes.map((route) => route.route);
21
+ const { entry, routes } = Astro.props;
22
+ if (!entry.rendered) {
23
+ throw new Error(`Cookbook did not render ${entry.sourcePath}.`);
24
+ }
25
+ const frontmatter = {
26
+ title: entry.title,
27
+ ...(entry.description ? { description: entry.description } : {}),
28
+ ...(entry.frontmatter.toc !== undefined
29
+ ? { tableOfContents: entry.frontmatter.toc }
30
+ : {}),
31
+ ...(entry.frontmatter.editUrl !== undefined
32
+ ? { editUrl: entry.frontmatter.editUrl }
33
+ : {}),
34
+ ...(entry.frontmatter.prev !== undefined
35
+ ? { prev: entry.frontmatter.prev }
36
+ : {}),
37
+ ...(entry.frontmatter.next !== undefined
38
+ ? { next: entry.frontmatter.next }
39
+ : {}),
40
+ ...(entry.frontmatter.search !== undefined
41
+ ? { pagefind: entry.frontmatter.search }
42
+ : {}),
43
+ ...(entry.frontmatter.head ? { head: entry.frontmatter.head } : {}),
44
+ ...(entry.frontmatter.draft ? { draft: true } : {}),
45
+ };
51
46
  ---
52
47
 
53
- <!doctype html>
54
- <html lang="en">
55
- <head>
56
- <meta charset="utf-8" />
57
- <meta name="viewport" content="width=device-width" />
58
- <title>{entry.title} | {site.title ?? "Documentation"}</title>
59
- {
60
- entry.description && (
61
- <meta name="description" content={entry.description} />
62
- )
63
- }
64
- </head>
65
- <body class="td-shell">
66
- <GlobalStyles />
67
- <SkipLinkRoot
68
- className="td-skip"
69
- href="#main-content"
70
- data-tasty-anatomy="SkipLink"
71
- >
72
- Skip to content
73
- </SkipLinkRoot>
74
- <StandaloneHeaderRoot
75
- className="td-shell__header"
76
- data-tasty-anatomy="Header"
77
- data-docs-base={base}
78
- >
79
- <div class="td-shell__header-primary">
80
- <div class="td-shell__brand">
81
- <a href={withBase("/")}>{site.title ?? "Documentation"}</a>
82
- <PackageVersion version={site.version} />
83
- </div>
84
- <div class="td-shell__actions">
85
- <AppearanceControlRoot
86
- className="td-appearance-control"
87
- title="Color theme"
88
- data-tasty-anatomy="AppearanceControl"
89
- >
90
- <VisuallyHiddenRoot>Color theme</VisuallyHiddenRoot>
91
- <select data-docs-theme aria-label="Color theme">
92
- <option value="system">System theme</option>
93
- <option value="light">Light theme</option>
94
- <option value="dark">Dark theme</option>
95
- </select>
96
- </AppearanceControlRoot>
97
- <AppearanceControlRoot
98
- className="td-appearance-control td-appearance-control--contrast"
99
- title="Contrast"
100
- data-tasty-anatomy="AppearanceControl"
101
- >
102
- <VisuallyHiddenRoot>Contrast</VisuallyHiddenRoot>
103
- <select data-docs-contrast aria-label="Contrast">
104
- <option value="system">System contrast</option>
105
- <option value="normal">Normal contrast</option>
106
- <option value="more">High contrast</option>
107
- </select>
108
- </AppearanceControlRoot>
109
- {
110
- search && (
111
- <SearchTriggerRoot
112
- type="button"
113
- data-docs-search-open
114
- aria-haspopup="dialog"
115
- aria-keyshortcuts="Control+K"
116
- data-tasty-anatomy="SearchTrigger"
117
- >
118
- <span>Search</span>
119
- <kbd data-docs-search-shortcut>
120
- <>
121
- <kbd>Ctrl</kbd>
122
- <kbd>K</kbd>
123
- </>
124
- </kbd>
125
- </SearchTriggerRoot>
126
- )
127
- }
128
- </div>
129
- </div>
130
- {
131
- layout.tabs.length > 0 && (
132
- <TopNavigationRoot
133
- className="td-top-tabs"
134
- aria-label="Primary"
135
- data-tasty-anatomy="TopNavigation"
136
- >
137
- {layout.tabs.map((tab, index) => (
138
- <a
139
- href={tab.link.startsWith("/") ? withBase(tab.link) : tab.link}
140
- aria-current={index === activeTab ? "page" : undefined}
141
- >
142
- {tab.label}
143
- </a>
144
- ))}
145
- </TopNavigationRoot>
146
- )
147
- }
148
- </StandaloneHeaderRoot>
149
- <DocsLayoutRoot
150
- className="td-shell__layout"
151
- data-tasty-anatomy="DocsLayout"
152
- >
153
- <DocsSidebarRoot
154
- className="td-shell__nav"
155
- aria-label="Documentation"
156
- data-tasty-anatomy="DocsSidebar"
157
- >
158
- <MobileNavigationTabs base={base} currentPath={entry.route} />
159
- <NavigationTree
160
- items={navigationItems}
161
- routes={routes}
162
- current={entry.route}
163
- base={base}
164
- />
165
- </DocsSidebarRoot>
166
- <DocsArticleRoot
167
- id="main-content"
168
- className="td-shell__main"
169
- data-pagefind-body
170
- data-tasty-anatomy="DocsArticle"
171
- >
172
- <h1>{entry.title}</h1>
173
- <div set:html={html} />
174
- </DocsArticleRoot>
175
- </DocsLayoutRoot>
176
- {
177
- search && (
178
- <SearchDialogRoot
179
- data-docs-search
180
- aria-labelledby="td-search-title"
181
- data-tasty-anatomy="SearchDialog"
182
- >
183
- <form method="dialog">
184
- <button aria-label="Close search">Close</button>
185
- </form>
186
- <h2 id="td-search-title">Search documentation</h2>
187
- <label>
188
- Search{" "}
189
- <input type="search" data-docs-search-input autocomplete="off" />
190
- </label>
191
- <div data-docs-search-status aria-live="polite" />
192
- <ul data-docs-search-results />
193
- </SearchDialogRoot>
194
- )
195
- }
196
- </body>
197
- </html>
48
+ <StarlightPage
49
+ frontmatter={frontmatter}
50
+ headings={entry.rendered.headings}
51
+ sidebar={starlightPageSidebar(layout, routes)}
52
+ >
53
+ <div set:html={entry.rendered.html} />
54
+ </StarlightPage>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tenphi/starlight",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "Astro and Starlight renderer for Cookbook",
5
5
  "type": "module",
6
6
  "sideEffects": [
@@ -49,10 +49,9 @@
49
49
  "@astrojs/starlight": "^0.41.10",
50
50
  "@fontsource-variable/jetbrains-mono": "^5.3.0",
51
51
  "@fontsource-variable/onest": "^5.3.0",
52
- "@tenphi/docs": "0.6.0",
52
+ "@tenphi/docs": "0.6.1",
53
53
  "@tenphi/glaze": "2.0.0",
54
54
  "@tenphi/tasty": "3.6.0",
55
- "pagefind": "^1.5.2",
56
55
  "react": "^18.3.1 || ^19.0.0",
57
56
  "react-dom": "^18.3.1 || ^19.0.0",
58
57
  "tsx": "^4.20.6"