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,240 @@
1
+ ---
2
+ interface Props {
3
+ currentPage: number;
4
+ totalPages: number;
5
+ hrefTemplate?: string;
6
+ showFirstLast?: boolean;
7
+ maxVisible?: number;
8
+ /** When true, add data attributes and script so clicking updates hash and current page (for demos) */
9
+ syncHash?: boolean;
10
+ class?: string;
11
+ }
12
+
13
+ const {
14
+ currentPage,
15
+ totalPages,
16
+ hrefTemplate = '?page={page}',
17
+ showFirstLast = true,
18
+ maxVisible = 5,
19
+ syncHash = false,
20
+ class: className = '',
21
+ } = Astro.props;
22
+
23
+ const classes = `pagination ${className}`.trim();
24
+ const hashMatch = typeof hrefTemplate === 'string' && hrefTemplate.startsWith('#');
25
+ const dataSync = syncHash && hashMatch ? { 'data-pagination-sync': 'true', 'data-total-pages': String(totalPages), 'data-href-template': hrefTemplate } : {};
26
+
27
+ function buildHref(page: number): string {
28
+ return hrefTemplate.replace(/\{page\}/g, String(page));
29
+ }
30
+
31
+ /** Build array of page numbers and 'ellipsis' for display */
32
+ function getPageItems(total: number, current: number, maxVisible: number): (number | 'ellipsis')[] {
33
+ if (total <= 1) return [];
34
+ if (total <= maxVisible) {
35
+ return Array.from({ length: total }, (_, i) => i + 1);
36
+ }
37
+ const items: (number | 'ellipsis')[] = [1];
38
+ const delta = Math.max(0, Math.floor((maxVisible - 2) / 2));
39
+ const start = Math.max(2, current - delta);
40
+ const end = Math.min(total - 1, current + delta);
41
+ if (start > 2) items.push('ellipsis');
42
+ for (let p = start; p <= end; p++) {
43
+ if (p !== 1 && p !== total) items.push(p);
44
+ }
45
+ if (end < total - 1) items.push('ellipsis');
46
+ if (total > 1) items.push(total);
47
+ return items;
48
+ }
49
+
50
+ const pageItems = getPageItems(totalPages, currentPage, maxVisible);
51
+ const hasPrev = currentPage > 1;
52
+ const hasNext = currentPage < totalPages;
53
+ ---
54
+
55
+ <nav class={classes} aria-label="Pagination" {...dataSync}>
56
+ <ul class="pagination__list">
57
+ {showFirstLast && totalPages > 1 && (
58
+ <li class="pagination__item">
59
+ {hasPrev ? (
60
+ <a class="pagination__link pagination__link--prev" href={buildHref(1)} aria-label="First page" data-pagination-role="first">
61
+ First
62
+ </a>
63
+ ) : (
64
+ <span class="pagination__link pagination__link--prev pagination__link--disabled" aria-disabled="true" data-pagination-role="first">
65
+ First
66
+ </span>
67
+ )}
68
+ </li>
69
+ )}
70
+ <li class="pagination__item">
71
+ {hasPrev ? (
72
+ <a class="pagination__link pagination__link--prev" href={buildHref(currentPage - 1)} aria-label="Previous page" data-pagination-role="prev">
73
+ Previous
74
+ </a>
75
+ ) : (
76
+ <span class="pagination__link pagination__link--prev pagination__link--disabled" aria-disabled="true" data-pagination-role="prev">
77
+ Previous
78
+ </span>
79
+ )}
80
+ </li>
81
+ {pageItems.map((item) => (
82
+ <li class="pagination__item">
83
+ {item === 'ellipsis' ? (
84
+ <span class="pagination__ellipsis" aria-hidden="true">
85
+
86
+ </span>
87
+ ) : item === currentPage ? (
88
+ <span class="pagination__link pagination__link--current" aria-current="page" data-page={String(item)}>
89
+ {item}
90
+ </span>
91
+ ) : (
92
+ <a class="pagination__link" href={buildHref(item)} aria-label={`Page ${item}`} data-page={String(item)}>
93
+ {item}
94
+ </a>
95
+ )}
96
+ </li>
97
+ ))}
98
+ <li class="pagination__item">
99
+ {hasNext ? (
100
+ <a class="pagination__link pagination__link--next" href={buildHref(currentPage + 1)} aria-label="Next page" data-pagination-role="next">
101
+ Next
102
+ </a>
103
+ ) : (
104
+ <span class="pagination__link pagination__link--next pagination__link--disabled" aria-disabled="true" data-pagination-role="next">
105
+ Next
106
+ </span>
107
+ )}
108
+ </li>
109
+ {showFirstLast && totalPages > 1 && (
110
+ <li class="pagination__item">
111
+ {hasNext ? (
112
+ <a class="pagination__link pagination__link--next" href={buildHref(totalPages)} aria-label="Last page" data-pagination-role="last">
113
+ Last
114
+ </a>
115
+ ) : (
116
+ <span class="pagination__link pagination__link--next pagination__link--disabled" aria-disabled="true" data-pagination-role="last">
117
+ Last
118
+ </span>
119
+ )}
120
+ </li>
121
+ )}
122
+ </ul>
123
+ </nav>
124
+
125
+ {syncHash && hashMatch && (
126
+ <script is:inline>
127
+ (function() {
128
+ function getHref(nav, page) {
129
+ var t = nav.getAttribute('data-href-template') || '#page-{page}';
130
+ return t.replace(/\{page\}/g, String(page));
131
+ }
132
+ function getRoleElement(nav, role) {
133
+ var candidates = nav.querySelectorAll('[data-pagination-role="' + role + '"]');
134
+ for (var i = 0; i < candidates.length; i++) {
135
+ if (candidates[i].closest && candidates[i].closest('[data-pagination-sync="true"]') === nav) return candidates[i];
136
+ }
137
+ return candidates[0] || null;
138
+ }
139
+ function setCurrentPage(nav, pageNum) {
140
+ var total = parseInt(nav.getAttribute('data-total-pages'), 10) || 1;
141
+ pageNum = Math.max(1, Math.min(pageNum, total));
142
+
143
+ Array.from(nav.querySelectorAll('[data-page]')).forEach(function(el) {
144
+ var page = el.getAttribute('data-page');
145
+ if (page === 'ellipsis') return;
146
+ var num = parseInt(page, 10);
147
+ if (isNaN(num)) return;
148
+ var isCurrent = num === pageNum;
149
+ var parent = el.parentNode;
150
+ if (isCurrent && el.tagName !== 'SPAN') {
151
+ var span = document.createElement('span');
152
+ span.className = 'pagination__link pagination__link--current';
153
+ span.setAttribute('aria-current', 'page');
154
+ span.setAttribute('data-page', page);
155
+ span.textContent = el.textContent;
156
+ parent.replaceChild(span, el);
157
+ } else if (!isCurrent && el.tagName !== 'A') {
158
+ var a = document.createElement('a');
159
+ a.className = 'pagination__link';
160
+ a.href = getHref(nav, num);
161
+ a.setAttribute('aria-label', 'Page ' + page);
162
+ a.setAttribute('data-page', page);
163
+ a.textContent = el.textContent;
164
+ parent.replaceChild(a, el);
165
+ }
166
+ });
167
+
168
+ ['first', 'prev', 'next', 'last'].forEach(function(role) {
169
+ var el = getRoleElement(nav, role);
170
+ if (!el) return;
171
+ var disabled = (role === 'first' || role === 'prev') ? pageNum <= 1 : pageNum >= total;
172
+ var hrefPage = role === 'first' ? 1 : role === 'last' ? total : role === 'prev' ? pageNum - 1 : pageNum + 1;
173
+ var parent = el.parentNode;
174
+ if (disabled) {
175
+ if (el.tagName !== 'SPAN') {
176
+ var span = document.createElement('span');
177
+ span.className = 'pagination__link pagination__link--' + (role === 'first' || role === 'prev' ? 'prev' : 'next') + ' pagination__link--disabled';
178
+ span.setAttribute('aria-disabled', 'true');
179
+ span.setAttribute('data-pagination-role', role);
180
+ span.textContent = el.textContent;
181
+ parent.replaceChild(span, el);
182
+ }
183
+ } else {
184
+ if (el.tagName !== 'A') {
185
+ var a = document.createElement('a');
186
+ a.className = 'pagination__link pagination__link--' + (role === 'first' || role === 'prev' ? 'prev' : 'next');
187
+ a.href = getHref(nav, hrefPage);
188
+ a.setAttribute('aria-label', role === 'first' ? 'First page' : role === 'last' ? 'Last page' : role === 'prev' ? 'Previous page' : 'Next page');
189
+ a.setAttribute('data-pagination-role', role);
190
+ a.textContent = el.textContent;
191
+ parent.replaceChild(a, el);
192
+ } else {
193
+ el.href = getHref(nav, hrefPage);
194
+ }
195
+ }
196
+ });
197
+ }
198
+ function init() {
199
+ document.querySelectorAll('[data-pagination-sync="true"]').forEach(function(nav) {
200
+ var total = parseInt(nav.getAttribute('data-total-pages'), 10) || 1;
201
+ var hash = window.location.hash;
202
+ var m = hash && hash.match(/^#page-(\d+)$/);
203
+ var page = m ? parseInt(m[1], 10) : null;
204
+ if (page >= 1 && page <= total) setCurrentPage(nav, page);
205
+
206
+ if (nav.hasAttribute('data-pagination-initialized')) return;
207
+ nav.setAttribute('data-pagination-initialized', 'true');
208
+ nav.addEventListener('click', function(e) {
209
+ var a = e.target.closest('a.pagination__link');
210
+ if (!a || !a.href) return;
211
+ var href = a.getAttribute('href') || a.href || '';
212
+ var match = href.match(/#page-(\d+)/);
213
+ if (!match) return;
214
+ e.preventDefault();
215
+ var pageNum = parseInt(match[1], 10);
216
+ if (pageNum >= 1 && pageNum <= total) {
217
+ window.location.hash = '#page-' + pageNum;
218
+ setCurrentPage(nav, pageNum);
219
+ }
220
+ });
221
+ });
222
+
223
+ if (window.__paginationSyncHashListener) return;
224
+ window.__paginationSyncHashListener = true;
225
+ window.addEventListener('hashchange', function() {
226
+ var hash = window.location.hash;
227
+ var m = hash && hash.match(/^#page-(\d+)$/);
228
+ if (!m) return;
229
+ var pageNum = parseInt(m[1], 10);
230
+ document.querySelectorAll('[data-pagination-sync="true"]').forEach(function(nav) {
231
+ var total = parseInt(nav.getAttribute('data-total-pages'), 10) || 1;
232
+ if (pageNum >= 1 && pageNum <= total) setCurrentPage(nav, pageNum);
233
+ });
234
+ });
235
+ }
236
+ if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
237
+ else init();
238
+ })();
239
+ </script>
240
+ )}
@@ -0,0 +1,65 @@
1
+ ---
2
+ interface Props {
3
+ /** Current value (0 to max) */
4
+ value?: number;
5
+ /** Maximum value (default: 100) */
6
+ max?: number;
7
+ /** Visual variant */
8
+ variant?: 'primary' | 'success' | 'warning' | 'error' | 'info';
9
+ /** Bar height size */
10
+ size?: 'sm' | 'md' | 'lg';
11
+ /** Show percentage or value label */
12
+ showLabel?: boolean;
13
+ /** Indeterminate (animated) state - ignores value */
14
+ indeterminate?: boolean;
15
+ /** Accessible label for the progress bar */
16
+ label?: string;
17
+ class?: string;
18
+ }
19
+
20
+ const {
21
+ value = 0,
22
+ max = 100,
23
+ variant = 'primary',
24
+ size = 'md',
25
+ showLabel = false,
26
+ indeterminate = false,
27
+ label,
28
+ class: className = '',
29
+ } = Astro.props;
30
+
31
+ const safeMax = max <= 0 ? 100 : max;
32
+ const clampedValue = indeterminate ? 0 : Math.max(0, Math.min(value, safeMax));
33
+ const percentage = indeterminate ? 0 : Math.round((clampedValue / safeMax) * 100);
34
+
35
+ const variantClass = `progress--${variant}`;
36
+ const sizeClass = `progress--${size}`;
37
+ const indeterminateClass = indeterminate ? 'progress--indeterminate' : '';
38
+ const classes = `progress ${variantClass} ${sizeClass} ${indeterminateClass} ${className}`.trim();
39
+
40
+ const ariaAttrs = indeterminate
41
+ ? { 'aria-valuemin': 0, 'aria-valuemax': safeMax, 'aria-label': label ?? 'Loading', 'aria-valuetext': 'Loading' }
42
+ : {
43
+ 'aria-valuenow': clampedValue,
44
+ 'aria-valuemin': 0,
45
+ 'aria-valuemax': safeMax,
46
+ 'aria-label': label ?? undefined,
47
+ };
48
+
49
+ const barStyle = indeterminate ? {} : { width: `${percentage}%` };
50
+ ---
51
+
52
+ <div
53
+ class={classes}
54
+ role="progressbar"
55
+ {...ariaAttrs}
56
+ >
57
+ <div class="progress__track">
58
+ <div class="progress__bar" style={barStyle} />
59
+ </div>
60
+ {showLabel && !indeterminate && (
61
+ <span class="progress__label" aria-hidden="true">
62
+ {percentage}%
63
+ </span>
64
+ )}
65
+ </div>
@@ -0,0 +1,38 @@
1
+ ---
2
+ interface Props {
3
+ id?: string;
4
+ name?: string;
5
+ value?: string;
6
+ checked?: boolean;
7
+ required?: boolean;
8
+ disabled?: boolean;
9
+ class?: string;
10
+ ariaDescribedby?: string;
11
+ ariaLabel?: string;
12
+ }
13
+
14
+ const {
15
+ id,
16
+ name,
17
+ value,
18
+ checked = false,
19
+ required = false,
20
+ disabled = false,
21
+ class: className = '',
22
+ ariaDescribedby,
23
+ ariaLabel,
24
+ } = Astro.props;
25
+ ---
26
+
27
+ <input
28
+ type="radio"
29
+ id={id}
30
+ name={name}
31
+ value={value}
32
+ checked={checked}
33
+ required={required}
34
+ disabled={disabled}
35
+ class={className}
36
+ aria-describedby={ariaDescribedby}
37
+ aria-label={ariaLabel}
38
+ />