@bl33dz/fa814698dcde12f86a37ac31dd3aedf9 1.0.5 → 1.0.7
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/README.md +80 -95
- package/dist/fa814698dcde12f86a37ac31dd3aedf9.css +1 -1
- package/dist/perisai-ui.es.js +864 -847
- package/dist/perisai-ui.umd.js +1 -1
- package/package.json +45 -45
- package/src/{global.css → globals.css} +575 -575
- package/src/index.ts +178 -176
- package/src/lib/utils.ts +6 -6
- package/src/shadcn/accordion/Accordion.vue +19 -19
- package/src/shadcn/accordion/AccordionContent.vue +23 -23
- package/src/shadcn/accordion/AccordionItem.vue +23 -23
- package/src/shadcn/accordion/AccordionTrigger.vue +38 -38
- package/src/shadcn/accordion/index.ts +4 -4
- package/src/shadcn/avatar/Avatar.vue +18 -18
- package/src/shadcn/avatar/AvatarFallback.vue +21 -21
- package/src/shadcn/avatar/AvatarImage.vue +16 -16
- package/src/shadcn/avatar/index.ts +3 -3
- package/src/shadcn/breadcrumb/Breadcrumb.vue +8 -8
- package/src/shadcn/breadcrumb/BreadcrumbEllipsis.vue +9 -9
- package/src/shadcn/breadcrumb/BreadcrumbItem.vue +8 -8
- package/src/shadcn/breadcrumb/BreadcrumbLink.vue +8 -8
- package/src/shadcn/breadcrumb/BreadcrumbList.vue +8 -8
- package/src/shadcn/breadcrumb/BreadcrumbPage.vue +8 -8
- package/src/shadcn/breadcrumb/BreadcrumbSeparator.vue +8 -8
- package/src/shadcn/breadcrumb/index.ts +7 -7
- package/src/shadcn/button/Button.vue +29 -29
- package/src/shadcn/button/index.ts +38 -38
- package/src/shadcn/calendar/Calendar.vue +64 -64
- package/src/shadcn/calendar/CalendarCell.vue +23 -23
- package/src/shadcn/calendar/CalendarCellTrigger.vue +39 -39
- package/src/shadcn/calendar/CalendarGrid.vue +23 -23
- package/src/shadcn/calendar/CalendarGridBody.vue +15 -15
- package/src/shadcn/calendar/CalendarGridHead.vue +16 -16
- package/src/shadcn/calendar/CalendarGridRow.vue +22 -22
- package/src/shadcn/calendar/CalendarHeadCell.vue +23 -23
- package/src/shadcn/calendar/CalendarHeader.vue +23 -23
- package/src/shadcn/calendar/CalendarHeading.vue +30 -30
- package/src/shadcn/calendar/CalendarNextButton.vue +32 -32
- package/src/shadcn/calendar/CalendarPrevButton.vue +32 -32
- package/src/shadcn/calendar/index.ts +12 -12
- package/src/shadcn/card/Card.vue +8 -8
- package/src/shadcn/card/CardContent.vue +8 -8
- package/src/shadcn/card/CardDescription.vue +8 -8
- package/src/shadcn/card/CardHeader.vue +8 -8
- package/src/shadcn/card/CardTitle.vue +8 -8
- package/src/shadcn/card/index.ts +5 -5
- package/src/shadcn/checkbox/Checkbox.vue +38 -38
- package/src/shadcn/checkbox/index.ts +1 -1
- package/src/shadcn/command/Command.vue +87 -87
- package/src/shadcn/command/CommandDialog.vue +31 -31
- package/src/shadcn/command/CommandEmpty.vue +27 -27
- package/src/shadcn/command/CommandGroup.vue +45 -45
- package/src/shadcn/command/CommandInput.vue +39 -39
- package/src/shadcn/command/CommandItem.vue +76 -76
- package/src/shadcn/command/CommandList.vue +25 -25
- package/src/shadcn/command/CommandSeparator.vue +21 -21
- package/src/shadcn/command/CommandShortcut.vue +17 -17
- package/src/shadcn/command/index.ts +25 -25
- package/src/shadcn/context-menu/ContextMenu.vue +18 -18
- package/src/shadcn/context-menu/ContextMenuCheckboxItem.vue +38 -38
- package/src/shadcn/context-menu/ContextMenuContent.vue +34 -34
- package/src/shadcn/context-menu/ContextMenuGroup.vue +15 -15
- package/src/shadcn/context-menu/ContextMenuItem.vue +39 -39
- package/src/shadcn/context-menu/ContextMenuLabel.vue +22 -22
- package/src/shadcn/context-menu/ContextMenuPortal.vue +15 -15
- package/src/shadcn/context-menu/ContextMenuRadioGroup.vue +22 -22
- package/src/shadcn/context-menu/ContextMenuRadioItem.vue +38 -38
- package/src/shadcn/context-menu/ContextMenuSeparator.vue +22 -22
- package/src/shadcn/context-menu/ContextMenuShortcut.vue +17 -17
- package/src/shadcn/context-menu/ContextMenuSub.vue +22 -22
- package/src/shadcn/context-menu/ContextMenuSubContent.vue +33 -33
- package/src/shadcn/context-menu/ContextMenuSubTrigger.vue +33 -33
- package/src/shadcn/context-menu/ContextMenuTrigger.vue +17 -17
- package/src/shadcn/context-menu/index.ts +15 -15
- package/src/shadcn/dialog/Dialog.vue +18 -18
- package/src/shadcn/dialog/DialogClose.vue +15 -15
- package/src/shadcn/dialog/DialogContent.vue +46 -46
- package/src/shadcn/dialog/DialogDescription.vue +23 -23
- package/src/shadcn/dialog/DialogFooter.vue +15 -15
- package/src/shadcn/dialog/DialogHeader.vue +17 -17
- package/src/shadcn/dialog/DialogOverlay.vue +21 -21
- package/src/shadcn/dialog/DialogScrollContent.vue +56 -56
- package/src/shadcn/dialog/DialogTitle.vue +23 -23
- package/src/shadcn/dialog/DialogTrigger.vue +15 -15
- package/src/shadcn/dialog/index.ts +10 -10
- package/src/shadcn/dropdown-menu/DropdownMenu.vue +18 -18
- package/src/shadcn/dropdown-menu/DropdownMenuCheckboxItem.vue +38 -38
- package/src/shadcn/dropdown-menu/DropdownMenuContent.vue +36 -36
- package/src/shadcn/dropdown-menu/DropdownMenuGroup.vue +15 -15
- package/src/shadcn/dropdown-menu/DropdownMenuItem.vue +31 -31
- package/src/shadcn/dropdown-menu/DropdownMenuLabel.vue +23 -23
- package/src/shadcn/dropdown-menu/DropdownMenuRadioGroup.vue +22 -22
- package/src/shadcn/dropdown-menu/DropdownMenuRadioItem.vue +39 -39
- package/src/shadcn/dropdown-menu/DropdownMenuSeparator.vue +24 -24
- package/src/shadcn/dropdown-menu/DropdownMenuShortcut.vue +17 -17
- package/src/shadcn/dropdown-menu/DropdownMenuSub.vue +19 -19
- package/src/shadcn/dropdown-menu/DropdownMenuSubContent.vue +28 -28
- package/src/shadcn/dropdown-menu/DropdownMenuSubTrigger.vue +31 -31
- package/src/shadcn/dropdown-menu/DropdownMenuTrigger.vue +17 -17
- package/src/shadcn/dropdown-menu/index.ts +16 -16
- package/src/shadcn/menubar/Menubar.vue +33 -33
- package/src/shadcn/menubar/MenubarCheckboxItem.vue +38 -38
- package/src/shadcn/menubar/MenubarContent.vue +42 -42
- package/src/shadcn/menubar/MenubarGroup.vue +15 -15
- package/src/shadcn/menubar/MenubarItem.vue +37 -37
- package/src/shadcn/menubar/MenubarLabel.vue +20 -20
- package/src/shadcn/menubar/MenubarMenu.vue +15 -15
- package/src/shadcn/menubar/MenubarPortal.vue +5 -5
- package/src/shadcn/menubar/MenubarRadioGroup.vue +22 -22
- package/src/shadcn/menubar/MenubarRadioItem.vue +38 -38
- package/src/shadcn/menubar/MenubarSeparator.vue +21 -21
- package/src/shadcn/menubar/MenubarShortcut.vue +17 -17
- package/src/shadcn/menubar/MenubarSub.vue +23 -23
- package/src/shadcn/menubar/MenubarSubContent.vue +36 -36
- package/src/shadcn/menubar/MenubarSubTrigger.vue +28 -28
- package/src/shadcn/menubar/MenubarTrigger.vue +28 -28
- package/src/shadcn/menubar/index.ts +15 -15
- package/src/shadcn/navigation-menu/NavigationMenu.vue +35 -35
- package/src/shadcn/navigation-menu/NavigationMenuContent.vue +31 -31
- package/src/shadcn/navigation-menu/NavigationMenuIndicator.vue +23 -23
- package/src/shadcn/navigation-menu/NavigationMenuItem.vue +21 -21
- package/src/shadcn/navigation-menu/NavigationMenuLink.vue +26 -26
- package/src/shadcn/navigation-menu/NavigationMenuList.vue +28 -28
- package/src/shadcn/navigation-menu/NavigationMenuTrigger.vue +24 -24
- package/src/shadcn/navigation-menu/NavigationMenuViewport.vue +31 -31
- package/src/shadcn/navigation-menu/index.ts +14 -14
- package/src/shadcn/pagination/Pagination.vue +151 -151
- package/src/shadcn/pagination/PaginationContent.vue +22 -22
- package/src/shadcn/pagination/PaginationEllipsis.vue +25 -25
- package/src/shadcn/pagination/PaginationFirst.vue +33 -33
- package/src/shadcn/pagination/PaginationItem.vue +31 -31
- package/src/shadcn/pagination/PaginationLast.vue +33 -33
- package/src/shadcn/pagination/PaginationLink.vue +13 -13
- package/src/shadcn/pagination/PaginationNext.vue +22 -22
- package/src/shadcn/pagination/PaginationPrevious.vue +33 -33
- package/src/shadcn/pagination/index.ts +9 -9
- package/src/shadcn/popover/Popover.vue +18 -18
- package/src/shadcn/popover/PopoverAnchor.vue +15 -15
- package/src/shadcn/popover/PopoverContent.vue +46 -46
- package/src/shadcn/popover/PopoverTrigger.vue +15 -15
- package/src/shadcn/popover/index.ts +4 -4
- package/src/shadcn/radio-group/RadioGroup.vue +24 -24
- package/src/shadcn/radio-group/RadioGroupItem.vue +39 -39
- package/src/shadcn/radio-group/index.ts +2 -2
- package/src/shadcn/range-calendar/RangeCalendar.vue +71 -71
- package/src/shadcn/range-calendar/RangeCalendarCell.vue +23 -23
- package/src/shadcn/range-calendar/RangeCalendarCellTrigger.vue +41 -41
- package/src/shadcn/range-calendar/RangeCalendarGrid.vue +23 -23
- package/src/shadcn/range-calendar/RangeCalendarGridBody.vue +15 -15
- package/src/shadcn/range-calendar/RangeCalendarGridHead.vue +15 -15
- package/src/shadcn/range-calendar/RangeCalendarGridRow.vue +22 -22
- package/src/shadcn/range-calendar/RangeCalendarHeadCell.vue +23 -23
- package/src/shadcn/range-calendar/RangeCalendarHeader.vue +23 -23
- package/src/shadcn/range-calendar/RangeCalendarHeading.vue +30 -30
- package/src/shadcn/range-calendar/RangeCalendarNextButton.vue +32 -32
- package/src/shadcn/range-calendar/RangeCalendarPrevButton.vue +32 -32
- package/src/shadcn/range-calendar/index.ts +12 -12
- package/src/shadcn/select/Select.vue +18 -18
- package/src/shadcn/select/SelectContent.vue +52 -52
- package/src/shadcn/select/SelectGroup.vue +15 -15
- package/src/shadcn/select/SelectItem.vue +43 -43
- package/src/shadcn/select/SelectItemText.vue +15 -15
- package/src/shadcn/select/SelectLabel.vue +17 -17
- package/src/shadcn/select/SelectScrollDownButton.vue +26 -26
- package/src/shadcn/select/SelectScrollUpButton.vue +26 -26
- package/src/shadcn/select/SelectSeparator.vue +19 -19
- package/src/shadcn/select/SelectTrigger.vue +33 -33
- package/src/shadcn/select/SelectValue.vue +15 -15
- package/src/shadcn/select/index.ts +11 -11
- package/src/shadcn/separator/Separator.vue +31 -31
- package/src/shadcn/separator/index.ts +1 -1
- package/src/shadcn/sidebar/MenuGroup.vue +28 -28
- package/src/shadcn/sidebar/MenuItemRenderer.vue +23 -23
- package/src/shadcn/sidebar/Sidebar.vue +14 -14
- package/src/shadcn/sidebar/SidebarDemoContent.vue +26 -26
- package/src/shadcn/sidebar/SidebarMenuGroupWithLabel.vue +29 -29
- package/src/shadcn/sidebar/SidebarMenuItemWithIcon.vue +103 -103
- package/src/shadcn/sidebar/SidebarMenuSub.vue +10 -10
- package/src/shadcn/sidebar/SidebarMenuSubItemStyled.vue +38 -38
- package/src/shadcn/sidebar/SidebarTrigger.vue +8 -8
- package/src/shadcn/sidebar/index.ts +5 -5
- package/src/shadcn/slider/Slider.vue +43 -43
- package/src/shadcn/slider/index.ts +1 -1
- package/src/shadcn/sonner/Sonner.vue +19 -19
- package/src/shadcn/sonner/index.ts +1 -1
- package/src/shadcn/spinner/Spinner.vue +17 -0
- package/src/shadcn/spinner/index.ts +1 -0
- package/src/shadcn/switch/Switch.vue +38 -38
- package/src/shadcn/switch/index.ts +1 -1
- package/src/shadcn/tabs/CardTabsContent.vue +16 -16
- package/src/shadcn/tabs/CornerCutTabsTrigger.vue +102 -102
- package/src/shadcn/tabs/GridTabsList.vue +30 -30
- package/src/shadcn/tabs/ScrollableTabsList.vue +8 -8
- package/src/shadcn/tabs/Tabs.vue +23 -23
- package/src/shadcn/tabs/TabsContent.vue +21 -21
- package/src/shadcn/tabs/TabsList.vue +24 -24
- package/src/shadcn/tabs/TabsTrigger.vue +30 -30
- package/src/shadcn/tabs/VerticalTabsList.vue +28 -28
- package/src/shadcn/tabs/VerticalTabsTrigger.vue +16 -16
- package/src/shadcn/tabs/index.ts +10 -10
- package/src/shadcn/toggle/Toggle.vue +35 -35
- package/src/shadcn/toggle/index.ts +28 -28
- package/src/shadcn/tooltip/Tooltip.vue +18 -18
- package/src/shadcn/tooltip/TooltipContent.vue +34 -34
- package/src/shadcn/tooltip/TooltipProvider.vue +14 -14
- package/src/shadcn/tooltip/TooltipTrigger.vue +15 -15
- package/src/shadcn/tooltip/index.ts +4 -4
- package/src/shadcn/tree/index.ts +2 -0
- package/src/ui/InputOTP.vue +69 -69
- package/src/ui/InputOTPContext.ts +9 -9
- package/src/ui/InputOTPGroup.vue +7 -7
- package/src/ui/InputOTPSeparator.vue +8 -8
- package/src/ui/InputOTPSlot.vue +61 -61
- package/src/ui/PopoverContent.vue +27 -27
- package/src/ui/PopoverTrigger.vue +9 -9
- package/src/ui/SelectContent.vue +23 -23
- package/src/ui/SelectGroup.vue +12 -12
- package/src/ui/SelectItem.vue +25 -25
- package/src/ui/SelectLabel.vue +16 -16
- package/src/ui/SelectSeparator.vue +17 -17
- package/src/ui/SelectTrigger.vue +22 -22
- package/src/ui/SelectValue.vue +9 -9
- package/src/ui/SheetContent.vue +34 -34
- package/src/ui/SheetDescription.vue +9 -9
- package/src/ui/SheetHeader.vue +11 -11
- package/src/ui/SheetTitle.vue +9 -9
- package/src/ui/accordion-content.vue +21 -21
- package/src/ui/accordion-item.vue +18 -18
- package/src/ui/accordion-trigger.vue +14 -14
- package/src/ui/accordion.vue +9 -9
- package/src/ui/alert-actions.vue +13 -13
- package/src/ui/alert-description.vue +13 -13
- package/src/ui/alert-title.vue +13 -13
- package/src/ui/alert.vue +63 -63
- package/src/ui/avatar-fallback.vue +38 -38
- package/src/ui/avatar-group.vue +32 -32
- package/src/ui/avatar-image.vue +19 -19
- package/src/ui/avatar.vue +32 -32
- package/src/ui/badge.vue +90 -90
- package/src/ui/breadcrumb-item.vue +11 -11
- package/src/ui/breadcrumb-separator.vue +9 -9
- package/src/ui/breadcrumb.vue +11 -11
- package/src/ui/button.vue +76 -76
- package/src/ui/card-content.vue +16 -16
- package/src/ui/card-description.vue +16 -16
- package/src/ui/card-footer.vue +13 -13
- package/src/ui/card-header.vue +19 -19
- package/src/ui/card-title.vue +16 -16
- package/src/ui/card.vue +73 -73
- package/src/ui/category-breakdown-metric.vue +205 -205
- package/src/ui/checkbox.vue +84 -84
- package/src/ui/cn.ts +6 -6
- package/src/ui/dialog-body.vue +13 -13
- package/src/ui/dialog-close.vue +9 -9
- package/src/ui/dialog-content.vue +36 -36
- package/src/ui/dialog-description.vue +13 -13
- package/src/ui/dialog-footer.vue +13 -13
- package/src/ui/dialog-header.vue +13 -13
- package/src/ui/dialog-overlay.vue +14 -14
- package/src/ui/dialog-portal.vue +9 -9
- package/src/ui/dialog-title.vue +13 -13
- package/src/ui/dialog-trigger.vue +9 -9
- package/src/ui/dialog.vue +9 -9
- package/src/ui/dismissible-badges-demo.vue +94 -94
- package/src/ui/drawer-content.vue +53 -53
- package/src/ui/drawer-description.vue +23 -23
- package/src/ui/drawer-footer.vue +22 -22
- package/src/ui/drawer-header.vue +22 -22
- package/src/ui/drawer-title.vue +23 -23
- package/src/ui/drawer-trigger.vue +23 -23
- package/src/ui/drawer.vue +34 -34
- package/src/ui/dropdown-menu-checkbox-item.vue +27 -27
- package/src/ui/dropdown-menu-content.vue +23 -23
- package/src/ui/dropdown-menu-group.vue +7 -7
- package/src/ui/dropdown-menu-item.vue +19 -19
- package/src/ui/dropdown-menu-label.vue +17 -17
- package/src/ui/dropdown-menu-portal.vue +8 -8
- package/src/ui/dropdown-menu-radio-group.vue +14 -14
- package/src/ui/dropdown-menu-radio-item.vue +30 -30
- package/src/ui/dropdown-menu-separator.vue +13 -13
- package/src/ui/dropdown-menu-shortcut.vue +15 -15
- package/src/ui/dropdown-menu-sub-content.vue +8 -8
- package/src/ui/dropdown-menu-sub-trigger.vue +8 -8
- package/src/ui/dropdown-menu-sub.vue +8 -8
- package/src/ui/dropdown-menu-trigger.vue +8 -8
- package/src/ui/dropdown-menu.vue +9 -9
- package/src/ui/grouped-avatar.vue +19 -19
- package/src/ui/icons/Accessibility.vue +7 -7
- package/src/ui/icons/AlignLeft.vue +6 -6
- package/src/ui/icons/ArrowDown.vue +7 -7
- package/src/ui/icons/ArrowUp.vue +7 -7
- package/src/ui/icons/ArrowUpDown.vue +8 -8
- package/src/ui/icons/BookOpen.vue +6 -6
- package/src/ui/icons/Calendar.vue +9 -9
- package/src/ui/icons/Check.vue +6 -6
- package/src/ui/icons/ChevronRight.vue +6 -6
- package/src/ui/icons/Circle.vue +6 -6
- package/src/ui/icons/Copy.vue +7 -7
- package/src/ui/icons/Dot.vue +6 -6
- package/src/ui/icons/Edit.vue +6 -6
- package/src/ui/icons/FileText.vue +9 -9
- package/src/ui/icons/Folder.vue +6 -6
- package/src/ui/icons/FolderOpen.vue +7 -7
- package/src/ui/icons/Hash.vue +6 -6
- package/src/ui/icons/Home.vue +6 -6
- package/src/ui/icons/Minus.vue +6 -6
- package/src/ui/icons/MoreHorizontal.vue +8 -8
- package/src/ui/icons/Settings.vue +7 -7
- package/src/ui/icons/Slash.vue +6 -6
- package/src/ui/icons/Trash2.vue +6 -6
- package/src/ui/icons/Type.vue +6 -6
- package/src/ui/icons/User.vue +7 -7
- package/src/ui/input-otp.vue +52 -52
- package/src/ui/input.vue +98 -98
- package/src/ui/label.vue +19 -19
- package/src/ui/pagination.vue +41 -41
- package/src/ui/popover.vue +9 -9
- package/src/ui/progress.vue +67 -67
- package/src/ui/radio-group-item.vue +53 -53
- package/src/ui/radio-group.vue +27 -27
- package/src/ui/scrollable-tabs-list.vue +148 -148
- package/src/ui/select-multiple.vue +135 -135
- package/src/ui/select.vue +77 -77
- package/src/ui/separator.vue +60 -60
- package/src/ui/sheet.vue +50 -50
- package/src/ui/sidebar/BaseSidebar.vue +97 -97
- package/src/ui/sidebar/BasicSearch.vue +27 -27
- package/src/ui/sidebar/ResponsiveSearch.vue +54 -54
- package/src/ui/sidebar/Sidebar.vue +227 -227
- package/src/ui/sidebar/SidebarCollapseButton.vue +10 -10
- package/src/ui/sidebar/SidebarContent.vue +31 -31
- package/src/ui/sidebar/SidebarDescription.vue +10 -10
- package/src/ui/sidebar/SidebarExpandButton.vue +10 -10
- package/src/ui/sidebar/SidebarFooter.vue +10 -10
- package/src/ui/sidebar/SidebarGroup.vue +11 -11
- package/src/ui/sidebar/SidebarGroupContent.vue +10 -10
- package/src/ui/sidebar/SidebarGroupLabel.vue +7 -7
- package/src/ui/sidebar/SidebarHeader.vue +10 -10
- package/src/ui/sidebar/SidebarInset.vue +19 -19
- package/src/ui/sidebar/SidebarMenu.vue +7 -7
- package/src/ui/sidebar/SidebarMenuBadge.vue +7 -7
- package/src/ui/sidebar/SidebarMenuButton.vue +17 -17
- package/src/ui/sidebar/SidebarMenuItem.vue +10 -10
- package/src/ui/sidebar/SidebarMenuSub.vue +18 -18
- package/src/ui/sidebar/SidebarMenuSubContent.vue +10 -10
- package/src/ui/sidebar/SidebarMenuSubItem.vue +10 -10
- package/src/ui/sidebar/SidebarMenuSubTrigger.vue +10 -10
- package/src/ui/sidebar/SidebarProvider.vue +108 -108
- package/src/ui/sidebar/SidebarScrollArea.vue +10 -10
- package/src/ui/sidebar/SidebarSection.vue +10 -10
- package/src/ui/sidebar/SidebarSeparator.vue +8 -8
- package/src/ui/sidebar/SidebarShortcut.vue +10 -10
- package/src/ui/sidebar/SidebarTitle.vue +10 -10
- package/src/ui/sidebar/SidebarTrigger.vue +27 -27
- package/src/ui/sidebar/Wrapper.vue +12 -12
- package/src/ui/sidebar/context.ts +8 -8
- package/src/ui/sidebar/index.ts +27 -27
- package/src/ui/sidebar/sidebarStore.ts +40 -40
- package/src/ui/sidebar/types.ts +30 -30
- package/src/ui/sidebar/useAutoCollapse.ts +81 -81
- package/src/ui/sidebar.vue +24 -24
- package/src/ui/skeleton.vue +15 -15
- package/src/ui/slider.vue +32 -32
- package/src/ui/sonner.vue +67 -67
- package/src/ui/switch.vue +33 -33
- package/src/ui/tab-content.vue +28 -28
- package/src/ui/tab-list.vue +31 -31
- package/src/ui/tab-panel.vue +19 -19
- package/src/ui/tab-trigger.vue +34 -34
- package/src/ui/tab.vue +30 -30
- package/src/ui/table-body.vue +16 -16
- package/src/ui/table-caption.vue +20 -20
- package/src/ui/table-cell.vue +16 -16
- package/src/ui/table-footer.vue +16 -16
- package/src/ui/table-header.vue +132 -132
- package/src/ui/table-row.vue +16 -16
- package/src/ui/table.vue +55 -55
- package/src/ui/tabs.vue +33 -33
- package/src/ui/textarea.vue +91 -91
- package/src/ui/threat-gauge.vue +137 -137
- package/src/ui/toggle.vue +69 -69
- package/src/ui/tooltip-content.vue +52 -52
- package/src/ui/tooltip-provider.vue +13 -13
- package/src/ui/tooltip-root.vue +9 -9
- package/src/ui/tooltip-trigger.vue +13 -13
- package/src/ui/tooltip.vue +22 -22
- package/src/ui/utils.ts +6 -6
- package/vite.config.ts +39 -39
|
@@ -1,205 +1,205 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { ref, computed } from 'vue'
|
|
3
|
-
import Tooltip from './tooltip.vue'
|
|
4
|
-
import TooltipContent from './tooltip-content.vue'
|
|
5
|
-
import TooltipProvider from './tooltip-provider.vue'
|
|
6
|
-
import TooltipTrigger from './tooltip-trigger.vue'
|
|
7
|
-
|
|
8
|
-
type Category = {
|
|
9
|
-
name: string
|
|
10
|
-
label?: string
|
|
11
|
-
color: string
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const props = defineProps({
|
|
17
|
-
title: String,
|
|
18
|
-
iconName: String,
|
|
19
|
-
categories: {
|
|
20
|
-
type: Array as () => Category[],
|
|
21
|
-
required: true
|
|
22
|
-
},
|
|
23
|
-
data: {
|
|
24
|
-
type: Object as () => Record<string, number>,
|
|
25
|
-
required: true
|
|
26
|
-
},
|
|
27
|
-
isLoading: Boolean
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
const nonZeroCategories = computed(() => props.categories?.filter(c => (props.data[c.name] ?? 0) > 0))
|
|
31
|
-
const total = computed(() => nonZeroCategories.value?.reduce((sum, cat) => sum + (props.data[cat.name] || 0), 0))
|
|
32
|
-
|
|
33
|
-
const categoryPositions = computed(() => {
|
|
34
|
-
let cumulativePercentage = 0
|
|
35
|
-
return nonZeroCategories.value?.map((category, index) => {
|
|
36
|
-
const value = props.data[category.name] || 0
|
|
37
|
-
const proportion = total.value > 0 ? value / total.value : 0
|
|
38
|
-
const percentage = proportion * 100
|
|
39
|
-
const boundaryPosition = cumulativePercentage
|
|
40
|
-
cumulativePercentage += percentage
|
|
41
|
-
return {
|
|
42
|
-
...category,
|
|
43
|
-
value,
|
|
44
|
-
boundaryPosition,
|
|
45
|
-
percentage,
|
|
46
|
-
index
|
|
47
|
-
}
|
|
48
|
-
})
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
const MIN_LABEL_WIDTH_PCT = 24
|
|
52
|
-
const showLabel = computed(() => {
|
|
53
|
-
const arr = categoryPositions.value?.map(() => true)
|
|
54
|
-
for (let i = 0; i < categoryPositions.value?.length - 1; i++) {
|
|
55
|
-
const cur = categoryPositions.value[i]
|
|
56
|
-
const next = categoryPositions.value[i + 1]
|
|
57
|
-
const segmentWidthPct = next.boundaryPosition - cur.boundaryPosition
|
|
58
|
-
if (segmentWidthPct < MIN_LABEL_WIDTH_PCT) {
|
|
59
|
-
arr[i] = false
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
if (categoryPositions.value?.length > 0) {
|
|
63
|
-
const last = categoryPositions.value[categoryPositions.value?.length - 1]
|
|
64
|
-
const lastWidthPct = 100 - last.boundaryPosition
|
|
65
|
-
if (lastWidthPct < MIN_LABEL_WIDTH_PCT) {
|
|
66
|
-
arr[categoryPositions.value?.length - 1] = false
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
return arr
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
const visibleCategories = computed(() => {
|
|
73
|
-
return categoryPositions.value?.map((category, index) => {
|
|
74
|
-
if (index === categoryPositions.value?.length - 1) {
|
|
75
|
-
return { ...category, isVisible: true }
|
|
76
|
-
}
|
|
77
|
-
const nextCategory = categoryPositions.value[index + 1]
|
|
78
|
-
const minSpacingNeeded = 15
|
|
79
|
-
const spaceAvailable = nextCategory.boundaryPosition - category.boundaryPosition
|
|
80
|
-
const isVisible = spaceAvailable >= minSpacingNeeded
|
|
81
|
-
return { ...category, isVisible }
|
|
82
|
-
})
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
const BAR_COUNT = 74
|
|
86
|
-
const bars = computed(() => {
|
|
87
|
-
const arr: Array<{ color: string; position: number }> = []
|
|
88
|
-
let currentPosition = 0
|
|
89
|
-
props.categories?.forEach(category => {
|
|
90
|
-
const value = props.data[category.name] || 0
|
|
91
|
-
const isNonZero = nonZeroCategories.value.find(c => c.name === category.name)
|
|
92
|
-
const proportion = total.value > 0 ? (isNonZero ? value / total.value : 0) : 0
|
|
93
|
-
const barCount = Math.round(proportion * BAR_COUNT)
|
|
94
|
-
for (let i = 0; i < barCount; i++) {
|
|
95
|
-
arr.push({ color: category.color, position: currentPosition + i })
|
|
96
|
-
}
|
|
97
|
-
currentPosition += barCount
|
|
98
|
-
})
|
|
99
|
-
while (arr?.length < BAR_COUNT) {
|
|
100
|
-
let lastNonZero
|
|
101
|
-
if (nonZeroCategories.value) lastNonZero = nonZeroCategories.value[nonZeroCategories.value?.length - 1]
|
|
102
|
-
const fallback = lastNonZero?.color || (props.categories && props.categories[props.categories?.length - 1]?.color) || '#9ca3af'
|
|
103
|
-
arr.push({ color: fallback, position: arr?.length })
|
|
104
|
-
}
|
|
105
|
-
return arr
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
const isEmpty = computed(() => total.value === 0)
|
|
109
|
-
</script>
|
|
110
|
-
|
|
111
|
-
<template>
|
|
112
|
-
<div v-if="isEmpty" class="relative w-full h-[75px] flex items-center justify-center bg-gray-800 rounded-md">
|
|
113
|
-
<span class="text-gray-400 text-sm">No data available</span>
|
|
114
|
-
</div>
|
|
115
|
-
<TooltipProvider v-else>
|
|
116
|
-
<Tooltip>
|
|
117
|
-
<TooltipTrigger as-child>
|
|
118
|
-
<div class="relative w-full h-[75px] cursor-help select-none">
|
|
119
|
-
<!-- Labels -->
|
|
120
|
-
<template v-for="(category, index) in categoryPositions" :key="category.name">
|
|
121
|
-
<div v-if="showLabel[index]">
|
|
122
|
-
<div
|
|
123
|
-
v-if="index !== categoryPositions?.length - 1"
|
|
124
|
-
class="absolute box-border content-stretch flex flex-col gap-[4px] py-0 top-[0.33px] items-start"
|
|
125
|
-
:style="{ left: category.boundaryPosition + '%', transform: 'translateX(8px)' }"
|
|
126
|
-
>
|
|
127
|
-
<p class="leading-[16px] text-[12px] text-muted-foreground">{{ category.label || category.name }}</p>
|
|
128
|
-
<p class="leading-[20px] text-[24px]" :style="{ color: category.color }">{{ category.value }}</p>
|
|
129
|
-
</div>
|
|
130
|
-
<div
|
|
131
|
-
v-else
|
|
132
|
-
class="absolute box-border content-stretch flex flex-col gap-[4px] py-0 top-[0.33px]"
|
|
133
|
-
:style="{
|
|
134
|
-
left: category.boundaryPosition + '%',
|
|
135
|
-
transform: (100 - category.boundaryPosition < 6) ? 'translateX(calc(-100% - 8px))' : 'translateX(8px)',
|
|
136
|
-
textAlign: (100 - category.boundaryPosition < 6) ? 'right' : 'left'
|
|
137
|
-
}"
|
|
138
|
-
>
|
|
139
|
-
<p class="leading-[16px] text-[12px] text-muted-foreground">{{ category.label || category.name }}</p>
|
|
140
|
-
<p class="leading-[20px] text-[24px]" :style="{ color: category.color }">{{ category.value }}</p>
|
|
141
|
-
</div>
|
|
142
|
-
</div>
|
|
143
|
-
</template>
|
|
144
|
-
|
|
145
|
-
<!-- Boundary separators -->
|
|
146
|
-
<template v-for="(category, index) in categoryPositions" :key="'line-' + index">
|
|
147
|
-
<div v-if="index !== 0" class="absolute flex h-[75px] items-center justify-center top-0 w-[0px] overflow-visible" :style="{ left: categoryPositions.slice(0, index).reduce((sum, cat) => sum + cat.percentage, 0) + '%' }">
|
|
148
|
-
<div class="flex-none" style="rotate: 90deg">
|
|
149
|
-
<div class="h-0 relative w-[75px]">
|
|
150
|
-
<div class="absolute bottom-0 left-0 right-0 top-[-1px]">
|
|
151
|
-
<svg class="block size-full" fill="none" preserveAspectRatio="none" viewBox="0 0 75 1">
|
|
152
|
-
<line :stroke="category.color" x2="75" y1="0.5" y2="0.5" />
|
|
153
|
-
</svg>
|
|
154
|
-
</div>
|
|
155
|
-
</div>
|
|
156
|
-
</div>
|
|
157
|
-
</div>
|
|
158
|
-
</template>
|
|
159
|
-
|
|
160
|
-
<!-- Left edge vertical line -->
|
|
161
|
-
<div class="absolute flex h-[75px] items-center justify-center left-0 top-0 w-[0px]">
|
|
162
|
-
<div class="flex-none" style="rotate: 90deg">
|
|
163
|
-
<div class="h-0 relative w-[75px]">
|
|
164
|
-
<div class="absolute bottom-0 left-0 right-0 top-[-1px]">
|
|
165
|
-
<svg class="block size-full" fill="none" preserveAspectRatio="none" viewBox="0 0 75 1">
|
|
166
|
-
<line :stroke="(visibleCategories && visibleCategories[0]?.color) || (nonZeroCategories && nonZeroCategories[0]?.color) || '#9ca3af'" x2="75" y1="0.5" y2="0.5" />
|
|
167
|
-
</svg>
|
|
168
|
-
</div>
|
|
169
|
-
</div>
|
|
170
|
-
</div>
|
|
171
|
-
</div>
|
|
172
|
-
|
|
173
|
-
<!-- Bars -->
|
|
174
|
-
<div class="absolute box-border content-stretch flex items-center justify-between left-[0.33px] overflow-clip px-[2px] py-0 right-[0.33px] rounded-[2px] top-[51px]">
|
|
175
|
-
<div v-for="(bar, index) in bars" :key="index" class="flex items-center justify-center relative shrink-0">
|
|
176
|
-
<div class="flex-none rotate-[180deg] scale-y-[-100%]">
|
|
177
|
-
<div class="h-[24px] w-px" :style="{ backgroundColor: isEmpty ? '#9ca3af' : bar.color }" />
|
|
178
|
-
</div>
|
|
179
|
-
</div>
|
|
180
|
-
</div>
|
|
181
|
-
</div>
|
|
182
|
-
</TooltipTrigger>
|
|
183
|
-
<TooltipContent variant="outline">
|
|
184
|
-
<div class="space-y-2">
|
|
185
|
-
<p class="font-medium text-sm">Threat Breakdown</p>
|
|
186
|
-
<div class="space-y-1">
|
|
187
|
-
<div v-for="category in props.categories" :key="category.name" class="flex items-center justify-between gap-4">
|
|
188
|
-
<div class="flex items-center gap-2">
|
|
189
|
-
<div class="w-2 h-2 rounded-full flex-shrink-0" :style="{ backgroundColor: category.color }" />
|
|
190
|
-
<span class="text-sm">{{ category.label || category.name }}</span>
|
|
191
|
-
</div>
|
|
192
|
-
<span class="text-sm font-mono" :style="{ color: category.color }">{{ props.data[category.name] || 0 }}</span>
|
|
193
|
-
</div>
|
|
194
|
-
</div>
|
|
195
|
-
<div class="border-t pt-2 mt-2">
|
|
196
|
-
<div class="flex items-center justify-between">
|
|
197
|
-
<span class="text-sm font-medium">Total</span>
|
|
198
|
-
<span class="text-sm font-mono font-medium">{{ props.categories.reduce((sum, c) => sum + (props.data[c.name] || 0), 0).toLocaleString() }}</span>
|
|
199
|
-
</div>
|
|
200
|
-
</div>
|
|
201
|
-
</div>
|
|
202
|
-
</TooltipContent>
|
|
203
|
-
</Tooltip>
|
|
204
|
-
</TooltipProvider>
|
|
205
|
-
</template>
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, computed } from 'vue'
|
|
3
|
+
import Tooltip from './tooltip.vue'
|
|
4
|
+
import TooltipContent from './tooltip-content.vue'
|
|
5
|
+
import TooltipProvider from './tooltip-provider.vue'
|
|
6
|
+
import TooltipTrigger from './tooltip-trigger.vue'
|
|
7
|
+
|
|
8
|
+
type Category = {
|
|
9
|
+
name: string
|
|
10
|
+
label?: string
|
|
11
|
+
color: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
const props = defineProps({
|
|
17
|
+
title: String,
|
|
18
|
+
iconName: String,
|
|
19
|
+
categories: {
|
|
20
|
+
type: Array as () => Category[],
|
|
21
|
+
required: true
|
|
22
|
+
},
|
|
23
|
+
data: {
|
|
24
|
+
type: Object as () => Record<string, number>,
|
|
25
|
+
required: true
|
|
26
|
+
},
|
|
27
|
+
isLoading: Boolean
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
const nonZeroCategories = computed(() => props.categories?.filter(c => (props.data[c.name] ?? 0) > 0))
|
|
31
|
+
const total = computed(() => nonZeroCategories.value?.reduce((sum, cat) => sum + (props.data[cat.name] || 0), 0))
|
|
32
|
+
|
|
33
|
+
const categoryPositions = computed(() => {
|
|
34
|
+
let cumulativePercentage = 0
|
|
35
|
+
return nonZeroCategories.value?.map((category, index) => {
|
|
36
|
+
const value = props.data[category.name] || 0
|
|
37
|
+
const proportion = total.value > 0 ? value / total.value : 0
|
|
38
|
+
const percentage = proportion * 100
|
|
39
|
+
const boundaryPosition = cumulativePercentage
|
|
40
|
+
cumulativePercentage += percentage
|
|
41
|
+
return {
|
|
42
|
+
...category,
|
|
43
|
+
value,
|
|
44
|
+
boundaryPosition,
|
|
45
|
+
percentage,
|
|
46
|
+
index
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
const MIN_LABEL_WIDTH_PCT = 24
|
|
52
|
+
const showLabel = computed(() => {
|
|
53
|
+
const arr = categoryPositions.value?.map(() => true)
|
|
54
|
+
for (let i = 0; i < categoryPositions.value?.length - 1; i++) {
|
|
55
|
+
const cur = categoryPositions.value[i]
|
|
56
|
+
const next = categoryPositions.value[i + 1]
|
|
57
|
+
const segmentWidthPct = next.boundaryPosition - cur.boundaryPosition
|
|
58
|
+
if (segmentWidthPct < MIN_LABEL_WIDTH_PCT) {
|
|
59
|
+
arr[i] = false
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (categoryPositions.value?.length > 0) {
|
|
63
|
+
const last = categoryPositions.value[categoryPositions.value?.length - 1]
|
|
64
|
+
const lastWidthPct = 100 - last.boundaryPosition
|
|
65
|
+
if (lastWidthPct < MIN_LABEL_WIDTH_PCT) {
|
|
66
|
+
arr[categoryPositions.value?.length - 1] = false
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return arr
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
const visibleCategories = computed(() => {
|
|
73
|
+
return categoryPositions.value?.map((category, index) => {
|
|
74
|
+
if (index === categoryPositions.value?.length - 1) {
|
|
75
|
+
return { ...category, isVisible: true }
|
|
76
|
+
}
|
|
77
|
+
const nextCategory = categoryPositions.value[index + 1]
|
|
78
|
+
const minSpacingNeeded = 15
|
|
79
|
+
const spaceAvailable = nextCategory.boundaryPosition - category.boundaryPosition
|
|
80
|
+
const isVisible = spaceAvailable >= minSpacingNeeded
|
|
81
|
+
return { ...category, isVisible }
|
|
82
|
+
})
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
const BAR_COUNT = 74
|
|
86
|
+
const bars = computed(() => {
|
|
87
|
+
const arr: Array<{ color: string; position: number }> = []
|
|
88
|
+
let currentPosition = 0
|
|
89
|
+
props.categories?.forEach(category => {
|
|
90
|
+
const value = props.data[category.name] || 0
|
|
91
|
+
const isNonZero = nonZeroCategories.value.find(c => c.name === category.name)
|
|
92
|
+
const proportion = total.value > 0 ? (isNonZero ? value / total.value : 0) : 0
|
|
93
|
+
const barCount = Math.round(proportion * BAR_COUNT)
|
|
94
|
+
for (let i = 0; i < barCount; i++) {
|
|
95
|
+
arr.push({ color: category.color, position: currentPosition + i })
|
|
96
|
+
}
|
|
97
|
+
currentPosition += barCount
|
|
98
|
+
})
|
|
99
|
+
while (arr?.length < BAR_COUNT) {
|
|
100
|
+
let lastNonZero
|
|
101
|
+
if (nonZeroCategories.value) lastNonZero = nonZeroCategories.value[nonZeroCategories.value?.length - 1]
|
|
102
|
+
const fallback = lastNonZero?.color || (props.categories && props.categories[props.categories?.length - 1]?.color) || '#9ca3af'
|
|
103
|
+
arr.push({ color: fallback, position: arr?.length })
|
|
104
|
+
}
|
|
105
|
+
return arr
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
const isEmpty = computed(() => total.value === 0)
|
|
109
|
+
</script>
|
|
110
|
+
|
|
111
|
+
<template>
|
|
112
|
+
<div v-if="isEmpty" class="relative w-full h-[75px] flex items-center justify-center bg-gray-800 rounded-md">
|
|
113
|
+
<span class="text-gray-400 text-sm">No data available</span>
|
|
114
|
+
</div>
|
|
115
|
+
<TooltipProvider v-else>
|
|
116
|
+
<Tooltip>
|
|
117
|
+
<TooltipTrigger as-child>
|
|
118
|
+
<div class="relative w-full h-[75px] cursor-help select-none">
|
|
119
|
+
<!-- Labels -->
|
|
120
|
+
<template v-for="(category, index) in categoryPositions" :key="category.name">
|
|
121
|
+
<div v-if="showLabel[index]">
|
|
122
|
+
<div
|
|
123
|
+
v-if="index !== categoryPositions?.length - 1"
|
|
124
|
+
class="absolute box-border content-stretch flex flex-col gap-[4px] py-0 top-[0.33px] items-start"
|
|
125
|
+
:style="{ left: category.boundaryPosition + '%', transform: 'translateX(8px)' }"
|
|
126
|
+
>
|
|
127
|
+
<p class="leading-[16px] text-[12px] text-muted-foreground">{{ category.label || category.name }}</p>
|
|
128
|
+
<p class="leading-[20px] text-[24px]" :style="{ color: category.color }">{{ category.value }}</p>
|
|
129
|
+
</div>
|
|
130
|
+
<div
|
|
131
|
+
v-else
|
|
132
|
+
class="absolute box-border content-stretch flex flex-col gap-[4px] py-0 top-[0.33px]"
|
|
133
|
+
:style="{
|
|
134
|
+
left: category.boundaryPosition + '%',
|
|
135
|
+
transform: (100 - category.boundaryPosition < 6) ? 'translateX(calc(-100% - 8px))' : 'translateX(8px)',
|
|
136
|
+
textAlign: (100 - category.boundaryPosition < 6) ? 'right' : 'left'
|
|
137
|
+
}"
|
|
138
|
+
>
|
|
139
|
+
<p class="leading-[16px] text-[12px] text-muted-foreground">{{ category.label || category.name }}</p>
|
|
140
|
+
<p class="leading-[20px] text-[24px]" :style="{ color: category.color }">{{ category.value }}</p>
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
</template>
|
|
144
|
+
|
|
145
|
+
<!-- Boundary separators -->
|
|
146
|
+
<template v-for="(category, index) in categoryPositions" :key="'line-' + index">
|
|
147
|
+
<div v-if="index !== 0" class="absolute flex h-[75px] items-center justify-center top-0 w-[0px] overflow-visible" :style="{ left: categoryPositions.slice(0, index).reduce((sum, cat) => sum + cat.percentage, 0) + '%' }">
|
|
148
|
+
<div class="flex-none" style="rotate: 90deg">
|
|
149
|
+
<div class="h-0 relative w-[75px]">
|
|
150
|
+
<div class="absolute bottom-0 left-0 right-0 top-[-1px]">
|
|
151
|
+
<svg class="block size-full" fill="none" preserveAspectRatio="none" viewBox="0 0 75 1">
|
|
152
|
+
<line :stroke="category.color" x2="75" y1="0.5" y2="0.5" />
|
|
153
|
+
</svg>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
</template>
|
|
159
|
+
|
|
160
|
+
<!-- Left edge vertical line -->
|
|
161
|
+
<div class="absolute flex h-[75px] items-center justify-center left-0 top-0 w-[0px]">
|
|
162
|
+
<div class="flex-none" style="rotate: 90deg">
|
|
163
|
+
<div class="h-0 relative w-[75px]">
|
|
164
|
+
<div class="absolute bottom-0 left-0 right-0 top-[-1px]">
|
|
165
|
+
<svg class="block size-full" fill="none" preserveAspectRatio="none" viewBox="0 0 75 1">
|
|
166
|
+
<line :stroke="(visibleCategories && visibleCategories[0]?.color) || (nonZeroCategories && nonZeroCategories[0]?.color) || '#9ca3af'" x2="75" y1="0.5" y2="0.5" />
|
|
167
|
+
</svg>
|
|
168
|
+
</div>
|
|
169
|
+
</div>
|
|
170
|
+
</div>
|
|
171
|
+
</div>
|
|
172
|
+
|
|
173
|
+
<!-- Bars -->
|
|
174
|
+
<div class="absolute box-border content-stretch flex items-center justify-between left-[0.33px] overflow-clip px-[2px] py-0 right-[0.33px] rounded-[2px] top-[51px]">
|
|
175
|
+
<div v-for="(bar, index) in bars" :key="index" class="flex items-center justify-center relative shrink-0">
|
|
176
|
+
<div class="flex-none rotate-[180deg] scale-y-[-100%]">
|
|
177
|
+
<div class="h-[24px] w-px" :style="{ backgroundColor: isEmpty ? '#9ca3af' : bar.color }" />
|
|
178
|
+
</div>
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
</div>
|
|
182
|
+
</TooltipTrigger>
|
|
183
|
+
<TooltipContent variant="outline">
|
|
184
|
+
<div class="space-y-2">
|
|
185
|
+
<p class="font-medium text-sm">Threat Breakdown</p>
|
|
186
|
+
<div class="space-y-1">
|
|
187
|
+
<div v-for="category in props.categories" :key="category.name" class="flex items-center justify-between gap-4">
|
|
188
|
+
<div class="flex items-center gap-2">
|
|
189
|
+
<div class="w-2 h-2 rounded-full flex-shrink-0" :style="{ backgroundColor: category.color }" />
|
|
190
|
+
<span class="text-sm">{{ category.label || category.name }}</span>
|
|
191
|
+
</div>
|
|
192
|
+
<span class="text-sm font-mono" :style="{ color: category.color }">{{ props.data[category.name] || 0 }}</span>
|
|
193
|
+
</div>
|
|
194
|
+
</div>
|
|
195
|
+
<div class="border-t pt-2 mt-2">
|
|
196
|
+
<div class="flex items-center justify-between">
|
|
197
|
+
<span class="text-sm font-medium">Total</span>
|
|
198
|
+
<span class="text-sm font-mono font-medium">{{ props.categories.reduce((sum, c) => sum + (props.data[c.name] || 0), 0).toLocaleString() }}</span>
|
|
199
|
+
</div>
|
|
200
|
+
</div>
|
|
201
|
+
</div>
|
|
202
|
+
</TooltipContent>
|
|
203
|
+
</Tooltip>
|
|
204
|
+
</TooltipProvider>
|
|
205
|
+
</template>
|
package/src/ui/checkbox.vue
CHANGED
|
@@ -1,84 +1,84 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
<template>
|
|
4
|
-
<div v-if="label" class="space-y-2">
|
|
5
|
-
<div class="flex items-center space-x-2">
|
|
6
|
-
<span class="relative flex items-center">
|
|
7
|
-
<input
|
|
8
|
-
id="with-label"
|
|
9
|
-
data-slot="checkbox"
|
|
10
|
-
type="checkbox"
|
|
11
|
-
:checked="modelValue"
|
|
12
|
-
:disabled="disabled"
|
|
13
|
-
:aria-invalid="validationState === 'error' ? 'true' : undefined"
|
|
14
|
-
:class="checkboxClass"
|
|
15
|
-
v-bind="$attrs"
|
|
16
|
-
@change="$emit('update:modelValue', $event.target.checked)"
|
|
17
|
-
/>
|
|
18
|
-
<span v-if="modelValue" data-slot="checkbox-indicator" class="absolute left-0 top-0 flex h-full w-full items-center justify-center text-current transition-none pointer-events-none">
|
|
19
|
-
<CheckIcon class="h-3.5 w-3.5" />
|
|
20
|
-
</span>
|
|
21
|
-
</span>
|
|
22
|
-
<Label htmlFor="with-label">{{ label }}</Label>
|
|
23
|
-
</div>
|
|
24
|
-
<p v-if="validationState === 'success' && validationText" class="text-sm text-green-600 flex items-center gap-1">
|
|
25
|
-
<CheckIcon class="h-4 w-4" />
|
|
26
|
-
{{ validationText }}
|
|
27
|
-
</p>
|
|
28
|
-
<p v-if="validationState === 'error' && validationText" class="text-sm text-red-600 flex items-center gap-1">
|
|
29
|
-
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor"><circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" fill="none"/><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01" /></svg>
|
|
30
|
-
{{ validationText }}
|
|
31
|
-
</p>
|
|
32
|
-
</div>
|
|
33
|
-
<div v-else class="space-y-2">
|
|
34
|
-
<span class="relative flex items-center">
|
|
35
|
-
<input
|
|
36
|
-
data-slot="checkbox"
|
|
37
|
-
type="checkbox"
|
|
38
|
-
:checked="modelValue"
|
|
39
|
-
:disabled="disabled"
|
|
40
|
-
:aria-invalid="validationState === 'error' ? 'true' : undefined"
|
|
41
|
-
:class="checkboxClass"
|
|
42
|
-
v-bind="$attrs"
|
|
43
|
-
@change="$emit('update:modelValue', $event.target.checked)"
|
|
44
|
-
/>
|
|
45
|
-
<span v-if="modelValue" data-slot="checkbox-indicator" class="absolute left-0 top-0 flex h-full w-full items-center justify-center text-current transition-none pointer-events-none">
|
|
46
|
-
<CheckIcon class="h-3.5 w-3.5" />
|
|
47
|
-
</span>
|
|
48
|
-
</span>
|
|
49
|
-
<slot name="label" />
|
|
50
|
-
<p v-if="validationState === 'success' && validationText" class="text-sm text-green-600 flex items-center gap-1">
|
|
51
|
-
<CheckIcon class="h-4 w-4" />
|
|
52
|
-
{{ validationText }}
|
|
53
|
-
</p>
|
|
54
|
-
<p v-if="validationState === 'error' && validationText" class="text-sm text-red-600 flex items-center gap-1">
|
|
55
|
-
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor"><circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" fill="none"/><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01" /></svg>
|
|
56
|
-
{{ validationText }}
|
|
57
|
-
</p>
|
|
58
|
-
</div>
|
|
59
|
-
</template>
|
|
60
|
-
|
|
61
|
-
<script setup>
|
|
62
|
-
import { computed } from 'vue';
|
|
63
|
-
import Label from './label.vue';
|
|
64
|
-
import CheckIcon from './icons/Check.vue';
|
|
65
|
-
|
|
66
|
-
const props = defineProps({
|
|
67
|
-
modelValue: { type: Boolean, default: false },
|
|
68
|
-
disabled: { type: Boolean, default: false },
|
|
69
|
-
label: { type: String, default: '' },
|
|
70
|
-
validationState: { type: String, default: undefined }, // 'success' | 'error'
|
|
71
|
-
validationText: { type: String, default: '' },
|
|
72
|
-
id: { type: String, default: undefined },
|
|
73
|
-
class: { type: String, default: '' },
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
const computedId = computed(() => props.id || `checkbox-${Math.random().toString(36).substr(2, 9)}`);
|
|
77
|
-
|
|
78
|
-
const checkboxClass = computed(() => [
|
|
79
|
-
'peer border bg-input-background dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50',
|
|
80
|
-
props.validationState === 'error' ? 'border-red-500 data-[state=checked]:bg-red-500' : '',
|
|
81
|
-
props.validationState === 'success' ? 'border-green-500 data-[state=checked]:bg-green-500' : '',
|
|
82
|
-
props.class,
|
|
83
|
-
]);
|
|
84
|
-
</script>
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
<template>
|
|
4
|
+
<div v-if="label" class="space-y-2">
|
|
5
|
+
<div class="flex items-center space-x-2">
|
|
6
|
+
<span class="relative flex items-center">
|
|
7
|
+
<input
|
|
8
|
+
id="with-label"
|
|
9
|
+
data-slot="checkbox"
|
|
10
|
+
type="checkbox"
|
|
11
|
+
:checked="modelValue"
|
|
12
|
+
:disabled="disabled"
|
|
13
|
+
:aria-invalid="validationState === 'error' ? 'true' : undefined"
|
|
14
|
+
:class="checkboxClass"
|
|
15
|
+
v-bind="$attrs"
|
|
16
|
+
@change="$emit('update:modelValue', $event.target.checked)"
|
|
17
|
+
/>
|
|
18
|
+
<span v-if="modelValue" data-slot="checkbox-indicator" class="absolute left-0 top-0 flex h-full w-full items-center justify-center text-current transition-none pointer-events-none">
|
|
19
|
+
<CheckIcon class="h-3.5 w-3.5" />
|
|
20
|
+
</span>
|
|
21
|
+
</span>
|
|
22
|
+
<Label htmlFor="with-label">{{ label }}</Label>
|
|
23
|
+
</div>
|
|
24
|
+
<p v-if="validationState === 'success' && validationText" class="text-sm text-green-600 flex items-center gap-1">
|
|
25
|
+
<CheckIcon class="h-4 w-4" />
|
|
26
|
+
{{ validationText }}
|
|
27
|
+
</p>
|
|
28
|
+
<p v-if="validationState === 'error' && validationText" class="text-sm text-red-600 flex items-center gap-1">
|
|
29
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor"><circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" fill="none"/><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01" /></svg>
|
|
30
|
+
{{ validationText }}
|
|
31
|
+
</p>
|
|
32
|
+
</div>
|
|
33
|
+
<div v-else class="space-y-2">
|
|
34
|
+
<span class="relative flex items-center">
|
|
35
|
+
<input
|
|
36
|
+
data-slot="checkbox"
|
|
37
|
+
type="checkbox"
|
|
38
|
+
:checked="modelValue"
|
|
39
|
+
:disabled="disabled"
|
|
40
|
+
:aria-invalid="validationState === 'error' ? 'true' : undefined"
|
|
41
|
+
:class="checkboxClass"
|
|
42
|
+
v-bind="$attrs"
|
|
43
|
+
@change="$emit('update:modelValue', $event.target.checked)"
|
|
44
|
+
/>
|
|
45
|
+
<span v-if="modelValue" data-slot="checkbox-indicator" class="absolute left-0 top-0 flex h-full w-full items-center justify-center text-current transition-none pointer-events-none">
|
|
46
|
+
<CheckIcon class="h-3.5 w-3.5" />
|
|
47
|
+
</span>
|
|
48
|
+
</span>
|
|
49
|
+
<slot name="label" />
|
|
50
|
+
<p v-if="validationState === 'success' && validationText" class="text-sm text-green-600 flex items-center gap-1">
|
|
51
|
+
<CheckIcon class="h-4 w-4" />
|
|
52
|
+
{{ validationText }}
|
|
53
|
+
</p>
|
|
54
|
+
<p v-if="validationState === 'error' && validationText" class="text-sm text-red-600 flex items-center gap-1">
|
|
55
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor"><circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" fill="none"/><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01" /></svg>
|
|
56
|
+
{{ validationText }}
|
|
57
|
+
</p>
|
|
58
|
+
</div>
|
|
59
|
+
</template>
|
|
60
|
+
|
|
61
|
+
<script setup>
|
|
62
|
+
import { computed } from 'vue';
|
|
63
|
+
import Label from './label.vue';
|
|
64
|
+
import CheckIcon from './icons/Check.vue';
|
|
65
|
+
|
|
66
|
+
const props = defineProps({
|
|
67
|
+
modelValue: { type: Boolean, default: false },
|
|
68
|
+
disabled: { type: Boolean, default: false },
|
|
69
|
+
label: { type: String, default: '' },
|
|
70
|
+
validationState: { type: String, default: undefined }, // 'success' | 'error'
|
|
71
|
+
validationText: { type: String, default: '' },
|
|
72
|
+
id: { type: String, default: undefined },
|
|
73
|
+
class: { type: String, default: '' },
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const computedId = computed(() => props.id || `checkbox-${Math.random().toString(36).substr(2, 9)}`);
|
|
77
|
+
|
|
78
|
+
const checkboxClass = computed(() => [
|
|
79
|
+
'peer border bg-input-background dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50',
|
|
80
|
+
props.validationState === 'error' ? 'border-red-500 data-[state=checked]:bg-red-500' : '',
|
|
81
|
+
props.validationState === 'success' ? 'border-green-500 data-[state=checked]:bg-green-500' : '',
|
|
82
|
+
props.class,
|
|
83
|
+
]);
|
|
84
|
+
</script>
|
package/src/ui/cn.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { clsx, type ClassValue } from "clsx";
|
|
2
|
-
import { twMerge } from "tailwind-merge";
|
|
3
|
-
|
|
4
|
-
export function cn(...inputs: ClassValue[]) {
|
|
5
|
-
return twMerge(clsx(inputs));
|
|
6
|
-
}
|
|
1
|
+
import { clsx, type ClassValue } from "clsx";
|
|
2
|
+
import { twMerge } from "tailwind-merge";
|
|
3
|
+
|
|
4
|
+
export function cn(...inputs: ClassValue[]) {
|
|
5
|
+
return twMerge(clsx(inputs));
|
|
6
|
+
}
|
package/src/ui/dialog-body.vue
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div
|
|
3
|
-
data-slot="dialog-body"
|
|
4
|
-
:class="['p-4 space-y-4', $attrs.class]"
|
|
5
|
-
v-bind="$attrs"
|
|
6
|
-
>
|
|
7
|
-
<slot />
|
|
8
|
-
</div>
|
|
9
|
-
</template>
|
|
10
|
-
|
|
11
|
-
<script setup>
|
|
12
|
-
// No additional logic needed
|
|
13
|
-
</script>
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
data-slot="dialog-body"
|
|
4
|
+
:class="['p-4 space-y-4', $attrs.class]"
|
|
5
|
+
v-bind="$attrs"
|
|
6
|
+
>
|
|
7
|
+
<slot />
|
|
8
|
+
</div>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script setup>
|
|
12
|
+
// No additional logic needed
|
|
13
|
+
</script>
|
package/src/ui/dialog-close.vue
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<DialogClose v-bind="$attrs">
|
|
3
|
-
<slot />
|
|
4
|
-
</DialogClose>
|
|
5
|
-
</template>
|
|
6
|
-
|
|
7
|
-
<script setup>
|
|
8
|
-
import { DialogClose } from "reka-ui"
|
|
9
|
-
</script>
|
|
1
|
+
<template>
|
|
2
|
+
<DialogClose v-bind="$attrs">
|
|
3
|
+
<slot />
|
|
4
|
+
</DialogClose>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script setup>
|
|
8
|
+
import { DialogClose } from "reka-ui"
|
|
9
|
+
</script>
|