@master/internal-site 0.1.3 → 0.2.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.
Files changed (105) hide show
  1. package/README.md +37 -0
  2. package/dist/astro.mjs +92 -41
  3. package/dist/config.d.mts +6 -0
  4. package/dist/localization-LfIbIysE.mjs +356 -0
  5. package/dist/localization.d.mts +69 -0
  6. package/dist/localization.mjs +1 -0
  7. package/package.json +12 -9
  8. package/src/astro/content-pages.ts +30 -11
  9. package/src/astro/index.ts +9 -5
  10. package/src/astro/localized-mdx.ts +45 -0
  11. package/src/astro/routes.template.ts +3 -0
  12. package/src/astro/site-context.ts +10 -2
  13. package/src/benchmarks/BenchmarkChart.astro +4 -1
  14. package/src/benchmarks/BenchmarkMetricTable.astro +1 -1
  15. package/src/benchmarks/BenchmarkStackedBars.astro +2 -2
  16. package/src/benchmarks/BenchmarkStatus.astro +3 -1
  17. package/src/benchmarks/localization.ts +22 -0
  18. package/src/blog/article/BlogArticleEnd.astro +6 -9
  19. package/src/blog/article/BlogArticleMasthead.astro +5 -8
  20. package/src/config.ts +3 -0
  21. package/src/css/foundation-data/specimen-content.ts +2 -2
  22. package/src/css/markdown.ts +52 -11
  23. package/src/demo/Demo.svelte +6 -4
  24. package/src/demo/DemoAsset.astro +5 -3
  25. package/src/demo/DemoAxes.svelte +4 -2
  26. package/src/demo/DemoCatalog.astro +8 -6
  27. package/src/demo/DemoContainer.svelte +5 -3
  28. package/src/demo/DemoControls.svelte +3 -1
  29. package/src/demo/DemoCopyButton.svelte +6 -4
  30. package/src/demo/DemoCopyGroup.svelte +4 -2
  31. package/src/demo/DemoExample.astro +3 -1
  32. package/src/demo/DemoFeatureSupport.svelte +3 -1
  33. package/src/demo/DemoGeneratedCSS.svelte +3 -1
  34. package/src/demo/DemoIndex.astro +5 -3
  35. package/src/demo/DemoLegend.svelte +3 -1
  36. package/src/demo/DemoMeasure.svelte +4 -2
  37. package/src/demo/DemoMedia.svelte +3 -1
  38. package/src/demo/DemoMotion.svelte +5 -3
  39. package/src/demo/DemoPaletteGroups.svelte +4 -2
  40. package/src/demo/DemoStyleComparison.astro +5 -3
  41. package/src/demo/DemoThemeComparison.astro +4 -2
  42. package/src/demo/DemoTokenTable.astro +4 -2
  43. package/src/demo/DemoViewTransition.astro +3 -1
  44. package/src/demo/DemoViewport.svelte +13 -11
  45. package/src/demo/DemoWaterfall.astro +3 -1
  46. package/src/demo/ProjectStyleExample.astro +4 -1
  47. package/src/demo/foundations/FoundationDialog.astro +5 -2
  48. package/src/demo/foundations/FoundationTokensView.astro +16 -5
  49. package/src/demo/foundations/Palette.svelte +9 -7
  50. package/src/demo/foundations/dialog-copy.d.ts +1 -0
  51. package/src/demo/foundations/dialog-copy.js +5 -0
  52. package/src/docs-shell/common/i18n.config.d.ts +1 -1
  53. package/src/docs-shell/common/i18n.config.js +4 -12
  54. package/src/docs-shell/common/locales.d.ts +8 -0
  55. package/src/docs-shell/common/locales.js +18 -0
  56. package/src/docs-shell/common/terminology.json +32 -0
  57. package/src/docs-shell/common/translations.d.ts +3 -0
  58. package/src/docs-shell/common/translations.js +294 -0
  59. package/src/docs-shell/components/ArticleHeader.astro +3 -3
  60. package/src/docs-shell/components/CodeCopyButton.astro +3 -1
  61. package/src/docs-shell/components/CodeTabBar.astro +5 -3
  62. package/src/docs-shell/components/DocHeader.svelte +3 -4
  63. package/src/docs-shell/components/DocHeading.astro +3 -1
  64. package/src/docs-shell/components/DocMenuButton.svelte +4 -5
  65. package/src/docs-shell/components/DocSidebar.svelte +1 -2
  66. package/src/docs-shell/components/DocumentCodeTable.astro +3 -1
  67. package/src/docs-shell/components/DocumentIllustration.astro +3 -1
  68. package/src/docs-shell/components/DocumentKeyList.astro +5 -3
  69. package/src/docs-shell/components/DocumentNamespaceTable.astro +4 -2
  70. package/src/docs-shell/components/DocumentOptions.astro +3 -1
  71. package/src/docs-shell/components/DocumentationIndex.svelte +6 -7
  72. package/src/docs-shell/components/GeneratedCSS.astro +3 -1
  73. package/src/docs-shell/components/Link.svelte +3 -2
  74. package/src/docs-shell/components/NotFound.astro +3 -4
  75. package/src/docs-shell/components/PageNavs.astro +2 -3
  76. package/src/docs-shell/components/SearchDialog.svelte +13 -16
  77. package/src/docs-shell/components/TimeAgo.svelte +6 -6
  78. package/src/docs-shell/contexts/search.ts +1 -1
  79. package/src/docs-shell/factories/Page.astro +10 -5
  80. package/src/docs-shell/factories/create-page.ts +33 -6
  81. package/src/docs-shell/layouts/BlogArticle.astro +3 -11
  82. package/src/docs-shell/remark/slug-and-toc.js +5 -7
  83. package/src/docs-shell/scripts/code.ts +5 -2
  84. package/src/docs-shell/site.ts +9 -1
  85. package/src/docs-shell/utils/document-copy.d.ts +2 -0
  86. package/src/docs-shell/utils/document-copy.js +18 -0
  87. package/src/docs-shell/utils/generate-metadata.ts +2 -0
  88. package/src/docs-shell/utils/i18n-pathname.ts +13 -2
  89. package/src/docs-shell/utils/i18n.ts +4 -1
  90. package/src/docs-shell/utils/localized-metadata.ts +22 -0
  91. package/src/docs-shell/utils/markdown-links.ts +61 -0
  92. package/src/docs-shell/utils/markdown-tree.ts +19 -6
  93. package/src/docs-shell/utils/resolve-heading.d.ts +1 -0
  94. package/src/docs-shell/utils/resolve-heading.js +21 -0
  95. package/src/docs-shell/utils/search-pages.ts +75 -22
  96. package/src/home/hero.css +5 -0
  97. package/src/layouts/Document.astro +1 -1
  98. package/src/scripts/localization.ts +239 -0
  99. package/src/scripts/mdx-sample.ts +12 -0
  100. package/src/scripts/static-social.ts +17 -3
  101. package/src/scripts/style-delivery.mjs +14 -4
  102. package/src/sections/guide.astro +3 -1
  103. package/src/styles/docs-shell/prose.css +1 -1
  104. package/src/virtual.d.ts +5 -1
  105. package/src/blog/article/language.ts +0 -29
@@ -15,7 +15,7 @@ export interface StaticSocialOptions {
15
15
  locales?: readonly string[]
16
16
  }
17
17
 
18
- /** Replace dynamic card placeholders with static, content-addressed PNG files. */
18
+ /** Share the canonical source artwork across locales; social text remains localized. */
19
19
  export async function generateStaticSocialImages({ siteDir, outDir, origin, logo, defaultLocale = 'en', locales = ['en'] }: StaticSocialOptions) {
20
20
  const authorImageFiles: Record<string, string> = { Aron: 'aron.jpg', Joy: 'joy.jpg', BenSeage: 'benseage.jpg', Miles: 'miles.jpg', Lola: 'lola.jpg' }
21
21
  await generate()
@@ -34,15 +34,29 @@ async function generate() {
34
34
 
35
35
  if (!filesWithMatches.length) return
36
36
 
37
+ const byPath = new Map(filesWithMatches.map(record => [path.relative(outDir, record.file).split(path.sep).join('/'), record]))
38
+ const sourceMatches = (file: string, matches: string[]) => {
39
+ const relative = path.relative(outDir, file).split(path.sep).join('/')
40
+ const [first, ...rest] = relative.split('/')
41
+ const locale = first.replace(/\.html$/, '')
42
+ if (!locales.includes(locale) || locale === defaultLocale) return matches
43
+ const source = byPath.get(rest.join('/') || 'index.html')
44
+ if (!source) throw new Error(`Missing canonical source social image for ${relative}`)
45
+ return source.matches
46
+ }
47
+
37
48
  await rm(path.join(outDir, 'og'), { recursive: true, force: true })
38
49
 
39
50
  const generated = new Map<string, string>()
40
51
 
41
52
  for (const { file, matches, content: originalContent } of filesWithMatches) {
42
53
  let content = originalContent
54
+ const canonical = sourceMatches(file, matches)
43
55
 
44
- for (const rawUrl of matches) {
45
- const normalizedUrl = normalizeOgImageUrl(rawUrl)
56
+ for (const [index, rawUrl] of matches.entries()) {
57
+ const sourceUrl = canonical[index] ?? (canonical.length === 1 ? canonical[0] : undefined)
58
+ if (!sourceUrl) throw new Error(`Cannot match canonical social artwork for ${path.relative(outDir, file)}`)
59
+ const normalizedUrl = normalizeOgImageUrl(sourceUrl)
46
60
  const cacheKey = getOgImageCacheKey(normalizedUrl)
47
61
  let staticPath = generated.get(cacheKey)
48
62
  if (!staticPath) {
@@ -4,6 +4,7 @@ import { resolve, relative, dirname } from 'node:path'
4
4
  import { pathToFileURL } from 'node:url'
5
5
  import { createHash } from 'node:crypto'
6
6
  import { gzipSync, brotliCompressSync } from 'node:zlib'
7
+ import { locales as siteLocales, defaultLocale as siteDefaultLocale } from '../docs-shell/common/locales.js'
7
8
 
8
9
  export async function filesAt(root) {
9
10
  const files = []
@@ -56,6 +57,7 @@ export async function auditStyles(directory) {
56
57
  routes[route] = {
57
58
  links, assets: [...seen], files: seen.size, depth,
58
59
  ...Object.fromEntries(['bytes', 'gzip', 'brotli'].map(k => [k, totals.reduce((n, x) => n + x[k], 0)])),
60
+ inlineSHA256: hash(inline.join('\n')),
59
61
  inlineBytes: inline.reduce((n, s) => n + Buffer.byteLength(s), 0),
60
62
  families: Object.fromEntries(families.map(name => [name, new RegExp(`(?:^|[;{}])\\s*\\.ui-${name}\\s*\\{`).test(delivered)])),
61
63
  foundationCount: [...delivered.matchAll(/body,\s*:host\s*\{\s*font-family:\s*var\(--font-family-sans\)/g)].length,
@@ -66,12 +68,14 @@ export async function auditStyles(directory) {
66
68
  return { version: 1, routes, assets: Object.fromEntries(Object.entries(assets).map(([href, { css, ...item }]) => [href, item])) }
67
69
  }
68
70
 
69
- /** Exact per-route ceilings. New routes require an explicit reviewed budget. */
70
- export function assertStyleBudget(report, budget) {
71
+ /** Exact per-page ceilings; localized editions share the ceiling only with identical CSS. */
72
+ export function assertStyleBudget(report, budget, { locales = siteLocales, defaultLocale = siteDefaultLocale } = {}) {
71
73
  const failures = []
72
74
  if (!Object.keys(report.routes).length) throw new Error('Empty style delivery inventory')
73
75
  for (const [route, item] of Object.entries(report.routes)) {
74
- const cap = budget.routes[route]
76
+ const segment = route.split('/')[1]
77
+ const canonical = segment !== defaultLocale && locales.includes(segment) ? route.slice(segment.length + 1) || '/' : route
78
+ const cap = budget.routes[route] ?? budget.routes[canonical]
75
79
  if (!cap) { failures.push(`${route}: missing reviewed budget`); continue }
76
80
  for (const key of ['files', 'depth', 'gzip', 'brotli', 'inlineBytes']) {
77
81
  if (item[key] > cap[key]) failures.push(`${route}: ${key} ${item[key]} > ${cap[key]}`)
@@ -79,7 +83,13 @@ export function assertStyleBudget(report, budget) {
79
83
  if (item.foundationCount !== 1) failures.push(`${route}: foundation count ${item.foundationCount}`)
80
84
  if (item.layerOrder.join(',') !== 'theme,base,defaults,components,utilities') failures.push(`${route}: layer order`)
81
85
  if (item.uncompiled) failures.push(`${route}: uncompiled directives`)
82
- if (['/', '/404', '/tw', '/tw/404'].includes(route)) {
86
+ if (canonical !== route) {
87
+ const source = report.routes[canonical]
88
+ const assets = entry => entry.assets.map(href => report.assets[href].sha256).sort().join(',')
89
+ if (!source) failures.push(`${route}: missing canonical style route ${canonical}`)
90
+ else if (assets(item) !== assets(source) || item.inlineSHA256 !== source.inlineSHA256) failures.push(`${route}: CSS differs from ${canonical}`)
91
+ }
92
+ if (['/', '/404'].includes(canonical)) {
83
93
  for (const name of ['sidebar', 'toc', 'pager', 'switch', 'range']) if (item.families[name]) failures.push(`${route}: unrelated ${name}`)
84
94
  }
85
95
  }
@@ -4,7 +4,9 @@ import DocHeader from '@master/internal-site/components/DocHeader.svelte'
4
4
  import DocSidebar from '@master/internal-site/components/DocSidebar.svelte'
5
5
  import DocWrapper from '@master/internal-site/components/DocWrapper.astro'
6
6
  import navigation from 'virtual:master-site/navigation'
7
- const pageCategories = navigation.guide ?? []
7
+ import { resolveNavigation } from '../docs-shell/factories/create-page'
8
+ import { siteOf } from '../astro/site-context'
9
+ const pageCategories = resolveNavigation(siteOf(Astro).locale, navigation.guide ?? [])
8
10
  import type { MetadataTitle } from '@master/internal-site/types/Metadata'
9
11
 
10
12
  export const bodyClass = 'bg-surface-base'
@@ -40,7 +40,7 @@
40
40
 
41
41
  /* Media: whole pictures on the code panels' corner, with the quiet perimeter every image keeps — except an
42
42
  illustration, which is a tray's stage and is told apart by its tone alone. */
43
- .ui-prose :is(img, video):not(:where(.site-demo *, [data-demo-container] *)) { height: auto; }
43
+ .ui-prose :is(img, video):not(:where(.site-demo *, [data-demo-container] *, .ui-tree *)) { height: auto; }
44
44
  .ui-prose :is(img, video):not(:where(.site-demo *, [data-demo-container] *, .document-illustration *, :focus-visible)) { outline: 1px solid var(--color-line-media); outline-offset: -1px; }
45
45
  :is(figure, p, a, picture):is(.ui-prose > *) :is(img, video):not(:where(.site-demo *, [data-demo-container] *)), :is(img, video):is(.ui-prose > *) { display: block; width: 100%; max-width: none; border-radius: var(--ui-radius-xl); }
46
46
  :is(a, picture):is(.ui-prose > *) { display: block; }
package/src/virtual.d.ts CHANGED
@@ -7,9 +7,13 @@ declare module 'virtual:master-site/app' {
7
7
  export default app
8
8
  }
9
9
  declare module 'virtual:master-site/translations' {
10
- const translations: Record<string, () => Promise<import('@master/internal-site/factories/create-page').ContentModule>>
10
+ const translations: Record<string, Record<string, () => Promise<import('@master/internal-site/astro/propagated-assets').PropagatedModule<import('@master/internal-site/factories/create-page').ContentModule>>>>
11
11
  export default translations
12
12
  }
13
+ declare module 'virtual:master-site/localized-metadata' {
14
+ const metadata: Record<string, Record<string, Record<string, any>>>
15
+ export default metadata
16
+ }
13
17
  declare module 'virtual:master-site/highlight' {
14
18
  const highlight: typeof import('@master/internal-site/utils/highlight-code-core').default
15
19
  export default highlight
@@ -1,29 +0,0 @@
1
- interface Locales {
2
- locale: string
3
- defaultLocale: string
4
- hreflangOfLocale?: Record<string, string>
5
- }
6
-
7
- interface Languages extends Locales {
8
- translations: Record<string, string>
9
- }
10
-
11
- /**
12
- * Text a translated page shows in the post's own language (the title or body before it is translated) keeps that
13
- * language, so screen readers pronounce it correctly and type set for Han text leaves it alone.
14
- */
15
- export function sourceLanguageOf(text: string | undefined, { locale, defaultLocale, translations, hreflangOfLocale }: Languages) {
16
- if (!text || locale === defaultLocale || translations[text]) return undefined
17
- return hreflangOfLocale?.[defaultLocale] ?? defaultLocale
18
- }
19
-
20
- /**
21
- * The language of a post's body on a translated page: its source language while no `content.<locale>.mdx` sits beside
22
- * the source (the key format of docs-shell/factories/create-page), otherwise the page's own.
23
- */
24
- export function contentLanguageOf(sourcePath: string | undefined, translatedContent: Set<string>, { locale, defaultLocale, hreflangOfLocale }: Locales) {
25
- if (locale === defaultLocale) return undefined
26
- const directory = /^site\/content\/(.+)\/content\.mdx$/.exec(sourcePath ?? '')?.[1]
27
- if (directory && translatedContent.has(`/content/${directory}/content.${locale}.mdx`)) return undefined
28
- return hreflangOfLocale?.[defaultLocale] ?? defaultLocale
29
- }