@regardio/react 0.3.2
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/LICENSE +9 -0
- package/README.md +133 -0
- package/dist/components/background-slideshow.d.ts +22 -0
- package/dist/components/background-slideshow.d.ts.map +1 -0
- package/dist/components/background-slideshow.js +76 -0
- package/dist/components/blurry-gradient.d.ts +9 -0
- package/dist/components/blurry-gradient.d.ts.map +1 -0
- package/dist/components/blurry-gradient.js +6 -0
- package/dist/components/box.d.ts +17 -0
- package/dist/components/box.d.ts.map +1 -0
- package/dist/components/box.js +25 -0
- package/dist/components/carousel.d.ts +26 -0
- package/dist/components/carousel.d.ts.map +1 -0
- package/dist/components/carousel.js +87 -0
- package/dist/components/countdown.d.ts +2 -0
- package/dist/components/countdown.d.ts.map +1 -0
- package/dist/components/countdown.js +48 -0
- package/dist/components/definition-list.d.ts +40 -0
- package/dist/components/definition-list.d.ts.map +1 -0
- package/dist/components/definition-list.js +57 -0
- package/dist/components/generic-error.d.ts +23 -0
- package/dist/components/generic-error.d.ts.map +1 -0
- package/dist/components/generic-error.js +39 -0
- package/dist/components/heading.d.ts +24 -0
- package/dist/components/heading.d.ts.map +1 -0
- package/dist/components/heading.js +29 -0
- package/dist/components/highlight.d.ts +16 -0
- package/dist/components/highlight.d.ts.map +1 -0
- package/dist/components/highlight.js +19 -0
- package/dist/components/icon-button.d.ts +6 -0
- package/dist/components/icon-button.d.ts.map +1 -0
- package/dist/components/icon-button.js +6 -0
- package/dist/components/if.d.ts +8 -0
- package/dist/components/if.d.ts.map +1 -0
- package/dist/components/if.js +16 -0
- package/dist/components/iframe.d.ts +8 -0
- package/dist/components/iframe.d.ts.map +1 -0
- package/dist/components/iframe.js +3 -0
- package/dist/components/item.d.ts +67 -0
- package/dist/components/item.d.ts.map +1 -0
- package/dist/components/item.js +309 -0
- package/dist/components/leaflet-map.d.ts +33 -0
- package/dist/components/leaflet-map.d.ts.map +1 -0
- package/dist/components/leaflet-map.js +195 -0
- package/dist/components/link.d.ts +41 -0
- package/dist/components/link.d.ts.map +1 -0
- package/dist/components/link.js +111 -0
- package/dist/components/link.test.d.ts +2 -0
- package/dist/components/link.test.d.ts.map +1 -0
- package/dist/components/link.test.js +204 -0
- package/dist/components/list-item.d.ts +16 -0
- package/dist/components/list-item.d.ts.map +1 -0
- package/dist/components/list-item.js +19 -0
- package/dist/components/maptiler-map.d.ts +26 -0
- package/dist/components/maptiler-map.d.ts.map +1 -0
- package/dist/components/maptiler-map.js +116 -0
- package/dist/components/markdown-container.d.ts +20 -0
- package/dist/components/markdown-container.d.ts.map +1 -0
- package/dist/components/markdown-container.js +93 -0
- package/dist/components/password-input.d.ts +9 -0
- package/dist/components/password-input.d.ts.map +1 -0
- package/dist/components/password-input.js +13 -0
- package/dist/components/picture.d.ts +26 -0
- package/dist/components/picture.d.ts.map +1 -0
- package/dist/components/picture.js +36 -0
- package/dist/components/protected-email.d.ts +9 -0
- package/dist/components/protected-email.d.ts.map +1 -0
- package/dist/components/protected-email.js +16 -0
- package/dist/components/text.d.ts +17 -0
- package/dist/components/text.d.ts.map +1 -0
- package/dist/components/text.js +27 -0
- package/dist/components/unordered-list.d.ts +16 -0
- package/dist/components/unordered-list.d.ts.map +1 -0
- package/dist/components/unordered-list.js +21 -0
- package/dist/hooks/use-current-route-data.d.ts +2 -0
- package/dist/hooks/use-current-route-data.d.ts.map +1 -0
- package/dist/hooks/use-current-route-data.js +12 -0
- package/dist/hooks/use-focus-search.d.ts +3 -0
- package/dist/hooks/use-focus-search.d.ts.map +1 -0
- package/dist/hooks/use-focus-search.js +15 -0
- package/dist/hooks/use-matches-data.d.ts +2 -0
- package/dist/hooks/use-matches-data.d.ts.map +1 -0
- package/dist/hooks/use-matches-data.js +11 -0
- package/dist/hooks/use-media-query.d.ts +2 -0
- package/dist/hooks/use-media-query.d.ts.map +1 -0
- package/dist/hooks/use-media-query.js +16 -0
- package/dist/hooks/use-mobile.d.ts +2 -0
- package/dist/hooks/use-mobile.d.ts.map +1 -0
- package/dist/hooks/use-mobile.js +15 -0
- package/dist/hooks/use-nonce.d.ts +5 -0
- package/dist/hooks/use-nonce.d.ts.map +1 -0
- package/dist/hooks/use-nonce.js +9 -0
- package/dist/hooks/use-nonce.test.d.ts +2 -0
- package/dist/hooks/use-nonce.test.d.ts.map +1 -0
- package/dist/hooks/use-nonce.test.js +27 -0
- package/dist/hooks/use-orientation.d.ts +3 -0
- package/dist/hooks/use-orientation.d.ts.map +1 -0
- package/dist/hooks/use-orientation.js +25 -0
- package/dist/hooks/use-user.d.ts +15 -0
- package/dist/hooks/use-user.d.ts.map +1 -0
- package/dist/hooks/use-user.js +17 -0
- package/dist/shadcn/accordion.d.ts +25 -0
- package/dist/shadcn/accordion.d.ts.map +1 -0
- package/dist/shadcn/accordion.js +45 -0
- package/dist/shadcn/alert-dialog.d.ts +73 -0
- package/dist/shadcn/alert-dialog.d.ts.map +1 -0
- package/dist/shadcn/alert-dialog.js +93 -0
- package/dist/shadcn/alert.d.ts +34 -0
- package/dist/shadcn/alert.d.ts.map +1 -0
- package/dist/shadcn/alert.js +42 -0
- package/dist/shadcn/aspect-ratio.d.ts +6 -0
- package/dist/shadcn/aspect-ratio.d.ts.map +1 -0
- package/dist/shadcn/aspect-ratio.js +7 -0
- package/dist/shadcn/avatar.d.ts +16 -0
- package/dist/shadcn/avatar.d.ts.map +1 -0
- package/dist/shadcn/avatar.js +27 -0
- package/dist/shadcn/badge.d.ts +29 -0
- package/dist/shadcn/badge.d.ts.map +1 -0
- package/dist/shadcn/badge.js +29 -0
- package/dist/shadcn/breadcrumb.d.ts +42 -0
- package/dist/shadcn/breadcrumb.d.ts.map +1 -0
- package/dist/shadcn/breadcrumb.js +74 -0
- package/dist/shadcn/button.d.ts +38 -0
- package/dist/shadcn/button.d.ts.map +1 -0
- package/dist/shadcn/button.js +38 -0
- package/dist/shadcn/calendar.d.ts +23 -0
- package/dist/shadcn/calendar.d.ts.map +1 -0
- package/dist/shadcn/calendar.js +163 -0
- package/dist/shadcn/card.d.ts +31 -0
- package/dist/shadcn/card.d.ts.map +1 -0
- package/dist/shadcn/card.js +55 -0
- package/dist/shadcn/carousel.d.ts +51 -0
- package/dist/shadcn/carousel.d.ts.map +1 -0
- package/dist/shadcn/carousel.js +161 -0
- package/dist/shadcn/chart.d.ts +103 -0
- package/dist/shadcn/chart.d.ts.map +1 -0
- package/dist/shadcn/chart.js +248 -0
- package/dist/shadcn/checkbox.d.ts +8 -0
- package/dist/shadcn/checkbox.d.ts.map +1 -0
- package/dist/shadcn/checkbox.js +22 -0
- package/dist/shadcn/collapsible.d.ts +16 -0
- package/dist/shadcn/collapsible.d.ts.map +1 -0
- package/dist/shadcn/collapsible.js +19 -0
- package/dist/shadcn/command.d.ts +61 -0
- package/dist/shadcn/command.d.ts.map +1 -0
- package/dist/shadcn/command.js +123 -0
- package/dist/shadcn/context-menu.d.ts +107 -0
- package/dist/shadcn/context-menu.d.ts.map +1 -0
- package/dist/shadcn/context-menu.js +151 -0
- package/dist/shadcn/dialog.d.ts +57 -0
- package/dist/shadcn/dialog.d.ts.map +1 -0
- package/dist/shadcn/dialog.js +96 -0
- package/dist/shadcn/drawer.d.ts +54 -0
- package/dist/shadcn/drawer.d.ts.map +1 -0
- package/dist/shadcn/drawer.js +96 -0
- package/dist/shadcn/dropdown-menu.d.ts +110 -0
- package/dist/shadcn/dropdown-menu.d.ts.map +1 -0
- package/dist/shadcn/dropdown-menu.js +152 -0
- package/dist/shadcn/form.d.ts +59 -0
- package/dist/shadcn/form.d.ts.map +1 -0
- package/dist/shadcn/form.js +99 -0
- package/dist/shadcn/hover-card.d.ts +20 -0
- package/dist/shadcn/hover-card.d.ts.map +1 -0
- package/dist/shadcn/hover-card.js +26 -0
- package/dist/shadcn/input-otp.d.ts +25 -0
- package/dist/shadcn/input-otp.d.ts.map +1 -0
- package/dist/shadcn/input-otp.js +54 -0
- package/dist/shadcn/input.d.ts +14 -0
- package/dist/shadcn/input.d.ts.map +1 -0
- package/dist/shadcn/input.js +48 -0
- package/dist/shadcn/label.d.ts +8 -0
- package/dist/shadcn/label.d.ts.map +1 -0
- package/dist/shadcn/label.js +16 -0
- package/dist/shadcn/menubar.d.ts +108 -0
- package/dist/shadcn/menubar.d.ts.map +1 -0
- package/dist/shadcn/menubar.js +174 -0
- package/dist/shadcn/navigation-menu.d.ts +79 -0
- package/dist/shadcn/navigation-menu.d.ts.map +1 -0
- package/dist/shadcn/navigation-menu.js +108 -0
- package/dist/shadcn/pagination.d.ts +45 -0
- package/dist/shadcn/pagination.d.ts.map +1 -0
- package/dist/shadcn/pagination.js +83 -0
- package/dist/shadcn/popover.d.ts +19 -0
- package/dist/shadcn/popover.d.ts.map +1 -0
- package/dist/shadcn/popover.js +29 -0
- package/dist/shadcn/progress.d.ts +9 -0
- package/dist/shadcn/progress.d.ts.map +1 -0
- package/dist/shadcn/progress.js +17 -0
- package/dist/shadcn/radio-group.d.ts +12 -0
- package/dist/shadcn/radio-group.d.ts.map +1 -0
- package/dist/shadcn/radio-group.js +32 -0
- package/dist/shadcn/resizable.d.ts +20 -0
- package/dist/shadcn/resizable.d.ts.map +1 -0
- package/dist/shadcn/resizable.js +32 -0
- package/dist/shadcn/scroll-area.d.ts +16 -0
- package/dist/shadcn/scroll-area.d.ts.map +1 -0
- package/dist/shadcn/scroll-area.js +40 -0
- package/dist/shadcn/select.d.ts +63 -0
- package/dist/shadcn/select.d.ts.map +1 -0
- package/dist/shadcn/select.js +120 -0
- package/dist/shadcn/separator.d.ts +10 -0
- package/dist/shadcn/separator.d.ts.map +1 -0
- package/dist/shadcn/separator.js +18 -0
- package/dist/shadcn/sheet.d.ts +48 -0
- package/dist/shadcn/sheet.d.ts.map +1 -0
- package/dist/shadcn/sheet.js +99 -0
- package/dist/shadcn/sidebar.d.ts +200 -0
- package/dist/shadcn/sidebar.d.ts.map +1 -0
- package/dist/shadcn/sidebar.js +528 -0
- package/dist/shadcn/skeleton.d.ts +6 -0
- package/dist/shadcn/skeleton.d.ts.map +1 -0
- package/dist/shadcn/skeleton.js +11 -0
- package/dist/shadcn/slider.d.ts +12 -0
- package/dist/shadcn/slider.d.ts.map +1 -0
- package/dist/shadcn/slider.js +50 -0
- package/dist/shadcn/sonner.d.ts +7 -0
- package/dist/shadcn/sonner.d.ts.map +1 -0
- package/dist/shadcn/sonner.js +20 -0
- package/dist/shadcn/switch.d.ts +8 -0
- package/dist/shadcn/switch.d.ts.map +1 -0
- package/dist/shadcn/switch.js +22 -0
- package/dist/shadcn/table.d.ts +35 -0
- package/dist/shadcn/table.d.ts.map +1 -0
- package/dist/shadcn/table.js +73 -0
- package/dist/shadcn/tabs.d.ts +20 -0
- package/dist/shadcn/tabs.d.ts.map +1 -0
- package/dist/shadcn/tabs.js +40 -0
- package/dist/shadcn/textarea.d.ts +7 -0
- package/dist/shadcn/textarea.d.ts.map +1 -0
- package/dist/shadcn/textarea.js +14 -0
- package/dist/shadcn/toggle-group.d.ts +22 -0
- package/dist/shadcn/toggle-group.d.ts.map +1 -0
- package/dist/shadcn/toggle-group.js +43 -0
- package/dist/shadcn/toggle.d.ts +29 -0
- package/dist/shadcn/toggle.d.ts.map +1 -0
- package/dist/shadcn/toggle.js +31 -0
- package/dist/shadcn/tooltip.d.ts +20 -0
- package/dist/shadcn/tooltip.d.ts.map +1 -0
- package/dist/shadcn/tooltip.js +40 -0
- package/dist/stories/BackgroundSlideshow.stories.d.ts +9 -0
- package/dist/stories/BackgroundSlideshow.stories.d.ts.map +1 -0
- package/dist/stories/BackgroundSlideshow.stories.js +60 -0
- package/dist/stories/BlurryGradient.stories.d.ts +11 -0
- package/dist/stories/BlurryGradient.stories.d.ts.map +1 -0
- package/dist/stories/BlurryGradient.stories.js +53 -0
- package/dist/stories/Box.stories.d.ts +13 -0
- package/dist/stories/Box.stories.d.ts.map +1 -0
- package/dist/stories/Box.stories.js +50 -0
- package/dist/stories/Carousel.stories.d.ts +9 -0
- package/dist/stories/Carousel.stories.d.ts.map +1 -0
- package/dist/stories/Carousel.stories.js +30 -0
- package/dist/stories/Countdown.stories.d.ts +7 -0
- package/dist/stories/Countdown.stories.d.ts.map +1 -0
- package/dist/stories/Countdown.stories.js +11 -0
- package/dist/stories/DefinitionList.stories.d.ts +9 -0
- package/dist/stories/DefinitionList.stories.d.ts.map +1 -0
- package/dist/stories/DefinitionList.stories.js +20 -0
- package/dist/stories/GenericError.stories.d.ts +9 -0
- package/dist/stories/GenericError.stories.d.ts.map +1 -0
- package/dist/stories/GenericError.stories.js +39 -0
- package/dist/stories/Heading.stories.d.ts +15 -0
- package/dist/stories/Heading.stories.d.ts.map +1 -0
- package/dist/stories/Heading.stories.js +61 -0
- package/dist/stories/Highlight.stories.d.ts +8 -0
- package/dist/stories/Highlight.stories.d.ts.map +1 -0
- package/dist/stories/Highlight.stories.js +19 -0
- package/dist/stories/IconButton.stories.d.ts +10 -0
- package/dist/stories/IconButton.stories.d.ts.map +1 -0
- package/dist/stories/IconButton.stories.js +32 -0
- package/dist/stories/If.stories.d.ts +13 -0
- package/dist/stories/If.stories.d.ts.map +1 -0
- package/dist/stories/If.stories.js +54 -0
- package/dist/stories/Iframe.stories.d.ts +8 -0
- package/dist/stories/Iframe.stories.d.ts.map +1 -0
- package/dist/stories/Iframe.stories.js +23 -0
- package/dist/stories/Item.stories.d.ts +10 -0
- package/dist/stories/Item.stories.d.ts.map +1 -0
- package/dist/stories/Item.stories.js +32 -0
- package/dist/stories/Link.stories.d.ts +10 -0
- package/dist/stories/Link.stories.d.ts.map +1 -0
- package/dist/stories/Link.stories.js +36 -0
- package/dist/stories/ListItem.stories.d.ts +9 -0
- package/dist/stories/ListItem.stories.d.ts.map +1 -0
- package/dist/stories/ListItem.stories.js +25 -0
- package/dist/stories/MarkdownContainer.stories.d.ts +11 -0
- package/dist/stories/MarkdownContainer.stories.d.ts.map +1 -0
- package/dist/stories/MarkdownContainer.stories.js +66 -0
- package/dist/stories/PasswordInput.stories.d.ts +9 -0
- package/dist/stories/PasswordInput.stories.d.ts.map +1 -0
- package/dist/stories/PasswordInput.stories.js +27 -0
- package/dist/stories/Picture.stories.d.ts +10 -0
- package/dist/stories/Picture.stories.d.ts.map +1 -0
- package/dist/stories/Picture.stories.js +46 -0
- package/dist/stories/ProtectedEmail.stories.d.ts +10 -0
- package/dist/stories/ProtectedEmail.stories.d.ts.map +1 -0
- package/dist/stories/ProtectedEmail.stories.js +34 -0
- package/dist/stories/Text.stories.d.ts +10 -0
- package/dist/stories/Text.stories.d.ts.map +1 -0
- package/dist/stories/Text.stories.js +31 -0
- package/dist/stories/UnorderedList.stories.d.ts +10 -0
- package/dist/stories/UnorderedList.stories.d.ts.map +1 -0
- package/dist/stories/UnorderedList.stories.js +24 -0
- package/dist/test-setup.d.ts +2 -0
- package/dist/test-setup.d.ts.map +1 -0
- package/dist/test-setup.js +1 -0
- package/dist/utils/author.d.ts +9 -0
- package/dist/utils/author.d.ts.map +1 -0
- package/dist/utils/author.js +37 -0
- package/dist/utils/author.test.d.ts +2 -0
- package/dist/utils/author.test.d.ts.map +1 -0
- package/dist/utils/author.test.js +46 -0
- package/dist/utils/cn.d.ts +5 -0
- package/dist/utils/cn.d.ts.map +1 -0
- package/dist/utils/cn.js +10 -0
- package/dist/utils/cn.test.d.ts +2 -0
- package/dist/utils/cn.test.d.ts.map +1 -0
- package/dist/utils/cn.test.js +33 -0
- package/dist/utils/is-route-active.d.ts +3 -0
- package/dist/utils/is-route-active.d.ts.map +1 -0
- package/dist/utils/is-route-active.js +54 -0
- package/dist/utils/is-route-active.test.d.ts +2 -0
- package/dist/utils/is-route-active.test.d.ts.map +1 -0
- package/dist/utils/is-route-active.test.js +61 -0
- package/dist/utils/locale.d.ts +22 -0
- package/dist/utils/locale.d.ts.map +1 -0
- package/dist/utils/locale.js +25 -0
- package/dist/utils/locale.test.d.ts +2 -0
- package/dist/utils/locale.test.d.ts.map +1 -0
- package/dist/utils/locale.test.js +99 -0
- package/dist/utils/text.d.ts +7 -0
- package/dist/utils/text.d.ts.map +1 -0
- package/dist/utils/text.js +102 -0
- package/dist/utils/text.test.d.ts +2 -0
- package/dist/utils/text.test.d.ts.map +1 -0
- package/dist/utils/text.test.js +122 -0
- package/package.json +117 -0
- package/src/components/background-slideshow.tsx +172 -0
- package/src/components/blurry-gradient.tsx +97 -0
- package/src/components/box.tsx +45 -0
- package/src/components/carousel.tsx +197 -0
- package/src/components/countdown.tsx +82 -0
- package/src/components/definition-list.tsx +90 -0
- package/src/components/generic-error.tsx +104 -0
- package/src/components/heading.tsx +60 -0
- package/src/components/highlight.tsx +53 -0
- package/src/components/icon-button.tsx +20 -0
- package/src/components/if.tsx +29 -0
- package/src/components/iframe.tsx +19 -0
- package/src/components/item.tsx +340 -0
- package/src/components/leaflet-map.tsx +294 -0
- package/src/components/link.test.tsx +387 -0
- package/src/components/link.tsx +206 -0
- package/src/components/list-item.tsx +30 -0
- package/src/components/maptiler-map.tsx +181 -0
- package/src/components/markdown-container.tsx +153 -0
- package/src/components/password-input.tsx +49 -0
- package/src/components/picture.tsx +107 -0
- package/src/components/protected-email.tsx +49 -0
- package/src/components/text.tsx +38 -0
- package/src/components/unordered-list.tsx +32 -0
- package/src/hooks/use-current-route-data.ts +18 -0
- package/src/hooks/use-focus-search.ts +20 -0
- package/src/hooks/use-matches-data.ts +19 -0
- package/src/hooks/use-media-query.ts +33 -0
- package/src/hooks/use-mobile.ts +19 -0
- package/src/hooks/use-nonce.test.ts +35 -0
- package/src/hooks/use-nonce.ts +20 -0
- package/src/hooks/use-orientation.ts +48 -0
- package/src/hooks/use-user.tsx +72 -0
- package/src/stories/BackgroundSlideshow.stories.tsx +68 -0
- package/src/stories/BlurryGradient.stories.tsx +62 -0
- package/src/stories/Box.stories.tsx +83 -0
- package/src/stories/Carousel.stories.tsx +95 -0
- package/src/stories/Countdown.stories.tsx +16 -0
- package/src/stories/DefinitionList.stories.tsx +51 -0
- package/src/stories/GenericError.stories.tsx +58 -0
- package/src/stories/Heading.stories.tsx +82 -0
- package/src/stories/Highlight.stories.tsx +28 -0
- package/src/stories/IconButton.stories.tsx +90 -0
- package/src/stories/If.stories.tsx +72 -0
- package/src/stories/Iframe.stories.tsx +29 -0
- package/src/stories/Item.stories.tsx +79 -0
- package/src/stories/Link.stories.tsx +58 -0
- package/src/stories/ListItem.stories.tsx +37 -0
- package/src/stories/MarkdownContainer.stories.tsx +76 -0
- package/src/stories/PasswordInput.stories.tsx +34 -0
- package/src/stories/Picture.stories.tsx +54 -0
- package/src/stories/ProtectedEmail.stories.tsx +57 -0
- package/src/stories/Text.stories.tsx +44 -0
- package/src/stories/UnorderedList.stories.tsx +73 -0
- package/src/styles/storybook.css +1 -0
- package/src/styles/tailwind.css +7 -0
- package/src/test-setup.ts +1 -0
- package/src/utils/author.test.ts +54 -0
- package/src/utils/author.tsx +73 -0
- package/src/utils/cn.test.ts +48 -0
- package/src/utils/cn.ts +14 -0
- package/src/utils/is-route-active.test.ts +80 -0
- package/src/utils/is-route-active.ts +100 -0
- package/src/utils/locale.test.ts +148 -0
- package/src/utils/locale.ts +127 -0
- package/src/utils/text.test.ts +152 -0
- package/src/utils/text.tsx +209 -0
- package/src/vite-env.d.ts +1 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import type { ReactElement } from 'react';
|
|
2
|
+
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
3
|
+
import { Picture } from './picture';
|
|
4
|
+
|
|
5
|
+
export type ImageData = {
|
|
6
|
+
at: Record<string, string>; // Alt text in different languages
|
|
7
|
+
fn: string; // File name
|
|
8
|
+
hu: number; // Hue in HSL degrees
|
|
9
|
+
id: string; // ID of the image
|
|
10
|
+
po: boolean; // Whether the image is a placeholder
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export interface BackgroundSlideshowProps {
|
|
14
|
+
baseUrl: string; // URL template with {id} and {format} placeholders
|
|
15
|
+
className?: string; // CSS class for the container
|
|
16
|
+
imgClassName?: string; // CSS class for the image
|
|
17
|
+
locale: string; // Locale for the alt text
|
|
18
|
+
pictureClassName?: string; // CSS class for the picture component
|
|
19
|
+
images: ImageData[]; // Array of images
|
|
20
|
+
filter?: (image: ImageData) => boolean; // Optional filter function
|
|
21
|
+
slideshow?: boolean; // Whether to enable the slideshow
|
|
22
|
+
slideshowInterval?: number; // Time in ms between transitions
|
|
23
|
+
transitionDuration?: number; // Time in ms for the fade transition
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function BackgroundSlideshow({
|
|
27
|
+
baseUrl,
|
|
28
|
+
className = '',
|
|
29
|
+
imgClassName = '',
|
|
30
|
+
locale,
|
|
31
|
+
pictureClassName = '',
|
|
32
|
+
images = [],
|
|
33
|
+
slideshow = true,
|
|
34
|
+
slideshowInterval = 6000,
|
|
35
|
+
transitionDuration = 6000,
|
|
36
|
+
filter,
|
|
37
|
+
}: BackgroundSlideshowProps): ReactElement {
|
|
38
|
+
// Validate images synchronously for immediate first image render
|
|
39
|
+
const validatedImages = useMemo(() => {
|
|
40
|
+
return images
|
|
41
|
+
.map((img) => {
|
|
42
|
+
if (typeof img !== 'object' || img === null) return null;
|
|
43
|
+
return {
|
|
44
|
+
at: img.at || {},
|
|
45
|
+
fn: img.fn || '',
|
|
46
|
+
hu: img.hu || 0,
|
|
47
|
+
id: img.id || '',
|
|
48
|
+
po: img.po || false,
|
|
49
|
+
};
|
|
50
|
+
})
|
|
51
|
+
.filter((img): img is ImageData => img !== null);
|
|
52
|
+
}, [images]);
|
|
53
|
+
|
|
54
|
+
// Get filtered images for slideshow
|
|
55
|
+
const availableImages = useMemo(() => {
|
|
56
|
+
const filtered = filter ? validatedImages.filter(filter) : validatedImages;
|
|
57
|
+
return filtered.length > 0 ? filtered : validatedImages;
|
|
58
|
+
}, [validatedImages, filter]);
|
|
59
|
+
|
|
60
|
+
// First image is shown immediately (no animation needed)
|
|
61
|
+
const firstImage = availableImages[0] || null;
|
|
62
|
+
|
|
63
|
+
// Track if slideshow has started (client-side only)
|
|
64
|
+
const [slideshowStarted, setSlideshowStarted] = useState(false);
|
|
65
|
+
|
|
66
|
+
// The overlay image that fades in over the first image
|
|
67
|
+
const [overlayImage, setOverlayImage] = useState<ImageData | null>(null);
|
|
68
|
+
const [overlayVisible, setOverlayVisible] = useState(false);
|
|
69
|
+
const [currentIndex, setCurrentIndex] = useState(0);
|
|
70
|
+
const timerRef = useRef<number | undefined>(undefined);
|
|
71
|
+
const isTransitioning = useRef(false);
|
|
72
|
+
|
|
73
|
+
// Start slideshow after mount
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
if (!slideshow || availableImages.length <= 1) return;
|
|
76
|
+
|
|
77
|
+
// Delay slideshow start to allow first image to be LCP
|
|
78
|
+
const timeout = window.setTimeout(() => {
|
|
79
|
+
setSlideshowStarted(true);
|
|
80
|
+
}, slideshowInterval);
|
|
81
|
+
|
|
82
|
+
return () => window.clearTimeout(timeout);
|
|
83
|
+
}, [slideshow, availableImages.length, slideshowInterval]);
|
|
84
|
+
|
|
85
|
+
// Run the slideshow cycle
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
if (!slideshowStarted || availableImages.length <= 1) return;
|
|
88
|
+
|
|
89
|
+
// Clear any existing timers
|
|
90
|
+
if (timerRef.current) window.clearTimeout(timerRef.current);
|
|
91
|
+
|
|
92
|
+
const cycleImages = () => {
|
|
93
|
+
if (isTransitioning.current) return;
|
|
94
|
+
|
|
95
|
+
isTransitioning.current = true;
|
|
96
|
+
|
|
97
|
+
// Get next image index
|
|
98
|
+
const nextIdx = (currentIndex + 1) % availableImages.length;
|
|
99
|
+
const nextImage = availableImages[nextIdx];
|
|
100
|
+
|
|
101
|
+
if (!nextImage) {
|
|
102
|
+
isTransitioning.current = false;
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Load next image into overlay (hidden)
|
|
107
|
+
setOverlayImage(nextImage);
|
|
108
|
+
|
|
109
|
+
// Short delay to ensure image starts loading, then fade in
|
|
110
|
+
window.setTimeout(() => {
|
|
111
|
+
setOverlayVisible(true);
|
|
112
|
+
|
|
113
|
+
// After transition completes, update state
|
|
114
|
+
window.setTimeout(() => {
|
|
115
|
+
setCurrentIndex(nextIdx);
|
|
116
|
+
setOverlayVisible(false);
|
|
117
|
+
isTransitioning.current = false;
|
|
118
|
+
|
|
119
|
+
// Schedule next transition
|
|
120
|
+
timerRef.current = window.setTimeout(cycleImages, slideshowInterval);
|
|
121
|
+
}, transitionDuration);
|
|
122
|
+
}, 100);
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
// Start first transition
|
|
126
|
+
cycleImages();
|
|
127
|
+
|
|
128
|
+
return () => {
|
|
129
|
+
if (timerRef.current) window.clearTimeout(timerRef.current);
|
|
130
|
+
};
|
|
131
|
+
}, [slideshowStarted, availableImages, currentIndex, slideshowInterval, transitionDuration]);
|
|
132
|
+
|
|
133
|
+
// If no valid images, return empty div
|
|
134
|
+
if (validatedImages.length === 0 || !firstImage) {
|
|
135
|
+
return <div className={className} />;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Get current base image (first image initially, then cycles)
|
|
139
|
+
const baseImage = availableImages[currentIndex] || firstImage;
|
|
140
|
+
|
|
141
|
+
return (
|
|
142
|
+
<div className={className}>
|
|
143
|
+
{/* Base image - always visible, no fade-in animation */}
|
|
144
|
+
<div className="absolute inset-0 w-full h-full">
|
|
145
|
+
<Picture
|
|
146
|
+
alt={baseImage.at[locale] || ''}
|
|
147
|
+
baseUrl={baseUrl.replace('{id}', baseImage.id).replace('{fn}', baseImage.fn)}
|
|
148
|
+
className={pictureClassName}
|
|
149
|
+
formats={[{ size: '', width: 1080 }]}
|
|
150
|
+
imgClassName={imgClassName}
|
|
151
|
+
placeholder=""
|
|
152
|
+
/>
|
|
153
|
+
</div>
|
|
154
|
+
|
|
155
|
+
{/* Overlay image - fades in over base image during transitions */}
|
|
156
|
+
{overlayImage && (
|
|
157
|
+
<div
|
|
158
|
+
className={`absolute inset-0 w-full h-full transition-opacity ${overlayVisible ? 'opacity-100' : 'opacity-0'} ${transitionDuration <= 3000 ? 'duration-3000' : transitionDuration <= 4000 ? 'duration-4000' : transitionDuration <= 5000 ? 'duration-5000' : 'duration-6000'}`}
|
|
159
|
+
>
|
|
160
|
+
<Picture
|
|
161
|
+
alt={overlayImage.at[locale] || ''}
|
|
162
|
+
baseUrl={baseUrl.replace('{id}', overlayImage.id).replace('{fn}', overlayImage.fn)}
|
|
163
|
+
className={pictureClassName}
|
|
164
|
+
formats={[{ size: '', width: 1080 }]}
|
|
165
|
+
imgClassName={imgClassName}
|
|
166
|
+
placeholder=""
|
|
167
|
+
/>
|
|
168
|
+
</div>
|
|
169
|
+
)}
|
|
170
|
+
</div>
|
|
171
|
+
);
|
|
172
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { SVGProps } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface BlurryGradientProps extends SVGProps<SVGSVGElement> {
|
|
4
|
+
primaryColor: string;
|
|
5
|
+
secondaryColor: string;
|
|
6
|
+
neutralColor: string;
|
|
7
|
+
/**
|
|
8
|
+
* Accessible description for the gradient (for screen readers)
|
|
9
|
+
* @default 'Decorative blurry gradient'
|
|
10
|
+
*/
|
|
11
|
+
description?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const BlurryGradient = (props: BlurryGradientProps) => {
|
|
15
|
+
const { description = 'Decorative blurry gradient', ...svgProps } = props;
|
|
16
|
+
const titleId = 'blurryGradientTitle';
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<svg
|
|
20
|
+
aria-labelledby={titleId}
|
|
21
|
+
preserveAspectRatio="none"
|
|
22
|
+
role="img"
|
|
23
|
+
viewBox="0 0 1000 1000"
|
|
24
|
+
{...svgProps}
|
|
25
|
+
>
|
|
26
|
+
<title id={titleId}>{description}</title>
|
|
27
|
+
<defs>
|
|
28
|
+
<filter
|
|
29
|
+
colorInterpolationFilters="sRGB"
|
|
30
|
+
filterUnits="userSpaceOnUse"
|
|
31
|
+
height="120%"
|
|
32
|
+
width="120%"
|
|
33
|
+
x="-10%"
|
|
34
|
+
y="-10%"
|
|
35
|
+
>
|
|
36
|
+
<feFlood
|
|
37
|
+
floodOpacity="0"
|
|
38
|
+
result="BackgroundImageFix"
|
|
39
|
+
/>
|
|
40
|
+
<feBlend
|
|
41
|
+
in="SourceGraphic"
|
|
42
|
+
in2="BackgroundImageFix"
|
|
43
|
+
mode="normal"
|
|
44
|
+
result="shape"
|
|
45
|
+
/>
|
|
46
|
+
<feGaussianBlur
|
|
47
|
+
result="effect1_foregroundBlur"
|
|
48
|
+
stdDeviation="161"
|
|
49
|
+
/>
|
|
50
|
+
</filter>
|
|
51
|
+
</defs>
|
|
52
|
+
<rect
|
|
53
|
+
fill={props.primaryColor}
|
|
54
|
+
height="1000"
|
|
55
|
+
width="1000"
|
|
56
|
+
/>
|
|
57
|
+
<g filter="url(#blurryGradient)">
|
|
58
|
+
<circle
|
|
59
|
+
cx="730"
|
|
60
|
+
cy="559"
|
|
61
|
+
fill={props.secondaryColor}
|
|
62
|
+
r="357"
|
|
63
|
+
/>
|
|
64
|
+
<circle
|
|
65
|
+
cx="316"
|
|
66
|
+
cy="248"
|
|
67
|
+
fill={props.primaryColor}
|
|
68
|
+
r="357"
|
|
69
|
+
/>
|
|
70
|
+
<circle
|
|
71
|
+
cx="509"
|
|
72
|
+
cy="410"
|
|
73
|
+
fill={props.neutralColor}
|
|
74
|
+
r="357"
|
|
75
|
+
/>
|
|
76
|
+
<circle
|
|
77
|
+
cx="633"
|
|
78
|
+
cy="232"
|
|
79
|
+
fill={props.secondaryColor}
|
|
80
|
+
r="357"
|
|
81
|
+
/>
|
|
82
|
+
<circle
|
|
83
|
+
cx="156"
|
|
84
|
+
cy="82"
|
|
85
|
+
fill={props.primaryColor}
|
|
86
|
+
r="357"
|
|
87
|
+
/>
|
|
88
|
+
<circle
|
|
89
|
+
cx="150"
|
|
90
|
+
cy="389"
|
|
91
|
+
fill={props.neutralColor}
|
|
92
|
+
r="357"
|
|
93
|
+
/>
|
|
94
|
+
</g>
|
|
95
|
+
</svg>
|
|
96
|
+
);
|
|
97
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { ComponentProps, ElementType } from 'react';
|
|
2
|
+
|
|
3
|
+
import { cva, type VariantProps } from '../utils/cn';
|
|
4
|
+
|
|
5
|
+
const box = cva({
|
|
6
|
+
defaultVariants: {
|
|
7
|
+
variant: 'primary',
|
|
8
|
+
},
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
aside: [],
|
|
12
|
+
code: ['font-monospace', 'overflow-scroll'],
|
|
13
|
+
container: ['u-container'],
|
|
14
|
+
flex: ['flex'],
|
|
15
|
+
grid: ['u-grid'],
|
|
16
|
+
main: [],
|
|
17
|
+
primary: [],
|
|
18
|
+
section: ['u-grid', 'content-start'],
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export interface BoxProps extends ComponentProps<'div'>, VariantProps<typeof box> {
|
|
24
|
+
as?: ElementType;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const Box = ({
|
|
28
|
+
as: Component = 'div',
|
|
29
|
+
children,
|
|
30
|
+
className,
|
|
31
|
+
variant,
|
|
32
|
+
...props
|
|
33
|
+
}: BoxProps) => {
|
|
34
|
+
return (
|
|
35
|
+
<Component
|
|
36
|
+
className={box({
|
|
37
|
+
className,
|
|
38
|
+
variant,
|
|
39
|
+
})}
|
|
40
|
+
{...props}
|
|
41
|
+
>
|
|
42
|
+
{children}
|
|
43
|
+
</Component>
|
|
44
|
+
);
|
|
45
|
+
};
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import type { EmblaCarouselType, EmblaOptionsType } from 'embla-carousel';
|
|
2
|
+
import useEmblaCarousel from 'embla-carousel-react';
|
|
3
|
+
import {
|
|
4
|
+
createContext,
|
|
5
|
+
forwardRef,
|
|
6
|
+
type HTMLAttributes,
|
|
7
|
+
type KeyboardEvent,
|
|
8
|
+
useCallback,
|
|
9
|
+
useContext,
|
|
10
|
+
useEffect,
|
|
11
|
+
useState,
|
|
12
|
+
} from 'react';
|
|
13
|
+
import { cn } from '../utils/cn';
|
|
14
|
+
|
|
15
|
+
export type CarouselApi = EmblaCarouselType;
|
|
16
|
+
|
|
17
|
+
interface CarouselContextValue {
|
|
18
|
+
api: CarouselApi | undefined;
|
|
19
|
+
scrollPrev: () => void;
|
|
20
|
+
scrollNext: () => void;
|
|
21
|
+
canScrollPrev: boolean;
|
|
22
|
+
canScrollNext: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const CarouselContext = createContext<CarouselContextValue | null>(null);
|
|
26
|
+
|
|
27
|
+
function useCarousel() {
|
|
28
|
+
const context = useContext(CarouselContext);
|
|
29
|
+
if (!context) {
|
|
30
|
+
throw new Error('useCarousel must be used within a <Carousel />');
|
|
31
|
+
}
|
|
32
|
+
return context;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface CarouselProps extends HTMLAttributes<HTMLDivElement> {
|
|
36
|
+
opts?: EmblaOptionsType;
|
|
37
|
+
setApi?: (api: CarouselApi) => void;
|
|
38
|
+
orientation?: 'horizontal' | 'vertical';
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const Carousel = forwardRef<HTMLDivElement, CarouselProps>(
|
|
42
|
+
({ children, className, opts, orientation = 'horizontal', setApi, ...props }, ref) => {
|
|
43
|
+
const [emblaRef, emblaApi] = useEmblaCarousel({
|
|
44
|
+
...opts,
|
|
45
|
+
axis: orientation === 'horizontal' ? 'x' : 'y',
|
|
46
|
+
});
|
|
47
|
+
const [canScrollPrev, setCanScrollPrev] = useState(false);
|
|
48
|
+
const [canScrollNext, setCanScrollNext] = useState(false);
|
|
49
|
+
|
|
50
|
+
const onSelect = useCallback((api: CarouselApi) => {
|
|
51
|
+
if (!api) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
setCanScrollPrev(api.canScrollPrev());
|
|
55
|
+
setCanScrollNext(api.canScrollNext());
|
|
56
|
+
}, []);
|
|
57
|
+
|
|
58
|
+
const scrollPrev = useCallback(() => {
|
|
59
|
+
emblaApi?.scrollPrev();
|
|
60
|
+
}, [emblaApi]);
|
|
61
|
+
|
|
62
|
+
const scrollNext = useCallback(() => {
|
|
63
|
+
emblaApi?.scrollNext();
|
|
64
|
+
}, [emblaApi]);
|
|
65
|
+
|
|
66
|
+
const handleKeyDown = useCallback(
|
|
67
|
+
(event: KeyboardEvent<HTMLDivElement>) => {
|
|
68
|
+
if (event.key === 'ArrowLeft') {
|
|
69
|
+
event.preventDefault();
|
|
70
|
+
scrollPrev();
|
|
71
|
+
} else if (event.key === 'ArrowRight') {
|
|
72
|
+
event.preventDefault();
|
|
73
|
+
scrollNext();
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
[scrollPrev, scrollNext],
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
if (!emblaApi || !setApi) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
setApi(emblaApi);
|
|
84
|
+
}, [emblaApi, setApi]);
|
|
85
|
+
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
if (!emblaApi) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
onSelect(emblaApi);
|
|
92
|
+
emblaApi.on('reInit', onSelect);
|
|
93
|
+
emblaApi.on('select', onSelect);
|
|
94
|
+
|
|
95
|
+
return () => {
|
|
96
|
+
emblaApi?.off('select', onSelect);
|
|
97
|
+
};
|
|
98
|
+
}, [emblaApi, onSelect]);
|
|
99
|
+
|
|
100
|
+
return (
|
|
101
|
+
<CarouselContext.Provider
|
|
102
|
+
value={{
|
|
103
|
+
api: emblaApi,
|
|
104
|
+
canScrollNext,
|
|
105
|
+
canScrollPrev,
|
|
106
|
+
scrollNext,
|
|
107
|
+
scrollPrev,
|
|
108
|
+
}}
|
|
109
|
+
>
|
|
110
|
+
<section
|
|
111
|
+
aria-label="Carousel"
|
|
112
|
+
aria-roledescription="carousel"
|
|
113
|
+
className={cn('relative', className)}
|
|
114
|
+
onKeyDownCapture={handleKeyDown}
|
|
115
|
+
ref={ref}
|
|
116
|
+
{...props}
|
|
117
|
+
>
|
|
118
|
+
<div ref={emblaRef}>
|
|
119
|
+
<div>{children}</div>
|
|
120
|
+
</div>
|
|
121
|
+
</section>
|
|
122
|
+
</CarouselContext.Provider>
|
|
123
|
+
);
|
|
124
|
+
},
|
|
125
|
+
);
|
|
126
|
+
Carousel.displayName = 'Carousel';
|
|
127
|
+
|
|
128
|
+
const CarouselContent = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
|
129
|
+
({ className, ...props }, ref) => {
|
|
130
|
+
return (
|
|
131
|
+
<div
|
|
132
|
+
className={cn('flex', className)}
|
|
133
|
+
ref={ref}
|
|
134
|
+
{...props}
|
|
135
|
+
/>
|
|
136
|
+
);
|
|
137
|
+
},
|
|
138
|
+
);
|
|
139
|
+
CarouselContent.displayName = 'CarouselContent';
|
|
140
|
+
|
|
141
|
+
interface CarouselItemProps extends HTMLAttributes<HTMLDivElement> {
|
|
142
|
+
'aria-label'?: string;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const CarouselItem = forwardRef<HTMLDivElement, CarouselItemProps>(
|
|
146
|
+
({ className, ...props }, ref) => {
|
|
147
|
+
return (
|
|
148
|
+
// biome-ignore lint/a11y/useSemanticElements: False positive
|
|
149
|
+
<div
|
|
150
|
+
aria-roledescription="slide"
|
|
151
|
+
className={cn('min-w-0 shrink-0 grow-0', className)}
|
|
152
|
+
ref={ref}
|
|
153
|
+
role="group"
|
|
154
|
+
{...props}
|
|
155
|
+
/>
|
|
156
|
+
);
|
|
157
|
+
},
|
|
158
|
+
);
|
|
159
|
+
CarouselItem.displayName = 'CarouselItem';
|
|
160
|
+
|
|
161
|
+
const CarouselPrevious = forwardRef<HTMLButtonElement, HTMLAttributes<HTMLButtonElement>>(
|
|
162
|
+
({ className, ...props }, ref) => {
|
|
163
|
+
const { canScrollPrev, scrollPrev } = useCarousel();
|
|
164
|
+
|
|
165
|
+
return (
|
|
166
|
+
<button
|
|
167
|
+
className={cn('disabled:opacity-50', className)}
|
|
168
|
+
disabled={!canScrollPrev}
|
|
169
|
+
onClick={scrollPrev}
|
|
170
|
+
ref={ref}
|
|
171
|
+
type="button"
|
|
172
|
+
{...props}
|
|
173
|
+
/>
|
|
174
|
+
);
|
|
175
|
+
},
|
|
176
|
+
);
|
|
177
|
+
CarouselPrevious.displayName = 'CarouselPrevious';
|
|
178
|
+
|
|
179
|
+
const CarouselNext = forwardRef<HTMLButtonElement, HTMLAttributes<HTMLButtonElement>>(
|
|
180
|
+
({ className, ...props }, ref) => {
|
|
181
|
+
const { canScrollNext, scrollNext } = useCarousel();
|
|
182
|
+
|
|
183
|
+
return (
|
|
184
|
+
<button
|
|
185
|
+
className={cn('disabled:opacity-50', className)}
|
|
186
|
+
disabled={!canScrollNext}
|
|
187
|
+
onClick={scrollNext}
|
|
188
|
+
ref={ref}
|
|
189
|
+
type="button"
|
|
190
|
+
{...props}
|
|
191
|
+
/>
|
|
192
|
+
);
|
|
193
|
+
},
|
|
194
|
+
);
|
|
195
|
+
CarouselNext.displayName = 'CarouselNext';
|
|
196
|
+
|
|
197
|
+
export { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, useCarousel };
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { cn } from '../utils/cn';
|
|
3
|
+
|
|
4
|
+
export function Countdown() {
|
|
5
|
+
const [timerValue, setTimerValue] = useState(0);
|
|
6
|
+
const [isMounted, setIsMounted] = useState(false);
|
|
7
|
+
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
// Set the mounted flag to true after the component has been mounted
|
|
10
|
+
setIsMounted(true);
|
|
11
|
+
|
|
12
|
+
const intervalId = setInterval(() => {
|
|
13
|
+
setTimerValue((prevValue) => {
|
|
14
|
+
return prevValue + 1;
|
|
15
|
+
});
|
|
16
|
+
}, 1000);
|
|
17
|
+
|
|
18
|
+
return () => {
|
|
19
|
+
return clearInterval(intervalId);
|
|
20
|
+
};
|
|
21
|
+
}, []);
|
|
22
|
+
|
|
23
|
+
// const formattedDate = partyDate.toLocaleDateString(data.locale, {
|
|
24
|
+
// day: '2-digit',
|
|
25
|
+
// month: 'long',
|
|
26
|
+
// year: 'numeric',
|
|
27
|
+
// });
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<div
|
|
31
|
+
className={cn(
|
|
32
|
+
'before:absolute',
|
|
33
|
+
'before:bg-white',
|
|
34
|
+
'before:content-[""]',
|
|
35
|
+
'before:h-[180px]',
|
|
36
|
+
'before:rounded-full',
|
|
37
|
+
'before:w-[180px]',
|
|
38
|
+
'flex',
|
|
39
|
+
'h-[240px]',
|
|
40
|
+
'items-center',
|
|
41
|
+
'justify-center',
|
|
42
|
+
'relative',
|
|
43
|
+
'rounded-full',
|
|
44
|
+
'w-[240px]',
|
|
45
|
+
)}
|
|
46
|
+
style={{
|
|
47
|
+
background: `conic-gradient(
|
|
48
|
+
transparent ${6 * (isMounted ? timerValue : 0)}deg,
|
|
49
|
+
hsl(var(--red-500)) 0deg,
|
|
50
|
+
hsl(var(--red-500)) 15deg,
|
|
51
|
+
hsl(var(--coral-500)) 15deg,
|
|
52
|
+
hsl(var(--coral-500)) 45deg,
|
|
53
|
+
hsl(var(--orange-500)) 45deg,
|
|
54
|
+
hsl(var(--orange-500)) 75deg,
|
|
55
|
+
hsl(var(--yellow-500)) 75deg,
|
|
56
|
+
hsl(var(--yellow-500)) 105deg,
|
|
57
|
+
hsl(var(--olive-500)) 105deg,
|
|
58
|
+
hsl(var(--olive-500)) 135deg,
|
|
59
|
+
hsl(var(--lime-500)) 135deg,
|
|
60
|
+
hsl(var(--lime-500)) 165deg,
|
|
61
|
+
hsl(var(--green-500)) 165deg,
|
|
62
|
+
hsl(var(--green-500)) 195deg,
|
|
63
|
+
hsl(var(--teal-500)) 195deg,
|
|
64
|
+
hsl(var(--teal-500)) 225deg,
|
|
65
|
+
hsl(var(--cyan-500)) 225deg,
|
|
66
|
+
hsl(var(--cyan-500)) 255deg,
|
|
67
|
+
hsl(var(--blue-500)) 255deg,
|
|
68
|
+
hsl(var(--blue-500)) 285deg,
|
|
69
|
+
hsl(var(--purple-500)) 285deg,
|
|
70
|
+
hsl(var(--purple-500)) 315deg,
|
|
71
|
+
hsl(var(--pink-500)) 315deg,
|
|
72
|
+
hsl(var(--pink-500)) 345deg,
|
|
73
|
+
hsl(var(--red-500)) 345deg
|
|
74
|
+
)`,
|
|
75
|
+
}}
|
|
76
|
+
>
|
|
77
|
+
<span className={cn('text-foreground', 'relative', 'text-3xl', 'font-bold')}>
|
|
78
|
+
{isMounted ? (timerValue < 10 ? `0${timerValue}` : timerValue) : 0}
|
|
79
|
+
</span>
|
|
80
|
+
</div>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { ComponentProps } from 'react';
|
|
2
|
+
import { cva, type VariantProps } from '../utils/cn';
|
|
3
|
+
|
|
4
|
+
const dl = cva({
|
|
5
|
+
base: ['grid'],
|
|
6
|
+
defaultVariants: {
|
|
7
|
+
variant: 'primary',
|
|
8
|
+
},
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
primary: ['grid-cols-[auto,1fr]', 'gap-x-s', 'gap-y-2xs'], // Two-column grid with gap
|
|
12
|
+
unstyled: ['list-none', 'p-0', 'grid-cols-1'], // Unstyled, single column
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const dt = cva({
|
|
18
|
+
base: [],
|
|
19
|
+
defaultVariants: {
|
|
20
|
+
variant: 'primary',
|
|
21
|
+
},
|
|
22
|
+
variants: {
|
|
23
|
+
variant: {
|
|
24
|
+
primary: ['uppercase', 'tracking-wide'],
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const dd = cva({
|
|
30
|
+
base: ['mb-xs'],
|
|
31
|
+
defaultVariants: {
|
|
32
|
+
variant: 'primary',
|
|
33
|
+
},
|
|
34
|
+
variants: {
|
|
35
|
+
variant: {
|
|
36
|
+
primary: [],
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
export interface DefinitionListProps extends ComponentProps<'dl'>, VariantProps<typeof dl> {}
|
|
42
|
+
|
|
43
|
+
export interface DtProps extends ComponentProps<'dt'>, VariantProps<typeof dt> {}
|
|
44
|
+
|
|
45
|
+
export interface DdProps extends ComponentProps<'dd'>, VariantProps<typeof dd> {}
|
|
46
|
+
|
|
47
|
+
export const DefinitionList = (props: DefinitionListProps) => {
|
|
48
|
+
const { children, className, variant } = props;
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<dl
|
|
52
|
+
className={dl({
|
|
53
|
+
className,
|
|
54
|
+
variant,
|
|
55
|
+
})}
|
|
56
|
+
>
|
|
57
|
+
{children}
|
|
58
|
+
</dl>
|
|
59
|
+
);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const Dt = (props: DtProps) => {
|
|
63
|
+
const { children, className, variant } = props;
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<dt
|
|
67
|
+
className={dt({
|
|
68
|
+
className,
|
|
69
|
+
variant,
|
|
70
|
+
})}
|
|
71
|
+
>
|
|
72
|
+
{children}
|
|
73
|
+
</dt>
|
|
74
|
+
);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export const Dd = (props: DdProps) => {
|
|
78
|
+
const { children, className, variant } = props;
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<dd
|
|
82
|
+
className={dd({
|
|
83
|
+
className,
|
|
84
|
+
variant,
|
|
85
|
+
})}
|
|
86
|
+
>
|
|
87
|
+
{children}
|
|
88
|
+
</dd>
|
|
89
|
+
);
|
|
90
|
+
};
|