@rimelight/ui 0.0.1

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 (301) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +30 -0
  3. package/i18n-data.json +186 -0
  4. package/package.json +49 -0
  5. package/src/components/FormattedDate.astro +22 -0
  6. package/src/components/HeaderLink.astro +24 -0
  7. package/src/components/HttpObservatory.astro +103 -0
  8. package/src/components/LighthouseScores.astro +204 -0
  9. package/src/components/MissingTranslationBanner.astro +39 -0
  10. package/src/components/TableOfContents.astro +106 -0
  11. package/src/components/ThemeToggle.astro +71 -0
  12. package/src/components/accordion/Accordion.astro +257 -0
  13. package/src/components/accordion/AccordionContent.astro +34 -0
  14. package/src/components/accordion/AccordionItem.astro +29 -0
  15. package/src/components/accordion/AccordionTrigger.astro +33 -0
  16. package/src/components/alert/Alert.astro +34 -0
  17. package/src/components/alert/AlertDescription.astro +15 -0
  18. package/src/components/alert/AlertTitle.astro +17 -0
  19. package/src/components/alert-dialog/AlertDialog.astro +275 -0
  20. package/src/components/alert-dialog/AlertDialogAction.astro +46 -0
  21. package/src/components/alert-dialog/AlertDialogCancel.astro +46 -0
  22. package/src/components/alert-dialog/AlertDialogContent.astro +52 -0
  23. package/src/components/alert-dialog/AlertDialogDescription.astro +18 -0
  24. package/src/components/alert-dialog/AlertDialogFooter.astro +16 -0
  25. package/src/components/alert-dialog/AlertDialogHeader.astro +14 -0
  26. package/src/components/alert-dialog/AlertDialogTitle.astro +20 -0
  27. package/src/components/alert-dialog/AlertDialogTrigger.astro +47 -0
  28. package/src/components/aspect-ratio/AspectRatio.astro +32 -0
  29. package/src/components/avatar/Avatar.astro +29 -0
  30. package/src/components/avatar/AvatarFallback.astro +18 -0
  31. package/src/components/avatar/AvatarImage.astro +66 -0
  32. package/src/components/badge/Badge.astro +57 -0
  33. package/src/components/breadcrumb/Breadcrumb.astro +12 -0
  34. package/src/components/breadcrumb/BreadcrumbEllipsis.astro +29 -0
  35. package/src/components/breadcrumb/BreadcrumbItem.astro +15 -0
  36. package/src/components/breadcrumb/BreadcrumbLink.astro +24 -0
  37. package/src/components/breadcrumb/BreadcrumbList.astro +17 -0
  38. package/src/components/breadcrumb/BreadcrumbPage.astro +22 -0
  39. package/src/components/breadcrumb/BreadcrumbSeparator.astro +24 -0
  40. package/src/components/button/Button.astro +58 -0
  41. package/src/components/button-group/ButtonGroup.astro +64 -0
  42. package/src/components/button-group/ButtonGroupSeparator.astro +20 -0
  43. package/src/components/button-group/ButtonGroupText.astro +19 -0
  44. package/src/components/card/Card.astro +36 -0
  45. package/src/components/card/CardAction.astro +16 -0
  46. package/src/components/card/CardContent.astro +16 -0
  47. package/src/components/card/CardDescription.astro +16 -0
  48. package/src/components/card/CardFooter.astro +16 -0
  49. package/src/components/card/CardHeader.astro +19 -0
  50. package/src/components/card/CardTitle.astro +16 -0
  51. package/src/components/carousel/Carousel.astro +55 -0
  52. package/src/components/carousel/CarouselContent.astro +26 -0
  53. package/src/components/carousel/CarouselItem.astro +26 -0
  54. package/src/components/carousel/CarouselNext.astro +39 -0
  55. package/src/components/carousel/CarouselPrevious.astro +41 -0
  56. package/src/components/carousel/carousel-script.ts +188 -0
  57. package/src/components/carousel/index.ts +1 -0
  58. package/src/components/checkbox/Checkbox.astro +133 -0
  59. package/src/components/collapsible/Collapsible.astro +161 -0
  60. package/src/components/collapsible/CollapsibleContent.astro +22 -0
  61. package/src/components/collapsible/CollapsibleTrigger.astro +44 -0
  62. package/src/components/dialog/Dialog.astro +389 -0
  63. package/src/components/dialog/DialogClose.astro +35 -0
  64. package/src/components/dialog/DialogContent.astro +78 -0
  65. package/src/components/dialog/DialogDescription.astro +14 -0
  66. package/src/components/dialog/DialogFooter.astro +14 -0
  67. package/src/components/dialog/DialogHeader.astro +14 -0
  68. package/src/components/dialog/DialogTitle.astro +18 -0
  69. package/src/components/dialog/DialogTrigger.astro +47 -0
  70. package/src/components/dropdown/Dropdown.astro +604 -0
  71. package/src/components/dropdown/DropdownContent.astro +118 -0
  72. package/src/components/dropdown/DropdownItem.astro +48 -0
  73. package/src/components/dropdown/DropdownLabel.astro +29 -0
  74. package/src/components/dropdown/DropdownSeparator.astro +21 -0
  75. package/src/components/dropdown/DropdownShortcut.astro +17 -0
  76. package/src/components/dropdown/DropdownSub.astro +15 -0
  77. package/src/components/dropdown/DropdownSubContent.astro +39 -0
  78. package/src/components/dropdown/DropdownSubTrigger.astro +34 -0
  79. package/src/components/dropdown/DropdownTrigger.astro +52 -0
  80. package/src/components/dropzone/Dropzone.astro +236 -0
  81. package/src/components/dropzone/DropzoneFilesList.astro +26 -0
  82. package/src/components/dropzone/DropzoneLoadingIndicator.astro +10 -0
  83. package/src/components/dropzone/DropzoneUploadIndicator.astro +10 -0
  84. package/src/components/embeds/YoutubeEmbed.astro +94 -0
  85. package/src/components/hero/Hero.astro +166 -0
  86. package/src/components/icons/Flag.astro +62 -0
  87. package/src/components/image/ExtendedImage.astro +46 -0
  88. package/src/components/image/Image.astro +25 -0
  89. package/src/components/input/Input.astro +27 -0
  90. package/src/components/input-group/InputGroup.astro +28 -0
  91. package/src/components/input-group/InputGroupAddon.astro +76 -0
  92. package/src/components/input-group/InputGroupButton.astro +36 -0
  93. package/src/components/input-group/InputGroupInput.astro +18 -0
  94. package/src/components/input-group/InputGroupText.astro +17 -0
  95. package/src/components/input-group/InputGroupTextarea.astro +22 -0
  96. package/src/components/input-otp/InputOtp.astro +352 -0
  97. package/src/components/input-otp/InputOtpGroup.astro +16 -0
  98. package/src/components/input-otp/InputOtpSeparator.astro +25 -0
  99. package/src/components/input-otp/InputOtpSlot.astro +50 -0
  100. package/src/components/input-otp/InputOtpTypes.ts +6 -0
  101. package/src/components/item/Item.astro +52 -0
  102. package/src/components/item/ItemActions.astro +16 -0
  103. package/src/components/item/ItemContent.astro +16 -0
  104. package/src/components/item/ItemDescription.astro +19 -0
  105. package/src/components/item/ItemFooter.astro +16 -0
  106. package/src/components/item/ItemGroup.astro +16 -0
  107. package/src/components/item/ItemHeader.astro +16 -0
  108. package/src/components/item/ItemMedia.astro +40 -0
  109. package/src/components/item/ItemSeparator.astro +23 -0
  110. package/src/components/item/ItemTitle.astro +16 -0
  111. package/src/components/kbd/Kbd.astro +21 -0
  112. package/src/components/kbd/KbdGroup.astro +16 -0
  113. package/src/components/label/Label.astro +24 -0
  114. package/src/components/marquee/Marquee.astro +73 -0
  115. package/src/components/native-select/NativeSelect.astro +68 -0
  116. package/src/components/native-select/NativeSelectOptGroup.astro +15 -0
  117. package/src/components/native-select/NativeSelectOption.astro +15 -0
  118. package/src/components/pagination/Pagination.astro +20 -0
  119. package/src/components/pagination/PaginationContent.astro +16 -0
  120. package/src/components/pagination/PaginationEllipsis.astro +37 -0
  121. package/src/components/pagination/PaginationItem.astro +16 -0
  122. package/src/components/pagination/PaginationLink.astro +27 -0
  123. package/src/components/pagination/PaginationNext.astro +33 -0
  124. package/src/components/pagination/PaginationPrevious.astro +33 -0
  125. package/src/components/popover/Popover.astro +717 -0
  126. package/src/components/popover/PopoverContent.astro +102 -0
  127. package/src/components/popover/PopoverDescription.astro +14 -0
  128. package/src/components/popover/PopoverHeader.astro +14 -0
  129. package/src/components/popover/PopoverTitle.astro +14 -0
  130. package/src/components/popover/PopoverTrigger.astro +51 -0
  131. package/src/components/progress/Progress.astro +154 -0
  132. package/src/components/prose/Prose.astro +619 -0
  133. package/src/components/radio-group/RadioGroup.astro +162 -0
  134. package/src/components/radio-group/RadioGroupItem.astro +133 -0
  135. package/src/components/radio-group/RadioGroupTypes.ts +6 -0
  136. package/src/components/section/Section.astro +167 -0
  137. package/src/components/select/Select.astro +752 -0
  138. package/src/components/select/SelectContent.astro +94 -0
  139. package/src/components/select/SelectGroup.astro +9 -0
  140. package/src/components/select/SelectItem.astro +51 -0
  141. package/src/components/select/SelectLabel.astro +14 -0
  142. package/src/components/select/SelectSearch.astro +49 -0
  143. package/src/components/select/SelectSeparator.astro +12 -0
  144. package/src/components/select/SelectTrigger.astro +56 -0
  145. package/src/components/select/SelectTypes.ts +13 -0
  146. package/src/components/select/SelectValue.astro +19 -0
  147. package/src/components/separator/Separator.astro +36 -0
  148. package/src/components/sheet/Sheet.astro +15 -0
  149. package/src/components/sheet/SheetClose.astro +15 -0
  150. package/src/components/sheet/SheetContent.astro +89 -0
  151. package/src/components/sheet/SheetDescription.astro +16 -0
  152. package/src/components/sheet/SheetFooter.astro +16 -0
  153. package/src/components/sheet/SheetHeader.astro +16 -0
  154. package/src/components/sheet/SheetTitle.astro +16 -0
  155. package/src/components/sheet/SheetTrigger.astro +15 -0
  156. package/src/components/sidebar/Sidebar.astro +231 -0
  157. package/src/components/sidebar/SidebarContent.astro +25 -0
  158. package/src/components/sidebar/SidebarFooter.astro +22 -0
  159. package/src/components/sidebar/SidebarGroup.astro +22 -0
  160. package/src/components/sidebar/SidebarGroupContent.astro +22 -0
  161. package/src/components/sidebar/SidebarGroupLabel.astro +53 -0
  162. package/src/components/sidebar/SidebarHeader.astro +22 -0
  163. package/src/components/sidebar/SidebarInput.astro +24 -0
  164. package/src/components/sidebar/SidebarInset.astro +22 -0
  165. package/src/components/sidebar/SidebarMenu.astro +22 -0
  166. package/src/components/sidebar/SidebarMenuAction.astro +63 -0
  167. package/src/components/sidebar/SidebarMenuBadge.astro +31 -0
  168. package/src/components/sidebar/SidebarMenuButton.astro +124 -0
  169. package/src/components/sidebar/SidebarMenuItem.astro +22 -0
  170. package/src/components/sidebar/SidebarMenuSkeleton.astro +43 -0
  171. package/src/components/sidebar/SidebarMenuSub.astro +25 -0
  172. package/src/components/sidebar/SidebarMenuSubButton.astro +52 -0
  173. package/src/components/sidebar/SidebarMenuSubItem.astro +17 -0
  174. package/src/components/sidebar/SidebarProvider.astro +215 -0
  175. package/src/components/sidebar/SidebarRail.astro +72 -0
  176. package/src/components/sidebar/SidebarSeparator.astro +25 -0
  177. package/src/components/sidebar/SidebarTrigger.astro +69 -0
  178. package/src/components/skeleton/Skeleton.astro +14 -0
  179. package/src/components/slider/Slider.astro +425 -0
  180. package/src/components/spinner/Spinner.astro +23 -0
  181. package/src/components/switch/Switch.astro +192 -0
  182. package/src/components/switch/SwitchTypes.ts +6 -0
  183. package/src/components/table/Table.astro +20 -0
  184. package/src/components/table/TableBody.astro +18 -0
  185. package/src/components/table/TableCaption.astro +18 -0
  186. package/src/components/table/TableCell.astro +18 -0
  187. package/src/components/table/TableFoot.astro +18 -0
  188. package/src/components/table/TableHead.astro +18 -0
  189. package/src/components/table/TableHeader.astro +18 -0
  190. package/src/components/table/TableRow.astro +17 -0
  191. package/src/components/tabs/Tabs.astro +270 -0
  192. package/src/components/tabs/TabsContent.astro +28 -0
  193. package/src/components/tabs/TabsList.astro +23 -0
  194. package/src/components/tabs/TabsTrigger.astro +34 -0
  195. package/src/components/textarea/Textarea.astro +31 -0
  196. package/src/components/toast/ToastDescription.astro +22 -0
  197. package/src/components/toast/ToastItem.astro +56 -0
  198. package/src/components/toast/ToastTemplate.astro +27 -0
  199. package/src/components/toast/ToastTitle.astro +59 -0
  200. package/src/components/toast/Toaster.astro +981 -0
  201. package/src/components/toast/index.ts +1 -0
  202. package/src/components/toast/toast-manager.ts +234 -0
  203. package/src/components/toggle/Toggle.astro +174 -0
  204. package/src/components/toggle/ToggleTypes.ts +14 -0
  205. package/src/components/tooltip/Tooltip.astro +422 -0
  206. package/src/components/tooltip/TooltipContent.astro +83 -0
  207. package/src/components/tooltip/TooltipTrigger.astro +13 -0
  208. package/src/components/video/Video.astro +121 -0
  209. package/src/config/cookies.ts +5 -0
  210. package/src/config/index.ts +3 -0
  211. package/src/config/links.ts +4 -0
  212. package/src/config/site.config.ts +45 -0
  213. package/src/domain/cms/index.ts +1 -0
  214. package/src/domain/cms/types.ts +20 -0
  215. package/src/domain/i18n/constants.ts +21 -0
  216. package/src/domain/i18n/cookie-storage.ts +13 -0
  217. package/src/domain/i18n/country-to-locale-map.ts +67 -0
  218. package/src/domain/i18n/fallbacks.generated.ts +230 -0
  219. package/src/domain/i18n/fetcher.ts +268 -0
  220. package/src/domain/i18n/flags.ts +16 -0
  221. package/src/domain/i18n/format.ts +90 -0
  222. package/src/domain/i18n/index.ts +10 -0
  223. package/src/domain/i18n/middleware/i18n.ts +160 -0
  224. package/src/domain/i18n/resolve-locale.ts +55 -0
  225. package/src/domain/i18n/runtime-constants.ts +14 -0
  226. package/src/domain/i18n/schema.ts +29 -0
  227. package/src/domain/index.ts +4 -0
  228. package/src/domain/seo/constants.ts +20 -0
  229. package/src/domain/seo/index.ts +3 -0
  230. package/src/domain/seo/services/index.ts +3 -0
  231. package/src/domain/seo/services/llms.ts +53 -0
  232. package/src/domain/seo/services/robots.ts +12 -0
  233. package/src/domain/seo/services/sitemap.ts +56 -0
  234. package/src/domain/seo/utils.ts +37 -0
  235. package/src/domain/theme/constants.ts +6 -0
  236. package/src/domain/theme/index.ts +2 -0
  237. package/src/domain/theme/schema.ts +10 -0
  238. package/src/env.d.ts +49 -0
  239. package/src/i18n.generated.d.ts +202 -0
  240. package/src/lib/component-preview.ts +73 -0
  241. package/src/lib/index.ts +6 -0
  242. package/src/lib/remark/remark-modified-time.ts +13 -0
  243. package/src/lib/showcase-preview-elements.ts +408 -0
  244. package/src/lib/showcase-renderer.ts +218 -0
  245. package/src/lib/showcase-utils.ts +189 -0
  246. package/src/lib/turnstile.ts +35 -0
  247. package/src/lib/utils/starwind/positioning.ts +318 -0
  248. package/src/locales/de/blog.json +9 -0
  249. package/src/locales/de/common.json +19 -0
  250. package/src/locales/de/errors.json +6 -0
  251. package/src/locales/de/home.json +20 -0
  252. package/src/locales/de/messages.json +8 -0
  253. package/src/locales/de/nav.json +13 -0
  254. package/src/locales/de/projects.json +9 -0
  255. package/src/locales/de/services.json +43 -0
  256. package/src/locales/en/blog.json +9 -0
  257. package/src/locales/en/chat.json +29 -0
  258. package/src/locales/en/common.json +19 -0
  259. package/src/locales/en/cookie_notice.json +11 -0
  260. package/src/locales/en/editor.json +24 -0
  261. package/src/locales/en/errors.json +6 -0
  262. package/src/locales/en/home.json +20 -0
  263. package/src/locales/en/messages.json +8 -0
  264. package/src/locales/en/nav.json +13 -0
  265. package/src/locales/en/projects.json +9 -0
  266. package/src/locales/en/services.json +43 -0
  267. package/src/locales/es/blog.json +9 -0
  268. package/src/locales/es/common.json +19 -0
  269. package/src/locales/es/errors.json +6 -0
  270. package/src/locales/es/home.json +20 -0
  271. package/src/locales/es/messages.json +8 -0
  272. package/src/locales/es/nav.json +13 -0
  273. package/src/locales/es/projects.json +9 -0
  274. package/src/locales/es/services.json +43 -0
  275. package/src/locales/ja/blog.json +9 -0
  276. package/src/locales/ja/common.json +19 -0
  277. package/src/locales/ja/errors.json +6 -0
  278. package/src/locales/ja/home.json +20 -0
  279. package/src/locales/ja/messages.json +8 -0
  280. package/src/locales/ja/nav.json +13 -0
  281. package/src/locales/ja/projects.json +9 -0
  282. package/src/locales/ja/services.json +43 -0
  283. package/src/locales/pt/blog.json +9 -0
  284. package/src/locales/pt/chat.json +29 -0
  285. package/src/locales/pt/common.json +19 -0
  286. package/src/locales/pt/cookie_notice.json +11 -0
  287. package/src/locales/pt/editor.json +24 -0
  288. package/src/locales/pt/errors.json +6 -0
  289. package/src/locales/pt/home.json +20 -0
  290. package/src/locales/pt/messages.json +8 -0
  291. package/src/locales/pt/nav.json +13 -0
  292. package/src/locales/pt/projects.json +9 -0
  293. package/src/locales/pt/services.json +43 -0
  294. package/src/utils/index.ts +2 -0
  295. package/src/utils/server/cookies.ts +98 -0
  296. package/src/utils/server/index.ts +1 -0
  297. package/src/utils/shared/deep-merge.ts +36 -0
  298. package/src/utils/shared/embed.ts +105 -0
  299. package/src/utils/shared/index.ts +3 -0
  300. package/src/utils/shared/parse-boolean.ts +14 -0
  301. package/worker-configuration.d.ts +14791 -0
@@ -0,0 +1,16 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types";
3
+ import { cv } from "css-variants";
4
+
5
+ type Props = HTMLAttributes<"div">;
6
+
7
+ export const cardFooter = cv({
8
+ base: "bg-muted/50 flex items-center rounded-b-xl border-t p-xl group-data-[size=sm]/card:p-2xl",
9
+ });
10
+
11
+ const { class: className, ...rest } = Astro.props;
12
+ ---
13
+
14
+ <div class:list={[cardFooter(), className]} {...rest} data-slot="card-footer">
15
+ <slot />
16
+ </div>
@@ -0,0 +1,19 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types";
3
+ import { cv } from "css-variants";
4
+
5
+ type Props = HTMLAttributes<"div">;
6
+
7
+ export const cardHeader = cv({
8
+ base: [
9
+ "@container/card-header grid auto-rows-min items-start gap-1 px-xl group-data-[size=sm]/card:px-2xl",
10
+ "has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto]",
11
+ ],
12
+ });
13
+
14
+ const { class: className, ...rest } = Astro.props;
15
+ ---
16
+
17
+ <div class:list={[cardHeader(), className]} {...rest} data-slot="card-header">
18
+ <slot />
19
+ </div>
@@ -0,0 +1,16 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types";
3
+ import { cv } from "css-variants";
4
+
5
+ type Props = HTMLAttributes<"div">;
6
+
7
+ export const cardTitle = cv({
8
+ base: "font-heading text-xl leading-snug font-medium group-data-[size=sm]/card:text-base",
9
+ });
10
+
11
+ const { class: className, ...rest } = Astro.props;
12
+ ---
13
+
14
+ <div class:list={[cardTitle(), className]} {...rest} data-slot="card-title">
15
+ <slot />
16
+ </div>
@@ -0,0 +1,55 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types";
3
+ import { type EmblaOptionsType } from "embla-carousel";
4
+ import { cv } from "css-variants";
5
+
6
+ export const carousel = cv({
7
+ base: "starwind-carousel group/carousel relative",
8
+ });
9
+
10
+ export interface Props extends HTMLAttributes<"div"> {
11
+ orientation?: "horizontal" | "vertical";
12
+ opts?: EmblaOptionsType;
13
+ autoInit?: boolean;
14
+ }
15
+
16
+ const {
17
+ class: className,
18
+ orientation = "horizontal",
19
+ opts = {},
20
+ autoInit = true,
21
+ ...rest
22
+ } = Astro.props;
23
+ ---
24
+
25
+ <div
26
+ class:list={[carousel(), className]}
27
+ role="region"
28
+ aria-roledescription="carousel"
29
+ data-axis={orientation === "horizontal" ? "x" : "y"}
30
+ data-opts={JSON.stringify(opts)}
31
+ data-auto-init={autoInit}
32
+ {...rest}
33
+ data-slot="carousel"
34
+ >
35
+ <slot />
36
+ </div>
37
+
38
+ <script>
39
+ import { initCarousel } from "./carousel-script";
40
+
41
+ const setupCarousels = () => {
42
+ const carousels = document.querySelectorAll(".starwind-carousel") as NodeListOf<HTMLElement>;
43
+ carousels.forEach((carousel) => {
44
+ if (carousel.dataset.autoInit === "false") {
45
+ return;
46
+ }
47
+ initCarousel(carousel);
48
+ });
49
+ };
50
+
51
+ document.addEventListener("DOMContentLoaded", setupCarousels);
52
+
53
+ // Re-initialize after Astro page transitions
54
+ document.addEventListener("astro:after-swap", setupCarousels);
55
+ </script>
@@ -0,0 +1,26 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types";
3
+ import { cv } from "css-variants";
4
+
5
+ export const carouselContent = cv({
6
+ base: "overflow-hidden",
7
+ });
8
+
9
+ const carouselContainer = cv({
10
+ base: [
11
+ "flex group-data-[axis=y]/carousel:flex-col",
12
+ "group-data-[axis=x]/carousel:-ml-4",
13
+ "group-data-[axis=y]/carousel:-mt-4",
14
+ ],
15
+ });
16
+
17
+ type Props = HTMLAttributes<"div">;
18
+
19
+ const { class: className = "", ...rest } = Astro.props;
20
+ ---
21
+
22
+ <div class={carouselContent()} {...rest} data-slot="carousel-content">
23
+ <div class:list={[carouselContainer(), className]} data-slot="carousel-container">
24
+ <slot />
25
+ </div>
26
+ </div>
@@ -0,0 +1,26 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types";
3
+ import { cv } from "css-variants";
4
+
5
+ export const carouselItem = cv({
6
+ base: [
7
+ "min-w-0 shrink-0 grow-0 basis-full",
8
+ "group-data-[axis=x]/carousel:pl-4",
9
+ "group-data-[axis=y]/carousel:pt-4",
10
+ ],
11
+ });
12
+
13
+ type Props = HTMLAttributes<"div">;
14
+
15
+ const { class: className = "", ...rest } = Astro.props;
16
+ ---
17
+
18
+ <div
19
+ role="group"
20
+ aria-roledescription="slide"
21
+ class:list={[carouselItem(), className]}
22
+ {...rest}
23
+ data-slot="carousel-item"
24
+ >
25
+ <slot />
26
+ </div>
@@ -0,0 +1,39 @@
1
+ ---
2
+ import type { ComponentProps } from "astro/types";
3
+ import { cv } from "css-variants";
4
+ import IconArrowRight from "~icons/lucide/arrow-right";
5
+
6
+ // eslint-disable-next-line typescript/consistent-type-imports
7
+ import Button from "../button/Button.astro";
8
+
9
+ export const carouselNext = cv({
10
+ base: [
11
+ "starwind-carousel-next absolute size-8 rounded-full",
12
+ // Horizontal positioning
13
+ "group-data-[axis=x]/carousel:top-1/2 group-data-[axis=x]/carousel:-right-12 group-data-[axis=x]/carousel:-translate-y-1/2",
14
+ // Vertical positioning
15
+ "group-data-[axis=y]/carousel:-bottom-12 group-data-[axis=y]/carousel:left-1/2 group-data-[axis=y]/carousel:-translate-x-1/2 group-data-[axis=y]/carousel:rotate-90",
16
+ ],
17
+ });
18
+
19
+ type Props = ComponentProps<typeof Button> & { orientation?: "horizontal" | "vertical" };
20
+
21
+ const { class: className = "", variant = "outline", size = "icon", orientation = "horizontal", ...rest } = Astro.props;
22
+ ---
23
+
24
+ <Button
25
+ variant={variant}
26
+ size={size}
27
+ class:list={[carouselNext({ orientation }), className]}
28
+ aria-label="Next slide"
29
+ {...rest}
30
+ data-slot="carousel-next"
31
+ >
32
+ <slot name="icon">
33
+ <IconArrowRight />
34
+ </slot>
35
+ <slot>
36
+ <span class="sr-only">Next slide</span>
37
+ </slot>
38
+ </Button>
39
+
@@ -0,0 +1,41 @@
1
+ ---
2
+ import type { ComponentProps } from "astro/types";
3
+ import { cv } from "css-variants";
4
+ import IconArrowLeft from "~icons/lucide/arrow-left";
5
+
6
+ // eslint-disable-next-line typescript/consistent-type-imports
7
+ import Button from "../button/Button.astro";
8
+
9
+ export const carouselPrevious = cv({
10
+ base: [
11
+ "starwind-carousel-previous absolute size-8 rounded-full",
12
+ // Horizontal positioning
13
+ "group-data-[axis=x]/carousel:top-1/2 group-data-[axis=x]/carousel:-left-12 group-data-[axis=x]/carousel:-translate-y-1/2",
14
+ // Vertical positioning
15
+ "group-data-[axis=y]/carousel:-top-12 group-data-[axis=y]/carousel:left-1/2 group-data-[axis=y]/carousel:-translate-x-1/2 group-data-[axis=y]/carousel:rotate-90",
16
+ ],
17
+ });
18
+
19
+ type Props = ComponentProps<typeof Button> & {
20
+ orientation?: "horizontal" | "vertical";
21
+ };
22
+
23
+ const { class: className = "", variant = "outline", size = "icon", orientation = "horizontal", ...rest } = Astro.props;
24
+ ---
25
+
26
+ <Button
27
+ variant={variant}
28
+ size={size}
29
+ class:list={[carouselPrevious({ orientation }), className]}
30
+ aria-label="Previous slide"
31
+ {...rest}
32
+ data-slot="carousel-previous"
33
+ >
34
+ <slot name="icon">
35
+ <IconArrowLeft />
36
+ </slot>
37
+ <slot>
38
+ <span class="sr-only">Previous slide</span>
39
+ </slot>
40
+ </Button>
41
+
@@ -0,0 +1,188 @@
1
+ import EmblaCarousel, {
2
+ type EmblaCarouselType,
3
+ type EmblaOptionsType,
4
+ type EmblaPluginType
5
+ } from "embla-carousel"
6
+
7
+ export type CarouselApi = EmblaCarouselType
8
+
9
+ export interface CarouselOptions {
10
+ opts?: EmblaOptionsType
11
+ plugins?: EmblaPluginType[]
12
+ setApi?: (api: CarouselApi) => void
13
+ }
14
+
15
+ export interface CarouselManager {
16
+ api: CarouselApi
17
+ scrollPrev: () => void
18
+ scrollNext: () => void
19
+ canScrollPrev: () => boolean
20
+ canScrollNext: () => boolean
21
+ destroy: () => void
22
+ }
23
+
24
+ export function initCarousel(
25
+ carouselElement: HTMLElement,
26
+ options: CarouselOptions = {}
27
+ ): CarouselManager | null {
28
+ // don't re-initialize if already initialized
29
+ if (carouselElement.dataset.initialized === "true") return null
30
+ carouselElement.dataset.initialized = "true"
31
+
32
+ if (!carouselElement) {
33
+ console.warn("Carousel element not found")
34
+ return null
35
+ }
36
+
37
+ // Find content element - Embla expects the viewport element, not the container
38
+ const viewportElement = carouselElement.querySelector('[data-slot="carousel-content"]')
39
+
40
+ if (!(viewportElement instanceof HTMLElement)) {
41
+ console.warn("Carousel content element not found")
42
+ return null
43
+ }
44
+
45
+ // Get configuration from data attributes
46
+ const axisData = carouselElement.dataset.axis
47
+ const axis: EmblaOptionsType["axis"] = axisData === "y" ? "y" : "x"
48
+
49
+ // Safely parse data options
50
+ let dataOpts = {}
51
+ try {
52
+ const optsString = carouselElement.dataset.opts
53
+ if (optsString && optsString !== "undefined" && optsString !== "null") {
54
+ dataOpts = JSON.parse(optsString)
55
+ }
56
+ } catch (e) {
57
+ console.warn("Failed to parse carousel opts:", e)
58
+ dataOpts = {}
59
+ }
60
+
61
+ // Ensure dataOpts is a valid object
62
+ if (!dataOpts || typeof dataOpts !== "object") {
63
+ dataOpts = {}
64
+ }
65
+
66
+ // Merge options - ensure we always have a valid object
67
+ const emblaOptions: EmblaOptionsType = {
68
+ axis,
69
+ ...dataOpts,
70
+ ...options.opts
71
+ }
72
+
73
+ // Handle plugins - EmblaCarousel expects undefined when no plugins, not empty array
74
+ const plugins = options.plugins && options.plugins.length > 0 ? options.plugins : undefined
75
+
76
+ // console.log("ID:", carouselElement.id);
77
+ // console.log("Plugins:", plugins);
78
+ // console.log("Options:", emblaOptions);
79
+
80
+ // Find navigation buttons
81
+ const prevButton = carouselElement.querySelector(".starwind-carousel-previous")
82
+ const nextButton = carouselElement.querySelector(".starwind-carousel-next")
83
+
84
+ const prevButtonEl = prevButton instanceof HTMLButtonElement ? prevButton : null
85
+ const nextButtonEl = nextButton instanceof HTMLButtonElement ? nextButton : null
86
+
87
+ // Initialize Embla
88
+ let emblaApi: EmblaCarouselType
89
+ if (plugins) {
90
+ emblaApi = EmblaCarousel(viewportElement, emblaOptions, plugins)
91
+ } else {
92
+ emblaApi = EmblaCarousel(viewportElement, emblaOptions)
93
+ }
94
+
95
+ // Update button states
96
+ const updateButtons = () => {
97
+ const canScrollPrev = emblaApi.canScrollPrev()
98
+ const canScrollNext = emblaApi.canScrollNext()
99
+
100
+ if (prevButtonEl) {
101
+ prevButtonEl.disabled = !canScrollPrev
102
+ prevButtonEl.setAttribute("aria-disabled", (!canScrollPrev).toString())
103
+ }
104
+
105
+ if (nextButtonEl) {
106
+ nextButtonEl.disabled = !canScrollNext
107
+ nextButtonEl.setAttribute("aria-disabled", (!canScrollNext).toString())
108
+ }
109
+ }
110
+
111
+ // Event handlers for cleanup
112
+ const prevClickHandler = () => emblaApi.scrollPrev()
113
+ const nextClickHandler = () => emblaApi.scrollNext()
114
+ const keydownHandler = (event: KeyboardEvent) => {
115
+ if (axis === "y") {
116
+ // Vertical axis: ArrowUp = previous, ArrowDown = next
117
+ if (event.key === "ArrowUp") {
118
+ event.preventDefault()
119
+ emblaApi.scrollPrev()
120
+ } else if (event.key === "ArrowDown") {
121
+ event.preventDefault()
122
+ emblaApi.scrollNext()
123
+ }
124
+ } else {
125
+ // Horizontal axis (default): ArrowLeft = previous, ArrowRight = next
126
+ if (event.key === "ArrowLeft") {
127
+ event.preventDefault()
128
+ emblaApi.scrollPrev()
129
+ } else if (event.key === "ArrowRight") {
130
+ event.preventDefault()
131
+ emblaApi.scrollNext()
132
+ }
133
+ }
134
+ }
135
+
136
+ // Setup event listeners
137
+ const setupEventListeners = () => {
138
+ // Navigation button listeners
139
+ prevButtonEl?.addEventListener("click", prevClickHandler)
140
+ nextButtonEl?.addEventListener("click", nextClickHandler)
141
+
142
+ // Keyboard navigation
143
+ carouselElement.addEventListener("keydown", keydownHandler)
144
+ }
145
+
146
+ // Setup user API callback
147
+ const setupUserCallbacks = () => {
148
+ if (options.setApi) {
149
+ options.setApi(emblaApi)
150
+ }
151
+ }
152
+
153
+ // Initialize everything
154
+ updateButtons()
155
+ setupEventListeners()
156
+ setupUserCallbacks()
157
+
158
+ // Setup internal event listeners
159
+ emblaApi.on("select", updateButtons)
160
+ emblaApi.on("init", () => {
161
+ updateButtons()
162
+ })
163
+ emblaApi.on("reInit", () => {
164
+ updateButtons()
165
+ })
166
+
167
+ // Return manager interface
168
+ return {
169
+ api: emblaApi,
170
+ scrollPrev: () => emblaApi.scrollPrev(),
171
+ scrollNext: () => emblaApi.scrollNext(),
172
+ canScrollPrev: () => emblaApi.canScrollPrev(),
173
+ canScrollNext: () => emblaApi.canScrollNext(),
174
+ destroy: () => {
175
+ // Remove event listeners to prevent memory leaks
176
+ if (prevButtonEl) {
177
+ prevButtonEl.removeEventListener("click", prevClickHandler)
178
+ }
179
+ if (nextButtonEl) {
180
+ nextButtonEl.removeEventListener("click", nextClickHandler)
181
+ }
182
+ carouselElement.removeEventListener("keydown", keydownHandler)
183
+
184
+ // Destroy the Embla instance
185
+ emblaApi.destroy()
186
+ }
187
+ }
188
+ }
@@ -0,0 +1 @@
1
+ export * from "./carousel-script"
@@ -0,0 +1,133 @@
1
+ ---
2
+ import type { HTMLAttributes } from "astro/types";
3
+ import { scv } from "css-variants";
4
+ import IconCheck from "~icons/lucide/check";
5
+
6
+ type VariantProps<T extends (...args: any) => any> = NonNullable<Parameters<T>[0]>;
7
+
8
+ type Props = Omit<HTMLAttributes<"input">, "type"> &
9
+ VariantProps<typeof checkbox> & {
10
+ /**
11
+ * Optional label text to display next to the checkbox
12
+ */
13
+ label?: string;
14
+ };
15
+
16
+ export const checkbox = scv({
17
+ slots: ["base", "input", "icon", "label"],
18
+ base: {
19
+ base: "starwind-checkbox relative flex items-center space-x-2",
20
+ input: [
21
+ "peer border-input bg-background dark:bg-input/30 shrink-0 transform-gpu rounded-sm border",
22
+ "transition-all focus-visible:ring-3",
23
+ "outline-0 focus:ring-0 focus:ring-offset-0",
24
+ "not-disabled:cursor-pointer disabled:cursor-not-allowed disabled:op-50",
25
+ "aria-invalid:border-error aria-invalid:focus-visible:ring-error/40",
26
+ ],
27
+ icon: [
28
+ "pointer-events-none absolute stroke-3 p-0.5 op-0 transition-op peer-checked:op-100",
29
+ "starwind-check-icon",
30
+ ],
31
+ label:
32
+ "font-medium peer-not-disabled:cursor-pointer peer-disabled:cursor-not-allowed peer-disabled:op-70",
33
+ },
34
+ variants: {
35
+ size: {
36
+ sm: { input: "size-4", icon: "size-4", label: "text-sm" },
37
+ md: { input: "size-5", icon: "size-5", label: "text-base" },
38
+ lg: { input: "size-6", icon: "size-6", label: "text-lg" },
39
+ },
40
+ variant: {
41
+ default: {
42
+ input: "checked:bg-foreground focus-visible:ring-outline/50 focus-visible:border-outline",
43
+ icon: "text-background",
44
+ },
45
+ primary: {
46
+ input:
47
+ "checked:bg-primary checked:border-primary focus-visible:ring-primary/50 focus-visible:border-primary",
48
+ icon: "text-primary-foreground",
49
+ },
50
+ secondary: {
51
+ input:
52
+ "checked:bg-secondary checked:border-secondary focus-visible:ring-secondary/50 focus-visible:border-secondary",
53
+ icon: "text-secondary-foreground",
54
+ },
55
+ info: {
56
+ input:
57
+ "checked:bg-info checked:border-info focus-visible:ring-info/50 focus-visible:border-info",
58
+ icon: "text-info-foreground",
59
+ },
60
+ success: {
61
+ input:
62
+ "checked:bg-success checked:border-success focus-visible:ring-success/50 focus-visible:border-success",
63
+ icon: "text-success-foreground",
64
+ },
65
+ warning: {
66
+ input:
67
+ "checked:bg-warning checked:border-warning focus-visible:ring-warning/50 focus-visible:border-warning",
68
+ icon: "text-warning-foreground",
69
+ },
70
+ error: {
71
+ input:
72
+ "checked:bg-error checked:border-error focus-visible:ring-error/50 focus-visible:border-error",
73
+ icon: "text-error-foreground",
74
+ },
75
+ },
76
+ },
77
+ defaultVariants: { size: "md", variant: "default" },
78
+ });
79
+
80
+ const { id, label, checked, size, variant, class: className, ...rest } = Astro.props;
81
+
82
+ const { base, input, icon, label: labelClass } = checkbox({ size, variant });
83
+ ---
84
+
85
+ <div class={base}>
86
+ <input
87
+ type="checkbox"
88
+ id={id}
89
+ class:list={[input, className]}
90
+ {checked}
91
+ {...rest}
92
+ data-slot="checkbox-input"
93
+ />
94
+ <span class={icon}>
95
+ <IconCheck />
96
+ </span>
97
+ {
98
+ label && (
99
+ <label for={id} class={labelClass} data-slot="checkbox-label">
100
+ {label}
101
+ </label>
102
+ )
103
+ }
104
+ </div>
105
+
106
+ <style>
107
+ .starwind-checkbox input[type="checkbox"]:checked {
108
+ background-image: none;
109
+ }
110
+
111
+ /* Check drawing animation */
112
+ .starwind-check-icon {
113
+ stroke-dasharray: 65;
114
+ stroke-dashoffset: 65;
115
+ opacity: 0;
116
+ }
117
+
118
+ .starwind-checkbox input[type="checkbox"]:checked + .starwind-check-icon {
119
+ animation: draw-check 0.3s ease forwards;
120
+ animation-delay: 0.15s;
121
+ }
122
+
123
+ @keyframes draw-check {
124
+ 0% {
125
+ stroke-dashoffset: 65;
126
+ opacity: 1;
127
+ }
128
+ 100% {
129
+ stroke-dashoffset: 0;
130
+ opacity: 1;
131
+ }
132
+ }
133
+ </style>