@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.
- package/package.json +38 -0
- package/src/accordion/Accordion.astro +38 -0
- package/src/accordion/AccordionContent.astro +25 -0
- package/src/accordion/AccordionItem.astro +26 -0
- package/src/accordion/AccordionTrigger.astro +38 -0
- package/src/accordion/accordion.ts +189 -0
- package/src/accordion/index.ts +4 -0
- package/src/alert/Alert.astro +69 -0
- package/src/alert/AlertDescription.astro +17 -0
- package/src/alert/AlertTitle.astro +21 -0
- package/src/alert/CollapsibleAlert.astro +103 -0
- package/src/alert/icon.ts +32 -0
- package/src/alert/index.ts +4 -0
- package/src/alert/variants.ts +29 -0
- package/src/alert-dialog/AlertDialog.astro +16 -0
- package/src/alert-dialog/AlertDialogAction.astro +23 -0
- package/src/alert-dialog/AlertDialogCancel.astro +23 -0
- package/src/alert-dialog/AlertDialogContent.astro +37 -0
- package/src/alert-dialog/AlertDialogDescription.astro +18 -0
- package/src/alert-dialog/AlertDialogFooter.astro +18 -0
- package/src/alert-dialog/AlertDialogHeader.astro +18 -0
- package/src/alert-dialog/AlertDialogTitle.astro +18 -0
- package/src/alert-dialog/AlertDialogTrigger.astro +24 -0
- package/src/alert-dialog/alert-dialog.ts +154 -0
- package/src/alert-dialog/index.ts +9 -0
- package/src/api-doc/ApiDoc.astro +52 -0
- package/src/api-doc/index.ts +1 -0
- package/src/api-layout/ApiCodePanel.astro +21 -0
- package/src/api-layout/ApiLayout.astro +29 -0
- package/src/api-layout/ExampleBlock.astro +63 -0
- package/src/api-params/ApiParams.astro +96 -0
- package/src/api-params/index.ts +1 -0
- package/src/api-source/ApiSource.astro +20 -0
- package/src/api-source/api-source.css +32 -0
- package/src/api-source/index.ts +1 -0
- package/src/api-symbol/ApiSymbol.astro +48 -0
- package/src/api-symbol/api-symbol.css +89 -0
- package/src/api-symbol/index.ts +1 -0
- package/src/api-url-bar/ApiUrlBar.astro +63 -0
- package/src/avatar/Avatar.astro +57 -0
- package/src/avatar/index.ts +1 -0
- package/src/badge/Badge.astro +37 -0
- package/src/badge/index.ts +1 -0
- package/src/breadcrumb/Breadcrumb.astro +32 -0
- package/src/breadcrumb/BreadcrumbEllipsis.astro +32 -0
- package/src/breadcrumb/BreadcrumbItem.astro +41 -0
- package/src/breadcrumb/BreadcrumbSeparator.astro +33 -0
- package/src/breadcrumb/index.ts +4 -0
- package/src/button/Button.astro +70 -0
- package/src/button/index.ts +1 -0
- package/src/card/Card.astro +17 -0
- package/src/card/CardContent.astro +17 -0
- package/src/card/CardDescription.astro +17 -0
- package/src/card/CardFooter.astro +17 -0
- package/src/card/CardHeader.astro +17 -0
- package/src/card/CardTitle.astro +17 -0
- package/src/card/index.ts +6 -0
- package/src/checkbox/Checkbox.astro +70 -0
- package/src/checkbox/index.ts +1 -0
- package/src/checkbox-group/CheckboxGroup.astro +38 -0
- package/src/checkbox-group/checkbox-group.ts +53 -0
- package/src/checkbox-group/index.ts +1 -0
- package/src/code-block/CodeBlock.astro +160 -0
- package/src/code-rich/CodeRich.astro +267 -0
- package/src/code-rich/code-rich.css +68 -0
- package/src/code-rich/index.ts +1 -0
- package/src/code-samples/CodeSamples.astro +59 -0
- package/src/collapsible/Collapsible.astro +35 -0
- package/src/collapsible/CollapsibleContent.astro +24 -0
- package/src/collapsible/CollapsibleTrigger.astro +23 -0
- package/src/collapsible/collapsible.ts +42 -0
- package/src/collapsible/index.ts +3 -0
- package/src/combobox/Combobox.astro +53 -0
- package/src/combobox/ComboboxEmpty.astro +18 -0
- package/src/combobox/ComboboxItem.astro +28 -0
- package/src/combobox/combobox.ts +179 -0
- package/src/combobox/index.ts +3 -0
- package/src/command/Command.astro +22 -0
- package/src/command/CommandEmpty.astro +18 -0
- package/src/command/CommandGroup.astro +24 -0
- package/src/command/CommandInput.astro +49 -0
- package/src/command/CommandItem.astro +26 -0
- package/src/command/CommandList.astro +19 -0
- package/src/command/CommandSeparator.astro +16 -0
- package/src/command/CommandShortcut.astro +18 -0
- package/src/command/command.ts +212 -0
- package/src/command/index.ts +8 -0
- package/src/content-renderer/ContentRenderer.astro +410 -0
- package/src/content-renderer/InlineRenderer.astro +149 -0
- package/src/context-menu/ContextMenu.astro +22 -0
- package/src/context-menu/ContextMenuContent.astro +24 -0
- package/src/context-menu/ContextMenuItem.astro +49 -0
- package/src/context-menu/ContextMenuSeparator.astro +14 -0
- package/src/context-menu/ContextMenuShortcut.astro +14 -0
- package/src/context-menu/ContextMenuTrigger.astro +22 -0
- package/src/context-menu/context-menu.ts +238 -0
- package/src/context-menu/index.ts +6 -0
- package/src/copy-button/CopyButton.astro +88 -0
- package/src/copy-button/index.ts +1 -0
- package/src/diagram/Diagram.astro +15 -0
- package/src/diagram/index.ts +1 -0
- package/src/dialog/Dialog.astro +22 -0
- package/src/dialog/DialogClose.astro +32 -0
- package/src/dialog/DialogContent.astro +37 -0
- package/src/dialog/DialogDescription.astro +22 -0
- package/src/dialog/DialogFooter.astro +18 -0
- package/src/dialog/DialogHeader.astro +18 -0
- package/src/dialog/DialogTitle.astro +18 -0
- package/src/dialog/DialogTrigger.astro +33 -0
- package/src/dialog/dialog.ts +291 -0
- package/src/dialog/index.ts +8 -0
- package/src/docs-footer/DocsFooter.astro +50 -0
- package/src/docs-header/DocsHeader.astro +32 -0
- package/src/docs-layout/DocsLayout.astro +187 -0
- package/src/docs-layout/index.ts +1 -0
- package/src/drawer/Drawer.astro +12 -0
- package/src/drawer/DrawerClose.astro +12 -0
- package/src/drawer/DrawerContent.astro +46 -0
- package/src/drawer/DrawerDescription.astro +10 -0
- package/src/drawer/DrawerFooter.astro +10 -0
- package/src/drawer/DrawerHandle.astro +16 -0
- package/src/drawer/DrawerHeader.astro +10 -0
- package/src/drawer/DrawerTitle.astro +10 -0
- package/src/drawer/DrawerTrigger.astro +25 -0
- package/src/drawer/drawer.ts +262 -0
- package/src/drawer/index.ts +9 -0
- package/src/dropdown-menu/DropdownMenu.astro +22 -0
- package/src/dropdown-menu/DropdownMenuContent.astro +33 -0
- package/src/dropdown-menu/DropdownMenuGroup.astro +17 -0
- package/src/dropdown-menu/DropdownMenuItem.astro +48 -0
- package/src/dropdown-menu/DropdownMenuLabel.astro +28 -0
- package/src/dropdown-menu/DropdownMenuSeparator.astro +21 -0
- package/src/dropdown-menu/DropdownMenuShortcut.astro +18 -0
- package/src/dropdown-menu/DropdownMenuTrigger.astro +34 -0
- package/src/dropdown-menu/dropdown-menu.ts +348 -0
- package/src/dropdown-menu/index.ts +8 -0
- package/src/endpoint-card/EndpointCard.astro +60 -0
- package/src/endpoint-card/EndpointCardSection.astro +22 -0
- package/src/endpoint-card/EndpointSection.astro +35 -0
- package/src/field/Field.astro +31 -0
- package/src/field/FieldDescription.astro +22 -0
- package/src/field/FieldLabel.astro +24 -0
- package/src/field/field.ts +61 -0
- package/src/field/index.ts +3 -0
- package/src/fieldset/Fieldset.astro +24 -0
- package/src/fieldset/FieldsetLegend.astro +18 -0
- package/src/fieldset/index.ts +2 -0
- package/src/footnote/Footnote.astro +37 -0
- package/src/footnote/footnote.ts +79 -0
- package/src/footnote/index.ts +1 -0
- package/src/form/Form.astro +27 -0
- package/src/form/form.ts +160 -0
- package/src/form/index.ts +1 -0
- package/src/grid/Grid.astro +117 -0
- package/src/grid/GridItem.astro +95 -0
- package/src/grid/index.ts +2 -0
- package/src/image/Image.astro +115 -0
- package/src/image/index.ts +1 -0
- package/src/input/Input.astro +34 -0
- package/src/input/index.ts +1 -0
- package/src/kbd/Kbd.astro +17 -0
- package/src/kbd/index.ts +1 -0
- package/src/label/Label.astro +17 -0
- package/src/label/index.ts +1 -0
- package/src/link-card/LinkCard.astro +47 -0
- package/src/link-card/index.ts +1 -0
- package/src/map-view/MapView.astro +88 -0
- package/src/map-view/index.ts +1 -0
- package/src/map-view/map-view.ts +194 -0
- package/src/markdown-example/MarkdownExample.astro +138 -0
- package/src/markdown-example/index.ts +1 -0
- package/src/math/MathKatex.astro +35 -0
- package/src/math/index.ts +1 -0
- package/src/menubar/Menubar.astro +25 -0
- package/src/menubar/MenubarContent.astro +24 -0
- package/src/menubar/MenubarItem.astro +26 -0
- package/src/menubar/MenubarMenu.astro +12 -0
- package/src/menubar/MenubarSeparator.astro +11 -0
- package/src/menubar/MenubarShortcut.astro +11 -0
- package/src/menubar/MenubarTrigger.astro +27 -0
- package/src/menubar/index.ts +7 -0
- package/src/menubar/menubar.ts +258 -0
- package/src/meter/Meter.astro +75 -0
- package/src/meter/index.ts +1 -0
- package/src/method-badge/MethodBadge.astro +32 -0
- package/src/navigation-menu/NavigationMenu.astro +24 -0
- package/src/navigation-menu/NavigationMenuContent.astro +24 -0
- package/src/navigation-menu/NavigationMenuItem.astro +22 -0
- package/src/navigation-menu/NavigationMenuLink.astro +26 -0
- package/src/navigation-menu/NavigationMenuList.astro +22 -0
- package/src/navigation-menu/NavigationMenuTrigger.astro +40 -0
- package/src/navigation-menu/index.ts +6 -0
- package/src/navigation-menu/navigation-menu.ts +192 -0
- package/src/number-field/NumberField.astro +84 -0
- package/src/number-field/index.ts +1 -0
- package/src/number-field/number-field.ts +68 -0
- package/src/pagination/Pagination.astro +59 -0
- package/src/pagination/index.ts +1 -0
- package/src/parameter-table/ParameterTable.astro +75 -0
- package/src/popover/Popover.astro +21 -0
- package/src/popover/PopoverContent.astro +31 -0
- package/src/popover/PopoverTrigger.astro +31 -0
- package/src/popover/index.ts +3 -0
- package/src/popover/popover.ts +144 -0
- package/src/preview-card/PreviewCard.astro +24 -0
- package/src/preview-card/PreviewCardContent.astro +24 -0
- package/src/preview-card/PreviewCardTrigger.astro +23 -0
- package/src/preview-card/index.ts +3 -0
- package/src/preview-card/preview-card.ts +91 -0
- package/src/progress/Progress.astro +61 -0
- package/src/progress/index.ts +1 -0
- package/src/property-item/PropertyItem.astro +183 -0
- package/src/property-list/PropertyList.astro +68 -0
- package/src/radio-group/RadioGroup.astro +41 -0
- package/src/radio-group/RadioGroupItem.astro +36 -0
- package/src/radio-group/index.ts +2 -0
- package/src/radio-group/radio-group.ts +126 -0
- package/src/response-tabs/ResponseTabs.astro +60 -0
- package/src/schema-viewer/SchemaViewer.astro +42 -0
- package/src/scroll-area/ScrollArea.astro +44 -0
- package/src/scroll-area/index.ts +1 -0
- package/src/scroll-area/scroll-area.ts +176 -0
- package/src/select/Select.astro +34 -0
- package/src/select/SelectContent.astro +24 -0
- package/src/select/SelectGroup.astro +23 -0
- package/src/select/SelectItem.astro +28 -0
- package/src/select/SelectLabel.astro +18 -0
- package/src/select/SelectSeparator.astro +22 -0
- package/src/select/SelectTrigger.astro +28 -0
- package/src/select/SelectValue.astro +18 -0
- package/src/select/index.ts +8 -0
- package/src/select/select.ts +381 -0
- package/src/separator/Separator.astro +35 -0
- package/src/separator/index.ts +1 -0
- package/src/sheet/Sheet.astro +12 -0
- package/src/sheet/SheetClose.astro +35 -0
- package/src/sheet/SheetContent.astro +52 -0
- package/src/sheet/SheetDescription.astro +18 -0
- package/src/sheet/SheetFooter.astro +18 -0
- package/src/sheet/SheetHeader.astro +18 -0
- package/src/sheet/SheetTitle.astro +18 -0
- package/src/sheet/SheetTrigger.astro +32 -0
- package/src/sheet/index.ts +8 -0
- package/src/sheet/sheet.ts +173 -0
- package/src/sidebar/Sidebar.astro +113 -0
- package/src/sidebar/SidebarContent.astro +18 -0
- package/src/sidebar/SidebarFooter.astro +18 -0
- package/src/sidebar/SidebarGroup.astro +18 -0
- package/src/sidebar/SidebarGroupContent.astro +18 -0
- package/src/sidebar/SidebarGroupLabel.astro +18 -0
- package/src/sidebar/SidebarHeader.astro +18 -0
- package/src/sidebar/SidebarInset.astro +18 -0
- package/src/sidebar/SidebarMenu.astro +18 -0
- package/src/sidebar/SidebarMenuBadge.astro +18 -0
- package/src/sidebar/SidebarMenuButton.astro +71 -0
- package/src/sidebar/SidebarMenuItem.astro +18 -0
- package/src/sidebar/SidebarMenuSub.astro +18 -0
- package/src/sidebar/SidebarMenuSubButton.astro +45 -0
- package/src/sidebar/SidebarMenuSubItem.astro +12 -0
- package/src/sidebar/SidebarNavTree.astro +106 -0
- package/src/sidebar/SidebarProvider.astro +23 -0
- package/src/sidebar/SidebarRail.astro +25 -0
- package/src/sidebar/SidebarSeparator.astro +21 -0
- package/src/sidebar/SidebarTrigger.astro +40 -0
- package/src/sidebar/index.ts +19 -0
- package/src/sidebar/sidebar.ts +265 -0
- package/src/skeleton/Skeleton.astro +16 -0
- package/src/skeleton/index.ts +1 -0
- package/src/skip-link/SkipLink.astro +24 -0
- package/src/slider/Slider.astro +61 -0
- package/src/slider/index.ts +1 -0
- package/src/slider/slider.ts +111 -0
- package/src/spinner/Spinner.astro +54 -0
- package/src/spinner/index.ts +1 -0
- package/src/steps/Step.astro +16 -0
- package/src/steps/Steps.astro +122 -0
- package/src/steps/SubSteps.astro +73 -0
- package/src/switch/Switch.astro +52 -0
- package/src/switch/index.ts +1 -0
- package/src/switch/switch.ts +109 -0
- package/src/table/Table.astro +24 -0
- package/src/table/TableBody.astro +18 -0
- package/src/table/TableCaption.astro +18 -0
- package/src/table/TableCell.astro +18 -0
- package/src/table/TableFooter.astro +18 -0
- package/src/table/TableHead.astro +18 -0
- package/src/table/TableHeader.astro +18 -0
- package/src/table/TableRow.astro +18 -0
- package/src/table/index.ts +8 -0
- package/src/tabs/Tabs.astro +37 -0
- package/src/tabs/TabsContent.astro +32 -0
- package/src/tabs/TabsList.astro +23 -0
- package/src/tabs/TabsTrigger.astro +29 -0
- package/src/tabs/index.ts +4 -0
- package/src/tabs/tabs.ts +220 -0
- package/src/textarea/Textarea.astro +25 -0
- package/src/textarea/index.ts +1 -0
- package/src/theme-toggle/ThemeToggle.astro +67 -0
- package/src/theme-toggle/index.ts +1 -0
- package/src/toast/Toaster.astro +39 -0
- package/src/toast/index.ts +3 -0
- package/src/toast/toast.ts +104 -0
- package/src/toc/TableOfContents.astro +225 -0
- package/src/toggle/Toggle.astro +56 -0
- package/src/toggle/index.ts +1 -0
- package/src/toggle/toggle.ts +38 -0
- package/src/toggle-group/ToggleGroup.astro +39 -0
- package/src/toggle-group/ToggleGroupItem.astro +56 -0
- package/src/toggle-group/index.ts +2 -0
- package/src/toggle-group/toggle-group.ts +121 -0
- package/src/toolbar/Toolbar.astro +26 -0
- package/src/toolbar/ToolbarButton.astro +29 -0
- package/src/toolbar/ToolbarSeparator.astro +14 -0
- package/src/toolbar/index.ts +3 -0
- package/src/toolbar/toolbar.ts +65 -0
- package/src/tooltip/Tooltip.astro +21 -0
- package/src/tooltip/TooltipContent.astro +25 -0
- package/src/tooltip/TooltipTrigger.astro +31 -0
- package/src/tooltip/index.ts +3 -0
- package/src/tooltip/tooltip.ts +156 -0
- package/src/youtube/YouTube.astro +119 -0
- package/src/youtube/index.ts +1 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* Recursive sidebar navigation tree.
|
|
4
|
+
* Renders a data-driven tree with native <details>/<summary> for zero-JS expand/collapse.
|
|
5
|
+
* Left-side chevrons, consistent indentation per level, active page highlighting.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* <SidebarNavTree items={navItems} currentPath={Astro.url.pathname} />
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
interface NavItem {
|
|
12
|
+
label: string;
|
|
13
|
+
href?: string;
|
|
14
|
+
icon?: string; // Raw SVG string (rendered via set:html)
|
|
15
|
+
children?: NavItem[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface Props {
|
|
19
|
+
items: NavItem[];
|
|
20
|
+
currentPath: string;
|
|
21
|
+
level?: number;
|
|
22
|
+
class?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const { items, currentPath, level = 0, class: className } = Astro.props;
|
|
26
|
+
|
|
27
|
+
const normalizedPath = currentPath.replace(/\/$/, "") || "/";
|
|
28
|
+
|
|
29
|
+
function isActive(href: string) {
|
|
30
|
+
return normalizedPath === href;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function hasActiveDescendant(item: NavItem): boolean {
|
|
34
|
+
if (item.href && isActive(item.href)) return true;
|
|
35
|
+
if (item.children) return item.children.some(hasActiveDescendant);
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Indentation: 8px base + 12px per level
|
|
40
|
+
const paddingLeft = `${8 + level * 12}px`;
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
<ul
|
|
44
|
+
class:list={[
|
|
45
|
+
"flex min-w-0 flex-col",
|
|
46
|
+
level === 0 && "w-full",
|
|
47
|
+
level === 0 && "group-data-[collapsible=icon]:hidden",
|
|
48
|
+
className,
|
|
49
|
+
]}
|
|
50
|
+
data-sidebar="nav-tree"
|
|
51
|
+
data-level={level}
|
|
52
|
+
>
|
|
53
|
+
{items.map((item) => {
|
|
54
|
+
const active = item.href ? isActive(item.href) : false;
|
|
55
|
+
const hasChildren = item.children && item.children.length > 0;
|
|
56
|
+
const shouldOpen = hasChildren && hasActiveDescendant(item);
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<li data-sidebar="nav-tree-item">
|
|
60
|
+
{hasChildren ? (
|
|
61
|
+
<details open={shouldOpen || active}>
|
|
62
|
+
<summary
|
|
63
|
+
class:list={[
|
|
64
|
+
"flex w-full min-w-0 cursor-pointer items-center gap-2 rounded-md text-sm text-sidebar-foreground outline-none [list-style:none] ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&::-webkit-details-marker]:hidden",
|
|
65
|
+
level === 0 ? "h-8" : "h-7",
|
|
66
|
+
active && "bg-sidebar-accent font-medium text-sidebar-accent-foreground",
|
|
67
|
+
]}
|
|
68
|
+
style={`padding-left: ${paddingLeft};`}
|
|
69
|
+
data-nav-href={item.href || undefined}
|
|
70
|
+
data-active={active || undefined}
|
|
71
|
+
>
|
|
72
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4 shrink-0 transition-transform duration-200" data-chevron aria-hidden="true"><polyline points="9 18 15 12 9 6" /></svg>
|
|
73
|
+
{item.icon && <span class="shrink-0 [&>svg]:size-4" set:html={item.icon} />}
|
|
74
|
+
<span class="truncate">{item.label}</span>
|
|
75
|
+
</summary>
|
|
76
|
+
<Astro.self items={item.children!} currentPath={currentPath} level={level + 1} />
|
|
77
|
+
</details>
|
|
78
|
+
) : (
|
|
79
|
+
<a
|
|
80
|
+
href={item.href || "#"}
|
|
81
|
+
class:list={[
|
|
82
|
+
"flex w-full min-w-0 items-center gap-2 rounded-md text-sm text-sidebar-foreground outline-none ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2",
|
|
83
|
+
level === 0 ? "h-8" : "h-7",
|
|
84
|
+
active && "bg-sidebar-accent font-medium text-sidebar-accent-foreground",
|
|
85
|
+
]}
|
|
86
|
+
style={`padding-left: ${paddingLeft};`}
|
|
87
|
+
data-active={active || undefined}
|
|
88
|
+
data-nav-href={item.href}
|
|
89
|
+
>
|
|
90
|
+
{/* Spacer to align with chevron in branch items */}
|
|
91
|
+
<span class="size-4 shrink-0" />
|
|
92
|
+
{/* Icon (level 0 only) */}
|
|
93
|
+
{item.icon && <span class="shrink-0 [&>svg]:size-4" set:html={item.icon} />}
|
|
94
|
+
<span class="truncate">{item.label}</span>
|
|
95
|
+
</a>
|
|
96
|
+
)}
|
|
97
|
+
</li>
|
|
98
|
+
);
|
|
99
|
+
})}
|
|
100
|
+
</ul>
|
|
101
|
+
|
|
102
|
+
<style is:global>
|
|
103
|
+
details[open] > summary [data-chevron] {
|
|
104
|
+
transform: rotate(90deg);
|
|
105
|
+
}
|
|
106
|
+
</style>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { tv } from "tailwind-variants";
|
|
3
|
+
|
|
4
|
+
const sidebarProvider = tv({
|
|
5
|
+
base: "group/sidebar-wrapper flex min-h-svh w-full has-[[data-variant=inset]]:bg-sidebar",
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
class?: string;
|
|
10
|
+
[key: string]: unknown;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const { class: className, ...rest } = Astro.props;
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
<div
|
|
17
|
+
class={sidebarProvider({ class: className })}
|
|
18
|
+
data-component="sidebar-provider"
|
|
19
|
+
style="--sidebar-width: 16rem; --sidebar-width-icon: 3rem;"
|
|
20
|
+
{...rest}
|
|
21
|
+
>
|
|
22
|
+
<slot />
|
|
23
|
+
</div>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { tv } from "tailwind-variants";
|
|
3
|
+
|
|
4
|
+
const sidebarRail = tv({
|
|
5
|
+
base: "absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] hover:after:bg-sidebar-border group-data-[side=left]:-right-4 group-data-[side=right]:left-0 sm:flex group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full hover:group-data-[collapsible=offcanvas]:bg-sidebar",
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
class?: string;
|
|
10
|
+
[key: string]: unknown;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const { class: className, ...rest } = Astro.props;
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
<button
|
|
17
|
+
class={sidebarRail({ class: className })}
|
|
18
|
+
data-part="rail"
|
|
19
|
+
aria-label="Toggle Sidebar"
|
|
20
|
+
tabindex={-1}
|
|
21
|
+
title="Toggle Sidebar"
|
|
22
|
+
type="button"
|
|
23
|
+
{...rest}
|
|
24
|
+
>
|
|
25
|
+
</button>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { tv } from "tailwind-variants";
|
|
3
|
+
|
|
4
|
+
const sidebarSeparator = tv({
|
|
5
|
+
base: "mx-2 w-auto bg-sidebar-border h-px shrink-0",
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
class?: string;
|
|
10
|
+
[key: string]: unknown;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const { class: className, ...rest } = Astro.props;
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
<div
|
|
17
|
+
class={sidebarSeparator({ class: className })}
|
|
18
|
+
role="separator"
|
|
19
|
+
{...rest}
|
|
20
|
+
>
|
|
21
|
+
</div>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { tv } from "tailwind-variants";
|
|
3
|
+
|
|
4
|
+
const sidebarTrigger = tv({
|
|
5
|
+
base: "inline-flex h-7 w-7 items-center justify-center rounded-md text-sm hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
class?: string;
|
|
10
|
+
[key: string]: unknown;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const { class: className, ...rest } = Astro.props;
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
<button
|
|
17
|
+
class={sidebarTrigger({ class: className })}
|
|
18
|
+
data-part="sidebar-trigger"
|
|
19
|
+
type="button"
|
|
20
|
+
{...rest}
|
|
21
|
+
>
|
|
22
|
+
<slot>
|
|
23
|
+
<svg
|
|
24
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
25
|
+
width="16"
|
|
26
|
+
height="16"
|
|
27
|
+
viewBox="0 0 24 24"
|
|
28
|
+
fill="none"
|
|
29
|
+
stroke="currentColor"
|
|
30
|
+
stroke-width="2"
|
|
31
|
+
stroke-linecap="round"
|
|
32
|
+
stroke-linejoin="round"
|
|
33
|
+
aria-hidden="true"
|
|
34
|
+
>
|
|
35
|
+
<rect width="18" height="18" x="3" y="3" rx="2"></rect>
|
|
36
|
+
<path d="M9 3v18"></path>
|
|
37
|
+
</svg>
|
|
38
|
+
</slot>
|
|
39
|
+
<span class="sr-only">Toggle Sidebar</span>
|
|
40
|
+
</button>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export { default as SidebarProvider } from "./SidebarProvider.astro";
|
|
2
|
+
export { default as Sidebar } from "./Sidebar.astro";
|
|
3
|
+
export { default as SidebarHeader } from "./SidebarHeader.astro";
|
|
4
|
+
export { default as SidebarContent } from "./SidebarContent.astro";
|
|
5
|
+
export { default as SidebarFooter } from "./SidebarFooter.astro";
|
|
6
|
+
export { default as SidebarTrigger } from "./SidebarTrigger.astro";
|
|
7
|
+
export { default as SidebarInset } from "./SidebarInset.astro";
|
|
8
|
+
export { default as SidebarRail } from "./SidebarRail.astro";
|
|
9
|
+
export { default as SidebarGroup } from "./SidebarGroup.astro";
|
|
10
|
+
export { default as SidebarGroupLabel } from "./SidebarGroupLabel.astro";
|
|
11
|
+
export { default as SidebarGroupContent } from "./SidebarGroupContent.astro";
|
|
12
|
+
export { default as SidebarMenu } from "./SidebarMenu.astro";
|
|
13
|
+
export { default as SidebarMenuItem } from "./SidebarMenuItem.astro";
|
|
14
|
+
export { default as SidebarMenuButton } from "./SidebarMenuButton.astro";
|
|
15
|
+
export { default as SidebarMenuSub } from "./SidebarMenuSub.astro";
|
|
16
|
+
export { default as SidebarMenuSubItem } from "./SidebarMenuSubItem.astro";
|
|
17
|
+
export { default as SidebarMenuSubButton } from "./SidebarMenuSubButton.astro";
|
|
18
|
+
export { default as SidebarSeparator } from "./SidebarSeparator.astro";
|
|
19
|
+
export { default as SidebarMenuBadge } from "./SidebarMenuBadge.astro";
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { ScrollLock } from "@dogsbay/primitives/scroll-lock";
|
|
2
|
+
|
|
3
|
+
const SIDEBAR_STORAGE_KEY = "sidebar_state";
|
|
4
|
+
const SIDEBAR_KEYBOARD_SHORTCUT = "b";
|
|
5
|
+
const MOBILE_BREAKPOINT = 768;
|
|
6
|
+
|
|
7
|
+
interface SidebarInstance {
|
|
8
|
+
provider: HTMLElement;
|
|
9
|
+
sidebar: HTMLElement;
|
|
10
|
+
desktopSidebar: HTMLElement | null;
|
|
11
|
+
mobileSidebar: HTMLElement | null;
|
|
12
|
+
mobileBackdrop: HTMLElement | null;
|
|
13
|
+
collapsible: "offcanvas" | "icon" | "none";
|
|
14
|
+
side: "left" | "right";
|
|
15
|
+
open: boolean;
|
|
16
|
+
openMobile: boolean;
|
|
17
|
+
isMobile: boolean;
|
|
18
|
+
mediaQuery: MediaQueryList;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const instances = new WeakMap<HTMLElement, SidebarInstance>();
|
|
22
|
+
|
|
23
|
+
function getStoredState(key: string): string | null {
|
|
24
|
+
try {
|
|
25
|
+
return localStorage.getItem(key);
|
|
26
|
+
} catch {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function setStoredState(key: string, value: string) {
|
|
32
|
+
try {
|
|
33
|
+
localStorage.setItem(key, value);
|
|
34
|
+
} catch {
|
|
35
|
+
// localStorage unavailable (private browsing, etc.)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function initSidebar(provider: HTMLElement) {
|
|
40
|
+
if (instances.has(provider)) return;
|
|
41
|
+
|
|
42
|
+
const sidebar = provider.querySelector(
|
|
43
|
+
"[data-component='sidebar']",
|
|
44
|
+
) as HTMLElement | null;
|
|
45
|
+
if (!sidebar) return;
|
|
46
|
+
|
|
47
|
+
const collapsible =
|
|
48
|
+
(sidebar.dataset.collapsible as SidebarInstance["collapsible"]) ||
|
|
49
|
+
"offcanvas";
|
|
50
|
+
const side = (sidebar.dataset.side as "left" | "right") || "left";
|
|
51
|
+
const defaultOpen = sidebar.dataset.defaultOpen !== "false";
|
|
52
|
+
|
|
53
|
+
// Read persisted state from localStorage
|
|
54
|
+
const storedState = getStoredState(SIDEBAR_STORAGE_KEY);
|
|
55
|
+
const initialOpen =
|
|
56
|
+
storedState !== null ? storedState === "true" : defaultOpen;
|
|
57
|
+
|
|
58
|
+
// Find desktop and mobile sidebar containers
|
|
59
|
+
const desktopSidebar = sidebar.querySelector(
|
|
60
|
+
"[data-sidebar-desktop]",
|
|
61
|
+
) as HTMLElement | null;
|
|
62
|
+
const mobileSidebar = sidebar.querySelector(
|
|
63
|
+
"[data-sidebar-mobile]",
|
|
64
|
+
) as HTMLElement | null;
|
|
65
|
+
const mobileBackdrop = sidebar.querySelector(
|
|
66
|
+
"[data-sidebar-mobile-backdrop]",
|
|
67
|
+
) as HTMLElement | null;
|
|
68
|
+
|
|
69
|
+
const mediaQuery = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
|
|
70
|
+
|
|
71
|
+
const instance: SidebarInstance = {
|
|
72
|
+
provider,
|
|
73
|
+
sidebar,
|
|
74
|
+
desktopSidebar,
|
|
75
|
+
mobileSidebar,
|
|
76
|
+
mobileBackdrop,
|
|
77
|
+
collapsible,
|
|
78
|
+
side,
|
|
79
|
+
open: initialOpen,
|
|
80
|
+
openMobile: false,
|
|
81
|
+
isMobile: mediaQuery.matches,
|
|
82
|
+
mediaQuery,
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
instances.set(provider, instance);
|
|
86
|
+
|
|
87
|
+
// Set initial state
|
|
88
|
+
updateDesktopState(instance);
|
|
89
|
+
|
|
90
|
+
// Responsive listener
|
|
91
|
+
const handleMediaChange = (e: MediaQueryListEvent | MediaQueryList) => {
|
|
92
|
+
instance.isMobile = e.matches;
|
|
93
|
+
if (!e.matches && instance.openMobile) {
|
|
94
|
+
// Switched to desktop while mobile sidebar was open — close it
|
|
95
|
+
closeMobile(provider);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
mediaQuery.addEventListener("change", handleMediaChange);
|
|
99
|
+
|
|
100
|
+
// Keyboard: Cmd+B / Ctrl+B toggle, Escape closes mobile
|
|
101
|
+
const handleKeyDown = (e: KeyboardEvent) => {
|
|
102
|
+
if (
|
|
103
|
+
e.key === SIDEBAR_KEYBOARD_SHORTCUT &&
|
|
104
|
+
(e.metaKey || e.ctrlKey)
|
|
105
|
+
) {
|
|
106
|
+
e.preventDefault();
|
|
107
|
+
toggleSidebar(provider);
|
|
108
|
+
} else if (e.key === "Escape" && instance.openMobile) {
|
|
109
|
+
e.preventDefault();
|
|
110
|
+
closeMobile(provider);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
114
|
+
|
|
115
|
+
// Bind triggers
|
|
116
|
+
bindTriggers(provider, instance);
|
|
117
|
+
|
|
118
|
+
// Bind mobile backdrop click
|
|
119
|
+
if (mobileBackdrop) {
|
|
120
|
+
mobileBackdrop.addEventListener("click", () => {
|
|
121
|
+
closeMobile(provider);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Bind rail
|
|
126
|
+
const rail = sidebar.querySelector("[data-part='rail']") as HTMLElement | null;
|
|
127
|
+
if (rail) {
|
|
128
|
+
rail.addEventListener("click", () => {
|
|
129
|
+
toggleSidebar(provider);
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function bindTriggers(provider: HTMLElement, instance: SidebarInstance) {
|
|
135
|
+
// Find all triggers within the provider (or globally if using data-sidebar-for)
|
|
136
|
+
provider.querySelectorAll("[data-part='sidebar-trigger']").forEach((el) => {
|
|
137
|
+
el.addEventListener("click", () => {
|
|
138
|
+
toggleSidebar(provider);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function toggleSidebar(provider: HTMLElement) {
|
|
144
|
+
const instance = instances.get(provider);
|
|
145
|
+
if (!instance) return;
|
|
146
|
+
|
|
147
|
+
if (instance.isMobile) {
|
|
148
|
+
if (instance.openMobile) {
|
|
149
|
+
closeMobile(provider);
|
|
150
|
+
} else {
|
|
151
|
+
openMobile(provider);
|
|
152
|
+
}
|
|
153
|
+
} else {
|
|
154
|
+
instance.open = !instance.open;
|
|
155
|
+
updateDesktopState(instance);
|
|
156
|
+
setStoredState(SIDEBAR_STORAGE_KEY, String(instance.open));
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function updateDesktopState(instance: SidebarInstance) {
|
|
161
|
+
const state = instance.open ? "expanded" : "collapsed";
|
|
162
|
+
instance.provider.setAttribute("data-state", state);
|
|
163
|
+
instance.sidebar.setAttribute("data-state", state);
|
|
164
|
+
|
|
165
|
+
if (instance.desktopSidebar) {
|
|
166
|
+
instance.desktopSidebar.setAttribute("data-state", state);
|
|
167
|
+
|
|
168
|
+
// Set data-collapsible only when collapsed
|
|
169
|
+
if (!instance.open) {
|
|
170
|
+
instance.desktopSidebar.setAttribute(
|
|
171
|
+
"data-collapsible",
|
|
172
|
+
instance.collapsible,
|
|
173
|
+
);
|
|
174
|
+
} else {
|
|
175
|
+
instance.desktopSidebar.setAttribute("data-collapsible", "");
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function openMobile(provider: HTMLElement) {
|
|
181
|
+
const instance = instances.get(provider);
|
|
182
|
+
if (!instance || instance.openMobile || !instance.mobileSidebar) return;
|
|
183
|
+
|
|
184
|
+
instance.openMobile = true;
|
|
185
|
+
|
|
186
|
+
// Move sidebar inner content to mobile shell
|
|
187
|
+
const sidebarInner = instance.desktopSidebar?.querySelector(
|
|
188
|
+
"[data-sidebar='sidebar-inner']",
|
|
189
|
+
) as HTMLElement | null;
|
|
190
|
+
if (sidebarInner) {
|
|
191
|
+
// Move all children to mobile shell
|
|
192
|
+
while (sidebarInner.firstChild) {
|
|
193
|
+
instance.mobileSidebar.appendChild(sidebarInner.firstChild);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
instance.mobileSidebar.hidden = false;
|
|
198
|
+
instance.mobileSidebar.setAttribute("data-state", "open");
|
|
199
|
+
|
|
200
|
+
if (instance.mobileBackdrop) {
|
|
201
|
+
instance.mobileBackdrop.hidden = false;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Lock scroll
|
|
205
|
+
ScrollLock.lock();
|
|
206
|
+
|
|
207
|
+
// Focus first focusable element in sidebar
|
|
208
|
+
requestAnimationFrame(() => {
|
|
209
|
+
const focusable = instance.mobileSidebar?.querySelector(
|
|
210
|
+
'a, button, [tabindex]:not([tabindex="-1"])',
|
|
211
|
+
) as HTMLElement | null;
|
|
212
|
+
focusable?.focus();
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function closeMobile(provider: HTMLElement) {
|
|
217
|
+
const instance = instances.get(provider);
|
|
218
|
+
if (!instance || !instance.openMobile || !instance.mobileSidebar) return;
|
|
219
|
+
|
|
220
|
+
instance.openMobile = false;
|
|
221
|
+
|
|
222
|
+
// Move content back to desktop inner
|
|
223
|
+
const sidebarInner = instance.desktopSidebar?.querySelector(
|
|
224
|
+
"[data-sidebar='sidebar-inner']",
|
|
225
|
+
) as HTMLElement | null;
|
|
226
|
+
if (sidebarInner && instance.mobileSidebar) {
|
|
227
|
+
while (instance.mobileSidebar.firstChild) {
|
|
228
|
+
sidebarInner.appendChild(instance.mobileSidebar.firstChild);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
instance.mobileSidebar.setAttribute("data-state", "closed");
|
|
233
|
+
instance.mobileSidebar.hidden = true;
|
|
234
|
+
|
|
235
|
+
if (instance.mobileBackdrop) {
|
|
236
|
+
instance.mobileBackdrop.hidden = true;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Unlock scroll
|
|
240
|
+
ScrollLock.unlock();
|
|
241
|
+
|
|
242
|
+
// Return focus to trigger
|
|
243
|
+
const trigger = instance.provider.querySelector(
|
|
244
|
+
"[data-part='sidebar-trigger']",
|
|
245
|
+
) as HTMLElement | null;
|
|
246
|
+
trigger?.focus();
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Auto-initialize
|
|
250
|
+
function init() {
|
|
251
|
+
document
|
|
252
|
+
.querySelectorAll("[data-component='sidebar-provider']")
|
|
253
|
+
.forEach((el) => {
|
|
254
|
+
initSidebar(el as HTMLElement);
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (document.readyState === "loading") {
|
|
259
|
+
document.addEventListener("DOMContentLoaded", init);
|
|
260
|
+
} else {
|
|
261
|
+
init();
|
|
262
|
+
}
|
|
263
|
+
document.addEventListener("astro:page-load", init);
|
|
264
|
+
|
|
265
|
+
export { initSidebar, toggleSidebar, openMobile, closeMobile };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { tv } from "tailwind-variants";
|
|
3
|
+
|
|
4
|
+
const skeleton = tv({
|
|
5
|
+
base: "animate-pulse rounded-md bg-muted",
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
class?: string;
|
|
10
|
+
[key: string]: unknown;
|
|
11
|
+
}
|
|
12
|
+
const { class: className, ...rest } = Astro.props;
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
<div class={skeleton({ class: className })} aria-hidden="true" {...rest}>
|
|
16
|
+
</div>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Skeleton } from "./Skeleton.astro";
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { tv } from "tailwind-variants";
|
|
3
|
+
|
|
4
|
+
const skipLink = tv({
|
|
5
|
+
base: "sr-only focus:not-sr-only fixed left-4 top-4 z-[100] rounded-md bg-background px-4 py-2 text-sm font-medium text-foreground shadow-md ring-2 ring-ring focus:outline-none",
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
/** Target element ID (without #). Defaults to "content" */
|
|
10
|
+
target?: string;
|
|
11
|
+
class?: string;
|
|
12
|
+
[key: string]: unknown;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const { target = "content", class: className, ...rest } = Astro.props;
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
<a
|
|
19
|
+
href={`#${target}`}
|
|
20
|
+
class={skipLink({ class: className })}
|
|
21
|
+
{...rest}
|
|
22
|
+
>
|
|
23
|
+
Skip to content
|
|
24
|
+
</a>
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { tv } from "tailwind-variants";
|
|
3
|
+
|
|
4
|
+
const slider = tv({
|
|
5
|
+
base: "relative flex w-full touch-none select-none items-center",
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
name?: string;
|
|
10
|
+
defaultValue?: number;
|
|
11
|
+
min?: number;
|
|
12
|
+
max?: number;
|
|
13
|
+
step?: number;
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
class?: string;
|
|
16
|
+
[key: string]: unknown;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const {
|
|
20
|
+
name,
|
|
21
|
+
defaultValue = 50,
|
|
22
|
+
min = 0,
|
|
23
|
+
max = 100,
|
|
24
|
+
step = 1,
|
|
25
|
+
disabled = false,
|
|
26
|
+
class: className,
|
|
27
|
+
...rest
|
|
28
|
+
} = Astro.props;
|
|
29
|
+
|
|
30
|
+
const pct = ((defaultValue - min) / (max - min)) * 100;
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
<div
|
|
34
|
+
class={slider({ class: className })}
|
|
35
|
+
data-component="slider"
|
|
36
|
+
data-min={min}
|
|
37
|
+
data-max={max}
|
|
38
|
+
data-step={step}
|
|
39
|
+
data-name={name}
|
|
40
|
+
data-disabled={disabled || undefined}
|
|
41
|
+
{...rest}
|
|
42
|
+
>
|
|
43
|
+
<div class="relative h-2 w-full grow overflow-hidden rounded-full bg-secondary" data-part="track">
|
|
44
|
+
<div class="absolute h-full bg-primary" data-part="range" style={`width: ${pct}%`}></div>
|
|
45
|
+
</div>
|
|
46
|
+
<button
|
|
47
|
+
class="absolute block h-5 w-5 rounded-full border-2 border-primary bg-background ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
|
|
48
|
+
data-part="thumb"
|
|
49
|
+
type="button"
|
|
50
|
+
role="slider"
|
|
51
|
+
aria-valuenow={defaultValue}
|
|
52
|
+
aria-valuemin={min}
|
|
53
|
+
aria-valuemax={max}
|
|
54
|
+
aria-label={name || "Value"}
|
|
55
|
+
aria-orientation="horizontal"
|
|
56
|
+
disabled={disabled || undefined}
|
|
57
|
+
tabindex={disabled ? -1 : 0}
|
|
58
|
+
style={`left: calc(${pct}% - 10px)`}
|
|
59
|
+
></button>
|
|
60
|
+
{name && <input type="hidden" name={name} value={String(defaultValue)} data-part="hidden-input" />}
|
|
61
|
+
</div>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Slider } from "./Slider.astro";
|