rizzo-css 0.0.12 → 0.0.13

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 (230) hide show
  1. package/.env.example +12 -0
  2. package/LICENSE +21 -0
  3. package/README.md +17 -3
  4. package/bin/rizzo-css.js +93 -43
  5. package/package.json +5 -3
  6. package/scaffold/astro-app/README.md +13 -2
  7. package/scaffold/astro-app/src/components/Accordion.astro +178 -0
  8. package/scaffold/astro-app/src/components/Alert.astro +131 -0
  9. package/scaffold/astro-app/src/components/Avatar.astro +59 -0
  10. package/scaffold/astro-app/src/components/Badge.astro +24 -0
  11. package/scaffold/astro-app/src/components/Breadcrumb.astro +61 -0
  12. package/scaffold/astro-app/src/components/Button.astro +3 -0
  13. package/scaffold/astro-app/src/components/Card.astro +18 -0
  14. package/scaffold/astro-app/src/components/Checkbox.astro +38 -0
  15. package/scaffold/astro-app/src/components/CodeBlock.astro +393 -0
  16. package/scaffold/astro-app/src/components/CopyToClipboard.astro +219 -0
  17. package/scaffold/astro-app/src/components/Divider.astro +37 -0
  18. package/scaffold/astro-app/src/components/Dropdown.astro +807 -0
  19. package/scaffold/astro-app/src/components/FormGroup.astro +59 -0
  20. package/scaffold/astro-app/src/components/FrameworkSwitcher.astro +72 -0
  21. package/scaffold/astro-app/src/components/Input.astro +59 -0
  22. package/scaffold/astro-app/src/components/Modal.astro +212 -0
  23. package/scaffold/astro-app/src/components/Navbar.astro +701 -0
  24. package/scaffold/astro-app/src/components/Pagination.astro +240 -0
  25. package/scaffold/astro-app/src/components/ProgressBar.astro +65 -0
  26. package/scaffold/astro-app/src/components/Radio.astro +38 -0
  27. package/scaffold/astro-app/src/components/Search.astro +1259 -0
  28. package/scaffold/astro-app/src/components/Select.astro +49 -0
  29. package/scaffold/astro-app/src/components/Settings.astro +382 -0
  30. package/scaffold/astro-app/src/components/Spinner.astro +30 -0
  31. package/scaffold/astro-app/src/components/Table.astro +181 -0
  32. package/scaffold/astro-app/src/components/Tabs.astro +223 -0
  33. package/scaffold/astro-app/src/components/Textarea.astro +58 -0
  34. package/scaffold/astro-app/src/components/ThemeSwitcher.astro +504 -0
  35. package/scaffold/astro-app/src/components/Toast.astro +30 -0
  36. package/scaffold/astro-app/src/components/Tooltip.astro +32 -0
  37. package/scaffold/astro-app/src/components/icons/Brush.astro +10 -0
  38. package/scaffold/astro-app/src/components/icons/Cake.astro +11 -0
  39. package/scaffold/astro-app/src/components/icons/Check.astro +29 -0
  40. package/scaffold/astro-app/src/components/icons/Cherry.astro +11 -0
  41. package/scaffold/astro-app/src/components/icons/ChevronDown.astro +29 -0
  42. package/scaffold/astro-app/src/components/icons/Circle.astro +29 -0
  43. package/scaffold/astro-app/src/components/icons/Close.astro +30 -0
  44. package/scaffold/astro-app/src/components/icons/Cmd.astro +26 -0
  45. package/scaffold/astro-app/src/components/icons/Copy.astro +30 -0
  46. package/scaffold/astro-app/src/components/icons/Eye.astro +30 -0
  47. package/scaffold/astro-app/src/components/icons/Filter.astro +29 -0
  48. package/scaffold/astro-app/src/components/icons/Flame.astro +28 -0
  49. package/scaffold/astro-app/src/components/icons/Flower.astro +11 -0
  50. package/scaffold/astro-app/src/components/icons/Gear.astro +30 -0
  51. package/scaffold/astro-app/src/components/icons/Heart.astro +28 -0
  52. package/scaffold/astro-app/src/components/icons/IceCream.astro +31 -0
  53. package/scaffold/astro-app/src/components/icons/Leaf.astro +29 -0
  54. package/scaffold/astro-app/src/components/icons/Lemon.astro +11 -0
  55. package/scaffold/astro-app/src/components/icons/Moon.astro +29 -0
  56. package/scaffold/astro-app/src/components/icons/Owl.astro +34 -0
  57. package/scaffold/astro-app/src/components/icons/Palette.astro +33 -0
  58. package/scaffold/astro-app/src/components/icons/Rainbow.astro +31 -0
  59. package/scaffold/astro-app/src/components/icons/Search.astro +30 -0
  60. package/scaffold/astro-app/src/components/icons/Shield.astro +28 -0
  61. package/scaffold/astro-app/src/components/icons/Snowflake.astro +34 -0
  62. package/scaffold/astro-app/src/components/icons/Sort.astro +30 -0
  63. package/scaffold/astro-app/src/components/icons/Sun.astro +29 -0
  64. package/scaffold/astro-app/src/components/icons/Sunset.astro +10 -0
  65. package/scaffold/astro-app/src/components/icons/Zap.astro +9 -0
  66. package/scaffold/astro-app/src/components/icons/devicons/Astro.astro +53 -0
  67. package/scaffold/astro-app/src/components/icons/devicons/Bash.astro +34 -0
  68. package/scaffold/astro-app/src/components/icons/devicons/Css3.astro +29 -0
  69. package/scaffold/astro-app/src/components/icons/devicons/Git.astro +24 -0
  70. package/scaffold/astro-app/src/components/icons/devicons/Html5.astro +27 -0
  71. package/scaffold/astro-app/src/components/icons/devicons/Javascript.astro +25 -0
  72. package/scaffold/astro-app/src/components/icons/devicons/Nodejs.astro +47 -0
  73. package/scaffold/astro-app/src/components/icons/devicons/Plaintext.astro +33 -0
  74. package/scaffold/astro-app/src/components/icons/devicons/React.astro +27 -0
  75. package/scaffold/astro-app/src/components/icons/devicons/Svelte.astro +25 -0
  76. package/scaffold/astro-app/src/components/icons/devicons/Vue.astro +26 -0
  77. package/scaffold/astro-app/src/config/frameworks.ts +26 -0
  78. package/scaffold/astro-app/src/config/themes.ts +54 -0
  79. package/scaffold/astro-app/src/layouts/DocsLayout.astro +204 -0
  80. package/scaffold/astro-app/src/layouts/Layout.astro +11 -2
  81. package/scaffold/astro-app/src/pages/components/accordion.astro +172 -0
  82. package/scaffold/astro-app/src/pages/components/alert.astro +250 -0
  83. package/scaffold/astro-app/src/pages/components/avatar.astro +102 -0
  84. package/scaffold/astro-app/src/pages/components/badge.astro +119 -0
  85. package/scaffold/astro-app/src/pages/components/breadcrumb.astro +124 -0
  86. package/scaffold/astro-app/src/pages/components/button.astro +74 -0
  87. package/scaffold/astro-app/src/pages/components/cards.astro +247 -0
  88. package/scaffold/astro-app/src/pages/components/copy-to-clipboard.astro +49 -0
  89. package/scaffold/astro-app/src/pages/components/divider.astro +74 -0
  90. package/scaffold/astro-app/src/pages/components/dropdown.astro +394 -0
  91. package/scaffold/astro-app/src/pages/components/forms.astro +367 -0
  92. package/scaffold/astro-app/src/pages/components/icons.astro +246 -0
  93. package/scaffold/astro-app/src/pages/components/modal.astro +152 -0
  94. package/scaffold/astro-app/src/pages/components/navbar.astro +80 -0
  95. package/scaffold/astro-app/src/pages/components/pagination.astro +126 -0
  96. package/scaffold/astro-app/src/pages/components/progress-bar.astro +94 -0
  97. package/scaffold/astro-app/src/pages/components/search.astro +155 -0
  98. package/scaffold/astro-app/src/pages/components/settings.astro +78 -0
  99. package/scaffold/astro-app/src/pages/components/spinner.astro +81 -0
  100. package/scaffold/astro-app/src/pages/components/table.astro +144 -0
  101. package/scaffold/astro-app/src/pages/components/tabs.astro +220 -0
  102. package/scaffold/astro-app/src/pages/components/theme-switcher.astro +67 -0
  103. package/scaffold/astro-app/src/pages/components/toast.astro +157 -0
  104. package/scaffold/astro-app/src/pages/components/tooltip.astro +209 -0
  105. package/scaffold/astro-app/src/pages/components.astro +290 -0
  106. package/scaffold/astro-app/src/pages/docs/accessibility.astro +9 -0
  107. package/scaffold/astro-app/src/pages/docs/colors.astro +9 -0
  108. package/scaffold/astro-app/src/pages/docs/design-system.astro +9 -0
  109. package/scaffold/astro-app/src/pages/docs/getting-started.astro +9 -0
  110. package/scaffold/astro-app/src/pages/docs/index.astro +15 -0
  111. package/scaffold/astro-app/src/pages/docs/themes/[theme].astro +14 -0
  112. package/scaffold/astro-app/src/pages/docs/theming.astro +10 -0
  113. package/scaffold/astro-app/src/pages/index.astro +5 -11
  114. package/scaffold/svelte-app/README.md +9 -2
  115. package/scaffold/svelte-app/src/app.html +1 -1
  116. package/scaffold/svelte-app/src/lib/rizzo/Accordion.svelte +128 -0
  117. package/scaffold/svelte-app/src/lib/rizzo/Alert.svelte +85 -0
  118. package/scaffold/svelte-app/src/lib/rizzo/Avatar.svelte +39 -0
  119. package/scaffold/svelte-app/src/lib/rizzo/Badge.svelte +31 -0
  120. package/scaffold/svelte-app/src/lib/rizzo/Breadcrumb.svelte +49 -0
  121. package/scaffold/svelte-app/src/lib/rizzo/Button.svelte +27 -0
  122. package/scaffold/svelte-app/src/lib/rizzo/Card.svelte +17 -0
  123. package/scaffold/svelte-app/src/lib/rizzo/Checkbox.svelte +37 -0
  124. package/scaffold/svelte-app/src/lib/rizzo/CopyToClipboard.svelte +79 -0
  125. package/scaffold/svelte-app/src/lib/rizzo/Divider.svelte +28 -0
  126. package/scaffold/svelte-app/src/lib/rizzo/Dropdown.svelte +254 -0
  127. package/scaffold/svelte-app/src/lib/rizzo/FormGroup.svelte +51 -0
  128. package/scaffold/svelte-app/src/lib/rizzo/Input.svelte +59 -0
  129. package/scaffold/svelte-app/src/lib/rizzo/Modal.svelte +157 -0
  130. package/scaffold/svelte-app/src/lib/rizzo/Pagination.svelte +93 -0
  131. package/scaffold/svelte-app/src/lib/rizzo/ProgressBar.svelte +58 -0
  132. package/scaffold/svelte-app/src/lib/rizzo/Radio.svelte +38 -0
  133. package/scaffold/svelte-app/src/lib/rizzo/Select.svelte +51 -0
  134. package/scaffold/svelte-app/src/lib/rizzo/Spinner.svelte +14 -0
  135. package/scaffold/svelte-app/src/lib/rizzo/Table.svelte +158 -0
  136. package/scaffold/svelte-app/src/lib/rizzo/Tabs.svelte +117 -0
  137. package/scaffold/svelte-app/src/lib/rizzo/Textarea.svelte +59 -0
  138. package/scaffold/svelte-app/src/lib/rizzo/ThemeSwitcher.svelte +315 -0
  139. package/scaffold/svelte-app/src/lib/rizzo/Toast.svelte +33 -0
  140. package/scaffold/svelte-app/src/lib/rizzo/Tooltip.svelte +19 -0
  141. package/scaffold/svelte-app/src/lib/rizzo/icons/Check.svelte +29 -0
  142. package/scaffold/svelte-app/src/lib/rizzo/icons/ChevronDown.svelte +29 -0
  143. package/scaffold/svelte-app/src/lib/rizzo/icons/Circle.svelte +29 -0
  144. package/scaffold/svelte-app/src/lib/rizzo/icons/Close.svelte +30 -0
  145. package/scaffold/svelte-app/src/lib/rizzo/icons/Cmd.svelte +27 -0
  146. package/scaffold/svelte-app/src/lib/rizzo/icons/Copy.svelte +30 -0
  147. package/scaffold/svelte-app/src/lib/rizzo/icons/Eye.svelte +30 -0
  148. package/scaffold/svelte-app/src/lib/rizzo/icons/Filter.svelte +29 -0
  149. package/scaffold/svelte-app/src/lib/rizzo/icons/Gear.svelte +30 -0
  150. package/scaffold/svelte-app/src/lib/rizzo/icons/IceCream.svelte +31 -0
  151. package/scaffold/svelte-app/src/lib/rizzo/icons/Moon.svelte +29 -0
  152. package/scaffold/svelte-app/src/lib/rizzo/icons/Owl.svelte +34 -0
  153. package/scaffold/svelte-app/src/lib/rizzo/icons/Palette.svelte +33 -0
  154. package/scaffold/svelte-app/src/lib/rizzo/icons/Rainbow.svelte +31 -0
  155. package/scaffold/svelte-app/src/lib/rizzo/icons/Search.svelte +30 -0
  156. package/scaffold/svelte-app/src/lib/rizzo/icons/Snowflake.svelte +34 -0
  157. package/scaffold/svelte-app/src/lib/rizzo/icons/Sort.svelte +30 -0
  158. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Astro.svelte +45 -0
  159. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Bash.svelte +28 -0
  160. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Css3.svelte +23 -0
  161. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Git.svelte +18 -0
  162. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Html5.svelte +21 -0
  163. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Javascript.svelte +19 -0
  164. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Nodejs.svelte +44 -0
  165. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Plaintext.svelte +24 -0
  166. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/React.svelte +21 -0
  167. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/SvelteIcon.svelte +19 -0
  168. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Vue.svelte +20 -0
  169. package/scaffold/svelte-app/src/lib/rizzo/index.ts +33 -0
  170. package/scaffold/svelte-app/src/lib/rizzo-docs/CodeBlock.svelte +239 -0
  171. package/scaffold/svelte-app/src/lib/rizzo-docs/SvelteDocPage.svelte +99 -0
  172. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/AccordionDoc.svelte +53 -0
  173. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/AlertDoc.svelte +114 -0
  174. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/AvatarDoc.svelte +92 -0
  175. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/BadgeDoc.svelte +60 -0
  176. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/BreadcrumbDoc.svelte +55 -0
  177. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/ButtonDoc.svelte +55 -0
  178. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/CardsDoc.svelte +173 -0
  179. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/ComingSoon.svelte +12 -0
  180. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/ComponentsOverview.svelte +92 -0
  181. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/CopyToClipboardDoc.svelte +26 -0
  182. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/DividerDoc.svelte +105 -0
  183. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/DropdownDoc.svelte +161 -0
  184. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/FormsDoc.svelte +375 -0
  185. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/IconsDoc.svelte +246 -0
  186. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/Index.svelte +8 -0
  187. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/ModalDoc.svelte +50 -0
  188. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/NavbarDoc.svelte +79 -0
  189. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/PaginationDoc.svelte +44 -0
  190. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/ProgressBarDoc.svelte +95 -0
  191. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/SearchDoc.svelte +147 -0
  192. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/SettingsDoc.svelte +158 -0
  193. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/SpinnerDoc.svelte +41 -0
  194. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/TableDoc.svelte +116 -0
  195. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/TabsDoc.svelte +152 -0
  196. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/ThemeSwitcherDoc.svelte +181 -0
  197. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/Theming.svelte +6 -0
  198. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/ToastDoc.svelte +136 -0
  199. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/TooltipDoc.svelte +57 -0
  200. package/scaffold/svelte-app/src/routes/+page.svelte +2 -2
  201. package/scaffold/svelte-app/src/routes/components/+page.svelte +4 -0
  202. package/scaffold/svelte-app/src/routes/components/[slug]/+page.svelte +7 -0
  203. package/scaffold/vanilla/README.md +11 -4
  204. package/scaffold/vanilla/components/accordion.html +187 -0
  205. package/scaffold/vanilla/components/alert.html +187 -0
  206. package/scaffold/vanilla/components/avatar.html +187 -0
  207. package/scaffold/vanilla/components/badge.html +187 -0
  208. package/scaffold/vanilla/components/breadcrumb.html +187 -0
  209. package/scaffold/vanilla/components/button.html +187 -0
  210. package/scaffold/vanilla/components/cards.html +187 -0
  211. package/scaffold/vanilla/components/copy-to-clipboard.html +187 -0
  212. package/scaffold/vanilla/components/divider.html +187 -0
  213. package/scaffold/vanilla/components/dropdown.html +187 -0
  214. package/scaffold/vanilla/components/forms.html +187 -0
  215. package/scaffold/vanilla/components/icons.html +187 -0
  216. package/scaffold/vanilla/components/index.html +212 -0
  217. package/scaffold/vanilla/components/modal.html +187 -0
  218. package/scaffold/vanilla/components/navbar.html +187 -0
  219. package/scaffold/vanilla/components/pagination.html +187 -0
  220. package/scaffold/vanilla/components/progress-bar.html +187 -0
  221. package/scaffold/vanilla/components/search.html +187 -0
  222. package/scaffold/vanilla/components/settings.html +187 -0
  223. package/scaffold/vanilla/components/spinner.html +187 -0
  224. package/scaffold/vanilla/components/table.html +187 -0
  225. package/scaffold/vanilla/components/tabs.html +187 -0
  226. package/scaffold/vanilla/components/theme-switcher.html +187 -0
  227. package/scaffold/vanilla/components/toast.html +187 -0
  228. package/scaffold/vanilla/components/tooltip.html +187 -0
  229. package/scaffold/vanilla/index.html +16 -6
  230. package/scaffold/vanilla/js/main.js +4 -3
@@ -0,0 +1,393 @@
1
+ ---
2
+ import Copy from './icons/Copy.astro';
3
+ import Check from './icons/Check.astro';
4
+ import Css3 from './icons/devicons/Css3.astro';
5
+ import Html5 from './icons/devicons/Html5.astro';
6
+ import Javascript from './icons/devicons/Javascript.astro';
7
+ import Nodejs from './icons/devicons/Nodejs.astro';
8
+ import AstroIcon from './icons/devicons/Astro.astro';
9
+ import Plaintext from './icons/devicons/Plaintext.astro';
10
+ import Git from './icons/devicons/Git.astro';
11
+ import Bash from './icons/devicons/Bash.astro';
12
+ import Svelte from './icons/devicons/Svelte.astro';
13
+ import React from './icons/devicons/React.astro';
14
+ import Vue from './icons/devicons/Vue.astro';
15
+
16
+ interface Props {
17
+ code: string;
18
+ language?: string;
19
+ class?: string;
20
+ }
21
+
22
+ const {
23
+ code,
24
+ language = '',
25
+ class: className = '',
26
+ } = Astro.props;
27
+
28
+ const languageLabel = language || '';
29
+ const languageLower = language.toLowerCase();
30
+
31
+ const codeId = `code-${Math.random().toString(36).substr(2, 9)}`;
32
+ const copyButtonId = `copy-btn-${Math.random().toString(36).substr(2, 9)}`;
33
+ ---
34
+
35
+ <div class={`code-block ${className}`.trim()}>
36
+ <div class="code-block__header">
37
+ {language && (
38
+ <span class="code-block__language" aria-label={languageLabel}>
39
+ {languageLower === 'css' && (
40
+ <>
41
+ <Css3 width={20} height={20} class="code-block__language-icon" />
42
+ <span class="code-block__language-text">{languageLabel}</span>
43
+ </>
44
+ )}
45
+ {languageLower === 'html' && (
46
+ <>
47
+ <Html5 width={20} height={20} class="code-block__language-icon" />
48
+ <span class="code-block__language-text">{languageLabel}</span>
49
+ </>
50
+ )}
51
+ {languageLower === 'javascript' && (
52
+ <>
53
+ <Javascript width={20} height={20} class="code-block__language-icon" />
54
+ <span class="code-block__language-text">{languageLabel}</span>
55
+ </>
56
+ )}
57
+ {languageLower === 'nodejs' && (
58
+ <>
59
+ <Nodejs width={20} height={20} class="code-block__language-icon" />
60
+ <span class="code-block__language-text">{languageLabel}</span>
61
+ </>
62
+ )}
63
+ {languageLower === 'astro' && (
64
+ <>
65
+ <AstroIcon width={20} height={20} class="code-block__language-icon" />
66
+ <span class="code-block__language-text">{languageLabel}</span>
67
+ </>
68
+ )}
69
+ {languageLower === 'plaintext' && (
70
+ <>
71
+ <Plaintext width={20} height={20} class="code-block__language-icon" />
72
+ <span class="code-block__language-text">{languageLabel}</span>
73
+ </>
74
+ )}
75
+ {languageLower === 'git' && (
76
+ <>
77
+ <Git width={20} height={20} class="code-block__language-icon" />
78
+ <span class="code-block__language-text">{languageLabel}</span>
79
+ </>
80
+ )}
81
+ {languageLower === 'svelte' && (
82
+ <>
83
+ <Svelte width={20} height={20} class="code-block__language-icon" />
84
+ <span class="code-block__language-text">{languageLabel}</span>
85
+ </>
86
+ )}
87
+ {(languageLower === 'react' || languageLower === 'jsx' || languageLower === 'tsx') && (
88
+ <>
89
+ <React width={20} height={20} class="code-block__language-icon" />
90
+ <span class="code-block__language-text">{languageLabel}</span>
91
+ </>
92
+ )}
93
+ {languageLower === 'vue' && (
94
+ <>
95
+ <Vue width={20} height={20} class="code-block__language-icon" />
96
+ <span class="code-block__language-text">{languageLabel}</span>
97
+ </>
98
+ )}
99
+ {(languageLower === 'bash' || languageLower === 'shell' || languageLower === 'sh') && (
100
+ <>
101
+ <Bash width={20} height={20} class="code-block__language-icon" />
102
+ <span class="code-block__language-text">{languageLabel}</span>
103
+ </>
104
+ )}
105
+ {!['css', 'html', 'javascript', 'nodejs', 'astro', 'plaintext', 'git', 'svelte', 'react', 'jsx', 'tsx', 'vue', 'bash', 'shell', 'sh'].includes(languageLower) && (
106
+ <span class="code-block__language-text">{language}</span>
107
+ )}
108
+ <span class="sr-only">{languageLabel}</span>
109
+ </span>
110
+ )}
111
+ <span class="tooltip-host" data-tooltip="Copy code to clipboard">
112
+ <button
113
+ type="button"
114
+ class="code-block__copy-btn"
115
+ aria-label="Copy code to clipboard"
116
+ data-code-id={codeId}
117
+ id={copyButtonId}
118
+ >
119
+ <span class="code-block__copy-icon code-block__copy-icon--copy" aria-hidden="true">
120
+ <Copy width={20} height={20} />
121
+ </span>
122
+ <span class="code-block__copy-icon code-block__copy-icon--check" aria-hidden="true">
123
+ <Check width={20} height={20} />
124
+ </span>
125
+ <span class="sr-only">Copy code</span>
126
+ </button>
127
+ </span>
128
+ </div>
129
+ <pre><code id={codeId}>{code}</code></pre>
130
+ </div>
131
+
132
+ <script is:inline>
133
+ (function initCodeBlockCopy() {
134
+ const init = () => {
135
+ const copyButtons = document.querySelectorAll('.code-block__copy-btn');
136
+
137
+ copyButtons.forEach((button) => {
138
+ if (button.hasAttribute('data-copy-initialized')) return;
139
+ button.setAttribute('data-copy-initialized', 'true');
140
+
141
+ const codeId = button.getAttribute('data-code-id');
142
+ if (!codeId) return;
143
+
144
+ const codeElement = document.getElementById(codeId);
145
+ if (!codeElement) return;
146
+
147
+ const copyIcon = button.querySelector('.code-block__copy-icon--copy');
148
+ const checkIcon = button.querySelector('.code-block__copy-icon--check');
149
+
150
+ // Remove title elements from SVG icons to prevent tooltip conflicts
151
+ const copyIconSvg = copyIcon?.querySelector('svg');
152
+ const checkIconSvg = checkIcon?.querySelector('svg');
153
+ if (copyIconSvg) {
154
+ const copyTitle = copyIconSvg.querySelector('title');
155
+ if (copyTitle) copyTitle.remove();
156
+ }
157
+ if (checkIconSvg) {
158
+ const checkTitle = checkIconSvg.querySelector('title');
159
+ if (checkTitle) checkTitle.remove();
160
+ }
161
+
162
+ const copyToClipboard = async () => {
163
+ const codeText = codeElement.textContent || '';
164
+
165
+ if (!codeText) return;
166
+
167
+ try {
168
+ await navigator.clipboard.writeText(codeText);
169
+
170
+ // Show success state
171
+ if (copyIcon) copyIcon.classList.add('code-block__copy-icon--hidden');
172
+ if (checkIcon) checkIcon.classList.remove('code-block__copy-icon--hidden');
173
+ button.setAttribute('aria-label', 'Code copied!');
174
+ const tooltipHost = button.closest('.tooltip-host');
175
+ if (tooltipHost) tooltipHost.setAttribute('data-tooltip', 'Code copied!');
176
+
177
+ // Reset after 2 seconds
178
+ setTimeout(() => {
179
+ if (copyIcon) copyIcon.classList.remove('code-block__copy-icon--hidden');
180
+ if (checkIcon) checkIcon.classList.add('code-block__copy-icon--hidden');
181
+ button.setAttribute('aria-label', 'Copy code to clipboard');
182
+ if (tooltipHost) tooltipHost.setAttribute('data-tooltip', 'Copy code to clipboard');
183
+ }, 2000);
184
+ } catch (err) {
185
+ // Fallback for older browsers
186
+ const textArea = document.createElement('textarea');
187
+ textArea.value = codeText;
188
+ textArea.style.position = 'fixed';
189
+ textArea.style.left = '-999999px';
190
+ document.body.appendChild(textArea);
191
+ textArea.focus();
192
+ textArea.select();
193
+
194
+ try {
195
+ document.execCommand('copy');
196
+ if (copyIcon) copyIcon.classList.add('code-block__copy-icon--hidden');
197
+ if (checkIcon) checkIcon.classList.remove('code-block__copy-icon--hidden');
198
+ button.setAttribute('aria-label', 'Code copied!');
199
+ const tooltipHostFallback = button.closest('.tooltip-host');
200
+ if (tooltipHostFallback) tooltipHostFallback.setAttribute('data-tooltip', 'Code copied!');
201
+
202
+ setTimeout(() => {
203
+ if (copyIcon) copyIcon.classList.remove('code-block__copy-icon--hidden');
204
+ if (checkIcon) checkIcon.classList.add('code-block__copy-icon--hidden');
205
+ button.setAttribute('aria-label', 'Copy code to clipboard');
206
+ if (tooltipHostFallback) tooltipHostFallback.setAttribute('data-tooltip', 'Copy code to clipboard');
207
+ }, 2000);
208
+ } catch (fallbackErr) {
209
+ console.error('Failed to copy:', fallbackErr);
210
+ }
211
+
212
+ document.body.removeChild(textArea);
213
+ }
214
+ };
215
+
216
+ button.addEventListener('click', copyToClipboard);
217
+
218
+ // Keyboard support
219
+ button.addEventListener('keydown', (e) => {
220
+ if (e && 'key' in e) {
221
+ const keyEvent = e;
222
+ if (keyEvent.key === 'Enter' || keyEvent.key === ' ') {
223
+ keyEvent.preventDefault();
224
+ copyToClipboard();
225
+ }
226
+ }
227
+ });
228
+ });
229
+ };
230
+
231
+ if (document.readyState === 'loading') {
232
+ document.addEventListener('DOMContentLoaded', init);
233
+ } else {
234
+ init();
235
+ }
236
+ })();
237
+ </script>
238
+
239
+ <style>
240
+ .code-block {
241
+ position: relative;
242
+ margin: var(--spacing-4) 0;
243
+ border-radius: var(--radius-lg);
244
+ overflow: visible;
245
+ background-color: var(--background-alt);
246
+ border: 1px solid var(--border);
247
+ }
248
+
249
+ .code-block__header {
250
+ display: flex;
251
+ align-items: center;
252
+ justify-content: space-between;
253
+ padding: var(--spacing-2) var(--spacing-3);
254
+ background-color: var(--background);
255
+ border-bottom: 1px solid var(--border);
256
+ border-radius: var(--radius-lg) var(--radius-lg) 0 0;
257
+ overflow: visible;
258
+ position: relative;
259
+ z-index: 1;
260
+ }
261
+
262
+ .code-block__language {
263
+ display: flex;
264
+ align-items: center;
265
+ gap: var(--spacing-2);
266
+ font-size: var(--font-size-xs);
267
+ color: var(--text-dim);
268
+ text-transform: uppercase;
269
+ letter-spacing: var(--letter-spacing-wider);
270
+ font-weight: var(--font-weight-medium);
271
+ }
272
+
273
+ .code-block__language-icon {
274
+ display: block;
275
+ flex-shrink: 0;
276
+ color: var(--text-dim);
277
+ width: var(--spacing-5); /* 20px - larger for better visibility */
278
+ height: var(--spacing-5);
279
+ }
280
+
281
+ .code-block__language-icon svg {
282
+ width: 100%;
283
+ height: 100%;
284
+ }
285
+
286
+ .code-block__language-text {
287
+ display: none;
288
+ }
289
+
290
+ /* Show text next to icon on large screens */
291
+ @media (width >= 768px) {
292
+ .code-block__language-text {
293
+ display: inline;
294
+ }
295
+ }
296
+
297
+ .code-block__copy-btn {
298
+ display: flex;
299
+ align-items: center;
300
+ justify-content: center;
301
+ padding: var(--spacing-2);
302
+ min-width: var(--spacing-8);
303
+ height: var(--spacing-8);
304
+ margin-left: auto;
305
+ background-color: var(--background-alt);
306
+ border: 1px solid var(--border);
307
+ border-radius: var(--radius-md);
308
+ color: var(--text);
309
+ cursor: pointer;
310
+ transition: background-color var(--transition-base), border-color var(--transition-base), color var(--transition-base);
311
+ position: relative;
312
+ }
313
+
314
+ .code-block__copy-btn:hover {
315
+ background-color: var(--background);
316
+ border-color: var(--accent);
317
+ color: var(--accent);
318
+ }
319
+
320
+ .code-block__copy-btn:focus-visible {
321
+ outline: var(--outline-width) solid var(--accent);
322
+ outline-offset: var(--outline-offset);
323
+ }
324
+
325
+ .code-block__copy-icon {
326
+ position: absolute;
327
+ display: flex;
328
+ align-items: center;
329
+ justify-content: center;
330
+ width: var(--spacing-5); /* 20px - larger for better visibility */
331
+ height: var(--spacing-5);
332
+ transition: opacity var(--transition-base), transform var(--transition-base);
333
+ }
334
+
335
+ .code-block__copy-icon svg {
336
+ width: 100%;
337
+ height: 100%;
338
+ }
339
+
340
+ .code-block__copy-icon--copy {
341
+ opacity: 1;
342
+ transform: scale(1);
343
+ }
344
+
345
+ .code-block__copy-icon--check {
346
+ opacity: 0;
347
+ transform: scale(0.8);
348
+ }
349
+
350
+ .code-block__copy-icon--check:not(.code-block__copy-icon--hidden) {
351
+ opacity: 1;
352
+ transform: scale(1);
353
+ }
354
+
355
+ .code-block__copy-icon--copy.code-block__copy-icon--hidden {
356
+ opacity: 0;
357
+ transform: scale(0.8);
358
+ }
359
+
360
+ .code-block pre {
361
+ margin: 0;
362
+ padding: var(--spacing-4);
363
+ overflow-x: auto;
364
+ background-color: var(--background-alt);
365
+ border-radius: 0 0 var(--radius-lg) var(--radius-lg);
366
+ }
367
+
368
+ .code-block code {
369
+ font-family: var(--font-family-mono);
370
+ font-size: var(--font-size-sm);
371
+ line-height: var(--line-height-relaxed);
372
+ color: var(--text);
373
+ white-space: pre;
374
+ word-wrap: normal;
375
+ }
376
+
377
+ @media (width <= 640px) {
378
+ .code-block__header {
379
+ flex-direction: row; /* Keep horizontal layout on mobile */
380
+ align-items: center; /* Vertically center all items */
381
+ gap: var(--spacing-2);
382
+ }
383
+
384
+ .code-block__language {
385
+ align-items: center; /* Ensure language icon is vertically centered */
386
+ }
387
+
388
+ .code-block__copy-btn {
389
+ margin-left: auto; /* Push copy button to the right */
390
+ flex-shrink: 0; /* Prevent copy button from shrinking */
391
+ }
392
+ }
393
+ </style>
@@ -0,0 +1,219 @@
1
+ ---
2
+ import Copy from './icons/Copy.astro';
3
+ import Check from './icons/Check.astro';
4
+
5
+ interface Props {
6
+ value: string;
7
+ label?: string;
8
+ format?: string;
9
+ class?: string;
10
+ id?: string;
11
+ }
12
+
13
+ const {
14
+ value,
15
+ label,
16
+ format,
17
+ class: className = '',
18
+ id,
19
+ } = Astro.props;
20
+
21
+ const buttonId = id || `copy-btn-${Math.random().toString(36).substr(2, 9)}`;
22
+ const defaultTooltip = label || 'Copy to clipboard';
23
+ ---
24
+
25
+ <span class="tooltip-host" data-tooltip={defaultTooltip}>
26
+ <button
27
+ type="button"
28
+ class={`copy-to-clipboard ${className}`.trim()}
29
+ data-copy-value={value}
30
+ data-copy-format={format}
31
+ aria-label={label || `Copy ${value} to clipboard`}
32
+ id={buttonId}
33
+ >
34
+ <span class="copy-to-clipboard__text">{value}</span>
35
+ <span class="copy-to-clipboard__icon copy-to-clipboard__icon--copy" aria-hidden="true">
36
+ <Copy width={16} height={16} />
37
+ </span>
38
+ <span class="copy-to-clipboard__icon copy-to-clipboard__icon--check" aria-hidden="true">
39
+ <Check width={16} height={16} />
40
+ </span>
41
+ <span class="copy-to-clipboard__feedback" aria-live="polite"></span>
42
+ </button>
43
+ </span>
44
+
45
+ <script>
46
+ (function initCopyToClipboard() {
47
+ // Wait for DOM to be ready
48
+ const init = () => {
49
+ const buttons = document.querySelectorAll('.copy-to-clipboard');
50
+
51
+ buttons.forEach((button) => {
52
+ // Skip if already initialized
53
+ if (button.hasAttribute('data-copy-initialized')) return;
54
+ button.setAttribute('data-copy-initialized', 'true');
55
+
56
+ const tooltipHost = button.closest('.tooltip-host');
57
+ const defaultTooltip = tooltipHost ? (tooltipHost.getAttribute('data-tooltip') || 'Copy to clipboard') : 'Copy to clipboard';
58
+ const defaultAriaLabel = button.getAttribute('aria-label') || 'Copy to clipboard';
59
+ if (tooltipHost) tooltipHost.setAttribute('data-tooltip', defaultTooltip);
60
+ button.setAttribute('data-copy-aria-label', defaultAriaLabel);
61
+ if (tooltipHost) tooltipHost.setAttribute('data-copy-default-tooltip', defaultTooltip);
62
+
63
+ const getValue = () => button.getAttribute('data-copy-value') || '';
64
+ const getFormat = () => button.getAttribute('data-copy-format') || '';
65
+ const feedback = button.querySelector('.copy-to-clipboard__feedback');
66
+ const copyIcon = button.querySelector('.copy-to-clipboard__icon--copy');
67
+ const checkIcon = button.querySelector('.copy-to-clipboard__icon--check');
68
+ const textSpan = button.querySelector('.copy-to-clipboard__text');
69
+
70
+ // Update text span with current value
71
+ const updateDisplay = () => {
72
+ const value = getValue();
73
+ if (textSpan) {
74
+ textSpan.textContent = value || '';
75
+ }
76
+ };
77
+
78
+ // Initial display update
79
+ updateDisplay();
80
+
81
+ // Watch for attribute changes (for dynamic updates)
82
+ const observer = new MutationObserver((mutations) => {
83
+ let shouldUpdate = false;
84
+ mutations.forEach((mutation) => {
85
+ if (mutation.type === 'attributes') {
86
+ if (mutation.attributeName === 'data-copy-value' || mutation.attributeName === 'data-copy-format') {
87
+ shouldUpdate = true;
88
+ }
89
+ }
90
+ });
91
+ if (shouldUpdate) {
92
+ // Use requestAnimationFrame to ensure DOM is ready
93
+ requestAnimationFrame(() => {
94
+ updateDisplay();
95
+ });
96
+ }
97
+ });
98
+ observer.observe(button, {
99
+ attributes: true,
100
+ attributeFilter: ['data-copy-value', 'data-copy-format'],
101
+ attributeOldValue: false
102
+ });
103
+
104
+ // Listen for custom value-updated event
105
+ button.addEventListener('value-updated', (event) => {
106
+ if (event && event.detail && event.detail.value) {
107
+ updateDisplay();
108
+ }
109
+ });
110
+
111
+ // Fallback: Periodically check for value changes (in case MutationObserver misses something)
112
+ let lastValue = getValue();
113
+ const intervalId = setInterval(() => {
114
+ const currentValue = getValue();
115
+ if (currentValue !== lastValue) {
116
+ lastValue = currentValue;
117
+ updateDisplay();
118
+ }
119
+ }, 300);
120
+
121
+ // Store interval ID for potential cleanup (though we don't need to clean it up in this case)
122
+ button.setAttribute('data-copy-interval-id', intervalId.toString());
123
+
124
+ const copyToClipboard = async () => {
125
+ // Always read fresh value on click (in case it was updated dynamically)
126
+ let value = getValue();
127
+ const format = getFormat();
128
+
129
+ // If value is still empty, try reading from text span as fallback
130
+ if (!value && textSpan) {
131
+ value = textSpan.textContent || '';
132
+ }
133
+
134
+ if (!value) {
135
+ return;
136
+ }
137
+
138
+ try {
139
+ await navigator.clipboard.writeText(value);
140
+
141
+ // Show success state
142
+ if (copyIcon) copyIcon.classList.add('copy-to-clipboard__icon--hidden');
143
+ if (checkIcon) checkIcon.classList.remove('copy-to-clipboard__icon--hidden');
144
+ if (feedback) {
145
+ feedback.textContent = format ? `Copied ${format}!` : 'Copied!';
146
+ }
147
+ const tooltipHost = button.closest('.tooltip-host');
148
+ if (tooltipHost) tooltipHost.setAttribute('data-tooltip', format ? `Copied ${format}!` : 'Copied!');
149
+ button.setAttribute('aria-label', format ? `Copied ${format}!` : 'Copied!');
150
+
151
+ // Reset after 2 seconds
152
+ setTimeout(() => {
153
+ if (copyIcon) copyIcon.classList.remove('copy-to-clipboard__icon--hidden');
154
+ if (checkIcon) checkIcon.classList.add('copy-to-clipboard__icon--hidden');
155
+ if (feedback) {
156
+ feedback.textContent = '';
157
+ }
158
+ if (tooltipHost) tooltipHost.setAttribute('data-tooltip', tooltipHost.getAttribute('data-copy-default-tooltip') || defaultTooltip);
159
+ button.setAttribute('aria-label', defaultAriaLabel);
160
+ }, 2000);
161
+ } catch (err) {
162
+ // Fallback for older browsers
163
+ const textArea = document.createElement('textarea');
164
+ textArea.value = value;
165
+ textArea.style.position = 'fixed';
166
+ textArea.style.left = '-999999px';
167
+ document.body.appendChild(textArea);
168
+ textArea.focus();
169
+ textArea.select();
170
+
171
+ try {
172
+ document.execCommand('copy');
173
+ if (copyIcon) copyIcon.classList.add('copy-to-clipboard__icon--hidden');
174
+ if (checkIcon) checkIcon.classList.remove('copy-to-clipboard__icon--hidden');
175
+ if (feedback) {
176
+ feedback.textContent = format ? `Copied ${format}!` : 'Copied!';
177
+ }
178
+ const tooltipHostFb = button.closest('.tooltip-host');
179
+ if (tooltipHostFb) tooltipHostFb.setAttribute('data-tooltip', format ? `Copied ${format}!` : 'Copied!');
180
+ button.setAttribute('aria-label', format ? `Copied ${format}!` : 'Copied!');
181
+
182
+ setTimeout(() => {
183
+ if (copyIcon) copyIcon.classList.remove('copy-to-clipboard__icon--hidden');
184
+ if (checkIcon) checkIcon.classList.add('copy-to-clipboard__icon--hidden');
185
+ if (feedback) {
186
+ feedback.textContent = '';
187
+ }
188
+ if (tooltipHostFb) tooltipHostFb.setAttribute('data-tooltip', tooltipHostFb.getAttribute('data-copy-default-tooltip') || defaultTooltip);
189
+ button.setAttribute('aria-label', defaultAriaLabel);
190
+ }, 2000);
191
+ } catch (fallbackErr) {
192
+ if (feedback) {
193
+ feedback.textContent = 'Failed to copy';
194
+ }
195
+ }
196
+
197
+ document.body.removeChild(textArea);
198
+ }
199
+ };
200
+
201
+ button.addEventListener('click', copyToClipboard);
202
+
203
+ // Keyboard support
204
+ button.addEventListener('keydown', (e) => {
205
+ if (e.key === 'Enter' || e.key === ' ') {
206
+ e.preventDefault();
207
+ copyToClipboard();
208
+ }
209
+ });
210
+ });
211
+ };
212
+
213
+ if (document.readyState === 'loading') {
214
+ document.addEventListener('DOMContentLoaded', init);
215
+ } else {
216
+ init();
217
+ }
218
+ })();
219
+ </script>
@@ -0,0 +1,37 @@
1
+ ---
2
+ interface Props {
3
+ /** Orientation of the divider line */
4
+ orientation?: 'horizontal' | 'vertical';
5
+ /** Optional label (e.g. "OR") shown in the middle; only used for horizontal */
6
+ label?: string;
7
+ class?: string;
8
+ }
9
+
10
+ const {
11
+ orientation = 'horizontal',
12
+ label,
13
+ class: className = '',
14
+ } = Astro.props;
15
+
16
+ const orientationClass = `divider--${orientation}`;
17
+ const hasLabel = Boolean(label && label.trim());
18
+ const labelClass = hasLabel ? 'divider--labeled' : '';
19
+ const classes = `divider ${orientationClass} ${labelClass} ${className}`.trim();
20
+ ---
21
+
22
+ <div
23
+ class={classes}
24
+ role="separator"
25
+ aria-orientation={orientation}
26
+ aria-label={label?.trim() || undefined}
27
+ >
28
+ {hasLabel && orientation === 'horizontal' ? (
29
+ <>
30
+ <span class="divider__line" aria-hidden="true" />
31
+ <span class="divider__label">{label!.trim()}</span>
32
+ <span class="divider__line" aria-hidden="true" />
33
+ </>
34
+ ) : (
35
+ <span class="divider__line" aria-hidden="true" />
36
+ )}
37
+ </div>