@dogsbay/ui 0.2.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (322) hide show
  1. package/package.json +38 -0
  2. package/src/accordion/Accordion.astro +38 -0
  3. package/src/accordion/AccordionContent.astro +25 -0
  4. package/src/accordion/AccordionItem.astro +26 -0
  5. package/src/accordion/AccordionTrigger.astro +38 -0
  6. package/src/accordion/accordion.ts +189 -0
  7. package/src/accordion/index.ts +4 -0
  8. package/src/alert/Alert.astro +69 -0
  9. package/src/alert/AlertDescription.astro +17 -0
  10. package/src/alert/AlertTitle.astro +21 -0
  11. package/src/alert/CollapsibleAlert.astro +103 -0
  12. package/src/alert/icon.ts +32 -0
  13. package/src/alert/index.ts +4 -0
  14. package/src/alert/variants.ts +29 -0
  15. package/src/alert-dialog/AlertDialog.astro +16 -0
  16. package/src/alert-dialog/AlertDialogAction.astro +23 -0
  17. package/src/alert-dialog/AlertDialogCancel.astro +23 -0
  18. package/src/alert-dialog/AlertDialogContent.astro +37 -0
  19. package/src/alert-dialog/AlertDialogDescription.astro +18 -0
  20. package/src/alert-dialog/AlertDialogFooter.astro +18 -0
  21. package/src/alert-dialog/AlertDialogHeader.astro +18 -0
  22. package/src/alert-dialog/AlertDialogTitle.astro +18 -0
  23. package/src/alert-dialog/AlertDialogTrigger.astro +24 -0
  24. package/src/alert-dialog/alert-dialog.ts +154 -0
  25. package/src/alert-dialog/index.ts +9 -0
  26. package/src/api-doc/ApiDoc.astro +52 -0
  27. package/src/api-doc/index.ts +1 -0
  28. package/src/api-layout/ApiCodePanel.astro +21 -0
  29. package/src/api-layout/ApiLayout.astro +29 -0
  30. package/src/api-layout/ExampleBlock.astro +63 -0
  31. package/src/api-params/ApiParams.astro +96 -0
  32. package/src/api-params/index.ts +1 -0
  33. package/src/api-source/ApiSource.astro +20 -0
  34. package/src/api-source/api-source.css +32 -0
  35. package/src/api-source/index.ts +1 -0
  36. package/src/api-symbol/ApiSymbol.astro +48 -0
  37. package/src/api-symbol/api-symbol.css +89 -0
  38. package/src/api-symbol/index.ts +1 -0
  39. package/src/api-url-bar/ApiUrlBar.astro +63 -0
  40. package/src/avatar/Avatar.astro +57 -0
  41. package/src/avatar/index.ts +1 -0
  42. package/src/badge/Badge.astro +37 -0
  43. package/src/badge/index.ts +1 -0
  44. package/src/breadcrumb/Breadcrumb.astro +32 -0
  45. package/src/breadcrumb/BreadcrumbEllipsis.astro +32 -0
  46. package/src/breadcrumb/BreadcrumbItem.astro +41 -0
  47. package/src/breadcrumb/BreadcrumbSeparator.astro +33 -0
  48. package/src/breadcrumb/index.ts +4 -0
  49. package/src/button/Button.astro +70 -0
  50. package/src/button/index.ts +1 -0
  51. package/src/card/Card.astro +17 -0
  52. package/src/card/CardContent.astro +17 -0
  53. package/src/card/CardDescription.astro +17 -0
  54. package/src/card/CardFooter.astro +17 -0
  55. package/src/card/CardHeader.astro +17 -0
  56. package/src/card/CardTitle.astro +17 -0
  57. package/src/card/index.ts +6 -0
  58. package/src/checkbox/Checkbox.astro +70 -0
  59. package/src/checkbox/index.ts +1 -0
  60. package/src/checkbox-group/CheckboxGroup.astro +38 -0
  61. package/src/checkbox-group/checkbox-group.ts +53 -0
  62. package/src/checkbox-group/index.ts +1 -0
  63. package/src/code-block/CodeBlock.astro +160 -0
  64. package/src/code-rich/CodeRich.astro +267 -0
  65. package/src/code-rich/code-rich.css +68 -0
  66. package/src/code-rich/index.ts +1 -0
  67. package/src/code-samples/CodeSamples.astro +59 -0
  68. package/src/collapsible/Collapsible.astro +35 -0
  69. package/src/collapsible/CollapsibleContent.astro +24 -0
  70. package/src/collapsible/CollapsibleTrigger.astro +23 -0
  71. package/src/collapsible/collapsible.ts +42 -0
  72. package/src/collapsible/index.ts +3 -0
  73. package/src/combobox/Combobox.astro +53 -0
  74. package/src/combobox/ComboboxEmpty.astro +18 -0
  75. package/src/combobox/ComboboxItem.astro +28 -0
  76. package/src/combobox/combobox.ts +179 -0
  77. package/src/combobox/index.ts +3 -0
  78. package/src/command/Command.astro +22 -0
  79. package/src/command/CommandEmpty.astro +18 -0
  80. package/src/command/CommandGroup.astro +24 -0
  81. package/src/command/CommandInput.astro +49 -0
  82. package/src/command/CommandItem.astro +26 -0
  83. package/src/command/CommandList.astro +19 -0
  84. package/src/command/CommandSeparator.astro +16 -0
  85. package/src/command/CommandShortcut.astro +18 -0
  86. package/src/command/command.ts +212 -0
  87. package/src/command/index.ts +8 -0
  88. package/src/content-renderer/ContentRenderer.astro +410 -0
  89. package/src/content-renderer/InlineRenderer.astro +149 -0
  90. package/src/context-menu/ContextMenu.astro +22 -0
  91. package/src/context-menu/ContextMenuContent.astro +24 -0
  92. package/src/context-menu/ContextMenuItem.astro +49 -0
  93. package/src/context-menu/ContextMenuSeparator.astro +14 -0
  94. package/src/context-menu/ContextMenuShortcut.astro +14 -0
  95. package/src/context-menu/ContextMenuTrigger.astro +22 -0
  96. package/src/context-menu/context-menu.ts +238 -0
  97. package/src/context-menu/index.ts +6 -0
  98. package/src/copy-button/CopyButton.astro +88 -0
  99. package/src/copy-button/index.ts +1 -0
  100. package/src/diagram/Diagram.astro +15 -0
  101. package/src/diagram/index.ts +1 -0
  102. package/src/dialog/Dialog.astro +22 -0
  103. package/src/dialog/DialogClose.astro +32 -0
  104. package/src/dialog/DialogContent.astro +37 -0
  105. package/src/dialog/DialogDescription.astro +22 -0
  106. package/src/dialog/DialogFooter.astro +18 -0
  107. package/src/dialog/DialogHeader.astro +18 -0
  108. package/src/dialog/DialogTitle.astro +18 -0
  109. package/src/dialog/DialogTrigger.astro +33 -0
  110. package/src/dialog/dialog.ts +291 -0
  111. package/src/dialog/index.ts +8 -0
  112. package/src/docs-footer/DocsFooter.astro +50 -0
  113. package/src/docs-header/DocsHeader.astro +32 -0
  114. package/src/docs-layout/DocsLayout.astro +187 -0
  115. package/src/docs-layout/index.ts +1 -0
  116. package/src/drawer/Drawer.astro +12 -0
  117. package/src/drawer/DrawerClose.astro +12 -0
  118. package/src/drawer/DrawerContent.astro +46 -0
  119. package/src/drawer/DrawerDescription.astro +10 -0
  120. package/src/drawer/DrawerFooter.astro +10 -0
  121. package/src/drawer/DrawerHandle.astro +16 -0
  122. package/src/drawer/DrawerHeader.astro +10 -0
  123. package/src/drawer/DrawerTitle.astro +10 -0
  124. package/src/drawer/DrawerTrigger.astro +25 -0
  125. package/src/drawer/drawer.ts +262 -0
  126. package/src/drawer/index.ts +9 -0
  127. package/src/dropdown-menu/DropdownMenu.astro +22 -0
  128. package/src/dropdown-menu/DropdownMenuContent.astro +33 -0
  129. package/src/dropdown-menu/DropdownMenuGroup.astro +17 -0
  130. package/src/dropdown-menu/DropdownMenuItem.astro +48 -0
  131. package/src/dropdown-menu/DropdownMenuLabel.astro +28 -0
  132. package/src/dropdown-menu/DropdownMenuSeparator.astro +21 -0
  133. package/src/dropdown-menu/DropdownMenuShortcut.astro +18 -0
  134. package/src/dropdown-menu/DropdownMenuTrigger.astro +34 -0
  135. package/src/dropdown-menu/dropdown-menu.ts +348 -0
  136. package/src/dropdown-menu/index.ts +8 -0
  137. package/src/endpoint-card/EndpointCard.astro +60 -0
  138. package/src/endpoint-card/EndpointCardSection.astro +22 -0
  139. package/src/endpoint-card/EndpointSection.astro +35 -0
  140. package/src/field/Field.astro +31 -0
  141. package/src/field/FieldDescription.astro +22 -0
  142. package/src/field/FieldLabel.astro +24 -0
  143. package/src/field/field.ts +61 -0
  144. package/src/field/index.ts +3 -0
  145. package/src/fieldset/Fieldset.astro +24 -0
  146. package/src/fieldset/FieldsetLegend.astro +18 -0
  147. package/src/fieldset/index.ts +2 -0
  148. package/src/footnote/Footnote.astro +37 -0
  149. package/src/footnote/footnote.ts +79 -0
  150. package/src/footnote/index.ts +1 -0
  151. package/src/form/Form.astro +27 -0
  152. package/src/form/form.ts +160 -0
  153. package/src/form/index.ts +1 -0
  154. package/src/grid/Grid.astro +117 -0
  155. package/src/grid/GridItem.astro +95 -0
  156. package/src/grid/index.ts +2 -0
  157. package/src/image/Image.astro +115 -0
  158. package/src/image/index.ts +1 -0
  159. package/src/input/Input.astro +34 -0
  160. package/src/input/index.ts +1 -0
  161. package/src/kbd/Kbd.astro +17 -0
  162. package/src/kbd/index.ts +1 -0
  163. package/src/label/Label.astro +17 -0
  164. package/src/label/index.ts +1 -0
  165. package/src/link-card/LinkCard.astro +47 -0
  166. package/src/link-card/index.ts +1 -0
  167. package/src/map-view/MapView.astro +88 -0
  168. package/src/map-view/index.ts +1 -0
  169. package/src/map-view/map-view.ts +194 -0
  170. package/src/markdown-example/MarkdownExample.astro +138 -0
  171. package/src/markdown-example/index.ts +1 -0
  172. package/src/math/MathKatex.astro +35 -0
  173. package/src/math/index.ts +1 -0
  174. package/src/menubar/Menubar.astro +25 -0
  175. package/src/menubar/MenubarContent.astro +24 -0
  176. package/src/menubar/MenubarItem.astro +26 -0
  177. package/src/menubar/MenubarMenu.astro +12 -0
  178. package/src/menubar/MenubarSeparator.astro +11 -0
  179. package/src/menubar/MenubarShortcut.astro +11 -0
  180. package/src/menubar/MenubarTrigger.astro +27 -0
  181. package/src/menubar/index.ts +7 -0
  182. package/src/menubar/menubar.ts +258 -0
  183. package/src/meter/Meter.astro +75 -0
  184. package/src/meter/index.ts +1 -0
  185. package/src/method-badge/MethodBadge.astro +32 -0
  186. package/src/navigation-menu/NavigationMenu.astro +24 -0
  187. package/src/navigation-menu/NavigationMenuContent.astro +24 -0
  188. package/src/navigation-menu/NavigationMenuItem.astro +22 -0
  189. package/src/navigation-menu/NavigationMenuLink.astro +26 -0
  190. package/src/navigation-menu/NavigationMenuList.astro +22 -0
  191. package/src/navigation-menu/NavigationMenuTrigger.astro +40 -0
  192. package/src/navigation-menu/index.ts +6 -0
  193. package/src/navigation-menu/navigation-menu.ts +192 -0
  194. package/src/number-field/NumberField.astro +84 -0
  195. package/src/number-field/index.ts +1 -0
  196. package/src/number-field/number-field.ts +68 -0
  197. package/src/pagination/Pagination.astro +59 -0
  198. package/src/pagination/index.ts +1 -0
  199. package/src/parameter-table/ParameterTable.astro +75 -0
  200. package/src/popover/Popover.astro +21 -0
  201. package/src/popover/PopoverContent.astro +31 -0
  202. package/src/popover/PopoverTrigger.astro +31 -0
  203. package/src/popover/index.ts +3 -0
  204. package/src/popover/popover.ts +144 -0
  205. package/src/preview-card/PreviewCard.astro +24 -0
  206. package/src/preview-card/PreviewCardContent.astro +24 -0
  207. package/src/preview-card/PreviewCardTrigger.astro +23 -0
  208. package/src/preview-card/index.ts +3 -0
  209. package/src/preview-card/preview-card.ts +91 -0
  210. package/src/progress/Progress.astro +61 -0
  211. package/src/progress/index.ts +1 -0
  212. package/src/property-item/PropertyItem.astro +183 -0
  213. package/src/property-list/PropertyList.astro +68 -0
  214. package/src/radio-group/RadioGroup.astro +41 -0
  215. package/src/radio-group/RadioGroupItem.astro +36 -0
  216. package/src/radio-group/index.ts +2 -0
  217. package/src/radio-group/radio-group.ts +126 -0
  218. package/src/response-tabs/ResponseTabs.astro +60 -0
  219. package/src/schema-viewer/SchemaViewer.astro +42 -0
  220. package/src/scroll-area/ScrollArea.astro +44 -0
  221. package/src/scroll-area/index.ts +1 -0
  222. package/src/scroll-area/scroll-area.ts +176 -0
  223. package/src/select/Select.astro +34 -0
  224. package/src/select/SelectContent.astro +24 -0
  225. package/src/select/SelectGroup.astro +23 -0
  226. package/src/select/SelectItem.astro +28 -0
  227. package/src/select/SelectLabel.astro +18 -0
  228. package/src/select/SelectSeparator.astro +22 -0
  229. package/src/select/SelectTrigger.astro +28 -0
  230. package/src/select/SelectValue.astro +18 -0
  231. package/src/select/index.ts +8 -0
  232. package/src/select/select.ts +381 -0
  233. package/src/separator/Separator.astro +35 -0
  234. package/src/separator/index.ts +1 -0
  235. package/src/sheet/Sheet.astro +12 -0
  236. package/src/sheet/SheetClose.astro +35 -0
  237. package/src/sheet/SheetContent.astro +52 -0
  238. package/src/sheet/SheetDescription.astro +18 -0
  239. package/src/sheet/SheetFooter.astro +18 -0
  240. package/src/sheet/SheetHeader.astro +18 -0
  241. package/src/sheet/SheetTitle.astro +18 -0
  242. package/src/sheet/SheetTrigger.astro +32 -0
  243. package/src/sheet/index.ts +8 -0
  244. package/src/sheet/sheet.ts +173 -0
  245. package/src/sidebar/Sidebar.astro +113 -0
  246. package/src/sidebar/SidebarContent.astro +18 -0
  247. package/src/sidebar/SidebarFooter.astro +18 -0
  248. package/src/sidebar/SidebarGroup.astro +18 -0
  249. package/src/sidebar/SidebarGroupContent.astro +18 -0
  250. package/src/sidebar/SidebarGroupLabel.astro +18 -0
  251. package/src/sidebar/SidebarHeader.astro +18 -0
  252. package/src/sidebar/SidebarInset.astro +18 -0
  253. package/src/sidebar/SidebarMenu.astro +18 -0
  254. package/src/sidebar/SidebarMenuBadge.astro +18 -0
  255. package/src/sidebar/SidebarMenuButton.astro +71 -0
  256. package/src/sidebar/SidebarMenuItem.astro +18 -0
  257. package/src/sidebar/SidebarMenuSub.astro +18 -0
  258. package/src/sidebar/SidebarMenuSubButton.astro +45 -0
  259. package/src/sidebar/SidebarMenuSubItem.astro +12 -0
  260. package/src/sidebar/SidebarNavTree.astro +106 -0
  261. package/src/sidebar/SidebarProvider.astro +23 -0
  262. package/src/sidebar/SidebarRail.astro +25 -0
  263. package/src/sidebar/SidebarSeparator.astro +21 -0
  264. package/src/sidebar/SidebarTrigger.astro +40 -0
  265. package/src/sidebar/index.ts +19 -0
  266. package/src/sidebar/sidebar.ts +265 -0
  267. package/src/skeleton/Skeleton.astro +16 -0
  268. package/src/skeleton/index.ts +1 -0
  269. package/src/skip-link/SkipLink.astro +24 -0
  270. package/src/slider/Slider.astro +61 -0
  271. package/src/slider/index.ts +1 -0
  272. package/src/slider/slider.ts +111 -0
  273. package/src/spinner/Spinner.astro +54 -0
  274. package/src/spinner/index.ts +1 -0
  275. package/src/steps/Step.astro +16 -0
  276. package/src/steps/Steps.astro +122 -0
  277. package/src/steps/SubSteps.astro +73 -0
  278. package/src/switch/Switch.astro +52 -0
  279. package/src/switch/index.ts +1 -0
  280. package/src/switch/switch.ts +109 -0
  281. package/src/table/Table.astro +24 -0
  282. package/src/table/TableBody.astro +18 -0
  283. package/src/table/TableCaption.astro +18 -0
  284. package/src/table/TableCell.astro +18 -0
  285. package/src/table/TableFooter.astro +18 -0
  286. package/src/table/TableHead.astro +18 -0
  287. package/src/table/TableHeader.astro +18 -0
  288. package/src/table/TableRow.astro +18 -0
  289. package/src/table/index.ts +8 -0
  290. package/src/tabs/Tabs.astro +37 -0
  291. package/src/tabs/TabsContent.astro +32 -0
  292. package/src/tabs/TabsList.astro +23 -0
  293. package/src/tabs/TabsTrigger.astro +29 -0
  294. package/src/tabs/index.ts +4 -0
  295. package/src/tabs/tabs.ts +220 -0
  296. package/src/textarea/Textarea.astro +25 -0
  297. package/src/textarea/index.ts +1 -0
  298. package/src/theme-toggle/ThemeToggle.astro +67 -0
  299. package/src/theme-toggle/index.ts +1 -0
  300. package/src/toast/Toaster.astro +39 -0
  301. package/src/toast/index.ts +3 -0
  302. package/src/toast/toast.ts +104 -0
  303. package/src/toc/TableOfContents.astro +225 -0
  304. package/src/toggle/Toggle.astro +56 -0
  305. package/src/toggle/index.ts +1 -0
  306. package/src/toggle/toggle.ts +38 -0
  307. package/src/toggle-group/ToggleGroup.astro +39 -0
  308. package/src/toggle-group/ToggleGroupItem.astro +56 -0
  309. package/src/toggle-group/index.ts +2 -0
  310. package/src/toggle-group/toggle-group.ts +121 -0
  311. package/src/toolbar/Toolbar.astro +26 -0
  312. package/src/toolbar/ToolbarButton.astro +29 -0
  313. package/src/toolbar/ToolbarSeparator.astro +14 -0
  314. package/src/toolbar/index.ts +3 -0
  315. package/src/toolbar/toolbar.ts +65 -0
  316. package/src/tooltip/Tooltip.astro +21 -0
  317. package/src/tooltip/TooltipContent.astro +25 -0
  318. package/src/tooltip/TooltipTrigger.astro +31 -0
  319. package/src/tooltip/index.ts +3 -0
  320. package/src/tooltip/tooltip.ts +156 -0
  321. package/src/youtube/YouTube.astro +119 -0
  322. package/src/youtube/index.ts +1 -0
@@ -0,0 +1,70 @@
1
+ ---
2
+ import { tv } from "tailwind-variants";
3
+
4
+ const checkboxWrapper = tv({
5
+ base: "inline-flex items-center gap-2 cursor-pointer",
6
+ });
7
+
8
+ const checkboxInput = tv({
9
+ base: "absolute h-px w-px overflow-hidden [clip:rect(0,0,0,0)] whitespace-nowrap",
10
+ });
11
+
12
+ const checkboxVisual = tv({
13
+ base: "inline-flex h-[1.125rem] w-[1.125rem] shrink-0 items-center justify-center rounded-[0.25rem] border border-primary transition-colors peer-checked:bg-primary peer-checked:text-primary-foreground peer-disabled:cursor-not-allowed peer-disabled:opacity-50 peer-focus-visible:outline-2 peer-focus-visible:outline-offset-2 peer-focus-visible:outline-ring",
14
+ });
15
+
16
+ interface Props {
17
+ name?: string;
18
+ defaultChecked?: boolean;
19
+ disabled?: boolean;
20
+ required?: boolean;
21
+ value?: string;
22
+ class?: string;
23
+ [key: string]: unknown;
24
+ }
25
+
26
+ const {
27
+ name,
28
+ defaultChecked = false,
29
+ disabled = false,
30
+ required = false,
31
+ value = "on",
32
+ class: className,
33
+ ...rest
34
+ } = Astro.props;
35
+ ---
36
+
37
+ <label class={checkboxWrapper({ class: className })}>
38
+ <input
39
+ class={`peer ${checkboxInput()}`}
40
+ data-component="checkbox"
41
+ type="checkbox"
42
+ name={name}
43
+ value={value}
44
+ checked={defaultChecked}
45
+ disabled={disabled || undefined}
46
+ required={required || undefined}
47
+ {...rest}
48
+ />
49
+ <span
50
+ class={checkboxVisual()}
51
+ data-state={defaultChecked ? "checked" : "unchecked"}
52
+ aria-hidden="true"
53
+ >
54
+ <svg
55
+ class="hidden peer-checked:block h-3.5 w-3.5"
56
+ xmlns="http://www.w3.org/2000/svg"
57
+ width="14"
58
+ height="14"
59
+ viewBox="0 0 24 24"
60
+ fill="none"
61
+ stroke="currentColor"
62
+ stroke-width="3"
63
+ stroke-linecap="round"
64
+ stroke-linejoin="round"
65
+ >
66
+ <polyline points="20 6 9 17 4 12"></polyline>
67
+ </svg>
68
+ </span>
69
+ <slot />
70
+ </label>
@@ -0,0 +1 @@
1
+ export { default as Checkbox } from "./Checkbox.astro";
@@ -0,0 +1,38 @@
1
+ ---
2
+ import { tv } from "tailwind-variants";
3
+
4
+ const checkboxGroup = tv({
5
+ base: "space-y-3",
6
+ });
7
+
8
+ interface Props {
9
+ name?: string;
10
+ defaultValue?: string[];
11
+ disabled?: boolean;
12
+ orientation?: "vertical" | "horizontal";
13
+ class?: string;
14
+ [key: string]: unknown;
15
+ }
16
+
17
+ const {
18
+ name,
19
+ defaultValue = [],
20
+ disabled = false,
21
+ orientation = "vertical",
22
+ class: className,
23
+ ...rest
24
+ } = Astro.props;
25
+ ---
26
+
27
+ <div
28
+ class={checkboxGroup({ class: className })}
29
+ data-component="checkbox-group"
30
+ data-name={name}
31
+ data-default-value={defaultValue.join(",")}
32
+ data-disabled={disabled || undefined}
33
+ data-orientation={orientation}
34
+ role="group"
35
+ {...rest}
36
+ >
37
+ <slot />
38
+ </div>
@@ -0,0 +1,53 @@
1
+ function init(root: HTMLElement) {
2
+ if (root.hasAttribute("data-initialized")) return;
3
+ root.setAttribute("data-initialized", "");
4
+
5
+ const name = root.getAttribute("data-name") || "";
6
+ const disabled = root.hasAttribute("data-disabled");
7
+
8
+ // Find all checkboxes inside the group
9
+ const checkboxes = () =>
10
+ Array.from(root.querySelectorAll<HTMLInputElement>("input[type='checkbox']"));
11
+
12
+ // Initialize default values
13
+ const defaultValue = root.getAttribute("data-default-value") || "";
14
+ const defaults = defaultValue ? defaultValue.split(",") : [];
15
+
16
+ checkboxes().forEach((cb) => {
17
+ if (defaults.includes(cb.value)) {
18
+ cb.checked = true;
19
+ }
20
+ if (disabled) {
21
+ cb.disabled = true;
22
+ }
23
+ // Ensure name is set for form submission
24
+ if (name && !cb.name) {
25
+ cb.name = name;
26
+ }
27
+ });
28
+
29
+ // Dispatch change event when any checkbox changes
30
+ root.addEventListener("change", () => {
31
+ const values = checkboxes()
32
+ .filter((cb) => cb.checked)
33
+ .map((cb) => cb.value);
34
+
35
+ root.dispatchEvent(
36
+ new CustomEvent("base-checkbox-group:change", {
37
+ detail: { values },
38
+ bubbles: true,
39
+ }),
40
+ );
41
+ });
42
+ }
43
+
44
+ function initAll() {
45
+ document.querySelectorAll<HTMLElement>("[data-component='checkbox-group']").forEach(init);
46
+ }
47
+
48
+ if (document.readyState === "loading") {
49
+ document.addEventListener("DOMContentLoaded", initAll);
50
+ } else {
51
+ initAll();
52
+ }
53
+ document.addEventListener("astro:page-load", initAll);
@@ -0,0 +1 @@
1
+ export { default as CheckboxGroup } from "./CheckboxGroup.astro";
@@ -0,0 +1,160 @@
1
+ ---
2
+ import { Code } from "astro/components";
3
+ import { tv } from "tailwind-variants";
4
+
5
+ const codeBlockWrapper = tv({
6
+ base: "group relative overflow-hidden rounded-lg border bg-code-bg text-sm",
7
+ });
8
+
9
+ const codeBlockHeader = tv({
10
+ base: "flex items-center justify-between border-b border-code-fg/10 bg-code-fg/5 px-4 py-2 text-xs text-code-fg/70",
11
+ });
12
+
13
+ const codeBlockCopy = tv({
14
+ base: "inline-flex h-7 w-7 items-center justify-center rounded-md text-code-fg/50 transition-colors hover:bg-code-fg/10 hover:text-code-fg/80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
15
+ });
16
+
17
+ interface Props {
18
+ /** The code string to highlight */
19
+ code: string;
20
+ /** Programming language for syntax highlighting */
21
+ lang?: string;
22
+ /** Optional title displayed in the header bar */
23
+ title?: string;
24
+ /** Show copy button (default: true) */
25
+ copy?: boolean;
26
+ /** Show the header title bar. true = always, false = never, "auto" = only when title prop is set (default: true) */
27
+ showTitle?: boolean | "auto";
28
+ /** Shiki theme (default: "github-dark") */
29
+ theme?: string;
30
+ class?: string;
31
+ [key: string]: unknown;
32
+ }
33
+
34
+ const {
35
+ code,
36
+ lang = "plaintext",
37
+ title,
38
+ copy = true,
39
+ showTitle = true,
40
+ theme = "github-dark-default",
41
+ class: className,
42
+ ...rest
43
+ } = Astro.props;
44
+
45
+ // Show header bar based on showTitle prop:
46
+ // - true: show when there's a title or a declared language (default, original behavior)
47
+ // - false: never show
48
+ // - "auto": only show when an explicit title is provided (not lang-only)
49
+ const showHeader =
50
+ showTitle === false ? false
51
+ : showTitle === "auto" ? !!title
52
+ : !!title || lang !== "plaintext";
53
+ // When no header, copy button floats inside the code body
54
+ const floatingCopy = copy && !showHeader;
55
+ ---
56
+
57
+ <div
58
+ class={codeBlockWrapper({ class: className })}
59
+ data-component="code-block"
60
+ {...rest}
61
+ >
62
+ {showHeader && (
63
+ <div class={codeBlockHeader()}>
64
+ <span class="select-none">{title || lang}</span>
65
+ {copy && (
66
+ <button
67
+ class={codeBlockCopy()}
68
+ data-part="copy"
69
+ data-copy-text={code}
70
+ type="button"
71
+ aria-label="Copy code"
72
+ >
73
+ <svg
74
+ xmlns="http://www.w3.org/2000/svg"
75
+ width="14"
76
+ height="14"
77
+ viewBox="0 0 24 24"
78
+ fill="none"
79
+ stroke="currentColor"
80
+ stroke-width="2"
81
+ stroke-linecap="round"
82
+ stroke-linejoin="round"
83
+ data-copy-icon
84
+ aria-hidden="true"
85
+ >
86
+ <rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect>
87
+ <path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path>
88
+ </svg>
89
+ <svg
90
+ xmlns="http://www.w3.org/2000/svg"
91
+ width="14"
92
+ height="14"
93
+ viewBox="0 0 24 24"
94
+ fill="none"
95
+ stroke="currentColor"
96
+ stroke-width="2"
97
+ stroke-linecap="round"
98
+ stroke-linejoin="round"
99
+ data-check-icon
100
+ class="hidden"
101
+ aria-hidden="true"
102
+ >
103
+ <polyline points="20 6 9 17 4 12"></polyline>
104
+ </svg>
105
+ </button>
106
+ )}
107
+ </div>
108
+ )}
109
+ <div class="relative overflow-x-auto [&_pre]:!m-0 [&_pre]:!rounded-none [&_pre]:!border-0 [&_pre]:px-4 [&_pre]:py-3">
110
+ <Code code={code} lang={lang.toLowerCase()} themes={{ light: "github-light-default", dark: theme }} defaultColor={false} />
111
+ {floatingCopy && (
112
+ <button
113
+ class:list={[codeBlockCopy(), "absolute right-2 top-2 opacity-0 group-hover:opacity-100 transition-opacity"]}
114
+ data-part="copy"
115
+ data-copy-text={code}
116
+ type="button"
117
+ aria-label="Copy code"
118
+ >
119
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-copy-icon aria-hidden="true">
120
+ <rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect>
121
+ <path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path>
122
+ </svg>
123
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-check-icon class="hidden" aria-hidden="true">
124
+ <polyline points="20 6 9 17 4 12"></polyline>
125
+ </svg>
126
+ </button>
127
+ )}
128
+ </div>
129
+ </div>
130
+
131
+ <script>
132
+ function setupCodeBlockCopy() {
133
+ document.querySelectorAll("[data-component='code-block'] [data-part='copy']").forEach((btn) => {
134
+ if ((btn as any).__copyBound) return;
135
+ (btn as any).__copyBound = true;
136
+
137
+ btn.addEventListener("click", async () => {
138
+ const text = btn.getAttribute("data-copy-text") || "";
139
+ try {
140
+ await navigator.clipboard.writeText(text);
141
+ const copyIcon = btn.querySelector("[data-copy-icon]") as HTMLElement;
142
+ const checkIcon = btn.querySelector("[data-check-icon]") as HTMLElement;
143
+ if (copyIcon && checkIcon) {
144
+ copyIcon.classList.add("hidden");
145
+ checkIcon.classList.remove("hidden");
146
+ setTimeout(() => {
147
+ copyIcon.classList.remove("hidden");
148
+ checkIcon.classList.add("hidden");
149
+ }, 2000);
150
+ }
151
+ } catch {
152
+ // Fallback: do nothing
153
+ }
154
+ });
155
+ });
156
+ }
157
+
158
+ setupCodeBlockCopy();
159
+ document.addEventListener("astro:after-swap", setupCodeBlockCopy);
160
+ </script>
@@ -0,0 +1,267 @@
1
+ ---
2
+ import "./code-rich.css";
3
+ import { codeToHtml, type BundledLanguage, type BundledTheme } from "shiki";
4
+ import {
5
+ transformerNotationDiff,
6
+ transformerNotationHighlight,
7
+ transformerNotationFocus,
8
+ transformerNotationErrorLevel,
9
+ transformerNotationWordHighlight,
10
+ transformerMetaHighlight,
11
+ transformerMetaWordHighlight,
12
+ } from "@shikijs/transformers";
13
+ import type { ShikiTransformer } from "shiki";
14
+ import { tv } from "tailwind-variants";
15
+
16
+ const codeRichWrapper = tv({
17
+ base: "group relative overflow-hidden rounded-lg border bg-code-bg text-sm",
18
+ });
19
+
20
+ const codeRichHeader = tv({
21
+ base: "flex items-center justify-between border-b border-code-fg/10 bg-code-fg/5 px-4 py-2 text-xs text-code-fg/70",
22
+ });
23
+
24
+ const codeRichCopy = tv({
25
+ base: "inline-flex h-7 w-7 items-center justify-center rounded-md text-code-fg/50 transition-colors hover:bg-code-fg/10 hover:text-code-fg/80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
26
+ });
27
+
28
+ interface Props {
29
+ /** The code string to highlight */
30
+ code: string;
31
+ /** Programming language for syntax highlighting */
32
+ lang?: string;
33
+ /** Optional title/filename displayed in the header bar */
34
+ title?: string;
35
+ /** Show copy button (default: true) */
36
+ copy?: boolean;
37
+ /** Show line numbers (default: false) */
38
+ lineNumbers?: boolean;
39
+ /** Starting line number (default: 1) */
40
+ startLine?: number;
41
+ /** Lines to highlight, e.g. "1,3-5" */
42
+ highlights?: string;
43
+ /** Words to highlight, e.g. "Hello" */
44
+ wordHighlights?: string;
45
+ /** Shiki theme */
46
+ theme?: string;
47
+ class?: string;
48
+ [key: string]: unknown;
49
+ }
50
+
51
+ const {
52
+ code,
53
+ lang = "plaintext",
54
+ title,
55
+ copy = true,
56
+ lineNumbers = false,
57
+ startLine = 1,
58
+ highlights,
59
+ wordHighlights,
60
+ theme = "github-dark-default",
61
+ class: className,
62
+ ...rest
63
+ } = Astro.props;
64
+
65
+ // Build transformers list
66
+ const transformers: ShikiTransformer[] = [
67
+ transformerNotationDiff(),
68
+ transformerNotationHighlight(),
69
+ transformerNotationFocus(),
70
+ transformerNotationErrorLevel(),
71
+ transformerNotationWordHighlight(),
72
+ ];
73
+
74
+ // Meta-based highlights: ```ts {1,3-5}
75
+ if (highlights) {
76
+ transformers.push(transformerMetaHighlight());
77
+ }
78
+
79
+ // Meta-based word highlights: ```ts /word/
80
+ if (wordHighlights) {
81
+ transformers.push(transformerMetaWordHighlight());
82
+ }
83
+
84
+ // Gutter: inject line number + diff marker spans into each line
85
+ // Single gutter: "5 +" or "5 −" or "5" or "+" or "−"
86
+ transformers.push({
87
+ name: "gutter",
88
+ code(node) {
89
+ // Runs after all line hooks — diff classes are now set
90
+ const lines = node.children.filter(
91
+ (c: any) => c.type === "element" && c.tagName === "span",
92
+ );
93
+
94
+ // Check if any line has diffs — if so, reserve the +/- column for all lines
95
+ const getClass = (n: any) => {
96
+ const rc = n.properties?.class ?? n.properties?.className ?? "";
97
+ return Array.isArray(rc) ? rc.join(" ") : String(rc);
98
+ };
99
+ const hasDiffs = lines.some((n: any) => getClass(n).includes("diff"));
100
+
101
+ let lineNum = startLine;
102
+ for (const lineNode of lines) {
103
+ const cls = getClass(lineNode);
104
+ if (!cls.includes("line")) continue;
105
+
106
+ const isAdd = cls.includes("add");
107
+ const isRemove = cls.includes("remove");
108
+
109
+ const needsGutter = lineNumbers || hasDiffs;
110
+ if (needsGutter) {
111
+ // Build separate fixed-width parts
112
+ const parts: string[] = [];
113
+ if (lineNumbers) {
114
+ parts.push(String(lineNum).padStart(3));
115
+ }
116
+ if (hasDiffs) {
117
+ parts.push(isAdd ? "+" : isRemove ? "−" : " ");
118
+ }
119
+
120
+ const gutterClass = `gutter${isAdd ? " add" : isRemove ? " remove" : ""}`;
121
+ (lineNode as any).children.unshift({
122
+ type: "element",
123
+ tagName: "span",
124
+ properties: { class: gutterClass },
125
+ children: [{ type: "text", value: parts.join(" ") }],
126
+ });
127
+ }
128
+
129
+ lineNum++;
130
+ }
131
+ },
132
+ });
133
+
134
+ // Build meta string
135
+ let metaStr = "";
136
+ if (highlights) metaStr += `{${highlights}} `;
137
+ if (wordHighlights) metaStr += `/${wordHighlights}/ `;
138
+
139
+ // Strip annotation comments from the copy text
140
+ const copyText = code
141
+ .replace(/\s*\/\/\s*\[!code\s[^\]]*\]\s*$/gm, "")
142
+ .replace(/\s*\/\/\s*![a-z]+.*$/gm, "")
143
+ .trim();
144
+
145
+ const html = await codeToHtml(code, {
146
+ lang: lang.toLowerCase() as BundledLanguage,
147
+ themes: {
148
+ light: "github-light-default" as BundledTheme,
149
+ dark: (theme || "github-dark-default") as BundledTheme,
150
+ },
151
+ defaultColor: false,
152
+ transformers,
153
+ meta: metaStr ? { __raw: metaStr } : undefined,
154
+ });
155
+
156
+ // Show header bar only when there's a title or a declared language
157
+ const hasLabel = !!title || (lang !== "plaintext");
158
+ const showHeader = hasLabel;
159
+ // When no header, copy button floats inside the code body
160
+ const floatingCopy = copy && !showHeader;
161
+ ---
162
+
163
+ <div
164
+ class={codeRichWrapper({ class: className })}
165
+ data-component="code-rich"
166
+ data-line-numbers={lineNumbers || undefined}
167
+ {...rest}
168
+ >
169
+ {showHeader && (
170
+ <div class={codeRichHeader()}>
171
+ <span class="select-none">{title || lang}</span>
172
+ {copy && (
173
+ <button
174
+ class={codeRichCopy()}
175
+ data-part="copy"
176
+ data-copy-text={copyText}
177
+ type="button"
178
+ aria-label="Copy code"
179
+ >
180
+ <svg
181
+ xmlns="http://www.w3.org/2000/svg"
182
+ width="14"
183
+ height="14"
184
+ viewBox="0 0 24 24"
185
+ fill="none"
186
+ stroke="currentColor"
187
+ stroke-width="2"
188
+ stroke-linecap="round"
189
+ stroke-linejoin="round"
190
+ data-copy-icon
191
+ aria-hidden="true"
192
+ >
193
+ <rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect>
194
+ <path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path>
195
+ </svg>
196
+ <svg
197
+ xmlns="http://www.w3.org/2000/svg"
198
+ width="14"
199
+ height="14"
200
+ viewBox="0 0 24 24"
201
+ fill="none"
202
+ stroke="currentColor"
203
+ stroke-width="2"
204
+ stroke-linecap="round"
205
+ stroke-linejoin="round"
206
+ data-check-icon
207
+ class="hidden"
208
+ aria-hidden="true"
209
+ >
210
+ <polyline points="20 6 9 17 4 12"></polyline>
211
+ </svg>
212
+ </button>
213
+ )}
214
+ </div>
215
+ )}
216
+ <div class="code-rich-body relative overflow-x-auto [&_pre]:!m-0 [&_pre]:!rounded-none [&_pre]:!border-0 [&_pre]:!bg-transparent [&_pre]:px-4 [&_pre]:py-3">
217
+ <Fragment set:html={html} />
218
+ {floatingCopy && (
219
+ <button
220
+ class:list={[codeRichCopy(), "absolute right-2 top-2 opacity-0 group-hover:opacity-100 transition-opacity"]}
221
+ data-part="copy"
222
+ data-copy-text={copyText}
223
+ type="button"
224
+ aria-label="Copy code"
225
+ >
226
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-copy-icon aria-hidden="true">
227
+ <rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect>
228
+ <path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path>
229
+ </svg>
230
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-check-icon class="hidden" aria-hidden="true">
231
+ <polyline points="20 6 9 17 4 12"></polyline>
232
+ </svg>
233
+ </button>
234
+ )}
235
+ </div>
236
+ </div>
237
+
238
+ <script>
239
+ function setupCodeRichCopy() {
240
+ document.querySelectorAll("[data-component='code-rich'] [data-part='copy']").forEach((btn) => {
241
+ if ((btn as any).__copyBound) return;
242
+ (btn as any).__copyBound = true;
243
+
244
+ btn.addEventListener("click", async () => {
245
+ const text = btn.getAttribute("data-copy-text") || "";
246
+ try {
247
+ await navigator.clipboard.writeText(text);
248
+ const copyIcon = btn.querySelector("[data-copy-icon]") as HTMLElement;
249
+ const checkIcon = btn.querySelector("[data-check-icon]") as HTMLElement;
250
+ if (copyIcon && checkIcon) {
251
+ copyIcon.classList.add("hidden");
252
+ checkIcon.classList.remove("hidden");
253
+ setTimeout(() => {
254
+ copyIcon.classList.remove("hidden");
255
+ checkIcon.classList.add("hidden");
256
+ }, 2000);
257
+ }
258
+ } catch {
259
+ // Fallback: do nothing
260
+ }
261
+ });
262
+ });
263
+ }
264
+
265
+ setupCodeRichCopy();
266
+ document.addEventListener("astro:after-swap", setupCodeRichCopy);
267
+ </script>
@@ -0,0 +1,68 @@
1
+ /* CodeRich annotation styles — applied via CSS classes from Shiki transformers */
2
+
3
+ /* ── All lines ────────────────────────────────────────── */
4
+ .code-rich-body .line {
5
+ display: inline-flex;
6
+ width: 100%;
7
+ }
8
+
9
+ /* ── Gutter (single column: line number + diff marker) ── */
10
+ .code-rich-body .gutter {
11
+ display: inline-block;
12
+ min-width: 4ch;
13
+ margin-right: 1.5ch;
14
+ text-align: right;
15
+ color: oklch(0.35 0 0 / 0.7);
16
+ user-select: none;
17
+ flex-shrink: 0;
18
+ }
19
+ .code-rich-body .gutter.add {
20
+ color: oklch(0.55 0.2 145);
21
+ }
22
+ .code-rich-body .gutter.remove {
23
+ color: oklch(0.55 0.2 25);
24
+ }
25
+
26
+ /* ── Diff line backgrounds ────────────────────────────── */
27
+ .code-rich-body .line.diff.add {
28
+ background-color: oklch(0.75 0.18 145 / 0.15);
29
+ }
30
+ .code-rich-body .line.diff.remove {
31
+ background-color: oklch(0.65 0.2 25 / 0.15);
32
+ }
33
+
34
+ /* ── Focus ─────────────────────────────────────────────── */
35
+ .code-rich-body pre.has-focused .line:not(.focused) {
36
+ opacity: 0.7;
37
+ transition: opacity 0.3s;
38
+ }
39
+ .code-rich-body pre.has-focused:hover .line:not(.focused) {
40
+ opacity: 0.9;
41
+ }
42
+ .code-rich-body pre.has-focused .line.focused {
43
+ opacity: 1;
44
+ }
45
+
46
+ /* ── Highlight (background only) ──────────────────────── */
47
+ .code-rich-body .line.highlighted {
48
+ background-color: oklch(0.7 0.1 250 / 0.08);
49
+ }
50
+
51
+ /* ── Error / Warning / Info levels ─────────────────────── */
52
+ .code-rich-body .line.highlighted.error {
53
+ background-color: oklch(0.65 0.2 25 / 0.08);
54
+ }
55
+ .code-rich-body .line.highlighted.warning {
56
+ background-color: oklch(0.75 0.18 65 / 0.08);
57
+ }
58
+ .code-rich-body .line.highlighted.info {
59
+ background-color: oklch(0.7 0.15 250 / 0.08);
60
+ }
61
+
62
+ /* ── Word highlight ────────────────────────────────────── */
63
+ .code-rich-body .highlighted-word {
64
+ background-color: oklch(0.7 0.1 250 / 0.25);
65
+ border-radius: 3px;
66
+ padding: 1px 4px;
67
+ margin: 0 -1px;
68
+ }
@@ -0,0 +1 @@
1
+ export { default as CodeRich } from "./CodeRich.astro";