@master/internal-site 0.1.2 → 0.1.3

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.
Files changed (183) hide show
  1. package/README.md +6 -0
  2. package/dist/astro.mjs +145 -10
  3. package/package.json +1 -1
  4. package/src/astro/index.ts +2 -0
  5. package/src/astro/routes.template.ts +1 -0
  6. package/src/astro/style-assets.ts +107 -0
  7. package/src/benchmarks/BenchmarkBarRows.astro +3 -2
  8. package/src/benchmarks/BenchmarkBars.astro +1 -1
  9. package/src/benchmarks/BenchmarkChart.astro +1 -0
  10. package/src/benchmarks/BenchmarkChartGroup.astro +1 -1
  11. package/src/benchmarks/BenchmarkDataTable.astro +1 -1
  12. package/src/benchmarks/BenchmarkFigure.astro +2 -1
  13. package/src/benchmarks/BenchmarkMetricTable.astro +1 -1
  14. package/src/benchmarks/BenchmarkMetrics.astro +1 -1
  15. package/src/benchmarks/BenchmarkSampleSummary.astro +1 -1
  16. package/src/benchmarks/BenchmarkScrollRegion.svelte +2 -1
  17. package/src/benchmarks/BenchmarkSource.astro +1 -1
  18. package/src/benchmarks/BenchmarkStackedBars.astro +2 -1
  19. package/src/benchmarks/types.ts +2 -0
  20. package/src/blog/article/BlogArticleContents.svelte +1 -1
  21. package/src/blog/article/BlogArticleMasthead.astro +12 -1
  22. package/src/css/NamespaceUtilityTable.astro +1 -1
  23. package/src/css/ThemeNumberVariableTable.astro +1 -1
  24. package/src/css/markdown.ts +14 -5
  25. package/src/demo/Demo.svelte +4 -0
  26. package/src/demo/DemoAsset.astro +1 -0
  27. package/src/demo/DemoCatalog.astro +1 -0
  28. package/src/demo/DemoComparison.svelte +3 -0
  29. package/src/demo/DemoContainer.svelte +3 -0
  30. package/src/demo/DemoControls.svelte +2 -0
  31. package/src/demo/DemoCopyButton.svelte +3 -0
  32. package/src/demo/DemoCopyGroup.svelte +2 -0
  33. package/src/demo/DemoFeatureSupport.svelte +2 -0
  34. package/src/demo/DemoGeneratedCSS.svelte +2 -0
  35. package/src/demo/DemoIndex.astro +1 -0
  36. package/src/demo/DemoMotion.svelte +1 -0
  37. package/src/demo/DemoScrollArea.svelte +2 -0
  38. package/src/demo/DemoStyleComparison.astro +1 -0
  39. package/src/demo/DemoSurface.svelte +2 -0
  40. package/src/demo/DemoThemeComparison.astro +1 -0
  41. package/src/demo/DemoTokenTable.astro +1 -1
  42. package/src/demo/DemoViewport.svelte +5 -0
  43. package/src/demo/DemoWaterfall.astro +1 -1
  44. package/src/demo/foundations/FoundationDialog.astro +1 -0
  45. package/src/demo/foundations/FoundationMedia.astro +1 -0
  46. package/src/demo/foundations/FoundationShrink.astro +1 -0
  47. package/src/demo/foundations/Palette.svelte +2 -0
  48. package/src/demo/illustration-materials.ts +1 -1
  49. package/src/demo/illustration.css +218 -0
  50. package/src/docs-shell/components/ArticleHeader.astro +2 -0
  51. package/src/docs-shell/components/Callout.astro +1 -0
  52. package/src/docs-shell/components/CodeCopyButton.astro +2 -0
  53. package/src/docs-shell/components/CodeTabBar.astro +2 -0
  54. package/src/docs-shell/components/CodeTabs.astro +2 -1
  55. package/src/docs-shell/components/CodeView.astro +1 -1
  56. package/src/docs-shell/components/DocHeader.svelte +10 -13
  57. package/src/docs-shell/components/DocMenuButton.svelte +126 -60
  58. package/src/docs-shell/components/DocSidebar.svelte +2 -0
  59. package/src/docs-shell/components/DocVersionSelect.svelte +2 -0
  60. package/src/docs-shell/components/DocumentAPIIndex.astro +1 -1
  61. package/src/docs-shell/components/DocumentChoices.astro +1 -1
  62. package/src/docs-shell/components/DocumentCodeExampleView.astro +3 -1
  63. package/src/docs-shell/components/DocumentCodeTable.astro +1 -1
  64. package/src/docs-shell/components/DocumentCopyButton.svelte +3 -0
  65. package/src/docs-shell/components/DocumentDisclosure.astro +2 -0
  66. package/src/docs-shell/components/DocumentFileTree.astro +3 -0
  67. package/src/docs-shell/components/DocumentFlow.astro +4 -1
  68. package/src/docs-shell/components/DocumentIllustration.astro +5 -11
  69. package/src/docs-shell/components/DocumentKeyList.astro +1 -1
  70. package/src/docs-shell/components/DocumentNamespaceTable.astro +1 -1
  71. package/src/docs-shell/components/DocumentOptionEntry.astro +0 -1
  72. package/src/docs-shell/components/DocumentOptionList.astro +1 -1
  73. package/src/docs-shell/components/DocumentOptions.astro +0 -1
  74. package/src/docs-shell/components/DocumentParameters.astro +1 -1
  75. package/src/docs-shell/components/DocumentPrompt.astro +2 -0
  76. package/src/docs-shell/components/DocumentValueList.astro +1 -1
  77. package/src/docs-shell/components/DocumentationIndex.svelte +2 -0
  78. package/src/docs-shell/components/ExpandContent.svelte +3 -0
  79. package/src/docs-shell/components/ExplorerView.astro +1 -0
  80. package/src/docs-shell/components/GeneratedCSS.astro +1 -0
  81. package/src/docs-shell/components/Header.svelte +1 -1
  82. package/src/docs-shell/components/InlineCode.astro +1 -0
  83. package/src/docs-shell/components/InteractingIndicator.astro +1 -0
  84. package/src/docs-shell/components/LanguageButton.svelte +1 -0
  85. package/src/docs-shell/components/LanguageSelect.svelte +2 -0
  86. package/src/docs-shell/components/NotFound.astro +3 -0
  87. package/src/docs-shell/components/PMAction.astro +1 -0
  88. package/src/docs-shell/components/PageContent.svelte +1 -1
  89. package/src/docs-shell/components/PageContentDisclosure.astro +2 -1
  90. package/src/docs-shell/components/PageContentList.svelte +2 -0
  91. package/src/docs-shell/components/PageNavs.astro +1 -0
  92. package/src/docs-shell/components/SearchButton.svelte +3 -0
  93. package/src/docs-shell/components/SearchDialog.svelte +6 -1
  94. package/src/docs-shell/components/Segments.svelte +2 -0
  95. package/src/docs-shell/components/StepSection.astro +1 -2
  96. package/src/docs-shell/components/Tabs.astro +1 -0
  97. package/src/docs-shell/components/ThemeSelect.svelte +2 -0
  98. package/src/docs-shell/components/markdown/Table.astro +1 -0
  99. package/src/docs-shell/components/markdown-components.ts +0 -1
  100. package/src/docs-shell/remark/markdown-components.js +28 -7
  101. package/src/docs-shell/scripts/document.ts +1 -1
  102. package/src/docs-shell/types/Metadata.ts +11 -0
  103. package/src/docs-shell/utils/generate-metadata.ts +3 -1
  104. package/src/docs-shell/utils/head.ts +5 -2
  105. package/src/examples/components/ArticleTransitionScene.svelte +4 -0
  106. package/src/examples/layout-system/page.astro +0 -1
  107. package/src/home/HomeBentoFrame.astro +1 -0
  108. package/src/home/HomeBentoGrid.astro +1 -0
  109. package/src/home/bento.css +167 -0
  110. package/src/home/design.css +1 -1
  111. package/src/home/home.css +4 -576
  112. package/src/home/segmented-control.css +94 -0
  113. package/src/layouts/Document.astro +3 -1
  114. package/src/public/icons/json.svg +1 -0
  115. package/src/scripts/atomic-class-authoring.ts +98 -0
  116. package/src/scripts/style-delivery.mjs +110 -0
  117. package/src/sections/blog.astro +1 -1
  118. package/src/sections/guide.astro +1 -2
  119. package/src/styles/blog-article.css +10 -7
  120. package/src/styles/blog-materials.css +13 -0
  121. package/src/styles/demo.css +0 -1
  122. package/src/styles/docs-shell/code.css +5 -61
  123. package/src/styles/docs-shell/documentation-search.css +1 -0
  124. package/src/styles/docs-shell/header.css +2 -73
  125. package/src/styles/docs-shell/menu.css +37 -17
  126. package/src/styles/docs-shell/page-content.css +2 -37
  127. package/src/styles/docs-shell/prose.css +18 -9
  128. package/src/styles/docs-shell/steps.css +2 -39
  129. package/src/styles/document-comparison.css +5 -2
  130. package/src/styles/documentation-illustration.css +1 -9
  131. package/src/styles/documentation-index.css +2 -1
  132. package/src/styles/documents.css +2 -4
  133. package/src/styles/interface.css +5 -3
  134. package/src/styles/system/DESIGN.md +34 -14
  135. package/src/styles/system/browser.css +21 -0
  136. package/src/styles/system/button-feedback.css +13 -0
  137. package/src/styles/system/callout.css +14 -0
  138. package/src/styles/system/chart.css +18 -0
  139. package/src/styles/system/checks.css +18 -0
  140. package/src/styles/system/code-panel.css +82 -0
  141. package/src/styles/system/code-tabs.css +40 -0
  142. package/src/styles/system/code.css +8 -85
  143. package/src/styles/system/compare.css +7 -0
  144. package/src/styles/system/controls.css +10 -109
  145. package/src/styles/system/copy.css +32 -0
  146. package/src/styles/system/data.css +10 -134
  147. package/src/styles/system/dialog.css +16 -0
  148. package/src/styles/system/disclosure.css +19 -0
  149. package/src/styles/system/expand.css +11 -0
  150. package/src/styles/system/fields.css +25 -0
  151. package/src/styles/system/header-core.css +101 -0
  152. package/src/styles/system/hint.css +5 -0
  153. package/src/styles/system/index.css +13 -0
  154. package/src/styles/system/inline-code.css +4 -0
  155. package/src/styles/system/kbd.css +4 -0
  156. package/src/styles/system/logos.css +10 -0
  157. package/src/styles/system/menu.css +14 -0
  158. package/src/styles/system/metrics.css +22 -0
  159. package/src/styles/system/pagehead.css +13 -0
  160. package/src/styles/system/pager.css +13 -0
  161. package/src/styles/system/parameters.css +17 -0
  162. package/src/styles/system/prompt.css +7 -0
  163. package/src/styles/system/prose.css +4 -75
  164. package/src/styles/system/range.css +12 -0
  165. package/src/styles/system/reading.css +44 -0
  166. package/src/styles/system/scroll.css +6 -0
  167. package/src/styles/system/search-trigger.css +10 -0
  168. package/src/styles/system/segmented.css +22 -0
  169. package/src/styles/system/sheet.css +8 -0
  170. package/src/styles/system/shell.css +8 -102
  171. package/src/styles/system/sidebar.css +14 -0
  172. package/src/styles/system/source.css +5 -0
  173. package/src/styles/system/specimens.css +3 -0
  174. package/src/styles/system/stage.css +18 -0
  175. package/src/styles/system/steps.css +51 -0
  176. package/src/styles/system/surfaces.css +8 -104
  177. package/src/styles/system/table.css +23 -0
  178. package/src/styles/system/toc.css +59 -0
  179. package/src/styles/system/tooltip.css +6 -0
  180. package/src/styles/system/tray-code.css +6 -0
  181. package/src/styles/system/tray.css +20 -0
  182. package/src/styles/system/tree.css +15 -0
  183. package/src/styles/system/waterfall.css +14 -0
package/README.md CHANGED
@@ -27,6 +27,12 @@ Optional `header.communityNavs` selects the links shown beside search without re
27
27
 
28
28
  The app module exports its logo component, navigation, version links and source/feedback URLs using the `SiteApp` contract. Consumers retain their own content and homepage composition. Ordinary documents use `content/<section>/<slug>/content.mdx` and `metadata.ts`; a local `page.astro` can override the generated entry. Dynamic routes enumerate params from lightweight `params.ts` files. The integration owns generated routes, page asset collection and the Astro/Svelte renderer setup.
29
29
 
30
+ Blog articles with a cover declare `cover: { src, alt, width, height }` in their
31
+ metadata. The shared article layout renders it below the byline and uses it for
32
+ Open Graph and Twitter images. An optional `socialImage` points to a PNG/JPEG
33
+ version of the same artwork; a cover takes precedence over separate social-card
34
+ images. Articles without a cover retain their existing layout and social cards.
35
+
30
36
  ```css
31
37
  /* styles/globals.css */
32
38
  @import '@master/css';
package/dist/astro.mjs CHANGED
@@ -9,6 +9,7 @@ import { cp, mkdir, readFile, readdir, unlink, writeFile } from "node:fs/promise
9
9
  import { createReadStream, existsSync } from "node:fs";
10
10
  import { isCSSRequest, searchForWorkspaceRoot, transformWithOxc } from "vite";
11
11
  import { optimize } from "svgo";
12
+ import { createHash } from "node:crypto";
12
13
  import Slugger from "github-slugger";
13
14
  import { SKIP, visit } from "unist-util-visit";
14
15
  import { parse, parseExpressionAt } from "acorn";
@@ -156,6 +157,108 @@ function svgMarkup() {
156
157
  }
157
158
  };
158
159
  }
160
+ // src/astro/style-assets.ts
161
+ /** Collapse only the compiler's unconditional, same-directory asset links.
162
+ * This is concatenation of already compiled CSS, not a second CSS compiler.
163
+ * Keep conditions, layers, URLs, repeated occurrences and unrelated imports intact.
164
+ */
165
+ async function inlineGeneratedStyles(file, ancestors = []) {
166
+ if (ancestors.includes(file)) throw new Error(`Cyclic generated stylesheet: ${file}`);
167
+ const source = await readFile(file, "utf8");
168
+ let code = "", cursor = 0;
169
+ while (cursor < source.length) {
170
+ const rest = source.slice(cursor);
171
+ const trivia = /^(?:\s+|\/\*[\s\S]*?\*\/|@layer\s+[\w,\s-]+;)/.exec(rest);
172
+ if (trivia) {
173
+ code += trivia[0];
174
+ cursor += trivia[0].length;
175
+ continue;
176
+ }
177
+ const match = /^@import\s+["'](\.\/master-css-[\w-]+\.css)["']\s*;/.exec(rest);
178
+ if (!match) break;
179
+ code += await inlineGeneratedStyles(resolve(dirname(file), match[1]), [...ancestors, file]) + "\n";
180
+ cursor += match[0].length;
181
+ }
182
+ const expanded = code + source.slice(cursor);
183
+ return /@(?:import|charset|namespace)\b/.test(expanded) ? source : expanded;
184
+ }
185
+ /** Preserve HTML link order and each reusable entry's cache identity. Originals
186
+ * remain available to any JS/CSS references; no client loading logic is added. */
187
+ async function compactStyleAssets(output) {
188
+ const root = resolve(output), replacements = /* @__PURE__ */ new Map();
189
+ const documents = /* @__PURE__ */ new Map(), users = /* @__PURE__ */ new Map();
190
+ const boundaries = /* @__PURE__ */ new Set();
191
+ async function emit(code) {
192
+ const href = `/_astro/site-style-${createHash("sha256").update(code).digest("hex").slice(0, 20)}.css`;
193
+ await writeFile(resolve(root, "." + href), code);
194
+ return href;
195
+ }
196
+ async function walk(directory) {
197
+ for (const entry of await readdir(directory, { withFileTypes: true })) {
198
+ const file = resolve(directory, entry.name);
199
+ if (entry.isDirectory()) {
200
+ await walk(file);
201
+ continue;
202
+ }
203
+ if (!entry.name.endsWith(".html")) continue;
204
+ let html = await readFile(file, "utf8");
205
+ const links = [...html.matchAll(/<link\b(?=[^>]*\brel="stylesheet")(?=[^>]*\bhref="(\/_astro\/[^"/]+\.css)")[^>]*>/g)];
206
+ for (const match of links) {
207
+ const href = match[1];
208
+ if (!replacements.has(href)) {
209
+ const input = resolve(root, "." + href);
210
+ const source = await readFile(input, "utf8");
211
+ const code = await inlineGeneratedStyles(input);
212
+ const next = source === code ? href : await emit(code);
213
+ replacements.set(href, next);
214
+ }
215
+ const next = replacements.get(href);
216
+ if (/\/(site|interface|documents)\./.test(href)) boundaries.add(next);
217
+ const pages = users.get(next) ?? [];
218
+ if (!pages.includes(file)) pages.push(file);
219
+ users.set(next, pages);
220
+ html = html.replace(match[0], match[0].replace(`href="${href}"`, `href="${next}"`));
221
+ }
222
+ documents.set(file, html);
223
+ }
224
+ }
225
+ await walk(root);
226
+ const signatures = new Map([...users].map(([href, pages]) => [href, pages.sort().join("\n")]));
227
+ const adjacent = /* @__PURE__ */ new Map();
228
+ for (const [file, html] of documents) for (const match of html.matchAll(/(?=<link rel="stylesheet" href="([^"\s]+)">\s*<link rel="stylesheet" href="([^"\s]+)">)/g)) {
229
+ const key = `${match[1]}\n${match[2]}`;
230
+ const pages = adjacent.get(key) ?? /* @__PURE__ */ new Set();
231
+ pages.add(file);
232
+ adjacent.set(key, pages);
233
+ }
234
+ for (const [file, source] of documents) {
235
+ let html = source;
236
+ const runs = [...source.matchAll(/(?:<link rel="stylesheet" href="\/_astro\/[^"/]+\.css">\s*){2,}/g)];
237
+ for (const run of runs) {
238
+ const links = [...run[0].matchAll(/<link rel="stylesheet" href="([^"\s]+)">\s*/g)];
239
+ let replacement = "", group = [];
240
+ async function flush() {
241
+ if (group.length > 1) {
242
+ const code = (await Promise.all(group.map((link) => readFile(resolve(root, "." + link[1]), "utf8")))).join("\n");
243
+ replacement += code.includes("@import") ? group.map((link) => link[0]).join("") : `<link rel="stylesheet" href="${await emit(code)}">`;
244
+ } else replacement += group.map((link) => link[0]).join("");
245
+ group = [];
246
+ }
247
+ for (const link of links) {
248
+ if (boundaries.has(link[1])) {
249
+ await flush();
250
+ replacement += link[0];
251
+ continue;
252
+ }
253
+ if (group.length && (signatures.get(group[0][1]) !== signatures.get(link[1]) || adjacent.get(`${group.at(-1)[1]}\n${link[1]}`)?.size !== users.get(link[1])?.length)) await flush();
254
+ group.push(link);
255
+ }
256
+ await flush();
257
+ html = html.replace(run[0], replacement);
258
+ }
259
+ await writeFile(file, html);
260
+ }
261
+ }
159
262
  // src/docs-shell/utils/resolve-heading.js
160
263
  function resolveHeading(title, id) {
161
264
  const explicit = typeof title === "string" && title.match(/\s+\{#([\w-]+)\}$/);
@@ -301,8 +404,38 @@ function fenceProps(node) {
301
404
  if (!props.lang) props.lang = node.lang ?? "";
302
405
  return props;
303
406
  }
304
- const componentsExport = `import { markdownComponents as __markdownComponents } from '@master/internal-site/components/markdown-components'
305
- export const components = __markdownComponents`;
407
+ const componentPaths = {
408
+ a: "markdown/Anchor.astro",
409
+ h2: "markdown/Heading2.astro",
410
+ h3: "markdown/Heading3.astro",
411
+ img: "Image.svelte",
412
+ Image: "Image.svelte",
413
+ table: "markdown/Table.astro",
414
+ Code: "Code.astro",
415
+ InlineCode: "InlineCode.astro",
416
+ PMAction: "PMAction.astro",
417
+ Do: "Do.astro",
418
+ DoNot: "DoNot.astro",
419
+ Info: "Info.astro",
420
+ Warn: "Warn.astro",
421
+ InteractingIndicator: "InteractingIndicator.astro"
422
+ };
423
+ function documentComponents(tree) {
424
+ const used = /* @__PURE__ */ new Set();
425
+ visit(tree, (node) => {
426
+ if (node.type === "link" || node.type === "linkReference") used.add("a");
427
+ if (node.type === "image" || node.type === "imageReference") used.add("img");
428
+ if (node.type === "table") used.add("table");
429
+ if (node.type === "heading" && [2, 3].includes(node.depth)) used.add(`h${node.depth}`);
430
+ if (["mdxJsxFlowElement", "mdxJsxTextElement"].includes(node.type) && node.name in componentPaths) used.add(node.name);
431
+ });
432
+ const entries = [...used].sort().map((name, index) => ({
433
+ name,
434
+ local: `__masterComponent${index}`,
435
+ path: componentPaths[name]
436
+ }));
437
+ return entries.map(({ local, path }) => `import ${local} from '@master/internal-site/components/${path}'`).join("\n") + `\nexport const components = {${entries.map(({ name, local }) => `${name}: ${local}`).join(", ")}}`;
438
+ }
306
439
  /**
307
440
  * Markdown constructs that render through site components: fences become `Code` (or a
308
441
  * package-manager `PMAction`), inline code becomes `InlineCode`, and marked paragraphs become
@@ -310,14 +443,6 @@ export const components = __markdownComponents`;
310
443
  */
311
444
  function remarkMarkdownComponents() {
312
445
  return (tree) => {
313
- tree.children.unshift({
314
- type: "mdxjsEsm",
315
- value: componentsExport,
316
- data: { estree: parse(componentsExport, {
317
- ecmaVersion: "latest",
318
- sourceType: "module"
319
- }) }
320
- });
321
446
  visit(tree, (node, index, parent) => {
322
447
  if (!parent || index === void 0) return;
323
448
  if (node.type === "code") {
@@ -352,6 +477,15 @@ function remarkMarkdownComponents() {
352
477
  return index;
353
478
  }
354
479
  });
480
+ const source = documentComponents(tree);
481
+ tree.children.unshift({
482
+ type: "mdxjsEsm",
483
+ value: source,
484
+ data: { estree: parse(source, {
485
+ ecmaVersion: "latest",
486
+ sourceType: "module"
487
+ }) }
488
+ });
355
489
  };
356
490
  }
357
491
  // src/astro/index.ts
@@ -503,6 +637,7 @@ function masterSite(site) {
503
637
  recursive: true,
504
638
  force: false
505
639
  });
640
+ await compactStyleAssets(fileURLToPath(destination));
506
641
  }
507
642
  }
508
643
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@master/internal-site",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
5
  "description": "First-party Astro and Svelte website framework for Master sites.",
6
6
  "engines": {
@@ -14,6 +14,7 @@ import sourceURL from './source-url'
14
14
  import { prepareContentPages } from './content-pages'
15
15
  import serverStyles from './server-styles'
16
16
  import svgMarkup from './svg-markup'
17
+ import { compactStyleAssets } from './style-assets'
17
18
  import remarkSlugAndTOC from '../docs-shell/remark/slug-and-toc.js'
18
19
  import remarkMarkdownComponents from '../docs-shell/remark/markdown-components.js'
19
20
  import svgoConfig from '../docs-shell/common/svgo.config.js'
@@ -118,6 +119,7 @@ export default function masterSite(site: SiteConfig): AstroIntegration {
118
119
  const destination = output
119
120
  await mkdir(destination, { recursive: true })
120
121
  await cp(new URL('../public/', import.meta.url), destination, { recursive: true, force: false })
122
+ await compactStyleAssets(fileURLToPath(destination))
121
123
  }
122
124
  }
123
125
  }
@@ -18,6 +18,7 @@ interface PageModule {
18
18
  metadata?: Partial<Metadata>
19
19
  generateMetadata?: (props: Pick<Props, 'params'>) => Promise<Partial<Metadata>> | Partial<Metadata>
20
20
  /** `false` for pages that render no document surfaces, code or prose, such as indexes. */
21
+ /** Article typography only; feature components own their CSS dependencies. */
21
22
  documentStyles?: boolean
22
23
  }
23
24
 
@@ -0,0 +1,107 @@
1
+ import { createHash } from 'node:crypto'
2
+ import { readdir, readFile, writeFile } from 'node:fs/promises'
3
+ import { dirname, resolve } from 'node:path'
4
+
5
+ /** Collapse only the compiler's unconditional, same-directory asset links.
6
+ * This is concatenation of already compiled CSS, not a second CSS compiler.
7
+ * Keep conditions, layers, URLs, repeated occurrences and unrelated imports intact.
8
+ */
9
+ export async function inlineGeneratedStyles(file: string, ancestors: string[] = []): Promise<string> {
10
+ if (ancestors.includes(file)) throw new Error(`Cyclic generated stylesheet: ${file}`)
11
+ const source = await readFile(file, 'utf8')
12
+ let code = '', cursor = 0
13
+ // Generated imports form a leading prologue. Never search declarations or
14
+ // comments for import-looking text (for example a teaching sample's content).
15
+ while (cursor < source.length) {
16
+ const rest = source.slice(cursor)
17
+ const trivia = /^(?:\s+|\/\*[\s\S]*?\*\/|@layer\s+[\w,\s-]+;)/.exec(rest)
18
+ if (trivia) { code += trivia[0]; cursor += trivia[0].length; continue }
19
+ const match = /^@import\s+["'](\.\/master-css-[\w-]+\.css)["']\s*;/.exec(rest)
20
+ if (!match) break
21
+ code += await inlineGeneratedStyles(resolve(dirname(file), match[1]), [...ancestors, file]) + '\n'
22
+ cursor += match[0].length
23
+ }
24
+ const expanded = code + source.slice(cursor)
25
+ // A remaining import would become invalid after an inlined declaration.
26
+ // Retain this entry intact, including its original import prologue. A match
27
+ // inside a comment/string merely skips this optional optimization.
28
+ return /@(?:import|charset|namespace)\b/.test(expanded) ? source : expanded
29
+ }
30
+
31
+ /** Preserve HTML link order and each reusable entry's cache identity. Originals
32
+ * remain available to any JS/CSS references; no client loading logic is added. */
33
+ export async function compactStyleAssets(output: string) {
34
+ const root = resolve(output), replacements = new Map<string, string>()
35
+ const documents = new Map<string, string>(), users = new Map<string, string[]>()
36
+ const boundaries = new Set<string>()
37
+ async function emit(code: string) {
38
+ const hash = createHash('sha256').update(code).digest('hex').slice(0, 20)
39
+ const href = `/_astro/site-style-${hash}.css`
40
+ await writeFile(resolve(root, '.' + href), code)
41
+ return href
42
+ }
43
+ async function walk(directory: string): Promise<void> {
44
+ for (const entry of await readdir(directory, { withFileTypes: true })) {
45
+ const file = resolve(directory, entry.name)
46
+ if (entry.isDirectory()) { await walk(file); continue }
47
+ if (!entry.name.endsWith('.html')) continue
48
+ let html = await readFile(file, 'utf8')
49
+ const links = [...html.matchAll(/<link\b(?=[^>]*\brel="stylesheet")(?=[^>]*\bhref="(\/_astro\/[^"/]+\.css)")[^>]*>/g)]
50
+ for (const match of links) {
51
+ const href = match[1]
52
+ if (!replacements.has(href)) {
53
+ const input = resolve(root, '.' + href)
54
+ const source = await readFile(input, 'utf8')
55
+ const code = await inlineGeneratedStyles(input)
56
+ const next = source === code ? href : await emit(code)
57
+ replacements.set(href, next)
58
+ }
59
+ const next = replacements.get(href)!
60
+ if (/\/(site|interface|documents)\./.test(href)) boundaries.add(next)
61
+ const pages = users.get(next) ?? []
62
+ if (!pages.includes(file)) pages.push(file)
63
+ users.set(next, pages)
64
+ html = html.replace(match[0], match[0].replace(`href="${href}"`, `href="${next}"`))
65
+ }
66
+ documents.set(file, html)
67
+ }
68
+ }
69
+ await walk(root)
70
+ // Co-delivered feature assets share a cache boundary. Merge only adjacent,
71
+ // plain links with identical route usage; never reorder a rule or pull a
72
+ // feature onto a route that did not already load it.
73
+ const signatures = new Map([...users].map(([href, pages]) => [href, pages.sort().join('\n')]))
74
+ const adjacent = new Map<string, Set<string>>()
75
+ for (const [file, html] of documents) {
76
+ for (const match of html.matchAll(/(?=<link rel="stylesheet" href="([^"\s]+)">\s*<link rel="stylesheet" href="([^"\s]+)">)/g)) {
77
+ const key = `${match[1]}\n${match[2]}`
78
+ const pages = adjacent.get(key) ?? new Set<string>()
79
+ pages.add(file); adjacent.set(key, pages)
80
+ }
81
+ }
82
+ for (const [file, source] of documents) {
83
+ let html = source
84
+ const runs = [...source.matchAll(/(?:<link rel="stylesheet" href="\/_astro\/[^"/]+\.css">\s*){2,}/g)]
85
+ for (const run of runs) {
86
+ const links = [...run[0].matchAll(/<link rel="stylesheet" href="([^"\s]+)">\s*/g)]
87
+ let replacement = '', group: typeof links = []
88
+ async function flush() {
89
+ if (group.length > 1) {
90
+ const code = (await Promise.all(group.map(link => readFile(resolve(root, '.' + link[1]), 'utf8')))).join('\n')
91
+ // An unresolved import must stay at the start of its own stylesheet.
92
+ replacement += code.includes('@import') ? group.map(link => link[0]).join('') : `<link rel="stylesheet" href="${await emit(code)}">`
93
+ } else replacement += group.map(link => link[0]).join('')
94
+ group = []
95
+ }
96
+ for (const link of links) {
97
+ if (boundaries.has(link[1])) { await flush(); replacement += link[0]; continue }
98
+ if (group.length && (signatures.get(group[0][1]) !== signatures.get(link[1])
99
+ || adjacent.get(`${group.at(-1)![1]}\n${link[1]}`)?.size !== users.get(link[1])?.length)) await flush()
100
+ group.push(link)
101
+ }
102
+ await flush()
103
+ html = html.replace(run[0], replacement)
104
+ }
105
+ await writeFile(file, html)
106
+ }
107
+ }
@@ -1,5 +1,6 @@
1
1
  ---
2
- import '@master/internal-site/styles/system/data.css'
2
+ import '@master/internal-site/styles/system/chart.css'
3
+ import '@master/internal-site/styles/system/metrics.css'
3
4
  import '@master/internal-site/styles/benchmarks.css'
4
5
  import { siteOf } from '@master/internal-site/astro/site-context'
5
6
  import { uniqueId } from '@master/internal-site/utils/unique-id'
@@ -27,7 +28,7 @@ const resolvedMax = max ?? Math.max(0, ...items.map((item) => item.max ?? item.v
27
28
  {item.detail && <small>{t(item.detail)}</small>}
28
29
  </span>
29
30
  <div class="ui-bar" role="meter" aria-labelledby={`${labelId} ${valueId}`} aria-valuemin={0} aria-valuemax={itemMax} aria-valuenow={item.value}>
30
- <i data-tone={item.color === 'neutral' ? 'muted' : undefined} style={{ width: `${clampPercent(item.value, itemMax)}%` }} />
31
+ <i data-tone={item.color === 'neutral' ? 'muted' : undefined} style={{ width: `${clampPercent(item.value, itemMax)}%`, background: item.fill }} />
31
32
  </div>
32
33
  <output id={valueId}>{valueLabel}</output>
33
34
  </div>
@@ -1,5 +1,5 @@
1
1
  ---
2
- import '@master/internal-site/styles/system/data.css'
2
+ import '@master/internal-site/styles/system/chart.css'
3
3
  import '@master/internal-site/styles/benchmarks.css'
4
4
  import BenchmarkBarRows from '@master/internal-site/benchmarks/BenchmarkBarRows.astro'
5
5
  import type { BenchmarkBarsProps } from '@master/internal-site/benchmarks/types.ts'
@@ -1,4 +1,5 @@
1
1
  ---
2
+ import '@master/internal-site/styles/system/table.css'
2
3
  import ExpandContent from '@master/internal-site/components/ExpandContent.svelte'
3
4
  import BenchmarkBars from '@master/internal-site/benchmarks/BenchmarkBars.astro'
4
5
  import BenchmarkMetricTable from '@master/internal-site/benchmarks/BenchmarkMetricTable.astro'
@@ -1,5 +1,5 @@
1
1
  ---
2
- import '@master/internal-site/styles/system/data.css'
2
+ import '@master/internal-site/styles/system/chart.css'
3
3
  import { siteOf } from '@master/internal-site/astro/site-context'
4
4
  import BenchmarkBarRows from '@master/internal-site/benchmarks/BenchmarkBarRows.astro'
5
5
  import type { BenchmarkBarItem } from '@master/internal-site/benchmarks/types.ts'
@@ -1,5 +1,5 @@
1
1
  ---
2
- import '@master/internal-site/styles/system/data.css'
2
+ import '@master/internal-site/styles/system/disclosure.css'
3
3
  import '@master/internal-site/styles/benchmarks.css'
4
4
  import { siteOf } from '@master/internal-site/astro/site-context'
5
5
  import BenchmarkScrollRegion from '@master/internal-site/benchmarks/BenchmarkScrollRegion.svelte'
@@ -1,5 +1,6 @@
1
1
  ---
2
- import '@master/internal-site/styles/system/data.css'
2
+ import '@master/internal-site/styles/system/tray.css'
3
+ import '@master/internal-site/styles/system/tray-code.css'
3
4
  import { siteOf } from '@master/internal-site/astro/site-context'
4
5
  import RenderNode from '@master/internal-site/components/RenderNode.astro'
5
6
 
@@ -1,5 +1,5 @@
1
1
  ---
2
- import '@master/internal-site/styles/system/data.css'
2
+ import '@master/internal-site/styles/system/table.css'
3
3
  import { siteOf } from '@master/internal-site/astro/site-context'
4
4
  import BenchmarkStatus from '@master/internal-site/benchmarks/BenchmarkStatus.astro'
5
5
  import type { BenchmarkMetric } from '@master/internal-site/benchmarks/types.ts'
@@ -1,5 +1,5 @@
1
1
  ---
2
- import '@master/internal-site/styles/system/data.css'
2
+ import '@master/internal-site/styles/system/metrics.css'
3
3
  import { siteOf } from '@master/internal-site/astro/site-context'
4
4
  import BenchmarkStatus from '@master/internal-site/benchmarks/BenchmarkStatus.astro'
5
5
  import type { BenchmarkMetric } from '@master/internal-site/benchmarks/types.ts'
@@ -1,5 +1,5 @@
1
1
  ---
2
- import '@master/internal-site/styles/system/data.css'
2
+ import '@master/internal-site/styles/system/metrics.css'
3
3
  import { siteOf } from '@master/internal-site/astro/site-context'
4
4
  import type { BenchmarkSampleSummaryStats } from '@master/internal-site/benchmarks/types.ts'
5
5
  import { formatMetricValue } from '@master/internal-site/benchmarks/utils.ts'
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
- import '@master/internal-site/styles/system/data.css'
2
+ import '@master/internal-site/styles/system/table.css'
3
+
3
4
  import type { Snippet } from 'svelte'
4
5
 
5
6
  let { title, children }: { title: string; children?: Snippet } = $props()
@@ -1,5 +1,5 @@
1
1
  ---
2
- import '@master/internal-site/styles/system/data.css'
2
+ import '@master/internal-site/styles/system/source.css'
3
3
  import { siteOf } from '@master/internal-site/astro/site-context'
4
4
 
5
5
  interface Props {
@@ -1,5 +1,6 @@
1
1
  ---
2
- import '@master/internal-site/styles/system/data.css'
2
+ import '@master/internal-site/styles/system/chart.css'
3
+ import '@master/internal-site/styles/system/metrics.css'
3
4
  import '@master/internal-site/styles/system/specimens.css'
4
5
  import '@master/internal-site/styles/benchmarks.css'
5
6
  import { siteOf } from '@master/internal-site/astro/site-context'
@@ -20,6 +20,8 @@ export interface BenchmarkBarItem {
20
20
  detail?: string
21
21
  icon?: BenchmarkIcon
22
22
  color?: BenchmarkColor
23
+ /** Explicit series identity, such as a brand's CSS color. Overrides the neutral fill. */
24
+ fill?: string
23
25
  }
24
26
 
25
27
  export interface BenchmarkSegment {
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import '@master/internal-site/styles/docs-shell/page-content.css'
2
+ import '@master/internal-site/styles/system/toc.css'
3
3
  import PageContentList from '@master/internal-site/components/PageContentList.svelte'
4
4
  import PageContentProvider from '@master/internal-site/components/PageContentProvider.svelte'
5
5
  import type { PageContentItem } from '@master/internal-site/components/page-content.svelte'
@@ -6,9 +6,10 @@ import Link from '@master/internal-site/components/Link.svelte'
6
6
  import { siteOf } from '@master/internal-site/astro/site-context'
7
7
  import TitleLines from './title-lines.astro'
8
8
  import { sourceLanguageOf } from './language'
9
+ import type { DefinedMetadata } from '@master/internal-site/types/Metadata'
9
10
 
10
11
  interface Props {
11
- metadata: any
12
+ metadata: DefinedMetadata
12
13
  }
13
14
 
14
15
  /**
@@ -58,4 +59,14 @@ const people = (metadata.authors ?? [])
58
59
  </ul>
59
60
  </div>
60
61
  )}
62
+ {metadata.cover && (
63
+ <img
64
+ class="blog-article-cover"
65
+ src={metadata.cover.src}
66
+ alt={metadata.cover.alt}
67
+ width={metadata.cover.width}
68
+ height={metadata.cover.height}
69
+ fetchpriority="high"
70
+ />
71
+ )}
61
72
  </header>
@@ -1,5 +1,5 @@
1
1
  ---
2
- import '@master/internal-site/styles/system/data.css'
2
+ import '@master/internal-site/styles/system/table.css'
3
3
  import { siteOf } from '@master/internal-site/astro/site-context'
4
4
  import { uniqueId } from '@master/internal-site/utils/unique-id'
5
5
  import InlineCode from '@master/internal-site/components/InlineCode.astro'
@@ -1,5 +1,5 @@
1
1
  ---
2
- import '@master/internal-site/styles/system/data.css'
2
+ import '@master/internal-site/styles/system/table.css'
3
3
  import { siteOf } from '@master/internal-site/astro/site-context'
4
4
  import { uniqueId } from '@master/internal-site/utils/unique-id'
5
5
  import InlineCode from '@master/internal-site/components/InlineCode.astro'
@@ -148,7 +148,8 @@ export async function extractReferenceMdx(file: string, rows: SyntaxRow[] = [],
148
148
  const result = await attribute(attrs.result)
149
149
  const diagnostic = await attribute(attrs.diagnostic)
150
150
  if (typeof source !== 'string' || typeof attrs.language !== 'string') throw new Error('DocumentCodeExample requires literal source and language')
151
- const parts = [`**${attrs.title}**`, `\`\`\`${attrs.language}\n${source}\n\`\`\``]
151
+ const sourceLabel = attrs.sourceLabel ?? (result !== undefined && attrs.resultKind !== 'generated-css' ? 'Source' : undefined)
152
+ const parts = [`**${attrs.title}**`, ...(sourceLabel ? [`**${sourceLabel}**`] : []), `\`\`\`${attrs.language}\n${source}\n\`\`\``]
152
153
  if (result !== undefined) {
153
154
  if (typeof result !== 'string') throw new Error('DocumentCodeExample requires a literal result')
154
155
  parts.push(`**${attrs.resultLabel ?? (attrs.resultKind === 'generated-css' ? 'Generated CSS' : 'Result')}**`, `\`\`\`${attrs.resultLanguage ?? attrs.language}\n${result}\n\`\`\``)
@@ -169,17 +170,25 @@ export async function extractReferenceMdx(file: string, rows: SyntaxRow[] = [],
169
170
  if (name === 'DocumentDeclaration') return `**${attrs.label}**\n\n\`\`\`typescript\n${await expression(inner)}\n\`\`\``
170
171
  if (name === 'DocumentValueList') {
171
172
  const values = await expression(attrs.rows.value) as { id: string, title: string, identifier?: string, values: { label: string, value: string }[] }[]
172
- return values.map(value => `### ${value.title} {#${value.id}}\n\n${value.identifier ? `\`${value.identifier}\`\n\n` : ''}${value.values.map(pair => `${pair.label}: \`${pair.value}\``).join('\n\n')}`).join('\n\n')
173
+ const headingLevel = await attribute(attrs.headingLevel) ?? 3
174
+ if (headingLevel !== 3 && headingLevel !== 4) throw new Error('DocumentValueList requires headingLevel 3 or 4')
175
+ return values.map(value => `${'#'.repeat(headingLevel)} ${value.title} {#${value.id}}\n\n${value.identifier ? `\`${value.identifier}\`\n\n` : ''}${value.values.map(pair => `${pair.label}: \`${pair.value}\``).join('\n\n')}`).join('\n\n')
176
+ }
177
+ if (name === 'DocumentCodeTable') {
178
+ const rows = await expression(attrs.rows.value) as { syntax: string, css: string }[]
179
+ if (!Array.isArray(rows) || rows.some(row => typeof row.syntax !== 'string' || typeof row.css !== 'string')) throw new Error('DocumentCodeTable requires literal syntax and CSS rows')
180
+ const code = (value: string) => `\`${value.replaceAll('|', '\\|')}\``
181
+ return `| ${attrs.label ?? 'Syntax'} | CSS |\n| --- | --- |\n${rows.map(row => `| ${code(row.syntax)} | ${code(row.css)} |`).join('\n')}`
173
182
  }
174
183
  if (name === 'DocumentFlow') {
175
184
  const steps = await expression(attrs.steps.value) as { title: string, description: string }[]
176
185
  return `**${attrs.title}**\n\n${steps.map((step, index) => `${index + 1}. **${step.title}** — ${step.description}`).join('\n')}${attrs.caption ? `\n\n${attrs.caption}` : ''}`
177
186
  }
178
- if (name === 'DocumentFileTree') {
187
+ if (name === 'DocumentFileTree' || name === 'ExplorerView') {
179
188
  type Entry = { name: string, description?: string, children?: Entry[] }
180
- const entries = await expression(attrs.entries.value) as Entry[]
189
+ const entries = await expression(attrs[name === 'ExplorerView' ? 'items' : 'entries'].value) as Entry[]
181
190
  const lines = (items: Entry[], level = 0): string => items.map(item => `${' '.repeat(level)}- \`${item.name}${item.children ? '/' : ''}\`${item.description ? ` — ${item.description}` : ''}${item.children?.length ? `\n${lines(item.children, level + 1)}` : ''}`).join('\n')
182
- return `**${attrs.title}**\n\n${lines(entries)}${attrs.caption ? `\n\n${attrs.caption}` : ''}`
191
+ return `${attrs.title ? `**${attrs.title}**\n\n` : ''}${lines(entries)}${attrs.caption ? `\n\n${attrs.caption}` : ''}`
183
192
  }
184
193
  if (name === 'Overview' && options.overview !== 'include') return syntaxMarkdown(rows)
185
194
  if (name === 'StylesheetExample') {
@@ -30,6 +30,10 @@
30
30
  </script>
31
31
 
32
32
  <script lang="ts">
33
+ import '@master/internal-site/styles/system/stage.css'
34
+ import '@master/internal-site/styles/system/tray.css'
35
+ import '@master/internal-site/styles/system/tray-code.css'
36
+
33
37
  import '@master/internal-site/styles/demo.css'
34
38
  import { styleText } from './style'
35
39
 
@@ -1,4 +1,5 @@
1
1
  ---
2
+ import '@master/internal-site/styles/interface.css'
2
3
  import '@master/internal-site/styles/system/specimens.css'
3
4
  import IconDownload from '@tabler/icons-svelte-runes/icons/download'
4
5
  import Demo from './Demo.svelte'
@@ -1,4 +1,5 @@
1
1
  ---
2
+ import '@master/internal-site/styles/system/disclosure.css'
2
3
  import '@master/internal-site/styles/demo.css'
3
4
  import RenderNode from '@master/internal-site/components/RenderNode.astro'
4
5
  import DemoIndex from '@master/internal-site/demo/DemoIndex.astro'
@@ -10,6 +10,9 @@
10
10
  </script>
11
11
 
12
12
  <script lang="ts">
13
+ import '@master/internal-site/styles/system/compare.css'
14
+ import '@master/internal-site/styles/system/stage.css'
15
+
13
16
  import '@master/internal-site/styles/system/specimens.css'
14
17
  import type { HTMLAttributes } from 'svelte/elements'
15
18
  import { styleText, type DemoStyle } from '@master/internal-site/demo/style.ts'
@@ -1,4 +1,7 @@
1
1
  <script lang="ts">
2
+ import '@master/internal-site/styles/interface.css'
3
+ import '@master/internal-site/styles/system/range.css'
4
+
2
5
  import '@master/internal-site/styles/system/specimens.css'
3
6
  import type { Snippet } from 'svelte'
4
7
  import type { HTMLAttributes } from 'svelte/elements'
@@ -1,4 +1,6 @@
1
1
  <script lang="ts">
2
+ import '@master/internal-site/styles/system/segmented.css'
3
+
2
4
  import '@master/internal-site/styles/system/specimens.css'
3
5
  import type { Snippet } from 'svelte'
4
6
  import type { HTMLAttributes } from 'svelte/elements'
@@ -1,4 +1,7 @@
1
1
  <script lang="ts">
2
+ import '@master/internal-site/styles/interface.css'
3
+ import '@master/internal-site/styles/system/copy.css'
4
+
2
5
  import type { Snippet } from 'svelte'
3
6
  import type { HTMLButtonAttributes } from 'svelte/elements'
4
7
  import IconCopy from '@tabler/icons-svelte-runes/icons/copy'
@@ -1,4 +1,6 @@
1
1
  <script lang="ts">
2
+ import '@master/internal-site/styles/system/copy.css'
3
+
2
4
  import type { Snippet } from 'svelte'
3
5
  import { setCopyFeedback, type CopyResult } from '@master/internal-site/demo/copy-feedback.ts'
4
6