xertica-ui 2.2.1 → 2.4.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/CHANGELOG.md +564 -525
- package/README.md +417 -382
- package/bin/cli.ts +1244 -748
- package/bin/generate-tokens.ts +262 -262
- package/bin/language-config.ts +5 -8
- package/components/assets/xertica-orbe-animation.ts +1162 -1162
- package/components/assistant/code-block/CodeBlock.tsx +268 -268
- package/components/assistant/code-block/code-block.stories.tsx +57 -57
- package/components/assistant/code-block/code-block.test.tsx +44 -44
- package/components/assistant/code-block/index.ts +1 -1
- package/components/assistant/formatted-document/FormattedDocument.tsx +147 -147
- package/components/assistant/formatted-document/formatted-document.stories.tsx +51 -51
- package/components/assistant/formatted-document/formatted-document.test.tsx +42 -42
- package/components/assistant/formatted-document/index.ts +1 -1
- package/components/assistant/index.ts +6 -6
- package/components/assistant/markdown-message/MarkdownMessage.tsx +152 -152
- package/components/assistant/markdown-message/index.ts +1 -1
- package/components/assistant/markdown-message/markdown-message.stories.tsx +50 -50
- package/components/assistant/markdown-message/markdown-message.test.tsx +33 -33
- package/components/assistant/modern-chat-input/ModernChatInput.tsx +17 -7
- package/components/assistant/modern-chat-input/index.ts +1 -1
- package/components/assistant/modern-chat-input/modern-chat-input.stories.tsx +131 -131
- package/components/assistant/modern-chat-input/modern-chat-input.test.tsx +79 -79
- package/components/assistant/xertica-assistant/index.ts +3 -3
- package/components/assistant/xertica-assistant/parts/AssistantCollapsedView.tsx +99 -99
- package/components/assistant/xertica-assistant/parts/AssistantConversationList.tsx +104 -106
- package/components/assistant/xertica-assistant/parts/AssistantDocumentEditor.tsx +81 -81
- package/components/assistant/xertica-assistant/parts/AssistantFeedbackDialog.tsx +88 -78
- package/components/assistant/xertica-assistant/parts/AssistantHeader.tsx +75 -75
- package/components/assistant/xertica-assistant/parts/AssistantMessageBubble.tsx +564 -560
- package/components/assistant/xertica-assistant/parts/AssistantTabBar.tsx +67 -67
- package/components/assistant/xertica-assistant/parts/AssistantTypingIndicator.tsx +41 -41
- package/components/assistant/xertica-assistant/parts/AssistantWelcomeScreen.tsx +103 -103
- package/components/assistant/xertica-assistant/parts/index.ts +16 -16
- package/components/assistant/xertica-assistant/types.ts +134 -134
- package/components/assistant/xertica-assistant/use-assistant.ts +615 -615
- package/components/assistant/xertica-assistant/xertica-assistant.stories.tsx +407 -407
- package/components/assistant/xertica-assistant/xertica-assistant.test.tsx +65 -65
- package/components/assistant/xertica-assistant/xertica-assistant.tsx +611 -613
- package/components/blocks/card-patterns/ActivityCard.tsx +100 -100
- package/components/blocks/card-patterns/FeatureCard.tsx +109 -109
- package/components/blocks/card-patterns/FeatureCardSkeleton.tsx +1 -6
- package/components/blocks/card-patterns/NotificationCard.tsx +140 -140
- package/components/blocks/card-patterns/ProfileCard.tsx +112 -114
- package/components/blocks/card-patterns/ProjectCard.tsx +123 -123
- package/components/blocks/card-patterns/ProjectCardSkeleton.tsx +1 -6
- package/components/blocks/card-patterns/QuickActionCard.tsx +68 -68
- package/components/blocks/card-patterns/card-patterns.mdx +123 -123
- package/components/blocks/card-patterns/card-patterns.stories.tsx +594 -594
- package/components/blocks/card-patterns/index.ts +29 -29
- package/components/blocks/index.ts +1 -1
- package/components/brand/branding/branding.stories.tsx +57 -57
- package/components/brand/index.ts +6 -6
- package/components/brand/language-selector/index.ts +1 -1
- package/components/brand/language-selector/language-selector.mdx +126 -126
- package/components/brand/language-selector/language-selector.stories.tsx +1 -4
- package/components/brand/theme-toggle/ThemeToggle.tsx +74 -70
- package/components/brand/theme-toggle/index.ts +1 -1
- package/components/brand/theme-toggle/theme-toggle.stories.tsx +34 -34
- package/components/brand/theme-toggle/theme-toggle.test.tsx +34 -34
- package/components/brand/xertica-logo/XerticaLogo.stories.tsx +82 -82
- package/components/brand/xertica-logo/XerticaLogo.tsx +104 -104
- package/components/brand/xertica-logo/index.ts +1 -1
- package/components/brand/xertica-logo/xertica-logo.test.tsx +26 -26
- package/components/brand/xertica-orbe/XerticaOrbe.tsx +1927 -1927
- package/components/brand/xertica-orbe/index.ts +1 -1
- package/components/brand/xertica-orbe/xertica-orbe.stories.tsx +40 -40
- package/components/brand/xertica-orbe/xertica-orbe.test.tsx +19 -19
- package/components/brand/xertica-provider/XerticaProvider.tsx +1 -4
- package/components/brand/xertica-provider/index.ts +1 -1
- package/components/brand/xertica-provider/xertica-provider.test.tsx +74 -74
- package/components/brand/xertica-xlogo/XerticaXLogo.stories.tsx +79 -79
- package/components/brand/xertica-xlogo/XerticaXLogo.tsx +65 -65
- package/components/brand/xertica-xlogo/index.ts +1 -1
- package/components/brand/xertica-xlogo/xertica-xlogo.test.tsx +16 -16
- package/components/examples/ApiKeyMapExample.tsx +71 -71
- package/components/examples/DrawingMapExample.tsx +565 -565
- package/components/examples/FilterableMapExample.tsx +393 -393
- package/components/examples/LocationPickerExample.tsx +348 -348
- package/components/examples/MapExamples.tsx +268 -268
- package/components/examples/MapGmpExample.tsx +169 -169
- package/components/examples/MapShowcase.tsx +471 -471
- package/components/examples/RouteMapExamples.tsx +329 -329
- package/components/examples/SidebarLogoExample.tsx +65 -65
- package/components/examples/SimpleFilterableMap.tsx +219 -219
- package/components/examples/index.ts +45 -45
- package/components/figma/ImageWithFallback.tsx +27 -27
- package/components/hooks/index.ts +13 -13
- package/components/hooks/use-layout-shortcuts.ts +43 -43
- package/components/index.ts +86 -90
- package/components/layout/header/header.stories.tsx +204 -204
- package/components/layout/header/header.test.tsx +75 -75
- package/components/layout/header/header.tsx +349 -349
- package/components/layout/header/index.ts +1 -1
- package/components/layout/index.ts +2 -2
- package/components/layout/sidebar/index.ts +3 -3
- package/components/layout/sidebar/sidebar.stories.tsx +586 -586
- package/components/layout/sidebar/sidebar.test.tsx +76 -76
- package/components/layout/sidebar/sidebar.tsx +1079 -1073
- package/components/layout/sidebar/use-sidebar.ts +104 -104
- package/components/media/FloatingMediaWrapper.tsx +371 -371
- package/components/media/audio-player/AudioPlayer.stories.tsx +124 -124
- package/components/media/audio-player/AudioPlayer.test.tsx +106 -106
- package/components/media/audio-player/AudioPlayer.tsx +767 -765
- package/components/media/audio-player/index.ts +1 -1
- package/components/media/audio-player/use-audio-player.ts +312 -312
- package/components/media/index.ts +3 -3
- package/components/media/video-player/VideoPlayer.stories.tsx +98 -98
- package/components/media/video-player/VideoPlayer.test.tsx +73 -73
- package/components/media/video-player/VideoPlayer.tsx +310 -310
- package/components/media/video-player/index.ts +1 -1
- package/components/pages/forgot-password-page/ForgotPasswordPage.stories.tsx +24 -24
- package/components/pages/forgot-password-page/ForgotPasswordPage.tsx +188 -188
- package/components/pages/forgot-password-page/forgot-password-page.test.tsx +45 -45
- package/components/pages/forgot-password-page/index.ts +1 -1
- package/components/pages/home-content/HomeContent.stories.tsx +43 -43
- package/components/pages/home-content/HomeContent.tsx +120 -120
- package/components/pages/home-content/index.ts +1 -1
- package/components/pages/home-page/HomePage.stories.tsx +39 -39
- package/components/pages/home-page/HomePage.tsx +78 -74
- package/components/pages/home-page/home-page.test.tsx +53 -53
- package/components/pages/home-page/index.ts +1 -1
- package/components/pages/index.ts +8 -8
- package/components/pages/login-page/LoginPage.stories.tsx +39 -39
- package/components/pages/login-page/LoginPage.tsx +218 -216
- package/components/pages/login-page/index.ts +1 -1
- package/components/pages/login-page/login-page.test.tsx +63 -63
- package/components/pages/reset-password-page/ResetPasswordPage.stories.tsx +24 -24
- package/components/pages/reset-password-page/ResetPasswordPage.tsx +243 -239
- package/components/pages/reset-password-page/index.ts +1 -1
- package/components/pages/template-content/TemplateContent.stories.tsx +43 -43
- package/components/pages/template-content/TemplateContent.tsx +1354 -1235
- package/components/pages/template-content/index.ts +1 -1
- package/components/pages/template-page/TemplatePage.stories.tsx +39 -39
- package/components/pages/template-page/TemplatePage.tsx +62 -62
- package/components/pages/template-page/index.ts +1 -1
- package/components/pages/template-page/template-page.test.tsx +52 -52
- package/components/pages/verify-email-page/VerifyEmailPage.stories.tsx +41 -41
- package/components/pages/verify-email-page/VerifyEmailPage.tsx +206 -206
- package/components/pages/verify-email-page/index.ts +1 -1
- package/components/public-api-smoke.test.tsx +52 -52
- package/components/shared/CustomTooltipContent.tsx +48 -48
- package/components/shared/assistant-utils.test.ts +16 -16
- package/components/shared/assistant-utils.ts +225 -225
- package/components/shared/error-boundary.stories.tsx +114 -132
- package/components/shared/error-boundary.tsx +150 -154
- package/components/shared/error-fallbacks.tsx +222 -226
- package/components/shared/layout-constants.ts +8 -8
- package/components/shared/navigation.ts +35 -35
- package/components/shared/use-mobile.test.ts +16 -16
- package/components/shared/use-mobile.ts +36 -36
- package/components/shared/utils.test.ts +14 -14
- package/components/shared/utils.ts +6 -6
- package/components/ui/accordion/accordion.stories.tsx +105 -105
- package/components/ui/accordion/accordion.test.tsx +59 -59
- package/components/ui/accordion/accordion.tsx +77 -77
- package/components/ui/accordion/index.ts +1 -1
- package/components/ui/alert/alert.stories.tsx +86 -86
- package/components/ui/alert/alert.test.tsx +53 -53
- package/components/ui/alert/alert.tsx +93 -93
- package/components/ui/alert/index.ts +1 -1
- package/components/ui/alert-dialog/alert-dialog.stories.tsx +84 -84
- package/components/ui/alert-dialog/alert-dialog.test.tsx +70 -70
- package/components/ui/alert-dialog/alert-dialog.tsx +149 -149
- package/components/ui/alert-dialog/index.ts +1 -1
- package/components/ui/aspect-ratio/aspect-ratio.stories.tsx +46 -46
- package/components/ui/aspect-ratio/aspect-ratio.test.tsx +28 -28
- package/components/ui/aspect-ratio/aspect-ratio.tsx +20 -20
- package/components/ui/aspect-ratio/index.ts +1 -1
- package/components/ui/assistant-chart/AssistantChart.tsx +64 -64
- package/components/ui/assistant-chart/assistant-chart.stories.tsx +44 -44
- package/components/ui/assistant-chart/assistant-chart.test.tsx +46 -46
- package/components/ui/assistant-chart/index.ts +1 -1
- package/components/ui/avatar/avatar.stories.tsx +86 -86
- package/components/ui/avatar/avatar.test.tsx +55 -55
- package/components/ui/avatar/avatar.tsx +71 -71
- package/components/ui/avatar/index.ts +1 -1
- package/components/ui/badge/badge.stories.tsx +72 -72
- package/components/ui/badge/badge.test.tsx +40 -40
- package/components/ui/badge/badge.tsx +58 -58
- package/components/ui/badge/index.ts +1 -1
- package/components/ui/breadcrumb/breadcrumb.stories.tsx +123 -123
- package/components/ui/breadcrumb/breadcrumb.test.tsx +70 -70
- package/components/ui/breadcrumb/breadcrumb.tsx +114 -114
- package/components/ui/breadcrumb/index.ts +1 -1
- package/components/ui/button/button.stories.tsx +183 -183
- package/components/ui/button/button.test.tsx +64 -64
- package/components/ui/button/button.tsx +98 -98
- package/components/ui/button/index.ts +1 -1
- package/components/ui/calendar/calendar.stories.tsx +108 -108
- package/components/ui/calendar/calendar.test.tsx +53 -53
- package/components/ui/calendar/calendar.tsx +230 -230
- package/components/ui/calendar/index.ts +1 -1
- package/components/ui/card/card.stories.tsx +301 -301
- package/components/ui/card/card.test.tsx +55 -55
- package/components/ui/card/card.tsx +83 -83
- package/components/ui/card/index.ts +1 -1
- package/components/ui/carousel/carousel.stories.tsx +80 -80
- package/components/ui/carousel/carousel.test.tsx +75 -75
- package/components/ui/carousel/carousel.tsx +242 -242
- package/components/ui/carousel/index.ts +1 -1
- package/components/ui/chart/chart.stories.tsx +1328 -1328
- package/components/ui/chart/chart.test.tsx +178 -178
- package/components/ui/chart/chart.tsx +2232 -2232
- package/components/ui/chart/index.ts +1 -1
- package/components/ui/checkbox/checkbox.stories.tsx +109 -109
- package/components/ui/checkbox/checkbox.test.tsx +49 -49
- package/components/ui/checkbox/checkbox.tsx +68 -68
- package/components/ui/checkbox/index.ts +1 -1
- package/components/ui/collapsible/collapsible.stories.tsx +45 -45
- package/components/ui/collapsible/collapsible.test.tsx +51 -51
- package/components/ui/collapsible/collapsible.tsx +32 -32
- package/components/ui/collapsible/index.ts +1 -1
- package/components/ui/command/command.stories.tsx +134 -134
- package/components/ui/command/command.test.tsx +48 -48
- package/components/ui/command/command.tsx +163 -163
- package/components/ui/command/index.ts +1 -1
- package/components/ui/context-menu/context-menu.stories.tsx +76 -76
- package/components/ui/context-menu/context-menu.test.tsx +61 -61
- package/components/ui/context-menu/context-menu.tsx +236 -236
- package/components/ui/context-menu/index.ts +1 -1
- package/components/ui/dialog/dialog.stories.tsx +174 -174
- package/components/ui/dialog/dialog.test.tsx +78 -78
- package/components/ui/dialog/dialog.tsx +189 -189
- package/components/ui/dialog/index.ts +1 -1
- package/components/ui/drawer/drawer.stories.tsx +71 -71
- package/components/ui/drawer/drawer.test.tsx +67 -67
- package/components/ui/drawer/drawer.tsx +146 -146
- package/components/ui/drawer/index.ts +1 -1
- package/components/ui/dropdown-menu/dropdown-menu.stories.tsx +156 -156
- package/components/ui/dropdown-menu/dropdown-menu.test.tsx +62 -62
- package/components/ui/dropdown-menu/dropdown-menu.tsx +240 -240
- package/components/ui/dropdown-menu/index.ts +1 -1
- package/components/ui/empty/empty.stories.tsx +85 -85
- package/components/ui/empty/empty.test.tsx +31 -31
- package/components/ui/empty/empty.tsx +88 -88
- package/components/ui/empty/index.ts +1 -1
- package/components/ui/file-upload/file-upload.stories.tsx +144 -144
- package/components/ui/file-upload/file-upload.test.tsx +65 -65
- package/components/ui/file-upload/file-upload.tsx +142 -142
- package/components/ui/file-upload/index.ts +2 -2
- package/components/ui/file-upload/use-file-upload.ts +177 -177
- package/components/ui/form/form.stories.tsx +85 -85
- package/components/ui/form/form.test.tsx +75 -75
- package/components/ui/form/form.tsx +163 -163
- package/components/ui/form/index.ts +1 -1
- package/components/ui/google-maps-loader/google-maps-loader.test.tsx +35 -35
- package/components/ui/google-maps-loader/google-maps-loader.tsx +465 -465
- package/components/ui/google-maps-loader/index.ts +1 -1
- package/components/ui/hover-card/hover-card.stories.tsx +61 -61
- package/components/ui/hover-card/hover-card.test.tsx +48 -48
- package/components/ui/hover-card/hover-card.tsx +50 -50
- package/components/ui/hover-card/index.ts +1 -1
- package/components/ui/index.ts +400 -400
- package/components/ui/input/index.ts +1 -1
- package/components/ui/input/input.stories.tsx +153 -153
- package/components/ui/input/input.test.tsx +47 -47
- package/components/ui/input/input.tsx +57 -57
- package/components/ui/input-otp/index.ts +1 -1
- package/components/ui/input-otp/input-otp.stories.tsx +120 -120
- package/components/ui/input-otp/input-otp.test.tsx +74 -74
- package/components/ui/input-otp/input-otp.tsx +101 -101
- package/components/ui/label/index.ts +1 -1
- package/components/ui/label/label.stories.tsx +74 -74
- package/components/ui/label/label.test.tsx +45 -45
- package/components/ui/label/label.tsx +53 -53
- package/components/ui/map/index.ts +1 -1
- package/components/ui/map/map.stories.tsx +86 -86
- package/components/ui/map/map.test.tsx +82 -82
- package/components/ui/map/map.tsx +506 -506
- package/components/ui/map/mock.test.tsx +13 -13
- package/components/ui/map-config/index.ts +1 -1
- package/components/ui/map-config/map-config.ts +18 -18
- package/components/ui/map-layers/index.ts +1 -1
- package/components/ui/map-layers/map-layers.test.tsx +48 -48
- package/components/ui/map-layers/map-layers.tsx +126 -126
- package/components/ui/map.exports/index.ts +1 -1
- package/components/ui/map.exports/map.exports.ts +31 -31
- package/components/ui/menubar/index.ts +1 -1
- package/components/ui/menubar/menubar.stories.tsx +130 -130
- package/components/ui/menubar/menubar.test.tsx +53 -53
- package/components/ui/menubar/menubar.tsx +265 -265
- package/components/ui/navigation-menu/index.ts +1 -1
- package/components/ui/navigation-menu/navigation-menu.stories.tsx +126 -126
- package/components/ui/navigation-menu/navigation-menu.test.tsx +47 -47
- package/components/ui/navigation-menu/navigation-menu.tsx +165 -165
- package/components/ui/notification-badge/index.ts +1 -1
- package/components/ui/notification-badge/notification-badge.stories.tsx +66 -66
- package/components/ui/notification-badge/notification-badge.test.tsx +61 -61
- package/components/ui/notification-badge/notification-badge.tsx +91 -91
- package/components/ui/page-header/index.ts +1 -1
- package/components/ui/page-header/page-header.stories.tsx +69 -69
- package/components/ui/page-header/page-header.test.tsx +37 -37
- package/components/ui/page-header/page-header.tsx +124 -124
- package/components/ui/pagination/index.ts +3 -3
- package/components/ui/pagination/pagination.stories.tsx +210 -210
- package/components/ui/pagination/pagination.test.tsx +63 -63
- package/components/ui/pagination/pagination.tsx +140 -140
- package/components/ui/pagination/use-pagination.ts +173 -173
- package/components/ui/popover/index.ts +1 -1
- package/components/ui/popover/popover.stories.tsx +73 -73
- package/components/ui/popover/popover.test.tsx +48 -48
- package/components/ui/popover/popover.tsx +54 -54
- package/components/ui/progress/index.ts +1 -1
- package/components/ui/progress/progress.stories.tsx +55 -55
- package/components/ui/progress/progress.test.tsx +23 -23
- package/components/ui/progress/progress.tsx +68 -68
- package/components/ui/radio-group/index.ts +1 -1
- package/components/ui/radio-group/radio-group.stories.tsx +114 -114
- package/components/ui/radio-group/radio-group.test.tsx +78 -78
- package/components/ui/radio-group/radio-group.tsx +93 -93
- package/components/ui/rating/index.ts +1 -1
- package/components/ui/rating/rating.stories.tsx +50 -50
- package/components/ui/rating/rating.test.tsx +48 -48
- package/components/ui/rating/rating.tsx +145 -145
- package/components/ui/resizable/index.ts +1 -1
- package/components/ui/resizable/resizable.stories.tsx +88 -88
- package/components/ui/resizable/resizable.test.tsx +61 -61
- package/components/ui/resizable/resizable.tsx +452 -452
- package/components/ui/rich-text-editor/index.ts +7 -7
- package/components/ui/rich-text-editor/rich-text-editor.stories.tsx +290 -290
- package/components/ui/rich-text-editor/rich-text-editor.test.tsx +86 -86
- package/components/ui/rich-text-editor/rich-text-editor.tsx +634 -634
- package/components/ui/rich-text-editor/use-rich-text-editor.ts +453 -453
- package/components/ui/route-map/index.ts +1 -1
- package/components/ui/route-map/route-map.stories.tsx +48 -48
- package/components/ui/route-map/route-map.test.tsx +108 -108
- package/components/ui/route-map/route-map.tsx +349 -349
- package/components/ui/scroll-area/index.ts +1 -1
- package/components/ui/scroll-area/scroll-area.stories.tsx +31 -31
- package/components/ui/scroll-area/scroll-area.test.tsx +27 -27
- package/components/ui/scroll-area/scroll-area.tsx +70 -70
- package/components/ui/search/index.ts +1 -1
- package/components/ui/search/search.stories.tsx +107 -107
- package/components/ui/search/search.test.tsx +67 -67
- package/components/ui/search/search.tsx +141 -141
- package/components/ui/select/index.ts +1 -1
- package/components/ui/select/select.stories.tsx +163 -163
- package/components/ui/select/select.test.tsx +99 -99
- package/components/ui/select/select.tsx +195 -195
- package/components/ui/separator/index.ts +1 -1
- package/components/ui/separator/separator.stories.tsx +55 -55
- package/components/ui/separator/separator.test.tsx +23 -23
- package/components/ui/separator/separator.tsx +39 -39
- package/components/ui/sheet/index.ts +1 -1
- package/components/ui/sheet/sheet.stories.tsx +93 -93
- package/components/ui/sheet/sheet.test.tsx +62 -62
- package/components/ui/sheet/sheet.tsx +149 -149
- package/components/ui/simple-map/index.ts +1 -1
- package/components/ui/simple-map/simple-map.stories.tsx +44 -44
- package/components/ui/simple-map/simple-map.test.tsx +36 -36
- package/components/ui/simple-map/simple-map.tsx +92 -92
- package/components/ui/skeleton/index.ts +1 -1
- package/components/ui/skeleton/skeleton.stories.tsx +36 -36
- package/components/ui/skeleton/skeleton.test.tsx +19 -19
- package/components/ui/skeleton/skeleton.tsx +25 -25
- package/components/ui/slider/index.ts +1 -1
- package/components/ui/slider/slider.stories.tsx +44 -44
- package/components/ui/slider/slider.test.tsx +25 -25
- package/components/ui/slider/slider.tsx +66 -66
- package/components/ui/sonner/index.ts +1 -1
- package/components/ui/sonner/sonner.stories.tsx +41 -41
- package/components/ui/sonner/sonner.test.tsx +24 -24
- package/components/ui/sonner/sonner.tsx +74 -74
- package/components/ui/stats-card/index.ts +2 -2
- package/components/ui/stats-card/stats-card-skeleton.tsx +1 -3
- package/components/ui/stats-card/stats-card.stories.tsx +99 -99
- package/components/ui/stats-card/stats-card.test.tsx +34 -34
- package/components/ui/stats-card/stats-card.tsx +93 -93
- package/components/ui/stepper/index.ts +3 -3
- package/components/ui/stepper/stepper.stories.tsx +171 -171
- package/components/ui/stepper/stepper.test.tsx +47 -47
- package/components/ui/stepper/stepper.tsx +190 -190
- package/components/ui/stepper/use-stepper.ts +139 -139
- package/components/ui/switch/index.ts +1 -1
- package/components/ui/switch/switch.stories.tsx +93 -93
- package/components/ui/switch/switch.test.tsx +44 -44
- package/components/ui/switch/switch.tsx +70 -70
- package/components/ui/table/index.ts +1 -1
- package/components/ui/table/table.stories.tsx +114 -114
- package/components/ui/table/table.test.tsx +43 -43
- package/components/ui/table/table.tsx +104 -104
- package/components/ui/tabs/index.ts +1 -1
- package/components/ui/tabs/tabs.stories.tsx +140 -140
- package/components/ui/tabs/tabs.test.tsx +50 -50
- package/components/ui/tabs/tabs.tsx +66 -66
- package/components/ui/textarea/index.ts +1 -1
- package/components/ui/textarea/textarea.stories.tsx +69 -69
- package/components/ui/textarea/textarea.test.tsx +41 -41
- package/components/ui/textarea/textarea.tsx +61 -61
- package/components/ui/timeline/index.ts +1 -1
- package/components/ui/timeline/timeline.stories.tsx +97 -97
- package/components/ui/timeline/timeline.test.tsx +53 -53
- package/components/ui/timeline/timeline.tsx +124 -124
- package/components/ui/toggle/index.ts +1 -1
- package/components/ui/toggle/toggle.stories.tsx +56 -56
- package/components/ui/toggle/toggle.test.tsx +32 -32
- package/components/ui/toggle/toggle.tsx +55 -55
- package/components/ui/toggle-group/index.ts +1 -1
- package/components/ui/toggle-group/toggle-group.stories.tsx +66 -66
- package/components/ui/toggle-group/toggle-group.test.tsx +47 -47
- package/components/ui/toggle-group/toggle-group.tsx +79 -79
- package/components/ui/tooltip/index.ts +1 -1
- package/components/ui/tooltip/tooltip.stories.tsx +83 -83
- package/components/ui/tooltip/tooltip.test.tsx +39 -39
- package/components/ui/tooltip/tooltip.tsx +69 -69
- package/components/ui/tree-view/index.ts +4 -4
- package/components/ui/tree-view/tree-view.stories.tsx +154 -154
- package/components/ui/tree-view/tree-view.test.tsx +58 -58
- package/components/ui/tree-view/tree-view.tsx +171 -171
- package/components/ui/tree-view/use-tree-view.ts +237 -237
- package/components.json +892 -892
- package/contexts/ApiKeyContext.test.tsx +26 -26
- package/contexts/ApiKeyContext.tsx +196 -196
- package/contexts/AssistenteContext.test.tsx +17 -17
- package/contexts/AssistenteContext.tsx +113 -113
- package/contexts/AuthContext.tsx +121 -118
- package/contexts/BrandColorsContext.test.tsx +21 -21
- package/contexts/BrandColorsContext.tsx +251 -251
- package/contexts/LanguageContext.tsx +1 -2
- package/contexts/LayoutContext.test.tsx +29 -29
- package/contexts/LayoutContext.tsx +140 -140
- package/contexts/ThemeContext.test.tsx +38 -38
- package/contexts/ThemeContext.tsx +111 -111
- package/contexts/index.ts +8 -8
- package/contexts/theme-data.ts +340 -340
- package/dist/AssistantChart-COGiOV-g.cjs +3541 -0
- package/dist/AssistantChart-CWX1OWNM.js +3373 -0
- package/dist/AudioPlayer-9psiEucT.cjs +1282 -0
- package/dist/AudioPlayer-Dp2bD1Gk.js +1278 -0
- package/dist/BrandColorsContext-DZT7JjeD.js +659 -0
- package/dist/BrandColorsContext-awnBCmC4.cjs +666 -0
- package/dist/CodeBlock-DYkTfR0f.js +221 -0
- package/dist/CodeBlock-EOvp9cVu.cjs +223 -0
- package/dist/CustomTooltipContent-BhdIeBEg.cjs +54 -0
- package/dist/CustomTooltipContent-CNbVB2NS.js +33 -0
- package/dist/FeatureCard-BZ4CYxFf.cjs +497 -0
- package/dist/FeatureCard-DNycVGwT.js +485 -0
- package/dist/FeatureCardSkeleton-DZqc96mt.js +27 -0
- package/dist/FeatureCardSkeleton-pTa0YNKP.cjs +29 -0
- package/dist/LayoutContext-BEq_-n98.cjs +96 -0
- package/dist/LayoutContext-DNl1xSoX.js +92 -0
- package/dist/ThemeContext-CMD3z2Dz.cjs +1930 -0
- package/dist/ThemeContext-x_F2zsnv.js +1923 -0
- package/dist/VerifyEmailPage-BJjAMUTW.js +3223 -0
- package/dist/VerifyEmailPage-Bv8Ah_TK.cjs +3235 -0
- package/dist/VerifyEmailPage-CkBYfsNy.cjs +3232 -0
- package/dist/VerifyEmailPage-Cyl55sJb.js +3226 -0
- package/dist/VerifyEmailPage-X14vhdyl.js +3296 -0
- package/dist/VerifyEmailPage-u_Dn7t1U.cjs +3305 -0
- package/dist/XerticaOrbe-Uk2JML1-.cjs +1927 -0
- package/dist/XerticaOrbe-jA5T2iOk.js +1925 -0
- package/dist/XerticaProvider-BErr83Bg.js +42 -0
- package/dist/XerticaProvider-CwOkHxiT.cjs +44 -0
- package/dist/XerticaProvider-DUOJg9iX.js +49 -0
- package/dist/XerticaProvider-Dl_b72_l.cjs +51 -0
- package/dist/XerticaXLogo-BX3ueACh.js +255 -0
- package/dist/XerticaXLogo-mqjoBiLI.js +252 -0
- package/dist/XerticaXLogo-qBPhwK3g.cjs +260 -0
- package/dist/XerticaXLogo-uQgwns_E.cjs +257 -0
- package/dist/alert-dialog-DhwPioBa.cjs +885 -0
- package/dist/alert-dialog-DqlRW_An.js +831 -0
- package/dist/assistant.cjs.js +8 -4
- package/dist/assistant.es.js +5 -11
- package/dist/avatar-3kO2Anrp.js +54 -0
- package/dist/avatar-BCM7YQRC.cjs +77 -0
- package/dist/blocks.cjs.js +9 -4
- package/dist/blocks.es.js +2 -16
- package/dist/brand.cjs.js +10 -5
- package/dist/brand.es.js +3 -11
- package/dist/breadcrumb-BKtHF4gk.cjs +98 -0
- package/dist/breadcrumb-ifNsA7Zl.js +90 -0
- package/dist/button-0BlA47It.cjs +85 -0
- package/dist/button-DZHzN1Gd.js +62 -0
- package/dist/cli.js +471 -93
- package/dist/components/brand/theme-toggle/ThemeToggle.d.ts +1 -1
- package/dist/components/index.d.ts +1 -1
- package/dist/dropdown-menu-BMcykFDf.cjs +225 -0
- package/dist/dropdown-menu-Dn_eV2Xb.js +190 -0
- package/dist/google-maps-loader-BCe58h9D.js +308 -0
- package/dist/google-maps-loader-casMyxlo.cjs +316 -0
- package/dist/hooks.cjs.js +12 -8
- package/dist/hooks.es.js +10 -27
- package/dist/index-9GWd0qxq.cjs +12 -0
- package/dist/index-BabBx2pa.js +6 -0
- package/dist/index.cjs.js +37 -32
- package/dist/index.es.js +30 -363
- package/dist/input-C_UiS2Py.cjs +152 -0
- package/dist/input-cc-PTD4R.js +123 -0
- package/dist/layout.cjs.js +10 -6
- package/dist/layout.es.js +7 -9
- package/dist/media.cjs.js +8 -3
- package/dist/media.es.js +1 -6
- package/dist/pages.cjs.js +8 -3
- package/dist/pages.es.js +1 -11
- package/dist/progress-C7Lti5wo.js +80 -0
- package/dist/progress-Cqwxbqs1.cjs +103 -0
- package/dist/rich-text-editor-DqLICivI.js +2832 -0
- package/dist/rich-text-editor-DxO1Hz3a.cjs +2903 -0
- package/dist/select-CH6v_KcQ.cjs +161 -0
- package/dist/select-D-xvCZK2.js +130 -0
- package/dist/sidebar-3XyzjVBw.js +792 -0
- package/dist/sidebar-B4ZWaMrE.js +792 -0
- package/dist/sidebar-BS1p2V7t.cjs +795 -0
- package/dist/sidebar-DyYvgyBj.cjs +795 -0
- package/dist/skeleton-DjiHerJn.cjs +87 -0
- package/dist/skeleton-DtR5tkYe.js +78 -0
- package/dist/slider-B00b9SVK.cjs +78 -0
- package/dist/slider-DQCNUUMj.js +56 -0
- package/dist/sonner-B-jWlik1.cjs +68 -0
- package/dist/sonner-C9tiqj4f.js +47 -0
- package/dist/tooltip-D8n9UYoU.cjs +72 -0
- package/dist/tooltip-RtbSmPYJ.js +48 -0
- package/dist/ui.cjs.js +23 -18
- package/dist/ui.es.js +16 -303
- package/dist/use-audio-player-B78fd2ct.js +188 -0
- package/dist/use-audio-player-DGvhPrgR.cjs +190 -0
- package/dist/use-mobile-BdXTRb0Z.cjs +51 -0
- package/dist/use-mobile-Ce2cBAQe.js +29 -0
- package/dist/xertica-assistant-B1NaSFFj.js +2173 -0
- package/dist/xertica-assistant-B687qEPU.js +2165 -0
- package/dist/xertica-assistant-CIaUlbIt.cjs +2180 -0
- package/dist/xertica-assistant-sOHwTgIP.cjs +2172 -0
- package/dist/xertica-ui.css +1 -1
- package/docs/ai-usage.md +195 -195
- package/docs/architecture-improvements.md +456 -456
- package/docs/architecture.md +312 -306
- package/docs/components/accordion.md +109 -109
- package/docs/components/alert-dialog.md +127 -127
- package/docs/components/alert.md +106 -106
- package/docs/components/aspect-ratio.md +58 -58
- package/docs/components/assistant-chart.md +47 -47
- package/docs/components/assistant.md +428 -426
- package/docs/components/audio-player.md +167 -167
- package/docs/components/avatar.md +101 -101
- package/docs/components/badge.md +84 -84
- package/docs/components/branding.md +252 -252
- package/docs/components/breadcrumb.md +104 -104
- package/docs/components/button.md +156 -156
- package/docs/components/calendar.md +141 -141
- package/docs/components/card-patterns.md +447 -445
- package/docs/components/card.md +245 -245
- package/docs/components/carousel.md +100 -100
- package/docs/components/chart.md +638 -638
- package/docs/components/checkbox.md +88 -88
- package/docs/components/code-block.md +105 -105
- package/docs/components/collapsible.md +86 -86
- package/docs/components/command.md +113 -113
- package/docs/components/context-menu.md +81 -81
- package/docs/components/dialog.md +198 -198
- package/docs/components/drawer.md +105 -105
- package/docs/components/dropdown-menu.md +127 -127
- package/docs/components/empty.md +127 -127
- package/docs/components/error-boundary.md +201 -191
- package/docs/components/file-upload.md +189 -189
- package/docs/components/floating-media-wrapper.md +63 -63
- package/docs/components/form.md +177 -177
- package/docs/components/formatted-document.md +105 -105
- package/docs/components/google-maps-loader.md +44 -44
- package/docs/components/header.md +177 -177
- package/docs/components/hooks.md +432 -430
- package/docs/components/hover-card.md +86 -86
- package/docs/components/image-with-fallback.md +107 -107
- package/docs/components/input-otp.md +95 -95
- package/docs/components/input.md +130 -130
- package/docs/components/label.md +69 -69
- package/docs/components/language-selector.md +20 -16
- package/docs/components/map-layers.md +138 -138
- package/docs/components/map.md +84 -84
- package/docs/components/markdown-message.md +47 -47
- package/docs/components/menubar.md +89 -89
- package/docs/components/modern-chat-input.md +164 -164
- package/docs/components/navigation-menu.md +83 -83
- package/docs/components/notification-badge.md +78 -78
- package/docs/components/page-header.md +93 -93
- package/docs/components/pages.md +323 -309
- package/docs/components/pagination.md +334 -334
- package/docs/components/popover.md +116 -116
- package/docs/components/progress.md +103 -103
- package/docs/components/radio-group.md +133 -133
- package/docs/components/rating.md +77 -77
- package/docs/components/resizable.md +84 -84
- package/docs/components/rich-text-editor.md +255 -255
- package/docs/components/route-map.md +124 -124
- package/docs/components/scroll-area.md +58 -58
- package/docs/components/search.md +87 -87
- package/docs/components/select.md +144 -144
- package/docs/components/separator.md +58 -58
- package/docs/components/sheet.md +122 -122
- package/docs/components/sidebar.md +314 -314
- package/docs/components/simple-map.md +51 -51
- package/docs/components/skeleton.md +99 -99
- package/docs/components/slider.md +84 -84
- package/docs/components/sonner.md +115 -115
- package/docs/components/stats-card.md +120 -120
- package/docs/components/stepper.md +268 -268
- package/docs/components/switch.md +106 -106
- package/docs/components/table.md +138 -138
- package/docs/components/tabs.md +117 -117
- package/docs/components/textarea.md +86 -86
- package/docs/components/theme-toggle.md +73 -73
- package/docs/components/timeline.md +121 -121
- package/docs/components/toggle-group.md +68 -68
- package/docs/components/toggle.md +62 -62
- package/docs/components/tooltip.md +116 -116
- package/docs/components/tree-view.md +238 -238
- package/docs/components/use-mobile.md +96 -96
- package/docs/components/video-player.md +68 -68
- package/docs/components/xertica-logo.md +36 -36
- package/docs/components/xertica-orbe.md +35 -35
- package/docs/components/xertica-provider.md +65 -65
- package/docs/components/xertica-xlogo.md +35 -35
- package/docs/decision-tree.md +293 -293
- package/docs/doc-audit.md +244 -243
- package/docs/form-sizing.md +162 -162
- package/docs/getting-started.md +616 -591
- package/docs/guidelines.md +330 -328
- package/docs/i18n.md +61 -57
- package/docs/installation.md +268 -267
- package/docs/layout.md +143 -143
- package/docs/llms.md +295 -295
- package/docs/patterns/analytics.md +194 -194
- package/docs/patterns/crud.md +149 -149
- package/docs/patterns/dashboard.md +138 -138
- package/docs/patterns/detail-page.md +296 -296
- package/docs/patterns/form.md +241 -241
- package/docs/patterns/login.md +156 -156
- package/docs/patterns/settings.md +368 -368
- package/docs/patterns/wizard.md +213 -213
- package/docs/state-management.md +289 -289
- package/guidelines/Guidelines.md +409 -406
- package/hooks/useTheme.test.tsx +16 -16
- package/hooks/useTheme.ts +4 -4
- package/imports/Podcast.tsx +540 -540
- package/imports/XerticaAi.tsx +46 -46
- package/imports/XerticaX.tsx +15 -15
- package/imports/svg-aueiaqngck.ts +20 -20
- package/imports/svg-v9krss1ozd.ts +23 -23
- package/imports/svg-vhrdofe3qe.ts +6 -6
- package/llms-compact.txt +2 -1
- package/llms.txt +2 -1
- package/mcp/resources.json +22 -22
- package/mcp/tools.json +35 -35
- package/package.json +219 -213
- package/scripts/ai-validator.ts +91 -91
- package/scripts/cleanup-case-dupes.ts +62 -62
- package/scripts/generate-ai-manifests.ts +107 -107
- package/styles/globals.css +13 -13
- package/styles/xertica/app-overrides/chat.css +61 -61
- package/styles/xertica/app-overrides/scrollbar.css +33 -33
- package/styles/xertica/base.css +90 -71
- package/styles/xertica/integrations/google-maps.css +76 -76
- package/styles/xertica/integrations/sonner.css +73 -73
- package/styles/xertica/theme-map.css +102 -99
- package/styles/xertica/tokens.css +240 -236
- package/templates/CLAUDE.md +16 -1
- package/templates/eslint.config.js +26 -26
- package/templates/guidelines/Guidelines.md +577 -553
- package/templates/package.json +69 -69
- package/templates/postcss.config.js +6 -6
- package/templates/src/app/App.tsx +46 -46
- package/templates/src/app/components/AppLayout.tsx +55 -55
- package/templates/src/app/components/AuthGuard.tsx +131 -82
- package/templates/src/app/context/AuthContext.tsx +108 -108
- package/templates/src/features/assistant/index.ts +5 -5
- package/templates/src/features/auth/index.ts +4 -4
- package/templates/src/features/auth/ui/AuthPageShell.tsx +32 -32
- package/templates/src/features/auth/ui/ForgotPasswordContent.tsx +70 -72
- package/templates/src/features/auth/ui/LoginContent.tsx +92 -92
- package/templates/src/features/auth/ui/ResetPasswordContent.tsx +6 -2
- package/templates/src/features/auth/ui/SocialLoginButtons.tsx +78 -78
- package/templates/src/features/auth/ui/VerifyEmailContent.tsx +2 -6
- package/templates/src/features/home/data/mock.ts +41 -35
- package/templates/src/features/home/index.ts +11 -11
- package/templates/src/features/home/store/dashboardStore.ts +25 -25
- package/templates/src/features/home/ui/HomeContent.tsx +117 -119
- package/templates/src/features/template/index.ts +5 -5
- package/templates/src/features/template/ui/CrudTemplate.tsx +1 -4
- package/templates/src/features/template/ui/LoginTemplate.tsx +1 -1
- package/templates/src/features/template/ui/TemplateContent.tsx +29 -21
- package/templates/src/locales/en/pages/templates.json +17 -17
- package/templates/src/locales/es/pages/templates.json +17 -17
- package/templates/src/locales/pt-BR/pages/templates.json +17 -17
- package/templates/src/main.tsx +11 -11
- package/templates/src/pages/AssistantPage.tsx +26 -20
- package/templates/src/pages/ForgotPasswordPage.tsx +6 -6
- package/templates/src/pages/HomePage.tsx +53 -49
- package/templates/src/pages/LoginPage.tsx +10 -10
- package/templates/src/pages/ResetPasswordPage.tsx +6 -6
- package/templates/src/pages/TemplatePage.tsx +28 -28
- package/templates/src/pages/VerifyEmailPage.tsx +6 -6
- package/templates/src/shared/config/navigation.ts +19 -19
- package/templates/src/shared/error-boundary.tsx +150 -154
- package/templates/src/shared/error-fallbacks.tsx +222 -226
- package/templates/src/shared/lib/auth.ts +20 -20
- package/templates/src/shared/types/auth.ts +3 -3
- package/templates/src/styles/index.css +95 -95
- package/templates/src/styles/xertica/tokens.css +240 -236
- package/templates/tsconfig.json +25 -25
- package/templates/tsconfig.node.json +12 -12
- package/templates/vite-env.d.ts +1 -1
- package/templates/vite.config.js +20 -20
- package/templates/vite.config.ts +54 -51
- package/utils/color-utils.ts +72 -72
- package/utils/demo-responses.test.ts +10 -10
- package/utils/demo-responses.ts +151 -151
- package/utils/gemini.test.ts +25 -25
- package/utils/gemini.ts +155 -155
|
@@ -1,123 +1,123 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import * as React from 'react';
|
|
4
|
-
import { useMemo } from 'react';
|
|
5
|
-
import { useTranslation } from 'react-i18next';
|
|
6
|
-
import {
|
|
7
|
-
Card,
|
|
8
|
-
CardHeader,
|
|
9
|
-
CardTitle,
|
|
10
|
-
CardDescription,
|
|
11
|
-
CardContent,
|
|
12
|
-
CardFooter,
|
|
13
|
-
CardAction,
|
|
14
|
-
} from '../../ui/card';
|
|
15
|
-
import { Avatar, AvatarFallback, AvatarImage } from '../../ui/avatar';
|
|
16
|
-
import { Badge } from '../../ui/badge';
|
|
17
|
-
import { Progress } from '../../ui/progress';
|
|
18
|
-
import { cn } from '../../shared/utils';
|
|
19
|
-
import type { ProgressVariant } from '../../ui/progress';
|
|
20
|
-
|
|
21
|
-
export type ProjectStatus = 'active' | 'review' | 'done' | 'paused' | 'at-risk';
|
|
22
|
-
|
|
23
|
-
export interface ProjectMember {
|
|
24
|
-
name: string;
|
|
25
|
-
initials: string;
|
|
26
|
-
avatar?: string;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface ProjectCardProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
30
|
-
title: string;
|
|
31
|
-
description?: string;
|
|
32
|
-
status: ProjectStatus;
|
|
33
|
-
progress: number;
|
|
34
|
-
dueDate?: string;
|
|
35
|
-
members?: ProjectMember[];
|
|
36
|
-
maxMembers?: number;
|
|
37
|
-
action?: React.ReactNode;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const statusVariantConfig: Record<
|
|
41
|
-
ProjectStatus,
|
|
42
|
-
{
|
|
43
|
-
variant: React.ComponentProps<typeof Badge>['variant'];
|
|
44
|
-
progressVariant: ProgressVariant;
|
|
45
|
-
}
|
|
46
|
-
> = {
|
|
47
|
-
active: { variant: 'info', progressVariant: 'info' },
|
|
48
|
-
review: { variant: 'warning', progressVariant: 'warning' },
|
|
49
|
-
done: { variant: 'success', progressVariant: 'success' },
|
|
50
|
-
paused: { variant: 'secondary', progressVariant: 'default' },
|
|
51
|
-
'at-risk': { variant: 'destructive', progressVariant: 'destructive' },
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
export function ProjectCard({
|
|
55
|
-
title,
|
|
56
|
-
description,
|
|
57
|
-
status,
|
|
58
|
-
progress,
|
|
59
|
-
dueDate,
|
|
60
|
-
members = [],
|
|
61
|
-
maxMembers = 4,
|
|
62
|
-
action,
|
|
63
|
-
className,
|
|
64
|
-
...props
|
|
65
|
-
}: ProjectCardProps) {
|
|
66
|
-
const { t } = useTranslation();
|
|
67
|
-
const statusLabelMap = useMemo<Record<ProjectStatus, string>>(
|
|
68
|
-
() => ({
|
|
69
|
-
active: t('projectCard.status.active'),
|
|
70
|
-
review: t('projectCard.status.review'),
|
|
71
|
-
done: t('projectCard.status.completed'),
|
|
72
|
-
paused: t('projectCard.status.paused'),
|
|
73
|
-
'at-risk': t('projectCard.status.atRisk'),
|
|
74
|
-
}),
|
|
75
|
-
[t]
|
|
76
|
-
);
|
|
77
|
-
const { variant, progressVariant } = statusVariantConfig[status];
|
|
78
|
-
const label = statusLabelMap[status];
|
|
79
|
-
const visible = members.slice(0, maxMembers);
|
|
80
|
-
const overflow = members.length - maxMembers;
|
|
81
|
-
|
|
82
|
-
return (
|
|
83
|
-
<Card className={cn('w-full', className)} {...props}>
|
|
84
|
-
<CardHeader>
|
|
85
|
-
<div className="flex flex-col gap-1 min-w-0">
|
|
86
|
-
<CardTitle className="truncate">{title}</CardTitle>
|
|
87
|
-
{description && <CardDescription className="line-clamp-2">{description}</CardDescription>}
|
|
88
|
-
</div>
|
|
89
|
-
<CardAction className="flex items-center gap-2">
|
|
90
|
-
<Badge variant={variant}>{label}</Badge>
|
|
91
|
-
{action}
|
|
92
|
-
</CardAction>
|
|
93
|
-
</CardHeader>
|
|
94
|
-
|
|
95
|
-
<CardContent className="space-y-4">
|
|
96
|
-
<div className="space-y-1.5">
|
|
97
|
-
<div className="flex justify-between text-xs text-muted-foreground">
|
|
98
|
-
<span>{t('projectCard.progress')}</span>
|
|
99
|
-
<span>{progress}%</span>
|
|
100
|
-
</div>
|
|
101
|
-
<Progress value={progress} variant={progressVariant} className="h-2" />
|
|
102
|
-
</div>
|
|
103
|
-
</CardContent>
|
|
104
|
-
|
|
105
|
-
<CardFooter className="flex items-center justify-between">
|
|
106
|
-
<div className="flex -space-x-2">
|
|
107
|
-
{visible.map(m => (
|
|
108
|
-
<Avatar key={m.name} className="size-7 border-2 border-background">
|
|
109
|
-
{m.avatar && <AvatarImage src={m.avatar} alt={m.name} />}
|
|
110
|
-
<AvatarFallback className="text-[10px]">{m.initials}</AvatarFallback>
|
|
111
|
-
</Avatar>
|
|
112
|
-
))}
|
|
113
|
-
{overflow > 0 && (
|
|
114
|
-
<div className="size-7 rounded-full border-2 border-background bg-muted flex items-center justify-center text-[10px] font-medium text-muted-foreground">
|
|
115
|
-
+{overflow}
|
|
116
|
-
</div>
|
|
117
|
-
)}
|
|
118
|
-
</div>
|
|
119
|
-
{dueDate && <span className="text-xs text-muted-foreground">{dueDate}</span>}
|
|
120
|
-
</CardFooter>
|
|
121
|
-
</Card>
|
|
122
|
-
);
|
|
123
|
-
}
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { useMemo } from 'react';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
6
|
+
import {
|
|
7
|
+
Card,
|
|
8
|
+
CardHeader,
|
|
9
|
+
CardTitle,
|
|
10
|
+
CardDescription,
|
|
11
|
+
CardContent,
|
|
12
|
+
CardFooter,
|
|
13
|
+
CardAction,
|
|
14
|
+
} from '../../ui/card';
|
|
15
|
+
import { Avatar, AvatarFallback, AvatarImage } from '../../ui/avatar';
|
|
16
|
+
import { Badge } from '../../ui/badge';
|
|
17
|
+
import { Progress } from '../../ui/progress';
|
|
18
|
+
import { cn } from '../../shared/utils';
|
|
19
|
+
import type { ProgressVariant } from '../../ui/progress';
|
|
20
|
+
|
|
21
|
+
export type ProjectStatus = 'active' | 'review' | 'done' | 'paused' | 'at-risk';
|
|
22
|
+
|
|
23
|
+
export interface ProjectMember {
|
|
24
|
+
name: string;
|
|
25
|
+
initials: string;
|
|
26
|
+
avatar?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface ProjectCardProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
30
|
+
title: string;
|
|
31
|
+
description?: string;
|
|
32
|
+
status: ProjectStatus;
|
|
33
|
+
progress: number;
|
|
34
|
+
dueDate?: string;
|
|
35
|
+
members?: ProjectMember[];
|
|
36
|
+
maxMembers?: number;
|
|
37
|
+
action?: React.ReactNode;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const statusVariantConfig: Record<
|
|
41
|
+
ProjectStatus,
|
|
42
|
+
{
|
|
43
|
+
variant: React.ComponentProps<typeof Badge>['variant'];
|
|
44
|
+
progressVariant: ProgressVariant;
|
|
45
|
+
}
|
|
46
|
+
> = {
|
|
47
|
+
active: { variant: 'info', progressVariant: 'info' },
|
|
48
|
+
review: { variant: 'warning', progressVariant: 'warning' },
|
|
49
|
+
done: { variant: 'success', progressVariant: 'success' },
|
|
50
|
+
paused: { variant: 'secondary', progressVariant: 'default' },
|
|
51
|
+
'at-risk': { variant: 'destructive', progressVariant: 'destructive' },
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export function ProjectCard({
|
|
55
|
+
title,
|
|
56
|
+
description,
|
|
57
|
+
status,
|
|
58
|
+
progress,
|
|
59
|
+
dueDate,
|
|
60
|
+
members = [],
|
|
61
|
+
maxMembers = 4,
|
|
62
|
+
action,
|
|
63
|
+
className,
|
|
64
|
+
...props
|
|
65
|
+
}: ProjectCardProps) {
|
|
66
|
+
const { t } = useTranslation();
|
|
67
|
+
const statusLabelMap = useMemo<Record<ProjectStatus, string>>(
|
|
68
|
+
() => ({
|
|
69
|
+
active: t('projectCard.status.active'),
|
|
70
|
+
review: t('projectCard.status.review'),
|
|
71
|
+
done: t('projectCard.status.completed'),
|
|
72
|
+
paused: t('projectCard.status.paused'),
|
|
73
|
+
'at-risk': t('projectCard.status.atRisk'),
|
|
74
|
+
}),
|
|
75
|
+
[t]
|
|
76
|
+
);
|
|
77
|
+
const { variant, progressVariant } = statusVariantConfig[status];
|
|
78
|
+
const label = statusLabelMap[status];
|
|
79
|
+
const visible = members.slice(0, maxMembers);
|
|
80
|
+
const overflow = members.length - maxMembers;
|
|
81
|
+
|
|
82
|
+
return (
|
|
83
|
+
<Card className={cn('w-full', className)} {...props}>
|
|
84
|
+
<CardHeader>
|
|
85
|
+
<div className="flex flex-col gap-1 min-w-0">
|
|
86
|
+
<CardTitle className="truncate">{title}</CardTitle>
|
|
87
|
+
{description && <CardDescription className="line-clamp-2">{description}</CardDescription>}
|
|
88
|
+
</div>
|
|
89
|
+
<CardAction className="flex items-center gap-2">
|
|
90
|
+
<Badge variant={variant}>{label}</Badge>
|
|
91
|
+
{action}
|
|
92
|
+
</CardAction>
|
|
93
|
+
</CardHeader>
|
|
94
|
+
|
|
95
|
+
<CardContent className="space-y-4">
|
|
96
|
+
<div className="space-y-1.5">
|
|
97
|
+
<div className="flex justify-between text-xs text-muted-foreground">
|
|
98
|
+
<span>{t('projectCard.progress')}</span>
|
|
99
|
+
<span>{progress}%</span>
|
|
100
|
+
</div>
|
|
101
|
+
<Progress value={progress} variant={progressVariant} className="h-2" />
|
|
102
|
+
</div>
|
|
103
|
+
</CardContent>
|
|
104
|
+
|
|
105
|
+
<CardFooter className="flex items-center justify-between">
|
|
106
|
+
<div className="flex -space-x-2">
|
|
107
|
+
{visible.map(m => (
|
|
108
|
+
<Avatar key={m.name} className="size-7 border-2 border-background">
|
|
109
|
+
{m.avatar && <AvatarImage src={m.avatar} alt={m.name} />}
|
|
110
|
+
<AvatarFallback className="text-[10px]">{m.initials}</AvatarFallback>
|
|
111
|
+
</Avatar>
|
|
112
|
+
))}
|
|
113
|
+
{overflow > 0 && (
|
|
114
|
+
<div className="size-7 rounded-full border-2 border-background bg-muted flex items-center justify-center text-[10px] font-medium text-muted-foreground">
|
|
115
|
+
+{overflow}
|
|
116
|
+
</div>
|
|
117
|
+
)}
|
|
118
|
+
</div>
|
|
119
|
+
{dueDate && <span className="text-xs text-muted-foreground">{dueDate}</span>}
|
|
120
|
+
</CardFooter>
|
|
121
|
+
</Card>
|
|
122
|
+
);
|
|
123
|
+
}
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import * as React from 'react';
|
|
4
|
-
import {
|
|
5
|
-
Card,
|
|
6
|
-
CardHeader,
|
|
7
|
-
CardContent,
|
|
8
|
-
CardFooter,
|
|
9
|
-
} from '../../ui/card';
|
|
4
|
+
import { Card, CardHeader, CardContent, CardFooter } from '../../ui/card';
|
|
10
5
|
import { Skeleton } from '../../ui/skeleton';
|
|
11
6
|
import { cn } from '../../shared/utils';
|
|
12
7
|
|
|
@@ -1,68 +1,68 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import * as React from 'react';
|
|
4
|
-
import { Card, CardContent } from '../../ui/card';
|
|
5
|
-
import { Button } from '../../ui/button';
|
|
6
|
-
import { Badge } from '../../ui/badge';
|
|
7
|
-
import { cn } from '../../shared/utils';
|
|
8
|
-
|
|
9
|
-
export interface QuickActionCardProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
10
|
-
title: string;
|
|
11
|
-
description?: string;
|
|
12
|
-
icon: React.ReactNode;
|
|
13
|
-
badge?: string;
|
|
14
|
-
badgeVariant?: React.ComponentProps<typeof Badge>['variant'];
|
|
15
|
-
actionLabel: string;
|
|
16
|
-
actionVariant?: React.ComponentProps<typeof Button>['variant'];
|
|
17
|
-
onAction?: () => void;
|
|
18
|
-
disabled?: boolean;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function QuickActionCard({
|
|
22
|
-
title,
|
|
23
|
-
description,
|
|
24
|
-
icon,
|
|
25
|
-
badge,
|
|
26
|
-
badgeVariant = 'secondary',
|
|
27
|
-
actionLabel,
|
|
28
|
-
actionVariant = 'default',
|
|
29
|
-
onAction,
|
|
30
|
-
disabled,
|
|
31
|
-
className,
|
|
32
|
-
...props
|
|
33
|
-
}: QuickActionCardProps) {
|
|
34
|
-
return (
|
|
35
|
-
<Card
|
|
36
|
-
className={cn(
|
|
37
|
-
'w-full group transition-shadow hover:shadow-md',
|
|
38
|
-
disabled && 'opacity-60 pointer-events-none',
|
|
39
|
-
className
|
|
40
|
-
)}
|
|
41
|
-
{...props}
|
|
42
|
-
>
|
|
43
|
-
<CardContent className="pt-6 flex flex-col items-start gap-4">
|
|
44
|
-
<div className="flex items-start justify-between w-full">
|
|
45
|
-
<div className="p-2.5 rounded-[var(--radius)] bg-primary/10 text-primary">{icon}</div>
|
|
46
|
-
{badge && <Badge variant={badgeVariant}>{badge}</Badge>}
|
|
47
|
-
</div>
|
|
48
|
-
|
|
49
|
-
<div className="space-y-1 flex-1">
|
|
50
|
-
<p className="font-semibold text-sm leading-tight">{title}</p>
|
|
51
|
-
{description && (
|
|
52
|
-
<p className="text-xs text-muted-foreground leading-relaxed">{description}</p>
|
|
53
|
-
)}
|
|
54
|
-
</div>
|
|
55
|
-
|
|
56
|
-
<Button
|
|
57
|
-
variant={actionVariant}
|
|
58
|
-
size="sm"
|
|
59
|
-
className="w-full"
|
|
60
|
-
onClick={onAction}
|
|
61
|
-
disabled={disabled}
|
|
62
|
-
>
|
|
63
|
-
{actionLabel}
|
|
64
|
-
</Button>
|
|
65
|
-
</CardContent>
|
|
66
|
-
</Card>
|
|
67
|
-
);
|
|
68
|
-
}
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { Card, CardContent } from '../../ui/card';
|
|
5
|
+
import { Button } from '../../ui/button';
|
|
6
|
+
import { Badge } from '../../ui/badge';
|
|
7
|
+
import { cn } from '../../shared/utils';
|
|
8
|
+
|
|
9
|
+
export interface QuickActionCardProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
10
|
+
title: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
icon: React.ReactNode;
|
|
13
|
+
badge?: string;
|
|
14
|
+
badgeVariant?: React.ComponentProps<typeof Badge>['variant'];
|
|
15
|
+
actionLabel: string;
|
|
16
|
+
actionVariant?: React.ComponentProps<typeof Button>['variant'];
|
|
17
|
+
onAction?: () => void;
|
|
18
|
+
disabled?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function QuickActionCard({
|
|
22
|
+
title,
|
|
23
|
+
description,
|
|
24
|
+
icon,
|
|
25
|
+
badge,
|
|
26
|
+
badgeVariant = 'secondary',
|
|
27
|
+
actionLabel,
|
|
28
|
+
actionVariant = 'default',
|
|
29
|
+
onAction,
|
|
30
|
+
disabled,
|
|
31
|
+
className,
|
|
32
|
+
...props
|
|
33
|
+
}: QuickActionCardProps) {
|
|
34
|
+
return (
|
|
35
|
+
<Card
|
|
36
|
+
className={cn(
|
|
37
|
+
'w-full group transition-shadow hover:shadow-md',
|
|
38
|
+
disabled && 'opacity-60 pointer-events-none',
|
|
39
|
+
className
|
|
40
|
+
)}
|
|
41
|
+
{...props}
|
|
42
|
+
>
|
|
43
|
+
<CardContent className="pt-6 flex flex-col items-start gap-4">
|
|
44
|
+
<div className="flex items-start justify-between w-full">
|
|
45
|
+
<div className="p-2.5 rounded-[var(--radius)] bg-primary/10 text-primary">{icon}</div>
|
|
46
|
+
{badge && <Badge variant={badgeVariant}>{badge}</Badge>}
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<div className="space-y-1 flex-1">
|
|
50
|
+
<p className="font-semibold text-sm leading-tight">{title}</p>
|
|
51
|
+
{description && (
|
|
52
|
+
<p className="text-xs text-muted-foreground leading-relaxed">{description}</p>
|
|
53
|
+
)}
|
|
54
|
+
</div>
|
|
55
|
+
|
|
56
|
+
<Button
|
|
57
|
+
variant={actionVariant}
|
|
58
|
+
size="sm"
|
|
59
|
+
className="w-full"
|
|
60
|
+
onClick={onAction}
|
|
61
|
+
disabled={disabled}
|
|
62
|
+
>
|
|
63
|
+
{actionLabel}
|
|
64
|
+
</Button>
|
|
65
|
+
</CardContent>
|
|
66
|
+
</Card>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
@@ -1,123 +1,123 @@
|
|
|
1
|
-
import { Meta, Title, Subtitle, Description, Primary, Controls, Stories, Canvas } from '@storybook/addon-docs/blocks';
|
|
2
|
-
import * as CardPatternsStories from './card-patterns.stories';
|
|
3
|
-
|
|
4
|
-
<Meta of={CardPatternsStories} />
|
|
5
|
-
|
|
6
|
-
<Title />
|
|
7
|
-
<Subtitle>Pre-composed card blocks for dashboards and feature pages — plus matching skeleton variants for loading states.</Subtitle>
|
|
8
|
-
|
|
9
|
-
<Description />
|
|
10
|
-
|
|
11
|
-
<Primary />
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## Overview
|
|
16
|
-
|
|
17
|
-
Six composed card components built exclusively from `ui/` primitives — no external dependencies. Each card has a matching `*Skeleton` companion that mirrors its layout with pulsing placeholders for use while data is loading.
|
|
18
|
-
|
|
19
|
-
| Card | Skeleton companion |
|
|
20
|
-
| ------------------- | -------------------------- |
|
|
21
|
-
| `ActivityCard` | `ActivityCardSkeleton` |
|
|
22
|
-
| `ProfileCard` | `ProfileCardSkeleton` |
|
|
23
|
-
| `ProjectCard` | `ProjectCardSkeleton` |
|
|
24
|
-
| `NotificationCard` | `NotificationCardSkeleton` |
|
|
25
|
-
| `QuickActionCard` | `QuickActionCardSkeleton` |
|
|
26
|
-
| `FeatureCard` | `FeatureCardSkeleton` |
|
|
27
|
-
|
|
28
|
-
> A matching `StatsCardSkeleton` is also available from `xertica-ui` (lives in `ui/stats-card/`).
|
|
29
|
-
|
|
30
|
-
---
|
|
31
|
-
|
|
32
|
-
## Import
|
|
33
|
-
|
|
34
|
-
```tsx
|
|
35
|
-
// All cards and skeletons are re-exported from the root barrel
|
|
36
|
-
import {
|
|
37
|
-
ActivityCard, ActivityCardSkeleton,
|
|
38
|
-
ProfileCard, ProfileCardSkeleton,
|
|
39
|
-
ProjectCard, ProjectCardSkeleton,
|
|
40
|
-
NotificationCard, NotificationCardSkeleton,
|
|
41
|
-
QuickActionCard, QuickActionCardSkeleton,
|
|
42
|
-
FeatureCard, FeatureCardSkeleton,
|
|
43
|
-
} from 'xertica-ui';
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
---
|
|
47
|
-
|
|
48
|
-
## When to Use Cards
|
|
49
|
-
|
|
50
|
-
- You need a recurring dashboard pattern (activity feed, KPI, project status, notifications) and don't want to re-compose it from scratch in every feature.
|
|
51
|
-
- The pattern is stable and reused across multiple pages.
|
|
52
|
-
|
|
53
|
-
## When NOT to Use Cards
|
|
54
|
-
|
|
55
|
-
- One-off layouts specific to a single page — compose directly from `Card` and `ui/` primitives instead.
|
|
56
|
-
- When the pattern has significant data-fetching logic — keep the block as a pure presentational component and handle state in the feature layer.
|
|
57
|
-
|
|
58
|
-
---
|
|
59
|
-
|
|
60
|
-
## Loading-state pattern
|
|
61
|
-
|
|
62
|
-
Always pair each card with its matching `*Skeleton` for loading states — never render a spinner or empty container while data fetches. The skeleton variants mirror the final layout closely, preventing layout shift when data arrives.
|
|
63
|
-
|
|
64
|
-
```tsx
|
|
65
|
-
function ActivityFeed() {
|
|
66
|
-
const { data: items, isLoading } = useActivityItems();
|
|
67
|
-
|
|
68
|
-
if (isLoading) return <ActivityCardSkeleton rows={5} />;
|
|
69
|
-
return <ActivityCard items={items!} />;
|
|
70
|
-
}
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
For grids, render one skeleton per expected card:
|
|
74
|
-
|
|
75
|
-
```tsx
|
|
76
|
-
{isLoading ? (
|
|
77
|
-
<>
|
|
78
|
-
<FeatureCardSkeleton showAction />
|
|
79
|
-
<FeatureCardSkeleton showAction />
|
|
80
|
-
<FeatureCardSkeleton showAction />
|
|
81
|
-
</>
|
|
82
|
-
) : (
|
|
83
|
-
data.map(item => <FeatureCard key={item.id} {...item} />)
|
|
84
|
-
)}
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
---
|
|
88
|
-
|
|
89
|
-
## Skeleton configuration
|
|
90
|
-
|
|
91
|
-
Each skeleton accepts props that tune which layout regions are rendered, so the placeholder matches the loaded state exactly.
|
|
92
|
-
|
|
93
|
-
| Skeleton | Props |
|
|
94
|
-
| -------------------------- | ------------------------------------------- |
|
|
95
|
-
| `ActivityCardSkeleton` | `rows` (default `5`) |
|
|
96
|
-
| `ProfileCardSkeleton` | `showStats`, `showActions` |
|
|
97
|
-
| `ProjectCardSkeleton` | `memberCount` (default `3`) |
|
|
98
|
-
| `NotificationCardSkeleton` | `rows` (default `4`), `showViewAll` |
|
|
99
|
-
| `QuickActionCardSkeleton` | — |
|
|
100
|
-
| `FeatureCardSkeleton` | `showAction` |
|
|
101
|
-
| `StatsCardSkeleton` | `showIcon`, `showTrend` |
|
|
102
|
-
|
|
103
|
-
Set `rows={maxItems}` on list-style skeletons to match the loaded state's row count.
|
|
104
|
-
|
|
105
|
-
---
|
|
106
|
-
|
|
107
|
-
## Stories
|
|
108
|
-
|
|
109
|
-
<Stories />
|
|
110
|
-
|
|
111
|
-
---
|
|
112
|
-
|
|
113
|
-
## AI Rules
|
|
114
|
-
|
|
115
|
-
> [!IMPORTANT]
|
|
116
|
-
>
|
|
117
|
-
> - **Import block components from `xertica-ui`** — they are included in the root barrel.
|
|
118
|
-
> - **Pass all data as props** — never embed fetch calls inside block components.
|
|
119
|
-
> - **Keep `maxItems` at a sensible limit (4–6)** to avoid overflow in fixed-height containers.
|
|
120
|
-
> - **Always pair each card with its matching `*Skeleton`** — do not render a spinner or empty container while data fetches.
|
|
121
|
-
> - **Skeleton row counts should match the expected data count** — pass `rows={maxItems}` to `ActivityCardSkeleton`/`NotificationCardSkeleton`.
|
|
122
|
-
> - **For chart panels**, use `ChartCard` from `xertica-ui/ui` (not a block component) with any dashboard-ready chart as `children`.
|
|
123
|
-
> - **`FeatureCard` badge wraps to a new line** when title + badge don't fit — this is intentional; do not constrain the container width to force inline layout.
|
|
1
|
+
import { Meta, Title, Subtitle, Description, Primary, Controls, Stories, Canvas } from '@storybook/addon-docs/blocks';
|
|
2
|
+
import * as CardPatternsStories from './card-patterns.stories';
|
|
3
|
+
|
|
4
|
+
<Meta of={CardPatternsStories} />
|
|
5
|
+
|
|
6
|
+
<Title />
|
|
7
|
+
<Subtitle>Pre-composed card blocks for dashboards and feature pages — plus matching skeleton variants for loading states.</Subtitle>
|
|
8
|
+
|
|
9
|
+
<Description />
|
|
10
|
+
|
|
11
|
+
<Primary />
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Overview
|
|
16
|
+
|
|
17
|
+
Six composed card components built exclusively from `ui/` primitives — no external dependencies. Each card has a matching `*Skeleton` companion that mirrors its layout with pulsing placeholders for use while data is loading.
|
|
18
|
+
|
|
19
|
+
| Card | Skeleton companion |
|
|
20
|
+
| ------------------- | -------------------------- |
|
|
21
|
+
| `ActivityCard` | `ActivityCardSkeleton` |
|
|
22
|
+
| `ProfileCard` | `ProfileCardSkeleton` |
|
|
23
|
+
| `ProjectCard` | `ProjectCardSkeleton` |
|
|
24
|
+
| `NotificationCard` | `NotificationCardSkeleton` |
|
|
25
|
+
| `QuickActionCard` | `QuickActionCardSkeleton` |
|
|
26
|
+
| `FeatureCard` | `FeatureCardSkeleton` |
|
|
27
|
+
|
|
28
|
+
> A matching `StatsCardSkeleton` is also available from `xertica-ui` (lives in `ui/stats-card/`).
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Import
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
// All cards and skeletons are re-exported from the root barrel
|
|
36
|
+
import {
|
|
37
|
+
ActivityCard, ActivityCardSkeleton,
|
|
38
|
+
ProfileCard, ProfileCardSkeleton,
|
|
39
|
+
ProjectCard, ProjectCardSkeleton,
|
|
40
|
+
NotificationCard, NotificationCardSkeleton,
|
|
41
|
+
QuickActionCard, QuickActionCardSkeleton,
|
|
42
|
+
FeatureCard, FeatureCardSkeleton,
|
|
43
|
+
} from 'xertica-ui';
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## When to Use Cards
|
|
49
|
+
|
|
50
|
+
- You need a recurring dashboard pattern (activity feed, KPI, project status, notifications) and don't want to re-compose it from scratch in every feature.
|
|
51
|
+
- The pattern is stable and reused across multiple pages.
|
|
52
|
+
|
|
53
|
+
## When NOT to Use Cards
|
|
54
|
+
|
|
55
|
+
- One-off layouts specific to a single page — compose directly from `Card` and `ui/` primitives instead.
|
|
56
|
+
- When the pattern has significant data-fetching logic — keep the block as a pure presentational component and handle state in the feature layer.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Loading-state pattern
|
|
61
|
+
|
|
62
|
+
Always pair each card with its matching `*Skeleton` for loading states — never render a spinner or empty container while data fetches. The skeleton variants mirror the final layout closely, preventing layout shift when data arrives.
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
function ActivityFeed() {
|
|
66
|
+
const { data: items, isLoading } = useActivityItems();
|
|
67
|
+
|
|
68
|
+
if (isLoading) return <ActivityCardSkeleton rows={5} />;
|
|
69
|
+
return <ActivityCard items={items!} />;
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
For grids, render one skeleton per expected card:
|
|
74
|
+
|
|
75
|
+
```tsx
|
|
76
|
+
{isLoading ? (
|
|
77
|
+
<>
|
|
78
|
+
<FeatureCardSkeleton showAction />
|
|
79
|
+
<FeatureCardSkeleton showAction />
|
|
80
|
+
<FeatureCardSkeleton showAction />
|
|
81
|
+
</>
|
|
82
|
+
) : (
|
|
83
|
+
data.map(item => <FeatureCard key={item.id} {...item} />)
|
|
84
|
+
)}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Skeleton configuration
|
|
90
|
+
|
|
91
|
+
Each skeleton accepts props that tune which layout regions are rendered, so the placeholder matches the loaded state exactly.
|
|
92
|
+
|
|
93
|
+
| Skeleton | Props |
|
|
94
|
+
| -------------------------- | ------------------------------------------- |
|
|
95
|
+
| `ActivityCardSkeleton` | `rows` (default `5`) |
|
|
96
|
+
| `ProfileCardSkeleton` | `showStats`, `showActions` |
|
|
97
|
+
| `ProjectCardSkeleton` | `memberCount` (default `3`) |
|
|
98
|
+
| `NotificationCardSkeleton` | `rows` (default `4`), `showViewAll` |
|
|
99
|
+
| `QuickActionCardSkeleton` | — |
|
|
100
|
+
| `FeatureCardSkeleton` | `showAction` |
|
|
101
|
+
| `StatsCardSkeleton` | `showIcon`, `showTrend` |
|
|
102
|
+
|
|
103
|
+
Set `rows={maxItems}` on list-style skeletons to match the loaded state's row count.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Stories
|
|
108
|
+
|
|
109
|
+
<Stories />
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## AI Rules
|
|
114
|
+
|
|
115
|
+
> [!IMPORTANT]
|
|
116
|
+
>
|
|
117
|
+
> - **Import block components from `xertica-ui`** — they are included in the root barrel.
|
|
118
|
+
> - **Pass all data as props** — never embed fetch calls inside block components.
|
|
119
|
+
> - **Keep `maxItems` at a sensible limit (4–6)** to avoid overflow in fixed-height containers.
|
|
120
|
+
> - **Always pair each card with its matching `*Skeleton`** — do not render a spinner or empty container while data fetches.
|
|
121
|
+
> - **Skeleton row counts should match the expected data count** — pass `rows={maxItems}` to `ActivityCardSkeleton`/`NotificationCardSkeleton`.
|
|
122
|
+
> - **For chart panels**, use `ChartCard` from `xertica-ui/ui` (not a block component) with any dashboard-ready chart as `children`.
|
|
123
|
+
> - **`FeatureCard` badge wraps to a new line** when title + badge don't fit — this is intentional; do not constrain the container width to force inline layout.
|