rizzo-css 0.0.53 → 0.0.55

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 (252) hide show
  1. package/README.md +13 -8
  2. package/bin/rizzo-css.js +522 -120
  3. package/dist/rizzo.min.css +40 -16
  4. package/package.json +5 -4
  5. package/scaffold/astro/AlertDialog.astro +86 -0
  6. package/scaffold/astro/AspectRatio.astro +22 -0
  7. package/scaffold/astro/ButtonGroup.astro +16 -0
  8. package/scaffold/astro/Collapsible.astro +69 -0
  9. package/scaffold/astro/ContextMenu.astro +58 -0
  10. package/scaffold/astro/CopyToClipboard.astro +4 -0
  11. package/scaffold/astro/Dashboard.astro +74 -0
  12. package/scaffold/astro/Empty.astro +23 -0
  13. package/scaffold/astro/HoverCard.astro +64 -0
  14. package/scaffold/astro/Kbd.astro +14 -0
  15. package/scaffold/astro/Label.astro +24 -0
  16. package/scaffold/astro/Modal.astro +17 -2
  17. package/scaffold/astro/Popover.astro +62 -0
  18. package/scaffold/astro/ResizableHandle.astro +16 -0
  19. package/scaffold/astro/ResizablePane.astro +20 -0
  20. package/scaffold/astro/ResizablePaneGroup.astro +84 -0
  21. package/scaffold/astro/ScrollArea.astro +19 -0
  22. package/scaffold/astro/Separator.astro +18 -0
  23. package/scaffold/astro/Settings.astro +10 -2
  24. package/scaffold/astro/Sheet.astro +90 -0
  25. package/scaffold/astro/Skeleton.astro +16 -0
  26. package/scaffold/astro/Slider.astro +75 -0
  27. package/scaffold/astro/SoundEffects.astro +1 -0
  28. package/scaffold/astro/Switch.astro +37 -0
  29. package/scaffold/astro/Tabs.astro +1 -1
  30. package/scaffold/astro/ThemeSwitcher.astro +11 -4
  31. package/scaffold/astro/Toggle.astro +35 -0
  32. package/scaffold/astro/ToggleGroup.astro +24 -0
  33. package/scaffold/astro/base/README-RIZZO.md +55 -0
  34. package/scaffold/{astro-core → astro/base}/src/pages/index.astro +1 -1
  35. package/scaffold/astro/variants/dashboard/src/layouts/Layout.astro +85 -0
  36. package/scaffold/astro/variants/dashboard/src/pages/index.astro +110 -0
  37. package/scaffold/astro/variants/docs/src/layouts/Layout.astro +81 -0
  38. package/scaffold/astro/variants/docs/src/pages/docs/getting-started.astro +36 -0
  39. package/scaffold/astro/variants/docs/src/pages/index.astro +38 -0
  40. package/scaffold/{astro-core → astro/variants/full}/README-RIZZO.md +2 -1
  41. package/scaffold/astro/variants/full/astro.config.mjs +5 -0
  42. package/scaffold/astro/variants/full/dist/_noop-middleware.mjs +3 -0
  43. package/scaffold/astro/variants/full/dist/chunks/astro/server_9Mzx7luy.mjs +6023 -0
  44. package/scaffold/astro/variants/full/dist/chunks/astro_BOYUKg7r.mjs +1 -0
  45. package/scaffold/astro/variants/full/dist/favicon.svg +18 -0
  46. package/scaffold/astro/variants/full/dist/manifest_DXpJmqSX.mjs +154 -0
  47. package/scaffold/astro/variants/full/dist/noop-entrypoint.mjs +3 -0
  48. package/scaffold/astro/variants/full/dist/pages/index.astro.mjs +87 -0
  49. package/scaffold/astro/variants/full/dist/renderers.mjs +3 -0
  50. package/scaffold/astro/variants/full/gitignore +24 -0
  51. package/scaffold/astro/variants/full/node_modules/.astro/data-store.json +1 -0
  52. package/scaffold/astro/variants/full/node_modules/.vite/deps/_metadata.json +31 -0
  53. package/scaffold/astro/variants/full/node_modules/.vite/deps/astro___aria-query.js +6776 -0
  54. package/scaffold/astro/variants/full/node_modules/.vite/deps/astro___aria-query.js.map +7 -0
  55. package/scaffold/astro/variants/full/node_modules/.vite/deps/astro___axobject-query.js +3754 -0
  56. package/scaffold/astro/variants/full/node_modules/.vite/deps/astro___axobject-query.js.map +7 -0
  57. package/scaffold/astro/variants/full/node_modules/.vite/deps/astro___cssesc.js +99 -0
  58. package/scaffold/astro/variants/full/node_modules/.vite/deps/astro___cssesc.js.map +7 -0
  59. package/scaffold/astro/variants/full/node_modules/.vite/deps/chunk-BUSYA2B4.js +8 -0
  60. package/scaffold/astro/variants/full/node_modules/.vite/deps/chunk-BUSYA2B4.js.map +7 -0
  61. package/scaffold/astro/variants/full/node_modules/.vite/deps/package.json +3 -0
  62. package/scaffold/astro/variants/full/package.json +13 -0
  63. package/scaffold/astro/variants/full/public/.gitkeep +0 -0
  64. package/scaffold/astro/variants/full/public/favicon.svg +18 -0
  65. package/scaffold/astro/variants/full/src/components/rizzo/CopyToClipboard.astro +157 -0
  66. package/scaffold/astro/variants/full/src/components/rizzo/icons/Check.astro +29 -0
  67. package/scaffold/astro/variants/full/src/components/rizzo/icons/Copy.astro +30 -0
  68. package/scaffold/astro/variants/full/src/layouts/Layout.astro +34 -0
  69. package/scaffold/astro/variants/full/src/pages/index.astro +107 -0
  70. package/scaffold/astro/variants/full/tsconfig.json +5 -0
  71. package/scaffold/landing/index.html +13 -0
  72. package/scaffold/minimal/index.html +13 -0
  73. package/scaffold/shared/navbar-vanilla.html +59 -0
  74. package/scaffold/shared/sound-effects-inline.js +6 -1
  75. package/scaffold/starter/index.html +13 -0
  76. package/scaffold/svelte/AlertDialog.svelte +55 -0
  77. package/scaffold/svelte/AspectRatio.svelte +21 -0
  78. package/scaffold/svelte/BackToTop.svelte +1 -0
  79. package/scaffold/svelte/ButtonGroup.svelte +16 -0
  80. package/scaffold/svelte/Collapsible.svelte +57 -0
  81. package/scaffold/svelte/ContextMenu.svelte +60 -0
  82. package/scaffold/svelte/Dashboard.svelte +87 -0
  83. package/scaffold/svelte/Empty.svelte +36 -0
  84. package/scaffold/svelte/HoverCard.svelte +55 -0
  85. package/scaffold/svelte/Kbd.svelte +13 -0
  86. package/scaffold/svelte/Label.svelte +19 -0
  87. package/scaffold/svelte/Popover.svelte +59 -0
  88. package/scaffold/svelte/ResizableHandle.svelte +13 -0
  89. package/scaffold/svelte/ResizablePane.svelte +16 -0
  90. package/scaffold/svelte/ResizablePaneGroup.svelte +92 -0
  91. package/scaffold/svelte/ScrollArea.svelte +18 -0
  92. package/scaffold/svelte/Separator.svelte +14 -0
  93. package/scaffold/svelte/Sheet.svelte +62 -0
  94. package/scaffold/svelte/Skeleton.svelte +19 -0
  95. package/scaffold/svelte/Slider.svelte +57 -0
  96. package/scaffold/svelte/SoundEffects.svelte +3 -0
  97. package/scaffold/svelte/Switch.svelte +35 -0
  98. package/scaffold/svelte/Tabs.svelte +1 -1
  99. package/scaffold/svelte/Toggle.svelte +41 -0
  100. package/scaffold/svelte/ToggleGroup.svelte +30 -0
  101. package/scaffold/svelte/base/README-RIZZO.md +55 -0
  102. package/scaffold/{svelte-core → svelte/base}/src/routes/+page.svelte +1 -1
  103. package/scaffold/svelte/base/static/.gitkeep +0 -0
  104. package/scaffold/svelte/index.ts +21 -0
  105. package/scaffold/svelte/variants/dashboard/src/routes/+layout.svelte +64 -0
  106. package/scaffold/svelte/variants/dashboard/src/routes/+page.svelte +104 -0
  107. package/scaffold/svelte/variants/docs/src/routes/+layout.svelte +60 -0
  108. package/scaffold/svelte/variants/docs/src/routes/+page.svelte +34 -0
  109. package/scaffold/svelte/variants/docs/src/routes/docs/getting-started/+page.svelte +31 -0
  110. package/scaffold/{svelte-core → svelte/variants/full}/README-RIZZO.md +2 -1
  111. package/scaffold/svelte/variants/full/gitignore +10 -0
  112. package/scaffold/svelte/variants/full/package.json +20 -0
  113. package/scaffold/svelte/variants/full/src/app.d.ts +11 -0
  114. package/scaffold/svelte/variants/full/src/app.html +16 -0
  115. package/scaffold/svelte/variants/full/src/routes/+layout.svelte +1 -0
  116. package/scaffold/svelte/variants/full/src/routes/+page.svelte +105 -0
  117. package/scaffold/svelte/variants/full/static/.gitkeep +0 -0
  118. package/scaffold/svelte/variants/full/svelte.config.js +10 -0
  119. package/scaffold/svelte/variants/full/tsconfig.json +11 -0
  120. package/scaffold/vanilla/README-RIZZO.md +7 -6
  121. package/scaffold/vanilla/components/accordion.html +71 -64
  122. package/scaffold/vanilla/components/alert-dialog.html +640 -0
  123. package/scaffold/vanilla/components/alert.html +71 -64
  124. package/scaffold/vanilla/components/aspect-ratio.html +640 -0
  125. package/scaffold/vanilla/components/avatar.html +71 -64
  126. package/scaffold/vanilla/components/back-to-top.html +71 -64
  127. package/scaffold/vanilla/components/badge.html +71 -64
  128. package/scaffold/vanilla/components/breadcrumb.html +71 -64
  129. package/scaffold/vanilla/components/button-group.html +640 -0
  130. package/scaffold/vanilla/components/button.html +71 -64
  131. package/scaffold/vanilla/components/cards.html +71 -64
  132. package/scaffold/vanilla/components/collapsible.html +640 -0
  133. package/scaffold/vanilla/components/context-menu.html +640 -0
  134. package/scaffold/vanilla/components/copy-to-clipboard.html +71 -64
  135. package/scaffold/vanilla/components/dashboard.html +640 -0
  136. package/scaffold/vanilla/components/divider.html +71 -64
  137. package/scaffold/vanilla/components/docs-sidebar.html +71 -64
  138. package/scaffold/vanilla/components/dropdown.html +71 -64
  139. package/scaffold/vanilla/components/empty.html +640 -0
  140. package/scaffold/vanilla/components/font-switcher.html +71 -64
  141. package/scaffold/vanilla/components/footer.html +71 -64
  142. package/scaffold/vanilla/components/forms.html +71 -64
  143. package/scaffold/vanilla/components/hover-card.html +640 -0
  144. package/scaffold/vanilla/components/icons.html +71 -64
  145. package/scaffold/vanilla/components/index.html +91 -64
  146. package/scaffold/vanilla/components/kbd.html +640 -0
  147. package/scaffold/vanilla/components/label.html +640 -0
  148. package/scaffold/vanilla/components/modal.html +71 -64
  149. package/scaffold/vanilla/components/navbar.html +71 -64
  150. package/scaffold/vanilla/components/pagination.html +71 -64
  151. package/scaffold/vanilla/components/popover.html +640 -0
  152. package/scaffold/vanilla/components/progress-bar.html +71 -64
  153. package/scaffold/vanilla/components/resizable.html +640 -0
  154. package/scaffold/vanilla/components/scroll-area.html +640 -0
  155. package/scaffold/vanilla/components/search.html +71 -64
  156. package/scaffold/vanilla/components/separator.html +640 -0
  157. package/scaffold/vanilla/components/settings.html +71 -64
  158. package/scaffold/vanilla/components/sheet.html +640 -0
  159. package/scaffold/vanilla/components/skeleton.html +640 -0
  160. package/scaffold/vanilla/components/slider.html +640 -0
  161. package/scaffold/vanilla/components/sound-effects.html +71 -64
  162. package/scaffold/vanilla/components/spinner.html +71 -64
  163. package/scaffold/vanilla/components/switch.html +640 -0
  164. package/scaffold/vanilla/components/table.html +71 -64
  165. package/scaffold/vanilla/components/tabs.html +71 -64
  166. package/scaffold/vanilla/components/theme-switcher.html +71 -64
  167. package/scaffold/vanilla/components/toast.html +71 -64
  168. package/scaffold/vanilla/components/toggle-group.html +640 -0
  169. package/scaffold/vanilla/components/toggle.html +640 -0
  170. package/scaffold/vanilla/components/tooltip.html +71 -64
  171. package/scaffold/vanilla/index.html +73 -66
  172. package/scaffold/vanilla/variants/dashboard/index.html +45 -0
  173. package/scaffold/vanilla/variants/docs/index.html +36 -0
  174. package/scaffold/vanilla/variants/full/components/accordion.html +592 -0
  175. package/scaffold/vanilla/variants/full/components/alert.html +592 -0
  176. package/scaffold/vanilla/variants/full/components/avatar.html +592 -0
  177. package/scaffold/vanilla/variants/full/components/back-to-top.html +592 -0
  178. package/scaffold/vanilla/variants/full/components/badge.html +592 -0
  179. package/scaffold/vanilla/variants/full/components/breadcrumb.html +592 -0
  180. package/scaffold/vanilla/variants/full/components/button.html +592 -0
  181. package/scaffold/vanilla/variants/full/components/cards.html +592 -0
  182. package/scaffold/vanilla/variants/full/components/copy-to-clipboard.html +592 -0
  183. package/scaffold/vanilla/variants/full/components/dashboard.html +592 -0
  184. package/scaffold/vanilla/variants/full/components/divider.html +592 -0
  185. package/scaffold/vanilla/variants/full/components/docs-sidebar.html +592 -0
  186. package/scaffold/vanilla/variants/full/components/dropdown.html +592 -0
  187. package/scaffold/vanilla/variants/full/components/font-switcher.html +592 -0
  188. package/scaffold/vanilla/variants/full/components/footer.html +592 -0
  189. package/scaffold/vanilla/variants/full/components/forms.html +592 -0
  190. package/scaffold/vanilla/variants/full/components/icons.html +592 -0
  191. package/scaffold/vanilla/variants/full/components/index.html +625 -0
  192. package/scaffold/vanilla/variants/full/components/modal.html +592 -0
  193. package/scaffold/vanilla/variants/full/components/navbar.html +592 -0
  194. package/scaffold/vanilla/variants/full/components/pagination.html +592 -0
  195. package/scaffold/vanilla/variants/full/components/progress-bar.html +592 -0
  196. package/scaffold/vanilla/variants/full/components/search.html +592 -0
  197. package/scaffold/vanilla/variants/full/components/settings.html +592 -0
  198. package/scaffold/vanilla/variants/full/components/skeleton.html +592 -0
  199. package/scaffold/vanilla/variants/full/components/sound-effects.html +592 -0
  200. package/scaffold/vanilla/variants/full/components/spinner.html +592 -0
  201. package/scaffold/vanilla/variants/full/components/switch.html +592 -0
  202. package/scaffold/vanilla/variants/full/components/table.html +592 -0
  203. package/scaffold/vanilla/variants/full/components/tabs.html +592 -0
  204. package/scaffold/vanilla/variants/full/components/theme-switcher.html +592 -0
  205. package/scaffold/vanilla/variants/full/components/toast.html +592 -0
  206. package/scaffold/vanilla/variants/full/components/tooltip.html +592 -0
  207. package/scaffold/vanilla/variants/full/index.html +682 -0
  208. package/scaffold/vanilla/variants/full/js/main.js +989 -0
  209. package/scaffold/astro-core/.astro/content-assets.mjs +0 -1
  210. package/scaffold/astro-core/.astro/content-modules.mjs +0 -1
  211. package/scaffold/astro-core/.astro/content.d.ts +0 -199
  212. package/scaffold/astro-core/.astro/types.d.ts +0 -2
  213. package/scaffold/astro-core/.env.example +0 -3
  214. package/scaffold/svelte-core/.env.example +0 -3
  215. /package/scaffold/{astro-core → astro/base}/astro.config.mjs +0 -0
  216. /package/scaffold/{astro-core → astro/base}/dist/.gitkeep +0 -0
  217. /package/scaffold/{astro-core → astro/base}/dist/_noop-middleware.mjs +0 -0
  218. /package/scaffold/{astro-core → astro/base}/dist/chunks/astro/server_9Mzx7luy.mjs +0 -0
  219. /package/scaffold/{astro-core → astro/base}/dist/chunks/astro_BOYUKg7r.mjs +0 -0
  220. /package/scaffold/{astro-core → astro/base}/dist/favicon.svg +0 -0
  221. /package/scaffold/{astro-core → astro/base}/dist/manifest_DXpJmqSX.mjs +0 -0
  222. /package/scaffold/{astro-core → astro/base}/dist/noop-entrypoint.mjs +0 -0
  223. /package/scaffold/{astro-core → astro/base}/dist/pages/index.astro.mjs +0 -0
  224. /package/scaffold/{astro-core → astro/base}/dist/renderers.mjs +0 -0
  225. /package/scaffold/{astro-core → astro/base}/gitignore +0 -0
  226. /package/scaffold/{astro-core → astro/base}/node_modules/.astro/data-store.json +0 -0
  227. /package/scaffold/{astro-core → astro/base}/node_modules/.vite/deps/_metadata.json +0 -0
  228. /package/scaffold/{astro-core → astro/base}/node_modules/.vite/deps/astro___aria-query.js +0 -0
  229. /package/scaffold/{astro-core → astro/base}/node_modules/.vite/deps/astro___aria-query.js.map +0 -0
  230. /package/scaffold/{astro-core → astro/base}/node_modules/.vite/deps/astro___axobject-query.js +0 -0
  231. /package/scaffold/{astro-core → astro/base}/node_modules/.vite/deps/astro___axobject-query.js.map +0 -0
  232. /package/scaffold/{astro-core → astro/base}/node_modules/.vite/deps/astro___cssesc.js +0 -0
  233. /package/scaffold/{astro-core → astro/base}/node_modules/.vite/deps/astro___cssesc.js.map +0 -0
  234. /package/scaffold/{astro-core → astro/base}/node_modules/.vite/deps/chunk-BUSYA2B4.js +0 -0
  235. /package/scaffold/{astro-core → astro/base}/node_modules/.vite/deps/chunk-BUSYA2B4.js.map +0 -0
  236. /package/scaffold/{astro-core → astro/base}/node_modules/.vite/deps/package.json +0 -0
  237. /package/scaffold/{astro-core → astro/base}/package.json +0 -0
  238. /package/scaffold/{astro-core → astro/base}/public/.gitkeep +0 -0
  239. /package/scaffold/{astro-core → astro/base}/public/favicon.svg +0 -0
  240. /package/scaffold/{astro-core → astro/base}/src/components/rizzo/CopyToClipboard.astro +0 -0
  241. /package/scaffold/{astro-core → astro/base}/src/components/rizzo/icons/Check.astro +0 -0
  242. /package/scaffold/{astro-core → astro/base}/src/components/rizzo/icons/Copy.astro +0 -0
  243. /package/scaffold/{astro-core → astro/base}/src/layouts/Layout.astro +0 -0
  244. /package/scaffold/{astro-core → astro/base}/tsconfig.json +0 -0
  245. /package/scaffold/{svelte-core/static → astro/variants/full/dist}/.gitkeep +0 -0
  246. /package/scaffold/{svelte-core → svelte/base}/gitignore +0 -0
  247. /package/scaffold/{svelte-core → svelte/base}/package.json +0 -0
  248. /package/scaffold/{svelte-core → svelte/base}/src/app.d.ts +0 -0
  249. /package/scaffold/{svelte-core → svelte/base}/src/app.html +0 -0
  250. /package/scaffold/{svelte-core → svelte/base}/src/routes/+layout.svelte +0 -0
  251. /package/scaffold/{svelte-core → svelte/base}/svelte.config.js +0 -0
  252. /package/scaffold/{svelte-core → svelte/base}/tsconfig.json +0 -0
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "rizzo-css",
3
- "version": "0.0.53",
3
+ "version": "0.0.55",
4
+ "engines": { "node": ">=18" },
4
5
  "scripts": {
5
6
  "prepublishOnly": "cd ../.. && pnpm run lint:css:fix && pnpm run build:css && node scripts/copy-scaffold.js && node scripts/prepare-vanilla-scaffold.js"
6
7
  },
7
- "description": "A modern CSS design system with semantic theming, 14 themes, and accessible components (BEM). Optimized for Vanilla JS, Astro, and Svelte; same CSS and component styles for all.",
8
+ "description": "A modern CSS design system with semantic theming, 14 themes, accessible components (BEM), and pre-built blocks. Same CSS and components for Vanilla JS, Astro, and Svelte; CLI scaffolds with flat nav (Docs, Components, Blocks, Themes, Colors).",
8
9
  "style": "dist/rizzo.min.css",
9
10
  "main": "dist/rizzo.min.css",
10
11
  "unpkg": "dist/rizzo.min.css",
@@ -26,12 +27,12 @@
26
27
  "bin",
27
28
  "dist",
28
29
  "scaffold/astro",
29
- "scaffold/astro-core",
30
+ "scaffold/landing","scaffold/minimal",
30
31
  "scaffold/config",
31
32
  "scaffold/shared",
32
33
  "scaffold/svelte",
33
- "scaffold/svelte-core",
34
34
  "scaffold/utils",
35
+ "scaffold/starter",
35
36
  "scaffold/vanilla"
36
37
  ],
37
38
  "keywords": [
@@ -0,0 +1,86 @@
1
+ ---
2
+ /**
3
+ * Alert Dialog: modal for confirm/cancel actions (destructive or important).
4
+ * Uses role="alertdialog". Matches shadcn-svelte Alert Dialog.
5
+ */
6
+ import Close from './icons/Close.astro';
7
+
8
+ interface Props {
9
+ id?: string;
10
+ title?: string;
11
+ description?: string;
12
+ open?: boolean;
13
+ class?: string;
14
+ }
15
+
16
+ const { id, title = 'Are you sure?', description, open = false, class: className = '' } = Astro.props;
17
+ const dialogId = id || `alert-dialog-${Math.random().toString(36).slice(2, 9)}`;
18
+ ---
19
+
20
+ <div
21
+ class={`alert-dialog__overlay ${open ? 'alert-dialog__overlay--open' : ''}`.trim()}
22
+ data-alert-dialog-overlay
23
+ aria-hidden={!open}
24
+ id={`${dialogId}-overlay`}
25
+ ></div>
26
+ <div
27
+ class={`alert-dialog ${className}`.trim()}
28
+ role="alertdialog"
29
+ aria-modal="true"
30
+ aria-labelledby={`${dialogId}-title`}
31
+ aria-describedby={description ? `${dialogId}-desc` : undefined}
32
+ aria-hidden={!open}
33
+ id={dialogId}
34
+ data-alert-dialog
35
+ hidden={!open}
36
+ >
37
+ <div class="alert-dialog__content">
38
+ <h2 id={`${dialogId}-title`} class="alert-dialog__title">{title}</h2>
39
+ {description && (
40
+ <p id={`${dialogId}-desc`} class="alert-dialog__description">{description}</p>
41
+ )}
42
+ <div class="alert-dialog__actions">
43
+ <slot name="actions" />
44
+ </div>
45
+ </div>
46
+ </div>
47
+
48
+ <script is:inline define:vars={{ dialogId, open }}>
49
+ (function () {
50
+ function init() {
51
+ const dialog = document.getElementById(dialogId);
52
+ if (!dialog) return;
53
+ const overlay = document.getElementById(dialogId + '-overlay');
54
+ if (!overlay) return;
55
+ let escapeHandler = null;
56
+ const close = () => {
57
+ dialog.setAttribute('aria-hidden', 'true');
58
+ dialog.hidden = true;
59
+ overlay.classList.remove('alert-dialog__overlay--open');
60
+ overlay.setAttribute('aria-hidden', 'true');
61
+ if (escapeHandler) {
62
+ document.removeEventListener('keydown', escapeHandler);
63
+ escapeHandler = null;
64
+ }
65
+ };
66
+ const openDialog = () => {
67
+ dialog.removeAttribute('hidden');
68
+ dialog.setAttribute('aria-hidden', 'false');
69
+ overlay.classList.add('alert-dialog__overlay--open');
70
+ overlay.setAttribute('aria-hidden', 'false');
71
+ if (!escapeHandler) {
72
+ escapeHandler = (e) => { if (e.key === 'Escape') close(); };
73
+ document.addEventListener('keydown', escapeHandler);
74
+ }
75
+ };
76
+ dialog.querySelectorAll('[data-alert-dialog-close]').forEach((btn) => btn.addEventListener('click', close));
77
+ overlay.addEventListener('click', close);
78
+ dialog.addEventListener('keydown', (e) => { if (e.key === 'Escape') close(); });
79
+ window['openAlertDialog_' + dialogId.replace(/-/g, '_')] = openDialog;
80
+ window['closeAlertDialog_' + dialogId.replace(/-/g, '_')] = close;
81
+ if (open) openDialog();
82
+ }
83
+ if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
84
+ else init();
85
+ })();
86
+ </script>
@@ -0,0 +1,22 @@
1
+ ---
2
+ /**
3
+ * Enforces an aspect ratio on the child (e.g. 16/9, 1/1). Matches shadcn-svelte Aspect Ratio.
4
+ */
5
+ interface Props {
6
+ /** Ratio as width/height, e.g. 16/9, 1/1, 4/3 */
7
+ ratio?: number;
8
+ class?: string;
9
+ }
10
+
11
+ const { ratio = 16 / 9, class: className = '' } = Astro.props;
12
+ const paddingPercent = (1 / ratio) * 100;
13
+ ---
14
+
15
+ <div
16
+ class={`aspect-ratio ${className}`.trim()}
17
+ style={`--aspect-ratio: ${ratio}; --aspect-ratio-padding: ${paddingPercent}%;`}
18
+ >
19
+ <div class="aspect-ratio__inner">
20
+ <slot />
21
+ </div>
22
+ </div>
@@ -0,0 +1,16 @@
1
+ ---
2
+ /**
3
+ * Group of buttons attached together (no gap). Matches shadcn-svelte Button Group.
4
+ */
5
+ interface Props {
6
+ orientation?: 'horizontal' | 'vertical';
7
+ class?: string;
8
+ }
9
+
10
+ const { orientation = 'horizontal', class: className = '' } = Astro.props;
11
+ const orientationClass = orientation === 'vertical' ? 'button-group--vertical' : '';
12
+ ---
13
+
14
+ <div class={`button-group ${orientationClass} ${className}`.trim()} role="group">
15
+ <slot />
16
+ </div>
@@ -0,0 +1,69 @@
1
+ ---
2
+ /**
3
+ * Single expand/collapse section (one trigger, one panel). Use Accordion for multiple sections.
4
+ * Matches shadcn-svelte Collapsible pattern.
5
+ */
6
+ import ChevronDown from './icons/ChevronDown.astro';
7
+
8
+ interface Props {
9
+ id?: string;
10
+ defaultOpen?: boolean;
11
+ triggerLabel?: string;
12
+ class?: string;
13
+ }
14
+
15
+ const { id, defaultOpen = false, triggerLabel = 'Toggle', class: className = '' } = Astro.props;
16
+ const collapsibleId = id || `collapsible-${Math.random().toString(36).slice(2, 9)}`;
17
+ const triggerId = `${collapsibleId}-trigger`;
18
+ const panelId = `${collapsibleId}-panel`;
19
+ ---
20
+
21
+ <div class={`collapsible ${className}`.trim()} data-collapsible id={collapsibleId}>
22
+ <button
23
+ type="button"
24
+ class={`collapsible__trigger ${defaultOpen ? 'collapsible__trigger--open' : ''}`}
25
+ id={triggerId}
26
+ aria-expanded={defaultOpen}
27
+ aria-controls={panelId}
28
+ data-collapsible-trigger
29
+ >
30
+ <span class="collapsible__trigger-label">{triggerLabel}</span>
31
+ <ChevronDown class="collapsible__icon" width={16} height={16} aria-hidden="true" />
32
+ </button>
33
+ <div
34
+ class={`collapsible__panel ${defaultOpen ? 'collapsible__panel--open' : ''}`}
35
+ id={panelId}
36
+ role="region"
37
+ aria-labelledby={triggerId}
38
+ hidden={!defaultOpen}
39
+ data-collapsible-panel
40
+ >
41
+ <div class="collapsible__panel-inner">
42
+ <slot />
43
+ </div>
44
+ </div>
45
+ </div>
46
+
47
+ <script is:inline>
48
+ function initCollapsible() {
49
+ document.querySelectorAll('[data-collapsible]').forEach(function (root) {
50
+ if (root.dataset.collapsibleInit === 'true') return;
51
+ root.dataset.collapsibleInit = 'true';
52
+ var trigger = root.querySelector('[data-collapsible-trigger]');
53
+ var panel = root.querySelector('[data-collapsible-panel]');
54
+ if (!trigger || !panel) return;
55
+ trigger.addEventListener('click', function () {
56
+ var open = trigger.getAttribute('aria-expanded') === 'true';
57
+ trigger.setAttribute('aria-expanded', String(!open));
58
+ trigger.classList.toggle('collapsible__trigger--open', !open);
59
+ panel.classList.toggle('collapsible__panel--open', !open);
60
+ panel.hidden = open;
61
+ });
62
+ });
63
+ }
64
+ if (document.readyState === 'loading') {
65
+ document.addEventListener('DOMContentLoaded', initCollapsible);
66
+ } else {
67
+ initCollapsible();
68
+ }
69
+ </script>
@@ -0,0 +1,58 @@
1
+ ---
2
+ /**
3
+ * Right-click menu. Matches shadcn-svelte Context Menu.
4
+ */
5
+ interface Props {
6
+ id?: string;
7
+ class?: string;
8
+ }
9
+
10
+ const { id, class: className = '' } = Astro.props;
11
+ const ctxId = id || `context-menu-${Math.random().toString(36).slice(2, 9)}`;
12
+ ---
13
+
14
+ <div class={`context-menu ${className}`.trim()} data-context-menu id={ctxId}>
15
+ <slot name="trigger" />
16
+ <div
17
+ class="context-menu__content"
18
+ role="menu"
19
+ aria-hidden="true"
20
+ hidden
21
+ data-context-menu-content
22
+ id={`${ctxId}-content`}
23
+ >
24
+ <slot />
25
+ </div>
26
+ </div>
27
+
28
+ <script is:inline define:vars={{ ctxId }}>
29
+ (function () {
30
+ function init() {
31
+ const root = document.getElementById(ctxId);
32
+ if (!root) return;
33
+ const trigger = root.querySelector('[data-context-menu-trigger]');
34
+ const content = root.querySelector('[data-context-menu-content]');
35
+ if (!trigger || !content) return;
36
+ const close = () => {
37
+ content.classList.remove('context-menu__content--open');
38
+ content.hidden = true;
39
+ content.setAttribute('aria-hidden', 'true');
40
+ document.removeEventListener('click', close);
41
+ };
42
+ trigger.addEventListener('contextmenu', function (e) {
43
+ e.preventDefault();
44
+ content.hidden = false;
45
+ content.classList.add('context-menu__content--open');
46
+ content.setAttribute('aria-hidden', 'false');
47
+ content.style.left = e.clientX + 'px';
48
+ content.style.top = e.clientY + 'px';
49
+ requestAnimationFrame(() => document.addEventListener('click', close));
50
+ });
51
+ content.addEventListener('keydown', function (e) {
52
+ if (e.key === 'Escape') close();
53
+ });
54
+ }
55
+ if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
56
+ else init();
57
+ })();
58
+ </script>
@@ -12,6 +12,8 @@ interface Props {
12
12
  buttonLabel?: string;
13
13
  class?: string;
14
14
  id?: string;
15
+ /** When true, add data-color-copy so the colors page script can find and update this button. */
16
+ dataColorCopy?: boolean;
15
17
  }
16
18
 
17
19
  const {
@@ -22,6 +24,7 @@ const {
22
24
  buttonLabel,
23
25
  class: className = '',
24
26
  id,
27
+ dataColorCopy = false,
25
28
  } = Astro.props;
26
29
 
27
30
  const buttonId = id || `copy-btn-${Math.random().toString(36).substr(2, 9)}`;
@@ -41,6 +44,7 @@ const buttonClass = ['copy-to-clipboard', iconOnly ? 'copy-to-clipboard--icon-on
41
44
  id={buttonId}
42
45
  data-copy-icon-only={iconOnly ? 'true' : undefined}
43
46
  data-copy-button-label={iconOnly ? (buttonLabel || 'Copy') : undefined}
47
+ data-color-copy={dataColorCopy ? 'true' : undefined}
44
48
  >
45
49
  <span class="copy-to-clipboard__text">{displayText}</span>
46
50
  <span class="copy-to-clipboard__icon copy-to-clipboard__icon--copy" aria-hidden="true">
@@ -0,0 +1,74 @@
1
+ ---
2
+ interface Props {
3
+ /** Aria-label for the sidebar (e.g. "Dashboard navigation") */
4
+ sidebarLabel?: string;
5
+ /** Optional class for the root wrapper */
6
+ class?: string;
7
+ }
8
+
9
+ const { sidebarLabel = 'Dashboard navigation', class: className = '' } = Astro.props;
10
+ const classes = `dashboard ${className}`.trim();
11
+ ---
12
+
13
+ <div class={classes}>
14
+ <aside class="dashboard__sidebar" aria-label={sidebarLabel}>
15
+ <slot name="sidebar">
16
+ <nav class="dashboard__nav">
17
+ <a href="/" class="dashboard__nav-link dashboard__nav-link--active" aria-current="page">Dashboard</a>
18
+ <a href="/" class="dashboard__nav-link">Items</a>
19
+ <a href="/" class="dashboard__nav-link">Settings</a>
20
+ </nav>
21
+ </slot>
22
+ </aside>
23
+ <main id="main-content" class="dashboard__main">
24
+ <slot />
25
+ </main>
26
+ </div>
27
+
28
+ <style is:global>
29
+ .dashboard {
30
+ display: flex;
31
+ min-height: 100vh;
32
+ }
33
+ .dashboard__sidebar {
34
+ width: 16rem;
35
+ flex-shrink: 0;
36
+ border-right: 1px solid var(--border);
37
+ padding: var(--spacing-4);
38
+ background: var(--background-alt);
39
+ }
40
+ .dashboard__nav {
41
+ display: flex;
42
+ flex-direction: column;
43
+ gap: var(--spacing-1);
44
+ }
45
+ .dashboard__nav-link {
46
+ display: block;
47
+ padding: var(--spacing-2) var(--spacing-3);
48
+ border-radius: var(--radius-md);
49
+ color: var(--text);
50
+ text-decoration: none;
51
+ }
52
+ .dashboard__nav-link:hover {
53
+ background: var(--background);
54
+ }
55
+ .dashboard__nav-link--active {
56
+ background: var(--accent);
57
+ color: var(--accent-text);
58
+ }
59
+ .dashboard__main {
60
+ flex: 1;
61
+ padding: var(--spacing-6);
62
+ overflow: auto;
63
+ }
64
+ @media (max-width: 768px) {
65
+ .dashboard {
66
+ flex-direction: column;
67
+ }
68
+ .dashboard__sidebar {
69
+ width: 100%;
70
+ border-right: none;
71
+ border-bottom: 1px solid var(--border);
72
+ }
73
+ }
74
+ </style>
@@ -0,0 +1,23 @@
1
+ ---
2
+ /**
3
+ * Empty state: icon + title + optional description and action. Matches shadcn-svelte Empty.
4
+ */
5
+ interface Props {
6
+ title?: string;
7
+ description?: string;
8
+ class?: string;
9
+ }
10
+
11
+ const { title = 'No results', description, class: className = '' } = Astro.props;
12
+ ---
13
+
14
+ <div class={`empty ${className}`.trim()}>
15
+ <div class="empty__icon">
16
+ <slot name="icon" />
17
+ </div>
18
+ <h3 class="empty__title">{title}</h3>
19
+ {description && <p class="empty__description">{description}</p>}
20
+ <div class="empty__action">
21
+ <slot name="action" />
22
+ </div>
23
+ </div>
@@ -0,0 +1,64 @@
1
+ ---
2
+ /**
3
+ * Floating panel that opens on hover (with delay). Matches shadcn-svelte Hover Card.
4
+ */
5
+ interface Props {
6
+ id?: string;
7
+ openDelay?: number;
8
+ closeDelay?: number;
9
+ class?: string;
10
+ }
11
+
12
+ const { id, openDelay = 200, closeDelay = 100, class: className = '' } = Astro.props;
13
+ const hoverId = id || `hover-card-${Math.random().toString(36).slice(2, 9)}`;
14
+ ---
15
+
16
+ <div class={`hover-card ${className}`.trim()} data-hover-card id={hoverId}>
17
+ <slot name="trigger" />
18
+ <div
19
+ class="hover-card__content"
20
+ role="dialog"
21
+ aria-hidden="true"
22
+ hidden
23
+ data-hover-card-content
24
+ id={`${hoverId}-content`}
25
+ >
26
+ <slot />
27
+ </div>
28
+ </div>
29
+
30
+ <script is:inline define:vars={{ hoverId, openDelay, closeDelay }}>
31
+ (function () {
32
+ function init() {
33
+ const root = document.getElementById(hoverId);
34
+ if (!root) return;
35
+ const trigger = root.querySelector('[data-hover-card-trigger]');
36
+ const content = root.querySelector('[data-hover-card-content]');
37
+ if (!trigger || !content) return;
38
+ let openT = null;
39
+ let closeT = null;
40
+ const open = () => {
41
+ clearTimeout(closeT);
42
+ openT = setTimeout(() => {
43
+ content.hidden = false;
44
+ content.classList.add('hover-card__content--open');
45
+ content.setAttribute('aria-hidden', 'false');
46
+ }, openDelay);
47
+ };
48
+ const close = () => {
49
+ clearTimeout(openT);
50
+ closeT = setTimeout(() => {
51
+ content.classList.remove('hover-card__content--open');
52
+ content.hidden = true;
53
+ content.setAttribute('aria-hidden', 'true');
54
+ }, closeDelay);
55
+ };
56
+ trigger.addEventListener('mouseenter', open);
57
+ trigger.addEventListener('mouseleave', close);
58
+ content.addEventListener('mouseenter', open);
59
+ content.addEventListener('mouseleave', close);
60
+ }
61
+ if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
62
+ else init();
63
+ })();
64
+ </script>
@@ -0,0 +1,14 @@
1
+ ---
2
+ /**
3
+ * Keyboard key styling for shortcuts (e.g. Ctrl+K). Matches shadcn-svelte Kbd pattern.
4
+ */
5
+ interface Props {
6
+ class?: string;
7
+ }
8
+
9
+ const { class: className = '' } = Astro.props;
10
+ ---
11
+
12
+ <kbd class={`kbd ${className}`.trim()}>
13
+ <slot />
14
+ </kbd>
@@ -0,0 +1,24 @@
1
+ ---
2
+ /**
3
+ * Standalone label for form controls. Use with `for` to associate with an input id.
4
+ * Matches shadcn-svelte Label / Field label pattern.
5
+ */
6
+ interface Props {
7
+ for?: string;
8
+ required?: boolean;
9
+ class?: string;
10
+ }
11
+
12
+ const { for: forId, required = false, class: className = '' } = Astro.props;
13
+ const classes = ['label', required ? 'label--required' : '', className].filter(Boolean).join(' ');
14
+ ---
15
+
16
+ {forId ? (
17
+ <label for={forId} class={classes}>
18
+ <slot />
19
+ </label>
20
+ ) : (
21
+ <span class={classes}>
22
+ <slot />
23
+ </span>
24
+ )}
@@ -136,6 +136,15 @@ const classes = `modal ${sizeClass} ${className}`.trim();
136
136
  // Open modal
137
137
  const openModal = () => {
138
138
  previousActiveElement = document.activeElement;
139
+
140
+ if (overlay.parentNode !== document.body) {
141
+ document.body.appendChild(overlay);
142
+ document.body.appendChild(modal);
143
+ }
144
+ const layoutContent = document.querySelector('[data-layout-content]');
145
+ if (layoutContent) layoutContent.setAttribute('inert', '');
146
+ document.body.style.overflow = 'hidden';
147
+
139
148
  overlay.removeAttribute('inert');
140
149
  overlay.removeAttribute('hidden');
141
150
  overlay.setAttribute('aria-hidden', 'false');
@@ -145,11 +154,13 @@ const classes = `modal ${sizeClass} ${className}`.trim();
145
154
  modal.setAttribute('data-open', 'true');
146
155
  restoreFocusables(modal);
147
156
 
148
- // Focus first focusable element or close button
157
+ // Focus first focusable element or close button (after rAF so restored tabindex is applied)
149
158
  const focusableElements = getFocusableElements(modal);
150
159
  const firstFocusable = focusableElements.length > 0 ? focusableElements[0] : closeBtn;
151
160
  if (firstFocusable) {
152
- setTimeout(() => firstFocusable.focus(), 0);
161
+ requestAnimationFrame(() => {
162
+ firstFocusable.focus();
163
+ });
153
164
  }
154
165
 
155
166
  // Add focus trap
@@ -201,6 +212,10 @@ const classes = `modal ${sizeClass} ${className}`.trim();
201
212
  modal.setAttribute('aria-hidden', 'true');
202
213
  modal.removeAttribute('data-open');
203
214
 
215
+ const layoutContent = document.querySelector('[data-layout-content]');
216
+ if (layoutContent) layoutContent.removeAttribute('inert');
217
+ document.body.style.overflow = '';
218
+
204
219
  // Remove focus trap
205
220
  if (focusTrapHandler) {
206
221
  document.removeEventListener('keydown', focusTrapHandler);
@@ -0,0 +1,62 @@
1
+ ---
2
+ /**
3
+ * Floating panel triggered by a button. Matches shadcn-svelte Popover.
4
+ */
5
+ interface Props {
6
+ id?: string;
7
+ open?: boolean;
8
+ class?: string;
9
+ }
10
+
11
+ const { id, open = false, class: className = '' } = Astro.props;
12
+ const popoverId = id || `popover-${Math.random().toString(36).slice(2, 9)}`;
13
+ ---
14
+
15
+ <div class={`popover ${className}`.trim()} data-popover id={popoverId}>
16
+ <slot name="trigger" />
17
+ <div
18
+ class={`popover__content ${open ? 'popover__content--open' : ''}`.trim()}
19
+ role="dialog"
20
+ aria-modal="false"
21
+ aria-hidden={!open}
22
+ hidden={!open}
23
+ data-popover-content
24
+ id={`${popoverId}-content`}
25
+ >
26
+ <slot />
27
+ </div>
28
+ </div>
29
+
30
+ <script is:inline define:vars={{ popoverId, open }}>
31
+ (function () {
32
+ function init() {
33
+ const root = document.getElementById(popoverId);
34
+ if (!root) return;
35
+ const trigger = root.querySelector('[data-popover-trigger]');
36
+ const content = root.querySelector('[data-popover-content]');
37
+ if (!trigger || !content) return;
38
+ const close = () => {
39
+ content.classList.remove('popover__content--open');
40
+ content.hidden = true;
41
+ content.setAttribute('aria-hidden', 'true');
42
+ };
43
+ const toggle = () => {
44
+ const isOpen = !content.hidden;
45
+ if (isOpen) close();
46
+ else {
47
+ content.hidden = false;
48
+ content.classList.add('popover__content--open');
49
+ content.setAttribute('aria-hidden', 'false');
50
+ }
51
+ };
52
+ trigger.addEventListener('click', (e) => { e.preventDefault(); toggle(); });
53
+ document.addEventListener('click', (e) => {
54
+ if (!root.contains(e.target)) close();
55
+ });
56
+ content.addEventListener('keydown', (e) => { if (e.key === 'Escape') close(); });
57
+ if (open) toggle();
58
+ }
59
+ if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
60
+ else init();
61
+ })();
62
+ </script>
@@ -0,0 +1,16 @@
1
+ ---
2
+ /**
3
+ * Drag handle between two ResizablePanes. Use withHandle for a visible handle grip.
4
+ */
5
+ interface Props {
6
+ withHandle?: boolean;
7
+ class?: string;
8
+ }
9
+
10
+ const { withHandle = false, class: className = '' } = Astro.props;
11
+ ---
12
+
13
+ <div
14
+ class={`resizable__handle ${withHandle ? 'resizable__handle--with-handle' : ''} ${className}`.trim()}
15
+ data-resizable-handle
16
+ ></div>
@@ -0,0 +1,20 @@
1
+ ---
2
+ /**
3
+ * A single pane in a ResizablePaneGroup. Use defaultSize (0–100) for initial size %.
4
+ */
5
+ interface Props {
6
+ defaultSize?: number;
7
+ class?: string;
8
+ }
9
+
10
+ const { defaultSize = 50, class: className = '' } = Astro.props;
11
+ const size = Math.min(100, Math.max(0, defaultSize));
12
+ ---
13
+
14
+ <div
15
+ class={`resizable__pane ${className}`.trim()}
16
+ data-resizable-pane
17
+ style={`flex: 1 1 ${size}%`}
18
+ >
19
+ <slot />
20
+ </div>