@geniusdynamics/ns8-ui-lib 1.0.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/README.md +167 -0
- package/dist/index.d.ts +14 -0
- package/dist/ns8-ui-lib.es.js +4278 -0
- package/dist/ns8-ui-lib.es.js.map +1 -0
- package/dist/ns8-ui-lib.umd.js +7 -0
- package/dist/ns8-ui-lib.umd.js.map +1 -0
- package/dist/src/App.vue.d.ts +2 -0
- package/dist/src/components/HelloWorld.vue.d.ts +5 -0
- package/dist/src/components/NS/cards/NSBackupCard.vue.d.ts +51 -0
- package/dist/src/components/NS/cards/NSSystemInfoCard.vue.d.ts +58 -0
- package/dist/src/components/NS/cards/NSSystemdServiceCard.vue.d.ts +47 -0
- package/dist/src/components/NS/cards/index.d.ts +3 -0
- package/dist/src/components/NS/checkbox/NSCheckbox.vue.d.ts +37 -0
- package/dist/src/components/NS/checkbox/index.d.ts +1 -0
- package/dist/src/components/NS/data-table/NSDataTable.vue.d.ts +98 -0
- package/dist/src/components/NS/data-table/index.d.ts +1 -0
- package/dist/src/components/NS/empty-state/NSEmptyState.vue.d.ts +45 -0
- package/dist/src/components/NS/empty-state/index.d.ts +1 -0
- package/dist/src/components/NS/index.d.ts +35 -0
- package/dist/src/components/NS/inline-notification/NSInlineNotification.vue.d.ts +44 -0
- package/dist/src/components/NS/inline-notification/index.d.ts +1 -0
- package/dist/src/components/NS/lottie-animation/NSLottieAnimation.vue.d.ts +75 -0
- package/dist/src/components/NS/lottie-animation/index.d.ts +1 -0
- package/dist/src/components/NS/modal/NSModal.vue.d.ts +56 -0
- package/dist/src/components/NS/modal/NSModalTrigger.vue.d.ts +64 -0
- package/dist/src/components/NS/modal/index.d.ts +2 -0
- package/dist/src/components/NS/pagination/NSPagination.vue.d.ts +36 -0
- package/dist/src/components/NS/pagination/index.d.ts +1 -0
- package/dist/src/components/NS/progress/NSProgress.vue.d.ts +37 -0
- package/dist/src/components/NS/progress/NSProgressBar.vue.d.ts +39 -0
- package/dist/src/components/NS/progress/index.d.ts +2 -0
- package/dist/src/components/NS/slider/NSByteSlider.vue.d.ts +50 -0
- package/dist/src/components/NS/slider/NSSlider.vue.d.ts +49 -0
- package/dist/src/components/NS/slider/index.d.ts +2 -0
- package/dist/src/components/NS/tag/NSTag.vue.d.ts +41 -0
- package/dist/src/components/NS/tag/index.d.ts +1 -0
- package/dist/src/components/NS/text-input/NSTextInput.vue.d.ts +67 -0
- package/dist/src/components/NS/text-input/index.d.ts +1 -0
- package/dist/src/components/NS/toast-notification/NSToastNotification.vue.d.ts +44 -0
- package/dist/src/components/NS/toast-notification/index.d.ts +1 -0
- package/dist/src/components/NS/toggle/NSToggle.vue.d.ts +51 -0
- package/dist/src/components/NS/toggle/index.d.ts +1 -0
- package/dist/src/components/NS/wizard/NSWizard.vue.d.ts +86 -0
- package/dist/src/components/NS/wizard/index.d.ts +1 -0
- package/dist/src/components/ui/button/Button.vue.d.ts +27 -0
- package/dist/src/components/ui/button/index.d.ts +7 -0
- package/dist/src/components/ui/card/Card.vue.d.ts +21 -0
- package/dist/src/components/ui/card/CardAction.vue.d.ts +21 -0
- package/dist/src/components/ui/card/CardContent.vue.d.ts +21 -0
- package/dist/src/components/ui/card/CardDescription.vue.d.ts +21 -0
- package/dist/src/components/ui/card/CardFooter.vue.d.ts +21 -0
- package/dist/src/components/ui/card/CardHeader.vue.d.ts +21 -0
- package/dist/src/components/ui/card/CardTitle.vue.d.ts +21 -0
- package/dist/src/components/ui/card/index.d.ts +7 -0
- package/dist/src/components/ui/checkbox/NsCheckbox.vue.d.ts +49 -0
- package/dist/src/components/ui/checkbox/index.d.ts +11 -0
- package/dist/src/components/ui/dialog/Dialog.vue.d.ts +28 -0
- package/dist/src/components/ui/dialog/index.d.ts +1 -0
- package/dist/src/components/ui/empty-state/NsEmptyState.vue.d.ts +45 -0
- package/dist/src/components/ui/empty-state/index.d.ts +11 -0
- package/dist/src/components/ui/inline-notification/NsInlineNotification.vue.d.ts +45 -0
- package/dist/src/components/ui/inline-notification/index.d.ts +6 -0
- package/dist/src/components/ui/input/Input.vue.d.ts +12 -0
- package/dist/src/components/ui/input/index.d.ts +1 -0
- package/dist/src/components/ui/input-group/InputGroup.vue.d.ts +21 -0
- package/dist/src/components/ui/input-group/InputGroupAddon.vue.d.ts +25 -0
- package/dist/src/components/ui/input-group/InputGroupButton.vue.d.ts +22 -0
- package/dist/src/components/ui/input-group/InputGroupInput.vue.d.ts +6 -0
- package/dist/src/components/ui/input-group/InputGroupText.vue.d.ts +21 -0
- package/dist/src/components/ui/input-group/InputGroupTextarea.vue.d.ts +6 -0
- package/dist/src/components/ui/input-group/index.d.ts +22 -0
- package/dist/src/components/ui/item/Item.vue.d.ts +27 -0
- package/dist/src/components/ui/item/ItemActions.vue.d.ts +21 -0
- package/dist/src/components/ui/item/ItemContent.vue.d.ts +21 -0
- package/dist/src/components/ui/item/ItemDescription.vue.d.ts +21 -0
- package/dist/src/components/ui/item/ItemFooter.vue.d.ts +21 -0
- package/dist/src/components/ui/item/ItemGroup.vue.d.ts +21 -0
- package/dist/src/components/ui/item/ItemHeader.vue.d.ts +21 -0
- package/dist/src/components/ui/item/ItemMedia.vue.d.ts +23 -0
- package/dist/src/components/ui/item/ItemSeparator.vue.d.ts +7 -0
- package/dist/src/components/ui/item/ItemTitle.vue.d.ts +21 -0
- package/dist/src/components/ui/item/index.d.ts +20 -0
- package/dist/src/components/ui/label/Label.vue.d.ts +22 -0
- package/dist/src/components/ui/label/index.d.ts +1 -0
- package/dist/src/components/ui/scroll-area/ScrollArea.vue.d.ts +22 -0
- package/dist/src/components/ui/scroll-area/ScrollBar.vue.d.ts +9 -0
- package/dist/src/components/ui/scroll-area/index.d.ts +2 -0
- package/dist/src/components/ui/select/Select.vue.d.ts +28 -0
- package/dist/src/components/ui/select/SelectContent.vue.d.ts +32 -0
- package/dist/src/components/ui/select/SelectGroup.vue.d.ts +18 -0
- package/dist/src/components/ui/select/SelectItem.vue.d.ts +23 -0
- package/dist/src/components/ui/select/SelectItemText.vue.d.ts +18 -0
- package/dist/src/components/ui/select/SelectLabel.vue.d.ts +22 -0
- package/dist/src/components/ui/select/SelectScrollDownButton.vue.d.ts +22 -0
- package/dist/src/components/ui/select/SelectScrollUpButton.vue.d.ts +22 -0
- package/dist/src/components/ui/select/SelectSeparator.vue.d.ts +7 -0
- package/dist/src/components/ui/select/SelectTrigger.vue.d.ts +25 -0
- package/dist/src/components/ui/select/SelectValue.vue.d.ts +18 -0
- package/dist/src/components/ui/select/index.d.ts +11 -0
- package/dist/src/components/ui/separator/Separator.vue.d.ts +10 -0
- package/dist/src/components/ui/separator/index.d.ts +1 -0
- package/dist/src/components/ui/sheet/Sheet.vue.d.ts +25 -0
- package/dist/src/components/ui/sheet/SheetClose.vue.d.ts +18 -0
- package/dist/src/components/ui/sheet/SheetContent.vue.d.ts +39 -0
- package/dist/src/components/ui/sheet/SheetDescription.vue.d.ts +22 -0
- package/dist/src/components/ui/sheet/SheetFooter.vue.d.ts +21 -0
- package/dist/src/components/ui/sheet/SheetHeader.vue.d.ts +21 -0
- package/dist/src/components/ui/sheet/SheetOverlay.vue.d.ts +22 -0
- package/dist/src/components/ui/sheet/SheetTitle.vue.d.ts +22 -0
- package/dist/src/components/ui/sheet/SheetTrigger.vue.d.ts +18 -0
- package/dist/src/components/ui/sheet/index.d.ts +8 -0
- package/dist/src/components/ui/sidebar/Sidebar.vue.d.ts +24 -0
- package/dist/src/components/ui/sidebar/SidebarContent.vue.d.ts +21 -0
- package/dist/src/components/ui/sidebar/SidebarFooter.vue.d.ts +21 -0
- package/dist/src/components/ui/sidebar/SidebarGroup.vue.d.ts +21 -0
- package/dist/src/components/ui/sidebar/SidebarGroupAction.vue.d.ts +22 -0
- package/dist/src/components/ui/sidebar/SidebarGroupContent.vue.d.ts +21 -0
- package/dist/src/components/ui/sidebar/SidebarGroupLabel.vue.d.ts +22 -0
- package/dist/src/components/ui/sidebar/SidebarHeader.vue.d.ts +21 -0
- package/dist/src/components/ui/sidebar/SidebarInput.vue.d.ts +21 -0
- package/dist/src/components/ui/sidebar/SidebarInset.vue.d.ts +21 -0
- package/dist/src/components/ui/sidebar/SidebarMenu.vue.d.ts +21 -0
- package/dist/src/components/ui/sidebar/SidebarMenuAction.vue.d.ts +25 -0
- package/dist/src/components/ui/sidebar/SidebarMenuBadge.vue.d.ts +21 -0
- package/dist/src/components/ui/sidebar/SidebarMenuButton.vue.d.ts +27 -0
- package/dist/src/components/ui/sidebar/SidebarMenuButtonChild.vue.d.ts +30 -0
- package/dist/src/components/ui/sidebar/SidebarMenuItem.vue.d.ts +21 -0
- package/dist/src/components/ui/sidebar/SidebarMenuSkeleton.vue.d.ts +7 -0
- package/dist/src/components/ui/sidebar/SidebarMenuSub.vue.d.ts +21 -0
- package/dist/src/components/ui/sidebar/SidebarMenuSubButton.vue.d.ts +27 -0
- package/dist/src/components/ui/sidebar/SidebarMenuSubItem.vue.d.ts +21 -0
- package/dist/src/components/ui/sidebar/SidebarProvider.vue.d.ts +30 -0
- package/dist/src/components/ui/sidebar/SidebarRail.vue.d.ts +21 -0
- package/dist/src/components/ui/sidebar/SidebarSeparator.vue.d.ts +21 -0
- package/dist/src/components/ui/sidebar/SidebarTrigger.vue.d.ts +6 -0
- package/dist/src/components/ui/sidebar/index.d.ts +37 -0
- package/dist/src/components/ui/sidebar/utils.d.ts +56 -0
- package/dist/src/components/ui/skeleton/Skeleton.vue.d.ts +6 -0
- package/dist/src/components/ui/skeleton/index.d.ts +1 -0
- package/dist/src/components/ui/sonner/Sonner.vue.d.ts +3 -0
- package/dist/src/components/ui/sonner/index.d.ts +1 -0
- package/dist/src/components/ui/switch/Switch.vue.d.ts +28 -0
- package/dist/src/components/ui/switch/index.d.ts +1 -0
- package/dist/src/components/ui/table/Table.vue.d.ts +21 -0
- package/dist/src/components/ui/table/TableBody.vue.d.ts +21 -0
- package/dist/src/components/ui/table/TableCaption.vue.d.ts +21 -0
- package/dist/src/components/ui/table/TableCell.vue.d.ts +21 -0
- package/dist/src/components/ui/table/TableEmpty.vue.d.ts +24 -0
- package/dist/src/components/ui/table/TableFooter.vue.d.ts +21 -0
- package/dist/src/components/ui/table/TableHead.vue.d.ts +21 -0
- package/dist/src/components/ui/table/TableHeader.vue.d.ts +21 -0
- package/dist/src/components/ui/table/TableRow.vue.d.ts +21 -0
- package/dist/src/components/ui/table/index.d.ts +9 -0
- package/dist/src/components/ui/table/utils.d.ts +3 -0
- package/dist/src/components/ui/tabs/Tabs.vue.d.ts +28 -0
- package/dist/src/components/ui/tabs/TabsContent.vue.d.ts +22 -0
- package/dist/src/components/ui/tabs/TabsList.vue.d.ts +22 -0
- package/dist/src/components/ui/tabs/TabsTrigger.vue.d.ts +22 -0
- package/dist/src/components/ui/tabs/index.d.ts +4 -0
- package/dist/src/components/ui/tag/NsTag.vue.d.ts +42 -0
- package/dist/src/components/ui/tag/index.d.ts +8 -0
- package/dist/src/components/ui/text-input/NsTextInput.vue.d.ts +79 -0
- package/dist/src/components/ui/text-input/index.d.ts +15 -0
- package/dist/src/components/ui/textarea/Textarea.vue.d.ts +12 -0
- package/dist/src/components/ui/textarea/index.d.ts +1 -0
- package/dist/src/components/ui/toggle/NsToggle.vue.d.ts +54 -0
- package/dist/src/components/ui/toggle/index.d.ts +15 -0
- package/dist/src/components/ui/tooltip/Tooltip.vue.d.ts +24 -0
- package/dist/src/components/ui/tooltip/TooltipContent.vue.d.ts +30 -0
- package/dist/src/components/ui/tooltip/TooltipProvider.vue.d.ts +20 -0
- package/dist/src/components/ui/tooltip/TooltipTrigger.vue.d.ts +18 -0
- package/dist/src/components/ui/tooltip/index.d.ts +4 -0
- package/dist/src/composables/index.d.ts +8 -0
- package/dist/src/composables/useDateTimeService.d.ts +10 -0
- package/dist/src/composables/useFilterService.d.ts +8 -0
- package/dist/src/composables/useIconService.d.ts +153 -0
- package/dist/src/composables/usePageTitleService.d.ts +3 -0
- package/dist/src/composables/useQueryParamService.d.ts +13 -0
- package/dist/src/composables/useStorageService.d.ts +5 -0
- package/dist/src/composables/useTaskService.d.ts +18 -0
- package/dist/src/composables/useUtilService.d.ts +27 -0
- package/dist/src/lib/utils.d.ts +2 -0
- package/dist/src/main.d.ts +0 -0
- package/dist/vite.svg +1 -0
- package/package.json +80 -0
- package/src/App.vue +30 -0
- package/src/components/HelloWorld.vue +41 -0
- package/src/components/NS/CompleteDemo.vue +475 -0
- package/src/components/NS/Demo.vue +191 -0
- package/src/components/NS/cards/NSBackupCard.vue +272 -0
- package/src/components/NS/cards/NSSystemInfoCard.vue +252 -0
- package/src/components/NS/cards/NSSystemdServiceCard.vue +250 -0
- package/src/components/NS/checkbox/NSCheckbox.vue +104 -0
- package/src/components/NS/data-table/NSDataTable.vue +434 -0
- package/src/components/NS/empty-state/NSEmptyState.vue +188 -0
- package/src/components/NS/inline-notification/NSInlineNotification.vue +162 -0
- package/src/components/NS/lottie-animation/NSLottieAnimation.vue +255 -0
- package/src/components/NS/modal/NSModal.vue +193 -0
- package/src/components/NS/modal/NSModalTrigger.vue +109 -0
- package/src/components/NS/pagination/NSPagination.vue +247 -0
- package/src/components/NS/progress/NSProgress.vue +115 -0
- package/src/components/NS/progress/NSProgressBar.vue +137 -0
- package/src/components/NS/slider/NSByteSlider.vue +144 -0
- package/src/components/NS/slider/NSSlider.vue +142 -0
- package/src/components/NS/tag/NSTag.vue +139 -0
- package/src/components/NS/text-input/NSTextInput.vue +242 -0
- package/src/components/NS/toast-notification/NSToastNotification.vue +163 -0
- package/src/components/NS/toggle/NSToggle.vue +156 -0
- package/src/components/NS/wizard/NSWizard.vue +399 -0
- package/src/components/ui/button/Button.vue +29 -0
- package/src/components/ui/card/Card.vue +22 -0
- package/src/components/ui/card/CardAction.vue +17 -0
- package/src/components/ui/card/CardContent.vue +17 -0
- package/src/components/ui/card/CardDescription.vue +17 -0
- package/src/components/ui/card/CardFooter.vue +17 -0
- package/src/components/ui/card/CardHeader.vue +17 -0
- package/src/components/ui/card/CardTitle.vue +17 -0
- package/src/components/ui/checkbox/NsCheckbox.vue +123 -0
- package/src/components/ui/dialog/Dialog.vue +68 -0
- package/src/components/ui/empty-state/NsEmptyState.vue +149 -0
- package/src/components/ui/inline-notification/NsInlineNotification.vue +163 -0
- package/src/components/ui/input/Input.vue +33 -0
- package/src/components/ui/input-group/InputGroup.vue +35 -0
- package/src/components/ui/input-group/InputGroupAddon.vue +36 -0
- package/src/components/ui/input-group/InputGroupButton.vue +21 -0
- package/src/components/ui/input-group/InputGroupInput.vue +19 -0
- package/src/components/ui/input-group/InputGroupText.vue +19 -0
- package/src/components/ui/input-group/InputGroupTextarea.vue +19 -0
- package/src/components/ui/item/Item.vue +27 -0
- package/src/components/ui/item/ItemActions.vue +17 -0
- package/src/components/ui/item/ItemContent.vue +17 -0
- package/src/components/ui/item/ItemDescription.vue +21 -0
- package/src/components/ui/item/ItemFooter.vue +17 -0
- package/src/components/ui/item/ItemGroup.vue +18 -0
- package/src/components/ui/item/ItemHeader.vue +17 -0
- package/src/components/ui/item/ItemMedia.vue +21 -0
- package/src/components/ui/item/ItemSeparator.vue +18 -0
- package/src/components/ui/item/ItemTitle.vue +17 -0
- package/src/components/ui/label/Label.vue +26 -0
- package/src/components/ui/scroll-area/ScrollArea.vue +33 -0
- package/src/components/ui/scroll-area/ScrollBar.vue +32 -0
- package/src/components/ui/select/Select.vue +19 -0
- package/src/components/ui/select/SelectContent.vue +51 -0
- package/src/components/ui/select/SelectGroup.vue +15 -0
- package/src/components/ui/select/SelectItem.vue +44 -0
- package/src/components/ui/select/SelectItemText.vue +15 -0
- package/src/components/ui/select/SelectLabel.vue +17 -0
- package/src/components/ui/select/SelectScrollDownButton.vue +26 -0
- package/src/components/ui/select/SelectScrollUpButton.vue +26 -0
- package/src/components/ui/select/SelectSeparator.vue +19 -0
- package/src/components/ui/select/SelectTrigger.vue +33 -0
- package/src/components/ui/select/SelectValue.vue +15 -0
- package/src/components/ui/separator/Separator.vue +29 -0
- package/src/components/ui/sheet/Sheet.vue +19 -0
- package/src/components/ui/sheet/SheetClose.vue +15 -0
- package/src/components/ui/sheet/SheetContent.vue +62 -0
- package/src/components/ui/sheet/SheetDescription.vue +21 -0
- package/src/components/ui/sheet/SheetFooter.vue +16 -0
- package/src/components/ui/sheet/SheetHeader.vue +15 -0
- package/src/components/ui/sheet/SheetOverlay.vue +21 -0
- package/src/components/ui/sheet/SheetTitle.vue +21 -0
- package/src/components/ui/sheet/SheetTrigger.vue +15 -0
- package/src/components/ui/sidebar/Sidebar.vue +96 -0
- package/src/components/ui/sidebar/SidebarContent.vue +18 -0
- package/src/components/ui/sidebar/SidebarFooter.vue +18 -0
- package/src/components/ui/sidebar/SidebarGroup.vue +18 -0
- package/src/components/ui/sidebar/SidebarGroupAction.vue +27 -0
- package/src/components/ui/sidebar/SidebarGroupContent.vue +18 -0
- package/src/components/ui/sidebar/SidebarGroupLabel.vue +25 -0
- package/src/components/ui/sidebar/SidebarHeader.vue +18 -0
- package/src/components/ui/sidebar/SidebarInput.vue +22 -0
- package/src/components/ui/sidebar/SidebarInset.vue +21 -0
- package/src/components/ui/sidebar/SidebarMenu.vue +18 -0
- package/src/components/ui/sidebar/SidebarMenuAction.vue +35 -0
- package/src/components/ui/sidebar/SidebarMenuBadge.vue +26 -0
- package/src/components/ui/sidebar/SidebarMenuButton.vue +48 -0
- package/src/components/ui/sidebar/SidebarMenuButtonChild.vue +36 -0
- package/src/components/ui/sidebar/SidebarMenuItem.vue +18 -0
- package/src/components/ui/sidebar/SidebarMenuSkeleton.vue +35 -0
- package/src/components/ui/sidebar/SidebarMenuSub.vue +22 -0
- package/src/components/ui/sidebar/SidebarMenuSubButton.vue +36 -0
- package/src/components/ui/sidebar/SidebarMenuSubItem.vue +18 -0
- package/src/components/ui/sidebar/SidebarProvider.vue +82 -0
- package/src/components/ui/sidebar/SidebarRail.vue +33 -0
- package/src/components/ui/sidebar/SidebarSeparator.vue +19 -0
- package/src/components/ui/sidebar/SidebarTrigger.vue +27 -0
- package/src/components/ui/skeleton/Skeleton.vue +17 -0
- package/src/components/ui/sonner/Sonner.vue +42 -0
- package/src/components/ui/switch/Switch.vue +38 -0
- package/src/components/ui/table/Table.vue +16 -0
- package/src/components/ui/table/TableBody.vue +17 -0
- package/src/components/ui/table/TableCaption.vue +17 -0
- package/src/components/ui/table/TableCell.vue +22 -0
- package/src/components/ui/table/TableEmpty.vue +34 -0
- package/src/components/ui/table/TableFooter.vue +17 -0
- package/src/components/ui/table/TableHead.vue +17 -0
- package/src/components/ui/table/TableHeader.vue +17 -0
- package/src/components/ui/table/TableRow.vue +17 -0
- package/src/components/ui/tabs/Tabs.vue +24 -0
- package/src/components/ui/tabs/TabsContent.vue +21 -0
- package/src/components/ui/tabs/TabsList.vue +24 -0
- package/src/components/ui/tabs/TabsTrigger.vue +26 -0
- package/src/components/ui/tag/NsTag.vue +114 -0
- package/src/components/ui/text-input/NsTextInput.vue +269 -0
- package/src/components/ui/textarea/Textarea.vue +28 -0
- package/src/components/ui/toggle/NsToggle.vue +126 -0
- package/src/components/ui/tooltip/Tooltip.vue +19 -0
- package/src/components/ui/tooltip/TooltipContent.vue +34 -0
- package/src/components/ui/tooltip/TooltipProvider.vue +14 -0
- package/src/components/ui/tooltip/TooltipTrigger.vue +15 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import { X, AlertCircle, AlertTriangle, CheckCircle, Info, Loader2 } from 'lucide-vue-next'
|
|
4
|
+
import { cn } from '@/lib/utils'
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
title?: string
|
|
8
|
+
description?: string
|
|
9
|
+
variant?: 'default' | 'destructive' | 'warning' | 'success' | 'info'
|
|
10
|
+
showCloseButton?: boolean
|
|
11
|
+
actionLabel?: string
|
|
12
|
+
closeAriaLabel?: string
|
|
13
|
+
loading?: boolean
|
|
14
|
+
timer?: number
|
|
15
|
+
lowContrast?: boolean
|
|
16
|
+
class?: string
|
|
17
|
+
icon?: object
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
21
|
+
variant: 'info',
|
|
22
|
+
showCloseButton: false,
|
|
23
|
+
closeAriaLabel: 'Dismiss notification',
|
|
24
|
+
loading: false,
|
|
25
|
+
lowContrast: false,
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
const emit = defineEmits<{
|
|
29
|
+
close: []
|
|
30
|
+
action: []
|
|
31
|
+
}>()
|
|
32
|
+
|
|
33
|
+
const NotificationIcon = computed(() => {
|
|
34
|
+
if (props.icon) {
|
|
35
|
+
return props.icon
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
switch (props.variant) {
|
|
39
|
+
case 'destructive':
|
|
40
|
+
return AlertCircle
|
|
41
|
+
case 'warning':
|
|
42
|
+
return AlertTriangle
|
|
43
|
+
case 'success':
|
|
44
|
+
return CheckCircle
|
|
45
|
+
case 'info':
|
|
46
|
+
default:
|
|
47
|
+
return Info
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
const containerClasses = computed(() => {
|
|
52
|
+
const baseClasses = 'relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground'
|
|
53
|
+
|
|
54
|
+
const variantClasses = {
|
|
55
|
+
default: 'bg-background text-foreground',
|
|
56
|
+
destructive: 'border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive',
|
|
57
|
+
warning: 'border-orange-500/50 text-orange-800 dark:border-orange-500 [&>svg]:text-orange-500 dark:text-orange-400',
|
|
58
|
+
success: 'border-green-500/50 text-green-800 dark:border-green-500 [&>svg]:text-green-500 dark:text-green-400',
|
|
59
|
+
info: 'border-blue-500/50 text-blue-800 dark:border-blue-500 [&>svg]:text-blue-500 dark:text-blue-400'
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return cn(baseClasses, variantClasses[props.variant], {
|
|
63
|
+
'opacity-75': props.lowContrast
|
|
64
|
+
}, props.class)
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
const role = computed(() => {
|
|
68
|
+
if (props.variant === 'destructive' || props.variant === 'warning') {
|
|
69
|
+
return 'alert'
|
|
70
|
+
}
|
|
71
|
+
return 'status'
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
const ariaLive = computed(() => {
|
|
75
|
+
if (props.variant === 'destructive') {
|
|
76
|
+
return 'assertive'
|
|
77
|
+
}
|
|
78
|
+
return 'polite'
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
const hasTitle = computed(() => props.title || $slots.title)
|
|
82
|
+
const hasDescription = computed(() => props.description || $slots.description)
|
|
83
|
+
const hasAction = computed(() => props.actionLabel)
|
|
84
|
+
const hasTimer = computed(() => props.timer)
|
|
85
|
+
const hasLoading = computed(() => props.loading)
|
|
86
|
+
|
|
87
|
+
const showCloseButtonVisible = computed(() => props.showCloseButton && !hasLoading.value)
|
|
88
|
+
</script>
|
|
89
|
+
|
|
90
|
+
<template>
|
|
91
|
+
<div
|
|
92
|
+
:class="containerClasses"
|
|
93
|
+
:role="role"
|
|
94
|
+
:aria-live="ariaLive"
|
|
95
|
+
>
|
|
96
|
+
<!-- Icon -->
|
|
97
|
+
<component
|
|
98
|
+
:is="NotificationIcon"
|
|
99
|
+
class="h-4 w-4"
|
|
100
|
+
/>
|
|
101
|
+
|
|
102
|
+
<!-- Loading spinner -->
|
|
103
|
+
<Loader2
|
|
104
|
+
v-if="loading"
|
|
105
|
+
class="h-4 w-4 animate-spin absolute right-12 top-4"
|
|
106
|
+
/>
|
|
107
|
+
|
|
108
|
+
<!-- Timer circle -->
|
|
109
|
+
<div
|
|
110
|
+
v-if="timer"
|
|
111
|
+
class="h-4 w-4 absolute right-12 top-4"
|
|
112
|
+
>
|
|
113
|
+
<!-- You can integrate NSCircleTimer component here -->
|
|
114
|
+
<div class="h-4 w-4 rounded-full border-2 border-current animate-pulse" />
|
|
115
|
+
</div>
|
|
116
|
+
|
|
117
|
+
<!-- Content -->
|
|
118
|
+
<div class="grid gap-1">
|
|
119
|
+
<!-- Title -->
|
|
120
|
+
<h4
|
|
121
|
+
v-if="hasTitle"
|
|
122
|
+
class="text-sm font-medium leading-none"
|
|
123
|
+
>
|
|
124
|
+
<slot name="title">{{ title }}</slot>
|
|
125
|
+
</h4>
|
|
126
|
+
|
|
127
|
+
<!-- Description -->
|
|
128
|
+
<p
|
|
129
|
+
v-if="hasDescription"
|
|
130
|
+
:class="cn('text-sm opacity-90', {
|
|
131
|
+
'mr-12': hasAction || showCloseButtonVisible || hasTimer || hasLoading
|
|
132
|
+
})"
|
|
133
|
+
>
|
|
134
|
+
<slot name="description">{{ description }}</slot>
|
|
135
|
+
</p>
|
|
136
|
+
|
|
137
|
+
<!-- Action button -->
|
|
138
|
+
<button
|
|
139
|
+
v-if="hasAction"
|
|
140
|
+
type="button"
|
|
141
|
+
class="inline-flex items-center text-sm font-medium underline underline-offset-2 hover:no-underline focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 rounded-sm"
|
|
142
|
+
@click="emit('action')"
|
|
143
|
+
>
|
|
144
|
+
{{ actionLabel }}
|
|
145
|
+
</button>
|
|
146
|
+
</div>
|
|
147
|
+
|
|
148
|
+
<!-- Close button -->
|
|
149
|
+
<button
|
|
150
|
+
v-if="showCloseButtonVisible"
|
|
151
|
+
type="button"
|
|
152
|
+
:aria-label="closeAriaLabel"
|
|
153
|
+
class="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none"
|
|
154
|
+
@click="emit('close')"
|
|
155
|
+
>
|
|
156
|
+
<X class="h-4 w-4" />
|
|
157
|
+
</button>
|
|
158
|
+
|
|
159
|
+
<!-- Extra content -->
|
|
160
|
+
<slot name="extra" />
|
|
161
|
+
</div>
|
|
162
|
+
</template>
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, ref, watch } from 'vue'
|
|
3
|
+
import LottieAnimation from 'lottie-web-vue'
|
|
4
|
+
import { cn } from '@/lib/utils'
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
path?: string // Path to Lottie JSON file
|
|
8
|
+
animationData?: any // Direct animation data
|
|
9
|
+
width?: number | string
|
|
10
|
+
height?: number | string
|
|
11
|
+
loop?: boolean
|
|
12
|
+
autoplay?: boolean
|
|
13
|
+
speed?: number
|
|
14
|
+
playOnHover?: boolean
|
|
15
|
+
stopOnHoverOut?: boolean
|
|
16
|
+
direction?: number
|
|
17
|
+
renderer?: 'svg' | 'canvas' | 'html'
|
|
18
|
+
className?: string
|
|
19
|
+
containerClassName?: string
|
|
20
|
+
lazy?: boolean
|
|
21
|
+
placeholder?: string
|
|
22
|
+
responsive?: boolean
|
|
23
|
+
preserveAspectRatio?: string
|
|
24
|
+
title?: string
|
|
25
|
+
ariaLabel?: string
|
|
26
|
+
role?: string
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
30
|
+
width: 200,
|
|
31
|
+
height: 200,
|
|
32
|
+
loop: false,
|
|
33
|
+
autoplay: true,
|
|
34
|
+
speed: 1,
|
|
35
|
+
playOnHover: false,
|
|
36
|
+
stopOnHoverOut: false,
|
|
37
|
+
direction: 1,
|
|
38
|
+
renderer: 'svg',
|
|
39
|
+
lazy: false,
|
|
40
|
+
responsive: true,
|
|
41
|
+
preserveAspectRatio: 'xMidYMid meet',
|
|
42
|
+
role: 'img',
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
const emit = defineEmits<{
|
|
46
|
+
load: []
|
|
47
|
+
ready: []
|
|
48
|
+
play: []
|
|
49
|
+
pause: []
|
|
50
|
+
stop: []
|
|
51
|
+
complete: []
|
|
52
|
+
loopComplete: []
|
|
53
|
+
enterFrame: [event: any]
|
|
54
|
+
error: [error: Error]
|
|
55
|
+
mouseOver: []
|
|
56
|
+
mouseOut: []
|
|
57
|
+
}>()
|
|
58
|
+
|
|
59
|
+
// State
|
|
60
|
+
const isLoading = ref(false)
|
|
61
|
+
const isError = ref(false)
|
|
62
|
+
const isLoaded = ref(false)
|
|
63
|
+
const isPlaying = ref(props.autoplay)
|
|
64
|
+
const error = ref<string | null>(null)
|
|
65
|
+
const lottieRef = ref<InstanceType<typeof LottieAnimation>>()
|
|
66
|
+
|
|
67
|
+
// Computed properties
|
|
68
|
+
const lottieOptions = computed(() => ({
|
|
69
|
+
path: props.path,
|
|
70
|
+
animationData: props.animationData,
|
|
71
|
+
loop: props.loop,
|
|
72
|
+
autoplay: props.autoplay && !props.playOnHover,
|
|
73
|
+
renderer: props.renderer,
|
|
74
|
+
rendererSettings: {
|
|
75
|
+
preserveAspectRatio: props.preserveAspectRatio,
|
|
76
|
+
},
|
|
77
|
+
}))
|
|
78
|
+
|
|
79
|
+
const containerStyle = computed(() => ({
|
|
80
|
+
width: props.width ? (typeof props.width === 'number' ? `${props.width}px` : props.width) : 'auto',
|
|
81
|
+
height: props.height ? (typeof props.height === 'number' ? `${props.height}px` : props.height) : 'auto',
|
|
82
|
+
maxWidth: props.responsive ? '100%' : undefined,
|
|
83
|
+
}))
|
|
84
|
+
|
|
85
|
+
const containerClasses = computed(() => {
|
|
86
|
+
return cn(
|
|
87
|
+
'relative inline-block',
|
|
88
|
+
{
|
|
89
|
+
'opacity-50': isLoading.value,
|
|
90
|
+
'opacity-100': !isLoading.value,
|
|
91
|
+
},
|
|
92
|
+
props.containerClassName
|
|
93
|
+
)
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
const playerClasses = computed(() => {
|
|
97
|
+
return cn('w-full h-full', props.className)
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
// Player controls
|
|
101
|
+
const play = () => {
|
|
102
|
+
if (lottieRef.value && !isPlaying.value) {
|
|
103
|
+
lottieRef.value.play()
|
|
104
|
+
isPlaying.value = true
|
|
105
|
+
emit('play')
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const pause = () => {
|
|
110
|
+
if (lottieRef.value && isPlaying.value) {
|
|
111
|
+
lottieRef.value.pause()
|
|
112
|
+
isPlaying.value = false
|
|
113
|
+
emit('pause')
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const stop = () => {
|
|
118
|
+
if (lottieRef.value) {
|
|
119
|
+
lottieRef.value.stop()
|
|
120
|
+
isPlaying.value = false
|
|
121
|
+
emit('stop')
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const goToAndStop = (frame?: number) => {
|
|
126
|
+
if (lottieRef.value) {
|
|
127
|
+
lottieRef.value.goToAndStop(frame || 0, true)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const setDirection = (direction: number) => {
|
|
132
|
+
if (lottieRef.value) {
|
|
133
|
+
lottieRef.value.setDirection(direction)
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const setSpeed = (speed: number) => {
|
|
138
|
+
if (lottieRef.value) {
|
|
139
|
+
lottieRef.value.setSpeed(speed)
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Event handlers
|
|
144
|
+
const handleDataReady = () => {
|
|
145
|
+
isLoaded.value = true
|
|
146
|
+
isLoading.value = false
|
|
147
|
+
emit('ready')
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const handleDataFailed = () => {
|
|
151
|
+
isLoading.value = false
|
|
152
|
+
isError.value = true
|
|
153
|
+
error.value = 'Failed to load animation'
|
|
154
|
+
emit('error', new Error('Animation data failed to load'))
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const handleDOMLoaded = () => {
|
|
158
|
+
emit('load')
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const handleComplete = () => {
|
|
162
|
+
emit('complete')
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const handleLoopComplete = () => {
|
|
166
|
+
emit('loopComplete')
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const handleEnterFrame = (event: any) => {
|
|
170
|
+
emit('enterFrame', event)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Hover handlers
|
|
174
|
+
const handleMouseOver = () => {
|
|
175
|
+
if (props.playOnHover && !isPlaying.value) {
|
|
176
|
+
play()
|
|
177
|
+
}
|
|
178
|
+
emit('mouseOver')
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const handleMouseOut = () => {
|
|
182
|
+
if (props.stopOnHoverOut && isPlaying.value) {
|
|
183
|
+
pause()
|
|
184
|
+
}
|
|
185
|
+
emit('mouseOut')
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Watch for prop changes
|
|
189
|
+
watch([() => props.path, () => props.animationData], () => {
|
|
190
|
+
isLoading.value = true
|
|
191
|
+
isLoaded.value = false
|
|
192
|
+
isError.value = false
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
watch(() => props.speed, (newSpeed) => {
|
|
196
|
+
setSpeed(newSpeed)
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
watch(() => props.direction, (newDirection) => {
|
|
200
|
+
setDirection(newDirection)
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
// Expose methods
|
|
204
|
+
defineExpose({
|
|
205
|
+
play,
|
|
206
|
+
pause,
|
|
207
|
+
stop,
|
|
208
|
+
goToAndStop,
|
|
209
|
+
setDirection,
|
|
210
|
+
setSpeed,
|
|
211
|
+
isLoaded,
|
|
212
|
+
isPlaying,
|
|
213
|
+
isLoading,
|
|
214
|
+
isError,
|
|
215
|
+
})
|
|
216
|
+
</script>
|
|
217
|
+
|
|
218
|
+
<template>
|
|
219
|
+
<div
|
|
220
|
+
:class="containerClasses"
|
|
221
|
+
:style="containerStyle"
|
|
222
|
+
:title="title"
|
|
223
|
+
:aria-label="ariaLabel"
|
|
224
|
+
:role="role"
|
|
225
|
+
@mouseover="handleMouseOver"
|
|
226
|
+
@mouseout="handleMouseOut"
|
|
227
|
+
>
|
|
228
|
+
<!-- Loading placeholder -->
|
|
229
|
+
<div v-if="isLoading && !isLoaded" class="flex items-center justify-center h-full">
|
|
230
|
+
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-primary"></div>
|
|
231
|
+
<span v-if="placeholder" class="ml-2 text-sm text-muted-foreground">{{ placeholder }}</span>
|
|
232
|
+
</div>
|
|
233
|
+
|
|
234
|
+
<!-- Error state -->
|
|
235
|
+
<div v-else-if="isError" class="flex items-center justify-center h-full text-destructive">
|
|
236
|
+
<div class="text-sm">{{ error || 'Failed to load animation' }}</div>
|
|
237
|
+
</div>
|
|
238
|
+
|
|
239
|
+
<!-- Lottie Animation -->
|
|
240
|
+
<LottieAnimation
|
|
241
|
+
v-if="path || animationData"
|
|
242
|
+
ref="lottieRef"
|
|
243
|
+
:options="lottieOptions"
|
|
244
|
+
:width="width"
|
|
245
|
+
:height="height"
|
|
246
|
+
:class="playerClasses"
|
|
247
|
+
@onDataReady="handleDataReady"
|
|
248
|
+
@onDataFailed="handleDataFailed"
|
|
249
|
+
@onDOMLoaded="handleDOMLoaded"
|
|
250
|
+
@onComplete="handleComplete"
|
|
251
|
+
@onLoopComplete="handleLoopComplete"
|
|
252
|
+
@onEnterFrame="handleEnterFrame"
|
|
253
|
+
/>
|
|
254
|
+
</div>
|
|
255
|
+
</template>
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, watch, nextTick } from 'vue'
|
|
3
|
+
import { X, Maximize2, Minimize2 } from 'lucide-vue-next'
|
|
4
|
+
import {
|
|
5
|
+
DialogClose,
|
|
6
|
+
DialogContent,
|
|
7
|
+
DialogDescription,
|
|
8
|
+
DialogOverlay,
|
|
9
|
+
DialogPortal,
|
|
10
|
+
DialogTitle,
|
|
11
|
+
DialogTrigger
|
|
12
|
+
} from 'radix-vue'
|
|
13
|
+
import { cn } from '@/lib/utils'
|
|
14
|
+
|
|
15
|
+
interface Props {
|
|
16
|
+
open?: boolean
|
|
17
|
+
modelValue?: boolean
|
|
18
|
+
title?: string
|
|
19
|
+
description?: string
|
|
20
|
+
showCloseButton?: boolean
|
|
21
|
+
closeOnOverlayClick?: boolean
|
|
22
|
+
closeOnEscape?: boolean
|
|
23
|
+
size?: 'sm' | 'default' | 'lg' | 'xl' | 'full'
|
|
24
|
+
maxWidth?: string
|
|
25
|
+
maxHeight?: string
|
|
26
|
+
persistent?: boolean
|
|
27
|
+
fullscreen?: boolean
|
|
28
|
+
class?: string
|
|
29
|
+
contentClass?: string
|
|
30
|
+
overlayClass?: string
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
34
|
+
showCloseButton: true,
|
|
35
|
+
closeOnOverlayClick: true,
|
|
36
|
+
closeOnEscape: true,
|
|
37
|
+
size: 'default',
|
|
38
|
+
persistent: false,
|
|
39
|
+
fullscreen: false,
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
const emit = defineEmits<{
|
|
43
|
+
'update:modelValue': [value: boolean]
|
|
44
|
+
'update:open': [value: boolean]
|
|
45
|
+
'open': []
|
|
46
|
+
'close': []
|
|
47
|
+
}>()
|
|
48
|
+
|
|
49
|
+
const isOpen = computed({
|
|
50
|
+
get: () => props.modelValue ?? props.open ?? false,
|
|
51
|
+
set: (value: boolean) => {
|
|
52
|
+
emit('update:modelValue', value)
|
|
53
|
+
emit('update:open', value)
|
|
54
|
+
if (value) {
|
|
55
|
+
emit('open')
|
|
56
|
+
} else {
|
|
57
|
+
emit('close')
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
const isFullscreen = computed(() => props.fullscreen)
|
|
63
|
+
|
|
64
|
+
const contentClasses = computed(() => {
|
|
65
|
+
const baseClasses = 'relative z-50 grid w-full gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg md:w-full'
|
|
66
|
+
|
|
67
|
+
const sizeClasses = {
|
|
68
|
+
sm: 'max-w-md',
|
|
69
|
+
default: 'max-w-lg',
|
|
70
|
+
lg: 'max-w-2xl',
|
|
71
|
+
xl: 'max-w-4xl',
|
|
72
|
+
full: 'max-w-screen-2xl'
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const fullscreenClasses = isFullscreen.value
|
|
76
|
+
? 'w-screen h-screen max-w-none rounded-none border-none p-0'
|
|
77
|
+
: ''
|
|
78
|
+
|
|
79
|
+
return cn(
|
|
80
|
+
baseClasses,
|
|
81
|
+
sizeClasses[props.size],
|
|
82
|
+
fullscreenClasses,
|
|
83
|
+
props.contentClass
|
|
84
|
+
)
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
const overlayClasses = computed(() => {
|
|
88
|
+
const baseClasses = 'fixed inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0'
|
|
89
|
+
|
|
90
|
+
return cn(baseClasses, props.overlayClass)
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
const sizeStyle = computed(() => {
|
|
94
|
+
if (props.maxWidth || props.maxHeight) {
|
|
95
|
+
return {
|
|
96
|
+
maxWidth: props.maxWidth,
|
|
97
|
+
maxHeight: props.maxHeight
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return {}
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
const handleClose = () => {
|
|
104
|
+
if (!props.persistent) {
|
|
105
|
+
isOpen.value = false
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
</script>
|
|
109
|
+
|
|
110
|
+
<template>
|
|
111
|
+
<DialogPortal>
|
|
112
|
+
<DialogOverlay
|
|
113
|
+
:class="overlayClasses"
|
|
114
|
+
@click="closeOnOverlayClick ? handleClose() : undefined"
|
|
115
|
+
/>
|
|
116
|
+
<DialogContent
|
|
117
|
+
:class="contentClasses"
|
|
118
|
+
:style="sizeStyle"
|
|
119
|
+
:aria-describedby="description ? undefined : undefined"
|
|
120
|
+
>
|
|
121
|
+
<!-- Header -->
|
|
122
|
+
<div
|
|
123
|
+
v-if="title || $slots.header || showCloseButton"
|
|
124
|
+
:class="cn(
|
|
125
|
+
'flex items-center justify-between',
|
|
126
|
+
isFullscreen ? 'border-b p-6' : 'mb-4'
|
|
127
|
+
)"
|
|
128
|
+
>
|
|
129
|
+
<!-- Title and description -->
|
|
130
|
+
<div class="space-y-1">
|
|
131
|
+
<DialogTitle
|
|
132
|
+
v-if="title || $slots.title"
|
|
133
|
+
class="text-lg font-semibold leading-none tracking-tight"
|
|
134
|
+
>
|
|
135
|
+
<slot name="title">{{ title }}</slot>
|
|
136
|
+
</DialogTitle>
|
|
137
|
+
<DialogDescription
|
|
138
|
+
v-if="description || $slots.description"
|
|
139
|
+
class="text-sm text-muted-foreground"
|
|
140
|
+
>
|
|
141
|
+
<slot name="description">{{ description }}</slot>
|
|
142
|
+
</DialogDescription>
|
|
143
|
+
</div>
|
|
144
|
+
|
|
145
|
+
<!-- Close button -->
|
|
146
|
+
<div class="flex items-center gap-2">
|
|
147
|
+
<!-- Fullscreen toggle -->
|
|
148
|
+
<button
|
|
149
|
+
v-if="!fullscreen"
|
|
150
|
+
type="button"
|
|
151
|
+
class="rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none"
|
|
152
|
+
:title="isFullscreen ? 'Exit fullscreen' : 'Enter fullscreen'"
|
|
153
|
+
@click="isFullscreen = !isFullscreen"
|
|
154
|
+
>
|
|
155
|
+
<Maximize2 v-if="!isFullscreen" class="h-4 w-4" />
|
|
156
|
+
<Minimize2 v-else class="h-4 w-4" />
|
|
157
|
+
</button>
|
|
158
|
+
|
|
159
|
+
<!-- Close button -->
|
|
160
|
+
<DialogClose
|
|
161
|
+
v-if="showCloseButton && !persistent"
|
|
162
|
+
class="rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none"
|
|
163
|
+
>
|
|
164
|
+
<X class="h-4 w-4" />
|
|
165
|
+
<span class="sr-only">Close</span>
|
|
166
|
+
</DialogClose>
|
|
167
|
+
</div>
|
|
168
|
+
</div>
|
|
169
|
+
|
|
170
|
+
<!-- Custom header slot -->
|
|
171
|
+
<slot name="header" />
|
|
172
|
+
|
|
173
|
+
<!-- Content -->
|
|
174
|
+
<div :class="cn('flex-1', isFullscreen ? 'p-6' : '')">
|
|
175
|
+
<slot />
|
|
176
|
+
</div>
|
|
177
|
+
|
|
178
|
+
<!-- Custom footer slot -->
|
|
179
|
+
<slot name="footer" />
|
|
180
|
+
|
|
181
|
+
<!-- Default actions -->
|
|
182
|
+
<div
|
|
183
|
+
v-if="$slots.actions"
|
|
184
|
+
:class="cn(
|
|
185
|
+
'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',
|
|
186
|
+
isFullscreen ? 'border-t p-6 mt-auto' : 'mt-6'
|
|
187
|
+
)"
|
|
188
|
+
>
|
|
189
|
+
<slot name="actions" />
|
|
190
|
+
</div>
|
|
191
|
+
</DialogContent>
|
|
192
|
+
</DialogPortal>
|
|
193
|
+
</template>
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, computed } from 'vue'
|
|
3
|
+
import NSModal from './NSModal.vue'
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
modelValue?: boolean
|
|
7
|
+
open?: boolean
|
|
8
|
+
title?: string
|
|
9
|
+
description?: string
|
|
10
|
+
showCloseButton?: boolean
|
|
11
|
+
closeOnOverlayClick?: boolean
|
|
12
|
+
closeOnEscape?: boolean
|
|
13
|
+
size?: 'sm' | 'default' | 'lg' | 'xl' | 'full'
|
|
14
|
+
maxWidth?: string
|
|
15
|
+
maxHeight?: string
|
|
16
|
+
persistent?: boolean
|
|
17
|
+
fullscreen?: boolean
|
|
18
|
+
class?: string
|
|
19
|
+
contentClass?: string
|
|
20
|
+
overlayClass?: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
24
|
+
showCloseButton: true,
|
|
25
|
+
closeOnOverlayClick: true,
|
|
26
|
+
closeOnEscape: true,
|
|
27
|
+
size: 'default',
|
|
28
|
+
persistent: false,
|
|
29
|
+
fullscreen: false,
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
const emit = defineEmits<{
|
|
33
|
+
'update:modelValue': [value: boolean]
|
|
34
|
+
'update:open': [value: boolean]
|
|
35
|
+
'open': []
|
|
36
|
+
'close': []
|
|
37
|
+
}>()
|
|
38
|
+
|
|
39
|
+
const isOpen = computed({
|
|
40
|
+
get: () => props.modelValue ?? props.open ?? false,
|
|
41
|
+
set: (value: boolean) => {
|
|
42
|
+
emit('update:modelValue', value)
|
|
43
|
+
emit('update:open', value)
|
|
44
|
+
if (value) {
|
|
45
|
+
emit('open')
|
|
46
|
+
} else {
|
|
47
|
+
emit('close')
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
const triggerRef = ref<HTMLElement>()
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
<template>
|
|
56
|
+
<!-- Use DialogTrigger to wrap trigger content -->
|
|
57
|
+
<slot name="trigger" :open="isOpen" :toggle="() => isOpen = !isOpen">
|
|
58
|
+
<button
|
|
59
|
+
v-if="!$slots.trigger"
|
|
60
|
+
ref="triggerRef"
|
|
61
|
+
@click="isOpen = !isOpen"
|
|
62
|
+
class="inline-flex items-center justify-center rounded-md text-sm font-medium 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 bg-primary text-primary-foreground hover:bg-primary/90"
|
|
63
|
+
>
|
|
64
|
+
Open Modal
|
|
65
|
+
</button>
|
|
66
|
+
</slot>
|
|
67
|
+
|
|
68
|
+
<!-- Modal -->
|
|
69
|
+
<NSModal
|
|
70
|
+
v-model="isOpen"
|
|
71
|
+
:title="title"
|
|
72
|
+
:description="description"
|
|
73
|
+
:show-close-button="showCloseButton"
|
|
74
|
+
:close-on-overlay-click="closeOnOverlayClick"
|
|
75
|
+
:close-on-escape="closeOnEscape"
|
|
76
|
+
:size="size"
|
|
77
|
+
:max-width="maxWidth"
|
|
78
|
+
:max-height="maxHeight"
|
|
79
|
+
:persistent="persistent"
|
|
80
|
+
:fullscreen="fullscreen"
|
|
81
|
+
:class="class"
|
|
82
|
+
:content-class="contentClass"
|
|
83
|
+
:overlay-class="overlayClass"
|
|
84
|
+
@open="emit('open')"
|
|
85
|
+
@close="emit('close')"
|
|
86
|
+
>
|
|
87
|
+
<slot />
|
|
88
|
+
|
|
89
|
+
<template #title>
|
|
90
|
+
<slot name="title" />
|
|
91
|
+
</template>
|
|
92
|
+
|
|
93
|
+
<template #description>
|
|
94
|
+
<slot name="description" />
|
|
95
|
+
</template>
|
|
96
|
+
|
|
97
|
+
<template #header>
|
|
98
|
+
<slot name="header" />
|
|
99
|
+
</template>
|
|
100
|
+
|
|
101
|
+
<template #actions>
|
|
102
|
+
<slot name="actions" />
|
|
103
|
+
</template>
|
|
104
|
+
|
|
105
|
+
<template #footer>
|
|
106
|
+
<slot name="footer" />
|
|
107
|
+
</template>
|
|
108
|
+
</NSModal>
|
|
109
|
+
</template>
|