@sakoa/ui 0.1.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 +171 -0
- package/dist/App.d.ts +2 -0
- package/dist/cli/index.js +9243 -0
- package/dist/components/DemoSection.d.ts +30 -0
- package/dist/components/SApiKeyboard.d.ts +22 -0
- package/dist/components/SApiSection.d.ts +21 -0
- package/dist/components/SApiTable.d.ts +46 -0
- package/dist/components/STableOfContents.d.ts +2 -0
- package/dist/components/ui/SAlert.d.ts +76 -0
- package/dist/components/ui/SBadge.d.ts +56 -0
- package/dist/components/ui/SButton.d.ts +67 -0
- package/dist/components/ui/SCheckbox.d.ts +64 -0
- package/dist/components/ui/SChip.d.ts +43 -0
- package/dist/components/ui/SDatePicker.d.ts +77 -0
- package/dist/components/ui/SGlassButton.d.ts +70 -0
- package/dist/components/ui/SIcon.d.ts +29 -0
- package/dist/components/ui/SInput.d.ts +129 -0
- package/dist/components/ui/SKbd.d.ts +24 -0
- package/dist/components/ui/SKbdShortcut.d.ts +14 -0
- package/dist/components/ui/SSelect.d.ts +148 -0
- package/dist/components/ui/SSkeleton.d.ts +37 -0
- package/dist/components/ui/SSwitch.d.ts +61 -0
- package/dist/components/ui/STooltip.d.ts +82 -0
- package/dist/components/ui/accordion/SAccordionContent.d.ts +23 -0
- package/dist/components/ui/accordion/SAccordionItem.d.ts +70 -0
- package/dist/components/ui/accordion/SAccordionTrigger.d.ts +37 -0
- package/dist/components/ui/accordion/index.d.ts +4 -0
- package/dist/components/ui/avatar/SAvatar.d.ts +36 -0
- package/dist/components/ui/avatar/SAvatarFallback.d.ts +26 -0
- package/dist/components/ui/avatar/SAvatarGroup.d.ts +30 -0
- package/dist/components/ui/avatar/SAvatarImage.d.ts +23 -0
- package/dist/components/ui/avatar/index.d.ts +4 -0
- package/dist/components/ui/breadcrumb/SBreadcrumb.d.ts +22 -0
- package/dist/components/ui/breadcrumb/SBreadcrumbEllipsis.d.ts +17 -0
- package/dist/components/ui/breadcrumb/SBreadcrumbItem.d.ts +17 -0
- package/dist/components/ui/breadcrumb/SBreadcrumbLink.d.ts +26 -0
- package/dist/components/ui/breadcrumb/SBreadcrumbList.d.ts +17 -0
- package/dist/components/ui/breadcrumb/SBreadcrumbPage.d.ts +17 -0
- package/dist/components/ui/breadcrumb/SBreadcrumbSeparator.d.ts +17 -0
- package/dist/components/ui/breadcrumb/index.d.ts +7 -0
- package/dist/components/ui/card/SCard.d.ts +103 -0
- package/dist/components/ui/card/SCardActions.d.ts +44 -0
- package/dist/components/ui/card/SCardContent.d.ts +35 -0
- package/dist/components/ui/card/SCardFooter.d.ts +38 -0
- package/dist/components/ui/card/SCardHeader.d.ts +53 -0
- package/dist/components/ui/card/SCardMedia.d.ts +83 -0
- package/dist/components/ui/card/SGlassCard.d.ts +103 -0
- package/dist/components/ui/card/SMorphingCardContent.d.ts +18 -0
- package/dist/components/ui/card/index.d.ts +24 -0
- package/dist/components/ui/carousel/SCarousel.d.ts +166 -0
- package/dist/components/ui/carousel/index.d.ts +2 -0
- package/dist/components/ui/color-picker/SColorPickerAlphaSlider.d.ts +4 -0
- package/dist/components/ui/color-picker/SColorPickerCopy.d.ts +19 -0
- package/dist/components/ui/color-picker/SColorPickerEyeDropper.d.ts +17 -0
- package/dist/components/ui/color-picker/SColorPickerHueSlider.d.ts +4 -0
- package/dist/components/ui/color-picker/SColorPickerInputs.d.ts +2 -0
- package/dist/components/ui/color-picker/SColorPickerPresets.d.ts +9 -0
- package/dist/components/ui/color-picker/SColorPickerPreview.d.ts +2 -0
- package/dist/components/ui/color-picker/SColorPickerRecent.d.ts +7 -0
- package/dist/components/ui/color-picker/SColorPickerSpectrum.d.ts +4 -0
- package/dist/components/ui/color-picker/index.d.ts +11 -0
- package/dist/components/ui/drawer/index.d.ts +11 -0
- package/dist/components/ui/dropdown/SDropdownDivider.d.ts +8 -0
- package/dist/components/ui/dropdown/SDropdownGroup.d.ts +25 -0
- package/dist/components/ui/dropdown/SDropdownItem.d.ts +56 -0
- package/dist/components/ui/dropdown/index.d.ts +4 -0
- package/dist/components/ui/form/SForm.d.ts +38 -0
- package/dist/components/ui/form/SFormField.d.ts +31 -0
- package/dist/components/ui/form/index.d.ts +5 -0
- package/dist/components/ui/modal/index.d.ts +19 -0
- package/dist/components/ui/option/SOption.d.ts +32 -0
- package/dist/components/ui/option/SOptionGroup.d.ts +28 -0
- package/dist/components/ui/option/index.d.ts +2 -0
- package/dist/components/ui/otp/SOTP.d.ts +122 -0
- package/dist/components/ui/otp/SOTPGroup.d.ts +23 -0
- package/dist/components/ui/otp/SOTPSeparator.d.ts +17 -0
- package/dist/components/ui/otp/SOTPSlot.d.ts +49 -0
- package/dist/components/ui/otp/index.d.ts +7 -0
- package/dist/components/ui/otp/types.d.ts +26 -0
- package/dist/components/ui/otp/useOTPContext.d.ts +42 -0
- package/dist/components/ui/pagination/SPagination.d.ts +151 -0
- package/dist/components/ui/pagination/index.d.ts +2 -0
- package/dist/components/ui/progress/SProgress.d.ts +62 -0
- package/dist/components/ui/progress/SProgressRange.d.ts +91 -0
- package/dist/components/ui/progress/index.d.ts +4 -0
- package/dist/components/ui/radio/SRadio.d.ts +58 -0
- package/dist/components/ui/radio/SRadioGroup.d.ts +52 -0
- package/dist/components/ui/radio/index.d.ts +2 -0
- package/dist/components/ui/stepper/SStepper.d.ts +83 -0
- package/dist/components/ui/stepper/SStepperContent.d.ts +24 -0
- package/dist/components/ui/stepper/SStepperDescription.d.ts +20 -0
- package/dist/components/ui/stepper/SStepperIndicator.d.ts +37 -0
- package/dist/components/ui/stepper/SStepperItem.d.ts +37 -0
- package/dist/components/ui/stepper/SStepperSeparator.d.ts +5 -0
- package/dist/components/ui/stepper/SStepperTitle.d.ts +20 -0
- package/dist/components/ui/stepper/SStepperTrigger.d.ts +22 -0
- package/dist/components/ui/stepper/index.d.ts +11 -0
- package/dist/components/ui/table/STableBody.d.ts +27 -0
- package/dist/components/ui/table/STableCell.d.ts +55 -0
- package/dist/components/ui/table/STableColumn.d.ts +87 -0
- package/dist/components/ui/table/STableEmpty.d.ts +54 -0
- package/dist/components/ui/table/STableHeader.d.ts +25 -0
- package/dist/components/ui/table/STableRow.d.ts +38 -0
- package/dist/components/ui/table/STableSkeleton.d.ts +29 -0
- package/dist/components/ui/table/index.d.ts +98 -0
- package/dist/components/ui/table/useDataTable.d.ts +80 -0
- package/dist/components/ui/tabs/STabPane.d.ts +31 -0
- package/dist/components/ui/tabs/STabsContent.d.ts +21 -0
- package/dist/components/ui/tabs/STabsIndicator.d.ts +9 -0
- package/dist/components/ui/tabs/STabsTrigger.d.ts +28 -0
- package/dist/components/ui/tabs/index.d.ts +6 -0
- package/dist/components/ui/toast/SToast.d.ts +49 -0
- package/dist/components/ui/toast/SToastContainer.d.ts +21 -0
- package/dist/components/ui/toast/index.d.ts +2 -0
- package/dist/composables/useAsync.d.ts +134 -0
- package/dist/composables/useClickOutside.d.ts +69 -0
- package/dist/composables/useClipboard.d.ts +46 -0
- package/dist/composables/useDebounce.d.ts +150 -0
- package/dist/composables/useDialog.d.ts +118 -0
- package/dist/composables/useForm.d.ts +204 -0
- package/dist/composables/useHotkey.d.ts +128 -0
- package/dist/composables/useIntersectionObserver.d.ts +156 -0
- package/dist/composables/useLocalStorage.d.ts +120 -0
- package/dist/composables/useMediaQuery.d.ts +115 -0
- package/dist/composables/useTheme.d.ts +8 -0
- package/dist/composables/useToast.d.ts +1619 -0
- package/dist/index.d.ts +71 -0
- package/dist/layouts/UILayout.d.ts +2 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/main.d.ts +0 -0
- package/dist/router.d.ts +2 -0
- package/dist/saka-ui.css +1 -0
- package/dist/saka-ui.js +18513 -0
- package/dist/saka-ui.umd.cjs +38 -0
- package/dist/views/docs/CustomizationView.d.ts +2 -0
- package/dist/views/docs/FormValidationView.d.ts +2 -0
- package/dist/views/docs/StylingGuideView.d.ts +2 -0
- package/dist/views/docs/UseAsyncView.d.ts +2 -0
- package/dist/views/docs/UseClickOutsideView.d.ts +124 -0
- package/dist/views/docs/UseClipboardView.d.ts +4 -0
- package/dist/views/docs/UseDebounceView.d.ts +2 -0
- package/dist/views/docs/UseHotkeyView.d.ts +205 -0
- package/dist/views/docs/UseIntersectionObserverView.d.ts +5 -0
- package/dist/views/docs/UseLocalStorageView.d.ts +2 -0
- package/dist/views/docs/UseMediaQueryView.d.ts +2 -0
- package/dist/views/docs/UseThemeView.d.ts +2 -0
- package/dist/views/examples/AuthFormView.d.ts +2 -0
- package/dist/views/examples/CreditCardFormView.d.ts +6 -0
- package/dist/views/examples/FormFieldExampleView.d.ts +2 -0
- package/dist/views/examples/ProjectFormView.d.ts +2 -0
- package/dist/views/ui/AccordionView.d.ts +2 -0
- package/dist/views/ui/AlertView.d.ts +2 -0
- package/dist/views/ui/AvatarView.d.ts +2 -0
- package/dist/views/ui/BadgeView.d.ts +2 -0
- package/dist/views/ui/BreadcrumbView.d.ts +2 -0
- package/dist/views/ui/ButtonView.d.ts +2 -0
- package/dist/views/ui/CardView.d.ts +2 -0
- package/dist/views/ui/CarouselView.d.ts +274 -0
- package/dist/views/ui/CheckboxView.d.ts +2 -0
- package/dist/views/ui/ChipView.d.ts +2 -0
- package/dist/views/ui/ColorPickerView.d.ts +2 -0
- package/dist/views/ui/DatePickerView.d.ts +2 -0
- package/dist/views/ui/DialogView.d.ts +2 -0
- package/dist/views/ui/DrawerView.d.ts +2 -0
- package/dist/views/ui/DropdownView.d.ts +2 -0
- package/dist/views/ui/GlassButtonView.d.ts +2 -0
- package/dist/views/ui/GlassCardView.d.ts +2 -0
- package/dist/views/ui/HomeView.d.ts +2 -0
- package/dist/views/ui/IconsView.d.ts +2 -0
- package/dist/views/ui/InputView.d.ts +2 -0
- package/dist/views/ui/KbdView.d.ts +2 -0
- package/dist/views/ui/ModalView.d.ts +2 -0
- package/dist/views/ui/MorphingCardView.d.ts +2 -0
- package/dist/views/ui/MorphingModalView.d.ts +2 -0
- package/dist/views/ui/OTPView.d.ts +206 -0
- package/dist/views/ui/PaginationView.d.ts +2 -0
- package/dist/views/ui/ProgressView.d.ts +2 -0
- package/dist/views/ui/RadioView.d.ts +2 -0
- package/dist/views/ui/SelectView.d.ts +2 -0
- package/dist/views/ui/SkeletonView.d.ts +2 -0
- package/dist/views/ui/StepperView.d.ts +2 -0
- package/dist/views/ui/SwitchView.d.ts +2 -0
- package/dist/views/ui/TableView.d.ts +2 -0
- package/dist/views/ui/TabsView.d.ts +2 -0
- package/dist/views/ui/ToastView.d.ts +2 -0
- package/dist/views/ui/TooltipView.d.ts +2 -0
- package/dist/vite.svg +1 -0
- package/package.json +64 -0
- package/registry/components/accordion.json +19 -0
- package/registry/components/alert.json +17 -0
- package/registry/components/avatar.json +18 -0
- package/registry/components/badge.json +14 -0
- package/registry/components/breadcrumb.json +24 -0
- package/registry/components/button.json +17 -0
- package/registry/components/card.json +23 -0
- package/registry/components/carousel.json +19 -0
- package/registry/components/checkbox.json +17 -0
- package/registry/components/chip.json +17 -0
- package/registry/components/color-picker.json +24 -0
- package/registry/components/date-picker.json +17 -0
- package/registry/components/drawer.json +26 -0
- package/registry/components/dropdown.json +21 -0
- package/registry/components/form.json +16 -0
- package/registry/components/glass-button.json +17 -0
- package/registry/components/icon.json +17 -0
- package/registry/components/input.json +17 -0
- package/registry/components/kbd.json +16 -0
- package/registry/components/modal.json +32 -0
- package/registry/components/option.json +16 -0
- package/registry/components/otp.json +23 -0
- package/registry/components/pagination.json +18 -0
- package/registry/components/progress.json +16 -0
- package/registry/components/radio.json +19 -0
- package/registry/components/select.json +17 -0
- package/registry/components/skeleton.json +14 -0
- package/registry/components/switch.json +17 -0
- package/registry/components/table.json +26 -0
- package/registry/components/tabs.json +19 -0
- package/registry/components/toast.json +19 -0
- package/registry/components/tooltip.json +14 -0
- package/registry/index.json +4 -0
- package/registry/source/components/ui/SAlert.vue +388 -0
- package/registry/source/components/ui/SBadge.vue +243 -0
- package/registry/source/components/ui/SButton.vue +387 -0
- package/registry/source/components/ui/SCheckbox.vue +310 -0
- package/registry/source/components/ui/SChip.vue +130 -0
- package/registry/source/components/ui/SDatePicker.vue +1290 -0
- package/registry/source/components/ui/SGlassButton.vue +547 -0
- package/registry/source/components/ui/SIcon.vue +78 -0
- package/registry/source/components/ui/SInput.vue +1054 -0
- package/registry/source/components/ui/SKbd.vue +96 -0
- package/registry/source/components/ui/SKbdShortcut.vue +36 -0
- package/registry/source/components/ui/SSelect.vue +1290 -0
- package/registry/source/components/ui/SSkeleton.vue +185 -0
- package/registry/source/components/ui/SSwitch.vue +275 -0
- package/registry/source/components/ui/STooltip.vue +491 -0
- package/registry/source/components/ui/accordion/SAccordion.vue +248 -0
- package/registry/source/components/ui/accordion/SAccordionItem.vue +353 -0
- package/registry/source/components/ui/accordion/index.ts +5 -0
- package/registry/source/components/ui/avatar/SAvatar.vue +169 -0
- package/registry/source/components/ui/avatar/SAvatarFallback.vue +66 -0
- package/registry/source/components/ui/avatar/SAvatarGroup.vue +69 -0
- package/registry/source/components/ui/avatar/SAvatarImage.vue +92 -0
- package/registry/source/components/ui/avatar/index.ts +5 -0
- package/registry/source/components/ui/breadcrumb/SBreadcrumb.vue +23 -0
- package/registry/source/components/ui/breadcrumb/SBreadcrumbEllipsis.vue +17 -0
- package/registry/source/components/ui/breadcrumb/SBreadcrumbItem.vue +14 -0
- package/registry/source/components/ui/breadcrumb/SBreadcrumbLink.vue +46 -0
- package/registry/source/components/ui/breadcrumb/SBreadcrumbList.vue +17 -0
- package/registry/source/components/ui/breadcrumb/SBreadcrumbPage.vue +15 -0
- package/registry/source/components/ui/breadcrumb/SBreadcrumbSeparator.vue +18 -0
- package/registry/source/components/ui/breadcrumb/index.ts +7 -0
- package/registry/source/components/ui/card/SCard.vue +517 -0
- package/registry/source/components/ui/card/SCardActions.vue +129 -0
- package/registry/source/components/ui/card/SCardContent.vue +117 -0
- package/registry/source/components/ui/card/SCardFooter.vue +103 -0
- package/registry/source/components/ui/card/SCardHeader.vue +163 -0
- package/registry/source/components/ui/card/SCardMedia.vue +312 -0
- package/registry/source/components/ui/card/index.ts +34 -0
- package/registry/source/components/ui/carousel/SCarousel.vue +1069 -0
- package/registry/source/components/ui/carousel/SCarouselSlide.vue +107 -0
- package/registry/source/components/ui/carousel/index.ts +3 -0
- package/registry/source/components/ui/color-picker/SColorPicker.vue +772 -0
- package/registry/source/components/ui/color-picker/SColorPickerAlphaSlider.vue +158 -0
- package/registry/source/components/ui/color-picker/SColorPickerCopy.vue +76 -0
- package/registry/source/components/ui/color-picker/SColorPickerEyeDropper.vue +68 -0
- package/registry/source/components/ui/color-picker/SColorPickerHueSlider.vue +138 -0
- package/registry/source/components/ui/color-picker/SColorPickerInputs.vue +227 -0
- package/registry/source/components/ui/color-picker/SColorPickerPresets.vue +87 -0
- package/registry/source/components/ui/color-picker/SColorPickerPreview.vue +46 -0
- package/registry/source/components/ui/color-picker/SColorPickerRecent.vue +74 -0
- package/registry/source/components/ui/color-picker/SColorPickerSpectrum.vue +149 -0
- package/registry/source/components/ui/color-picker/index.ts +11 -0
- package/registry/source/components/ui/drawer/SDrawer.vue +797 -0
- package/registry/source/components/ui/drawer/SDrawerClose.vue +64 -0
- package/registry/source/components/ui/drawer/SDrawerContent.vue +81 -0
- package/registry/source/components/ui/drawer/SDrawerDescription.vue +40 -0
- package/registry/source/components/ui/drawer/SDrawerFooter.vue +97 -0
- package/registry/source/components/ui/drawer/SDrawerHandle.vue +79 -0
- package/registry/source/components/ui/drawer/SDrawerHeader.vue +117 -0
- package/registry/source/components/ui/drawer/SDrawerTitle.vue +40 -0
- package/registry/source/components/ui/drawer/SDrawerTrigger.vue +51 -0
- package/registry/source/components/ui/drawer/index.ts +20 -0
- package/registry/source/components/ui/dropdown/SDropdown.vue +843 -0
- package/registry/source/components/ui/dropdown/SDropdownDivider.vue +23 -0
- package/registry/source/components/ui/dropdown/SDropdownGroup.vue +53 -0
- package/registry/source/components/ui/dropdown/SDropdownItem.vue +179 -0
- package/registry/source/components/ui/dropdown/index.ts +5 -0
- package/registry/source/components/ui/form/SForm.vue +84 -0
- package/registry/source/components/ui/form/SFormField.vue +78 -0
- package/registry/source/components/ui/form/index.ts +8 -0
- package/registry/source/components/ui/modal/SModal.vue +648 -0
- package/registry/source/components/ui/modal/SModalClose.vue +49 -0
- package/registry/source/components/ui/modal/SModalContent.vue +74 -0
- package/registry/source/components/ui/modal/SModalDescription.vue +39 -0
- package/registry/source/components/ui/modal/SModalFooter.vue +84 -0
- package/registry/source/components/ui/modal/SModalHeader.vue +107 -0
- package/registry/source/components/ui/modal/SModalTitle.vue +39 -0
- package/registry/source/components/ui/modal/SModalTrigger.vue +61 -0
- package/registry/source/components/ui/modal/SMorphingModal.vue +429 -0
- package/registry/source/components/ui/modal/SMorphingModalClose.vue +42 -0
- package/registry/source/components/ui/modal/SMorphingModalDescription.vue +49 -0
- package/registry/source/components/ui/modal/SMorphingModalImage.vue +44 -0
- package/registry/source/components/ui/modal/SMorphingModalSubtitle.vue +29 -0
- package/registry/source/components/ui/modal/SMorphingModalTitle.vue +34 -0
- package/registry/source/components/ui/modal/SMorphingModalTrigger.vue +95 -0
- package/registry/source/components/ui/modal/index.ts +32 -0
- package/registry/source/components/ui/option/SOption.vue +180 -0
- package/registry/source/components/ui/option/SOptionGroup.vue +77 -0
- package/registry/source/components/ui/option/index.ts +3 -0
- package/registry/source/components/ui/otp/SOTP.vue +843 -0
- package/registry/source/components/ui/otp/SOTPGroup.vue +29 -0
- package/registry/source/components/ui/otp/SOTPSeparator.vue +15 -0
- package/registry/source/components/ui/otp/SOTPSlot.vue +462 -0
- package/registry/source/components/ui/otp/index.ts +7 -0
- package/registry/source/components/ui/otp/types.ts +27 -0
- package/registry/source/components/ui/otp/useOTPContext.ts +62 -0
- package/registry/source/components/ui/pagination/SPagination.vue +923 -0
- package/registry/source/components/ui/pagination/index.ts +8 -0
- package/registry/source/components/ui/progress/SProgress.vue +635 -0
- package/registry/source/components/ui/progress/SProgressRange.vue +715 -0
- package/registry/source/components/ui/progress/index.ts +4 -0
- package/registry/source/components/ui/radio/SRadio.vue +407 -0
- package/registry/source/components/ui/radio/SRadioGroup.vue +200 -0
- package/registry/source/components/ui/radio/index.ts +3 -0
- package/registry/source/components/ui/table/SDataTable.vue +828 -0
- package/registry/source/components/ui/table/STableBody.vue +70 -0
- package/registry/source/components/ui/table/STableCell.vue +147 -0
- package/registry/source/components/ui/table/STableColumn.vue +120 -0
- package/registry/source/components/ui/table/STableEmpty.vue +159 -0
- package/registry/source/components/ui/table/STableHeader.vue +132 -0
- package/registry/source/components/ui/table/STableRow.vue +106 -0
- package/registry/source/components/ui/table/STableSkeleton.vue +208 -0
- package/registry/source/components/ui/table/index.ts +126 -0
- package/registry/source/components/ui/table/useDataTable.ts +519 -0
- package/registry/source/components/ui/tabs/STabPane.vue +130 -0
- package/registry/source/components/ui/tabs/STabs.vue +467 -0
- package/registry/source/components/ui/tabs/index.ts +7 -0
- package/registry/source/components/ui/toast/SToast.vue +261 -0
- package/registry/source/components/ui/toast/SToastContainer.vue +209 -0
- package/registry/source/components/ui/toast/index.ts +2 -0
- package/registry/source/composables/useForm.ts +960 -0
- package/registry/source/composables/useTheme.ts +86 -0
- package/registry/source/composables/useToast.ts +440 -0
- package/registry/source/lib/utils.ts +6 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { ref, watch, onMounted } from 'vue'
|
|
2
|
+
|
|
3
|
+
export type Theme = 'light' | 'dark' | 'system'
|
|
4
|
+
|
|
5
|
+
const THEME_KEY = 'saka-ui-theme'
|
|
6
|
+
|
|
7
|
+
// Cookie helpers
|
|
8
|
+
function getCookie(name: string): string | null {
|
|
9
|
+
const v = document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)');
|
|
10
|
+
return v ? v[2] : null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function setCookie(name: string, value: string, days: number = 365) {
|
|
14
|
+
const d = new Date();
|
|
15
|
+
d.setTime(d.getTime() + 24 * 60 * 60 * 1000 * days);
|
|
16
|
+
document.cookie = name + "=" + value + ";path=/;SameSite=Strict;expires=" + d.toUTCString();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Standalone function to apply theme (can be used outside component context)
|
|
20
|
+
export function applyTheme(t: Theme) {
|
|
21
|
+
if (typeof window === 'undefined') return
|
|
22
|
+
|
|
23
|
+
const root = document.documentElement
|
|
24
|
+
let isDark = false
|
|
25
|
+
|
|
26
|
+
if (t === 'system') {
|
|
27
|
+
isDark = window.matchMedia('(prefers-color-scheme: dark)').matches
|
|
28
|
+
} else {
|
|
29
|
+
isDark = t === 'dark'
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (isDark) {
|
|
33
|
+
root.classList.add('dark')
|
|
34
|
+
} else {
|
|
35
|
+
root.classList.remove('dark')
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Global state to share theme across composable usages
|
|
40
|
+
const globalTheme = ref<Theme>((getCookie(THEME_KEY) as Theme) || 'system')
|
|
41
|
+
|
|
42
|
+
// Watch for changes deeply to ensure consistency
|
|
43
|
+
watch(globalTheme, (newTheme) => {
|
|
44
|
+
setCookie(THEME_KEY, newTheme)
|
|
45
|
+
applyTheme(newTheme)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
export function useTheme() {
|
|
49
|
+
const toggleTheme = () => {
|
|
50
|
+
if (globalTheme.value === 'light') globalTheme.value = 'dark'
|
|
51
|
+
else if (globalTheme.value === 'dark') globalTheme.value = 'system'
|
|
52
|
+
else globalTheme.value = 'light'
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
onMounted(() => {
|
|
56
|
+
// Ensure theme is applied on mount (safeguard)
|
|
57
|
+
applyTheme(globalTheme.value)
|
|
58
|
+
|
|
59
|
+
// Listen for system theme changes
|
|
60
|
+
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
|
|
61
|
+
const handler = () => {
|
|
62
|
+
if (globalTheme.value === 'system') {
|
|
63
|
+
applyTheme('system')
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Modern addEventListener
|
|
68
|
+
mediaQuery.addEventListener('change', handler)
|
|
69
|
+
|
|
70
|
+
// Cleanup not strictly necessary for global composable used in root,
|
|
71
|
+
// but good practice if used in smaller components
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
theme: globalTheme,
|
|
76
|
+
toggleTheme,
|
|
77
|
+
setTheme: (t: Theme) => { globalTheme.value = t }
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Initialize theme immediately
|
|
82
|
+
export function initTheme() {
|
|
83
|
+
if (typeof window !== 'undefined') {
|
|
84
|
+
applyTheme(globalTheme.value)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
import { ref, reactive, readonly, markRaw, type Component } from 'vue'
|
|
2
|
+
|
|
3
|
+
// ============================================================================
|
|
4
|
+
// Types
|
|
5
|
+
// ============================================================================
|
|
6
|
+
|
|
7
|
+
export type ToastType = 'success' | 'error' | 'warning' | 'info' | 'loading' | 'custom'
|
|
8
|
+
|
|
9
|
+
export type ToastPosition =
|
|
10
|
+
| 'top-left'
|
|
11
|
+
| 'top-right'
|
|
12
|
+
| 'top-center'
|
|
13
|
+
| 'bottom-left'
|
|
14
|
+
| 'bottom-right'
|
|
15
|
+
| 'bottom-center'
|
|
16
|
+
|
|
17
|
+
export interface ToastOptions {
|
|
18
|
+
/** Toast title */
|
|
19
|
+
title?: string
|
|
20
|
+
/** Toast description/message */
|
|
21
|
+
description?: string
|
|
22
|
+
/** Duration in ms before auto-dismiss (0 = no auto-dismiss) */
|
|
23
|
+
duration?: number
|
|
24
|
+
/** Position on screen */
|
|
25
|
+
position?: ToastPosition
|
|
26
|
+
/** Show progress bar */
|
|
27
|
+
showProgress?: boolean
|
|
28
|
+
/** Show close button */
|
|
29
|
+
closable?: boolean
|
|
30
|
+
/** Custom icon (mdi icon name, or false to hide) */
|
|
31
|
+
icon?: string | boolean
|
|
32
|
+
/** Custom color for 'custom' type */
|
|
33
|
+
color?: string
|
|
34
|
+
/** Callback when toast is clicked */
|
|
35
|
+
onClick?: () => void
|
|
36
|
+
/** Callback when toast is closed */
|
|
37
|
+
onClose?: () => void
|
|
38
|
+
/** Custom component to render */
|
|
39
|
+
component?: Component
|
|
40
|
+
/** Props for custom component */
|
|
41
|
+
componentProps?: Record<string, unknown>
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface ToastInstance {
|
|
45
|
+
/** Unique toast ID */
|
|
46
|
+
id: string
|
|
47
|
+
/** Toast type */
|
|
48
|
+
type: ToastType
|
|
49
|
+
/** Toast options */
|
|
50
|
+
options: ToastOptions
|
|
51
|
+
/** Creation timestamp */
|
|
52
|
+
createdAt: number
|
|
53
|
+
/** Whether toast is paused */
|
|
54
|
+
paused: boolean
|
|
55
|
+
/** Remaining time when paused */
|
|
56
|
+
remainingTime: number
|
|
57
|
+
/** Progress percentage (0-100) */
|
|
58
|
+
progress: number
|
|
59
|
+
/** Dismiss this toast */
|
|
60
|
+
dismiss: () => void
|
|
61
|
+
/** Pause auto-dismiss */
|
|
62
|
+
pause: () => void
|
|
63
|
+
/** Resume auto-dismiss */
|
|
64
|
+
resume: () => void
|
|
65
|
+
/** Update toast content */
|
|
66
|
+
update: (options: Partial<ToastOptions>) => void
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface ToastPromiseOptions<T> {
|
|
70
|
+
loading: string | ToastOptions
|
|
71
|
+
success: string | ToastOptions | ((data: T) => string | ToastOptions)
|
|
72
|
+
error: string | ToastOptions | ((err: unknown) => string | ToastOptions)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface ToastConfig {
|
|
76
|
+
/** Default position for all toasts */
|
|
77
|
+
position?: ToastPosition
|
|
78
|
+
/** Default duration in ms */
|
|
79
|
+
duration?: number
|
|
80
|
+
/** Maximum toasts per position */
|
|
81
|
+
maxToasts?: number
|
|
82
|
+
/** Gap between toasts in px */
|
|
83
|
+
gap?: number
|
|
84
|
+
/** Whether to show progress bar by default */
|
|
85
|
+
showProgress?: boolean
|
|
86
|
+
/** Whether toasts are closable by default */
|
|
87
|
+
closable?: boolean
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ============================================================================
|
|
91
|
+
// Global State
|
|
92
|
+
// ============================================================================
|
|
93
|
+
|
|
94
|
+
const defaultConfig: Required<ToastConfig> = {
|
|
95
|
+
position: 'top-right',
|
|
96
|
+
duration: 5000,
|
|
97
|
+
maxToasts: 5,
|
|
98
|
+
gap: 8,
|
|
99
|
+
showProgress: true,
|
|
100
|
+
closable: true
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const globalConfig = reactive<Required<ToastConfig>>({ ...defaultConfig })
|
|
104
|
+
const toasts = ref<ToastInstance[]>([])
|
|
105
|
+
const timers = new Map<string, ReturnType<typeof setInterval>>()
|
|
106
|
+
|
|
107
|
+
// ============================================================================
|
|
108
|
+
// Helper Functions
|
|
109
|
+
// ============================================================================
|
|
110
|
+
|
|
111
|
+
function generateId(): string {
|
|
112
|
+
return `toast-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function normalizeOptions(
|
|
116
|
+
messageOrOptions: string | ToastOptions,
|
|
117
|
+
type: ToastType
|
|
118
|
+
): ToastOptions {
|
|
119
|
+
if (typeof messageOrOptions === 'string') {
|
|
120
|
+
return { description: messageOrOptions }
|
|
121
|
+
}
|
|
122
|
+
return messageOrOptions
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function getDefaultIcon(type: ToastType): string {
|
|
126
|
+
const icons: Record<ToastType, string> = {
|
|
127
|
+
success: 'check-circle',
|
|
128
|
+
error: 'alert-circle',
|
|
129
|
+
warning: 'alert',
|
|
130
|
+
info: 'information',
|
|
131
|
+
loading: 'loading',
|
|
132
|
+
custom: 'bell'
|
|
133
|
+
}
|
|
134
|
+
return icons[type]
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function startTimer(toast: ToastInstance) {
|
|
138
|
+
const duration = toast.options.duration ?? globalConfig.duration
|
|
139
|
+
if (duration <= 0) return
|
|
140
|
+
|
|
141
|
+
const startTime = Date.now()
|
|
142
|
+
const initialRemaining = toast.remainingTime > 0 ? toast.remainingTime : duration
|
|
143
|
+
|
|
144
|
+
const intervalId = setInterval(() => {
|
|
145
|
+
if (toast.paused) return
|
|
146
|
+
|
|
147
|
+
const elapsed = Date.now() - startTime
|
|
148
|
+
const remaining = initialRemaining - elapsed
|
|
149
|
+
|
|
150
|
+
if (remaining <= 0) {
|
|
151
|
+
toast.dismiss()
|
|
152
|
+
} else {
|
|
153
|
+
toast.remainingTime = remaining
|
|
154
|
+
toast.progress = (remaining / duration) * 100
|
|
155
|
+
}
|
|
156
|
+
}, 50)
|
|
157
|
+
|
|
158
|
+
timers.set(toast.id, intervalId)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function stopTimer(toastId: string) {
|
|
162
|
+
const timerId = timers.get(toastId)
|
|
163
|
+
if (timerId) {
|
|
164
|
+
clearInterval(timerId)
|
|
165
|
+
timers.delete(toastId)
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function removeToast(id: string) {
|
|
170
|
+
stopTimer(id)
|
|
171
|
+
const index = toasts.value.findIndex(t => t.id === id)
|
|
172
|
+
if (index !== -1) {
|
|
173
|
+
const toast = toasts.value[index]
|
|
174
|
+
toast.options.onClose?.()
|
|
175
|
+
toasts.value.splice(index, 1)
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function enforceMaxToasts(position: ToastPosition) {
|
|
180
|
+
const positionToasts = toasts.value.filter(t =>
|
|
181
|
+
(t.options.position ?? globalConfig.position) === position
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
while (positionToasts.length > globalConfig.maxToasts) {
|
|
185
|
+
const oldest = positionToasts.shift()
|
|
186
|
+
if (oldest) {
|
|
187
|
+
removeToast(oldest.id)
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// ============================================================================
|
|
193
|
+
// Core Functions
|
|
194
|
+
// ============================================================================
|
|
195
|
+
|
|
196
|
+
function createToast(type: ToastType, options: ToastOptions): ToastInstance {
|
|
197
|
+
const id = generateId()
|
|
198
|
+
const position = options.position ?? globalConfig.position
|
|
199
|
+
const duration = options.duration ?? globalConfig.duration
|
|
200
|
+
|
|
201
|
+
const toast: ToastInstance = reactive({
|
|
202
|
+
id,
|
|
203
|
+
type,
|
|
204
|
+
options: {
|
|
205
|
+
...options,
|
|
206
|
+
position,
|
|
207
|
+
duration,
|
|
208
|
+
showProgress: options.showProgress ?? globalConfig.showProgress,
|
|
209
|
+
closable: options.closable ?? globalConfig.closable,
|
|
210
|
+
icon: options.icon ?? getDefaultIcon(type),
|
|
211
|
+
component: options.component ? markRaw(options.component) : undefined
|
|
212
|
+
},
|
|
213
|
+
createdAt: Date.now(),
|
|
214
|
+
paused: false,
|
|
215
|
+
remainingTime: duration,
|
|
216
|
+
progress: 100,
|
|
217
|
+
dismiss: () => removeToast(id),
|
|
218
|
+
pause: () => {
|
|
219
|
+
toast.paused = true
|
|
220
|
+
stopTimer(id)
|
|
221
|
+
},
|
|
222
|
+
resume: () => {
|
|
223
|
+
toast.paused = false
|
|
224
|
+
startTimer(toast)
|
|
225
|
+
},
|
|
226
|
+
update: (newOptions: Partial<ToastOptions>) => {
|
|
227
|
+
Object.assign(toast.options, newOptions)
|
|
228
|
+
}
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
// Add to queue
|
|
232
|
+
toasts.value.push(toast)
|
|
233
|
+
|
|
234
|
+
// Enforce max toasts
|
|
235
|
+
enforceMaxToasts(position)
|
|
236
|
+
|
|
237
|
+
// Start auto-dismiss timer
|
|
238
|
+
if (type !== 'loading') {
|
|
239
|
+
startTimer(toast)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return toast
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// ============================================================================
|
|
246
|
+
// Public API
|
|
247
|
+
// ============================================================================
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Toast notification composable
|
|
251
|
+
*
|
|
252
|
+
* @example
|
|
253
|
+
* const toast = useToast()
|
|
254
|
+
*
|
|
255
|
+
* // Basic usage
|
|
256
|
+
* toast.success('Saved successfully!')
|
|
257
|
+
* toast.error('Failed to save')
|
|
258
|
+
*
|
|
259
|
+
* // With options
|
|
260
|
+
* toast.success({
|
|
261
|
+
* title: 'Success',
|
|
262
|
+
* description: 'Your changes have been saved',
|
|
263
|
+
* duration: 3000
|
|
264
|
+
* })
|
|
265
|
+
*
|
|
266
|
+
* // Promise-based
|
|
267
|
+
* toast.promise(saveData(), {
|
|
268
|
+
* loading: 'Saving...',
|
|
269
|
+
* success: 'Saved!',
|
|
270
|
+
* error: 'Failed to save'
|
|
271
|
+
* })
|
|
272
|
+
*/
|
|
273
|
+
export function useToast() {
|
|
274
|
+
/**
|
|
275
|
+
* Show a success toast
|
|
276
|
+
*/
|
|
277
|
+
function success(messageOrOptions: string | ToastOptions): ToastInstance {
|
|
278
|
+
const options = normalizeOptions(messageOrOptions, 'success')
|
|
279
|
+
return createToast('success', options)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Show an error toast
|
|
284
|
+
*/
|
|
285
|
+
function error(messageOrOptions: string | ToastOptions): ToastInstance {
|
|
286
|
+
const options = normalizeOptions(messageOrOptions, 'error')
|
|
287
|
+
return createToast('error', options)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Show a warning toast
|
|
292
|
+
*/
|
|
293
|
+
function warning(messageOrOptions: string | ToastOptions): ToastInstance {
|
|
294
|
+
const options = normalizeOptions(messageOrOptions, 'warning')
|
|
295
|
+
return createToast('warning', options)
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Show an info toast
|
|
300
|
+
*/
|
|
301
|
+
function info(messageOrOptions: string | ToastOptions): ToastInstance {
|
|
302
|
+
const options = normalizeOptions(messageOrOptions, 'info')
|
|
303
|
+
return createToast('info', options)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Show a loading toast (no auto-dismiss)
|
|
308
|
+
*/
|
|
309
|
+
function loading(messageOrOptions: string | ToastOptions): ToastInstance {
|
|
310
|
+
const options = normalizeOptions(messageOrOptions, 'loading')
|
|
311
|
+
return createToast('loading', { ...options, duration: 0, showProgress: false })
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Show a custom toast
|
|
316
|
+
*/
|
|
317
|
+
function custom(options: ToastOptions): ToastInstance {
|
|
318
|
+
return createToast('custom', options)
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Show a promise-based toast
|
|
323
|
+
* Displays loading → success/error based on promise resolution
|
|
324
|
+
*/
|
|
325
|
+
async function promise<T>(
|
|
326
|
+
promiseOrFn: Promise<T> | (() => Promise<T>),
|
|
327
|
+
options: ToastPromiseOptions<T>
|
|
328
|
+
): Promise<T> {
|
|
329
|
+
const actualPromise = typeof promiseOrFn === 'function' ? promiseOrFn() : promiseOrFn
|
|
330
|
+
|
|
331
|
+
// Show loading toast
|
|
332
|
+
const loadingOptions = normalizeOptions(options.loading, 'loading')
|
|
333
|
+
const loadingToast = loading(loadingOptions)
|
|
334
|
+
|
|
335
|
+
try {
|
|
336
|
+
const result = await actualPromise
|
|
337
|
+
|
|
338
|
+
// Dismiss loading and show success
|
|
339
|
+
loadingToast.dismiss()
|
|
340
|
+
|
|
341
|
+
let successOptions: ToastOptions
|
|
342
|
+
if (typeof options.success === 'function') {
|
|
343
|
+
const successResult = options.success(result)
|
|
344
|
+
successOptions = normalizeOptions(successResult, 'success')
|
|
345
|
+
} else {
|
|
346
|
+
successOptions = normalizeOptions(options.success, 'success')
|
|
347
|
+
}
|
|
348
|
+
success(successOptions)
|
|
349
|
+
|
|
350
|
+
return result
|
|
351
|
+
} catch (err) {
|
|
352
|
+
// Dismiss loading and show error
|
|
353
|
+
loadingToast.dismiss()
|
|
354
|
+
|
|
355
|
+
let errorOptions: ToastOptions
|
|
356
|
+
if (typeof options.error === 'function') {
|
|
357
|
+
const errorResult = options.error(err)
|
|
358
|
+
errorOptions = normalizeOptions(errorResult, 'error')
|
|
359
|
+
} else {
|
|
360
|
+
errorOptions = normalizeOptions(options.error, 'error')
|
|
361
|
+
}
|
|
362
|
+
error(errorOptions)
|
|
363
|
+
|
|
364
|
+
throw err
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Dismiss a specific toast by ID
|
|
370
|
+
*/
|
|
371
|
+
function dismiss(toastId: string) {
|
|
372
|
+
removeToast(toastId)
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Dismiss all toasts
|
|
377
|
+
*/
|
|
378
|
+
function dismissAll() {
|
|
379
|
+
const ids = toasts.value.map(t => t.id)
|
|
380
|
+
ids.forEach(removeToast)
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Configure global toast defaults
|
|
385
|
+
*/
|
|
386
|
+
function configure(config: ToastConfig) {
|
|
387
|
+
Object.assign(globalConfig, config)
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
return {
|
|
391
|
+
// Toast methods
|
|
392
|
+
success,
|
|
393
|
+
error,
|
|
394
|
+
warning,
|
|
395
|
+
info,
|
|
396
|
+
loading,
|
|
397
|
+
custom,
|
|
398
|
+
promise,
|
|
399
|
+
// Management
|
|
400
|
+
dismiss,
|
|
401
|
+
dismissAll,
|
|
402
|
+
configure,
|
|
403
|
+
// State (readonly)
|
|
404
|
+
toasts: readonly(toasts),
|
|
405
|
+
config: readonly(globalConfig)
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// ============================================================================
|
|
410
|
+
// Exports
|
|
411
|
+
// ============================================================================
|
|
412
|
+
|
|
413
|
+
/** Get all active toasts (for use in SToastContainer) */
|
|
414
|
+
export function getToasts() {
|
|
415
|
+
return readonly(toasts)
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/** Get global toast config */
|
|
419
|
+
export function getToastConfig() {
|
|
420
|
+
return readonly(globalConfig)
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/** Dismiss a toast by ID (for use in SToast) */
|
|
424
|
+
export function dismissToast(id: string) {
|
|
425
|
+
removeToast(id)
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/** Pause a toast by ID */
|
|
429
|
+
export function pauseToast(id: string) {
|
|
430
|
+
const toast = toasts.value.find(t => t.id === id)
|
|
431
|
+
toast?.pause()
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/** Resume a toast by ID */
|
|
435
|
+
export function resumeToast(id: string) {
|
|
436
|
+
const toast = toasts.value.find(t => t.id === id)
|
|
437
|
+
toast?.resume()
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
export default useToast
|