@master/internal-site 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (239) hide show
  1. package/README.md +43 -0
  2. package/dist/astro.mjs +233 -47
  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 +11 -5
  10. package/src/astro/localized-mdx.ts +45 -0
  11. package/src/astro/routes.template.ts +4 -0
  12. package/src/astro/site-context.ts +10 -2
  13. package/src/astro/style-assets.ts +107 -0
  14. package/src/benchmarks/BenchmarkBarRows.astro +3 -2
  15. package/src/benchmarks/BenchmarkBars.astro +1 -1
  16. package/src/benchmarks/BenchmarkChart.astro +5 -1
  17. package/src/benchmarks/BenchmarkChartGroup.astro +1 -1
  18. package/src/benchmarks/BenchmarkDataTable.astro +1 -1
  19. package/src/benchmarks/BenchmarkFigure.astro +2 -1
  20. package/src/benchmarks/BenchmarkMetricTable.astro +2 -2
  21. package/src/benchmarks/BenchmarkMetrics.astro +1 -1
  22. package/src/benchmarks/BenchmarkSampleSummary.astro +1 -1
  23. package/src/benchmarks/BenchmarkScrollRegion.svelte +2 -1
  24. package/src/benchmarks/BenchmarkSource.astro +1 -1
  25. package/src/benchmarks/BenchmarkStackedBars.astro +4 -3
  26. package/src/benchmarks/BenchmarkStatus.astro +3 -1
  27. package/src/benchmarks/localization.ts +22 -0
  28. package/src/benchmarks/types.ts +2 -0
  29. package/src/blog/article/BlogArticleContents.svelte +1 -1
  30. package/src/blog/article/BlogArticleEnd.astro +6 -9
  31. package/src/blog/article/BlogArticleMasthead.astro +17 -9
  32. package/src/config.ts +3 -0
  33. package/src/css/NamespaceUtilityTable.astro +1 -1
  34. package/src/css/ThemeNumberVariableTable.astro +1 -1
  35. package/src/css/foundation-data/specimen-content.ts +2 -2
  36. package/src/css/markdown.ts +64 -14
  37. package/src/demo/Demo.svelte +10 -4
  38. package/src/demo/DemoAsset.astro +6 -3
  39. package/src/demo/DemoAxes.svelte +4 -2
  40. package/src/demo/DemoCatalog.astro +9 -6
  41. package/src/demo/DemoComparison.svelte +3 -0
  42. package/src/demo/DemoContainer.svelte +8 -3
  43. package/src/demo/DemoControls.svelte +5 -1
  44. package/src/demo/DemoCopyButton.svelte +9 -4
  45. package/src/demo/DemoCopyGroup.svelte +6 -2
  46. package/src/demo/DemoExample.astro +3 -1
  47. package/src/demo/DemoFeatureSupport.svelte +5 -1
  48. package/src/demo/DemoGeneratedCSS.svelte +5 -1
  49. package/src/demo/DemoIndex.astro +6 -3
  50. package/src/demo/DemoLegend.svelte +3 -1
  51. package/src/demo/DemoMeasure.svelte +4 -2
  52. package/src/demo/DemoMedia.svelte +3 -1
  53. package/src/demo/DemoMotion.svelte +6 -3
  54. package/src/demo/DemoPaletteGroups.svelte +4 -2
  55. package/src/demo/DemoScrollArea.svelte +2 -0
  56. package/src/demo/DemoStyleComparison.astro +6 -3
  57. package/src/demo/DemoSurface.svelte +2 -0
  58. package/src/demo/DemoThemeComparison.astro +5 -2
  59. package/src/demo/DemoTokenTable.astro +5 -3
  60. package/src/demo/DemoViewTransition.astro +3 -1
  61. package/src/demo/DemoViewport.svelte +18 -11
  62. package/src/demo/DemoWaterfall.astro +4 -2
  63. package/src/demo/ProjectStyleExample.astro +4 -1
  64. package/src/demo/foundations/FoundationDialog.astro +6 -2
  65. package/src/demo/foundations/FoundationMedia.astro +1 -0
  66. package/src/demo/foundations/FoundationShrink.astro +1 -0
  67. package/src/demo/foundations/FoundationTokensView.astro +16 -5
  68. package/src/demo/foundations/Palette.svelte +11 -7
  69. package/src/demo/foundations/dialog-copy.d.ts +1 -0
  70. package/src/demo/foundations/dialog-copy.js +5 -0
  71. package/src/demo/illustration-materials.ts +1 -1
  72. package/src/demo/illustration.css +218 -0
  73. package/src/docs-shell/common/i18n.config.d.ts +1 -1
  74. package/src/docs-shell/common/i18n.config.js +4 -12
  75. package/src/docs-shell/common/locales.d.ts +8 -0
  76. package/src/docs-shell/common/locales.js +18 -0
  77. package/src/docs-shell/common/terminology.json +32 -0
  78. package/src/docs-shell/common/translations.d.ts +3 -0
  79. package/src/docs-shell/common/translations.js +294 -0
  80. package/src/docs-shell/components/ArticleHeader.astro +5 -3
  81. package/src/docs-shell/components/Callout.astro +1 -0
  82. package/src/docs-shell/components/CodeCopyButton.astro +5 -1
  83. package/src/docs-shell/components/CodeTabBar.astro +7 -3
  84. package/src/docs-shell/components/CodeTabs.astro +2 -1
  85. package/src/docs-shell/components/CodeView.astro +1 -1
  86. package/src/docs-shell/components/DocHeader.svelte +13 -17
  87. package/src/docs-shell/components/DocHeading.astro +3 -1
  88. package/src/docs-shell/components/DocMenuButton.svelte +126 -61
  89. package/src/docs-shell/components/DocSidebar.svelte +3 -2
  90. package/src/docs-shell/components/DocVersionSelect.svelte +2 -0
  91. package/src/docs-shell/components/DocumentAPIIndex.astro +1 -1
  92. package/src/docs-shell/components/DocumentChoices.astro +1 -1
  93. package/src/docs-shell/components/DocumentCodeExampleView.astro +3 -1
  94. package/src/docs-shell/components/DocumentCodeTable.astro +4 -2
  95. package/src/docs-shell/components/DocumentCopyButton.svelte +3 -0
  96. package/src/docs-shell/components/DocumentDisclosure.astro +2 -0
  97. package/src/docs-shell/components/DocumentFileTree.astro +3 -0
  98. package/src/docs-shell/components/DocumentFlow.astro +4 -1
  99. package/src/docs-shell/components/DocumentIllustration.astro +8 -12
  100. package/src/docs-shell/components/DocumentKeyList.astro +6 -4
  101. package/src/docs-shell/components/DocumentNamespaceTable.astro +5 -3
  102. package/src/docs-shell/components/DocumentOptionEntry.astro +0 -1
  103. package/src/docs-shell/components/DocumentOptionList.astro +1 -1
  104. package/src/docs-shell/components/DocumentOptions.astro +3 -2
  105. package/src/docs-shell/components/DocumentParameters.astro +1 -1
  106. package/src/docs-shell/components/DocumentPrompt.astro +2 -0
  107. package/src/docs-shell/components/DocumentValueList.astro +1 -1
  108. package/src/docs-shell/components/DocumentationIndex.svelte +8 -7
  109. package/src/docs-shell/components/ExpandContent.svelte +3 -0
  110. package/src/docs-shell/components/ExplorerView.astro +1 -0
  111. package/src/docs-shell/components/GeneratedCSS.astro +4 -1
  112. package/src/docs-shell/components/Header.svelte +1 -1
  113. package/src/docs-shell/components/InlineCode.astro +1 -0
  114. package/src/docs-shell/components/InteractingIndicator.astro +1 -0
  115. package/src/docs-shell/components/LanguageButton.svelte +1 -0
  116. package/src/docs-shell/components/LanguageSelect.svelte +2 -0
  117. package/src/docs-shell/components/Link.svelte +3 -2
  118. package/src/docs-shell/components/NotFound.astro +6 -4
  119. package/src/docs-shell/components/PMAction.astro +1 -0
  120. package/src/docs-shell/components/PageContent.svelte +1 -1
  121. package/src/docs-shell/components/PageContentDisclosure.astro +2 -1
  122. package/src/docs-shell/components/PageContentList.svelte +2 -0
  123. package/src/docs-shell/components/PageNavs.astro +3 -3
  124. package/src/docs-shell/components/SearchButton.svelte +3 -0
  125. package/src/docs-shell/components/SearchDialog.svelte +18 -16
  126. package/src/docs-shell/components/Segments.svelte +2 -0
  127. package/src/docs-shell/components/StepSection.astro +1 -2
  128. package/src/docs-shell/components/Tabs.astro +1 -0
  129. package/src/docs-shell/components/ThemeSelect.svelte +2 -0
  130. package/src/docs-shell/components/TimeAgo.svelte +6 -6
  131. package/src/docs-shell/components/markdown/Table.astro +1 -0
  132. package/src/docs-shell/components/markdown-components.ts +0 -1
  133. package/src/docs-shell/contexts/search.ts +1 -1
  134. package/src/docs-shell/factories/Page.astro +10 -5
  135. package/src/docs-shell/factories/create-page.ts +33 -6
  136. package/src/docs-shell/layouts/BlogArticle.astro +3 -11
  137. package/src/docs-shell/remark/markdown-components.js +28 -7
  138. package/src/docs-shell/remark/slug-and-toc.js +5 -7
  139. package/src/docs-shell/scripts/code.ts +5 -2
  140. package/src/docs-shell/scripts/document.ts +1 -1
  141. package/src/docs-shell/site.ts +9 -1
  142. package/src/docs-shell/types/Metadata.ts +11 -0
  143. package/src/docs-shell/utils/document-copy.d.ts +2 -0
  144. package/src/docs-shell/utils/document-copy.js +18 -0
  145. package/src/docs-shell/utils/generate-metadata.ts +5 -1
  146. package/src/docs-shell/utils/head.ts +5 -2
  147. package/src/docs-shell/utils/i18n-pathname.ts +13 -2
  148. package/src/docs-shell/utils/i18n.ts +4 -1
  149. package/src/docs-shell/utils/localized-metadata.ts +22 -0
  150. package/src/docs-shell/utils/markdown-links.ts +61 -0
  151. package/src/docs-shell/utils/markdown-tree.ts +19 -6
  152. package/src/docs-shell/utils/resolve-heading.d.ts +1 -0
  153. package/src/docs-shell/utils/resolve-heading.js +21 -0
  154. package/src/docs-shell/utils/search-pages.ts +75 -22
  155. package/src/examples/components/ArticleTransitionScene.svelte +4 -0
  156. package/src/examples/layout-system/page.astro +0 -1
  157. package/src/home/HomeBentoFrame.astro +1 -0
  158. package/src/home/HomeBentoGrid.astro +1 -0
  159. package/src/home/bento.css +167 -0
  160. package/src/home/design.css +1 -1
  161. package/src/home/hero.css +5 -0
  162. package/src/home/home.css +4 -576
  163. package/src/home/segmented-control.css +94 -0
  164. package/src/layouts/Document.astro +4 -2
  165. package/src/public/icons/json.svg +1 -0
  166. package/src/scripts/atomic-class-authoring.ts +98 -0
  167. package/src/scripts/localization.ts +239 -0
  168. package/src/scripts/mdx-sample.ts +12 -0
  169. package/src/scripts/static-social.ts +17 -3
  170. package/src/scripts/style-delivery.mjs +120 -0
  171. package/src/sections/blog.astro +1 -1
  172. package/src/sections/guide.astro +4 -3
  173. package/src/styles/blog-article.css +10 -7
  174. package/src/styles/blog-materials.css +13 -0
  175. package/src/styles/demo.css +0 -1
  176. package/src/styles/docs-shell/code.css +5 -61
  177. package/src/styles/docs-shell/documentation-search.css +1 -0
  178. package/src/styles/docs-shell/header.css +2 -73
  179. package/src/styles/docs-shell/menu.css +37 -17
  180. package/src/styles/docs-shell/page-content.css +2 -37
  181. package/src/styles/docs-shell/prose.css +18 -9
  182. package/src/styles/docs-shell/steps.css +2 -39
  183. package/src/styles/document-comparison.css +5 -2
  184. package/src/styles/documentation-illustration.css +1 -9
  185. package/src/styles/documentation-index.css +2 -1
  186. package/src/styles/documents.css +2 -4
  187. package/src/styles/interface.css +5 -3
  188. package/src/styles/system/DESIGN.md +34 -14
  189. package/src/styles/system/browser.css +21 -0
  190. package/src/styles/system/button-feedback.css +13 -0
  191. package/src/styles/system/callout.css +14 -0
  192. package/src/styles/system/chart.css +18 -0
  193. package/src/styles/system/checks.css +18 -0
  194. package/src/styles/system/code-panel.css +82 -0
  195. package/src/styles/system/code-tabs.css +40 -0
  196. package/src/styles/system/code.css +8 -85
  197. package/src/styles/system/compare.css +7 -0
  198. package/src/styles/system/controls.css +10 -109
  199. package/src/styles/system/copy.css +32 -0
  200. package/src/styles/system/data.css +10 -134
  201. package/src/styles/system/dialog.css +16 -0
  202. package/src/styles/system/disclosure.css +19 -0
  203. package/src/styles/system/expand.css +11 -0
  204. package/src/styles/system/fields.css +25 -0
  205. package/src/styles/system/header-core.css +101 -0
  206. package/src/styles/system/hint.css +5 -0
  207. package/src/styles/system/index.css +13 -0
  208. package/src/styles/system/inline-code.css +4 -0
  209. package/src/styles/system/kbd.css +4 -0
  210. package/src/styles/system/logos.css +10 -0
  211. package/src/styles/system/menu.css +14 -0
  212. package/src/styles/system/metrics.css +22 -0
  213. package/src/styles/system/pagehead.css +13 -0
  214. package/src/styles/system/pager.css +13 -0
  215. package/src/styles/system/parameters.css +17 -0
  216. package/src/styles/system/prompt.css +7 -0
  217. package/src/styles/system/prose.css +4 -75
  218. package/src/styles/system/range.css +12 -0
  219. package/src/styles/system/reading.css +44 -0
  220. package/src/styles/system/scroll.css +6 -0
  221. package/src/styles/system/search-trigger.css +10 -0
  222. package/src/styles/system/segmented.css +22 -0
  223. package/src/styles/system/sheet.css +8 -0
  224. package/src/styles/system/shell.css +8 -102
  225. package/src/styles/system/sidebar.css +14 -0
  226. package/src/styles/system/source.css +5 -0
  227. package/src/styles/system/specimens.css +3 -0
  228. package/src/styles/system/stage.css +18 -0
  229. package/src/styles/system/steps.css +51 -0
  230. package/src/styles/system/surfaces.css +8 -104
  231. package/src/styles/system/table.css +23 -0
  232. package/src/styles/system/toc.css +59 -0
  233. package/src/styles/system/tooltip.css +6 -0
  234. package/src/styles/system/tray-code.css +6 -0
  235. package/src/styles/system/tray.css +20 -0
  236. package/src/styles/system/tree.css +15 -0
  237. package/src/styles/system/waterfall.css +14 -0
  238. package/src/virtual.d.ts +5 -1
  239. package/src/blog/article/language.ts +0 -29
@@ -1,20 +1,18 @@
1
1
  <script lang="ts" module>
2
- import type { DocSidebarProps } from './DocSidebar.svelte'
3
-
4
2
  export interface DocHeaderProps {
5
3
  class?: string
6
4
  /** See `Header`: overlays the page and slides away while reading down. */
7
5
  stickable?: boolean
8
6
  transitionAtTop?: boolean
9
- /** Chapters the compact menu lists. */
10
- documentNavigation?: DocSidebarProps['pageCategories']
11
- documentNavigationTitle?: string
12
7
  /** Accepted for section shells; the header always spans the page. */
13
8
  contained?: boolean
14
9
  }
15
10
  </script>
16
11
 
17
12
  <script lang="ts">
13
+ import '@master/internal-site/styles/interface.css'
14
+ import '@master/internal-site/styles/system/header-core.css'
15
+
18
16
  // `.app-wrapper` sets the homepage sections' column gutters; the homepage loads it through this header.
19
17
  import '../../styles/docs-shell/wrapper.css'
20
18
  import Header from './Header.svelte'
@@ -31,18 +29,17 @@
31
29
  import app from 'virtual:master-site/app'
32
30
  import { getSite } from '../site'
33
31
 
34
- let { class: className, stickable, transitionAtTop, documentNavigation, documentNavigationTitle }: DocHeaderProps = $props()
32
+ let { class: className, stickable, transitionAtTop }: DocHeaderProps = $props()
35
33
  const { t, locale, pathname, i18n } = getSite()
36
- const tw = locale === 'tw'
37
- const home = pathname === (tw ? '/tw' : '/')
34
+ const home = pathname === (locale === i18n.defaultLocale ? '/' : `/${locale}`)
38
35
  const headerCommunityNavs = app.header?.communityNavs ?? app.communityNavs ?? []
39
36
  const showLanguage = i18n.locales.length > 1
40
37
  const version = import.meta.env.PUBLIC_VERSION ? `v${import.meta.env.PUBLIC_VERSION}` : ''
41
38
  </script>
42
39
 
43
40
  <Header class={className} {stickable} {transitionAtTop}>
44
- <DocMenuButton class="ui-header-menu" {documentNavigation} {documentNavigationTitle} />
45
- <Link href="/" class="ui-header-brand" aria-label={`${app.name} ${tw ? '首頁' : 'home'}`} oncontextmenu={(event: MouseEvent) => {
41
+ <DocMenuButton class="ui-header-menu ui-header-control" />
42
+ <Link href="/" class="ui-header-brand" aria-label={`${app.name} ${t('home')}`} oncontextmenu={(event: MouseEvent) => {
46
43
  event.preventDefault()
47
44
  location.assign(app.brandURL)
48
45
  }}>
@@ -57,26 +54,25 @@
57
54
  {:else if version}
58
55
  <span class="ui-version">{version}</span>
59
56
  {/if}
60
- <nav class="ui-header-nav" aria-label={tw ? '主要導覽' : 'Main navigation'}>
57
+ <nav class="ui-header-nav" aria-label={t('Main navigation')}>
61
58
  {#each app.navs as { Icon: _Icon, fullName: _fullName, ...eachLink } (eachLink.name)}<HeaderNav {...eachLink}>
62
59
  {t(eachLink.name)}
63
60
  {#if eachLink.date && isDateWithinSevenDays(eachLink.date)}<small>{t('New')}</small>{/if}
64
61
  </HeaderNav>{/each}
65
62
  </nav>
66
63
  <div class="ui-header-end" data-home-controls={app.header?.searchOnHome ? 'full' : undefined}>
67
- <!-- Search leads the end group as a quiet pill: the glass and its shortcut. Homepages may opt into the same desktop search control. -->
68
- <SearchButton class="ui-header-search" data-compact={home && !app.header?.searchOnHome ? '' : undefined}>
69
- <IconSearch size={16} stroke={1.5} aria-hidden="true" />
64
+ <!-- Desktop keeps the search pill and shortcut; compact headers use a 44px icon target. -->
65
+ <SearchButton class="ui-header-control ui-header-search" data-compact={home && !app.header?.searchOnHome ? '' : undefined}>
66
+ <IconSearch size={18} stroke={1.5} aria-hidden="true" />
70
67
  <kbd class="ui-kbd" aria-hidden="true">⌘K</kbd>
71
68
  </SearchButton>
72
69
  {#each headerCommunityNavs as { Icon, disabled, fullName, ...eachLink } (eachLink.name)}
73
70
  <Link
74
71
  {...eachLink}
75
72
  aria-label={fullName || eachLink.name}
76
- class="ui-button"
73
+ class="ui-button ui-header-control"
77
74
  data-variant="quiet"
78
75
  data-shape="icon"
79
- data-size="sm"
80
76
  data-disabled={disabled || undefined}
81
77
  {disabled}
82
78
  >
@@ -87,7 +83,7 @@
87
83
  {/each}
88
84
  {#if showLanguage}
89
85
  {#if headerCommunityNavs.length}<span class="ui-header-divider" aria-hidden="true"></span>{/if}
90
- <LanguageButton />
86
+ <LanguageButton class="ui-header-control" />
91
87
  {/if}
92
88
  </div>
93
89
  </Header>
@@ -1,4 +1,6 @@
1
1
  ---
2
+ import { siteOf } from '@master/internal-site/astro/site-context.ts'
3
+ const { t } = siteOf(Astro)
2
4
  import '../../styles/docs-shell/prose.css'
3
5
  import resolveHeading from '../utils/resolve-heading'
4
6
 
@@ -23,6 +25,6 @@ const title = typeof heading.title === 'string' ? heading.title : text
23
25
  ---
24
26
 
25
27
  <Element {...props} id={heading.id ?? id} class:list={[className, heading.className]} title={title || undefined} data-doc-heading="">
26
- <a class="ui-anchor" href={'#' + (heading.id ?? id)} aria-label={`Link to section: ${title}`}>#</a>
28
+ <a class="ui-anchor" href={'#' + (heading.id ?? id)} aria-label={t('Link to section: {title}').replace('{title}', title)}>#</a>
27
29
  <Fragment set:html={plain ? html.replace(' [sr-only]', '') : html} />
28
30
  </Element>
@@ -1,96 +1,161 @@
1
1
  <script lang="ts" module>
2
2
  import type { Attachment } from 'svelte/attachments'
3
3
 
4
- /** The sheet lives at the end of the body, outside the header that opens it. */
5
- const portal: Attachment<HTMLElement> = (node) => {
4
+ /** Keep the modal outside the header's transforms and stacking context. */
5
+ const portal: Attachment<HTMLDialogElement> = (node) => {
6
6
  document.body.append(node)
7
- return () => node.remove()
7
+ return () => { node.close(); node.remove() }
8
8
  }
9
9
  </script>
10
10
 
11
11
  <script lang="ts">
12
+ import '@master/internal-site/styles/interface.css'
13
+ import '@master/internal-site/styles/system/dialog.css'
14
+ import '@master/internal-site/styles/system/header-core.css'
15
+
12
16
  import '../../styles/docs-shell/menu.css'
17
+ import { onMount } from 'svelte'
13
18
  import clsx from 'clsx'
14
19
  import Link from './Link.svelte'
15
- import DocSidebar, { type DocSidebarProps } from './DocSidebar.svelte'
16
20
  import SearchButton from './SearchButton.svelte'
17
21
  import IconArrowUpRight from '@tabler/icons-svelte-runes/icons/arrow-up-right'
18
- import IconMenu2 from '@tabler/icons-svelte-runes/icons/menu-2'
19
- import IconX from '@tabler/icons-svelte-runes/icons/x'
22
+ import IconSearch from '@tabler/icons-svelte-runes/icons/search'
23
+ import IconMenu from '@tabler/icons-svelte-runes/icons/menu'
20
24
  import ThemeSelect from './ThemeSelect.svelte'
21
25
  import DocVersionSelect from './DocVersionSelect.svelte'
22
26
  import LanguageSelect from './LanguageSelect.svelte'
27
+ import { openSearch } from '../contexts/search'
23
28
  import app from 'virtual:master-site/app'
24
29
  import { getSite } from '../site'
25
30
 
26
- interface Props {
27
- class?: string
28
- documentNavigation?: DocSidebarProps['pageCategories']
29
- documentNavigationTitle?: string
30
- }
31
+ interface Props { class?: string }
31
32
 
32
- /** The compact header's menu: site sections, the section's chapters, community links and preferences in one sheet. */
33
- let { class: className, documentNavigation, documentNavigationTitle }: Props = $props()
33
+ /** Primary destinations, with community and preferences kept in a quiet footer. */
34
+ let { class: className }: Props = $props()
34
35
  let opened = $state(false)
35
36
  const id = $props.id()
36
- let dialog = $state<HTMLDialogElement>()
37
- let trigger = $state<HTMLButtonElement>()
37
+ let dialog: HTMLDialogElement
38
+ let trigger: HTMLButtonElement
39
+ let closing: ReturnType<typeof setTimeout> | undefined
38
40
  const { t, locale, i18n } = getSite()
39
- const tw = locale === 'tw'
41
+
42
+ function finishClose(restoreFocus = true) {
43
+ clearTimeout(closing)
44
+ closing = undefined
45
+ opened = false
46
+ dialog.close()
47
+ if (restoreFocus) {
48
+ const target = trigger.getClientRects().length ? trigger : trigger.closest('header')?.querySelector<HTMLElement>('.ui-header-brand')
49
+ target?.focus({ preventScroll: true })
50
+ }
51
+ }
52
+
53
+ function open() {
54
+ clearTimeout(closing)
55
+ closing = undefined
56
+ if (!dialog.open) {
57
+ dialog.showModal()
58
+ dialog.scrollTop = 0
59
+ // Establish the closed style before changing the target; CSS can reverse an interrupted transition.
60
+ getComputedStyle(dialog).opacity
61
+ }
62
+ opened = true
63
+ }
40
64
 
41
65
  function close() {
42
- dialog?.close()
43
66
  opened = false
44
- trigger?.focus({ preventScroll: true })
67
+ clearTimeout(closing)
68
+ if (matchMedia('(prefers-reduced-motion: reduce)').matches) finishClose()
69
+ else closing = setTimeout(finishClose, 220)
45
70
  }
46
71
 
47
- $effect(() => {
48
- if (!opened) return
49
- const element = dialog
50
- if (element && !element.open) element.showModal()
72
+ function transitionEnd(event: TransitionEvent) {
73
+ if (event.target === dialog && event.propertyName === 'opacity' && !opened) finishClose()
74
+ }
75
+
76
+ function search(event: Event) {
77
+ event.preventDefault()
78
+ const searchTrigger = trigger.closest('header')?.querySelector<HTMLElement>('.ui-header-search')
79
+ const target = searchTrigger?.getClientRects().length ? searchTrigger : trigger
80
+ finishClose(false)
81
+ openSearch(target)
82
+ }
83
+
84
+ function keydown(event: KeyboardEvent) {
85
+ if (event.key === 'Tab') {
86
+ const controls = Array.from(dialog.querySelectorAll<HTMLElement>('a[href], button:not(:disabled), select:not(:disabled)'))
87
+ .filter(element => element.getClientRects().length)
88
+ const first = controls[0]
89
+ const last = controls.at(-1)
90
+ if (event.shiftKey && document.activeElement === first) { event.preventDefault(); last?.focus() }
91
+ else if (!event.shiftKey && document.activeElement === last) { event.preventDefault(); first?.focus() }
92
+ }
93
+ if (!event.isComposing && (event.metaKey || event.ctrlKey) && event.key.toLowerCase() === 'k') {
94
+ event.stopPropagation()
95
+ search(event)
96
+ }
97
+ }
98
+
99
+ onMount(() => {
51
100
  const wide = matchMedia('(width >= 64rem)')
52
- const resize = () => { if (wide.matches) close() }
101
+ const motion = matchMedia('(prefers-reduced-motion: reduce)')
102
+ const resize = () => { if (wide.matches && dialog.open) finishClose() }
103
+ const reduceMotion = () => { if (motion.matches && closing) finishClose() }
53
104
  wide.addEventListener('change', resize)
54
- return () => wide.removeEventListener('change', resize)
105
+ motion.addEventListener('change', reduceMotion)
106
+ return () => {
107
+ clearTimeout(closing)
108
+ wide.removeEventListener('change', resize)
109
+ motion.removeEventListener('change', reduceMotion)
110
+ }
55
111
  })
56
112
  </script>
57
113
 
58
- <button bind:this={trigger} type="button" class={clsx('ui-button', className)} data-variant="quiet" data-shape="icon"
59
- aria-label={t('Menu')} aria-expanded={opened} aria-haspopup="dialog" aria-controls={opened ? id : undefined}
60
- onclick={() => { opened = !opened }}>
61
- <IconMenu2 size={20} stroke={1.5} aria-hidden="true" />
114
+ {#snippet lines()}
115
+ <IconMenu class="ui-menu-glyph" size={18} stroke={1.5} data-open={opened} aria-hidden="true" />
116
+ {/snippet}
117
+
118
+ <button bind:this={trigger} type="button" class={clsx('ui-button ui-menu-toggle', className)} data-variant="quiet" data-shape="icon"
119
+ aria-label={t('Menu')} aria-expanded={opened} aria-haspopup="dialog" aria-controls={id} onclick={open}>
120
+ {@render lines()}
62
121
  </button>
63
- {#if opened}
64
- <dialog bind:this={dialog} {@attach portal} {id} class="ui-dialog" data-variant="sheet" aria-labelledby={`${id}-title`} oncancel={event => { event.preventDefault(); close() }}>
65
- <div class="ui-dialog-bar">
66
- <button type="button" class="ui-button" data-variant="quiet" data-shape="icon" onclick={close} aria-label={tw ? '關閉選單' : 'Close menu'}><IconX size={20} stroke={1.5} aria-hidden="true" /></button>
67
- <Link href="/" class="ui-header-brand" onclick={close} aria-label={`${app.name} ${tw ? '首頁' : 'home'}`}><app.Logotype style="height: 20px; width: auto" aria-hidden="true" /></Link>
68
- </div>
69
- <div class="ui-dialog-body">
70
- <h2 class="sr-only" id={`${id}-title`}>{tw ? '網站導覽' : 'Navigation'}</h2>
71
- <SearchButton class="ui-search-trigger" />
72
- <nav class="ui-nav-group" aria-label={tw ? '主要導覽' : 'Main navigation'}>
73
- {#each app.navs as { Icon, disabled, fullName, ...link } (link.name)}<Link class="ui-nav-link" current="true" ambiguous {...link} {disabled} onclick={close}>
74
- {#if Icon}<Icon size={18} stroke={1.5} aria-hidden="true" />{/if}{t(fullName || link.name)}
75
- {#if link.href?.startsWith('http')}<IconArrowUpRight size={14} stroke={1.5} aria-hidden="true" />{/if}
76
- </Link>{/each}
77
- </nav>
78
- {#if documentNavigation?.length}<details class="ui-disclosure" data-variant="rule" open>
79
- <summary>{t(documentNavigationTitle || 'Documentation')}<span class="ui-disclosure-meta">{tw ? '文件章節' : 'Chapters'}</span></summary>
80
- <DocSidebar embedded includeNestedPages pageCategories={documentNavigation} onNavigate={close} />
81
- </details>{/if}
82
- {#if app.communityNavs?.length}<nav class="ui-nav-group" aria-labelledby={`${id}-community`}>
83
- <h4 id={`${id}-community`}>{t('Community')}</h4>
84
- {#each app.communityNavs as { Icon, disabled, fullName, ...link } (link.name)}<Link class="ui-nav-link" {...link} {disabled} onclick={close}>
85
- {#if Icon}<Icon size={18} stroke={1.5} aria-hidden="true" />{/if}{t(fullName || link.name)}<IconArrowUpRight size={14} stroke={1.5} aria-hidden="true" />
86
- </Link>{/each}
87
- </nav>{/if}
88
- <section class="ui-dialog-fields" aria-labelledby={`${id}-system`}>
89
- <h4 id={`${id}-system`}>{t('System')}</h4>
90
- {#if app.versions.length > 0}<label class="ui-field">{t('Version')}<DocVersionSelect aria-label={t('Version')} data-variant={undefined} /></label>{/if}
91
- {#if i18n.locales.length > 1}<label class="ui-field">{t('Language')}<LanguageSelect aria-label={t('Language')} data-variant={undefined} /></label>{/if}
92
- <label class="ui-field">{t('Theme')}<ThemeSelect aria-label={t('Theme')} data-variant={undefined} /></label>
93
- </section>
122
+ <dialog bind:this={dialog} {@attach portal} {id} class="ui-dialog ui-mobile-menu" data-variant="sheet" data-open={opened}
123
+ aria-labelledby={`${id}-title`} oncancel={event => { event.preventDefault(); close() }} ontransitionend={transitionEnd}
124
+ onkeydown={keydown} onclose={() => { if (!dialog.open) { opened = false; clearTimeout(closing) } }}>
125
+ <div class="ui-mobile-menu-bar">
126
+ <button type="button" class="ui-button ui-header-control ui-menu-toggle" data-variant="quiet" data-shape="icon"
127
+ onclick={() => opened ? close() : open()} aria-label={opened ? t('Close menu') : t('Menu')} aria-expanded={opened} aria-controls={id}>
128
+ {@render lines()}
129
+ </button>
130
+ <Link href="/" class="ui-header-brand" onclick={() => finishClose(false)} aria-label={`${app.name} ${t('home')}`}><app.Logotype style="height: 20px; width: auto" aria-hidden="true" /></Link>
131
+ <SearchButton class="ui-button ui-header-control ui-menu-search" data-variant="quiet" data-shape="icon" onclick={search}><IconSearch size={18} stroke={1.5} aria-hidden="true" /></SearchButton>
132
+ </div>
133
+ <div class="ui-mobile-menu-body">
134
+ <h2 class="sr-only" id={`${id}-title`}>{t('Navigation')}</h2>
135
+ <nav class="ui-mobile-menu-nav" aria-label={t('Main navigation')}>
136
+ {#each app.navs as { Icon: _Icon, disabled, fullName, ...link }, index (link.name)}
137
+ <Link class="ui-mobile-menu-link" current="true" ambiguous {...link} {disabled} style={`--menu-order: ${index}`} onclick={() => finishClose(false)}>
138
+ <span>{t(fullName || link.name)}</span>
139
+ {#if link.href?.startsWith('http')}<IconArrowUpRight size={16} stroke={1.5} aria-hidden="true" />{/if}
140
+ </Link>
141
+ {/each}
142
+ </nav>
143
+ <div class="ui-mobile-menu-footer">
144
+ {#if app.communityNavs?.length}
145
+ <nav class="ui-mobile-menu-community" aria-label={t('Community')}>
146
+ {#each app.communityNavs as { Icon, disabled, fullName, ...link } (link.name)}
147
+ <Link {...link} {disabled} aria-label={fullName || link.name} title={fullName || link.name} onclick={() => finishClose(false)}>
148
+ {#if Icon}<Icon size={20} stroke={1.5} aria-hidden="true" />{:else}{t(fullName || link.name)}{/if}
149
+ {#if Icon && link.href?.startsWith('http')}<IconArrowUpRight class="ui-menu-external" size={10} stroke={1.5} aria-hidden="true" />{/if}
150
+ </Link>
151
+ {/each}
152
+ </nav>
153
+ {/if}
154
+ <div class="ui-mobile-menu-preferences">
155
+ <ThemeSelect aria-label={t('Theme')} data-variant={undefined} />
156
+ {#if i18n.locales.length > 1}<LanguageSelect aria-label={t('Language')} data-variant={undefined} />{/if}
157
+ {#if app.versions.length > 0}<DocVersionSelect aria-label={t('Version')} data-variant={undefined} />{/if}
158
+ </div>
94
159
  </div>
95
- </dialog>
96
- {/if}
160
+ </div>
161
+ </dialog>
@@ -14,13 +14,14 @@
14
14
  </script>
15
15
 
16
16
  <script lang="ts">
17
+ import '@master/internal-site/styles/system/sidebar.css'
18
+
17
19
  import Link from './Link.svelte'
18
20
  import { getSite } from '../site'
19
21
 
20
22
  /** The documentation sidebar: one navigation group per category; the page being read inks a bar on the guide. Search lives in the header. */
21
23
  let { pageCategories, includeNestedPages = false, embedded = false, onNavigate }: DocSidebarProps = $props()
22
24
  const { t, locale } = getSite()
23
- const tw = locale === 'tw'
24
25
  const groups = $derived(pageCategories
25
26
  .filter((eachPageCategory: any) => eachPageCategory.name !== 'Overview')
26
27
  .map((eachPageCategory: any) => ({
@@ -56,7 +57,7 @@
56
57
  {#if embedded}
57
58
  <div class="ui-sidebar">{@render sidebarGroups()}</div>
58
59
  {:else}
59
- <aside id="sidebar" aria-label={tw ? '文件導覽' : 'Documentation navigation'} class="ui-sidebar">
60
+ <aside id="sidebar" aria-label={t('Documentation navigation')} class="ui-sidebar">
60
61
  {@render sidebarGroups()}
61
62
  </aside>
62
63
  {/if}
@@ -1,4 +1,6 @@
1
1
  <script lang="ts">
2
+ import '@master/internal-site/styles/system/fields.css'
3
+
2
4
  import type { HTMLSelectAttributes } from 'svelte/elements'
3
5
  import clsx from 'clsx'
4
6
  import app from 'virtual:master-site/app'
@@ -1,5 +1,5 @@
1
1
  ---
2
- import '@master/internal-site/styles/system/data.css'
2
+ import '@master/internal-site/styles/system/index.css'
3
3
  import Link from '@master/internal-site/components/Link.svelte'
4
4
  import DocumentIdentifier from '@master/internal-site/components/DocumentIdentifier.astro'
5
5
  import type { DocumentAPIEntry } from '@master/internal-site/components/document-types.ts'
@@ -1,5 +1,5 @@
1
1
  ---
2
- import '@master/internal-site/styles/system/data.css'
2
+ import '@master/internal-site/styles/system/index.css'
3
3
  import Link from '@master/internal-site/components/Link.svelte'
4
4
  import RenderNode from '@master/internal-site/components/RenderNode.astro'
5
5
  import type { DocumentChoice } from '@master/internal-site/components/document-types.ts'
@@ -1,5 +1,7 @@
1
1
  ---
2
- import '@master/internal-site/styles/system/data.css'
2
+ import '@master/internal-site/styles/system/callout.css'
3
+ import '@master/internal-site/styles/system/tray.css'
4
+ import '@master/internal-site/styles/system/tray-code.css'
3
5
  import IconAlertTriangle from '@tabler/icons-svelte-runes/icons/alert-triangle'
4
6
  import IconCircleX from '@tabler/icons-svelte-runes/icons/circle-x'
5
7
  import RenderNode from '@master/internal-site/components/RenderNode.astro'
@@ -1,5 +1,7 @@
1
1
  ---
2
- import '@master/internal-site/styles/system/data.css'
2
+ import { siteOf } from '../../astro/site-context'
3
+ const { t } = siteOf(Astro)
4
+ import '@master/internal-site/styles/system/table.css'
3
5
 
4
6
  interface Props {
5
7
  label?: string
@@ -12,7 +14,7 @@ const { label = 'Syntax', rows } = Astro.props
12
14
 
13
15
  {/* The table's narrow overflow region must be focusable for native keyboard scrolling. */}
14
16
  <div class="ui-table" data-variant="lookup" role="region" aria-label={`${label} and CSS`} tabindex="0"><table>
15
- <thead><tr><th scope="col">{label}</th><th scope="col">CSS</th></tr></thead>
17
+ <thead><tr><th scope="col">{t(label)}</th><th scope="col">CSS</th></tr></thead>
16
18
  <tbody>{rows.map(({ syntax, css }) => <tr>
17
19
  <th scope="row"><code>{syntax}</code></th><td><code>{css}</code></td>
18
20
  </tr>)}</tbody>
@@ -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 { onMount } from 'svelte'
3
6
  import IconCheck from '@tabler/icons-svelte-runes/icons/check'
4
7
  import IconCopy from '@tabler/icons-svelte-runes/icons/copy'
@@ -1,4 +1,6 @@
1
1
  ---
2
+ import '@master/internal-site/styles/documents.css'
3
+ import '@master/internal-site/styles/system/disclosure.css'
2
4
  interface Props {
3
5
  title: string
4
6
  open?: boolean
@@ -1,4 +1,7 @@
1
1
  ---
2
+ import '@master/internal-site/styles/system/tray.css'
3
+ import '@master/internal-site/styles/system/tray-code.css'
4
+ import '@master/internal-site/styles/system/tree.css'
2
5
  import IconFile from '@tabler/icons-svelte-runes/icons/file'
3
6
  import IconFolder from '@tabler/icons-svelte-runes/icons/folder'
4
7
  import type { DocumentFileEntry, DocumentFileTreeProps } from '@master/internal-site/components/document-types.ts'
@@ -1,5 +1,8 @@
1
1
  ---
2
- import '@master/internal-site/styles/system/data.css'
2
+ import '@master/internal-site/styles/system/stage.css'
3
+ import '@master/internal-site/styles/system/steps.css'
4
+ import '@master/internal-site/styles/system/tray.css'
5
+ import '@master/internal-site/styles/system/tray-code.css'
3
6
  import type { DocumentFlowProps } from '@master/internal-site/components/document-types.ts'
4
7
 
5
8
  export type { DocumentFlowStep, DocumentFlowProps } from '@master/internal-site/components/document-types.ts'
@@ -1,6 +1,10 @@
1
1
  ---
2
+ import { siteOf } from '../../astro/site-context'
3
+ const { t } = siteOf(Astro)
4
+ import '@master/internal-site/styles/system/disclosure.css'
5
+ import '@master/internal-site/styles/system/tray.css'
6
+ import '@master/internal-site/styles/system/tray-code.css'
2
7
  import '@master/internal-site/styles/documentation-illustration.css'
3
- import IconArrowsMaximize from '@tabler/icons-svelte-runes/icons/arrows-maximize'
4
8
  import Image from '@master/internal-site/components/Image.svelte'
5
9
  import type { IllustrationImages } from '../types/IllustrationImages'
6
10
 
@@ -11,23 +15,15 @@ interface Props {
11
15
  alt: string
12
16
  images: IllustrationImages
13
17
  caption: string
14
- fullSize?: boolean
15
18
  }
16
19
 
17
20
  /** A static figure with one accessible image and an independent text description. */
18
- const { title, alt, images, caption, fullSize = false } = Astro.props
21
+ const { title, alt, images, caption } = Astro.props
19
22
  ---
20
23
 
21
- <figure class="ui-tray" aria-label={title} data-illustration-expandable={fullSize || undefined}>
24
+ <figure class="ui-tray" aria-label={title}>
22
25
  <figcaption class="ui-tray-head">
23
26
  <p class="ui-tray-title">{title}</p>
24
- {fullSize && (['light', 'dark'] as const).map(scheme => <a
25
- class="document-illustration-expand ui-button"
26
- data-variant="quiet" data-shape="icon" data-size="sm" data-scheme={scheme}
27
- href={images[scheme].src} target="_blank" rel="noopener noreferrer"
28
- aria-label={`View full-size illustration: ${title} (opens in a new tab)`}
29
- title="View full-size illustration (opens in a new tab)"
30
- ><IconArrowsMaximize aria-hidden="true" /></a>)}
31
27
  </figcaption>
32
28
  <div class="document-illustration" role="img" aria-label={alt}>
33
29
  {(['light', 'dark'] as const).map(scheme => <Image
@@ -40,7 +36,7 @@ const { title, alt, images, caption, fullSize = false } = Astro.props
40
36
  </div>
41
37
  <p class="ui-tray-caption">{caption}</p>
42
38
  <details class="ui-disclosure" data-variant="text-description">
43
- <summary>Text description</summary>
39
+ <summary>{t('Text description')}</summary>
44
40
  <div class="ui-disclosure-body ui-tray-caption"><slot /></div>
45
41
  </details>
46
42
  </figure>
@@ -1,5 +1,7 @@
1
1
  ---
2
- import '@master/internal-site/styles/system/data.css'
2
+ import '@master/internal-site/styles/system/disclosure.css'
3
+ import { siteOf } from '../../astro/site-context'
4
+ const { t } = siteOf(Astro)
3
5
 
4
6
  interface Props {
5
7
  keys: string[]
@@ -11,12 +13,12 @@ const { keys, previewCount = keys.length } = Astro.props
11
13
  const lists = [keys.slice(0, previewCount), keys.slice(previewCount)]
12
14
  ---
13
15
 
14
- <ul aria-label="Utility keys">
16
+ <ul aria-label={t('Utility keys')}>
15
17
  {lists[0].map(key => <li><code>{key}</code></li>)}
16
18
  </ul>
17
19
  {keys.length > previewCount && <details class="ui-disclosure">
18
- <summary>Show {keys.length - previewCount} more keys</summary>
19
- <ul aria-label="Utility keys">
20
+ <summary>{t('Show {count} more keys').replace('{count}', String(keys.length - previewCount))}</summary>
21
+ <ul aria-label={t('Utility keys')}>
20
22
  {lists[1].map(key => <li><code>{key}</code></li>)}
21
23
  </ul>
22
24
  </details>}
@@ -1,6 +1,8 @@
1
1
  ---
2
- import '@master/internal-site/styles/system/data.css'
2
+ import '@master/internal-site/styles/system/table.css'
3
3
  import DocumentKeyList from '@master/internal-site/components/DocumentKeyList.astro'
4
+ import { siteOf } from '../../astro/site-context'
5
+ const { t } = siteOf(Astro)
4
6
 
5
7
  interface Props {
6
8
  rows: { namespace: string, consumers: string[] }[]
@@ -11,8 +13,8 @@ const { rows } = Astro.props
11
13
  ---
12
14
 
13
15
  {/* The table's narrow overflow region must be focusable for native keyboard scrolling. */}
14
- <div class="ui-table" data-variant="lookup" role="region" aria-label="Namespace consumers" tabindex="0"><table>
15
- <thead><tr><th scope="col">Namespace</th><th scope="col">Consumers</th></tr></thead>
16
+ <div class="ui-table" data-variant="lookup" role="region" aria-label={t('Namespace consumers')} tabindex="0"><table>
17
+ <thead><tr><th scope="col">{t('Namespace')}</th><th scope="col">{t('Consumers')}</th></tr></thead>
16
18
  <tbody>{rows.map(({ namespace, consumers }) => <tr>
17
19
  <th scope="row"><code>{namespace}-*</code></th>
18
20
  <td><DocumentKeyList keys={consumers} previewCount={6} /></td>
@@ -1,5 +1,4 @@
1
1
  ---
2
- import '@master/internal-site/styles/system/data.css'
3
2
  import DocumentIdentifier from '@master/internal-site/components/DocumentIdentifier.astro'
4
3
 
5
4
  interface Props {
@@ -1,5 +1,5 @@
1
1
  ---
2
- import '@master/internal-site/styles/system/data.css'
2
+ import '@master/internal-site/styles/system/parameters.css'
3
3
 
4
4
  interface Props {
5
5
  label: string
@@ -1,5 +1,6 @@
1
1
  ---
2
- import '@master/internal-site/styles/system/data.css'
2
+ import { siteOf } from '../../astro/site-context'
3
+ const { t } = siteOf(Astro)
3
4
  import RenderNode from '@master/internal-site/components/RenderNode.astro'
4
5
  import DocumentOptionEntry from '@master/internal-site/components/DocumentOptionEntry.astro'
5
6
  import DocumentOptionList from '@master/internal-site/components/DocumentOptionList.astro'
@@ -17,7 +18,7 @@ const { label, options } = Astro.props
17
18
 
18
19
  <DocumentOptionList label={label}>
19
20
  {options.map(option => <DocumentOptionEntry name={option.name}>
20
- {option.defaultValue !== undefined && <small>Default <code>{option.defaultValue}</code></small>}
21
+ {option.defaultValue !== undefined && <small>{t('Default')} <code>{option.defaultValue}</code></small>}
21
22
  <p><RenderNode node={option.description} /></p>
22
23
  </DocumentOptionEntry>)}
23
24
  </DocumentOptionList>
@@ -1,5 +1,5 @@
1
1
  ---
2
- import '@master/internal-site/styles/system/data.css'
2
+ import '@master/internal-site/styles/system/parameters.css'
3
3
  import '@master/internal-site/styles/system/specimens.css'
4
4
  import RenderNode from '@master/internal-site/components/RenderNode.astro'
5
5
  import DocumentIdentifier from '@master/internal-site/components/DocumentIdentifier.astro'
@@ -1,4 +1,6 @@
1
1
  ---
2
+ import '@master/internal-site/styles/system/code-panel.css'
3
+ import '@master/internal-site/styles/system/prompt.css'
2
4
  import DocumentCopyButton from '@master/internal-site/components/DocumentCopyButton.svelte'
3
5
  import type { DocumentPromptProps } from '@master/internal-site/components/document-types.ts'
4
6
 
@@ -1,5 +1,5 @@
1
1
  ---
2
- import '@master/internal-site/styles/system/data.css'
2
+ import '@master/internal-site/styles/system/parameters.css'
3
3
  import type { DocumentValueRow } from '@master/internal-site/components/document-types.ts'
4
4
 
5
5
  export type { DocumentValueRow } from '@master/internal-site/components/document-types.ts'