@nanisoft/prism-ui 0.10.1 → 0.13.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 (334) hide show
  1. package/LICENSE +21 -21
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/blocks/app-shell-01/app-shell.js +4 -4
  4. package/dist/blocks/app-shell-01/index.d.ts +2 -2
  5. package/dist/blocks/app-shell-01/index.js +1 -1
  6. package/dist/blocks/auth-form-01/auth-form.d.ts +11 -1
  7. package/dist/blocks/auth-form-01/auth-form.d.ts.map +1 -1
  8. package/dist/blocks/auth-form-01/auth-form.js +11 -8
  9. package/dist/blocks/auth-form-01/index.d.ts +2 -2
  10. package/dist/blocks/auth-form-01/index.js +1 -1
  11. package/dist/blocks/cta-01/cta.d.ts +26 -21
  12. package/dist/blocks/cta-01/cta.d.ts.map +1 -1
  13. package/dist/blocks/cta-01/cta.js +2 -2
  14. package/dist/blocks/cta-01/index.d.ts +2 -2
  15. package/dist/blocks/cta-01/index.js +1 -1
  16. package/dist/blocks/data-table-01/data-table.js +7 -7
  17. package/dist/blocks/data-table-01/index.d.ts +2 -2
  18. package/dist/blocks/data-table-01/index.js +1 -1
  19. package/dist/blocks/empty-state-01/empty-state.d.ts +143 -0
  20. package/dist/blocks/empty-state-01/empty-state.d.ts.map +1 -0
  21. package/dist/blocks/empty-state-01/empty-state.js +104 -0
  22. package/dist/blocks/empty-state-01/index.d.ts +3 -0
  23. package/dist/blocks/empty-state-01/index.d.ts.map +1 -0
  24. package/dist/blocks/empty-state-01/index.js +1 -0
  25. package/dist/blocks/feature-grid-01/feature-grid.d.ts +28 -1
  26. package/dist/blocks/feature-grid-01/feature-grid.d.ts.map +1 -1
  27. package/dist/blocks/feature-grid-01/feature-grid.js +34 -3
  28. package/dist/blocks/feature-grid-01/index.d.ts +2 -2
  29. package/dist/blocks/feature-grid-01/index.js +1 -1
  30. package/dist/blocks/hero-01/hero.d.ts +49 -17
  31. package/dist/blocks/hero-01/hero.d.ts.map +1 -1
  32. package/dist/blocks/hero-01/hero.js +14 -9
  33. package/dist/blocks/hero-01/index.d.ts +2 -1
  34. package/dist/blocks/hero-01/index.d.ts.map +1 -1
  35. package/dist/blocks/hero-01/index.js +1 -1
  36. package/dist/blocks/index.d.ts +20 -20
  37. package/dist/blocks/index.js +19 -19
  38. package/dist/blocks/instrument-panel-01/index.d.ts +2 -2
  39. package/dist/blocks/instrument-panel-01/index.js +1 -1
  40. package/dist/blocks/instrument-panel-01/instrument-panel.js +1 -1
  41. package/dist/blocks/logo-strip-01/index.d.ts +2 -2
  42. package/dist/blocks/logo-strip-01/index.js +1 -1
  43. package/dist/blocks/logo-strip-01/logo-strip.d.ts +1 -1
  44. package/dist/blocks/logo-strip-01/logo-strip.js +2 -2
  45. package/dist/blocks/note-grid-01/index.d.ts +2 -2
  46. package/dist/blocks/note-grid-01/index.js +1 -1
  47. package/dist/blocks/note-grid-01/note-grid.d.ts +1 -1
  48. package/dist/blocks/note-grid-01/note-grid.js +1 -1
  49. package/dist/blocks/page-header-01/index.d.ts +2 -2
  50. package/dist/blocks/page-header-01/index.js +1 -1
  51. package/dist/blocks/page-header-01/page-header.d.ts +1 -1
  52. package/dist/blocks/page-header-01/page-header.js +4 -4
  53. package/dist/blocks/pricing-01/index.d.ts +1 -1
  54. package/dist/blocks/pricing-01/index.js +1 -1
  55. package/dist/blocks/pricing-01/pricing.d.ts +8 -1
  56. package/dist/blocks/pricing-01/pricing.d.ts.map +1 -1
  57. package/dist/blocks/pricing-01/pricing.js +15 -5
  58. package/dist/blocks/process-flow-01/index.d.ts +3 -0
  59. package/dist/blocks/process-flow-01/index.d.ts.map +1 -0
  60. package/dist/blocks/process-flow-01/index.js +1 -0
  61. package/dist/blocks/process-flow-01/process-flow.d.ts +118 -0
  62. package/dist/blocks/process-flow-01/process-flow.d.ts.map +1 -0
  63. package/dist/blocks/process-flow-01/process-flow.js +71 -0
  64. package/dist/blocks/process-rail-01/index.d.ts +2 -2
  65. package/dist/blocks/process-rail-01/index.js +1 -1
  66. package/dist/blocks/process-rail-01/process-rail.d.ts +1 -1
  67. package/dist/blocks/process-rail-01/process-rail.js +2 -2
  68. package/dist/blocks/product-grid-01/index.d.ts +2 -2
  69. package/dist/blocks/product-grid-01/index.js +1 -1
  70. package/dist/blocks/product-grid-01/product-grid.d.ts +37 -5
  71. package/dist/blocks/product-grid-01/product-grid.d.ts.map +1 -1
  72. package/dist/blocks/product-grid-01/product-grid.js +20 -6
  73. package/dist/blocks/run-console-01/index.d.ts +3 -0
  74. package/dist/blocks/run-console-01/index.d.ts.map +1 -0
  75. package/dist/blocks/run-console-01/index.js +1 -0
  76. package/dist/blocks/run-console-01/run-console.d.ts +111 -0
  77. package/dist/blocks/run-console-01/run-console.d.ts.map +1 -0
  78. package/dist/blocks/run-console-01/run-console.js +48 -0
  79. package/dist/blocks/settings-panel-01/index.d.ts +2 -2
  80. package/dist/blocks/settings-panel-01/index.js +1 -1
  81. package/dist/blocks/settings-panel-01/settings-panel.d.ts +11 -1
  82. package/dist/blocks/settings-panel-01/settings-panel.d.ts.map +1 -1
  83. package/dist/blocks/settings-panel-01/settings-panel.js +15 -10
  84. package/dist/blocks/site-footer/index.d.ts +2 -2
  85. package/dist/blocks/site-footer/index.js +1 -1
  86. package/dist/blocks/site-footer/site-footer.d.ts +1 -1
  87. package/dist/blocks/site-footer/site-footer.js +2 -2
  88. package/dist/blocks/site-header/index.d.ts +2 -2
  89. package/dist/blocks/site-header/index.js +1 -1
  90. package/dist/blocks/site-header/site-header.d.ts +2 -2
  91. package/dist/blocks/site-header/site-header.js +3 -3
  92. package/dist/blocks/site-navbar/index.d.ts +3 -0
  93. package/dist/blocks/site-navbar/index.d.ts.map +1 -0
  94. package/dist/blocks/site-navbar/index.js +1 -0
  95. package/dist/blocks/site-navbar/mobile-nav.d.ts +48 -0
  96. package/dist/blocks/site-navbar/mobile-nav.d.ts.map +1 -0
  97. package/dist/blocks/site-navbar/mobile-nav.js +35 -0
  98. package/dist/blocks/site-navbar/mode-toggle.d.ts +39 -0
  99. package/dist/blocks/site-navbar/mode-toggle.d.ts.map +1 -0
  100. package/dist/blocks/site-navbar/mode-toggle.js +39 -0
  101. package/dist/blocks/site-navbar/navbar-controls.d.ts +79 -0
  102. package/dist/blocks/site-navbar/navbar-controls.d.ts.map +1 -0
  103. package/dist/blocks/site-navbar/navbar-controls.js +40 -0
  104. package/dist/blocks/site-navbar/search-entry.d.ts +29 -0
  105. package/dist/blocks/site-navbar/search-entry.d.ts.map +1 -0
  106. package/dist/blocks/site-navbar/search-entry.js +52 -0
  107. package/dist/blocks/site-navbar/site-navbar.d.ts +212 -0
  108. package/dist/blocks/site-navbar/site-navbar.d.ts.map +1 -0
  109. package/dist/blocks/site-navbar/site-navbar.js +61 -0
  110. package/dist/blocks/site-navbar/sites-menu.d.ts +40 -0
  111. package/dist/blocks/site-navbar/sites-menu.d.ts.map +1 -0
  112. package/dist/blocks/site-navbar/sites-menu.js +48 -0
  113. package/dist/blocks/site-navbar/theme-menu.d.ts +47 -0
  114. package/dist/blocks/site-navbar/theme-menu.d.ts.map +1 -0
  115. package/dist/blocks/site-navbar/theme-menu.js +55 -0
  116. package/dist/blocks/stack-grid-01/index.d.ts +2 -2
  117. package/dist/blocks/stack-grid-01/index.js +1 -1
  118. package/dist/blocks/stack-grid-01/stack-grid.d.ts +42 -11
  119. package/dist/blocks/stack-grid-01/stack-grid.d.ts.map +1 -1
  120. package/dist/blocks/stack-grid-01/stack-grid.js +15 -7
  121. package/dist/blocks/stats-01/index.d.ts +9 -1
  122. package/dist/blocks/stats-01/index.d.ts.map +1 -1
  123. package/dist/blocks/stats-01/index.js +8 -1
  124. package/dist/blocks/stats-01/stats.d.ts +1 -1
  125. package/dist/blocks/stats-01/stats.js +2 -2
  126. package/dist/blocks/status-ledger-01/index.d.ts +2 -2
  127. package/dist/blocks/status-ledger-01/index.js +1 -1
  128. package/dist/blocks/status-ledger-01/status-ledger.d.ts +1 -1
  129. package/dist/blocks/status-ledger-01/status-ledger.js +2 -2
  130. package/dist/catalog.d.ts +1 -1
  131. package/dist/catalog.d.ts.map +1 -1
  132. package/dist/catalog.js +473 -1
  133. package/dist/components/index.d.ts +104 -66
  134. package/dist/components/index.d.ts.map +1 -1
  135. package/dist/components/index.js +74 -40
  136. package/dist/components/ui/accordion.js +1 -1
  137. package/dist/components/ui/alert-dialog.d.ts +119 -0
  138. package/dist/components/ui/alert-dialog.d.ts.map +1 -0
  139. package/dist/components/ui/alert-dialog.js +82 -0
  140. package/dist/components/ui/alert.js +1 -1
  141. package/dist/components/ui/aspect-ratio.d.ts +60 -0
  142. package/dist/components/ui/aspect-ratio.d.ts.map +1 -0
  143. package/dist/components/ui/aspect-ratio.js +61 -0
  144. package/dist/components/ui/avatar.js +1 -1
  145. package/dist/components/ui/badge.js +1 -1
  146. package/dist/components/ui/breadcrumb.js +1 -1
  147. package/dist/components/ui/button-group.d.ts +68 -0
  148. package/dist/components/ui/button-group.d.ts.map +1 -0
  149. package/dist/components/ui/button-group.js +54 -0
  150. package/dist/components/ui/button.js +1 -1
  151. package/dist/components/ui/calendar.d.ts +158 -0
  152. package/dist/components/ui/calendar.d.ts.map +1 -0
  153. package/dist/components/ui/calendar.js +216 -0
  154. package/dist/components/ui/card.d.ts +18 -6
  155. package/dist/components/ui/card.d.ts.map +1 -1
  156. package/dist/components/ui/card.js +23 -8
  157. package/dist/components/ui/carousel.d.ts +118 -0
  158. package/dist/components/ui/carousel.d.ts.map +1 -0
  159. package/dist/components/ui/carousel.js +152 -0
  160. package/dist/components/ui/chart-frame.d.ts +216 -0
  161. package/dist/components/ui/chart-frame.d.ts.map +1 -0
  162. package/dist/components/ui/chart-frame.js +286 -0
  163. package/dist/components/ui/checkbox.js +1 -1
  164. package/dist/components/ui/collapsible.d.ts +97 -0
  165. package/dist/components/ui/collapsible.d.ts.map +1 -0
  166. package/dist/components/ui/collapsible.js +54 -0
  167. package/dist/components/ui/combobox.d.ts +141 -0
  168. package/dist/components/ui/combobox.d.ts.map +1 -0
  169. package/dist/components/ui/combobox.js +243 -0
  170. package/dist/components/ui/command-palette.d.ts +106 -0
  171. package/dist/components/ui/command-palette.d.ts.map +1 -0
  172. package/dist/components/ui/command-palette.js +176 -0
  173. package/dist/components/ui/command.d.ts +82 -0
  174. package/dist/components/ui/command.d.ts.map +1 -0
  175. package/dist/components/ui/command.js +37 -0
  176. package/dist/components/ui/context-menu.d.ts +151 -0
  177. package/dist/components/ui/context-menu.d.ts.map +1 -0
  178. package/dist/components/ui/context-menu.js +97 -0
  179. package/dist/components/ui/cta-link.js +1 -1
  180. package/dist/components/ui/date-picker.d.ts +111 -0
  181. package/dist/components/ui/date-picker.d.ts.map +1 -0
  182. package/dist/components/ui/date-picker.js +74 -0
  183. package/dist/components/ui/diagram.d.ts +84 -15
  184. package/dist/components/ui/diagram.d.ts.map +1 -1
  185. package/dist/components/ui/diagram.js +77 -7
  186. package/dist/components/ui/dialog.js +1 -1
  187. package/dist/components/ui/diff.d.ts +105 -0
  188. package/dist/components/ui/diff.d.ts.map +1 -0
  189. package/dist/components/ui/diff.js +113 -0
  190. package/dist/components/ui/dropdown-menu.d.ts +18 -0
  191. package/dist/components/ui/dropdown-menu.d.ts.map +1 -1
  192. package/dist/components/ui/dropdown-menu.js +1 -1
  193. package/dist/components/ui/fact-list.js +1 -1
  194. package/dist/components/ui/field.js +1 -1
  195. package/dist/components/ui/form.d.ts +151 -0
  196. package/dist/components/ui/form.d.ts.map +1 -0
  197. package/dist/components/ui/form.js +73 -0
  198. package/dist/components/ui/hover-card.d.ts +105 -0
  199. package/dist/components/ui/hover-card.d.ts.map +1 -0
  200. package/dist/components/ui/hover-card.js +49 -0
  201. package/dist/components/ui/input-group.d.ts +99 -0
  202. package/dist/components/ui/input-group.d.ts.map +1 -0
  203. package/dist/components/ui/input-group.js +83 -0
  204. package/dist/components/ui/input.js +1 -1
  205. package/dist/components/ui/item.d.ts +113 -0
  206. package/dist/components/ui/item.d.ts.map +1 -0
  207. package/dist/components/ui/item.js +61 -0
  208. package/dist/components/ui/kbd.js +1 -1
  209. package/dist/components/ui/label.d.ts +58 -0
  210. package/dist/components/ui/label.d.ts.map +1 -0
  211. package/dist/components/ui/label.js +29 -0
  212. package/dist/components/ui/live-region.d.ts +9 -0
  213. package/dist/components/ui/live-region.d.ts.map +1 -1
  214. package/dist/components/ui/live-region.js +10 -2
  215. package/dist/components/ui/mark.js +1 -1
  216. package/dist/components/ui/menubar.d.ts +197 -0
  217. package/dist/components/ui/menubar.d.ts.map +1 -0
  218. package/dist/components/ui/menubar.js +109 -0
  219. package/dist/components/ui/meter.d.ts +121 -0
  220. package/dist/components/ui/meter.d.ts.map +1 -0
  221. package/dist/components/ui/meter.js +82 -0
  222. package/dist/components/ui/native-select.d.ts +72 -0
  223. package/dist/components/ui/native-select.d.ts.map +1 -0
  224. package/dist/components/ui/native-select.js +55 -0
  225. package/dist/components/ui/navigation-menu.d.ts +186 -0
  226. package/dist/components/ui/navigation-menu.d.ts.map +1 -0
  227. package/dist/components/ui/navigation-menu.js +94 -0
  228. package/dist/components/ui/number-field.d.ts +111 -0
  229. package/dist/components/ui/number-field.d.ts.map +1 -0
  230. package/dist/components/ui/number-field.js +84 -0
  231. package/dist/components/ui/one-time-code.d.ts +127 -0
  232. package/dist/components/ui/one-time-code.d.ts.map +1 -0
  233. package/dist/components/ui/one-time-code.js +57 -0
  234. package/dist/components/ui/pagination.js +1 -1
  235. package/dist/components/ui/popover.js +1 -1
  236. package/dist/components/ui/product-mark.d.ts +1 -1
  237. package/dist/components/ui/product-mark.js +1 -1
  238. package/dist/components/ui/product-switcher.d.ts +1 -1
  239. package/dist/components/ui/product-switcher.js +2 -2
  240. package/dist/components/ui/progress.js +1 -1
  241. package/dist/components/ui/prose.js +1 -1
  242. package/dist/components/ui/pulse-graph.js +1 -1
  243. package/dist/components/ui/pulse-series.js +1 -1
  244. package/dist/components/ui/radio-group.js +1 -1
  245. package/dist/components/ui/resizable.d.ts +129 -0
  246. package/dist/components/ui/resizable.d.ts.map +1 -0
  247. package/dist/components/ui/resizable.js +205 -0
  248. package/dist/components/ui/scroll-area.d.ts +97 -0
  249. package/dist/components/ui/scroll-area.d.ts.map +1 -0
  250. package/dist/components/ui/scroll-area.js +68 -0
  251. package/dist/components/ui/search-dialog.d.ts +139 -0
  252. package/dist/components/ui/search-dialog.d.ts.map +1 -0
  253. package/dist/components/ui/search-dialog.js +178 -0
  254. package/dist/components/ui/section.d.ts +26 -0
  255. package/dist/components/ui/section.d.ts.map +1 -1
  256. package/dist/components/ui/section.js +32 -1
  257. package/dist/components/ui/select.js +1 -1
  258. package/dist/components/ui/separator.js +1 -1
  259. package/dist/components/ui/sheet.d.ts +103 -0
  260. package/dist/components/ui/sheet.d.ts.map +1 -0
  261. package/dist/components/ui/sheet.js +58 -0
  262. package/dist/components/ui/sidebar.d.ts +228 -0
  263. package/dist/components/ui/sidebar.d.ts.map +1 -0
  264. package/dist/components/ui/sidebar.js +172 -0
  265. package/dist/components/ui/signal-field.js +1 -1
  266. package/dist/components/ui/skeleton.js +1 -1
  267. package/dist/components/ui/slider.js +1 -1
  268. package/dist/components/ui/spinner.d.ts +79 -0
  269. package/dist/components/ui/spinner.d.ts.map +1 -0
  270. package/dist/components/ui/spinner.js +79 -0
  271. package/dist/components/ui/switch.js +1 -1
  272. package/dist/components/ui/table-sort.d.ts +97 -0
  273. package/dist/components/ui/table-sort.d.ts.map +1 -0
  274. package/dist/components/ui/table-sort.js +102 -0
  275. package/dist/components/ui/table.js +1 -1
  276. package/dist/components/ui/tabs.js +1 -1
  277. package/dist/components/ui/textarea.js +1 -1
  278. package/dist/components/ui/timeline.d.ts +106 -0
  279. package/dist/components/ui/timeline.d.ts.map +1 -0
  280. package/dist/components/ui/timeline.js +111 -0
  281. package/dist/components/ui/toast.d.ts +219 -0
  282. package/dist/components/ui/toast.d.ts.map +1 -0
  283. package/dist/components/ui/toast.js +270 -0
  284. package/dist/components/ui/toggle-group.d.ts +118 -0
  285. package/dist/components/ui/toggle-group.d.ts.map +1 -0
  286. package/dist/components/ui/toggle-group.js +194 -0
  287. package/dist/components/ui/toggle.d.ts +73 -0
  288. package/dist/components/ui/toggle.d.ts.map +1 -0
  289. package/dist/components/ui/toggle.js +44 -0
  290. package/dist/components/ui/tooltip.js +1 -1
  291. package/dist/components/ui/tree.js +1 -1
  292. package/dist/components/ui/typography.js +1 -1
  293. package/dist/fonts/Inter-OFL.txt +93 -93
  294. package/dist/index.d.ts +72 -70
  295. package/dist/index.d.ts.map +1 -1
  296. package/dist/index.js +61 -60
  297. package/dist/lib/rank.d.ts +69 -0
  298. package/dist/lib/rank.d.ts.map +1 -0
  299. package/dist/lib/rank.js +77 -0
  300. package/dist/live/index.d.ts +22 -0
  301. package/dist/live/index.d.ts.map +1 -0
  302. package/dist/live/index.js +20 -0
  303. package/dist/live/run-stream-01/index.d.ts +3 -0
  304. package/dist/live/run-stream-01/index.d.ts.map +1 -0
  305. package/dist/live/run-stream-01/index.js +1 -0
  306. package/dist/live/run-stream-01/run-stream.d.ts +125 -0
  307. package/dist/live/run-stream-01/run-stream.d.ts.map +1 -0
  308. package/dist/live/run-stream-01/run-stream.js +111 -0
  309. package/dist/pages/auth-page/index.d.ts +15 -2
  310. package/dist/pages/auth-page/index.d.ts.map +1 -1
  311. package/dist/pages/auth-page/index.js +8 -4
  312. package/dist/pages/blog-post-page/index.js +5 -5
  313. package/dist/pages/dashboard-page/index.d.ts +4 -4
  314. package/dist/pages/dashboard-page/index.js +4 -4
  315. package/dist/pages/docs-shell/docs-shell.d.ts +37 -4
  316. package/dist/pages/docs-shell/docs-shell.d.ts.map +1 -1
  317. package/dist/pages/docs-shell/docs-shell.js +107 -16
  318. package/dist/pages/docs-shell/index.d.ts +2 -2
  319. package/dist/pages/docs-shell/index.js +1 -1
  320. package/dist/pages/index.d.ts +14 -14
  321. package/dist/pages/index.js +7 -7
  322. package/dist/pages/marketing-page/index.d.ts +6 -6
  323. package/dist/pages/marketing-page/index.js +5 -5
  324. package/dist/pages/not-found-page/index.js +4 -4
  325. package/dist/pages/settings-page/index.d.ts +3 -3
  326. package/dist/pages/settings-page/index.js +4 -4
  327. package/dist/provider/index.d.ts +4 -4
  328. package/dist/provider/index.js +2 -2
  329. package/dist/provider/provider.d.ts +1 -1
  330. package/dist/provider/provider.js +1 -1
  331. package/dist/provider/theme-script.d.ts +1 -1
  332. package/dist/provider/theme-script.js +1 -1
  333. package/dist/styles.css +689 -0
  334. package/package.json +9 -1
@@ -0,0 +1,212 @@
1
+ import type { ReactNode } from 'react';
2
+ import { type ProductMarkProps } from '../../components/ui/product-mark.js';
3
+ import type { SwitcherProduct } from '../../components/ui/product-switcher.js';
4
+ import type { SearchDialogMessages } from '../../components/ui/search-dialog.js';
5
+ import type { Mode, PackId } from '../../theming/index.js';
6
+ import type { ThemePack } from './theme-menu.js';
7
+ /**
8
+ * One destination in the bar's own navigation.
9
+ *
10
+ * `href` is required and `current` is opt-in. The bar marks the current page with
11
+ * `aria-current="page"` rather than with a colour, so a reader who cannot see the
12
+ * colour still knows where they are.
13
+ */
14
+ export type SiteNavLink = {
15
+ /** The text of the link. */
16
+ label: string;
17
+ /** Where the link goes. */
18
+ href: string;
19
+ /**
20
+ * Marks this link as the page the reader is on. Set it on the one link whose
21
+ * destination is the current route.
22
+ *
23
+ * A site that renders the bar once in a root layout cannot know its own route,
24
+ * because a layout is handed no pathname. Such a site passes `currentPath`
25
+ * instead and the bar resolves the mark in the browser; see that prop.
26
+ */
27
+ current?: boolean;
28
+ /**
29
+ * Opens the destination in a new browsing context, which defaults the link
30
+ * relationship to `noopener noreferrer`. Prism does not decide what counts as
31
+ * external: a cross-origin destination is not by itself a reason to open a tab.
32
+ */
33
+ newTab?: boolean;
34
+ };
35
+ /** The search the bar offers, which is a URL rather than an index. */
36
+ export type SiteNavSearch = {
37
+ /**
38
+ * Where this site's JSON index is served from, fetched on the first search and
39
+ * not before. A URL rather than the index itself, because the index is the
40
+ * largest asset on a documentation site and a value passed as a prop is
41
+ * serialized into the document of every route that renders the bar.
42
+ */
43
+ indexUrl: string;
44
+ /** The accessible name of the trigger, of the dialog and of its field. */
45
+ label: string;
46
+ /** Every sentence the dialog can say, which a Component does not ship. */
47
+ messages: SearchDialogMessages;
48
+ /** The text shown before the reader has typed anything. */
49
+ hint?: string;
50
+ };
51
+ /** The colour chooser the bar offers, and whether it offers one at all. */
52
+ export type SiteNavTheme = {
53
+ /** The accessible name of the menu, and of the word on its trigger. */
54
+ label: string;
55
+ /**
56
+ * The packs to choose between, each with the word a reader reads for it. Omit it
57
+ * to offer every published pack under its own capitalised name.
58
+ *
59
+ * A product site passes nothing at all rather than passing this, because a site's
60
+ * ground is a property of the site and a reader who repaints it is a reader on a
61
+ * page that is no longer the one the site describes.
62
+ */
63
+ packs?: readonly ThemePack[];
64
+ };
65
+ /** The light and dark control the bar offers. */
66
+ export type SiteNavMode = {
67
+ /** The control's accessible name while the page is in dark mode. */
68
+ lightLabel: string;
69
+ /** The control's accessible name while the page is in light mode. */
70
+ darkLabel: string;
71
+ };
72
+ /** The two names of the control that opens the navigation below the row. */
73
+ export type SiteNavMobileLabels = {
74
+ /** The word on the trigger while the panel is closed. */
75
+ open: string;
76
+ /** The word on the trigger while the panel is open. */
77
+ close: string;
78
+ };
79
+ /** The props a SiteNavbar takes. */
80
+ export type SiteNavbarProps = {
81
+ /**
82
+ * The product this bar belongs to: the id, name and pack its `ProductMark` is
83
+ * drawn from, and the mark that heads the mobile panel. The bar renders the mark
84
+ * itself rather than a slot, because a bar whose brand lockup is a slot is a bar
85
+ * every consumer has to reimplement.
86
+ */
87
+ product: Pick<ProductMarkProps, 'id' | 'name' | 'pack'>;
88
+ /** Where the brand lockup goes. @defaultValue '/' */
89
+ homeHref?: string;
90
+ /**
91
+ * The pack a reader who has never chosen a pack gets. It is passed to the theme
92
+ * runtime rather than read from the document, so a site states its own default in
93
+ * one place and the control and the page cannot disagree about it.
94
+ */
95
+ defaultPack: PackId;
96
+ /**
97
+ * The mode a reader who has never chosen gets. Required for the same reason
98
+ * `defaultPack` is, and because a toggle with no stated starting mode is a
99
+ * control whose icon is a guess until it is pressed once.
100
+ */
101
+ defaultMode: Mode;
102
+ /** This site's own destinations. Omit for a bar that carries only the lockup. */
103
+ nav?: readonly SiteNavLink[];
104
+ /**
105
+ * The accessible name of the site's navigation. Required, and required rather
106
+ * than defaulted because it is a word a reader hears: a Block that ships no copy
107
+ * ships no reader-facing copy either.
108
+ */
109
+ navLabel: string;
110
+ /**
111
+ * The route the reader is on, for a site that renders the bar once in a root
112
+ * layout and therefore cannot mark the current link itself.
113
+ *
114
+ * A site that composes the bar per page, which is the arrangement that keeps the
115
+ * current link server rendered, sets `current` on the one link instead and leaves
116
+ * this off. The two are alternatives rather than layers, and a site that set both
117
+ * would have two answers to which link is current.
118
+ */
119
+ currentPath?: string;
120
+ /**
121
+ * The set of sites to move between, rendered as a menu. Omit it on a site that is
122
+ * the only one; a set of one is a menu with a single item and no reason to exist.
123
+ */
124
+ sites?: readonly SwitcherProduct[];
125
+ /** The `id` of the site the reader is on, marked in the menu. */
126
+ currentSiteId?: string;
127
+ /**
128
+ * The accessible name of the sites menu. Required whenever `sites` is passed, for
129
+ * the same reason `navLabel` is.
130
+ */
131
+ sitesLabel?: string;
132
+ /** The search the bar offers, or nothing for no search. */
133
+ search?: SiteNavSearch;
134
+ /** The colour chooser the bar offers, or nothing for no chooser. */
135
+ theme?: SiteNavTheme;
136
+ /** The light and dark control the bar offers, or nothing for no toggle. */
137
+ mode?: SiteNavMode;
138
+ /**
139
+ * The two names of the mobile trigger, which is a round icon with no visible
140
+ * word. Required rather than defaulted, because a default would be a sentence
141
+ * this Block ships about a product that is not the caller's, and because a bar
142
+ * that renders an unlabelled round control below its own threshold has a
143
+ * keyboard reader reaching for something it cannot name.
144
+ */
145
+ mobileLabels: SiteNavMobileLabels;
146
+ /**
147
+ * A slot for controls the product owns, after the ones this bar composes. A slot
148
+ * rather than a prop, because an account menu and a sign-in link are application
149
+ * state and neither is a fact a bar can be told.
150
+ */
151
+ actions?: ReactNode;
152
+ /**
153
+ * Keeps the bar at the top of the viewport as the page scrolls. On by default,
154
+ * because the bar is how a reader leaves the page they are on, and a bar that
155
+ * scrolls away takes that with it on exactly the long pages a reader needs it.
156
+ */
157
+ sticky?: boolean;
158
+ /** Layout only. Changing a Prism-owned visual property from here is prohibited. */
159
+ className?: string;
160
+ };
161
+ /**
162
+ * The bar at the top of a product site, with the controls a reader needs on every
163
+ * page of it.
164
+ *
165
+ * It is `SiteHeader` plus the four controls that were missing from it, and it
166
+ * exists because all five NaniSoft sites had the same bar and every one of them had
167
+ * written the missing four separately: Prism's own site had search and a colour
168
+ * chooser and no way to reach its four siblings, and each of the four had a row of
169
+ * product marks where a menu belongs and no search, no mode control and no
170
+ * navigation at all below the width its own row stopped fitting. Five bars, one
171
+ * design language, and no two of them the same bar.
172
+ *
173
+ * Every string is a prop and the Block ships none. There is no site name, no
174
+ * default navigation, no "Search", no list of packs and no list of sites: a bar
175
+ * that hardcoded any of them would hand every consumer a claim about a product that
176
+ * is not theirs, which is the defect this Block exists to remove. The one piece of
177
+ * copy it derives is a pack's own name from its own identifier, and only when the
178
+ * caller names none.
179
+ *
180
+ * **The bar is one flex row that wraps, and it fits by measurement.** The brand
181
+ * lockup and the controls hold their ends, the navigation sits in the middle, and
182
+ * the navigation row is hidden below `lg` where the panel takes over. The brand
183
+ * lockup is the one element that never wraps: a wordmark broken across two lines is
184
+ * not a wordmark, and it is also the one element that yields rather than pushing a
185
+ * control off the right edge of the viewport, which is the harm a header-fit test
186
+ * exists to catch.
187
+ *
188
+ * **The navigation is a `nav` and the sites menu is a second landmark of its own.**
189
+ * A reader who navigates by landmark needs two regions rather than one region with
190
+ * two lists in it, and the two sets are different places: one is where this site
191
+ * goes and the other is where the family goes. The controls are not a region at
192
+ * all, because they are whatever this bar composed plus whatever the consumer put
193
+ * in `actions`, and wrapping them in a landmark would be a claim about content the
194
+ * Block does not own.
195
+ *
196
+ * The bottom hairline is `border-border`, so the bar separates from the page by a
197
+ * line rather than by a fill change, which is how every surface in this system is
198
+ * separated: in the base pack `background` and `card` resolve to the same value, so
199
+ * a fill is not available as a separator. The bar is translucent and blurred, so the
200
+ * content scrolling under it is legible through it rather than hidden by it, which
201
+ * is the reason a sticky bar can be translucent at all.
202
+ *
203
+ * **It is a server Component with one client island inside it.** The lockup and the
204
+ * navigation are rendered on the server and ship no JavaScript; the controls are a
205
+ * single boundary, because a control's state is a reader's state. A site that
206
+ * passes no `search`, `sites`, `theme`, `mode` or `nav` renders the whole bar on the
207
+ * server and ships none, which is the arrangement a static site wants and the reason
208
+ * those props are optional rather than required.
209
+ */
210
+ export declare function SiteNavbar({ product, homeHref, defaultPack, defaultMode, nav, navLabel, currentPath, sites, currentSiteId, sitesLabel, search, theme, mode, mobileLabels, actions, sticky, className, }: SiteNavbarProps): import("react").JSX.Element;
211
+ export default SiteNavbar;
212
+ //# sourceMappingURL=site-navbar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"site-navbar.d.ts","sourceRoot":"","sources":["../../../src/blocks/site-navbar/site-navbar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC,OAAO,EAAe,KAAK,gBAAgB,EAAE,MAAM,kCAAkC,CAAA;AACrF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAA;AAC3E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAA;AAE7E,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AAEjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAE7C;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,4BAA4B;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,CAAA;AAED,sEAAsE;AACtE,MAAM,MAAM,aAAa,GAAG;IAC1B;;;;;OAKG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB,0EAA0E;IAC1E,KAAK,EAAE,MAAM,CAAA;IACb,0EAA0E;IAC1E,QAAQ,EAAE,oBAAoB,CAAA;IAC9B,2DAA2D;IAC3D,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,CAAA;AAED,2EAA2E;AAC3E,MAAM,MAAM,YAAY,GAAG;IACzB,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAA;IACb;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,SAAS,SAAS,EAAE,CAAA;CAC7B,CAAA;AAED,iDAAiD;AACjD,MAAM,MAAM,WAAW,GAAG;IACxB,oEAAoE;IACpE,UAAU,EAAE,MAAM,CAAA;IAClB,qEAAqE;IACrE,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,4EAA4E;AAC5E,MAAM,MAAM,mBAAmB,GAAG;IAChC,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAA;IACZ,uDAAuD;IACvD,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,oCAAoC;AACpC,MAAM,MAAM,eAAe,GAAG;IAC5B;;;;;OAKG;IACH,OAAO,EAAE,IAAI,CAAC,gBAAgB,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC,CAAA;IACvD,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAA;IACnB;;;;OAIG;IACH,WAAW,EAAE,IAAI,CAAA;IACjB,iFAAiF;IACjF,GAAG,CAAC,EAAE,SAAS,WAAW,EAAE,CAAA;IAC5B;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB;;;;;;;;OAQG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;OAGG;IACH,KAAK,CAAC,EAAE,SAAS,eAAe,EAAE,CAAA;IAClC,iEAAiE;IACjE,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,aAAa,CAAA;IACtB,oEAAoE;IACpE,KAAK,CAAC,EAAE,YAAY,CAAA;IACpB,2EAA2E;IAC3E,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB;;;;;;OAMG;IACH,YAAY,EAAE,mBAAmB,CAAA;IACjC;;;;OAIG;IACH,OAAO,CAAC,EAAE,SAAS,CAAA;IACnB;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,mFAAmF;IACnF,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,QAAc,EACd,WAAW,EACX,WAAW,EACX,GAAG,EACH,QAAQ,EACR,WAAW,EACX,KAAK,EACL,aAAa,EACb,UAAU,EACV,MAAM,EACN,KAAK,EACL,IAAI,EACJ,YAAY,EACZ,OAAO,EACP,MAAa,EACb,SAAS,GACV,EAAE,eAAe,+BAkEjB;AAED,eAAe,UAAU,CAAA"}
@@ -0,0 +1,61 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ProductMark } from '../../components/ui/product-mark.js';
3
+ import { cn } from '../../lib/utils.js';
4
+ import { NavbarControls } from './navbar-controls.js';
5
+ /**
6
+ * The bar at the top of a product site, with the controls a reader needs on every
7
+ * page of it.
8
+ *
9
+ * It is `SiteHeader` plus the four controls that were missing from it, and it
10
+ * exists because all five NaniSoft sites had the same bar and every one of them had
11
+ * written the missing four separately: Prism's own site had search and a colour
12
+ * chooser and no way to reach its four siblings, and each of the four had a row of
13
+ * product marks where a menu belongs and no search, no mode control and no
14
+ * navigation at all below the width its own row stopped fitting. Five bars, one
15
+ * design language, and no two of them the same bar.
16
+ *
17
+ * Every string is a prop and the Block ships none. There is no site name, no
18
+ * default navigation, no "Search", no list of packs and no list of sites: a bar
19
+ * that hardcoded any of them would hand every consumer a claim about a product that
20
+ * is not theirs, which is the defect this Block exists to remove. The one piece of
21
+ * copy it derives is a pack's own name from its own identifier, and only when the
22
+ * caller names none.
23
+ *
24
+ * **The bar is one flex row that wraps, and it fits by measurement.** The brand
25
+ * lockup and the controls hold their ends, the navigation sits in the middle, and
26
+ * the navigation row is hidden below `lg` where the panel takes over. The brand
27
+ * lockup is the one element that never wraps: a wordmark broken across two lines is
28
+ * not a wordmark, and it is also the one element that yields rather than pushing a
29
+ * control off the right edge of the viewport, which is the harm a header-fit test
30
+ * exists to catch.
31
+ *
32
+ * **The navigation is a `nav` and the sites menu is a second landmark of its own.**
33
+ * A reader who navigates by landmark needs two regions rather than one region with
34
+ * two lists in it, and the two sets are different places: one is where this site
35
+ * goes and the other is where the family goes. The controls are not a region at
36
+ * all, because they are whatever this bar composed plus whatever the consumer put
37
+ * in `actions`, and wrapping them in a landmark would be a claim about content the
38
+ * Block does not own.
39
+ *
40
+ * The bottom hairline is `border-border`, so the bar separates from the page by a
41
+ * line rather than by a fill change, which is how every surface in this system is
42
+ * separated: in the base pack `background` and `card` resolve to the same value, so
43
+ * a fill is not available as a separator. The bar is translucent and blurred, so the
44
+ * content scrolling under it is legible through it rather than hidden by it, which
45
+ * is the reason a sticky bar can be translucent at all.
46
+ *
47
+ * **It is a server Component with one client island inside it.** The lockup and the
48
+ * navigation are rendered on the server and ship no JavaScript; the controls are a
49
+ * single boundary, because a control's state is a reader's state. A site that
50
+ * passes no `search`, `sites`, `theme`, `mode` or `nav` renders the whole bar on the
51
+ * server and ships none, which is the arrangement a static site wants and the reason
52
+ * those props are optional rather than required.
53
+ */
54
+ export function SiteNavbar({ product, homeHref = '/', defaultPack, defaultMode, nav, navLabel, currentPath, sites, currentSiteId, sitesLabel, search, theme, mode, mobileLabels, actions, sticky = true, className, }) {
55
+ const links = nav ?? [];
56
+ const isCurrent = (link) => link.current ?? (currentPath !== undefined && link.href === currentPath);
57
+ return (_jsx("header", { "data-slot": "site-navbar", className: cn('border-border/80 bg-background/80 sticky top-0 z-20 w-full border-b backdrop-blur', className), children: _jsxs("div", { className: "mx-auto flex h-14 w-full max-w-page items-center gap-2 px-6", children: [_jsx("a", { href: homeHref, className: "focus-visible:border-ring focus-visible:ring-ring shrink-0 rounded-sm focus-visible:ring-[3px] focus-visible:outline-none", children: _jsx(ProductMark, { id: product.id, name: product.name, pack: product.pack, size: "sm" }) }), links.length > 0 ? (_jsx("nav", { "aria-label": navLabel, className: "hidden items-center lg:flex", children: links.map((link) => (_jsx("a", { href: link.href, "aria-current": isCurrent(link) ? 'page' : undefined, rel: link.newTab ? 'noopener noreferrer' : undefined, target: link.newTab ? '_blank' : undefined, className: isCurrent(link)
58
+ ? 'bg-accent text-accent-foreground focus-visible:border-ring focus-visible:ring-ring rounded-md px-2 py-1.5 text-sm font-medium transition-colors focus-visible:ring-[3px] focus-visible:outline-none'
59
+ : 'text-muted-foreground hover:bg-accent hover:text-accent-foreground focus-visible:border-ring focus-visible:ring-ring rounded-md px-2 py-1.5 text-sm font-medium transition-colors focus-visible:ring-[3px] focus-visible:outline-none', children: link.label }, link.href))) })) : null, _jsx(NavbarControls, { product: product, nav: links.map((link) => ({ ...link, current: isCurrent(link) })), navLabel: navLabel, sites: sites, currentSiteId: currentSiteId, sitesLabel: sitesLabel, search: search, theme: theme, mode: mode, mobileLabels: mobileLabels, defaultPack: defaultPack, defaultMode: defaultMode, actions: actions })] }) }));
60
+ }
61
+ export default SiteNavbar;
@@ -0,0 +1,40 @@
1
+ import type { SwitcherProduct } from '../../components/ui/product-switcher.js';
2
+ /** The props the sites menu takes. */
3
+ export type SitesMenuProps = {
4
+ /** The set to move between, in the order a reader should meet it. */
5
+ sites: readonly SwitcherProduct[];
6
+ /** The `id` of the site the reader is on. Marked `aria-current="page"`. */
7
+ currentId?: string;
8
+ /** The accessible name of the menu and of its trigger. A word a reader hears. */
9
+ label: string;
10
+ };
11
+ /**
12
+ * The set of sites, as a menu.
13
+ *
14
+ * Prism's own site had no way to reach its four siblings and each of the four had
15
+ * written its own way to reach the other four, so a reader on one site had to know
16
+ * that four other hosts existed before they could be found. This is the one control
17
+ * that states the set, and every site that composes it states the same five.
18
+ *
19
+ * **The trigger is an icon rather than a word, for the same reason Prism's search
20
+ * trigger is.** The bar carries the brand, the site's own destinations and a row of
21
+ * controls, and at the width the row is authored to fit, a fourth labelled control
22
+ * is the difference between fitting and folding the brand onto two lines. A control
23
+ * that is not a destination is the right place to spend that width, because a
24
+ * reader who does not recognise the icon is losing a word rather than a route.
25
+ *
26
+ * **The items are links, not commands, and the current one is marked rather than
27
+ * styled.** A menu item that navigated was a command wearing a link's clothes, and
28
+ * the cost of that is a reader with a middle-click expecting a new tab and getting
29
+ * nothing. `aria-current="page"` on the member the reader is on is the state a
30
+ * screen reader announces, and it is why the set is a list of anchors inside a menu
31
+ * rather than a `ProductSwitcher` row: the switcher renders every mark at once and
32
+ * this renders them on demand, which is what makes room for the icon-only trigger.
33
+ *
34
+ * Each item carries the site's own `ProductMark`, so a reader recognises a
35
+ * destination by its colour before they read its name, and the mark is where a
36
+ * pack boundary is safe: it is a fully rounded disc, so repointing the pack's corner
37
+ * radius beneath it moves nothing about its shape.
38
+ */
39
+ export declare function SitesMenu({ sites, currentId, label }: SitesMenuProps): import("react").JSX.Element | null;
40
+ //# sourceMappingURL=sites-menu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sites-menu.d.ts","sourceRoot":"","sources":["../../../src/blocks/site-navbar/sites-menu.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAA;AAE3E,sCAAsC;AACtC,MAAM,MAAM,cAAc,GAAG;IAC3B,qEAAqE;IACrE,KAAK,EAAE,SAAS,eAAe,EAAE,CAAA;IACjC,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,iFAAiF;IACjF,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,SAAS,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,cAAc,sCAmDpE"}
@@ -0,0 +1,48 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { LayoutGrid } from 'lucide-react';
4
+ import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuTrigger, } from '../../components/ui/dropdown-menu.js';
5
+ import { ProductMark } from '../../components/ui/product-mark.js';
6
+ /**
7
+ * The set of sites, as a menu.
8
+ *
9
+ * Prism's own site had no way to reach its four siblings and each of the four had
10
+ * written its own way to reach the other four, so a reader on one site had to know
11
+ * that four other hosts existed before they could be found. This is the one control
12
+ * that states the set, and every site that composes it states the same five.
13
+ *
14
+ * **The trigger is an icon rather than a word, for the same reason Prism's search
15
+ * trigger is.** The bar carries the brand, the site's own destinations and a row of
16
+ * controls, and at the width the row is authored to fit, a fourth labelled control
17
+ * is the difference between fitting and folding the brand onto two lines. A control
18
+ * that is not a destination is the right place to spend that width, because a
19
+ * reader who does not recognise the icon is losing a word rather than a route.
20
+ *
21
+ * **The items are links, not commands, and the current one is marked rather than
22
+ * styled.** A menu item that navigated was a command wearing a link's clothes, and
23
+ * the cost of that is a reader with a middle-click expecting a new tab and getting
24
+ * nothing. `aria-current="page"` on the member the reader is on is the state a
25
+ * screen reader announces, and it is why the set is a list of anchors inside a menu
26
+ * rather than a `ProductSwitcher` row: the switcher renders every mark at once and
27
+ * this renders them on demand, which is what makes room for the icon-only trigger.
28
+ *
29
+ * Each item carries the site's own `ProductMark`, so a reader recognises a
30
+ * destination by its colour before they read its name, and the mark is where a
31
+ * pack boundary is safe: it is a fully rounded disc, so repointing the pack's corner
32
+ * radius beneath it moves nothing about its shape.
33
+ */
34
+ export function SitesMenu({ sites, currentId, label }) {
35
+ if (sites.length === 0)
36
+ return null;
37
+ return (_jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { "data-slot": "site-navbar-sites-trigger", "aria-label": label, className: "border-border bg-card text-muted-foreground hover:bg-accent hover:text-accent-foreground data-[popup-open]:bg-accent data-[popup-open]:text-accent-foreground size-11 shrink-0 rounded-full border", children: _jsx(LayoutGrid, { "aria-hidden": true, className: "size-4" }) }), _jsx(DropdownMenuContent, { align: "end", sideOffset: 8, className: "min-w-56", children: _jsxs(DropdownMenuGroup, { children: [_jsx(DropdownMenuLabel, { children: label }), sites.map((site) => {
38
+ const current = site.id === currentId;
39
+ return (_jsx(DropdownMenuItem, {
40
+ /*
41
+ * Rendered AS the link rather than wrapping one. A focusable menu
42
+ * item with an anchor inside it is two tab stops for one row, and a
43
+ * reader who middle-clicks a row that only looks like a link gets no
44
+ * new tab and no way to tell that the row was a link at all.
45
+ */
46
+ render: _jsx("a", { href: site.href, target: "_blank", rel: "noopener noreferrer", "aria-current": current ? 'page' : undefined, "data-current": current ? 'true' : undefined }), children: _jsx(ProductMark, { id: site.id, name: site.name, pack: site.pack, size: "sm" }) }, site.id));
47
+ })] }) })] }));
48
+ }
@@ -0,0 +1,47 @@
1
+ import { type PackId } from '../../theming/index.js';
2
+ /** One pack the menu offers, and the word a reader reads for it. */
3
+ export type ThemePack = {
4
+ /** The pack identifier, which is a token rather than a string. */
5
+ id: PackId;
6
+ /** The pack's own name. */
7
+ name: string;
8
+ };
9
+ /** The props the theme menu takes. */
10
+ export type ThemeMenuProps = {
11
+ /** The packs to choose between. Defaults to every published pack. */
12
+ packs?: readonly ThemePack[];
13
+ /** The accessible name of the menu, and of the word on its trigger. */
14
+ label: string;
15
+ };
16
+ /**
17
+ * The pack chooser, as a menu.
18
+ *
19
+ * **The swatch is a pack boundary rather than a literal colour, and that is the
20
+ * whole of how this component avoids a runtime token read.** The obvious
21
+ * implementation reads each pack's compiled `--primary` and paints it as an inline
22
+ * style, which is what Prism's own documentation site did. A token resolved at
23
+ * runtime does not follow the cascade, so the dot holding a pack's colour is right
24
+ * in one mode and stale in the other, and it is the exact defect the
25
+ * `runtime-token-read` law names: the disagreement is between what is painted and
26
+ * what the cascade says, and only a program that reads the read can see it.
27
+ *
28
+ * `data-pack` on a span carrying `bg-primary` resolves through the cascade, holds
29
+ * every pack at once, and ships no client code. The boundary is safe on this shape
30
+ * and only this shape: a pack repoints its own corner radius as well as its colour,
31
+ * so a boundary on anything that is not fully rounded would quietly restyle that
32
+ * element's corners. A disc is fully rounded, so the radius axis is a no-op here.
33
+ *
34
+ * **It is a radio group rather than a list of commands.** One pack is active at a
35
+ * time out of a known set, which is what a radio group is for, and it is what
36
+ * gives the menu its announced state: a reader who opens the chooser hears which
37
+ * of the packs is in use, where a list of commands would announce six buttons and
38
+ * leave them to work out which one took effect.
39
+ *
40
+ * **The trigger shows the active pack's name, and drops it below `sm`.** Six
41
+ * options side by side need about 380 pixels, which is why this is a menu at all
42
+ * rather than a row of pills, and the name on the trigger is the one place the
43
+ * choice stays visible once the menu is closed. It is hidden rather than shortened
44
+ * below `sm` because a truncated pack name is a word that names nothing.
45
+ */
46
+ export declare function ThemeMenu({ packs, label }: ThemeMenuProps): import("react").JSX.Element | null;
47
+ //# sourceMappingURL=theme-menu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-menu.d.ts","sourceRoot":"","sources":["../../../src/blocks/site-navbar/theme-menu.tsx"],"names":[],"mappings":"AAcA,OAAO,EAAS,KAAK,MAAM,EAAE,MAAM,eAAe,CAAA;AAElD,oEAAoE;AACpE,MAAM,MAAM,SAAS,GAAG;IACtB,kEAAkE;IAClE,EAAE,EAAE,MAAM,CAAA;IACV,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED,sCAAsC;AACtC,MAAM,MAAM,cAAc,GAAG;IAC3B,qEAAqE;IACrE,KAAK,CAAC,EAAE,SAAS,SAAS,EAAE,CAAA;IAC5B,uEAAuE;IACvE,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAcD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,SAAS,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,cAAc,sCA8CzD"}
@@ -0,0 +1,55 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { ChevronDown } from 'lucide-react';
4
+ import { DropdownMenu, DropdownMenuContent, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuTrigger, } from '../../components/ui/dropdown-menu.js';
5
+ import { usePrismTheme } from '../../provider/provider.js';
6
+ import { PACKS } from '../../theming/index.js';
7
+ /**
8
+ * The name a pack is offered under when the caller names none.
9
+ *
10
+ * Capitalising the identifier is enough rather than a table, because the pack
11
+ * vocabulary is closed and every id in it is the lowercased form of its own name.
12
+ * The alternative is a lookup that could fall through for a pack added after this
13
+ * line was written, and a fallthrough here is a menu item with no readable name.
14
+ */
15
+ function nameOf(pack) {
16
+ return pack.charAt(0).toUpperCase() + pack.slice(1);
17
+ }
18
+ /**
19
+ * The pack chooser, as a menu.
20
+ *
21
+ * **The swatch is a pack boundary rather than a literal colour, and that is the
22
+ * whole of how this component avoids a runtime token read.** The obvious
23
+ * implementation reads each pack's compiled `--primary` and paints it as an inline
24
+ * style, which is what Prism's own documentation site did. A token resolved at
25
+ * runtime does not follow the cascade, so the dot holding a pack's colour is right
26
+ * in one mode and stale in the other, and it is the exact defect the
27
+ * `runtime-token-read` law names: the disagreement is between what is painted and
28
+ * what the cascade says, and only a program that reads the read can see it.
29
+ *
30
+ * `data-pack` on a span carrying `bg-primary` resolves through the cascade, holds
31
+ * every pack at once, and ships no client code. The boundary is safe on this shape
32
+ * and only this shape: a pack repoints its own corner radius as well as its colour,
33
+ * so a boundary on anything that is not fully rounded would quietly restyle that
34
+ * element's corners. A disc is fully rounded, so the radius axis is a no-op here.
35
+ *
36
+ * **It is a radio group rather than a list of commands.** One pack is active at a
37
+ * time out of a known set, which is what a radio group is for, and it is what
38
+ * gives the menu its announced state: a reader who opens the chooser hears which
39
+ * of the packs is in use, where a list of commands would announce six buttons and
40
+ * leave them to work out which one took effect.
41
+ *
42
+ * **The trigger shows the active pack's name, and drops it below `sm`.** Six
43
+ * options side by side need about 380 pixels, which is why this is a menu at all
44
+ * rather than a row of pills, and the name on the trigger is the one place the
45
+ * choice stays visible once the menu is closed. It is hidden rather than shortened
46
+ * below `sm` because a truncated pack name is a word that names nothing.
47
+ */
48
+ export function ThemeMenu({ packs, label }) {
49
+ const { pack, setPack } = usePrismTheme();
50
+ const options = packs ?? PACKS.map((id) => ({ id, name: nameOf(id) }));
51
+ const active = options.find((option) => option.id === pack) ?? options[0];
52
+ if (!active)
53
+ return null;
54
+ return (_jsxs(DropdownMenu, { children: [_jsxs(DropdownMenuTrigger, { "data-slot": "site-navbar-theme-trigger", "aria-label": `${label}: ${active.name}`, className: "border-border bg-card text-foreground hover:bg-accent hover:text-accent-foreground data-[popup-open]:bg-accent data-[popup-open]:text-accent-foreground h-11 shrink-0 gap-2 rounded-full border pr-2.5 pl-3", children: [_jsx("span", { "data-pack": active.id, "aria-hidden": true, className: "border-border/60 bg-primary size-3.5 rounded-full border" }), _jsx("span", { className: "hidden sm:inline", children: active.name }), _jsx(ChevronDown, { "aria-hidden": true, className: "size-3.5" })] }), _jsx(DropdownMenuContent, { align: "end", sideOffset: 8, className: "min-w-52", children: _jsxs(DropdownMenuRadioGroup, { value: active.id, onValueChange: (value) => setPack(value), children: [_jsx(DropdownMenuLabel, { children: label }), options.map((option) => (_jsxs(DropdownMenuRadioItem, { value: option.id, closeOnClick: true, children: [_jsx("span", { "data-pack": option.id, "aria-hidden": true, className: "border-border/60 bg-primary size-3.5 shrink-0 rounded-full border" }), _jsx("span", { className: "flex-1", children: option.name })] }, option.id)))] }) })] }));
55
+ }
@@ -1,3 +1,3 @@
1
- export { StackGrid01, default } from './stack-grid';
2
- export type { StackGrid01Props, StackPart, StackOwn } from './stack-grid';
1
+ export { StackGrid01, default } from './stack-grid.js';
2
+ export type { StackGrid01Props, StackPart, StackOwn } from './stack-grid.js';
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- export { StackGrid01, default } from './stack-grid';
1
+ export { StackGrid01, default } from './stack-grid.js';
@@ -1,14 +1,40 @@
1
- import { type HeadingLevel } from '../../components/ui/section';
1
+ import { type HeadingLevel } from '../../components/ui/section.js';
2
2
  /**
3
- * One part a product is assembled from: its name and the role it plays.
3
+ * One part a product is assembled from: its name, the product it wraps when the
4
+ * name is a codename, and the role it plays.
4
5
  *
5
- * Both are required, and a part with no role is a logo and a part with no name
6
- * is a role. A survey grid is a claim that a set of parts is sufficient, and both
7
- * halves of that claim are the caller's to make.
6
+ * `name` and `role` are required, and a part with no role is a logo and a part
7
+ * with no name is a role. A survey grid is a claim that a set of parts is
8
+ * sufficient, and both halves of that claim are the caller's to make.
8
9
  */
9
10
  export type StackPart = {
10
11
  /** The part's own name, as its authors spell it. */
11
12
  name: string;
13
+ /**
14
+ * The real product underneath a codename, when the name above is not a name a
15
+ * reader could look up.
16
+ *
17
+ * Optional and additive: a part whose name already is its product's own name
18
+ * omits it, and a tile that omits it renders the two elements it rendered
19
+ * before this field existed, with no line and no space held open for one.
20
+ *
21
+ * It is a field and not a slot, because the value goes inside the tile this
22
+ * Block already draws. A slot is a value that goes in an element the Block does
23
+ * not own, and a `StackPart` is a part's data, which is the `li` the Block
24
+ * renders. It is the same shape as `ProductGrid01`'s `pack` and
25
+ * `StatusLedger01`'s `detail`: one more value in a row the caller owns.
26
+ *
27
+ * Three of the four NaniSoft sites publish their stack under a codename with
28
+ * the product printed beneath it, and the missing field is what made the
29
+ * migration drop eight published names rather than move them. It is also the
30
+ * evidence for the claim the section makes: a grid that says it composes rather
31
+ * than forks can only be checked by a reader who can see what it composed.
32
+ *
33
+ * Pass it when it differs from `name`. The Block renders what it is handed and
34
+ * does not compare the two, so a caller that passes one name twice prints it
35
+ * twice.
36
+ */
37
+ realName?: string;
12
38
  /**
13
39
  * One phrase about what the part does here. It is a role rather than a
14
40
  * description: the grid is a survey of what a product is built from, not a
@@ -34,9 +60,9 @@ export type StackOwn = {
34
60
  /**
35
61
  * The props a StackGrid01 takes.
36
62
  *
37
- * Every string is a prop and the Block ships none: no part, no role, no blurb
38
- * and no default "built in-house" mark. A grid that hardcoded a part list would
39
- * hand every consumer a survey of somebody else's stack.
63
+ * Every string is a prop and the Block ships none: no part, no role, no
64
+ * realName, no blurb and no default "built in-house" mark. A grid that hardcoded
65
+ * a part list would hand every consumer a survey of somebody else's stack.
40
66
  */
41
67
  export type StackGrid01Props = {
42
68
  /** Optional label above the section title. See the No-Default-Eyebrow Rule. */
@@ -107,9 +133,14 @@ export type StackGrid01Props = {
107
133
  * the claim is the caller's words. Three of the four sites write three different
108
134
  * ones, and the Block does not choose.
109
135
  *
110
- * A tile carries a name and a role and nothing else. A part whose role needs two
111
- * lines belongs in the section's `description`, where it applies to the group
112
- * rather than to one tile.
136
+ * A tile carries a name, the real product behind it when the name is a codename,
137
+ * and a role. The middle value is optional and additive: eight of the sixteen
138
+ * parts on the three sites that draw this section are a codename over a product
139
+ * its reader could look up, and before the field existed the honest answer
140
+ * inside this surface was to lose those names. A part whose *role* needs two
141
+ * lines still belongs in the section's `description`, where it applies to the
142
+ * group rather than to one tile, because that is a claim about every tile rather
143
+ * than a second name for one of them.
113
144
  *
114
145
  * It is a server Component: no hook, no state and no client code.
115
146
  */
@@ -1 +1 @@
1
- {"version":3,"file":"stack-grid.d.ts","sourceRoot":"","sources":["../../../src/blocks/stack-grid-01/stack-grid.tsx"],"names":[],"mappings":"AACA,OAAO,EAA2B,KAAK,YAAY,EAAE,MAAM,6BAA6B,CAAA;AAGxF;;;;;;GAMG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAA;IACZ;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,QAAQ,GAAG;IACrB,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAA;IACZ,+DAA+D;IAC/D,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;OAIG;IACH,KAAK,EAAE,SAAS,SAAS,EAAE,CAAA;IAC3B;;;;OAIG;IACH,GAAG,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAA;IACzB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,+DAA+D;IAC/D,YAAY,CAAC,EAAE,YAAY,CAAA;IAC3B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,KAAK,EACL,WAAW,EACX,KAAK,EACL,GAAG,EACH,QAAQ,EACR,OAAO,EACP,YAAmB,EACnB,SAAS,GACV,EAAE,gBAAgB,+BA4DlB;AAED,eAAe,WAAW,CAAA"}
1
+ {"version":3,"file":"stack-grid.d.ts","sourceRoot":"","sources":["../../../src/blocks/stack-grid-01/stack-grid.tsx"],"names":[],"mappings":"AACA,OAAO,EAAuC,KAAK,YAAY,EAAE,MAAM,6BAA6B,CAAA;AAGpG;;;;;;;GAOG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAA;IACZ;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,QAAQ,GAAG;IACrB,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAA;IACZ,+DAA+D;IAC/D,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;OAIG;IACH,KAAK,EAAE,SAAS,SAAS,EAAE,CAAA;IAC3B;;;;OAIG;IACH,GAAG,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAA;IACzB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,+DAA+D;IAC/D,YAAY,CAAC,EAAE,YAAY,CAAA;IAC3B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,KAAK,EACL,WAAW,EACX,KAAK,EACL,GAAG,EACH,QAAQ,EACR,OAAO,EACP,YAAmB,EACnB,SAAS,GACV,EAAE,gBAAgB,+BA6ElB;AAED,eAAe,WAAW,CAAA"}
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Card, CardContent, CardHeader, CardTitle } from '../../components/ui/card';
3
- import { Section, SectionHeading } from '../../components/ui/section';
4
- import { cn } from '../../lib/utils';
2
+ import { Card, CardContent, CardHeader, CardTitle } from '../../components/ui/card.js';
3
+ import { Section, SectionHeading, childLevel } from '../../components/ui/section.js';
4
+ import { cn } from '../../lib/utils.js';
5
5
  /**
6
6
  * A survey of what a product is assembled from, and what it built itself.
7
7
  *
@@ -32,18 +32,26 @@ import { cn } from '../../lib/utils';
32
32
  * the claim is the caller's words. Three of the four sites write three different
33
33
  * ones, and the Block does not choose.
34
34
  *
35
- * A tile carries a name and a role and nothing else. A part whose role needs two
36
- * lines belongs in the section's `description`, where it applies to the group
37
- * rather than to one tile.
35
+ * A tile carries a name, the real product behind it when the name is a codename,
36
+ * and a role. The middle value is optional and additive: eight of the sixteen
37
+ * parts on the three sites that draw this section are a codename over a product
38
+ * its reader could look up, and before the field existed the honest answer
39
+ * inside this surface was to lose those names. A part whose *role* needs two
40
+ * lines still belongs in the section's `description`, where it applies to the
41
+ * group rather than to one tile, because that is a claim about every tile rather
42
+ * than a second name for one of them.
38
43
  *
39
44
  * It is a server Component: no hook, no state and no client code.
40
45
  */
41
46
  export function StackGrid01({ eyebrow, title, description, parts, own, ownLabel, caption, headingLevel = 'h2', className, }) {
47
+ // Both groups are sets of tiles under one section, so a tile name is a heading
48
+ // one step below it rather than a sibling of it.
49
+ const Title = childLevel(headingLevel);
42
50
  if (own !== undefined && own.length > 0 && !ownLabel) {
43
51
  throw new Error('StackGrid01: the in-house group was passed with no ownLabel, so the grid would make the claim ' +
44
52
  '"this part is ours" in a shape and leave the words to a reader to infer. Pass the words you mean, ' +
45
53
  'or omit the group.');
46
54
  }
47
- return (_jsxs(Section, { children: [title ? (_jsx(SectionHeading, { as: headingLevel, align: "left", eyebrow: eyebrow, title: title, description: description, className: "mb-12" })) : null, _jsxs("div", { "data-slot": "stack-grid", className: cn('flex flex-col gap-10', className), children: [_jsx("ul", { className: "grid gap-3 sm:grid-cols-2 lg:grid-cols-4", children: parts.map((part) => (_jsx("li", { children: _jsxs(Card, { className: "bg-muted h-full gap-2 py-4", children: [_jsx(CardHeader, { className: "gap-1", children: _jsx(CardTitle, { className: "text-sm", children: part.name }) }), _jsx(CardContent, { children: _jsx("p", { className: "text-muted-foreground text-pretty text-xs", children: part.role }) })] }) }, part.name))) }), own && own.length > 0 ? (_jsx("ul", { "data-slot": "stack-grid-own", className: "grid gap-3 sm:grid-cols-2 lg:grid-cols-4", children: own.map((entry) => (_jsx("li", { children: _jsxs(Card, { className: "border-primary shadow-md h-full gap-2 py-4", children: [_jsxs(CardHeader, { className: "gap-1", children: [_jsx("span", { className: "text-muted-foreground font-mono text-xs", children: ownLabel }), _jsx(CardTitle, { className: "text-sm", children: entry.name })] }), _jsx(CardContent, { children: _jsx("p", { className: "text-muted-foreground text-pretty text-xs", children: entry.blurb }) })] }) }, entry.name))) })) : null] }), caption ? _jsx("p", { className: "text-muted-foreground mt-6 text-pretty text-sm", children: caption }) : null] }));
55
+ return (_jsxs(Section, { children: [title ? (_jsx(SectionHeading, { as: headingLevel, align: "left", eyebrow: eyebrow, title: title, description: description, className: "mb-12" })) : null, _jsxs("div", { "data-slot": "stack-grid", className: cn('flex flex-col gap-10', className), children: [_jsx("ul", { className: "grid gap-3 sm:grid-cols-2 lg:grid-cols-4", children: parts.map((part) => (_jsx("li", { children: _jsxs(Card, { className: "bg-muted h-full gap-2 py-4", children: [_jsxs(CardHeader, { className: "gap-1", children: [_jsx(CardTitle, { className: "text-sm", children: _jsx(Title, { children: part.name }) }), part.realName ? (_jsx("span", { className: "text-muted-foreground font-mono text-xs", children: part.realName })) : null] }), _jsx(CardContent, { children: _jsx("p", { className: "text-muted-foreground text-pretty text-xs", children: part.role }) })] }) }, part.name))) }), own && own.length > 0 ? (_jsx("ul", { "data-slot": "stack-grid-own", className: "grid gap-3 sm:grid-cols-2 lg:grid-cols-4", children: own.map((entry) => (_jsx("li", { children: _jsxs(Card, { className: "border-primary shadow-md h-full gap-2 py-4", children: [_jsxs(CardHeader, { className: "gap-1", children: [_jsx("span", { className: "text-muted-foreground font-mono text-xs", children: ownLabel }), _jsx(CardTitle, { className: "text-sm", children: _jsx(Title, { children: entry.name }) })] }), _jsx(CardContent, { children: _jsx("p", { className: "text-muted-foreground text-pretty text-xs", children: entry.blurb }) })] }) }, entry.name))) })) : null] }), caption ? _jsx("p", { className: "text-muted-foreground mt-6 text-pretty text-sm", children: caption }) : null] }));
48
56
  }
49
57
  export default StackGrid01;