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,349 +1,349 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { Menu, ChevronRight, User, LogOut, Settings as SettingsIcon } from 'lucide-react';
|
|
3
|
-
import { Button } from '../../ui/button';
|
|
4
|
-
import { ThemeToggle } from '../../brand/theme-toggle';
|
|
5
|
-
import { LanguageSelector } from '../../brand/language-selector';
|
|
6
|
-
import {
|
|
7
|
-
Breadcrumb,
|
|
8
|
-
BreadcrumbItem,
|
|
9
|
-
BreadcrumbList,
|
|
10
|
-
BreadcrumbPage,
|
|
11
|
-
BreadcrumbSeparator,
|
|
12
|
-
BreadcrumbLink,
|
|
13
|
-
} from '../../ui/breadcrumb';
|
|
14
|
-
import {
|
|
15
|
-
DropdownMenu,
|
|
16
|
-
DropdownMenuContent,
|
|
17
|
-
DropdownMenuItem,
|
|
18
|
-
DropdownMenuLabel,
|
|
19
|
-
DropdownMenuSeparator,
|
|
20
|
-
DropdownMenuTrigger,
|
|
21
|
-
} from '../../ui/dropdown-menu';
|
|
22
|
-
import { Avatar, AvatarFallback, AvatarImage } from '../../ui/avatar';
|
|
23
|
-
|
|
24
|
-
import { useOptionalLayout } from '../../../contexts/LayoutContext';
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Breadcrumb entry for the header navigation.
|
|
28
|
-
*/
|
|
29
|
-
export interface BreadcrumbType {
|
|
30
|
-
/** Text label to display */
|
|
31
|
-
label: string;
|
|
32
|
-
/**
|
|
33
|
-
* URL to navigate to.
|
|
34
|
-
* When `renderLink` is provided on the Header, this value is passed to your
|
|
35
|
-
* custom link component (e.g., React Router's `<Link to={href}>`).
|
|
36
|
-
* Otherwise it's used as a standard `<a href>`.
|
|
37
|
-
*/
|
|
38
|
-
href?: string;
|
|
39
|
-
/** Optional leading icon */
|
|
40
|
-
icon?: React.ReactNode;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Action button configuration for the header.
|
|
45
|
-
*/
|
|
46
|
-
export interface HeaderAction {
|
|
47
|
-
/** Unique identifier for the action */
|
|
48
|
-
id: string;
|
|
49
|
-
/** Optional text label (hidden on mobile) */
|
|
50
|
-
label?: string;
|
|
51
|
-
/** Icon element to display */
|
|
52
|
-
icon: React.ReactNode;
|
|
53
|
-
/** Click handler */
|
|
54
|
-
onClick?: () => void;
|
|
55
|
-
/** Additional CSS classes */
|
|
56
|
-
className?: string;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Props for the Header component.
|
|
61
|
-
*/
|
|
62
|
-
export interface HeaderProps {
|
|
63
|
-
/**
|
|
64
|
-
* Page title — used only when the page has no navigation hierarchy.
|
|
65
|
-
* Renders as a plain text label without breadcrumb separators.
|
|
66
|
-
* This is the **exception** pattern; prefer `breadcrumbs` for all navigable pages.
|
|
67
|
-
*/
|
|
68
|
-
title?: string;
|
|
69
|
-
/**
|
|
70
|
-
* Navigation breadcrumb trail — the **primary** and recommended pattern.
|
|
71
|
-
* Supports unlimited levels. The last item (without `href`) is treated as the current page.
|
|
72
|
-
*/
|
|
73
|
-
breadcrumbs?: BreadcrumbType[];
|
|
74
|
-
/** Whether to show the language selector */
|
|
75
|
-
showLanguageSelector?: boolean;
|
|
76
|
-
/** Whether to show the theme toggle button */
|
|
77
|
-
showThemeToggle?: boolean;
|
|
78
|
-
/** Additional CSS classes */
|
|
79
|
-
className?: string;
|
|
80
|
-
/** Logged-in user information and menu */
|
|
81
|
-
user?: {
|
|
82
|
-
name?: string;
|
|
83
|
-
email?: string;
|
|
84
|
-
avatar?: string;
|
|
85
|
-
menuItems?: HeaderAction[];
|
|
86
|
-
};
|
|
87
|
-
/** Custom action buttons to display */
|
|
88
|
-
actions?: HeaderAction[];
|
|
89
|
-
/** Whether to show a quick settings button */
|
|
90
|
-
showSettings?: boolean;
|
|
91
|
-
/** Click handler for settings */
|
|
92
|
-
onSettingsClick?: () => void;
|
|
93
|
-
/** Whether to show a quick logout button */
|
|
94
|
-
showLogout?: boolean;
|
|
95
|
-
/** Click handler for logout */
|
|
96
|
-
onLogoutClick?: () => void;
|
|
97
|
-
/**
|
|
98
|
-
* Custom element rendered immediately after the breadcrumb / title area.
|
|
99
|
-
* Accepts any React node — badges, buttons, status chips, etc.
|
|
100
|
-
*
|
|
101
|
-
* @example
|
|
102
|
-
* ```tsx
|
|
103
|
-
* <Header
|
|
104
|
-
* breadcrumbs={[...]}
|
|
105
|
-
* breadcrumbSlot={<Badge variant="warning">Beta</Badge>}
|
|
106
|
-
* />
|
|
107
|
-
* ```
|
|
108
|
-
*/
|
|
109
|
-
breadcrumbSlot?: React.ReactNode;
|
|
110
|
-
/**
|
|
111
|
-
* Custom link renderer for breadcrumb navigation.
|
|
112
|
-
* Use this to integrate with client-side routers (e.g., React Router, Next.js Link)
|
|
113
|
-
* to prevent full-page reloads on navigation.
|
|
114
|
-
*
|
|
115
|
-
* When omitted, breadcrumbs render standard `<a>` tags.
|
|
116
|
-
*
|
|
117
|
-
* @example
|
|
118
|
-
* ```tsx
|
|
119
|
-
* import { Link } from 'react-router-dom';
|
|
120
|
-
*
|
|
121
|
-
* <Header
|
|
122
|
-
* breadcrumbs={[...]}
|
|
123
|
-
* renderLink={(href, props) => <Link to={href} {...props} />}
|
|
124
|
-
* />
|
|
125
|
-
* ```
|
|
126
|
-
*/
|
|
127
|
-
renderLink?: (
|
|
128
|
-
href: string,
|
|
129
|
-
props: { className?: string; children: React.ReactNode }
|
|
130
|
-
) => React.ReactNode;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Main application Header component.
|
|
135
|
-
*
|
|
136
|
-
* @description
|
|
137
|
-
* Provides a sticky top navigation bar with breadcrumbs, responsive mobile menu trigger,
|
|
138
|
-
* theme/language selectors, and user profile management.
|
|
139
|
-
*
|
|
140
|
-
* The Header supports two navigation modes:
|
|
141
|
-
* - **Breadcrumbs (default)**: Pass the `breadcrumbs` array for pages with navigation hierarchy.
|
|
142
|
-
* Supports unlimited depth levels.
|
|
143
|
-
* - **Title-only (exception)**: Pass `title` for pages without any navigation (e.g., standalone pages).
|
|
144
|
-
* This renders a simple text label without separators.
|
|
145
|
-
*
|
|
146
|
-
* @ai-rules
|
|
147
|
-
* 1. **Always prefer `breadcrumbs`** for any page that has a parent or navigation context.
|
|
148
|
-
* 2. Use `title` **only** when the page is a top-level standalone page with no navigation hierarchy.
|
|
149
|
-
* 3. Use `actions` for page-specific global actions (e.g., Save, Edit).
|
|
150
|
-
* 4. The `user` prop is mandatory for authenticated states to show the profile dropdown.
|
|
151
|
-
* 5. Breadcrumbs support unlimited levels — do not limit to 2 or 3 items.
|
|
152
|
-
*/
|
|
153
|
-
export function Header({
|
|
154
|
-
title,
|
|
155
|
-
breadcrumbs,
|
|
156
|
-
showLanguageSelector = true,
|
|
157
|
-
showThemeToggle = true,
|
|
158
|
-
className,
|
|
159
|
-
user,
|
|
160
|
-
actions,
|
|
161
|
-
showSettings,
|
|
162
|
-
onSettingsClick,
|
|
163
|
-
showLogout,
|
|
164
|
-
onLogoutClick,
|
|
165
|
-
renderLink,
|
|
166
|
-
breadcrumbSlot,
|
|
167
|
-
}: HeaderProps) {
|
|
168
|
-
const layout = useOptionalLayout();
|
|
169
|
-
const toggleSidebar = layout?.toggleSidebar ?? (() => {});
|
|
170
|
-
|
|
171
|
-
return (
|
|
172
|
-
<header
|
|
173
|
-
className={`bg-card text-foreground shadow-sm border-b border-border px-[24px] h-[64px] flex-shrink-0 flex items-center ${className || ''}`}
|
|
174
|
-
>
|
|
175
|
-
<div className="flex items-center justify-between w-full p-[0px]">
|
|
176
|
-
<div className="flex items-center gap-2 text-muted-foreground w-full overflow-x-auto">
|
|
177
|
-
{/* Mobile menu trigger */}
|
|
178
|
-
<Button
|
|
179
|
-
variant="ghost"
|
|
180
|
-
size="sm"
|
|
181
|
-
onClick={toggleSidebar}
|
|
182
|
-
className="md:hidden mr-2 p-2 shrink-0"
|
|
183
|
-
aria-label="Abrir menu lateral"
|
|
184
|
-
>
|
|
185
|
-
<Menu className="w-5 h-5" />
|
|
186
|
-
</Button>
|
|
187
|
-
|
|
188
|
-
{/* Breadcrumbs or Title */}
|
|
189
|
-
{breadcrumbs && breadcrumbs.length > 0 ? (
|
|
190
|
-
<Breadcrumb>
|
|
191
|
-
<BreadcrumbList className="flex-nowrap whitespace-nowrap">
|
|
192
|
-
{breadcrumbs.map((item, index) => (
|
|
193
|
-
<React.Fragment key={index}>
|
|
194
|
-
<BreadcrumbItem>
|
|
195
|
-
{item.href ? (
|
|
196
|
-
renderLink ? (
|
|
197
|
-
<BreadcrumbLink asChild className="flex items-center gap-1.5">
|
|
198
|
-
{renderLink(item.href, {
|
|
199
|
-
className: 'flex items-center gap-1.5',
|
|
200
|
-
children: (
|
|
201
|
-
<>
|
|
202
|
-
{item.icon}
|
|
203
|
-
{item.label}
|
|
204
|
-
</>
|
|
205
|
-
),
|
|
206
|
-
})}
|
|
207
|
-
</BreadcrumbLink>
|
|
208
|
-
) : (
|
|
209
|
-
<BreadcrumbLink href={item.href} className="flex items-center gap-1.5">
|
|
210
|
-
{item.icon}
|
|
211
|
-
{item.label}
|
|
212
|
-
</BreadcrumbLink>
|
|
213
|
-
)
|
|
214
|
-
) : (
|
|
215
|
-
<BreadcrumbPage className="flex items-center gap-1.5">
|
|
216
|
-
{item.icon}
|
|
217
|
-
{item.label}
|
|
218
|
-
</BreadcrumbPage>
|
|
219
|
-
)}
|
|
220
|
-
</BreadcrumbItem>
|
|
221
|
-
{index < breadcrumbs.length - 1 && <BreadcrumbSeparator />}
|
|
222
|
-
</React.Fragment>
|
|
223
|
-
))}
|
|
224
|
-
</BreadcrumbList>
|
|
225
|
-
</Breadcrumb>
|
|
226
|
-
) : title ? (
|
|
227
|
-
<span className="text-foreground font-medium shrink-0">{title}</span>
|
|
228
|
-
) : (
|
|
229
|
-
<Breadcrumb>
|
|
230
|
-
<BreadcrumbList className="flex-nowrap whitespace-nowrap">
|
|
231
|
-
<BreadcrumbItem>
|
|
232
|
-
<BreadcrumbPage className="text-foreground font-medium shrink-0">
|
|
233
|
-
Xertica.ai
|
|
234
|
-
</BreadcrumbPage>
|
|
235
|
-
</BreadcrumbItem>
|
|
236
|
-
</BreadcrumbList>
|
|
237
|
-
</Breadcrumb>
|
|
238
|
-
)}
|
|
239
|
-
{/* Breadcrumb slot */}
|
|
240
|
-
{breadcrumbSlot && <div className="flex items-center shrink-0">{breadcrumbSlot}</div>}
|
|
241
|
-
</div>
|
|
242
|
-
|
|
243
|
-
{/* User controls */}
|
|
244
|
-
<div className="flex items-center gap-3 shrink-0 ml-4">
|
|
245
|
-
{/* Language selector */}
|
|
246
|
-
{showLanguageSelector && (
|
|
247
|
-
<LanguageSelector variant="minimal" showIcon={false} className="hidden sm:flex" />
|
|
248
|
-
)}
|
|
249
|
-
|
|
250
|
-
{/* Theme toggle */}
|
|
251
|
-
{showThemeToggle && <ThemeToggle className="hover:bg-accent" />}
|
|
252
|
-
|
|
253
|
-
{/* Custom actions */}
|
|
254
|
-
{actions?.map(action => (
|
|
255
|
-
<Button
|
|
256
|
-
key={action.id}
|
|
257
|
-
variant="ghost"
|
|
258
|
-
size={action.label ? 'sm' : 'icon'}
|
|
259
|
-
onClick={action.onClick}
|
|
260
|
-
className={`hover:bg-accent ${action.className || ''}`}
|
|
261
|
-
aria-label={action.label || action.id}
|
|
262
|
-
>
|
|
263
|
-
{action.icon}
|
|
264
|
-
{action.label && <span className="ml-2 hidden md:inline">{action.label}</span>}
|
|
265
|
-
</Button>
|
|
266
|
-
))}
|
|
267
|
-
|
|
268
|
-
{/* Quick settings button */}
|
|
269
|
-
{showSettings && (
|
|
270
|
-
<Button
|
|
271
|
-
variant="ghost"
|
|
272
|
-
size="icon"
|
|
273
|
-
onClick={onSettingsClick}
|
|
274
|
-
className="hover:bg-accent"
|
|
275
|
-
aria-label="Configurações"
|
|
276
|
-
>
|
|
277
|
-
<SettingsIcon className="w-5 h-5" />
|
|
278
|
-
</Button>
|
|
279
|
-
)}
|
|
280
|
-
|
|
281
|
-
{/* User profile dropdown */}
|
|
282
|
-
{user && (
|
|
283
|
-
<DropdownMenu>
|
|
284
|
-
<DropdownMenuTrigger asChild>
|
|
285
|
-
<Button
|
|
286
|
-
variant="ghost"
|
|
287
|
-
className="relative h-8 w-8 rounded-full p-0 overflow-hidden border border-border/50 hover:border-primary/30 transition-colors"
|
|
288
|
-
aria-label="Menu do usuário"
|
|
289
|
-
>
|
|
290
|
-
<Avatar className="h-8 w-8">
|
|
291
|
-
<AvatarImage src={user.avatar} alt={user.name || 'User'} />
|
|
292
|
-
<AvatarFallback className="bg-primary/10 text-primary text-xs font-medium">
|
|
293
|
-
{user.name ? user.name.charAt(0).toUpperCase() : <User className="w-4 h-4" />}
|
|
294
|
-
</AvatarFallback>
|
|
295
|
-
</Avatar>
|
|
296
|
-
</Button>
|
|
297
|
-
</DropdownMenuTrigger>
|
|
298
|
-
<DropdownMenuContent className="w-56" align="end" forceMount>
|
|
299
|
-
<DropdownMenuLabel className="font-normal">
|
|
300
|
-
<div className="flex flex-col space-y-1">
|
|
301
|
-
<p className="text-sm font-medium leading-none">{user.name || 'User'}</p>
|
|
302
|
-
<p className="text-xs leading-none text-muted-foreground">
|
|
303
|
-
{user.email || 'user@example.com'}
|
|
304
|
-
</p>
|
|
305
|
-
</div>
|
|
306
|
-
</DropdownMenuLabel>
|
|
307
|
-
<DropdownMenuSeparator />
|
|
308
|
-
{user.menuItems?.map(item => (
|
|
309
|
-
<DropdownMenuItem key={item.id} onClick={item.onClick} className={item.className}>
|
|
310
|
-
{item.icon && <span className="mr-2">{item.icon}</span>}
|
|
311
|
-
{item.label}
|
|
312
|
-
</DropdownMenuItem>
|
|
313
|
-
))}
|
|
314
|
-
{!user.menuItems && (
|
|
315
|
-
<>
|
|
316
|
-
<DropdownMenuItem onClick={onSettingsClick}>
|
|
317
|
-
<SettingsIcon className="mr-2 h-4 w-4" />
|
|
318
|
-
<span>Settings</span>
|
|
319
|
-
</DropdownMenuItem>
|
|
320
|
-
<DropdownMenuItem
|
|
321
|
-
onClick={onLogoutClick}
|
|
322
|
-
className="text-destructive focus:text-destructive"
|
|
323
|
-
>
|
|
324
|
-
<LogOut className="mr-2 h-4 w-4" />
|
|
325
|
-
<span>Logout</span>
|
|
326
|
-
</DropdownMenuItem>
|
|
327
|
-
</>
|
|
328
|
-
)}
|
|
329
|
-
</DropdownMenuContent>
|
|
330
|
-
</DropdownMenu>
|
|
331
|
-
)}
|
|
332
|
-
|
|
333
|
-
{/* Quick logout button - always last */}
|
|
334
|
-
{showLogout && (
|
|
335
|
-
<Button
|
|
336
|
-
variant="ghost"
|
|
337
|
-
size="icon"
|
|
338
|
-
onClick={onLogoutClick}
|
|
339
|
-
className="hover:bg-accent text-muted-foreground hover:text-foreground"
|
|
340
|
-
aria-label="Sair"
|
|
341
|
-
>
|
|
342
|
-
<LogOut className="w-5 h-5" />
|
|
343
|
-
</Button>
|
|
344
|
-
)}
|
|
345
|
-
</div>
|
|
346
|
-
</div>
|
|
347
|
-
</header>
|
|
348
|
-
);
|
|
349
|
-
}
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Menu, ChevronRight, User, LogOut, Settings as SettingsIcon } from 'lucide-react';
|
|
3
|
+
import { Button } from '../../ui/button';
|
|
4
|
+
import { ThemeToggle } from '../../brand/theme-toggle';
|
|
5
|
+
import { LanguageSelector } from '../../brand/language-selector';
|
|
6
|
+
import {
|
|
7
|
+
Breadcrumb,
|
|
8
|
+
BreadcrumbItem,
|
|
9
|
+
BreadcrumbList,
|
|
10
|
+
BreadcrumbPage,
|
|
11
|
+
BreadcrumbSeparator,
|
|
12
|
+
BreadcrumbLink,
|
|
13
|
+
} from '../../ui/breadcrumb';
|
|
14
|
+
import {
|
|
15
|
+
DropdownMenu,
|
|
16
|
+
DropdownMenuContent,
|
|
17
|
+
DropdownMenuItem,
|
|
18
|
+
DropdownMenuLabel,
|
|
19
|
+
DropdownMenuSeparator,
|
|
20
|
+
DropdownMenuTrigger,
|
|
21
|
+
} from '../../ui/dropdown-menu';
|
|
22
|
+
import { Avatar, AvatarFallback, AvatarImage } from '../../ui/avatar';
|
|
23
|
+
|
|
24
|
+
import { useOptionalLayout } from '../../../contexts/LayoutContext';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Breadcrumb entry for the header navigation.
|
|
28
|
+
*/
|
|
29
|
+
export interface BreadcrumbType {
|
|
30
|
+
/** Text label to display */
|
|
31
|
+
label: string;
|
|
32
|
+
/**
|
|
33
|
+
* URL to navigate to.
|
|
34
|
+
* When `renderLink` is provided on the Header, this value is passed to your
|
|
35
|
+
* custom link component (e.g., React Router's `<Link to={href}>`).
|
|
36
|
+
* Otherwise it's used as a standard `<a href>`.
|
|
37
|
+
*/
|
|
38
|
+
href?: string;
|
|
39
|
+
/** Optional leading icon */
|
|
40
|
+
icon?: React.ReactNode;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Action button configuration for the header.
|
|
45
|
+
*/
|
|
46
|
+
export interface HeaderAction {
|
|
47
|
+
/** Unique identifier for the action */
|
|
48
|
+
id: string;
|
|
49
|
+
/** Optional text label (hidden on mobile) */
|
|
50
|
+
label?: string;
|
|
51
|
+
/** Icon element to display */
|
|
52
|
+
icon: React.ReactNode;
|
|
53
|
+
/** Click handler */
|
|
54
|
+
onClick?: () => void;
|
|
55
|
+
/** Additional CSS classes */
|
|
56
|
+
className?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Props for the Header component.
|
|
61
|
+
*/
|
|
62
|
+
export interface HeaderProps {
|
|
63
|
+
/**
|
|
64
|
+
* Page title — used only when the page has no navigation hierarchy.
|
|
65
|
+
* Renders as a plain text label without breadcrumb separators.
|
|
66
|
+
* This is the **exception** pattern; prefer `breadcrumbs` for all navigable pages.
|
|
67
|
+
*/
|
|
68
|
+
title?: string;
|
|
69
|
+
/**
|
|
70
|
+
* Navigation breadcrumb trail — the **primary** and recommended pattern.
|
|
71
|
+
* Supports unlimited levels. The last item (without `href`) is treated as the current page.
|
|
72
|
+
*/
|
|
73
|
+
breadcrumbs?: BreadcrumbType[];
|
|
74
|
+
/** Whether to show the language selector */
|
|
75
|
+
showLanguageSelector?: boolean;
|
|
76
|
+
/** Whether to show the theme toggle button */
|
|
77
|
+
showThemeToggle?: boolean;
|
|
78
|
+
/** Additional CSS classes */
|
|
79
|
+
className?: string;
|
|
80
|
+
/** Logged-in user information and menu */
|
|
81
|
+
user?: {
|
|
82
|
+
name?: string;
|
|
83
|
+
email?: string;
|
|
84
|
+
avatar?: string;
|
|
85
|
+
menuItems?: HeaderAction[];
|
|
86
|
+
};
|
|
87
|
+
/** Custom action buttons to display */
|
|
88
|
+
actions?: HeaderAction[];
|
|
89
|
+
/** Whether to show a quick settings button */
|
|
90
|
+
showSettings?: boolean;
|
|
91
|
+
/** Click handler for settings */
|
|
92
|
+
onSettingsClick?: () => void;
|
|
93
|
+
/** Whether to show a quick logout button */
|
|
94
|
+
showLogout?: boolean;
|
|
95
|
+
/** Click handler for logout */
|
|
96
|
+
onLogoutClick?: () => void;
|
|
97
|
+
/**
|
|
98
|
+
* Custom element rendered immediately after the breadcrumb / title area.
|
|
99
|
+
* Accepts any React node — badges, buttons, status chips, etc.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```tsx
|
|
103
|
+
* <Header
|
|
104
|
+
* breadcrumbs={[...]}
|
|
105
|
+
* breadcrumbSlot={<Badge variant="warning">Beta</Badge>}
|
|
106
|
+
* />
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
breadcrumbSlot?: React.ReactNode;
|
|
110
|
+
/**
|
|
111
|
+
* Custom link renderer for breadcrumb navigation.
|
|
112
|
+
* Use this to integrate with client-side routers (e.g., React Router, Next.js Link)
|
|
113
|
+
* to prevent full-page reloads on navigation.
|
|
114
|
+
*
|
|
115
|
+
* When omitted, breadcrumbs render standard `<a>` tags.
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```tsx
|
|
119
|
+
* import { Link } from 'react-router-dom';
|
|
120
|
+
*
|
|
121
|
+
* <Header
|
|
122
|
+
* breadcrumbs={[...]}
|
|
123
|
+
* renderLink={(href, props) => <Link to={href} {...props} />}
|
|
124
|
+
* />
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
renderLink?: (
|
|
128
|
+
href: string,
|
|
129
|
+
props: { className?: string; children: React.ReactNode }
|
|
130
|
+
) => React.ReactNode;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Main application Header component.
|
|
135
|
+
*
|
|
136
|
+
* @description
|
|
137
|
+
* Provides a sticky top navigation bar with breadcrumbs, responsive mobile menu trigger,
|
|
138
|
+
* theme/language selectors, and user profile management.
|
|
139
|
+
*
|
|
140
|
+
* The Header supports two navigation modes:
|
|
141
|
+
* - **Breadcrumbs (default)**: Pass the `breadcrumbs` array for pages with navigation hierarchy.
|
|
142
|
+
* Supports unlimited depth levels.
|
|
143
|
+
* - **Title-only (exception)**: Pass `title` for pages without any navigation (e.g., standalone pages).
|
|
144
|
+
* This renders a simple text label without separators.
|
|
145
|
+
*
|
|
146
|
+
* @ai-rules
|
|
147
|
+
* 1. **Always prefer `breadcrumbs`** for any page that has a parent or navigation context.
|
|
148
|
+
* 2. Use `title` **only** when the page is a top-level standalone page with no navigation hierarchy.
|
|
149
|
+
* 3. Use `actions` for page-specific global actions (e.g., Save, Edit).
|
|
150
|
+
* 4. The `user` prop is mandatory for authenticated states to show the profile dropdown.
|
|
151
|
+
* 5. Breadcrumbs support unlimited levels — do not limit to 2 or 3 items.
|
|
152
|
+
*/
|
|
153
|
+
export function Header({
|
|
154
|
+
title,
|
|
155
|
+
breadcrumbs,
|
|
156
|
+
showLanguageSelector = true,
|
|
157
|
+
showThemeToggle = true,
|
|
158
|
+
className,
|
|
159
|
+
user,
|
|
160
|
+
actions,
|
|
161
|
+
showSettings,
|
|
162
|
+
onSettingsClick,
|
|
163
|
+
showLogout,
|
|
164
|
+
onLogoutClick,
|
|
165
|
+
renderLink,
|
|
166
|
+
breadcrumbSlot,
|
|
167
|
+
}: HeaderProps) {
|
|
168
|
+
const layout = useOptionalLayout();
|
|
169
|
+
const toggleSidebar = layout?.toggleSidebar ?? (() => {});
|
|
170
|
+
|
|
171
|
+
return (
|
|
172
|
+
<header
|
|
173
|
+
className={`bg-card text-foreground shadow-sm border-b border-border px-[24px] h-[64px] flex-shrink-0 flex items-center ${className || ''}`}
|
|
174
|
+
>
|
|
175
|
+
<div className="flex items-center justify-between w-full p-[0px]">
|
|
176
|
+
<div className="flex items-center gap-2 text-muted-foreground w-full overflow-x-auto">
|
|
177
|
+
{/* Mobile menu trigger */}
|
|
178
|
+
<Button
|
|
179
|
+
variant="ghost"
|
|
180
|
+
size="sm"
|
|
181
|
+
onClick={toggleSidebar}
|
|
182
|
+
className="md:hidden mr-2 p-2 shrink-0"
|
|
183
|
+
aria-label="Abrir menu lateral"
|
|
184
|
+
>
|
|
185
|
+
<Menu className="w-5 h-5" />
|
|
186
|
+
</Button>
|
|
187
|
+
|
|
188
|
+
{/* Breadcrumbs or Title */}
|
|
189
|
+
{breadcrumbs && breadcrumbs.length > 0 ? (
|
|
190
|
+
<Breadcrumb>
|
|
191
|
+
<BreadcrumbList className="flex-nowrap whitespace-nowrap">
|
|
192
|
+
{breadcrumbs.map((item, index) => (
|
|
193
|
+
<React.Fragment key={index}>
|
|
194
|
+
<BreadcrumbItem>
|
|
195
|
+
{item.href ? (
|
|
196
|
+
renderLink ? (
|
|
197
|
+
<BreadcrumbLink asChild className="flex items-center gap-1.5">
|
|
198
|
+
{renderLink(item.href, {
|
|
199
|
+
className: 'flex items-center gap-1.5',
|
|
200
|
+
children: (
|
|
201
|
+
<>
|
|
202
|
+
{item.icon}
|
|
203
|
+
{item.label}
|
|
204
|
+
</>
|
|
205
|
+
),
|
|
206
|
+
})}
|
|
207
|
+
</BreadcrumbLink>
|
|
208
|
+
) : (
|
|
209
|
+
<BreadcrumbLink href={item.href} className="flex items-center gap-1.5">
|
|
210
|
+
{item.icon}
|
|
211
|
+
{item.label}
|
|
212
|
+
</BreadcrumbLink>
|
|
213
|
+
)
|
|
214
|
+
) : (
|
|
215
|
+
<BreadcrumbPage className="flex items-center gap-1.5">
|
|
216
|
+
{item.icon}
|
|
217
|
+
{item.label}
|
|
218
|
+
</BreadcrumbPage>
|
|
219
|
+
)}
|
|
220
|
+
</BreadcrumbItem>
|
|
221
|
+
{index < breadcrumbs.length - 1 && <BreadcrumbSeparator />}
|
|
222
|
+
</React.Fragment>
|
|
223
|
+
))}
|
|
224
|
+
</BreadcrumbList>
|
|
225
|
+
</Breadcrumb>
|
|
226
|
+
) : title ? (
|
|
227
|
+
<span className="text-foreground font-medium shrink-0">{title}</span>
|
|
228
|
+
) : (
|
|
229
|
+
<Breadcrumb>
|
|
230
|
+
<BreadcrumbList className="flex-nowrap whitespace-nowrap">
|
|
231
|
+
<BreadcrumbItem>
|
|
232
|
+
<BreadcrumbPage className="text-foreground font-medium shrink-0">
|
|
233
|
+
Xertica.ai
|
|
234
|
+
</BreadcrumbPage>
|
|
235
|
+
</BreadcrumbItem>
|
|
236
|
+
</BreadcrumbList>
|
|
237
|
+
</Breadcrumb>
|
|
238
|
+
)}
|
|
239
|
+
{/* Breadcrumb slot */}
|
|
240
|
+
{breadcrumbSlot && <div className="flex items-center shrink-0">{breadcrumbSlot}</div>}
|
|
241
|
+
</div>
|
|
242
|
+
|
|
243
|
+
{/* User controls */}
|
|
244
|
+
<div className="flex items-center gap-3 shrink-0 ml-4">
|
|
245
|
+
{/* Language selector */}
|
|
246
|
+
{showLanguageSelector && (
|
|
247
|
+
<LanguageSelector variant="minimal" showIcon={false} className="hidden sm:flex" />
|
|
248
|
+
)}
|
|
249
|
+
|
|
250
|
+
{/* Theme toggle */}
|
|
251
|
+
{showThemeToggle && <ThemeToggle className="hover:bg-accent" />}
|
|
252
|
+
|
|
253
|
+
{/* Custom actions */}
|
|
254
|
+
{actions?.map(action => (
|
|
255
|
+
<Button
|
|
256
|
+
key={action.id}
|
|
257
|
+
variant="ghost"
|
|
258
|
+
size={action.label ? 'sm' : 'icon'}
|
|
259
|
+
onClick={action.onClick}
|
|
260
|
+
className={`hover:bg-accent ${action.className || ''}`}
|
|
261
|
+
aria-label={action.label || action.id}
|
|
262
|
+
>
|
|
263
|
+
{action.icon}
|
|
264
|
+
{action.label && <span className="ml-2 hidden md:inline">{action.label}</span>}
|
|
265
|
+
</Button>
|
|
266
|
+
))}
|
|
267
|
+
|
|
268
|
+
{/* Quick settings button */}
|
|
269
|
+
{showSettings && (
|
|
270
|
+
<Button
|
|
271
|
+
variant="ghost"
|
|
272
|
+
size="icon"
|
|
273
|
+
onClick={onSettingsClick}
|
|
274
|
+
className="hover:bg-accent"
|
|
275
|
+
aria-label="Configurações"
|
|
276
|
+
>
|
|
277
|
+
<SettingsIcon className="w-5 h-5" />
|
|
278
|
+
</Button>
|
|
279
|
+
)}
|
|
280
|
+
|
|
281
|
+
{/* User profile dropdown */}
|
|
282
|
+
{user && (
|
|
283
|
+
<DropdownMenu>
|
|
284
|
+
<DropdownMenuTrigger asChild>
|
|
285
|
+
<Button
|
|
286
|
+
variant="ghost"
|
|
287
|
+
className="relative h-8 w-8 rounded-full p-0 overflow-hidden border border-border/50 hover:border-primary/30 transition-colors"
|
|
288
|
+
aria-label="Menu do usuário"
|
|
289
|
+
>
|
|
290
|
+
<Avatar className="h-8 w-8">
|
|
291
|
+
<AvatarImage src={user.avatar} alt={user.name || 'User'} />
|
|
292
|
+
<AvatarFallback className="bg-primary/10 text-primary text-xs font-medium">
|
|
293
|
+
{user.name ? user.name.charAt(0).toUpperCase() : <User className="w-4 h-4" />}
|
|
294
|
+
</AvatarFallback>
|
|
295
|
+
</Avatar>
|
|
296
|
+
</Button>
|
|
297
|
+
</DropdownMenuTrigger>
|
|
298
|
+
<DropdownMenuContent className="w-56" align="end" forceMount>
|
|
299
|
+
<DropdownMenuLabel className="font-normal">
|
|
300
|
+
<div className="flex flex-col space-y-1">
|
|
301
|
+
<p className="text-sm font-medium leading-none">{user.name || 'User'}</p>
|
|
302
|
+
<p className="text-xs leading-none text-muted-foreground">
|
|
303
|
+
{user.email || 'user@example.com'}
|
|
304
|
+
</p>
|
|
305
|
+
</div>
|
|
306
|
+
</DropdownMenuLabel>
|
|
307
|
+
<DropdownMenuSeparator />
|
|
308
|
+
{user.menuItems?.map(item => (
|
|
309
|
+
<DropdownMenuItem key={item.id} onClick={item.onClick} className={item.className}>
|
|
310
|
+
{item.icon && <span className="mr-2">{item.icon}</span>}
|
|
311
|
+
{item.label}
|
|
312
|
+
</DropdownMenuItem>
|
|
313
|
+
))}
|
|
314
|
+
{!user.menuItems && (
|
|
315
|
+
<>
|
|
316
|
+
<DropdownMenuItem onClick={onSettingsClick}>
|
|
317
|
+
<SettingsIcon className="mr-2 h-4 w-4" />
|
|
318
|
+
<span>Settings</span>
|
|
319
|
+
</DropdownMenuItem>
|
|
320
|
+
<DropdownMenuItem
|
|
321
|
+
onClick={onLogoutClick}
|
|
322
|
+
className="text-destructive focus:text-destructive"
|
|
323
|
+
>
|
|
324
|
+
<LogOut className="mr-2 h-4 w-4" />
|
|
325
|
+
<span>Logout</span>
|
|
326
|
+
</DropdownMenuItem>
|
|
327
|
+
</>
|
|
328
|
+
)}
|
|
329
|
+
</DropdownMenuContent>
|
|
330
|
+
</DropdownMenu>
|
|
331
|
+
)}
|
|
332
|
+
|
|
333
|
+
{/* Quick logout button - always last */}
|
|
334
|
+
{showLogout && (
|
|
335
|
+
<Button
|
|
336
|
+
variant="ghost"
|
|
337
|
+
size="icon"
|
|
338
|
+
onClick={onLogoutClick}
|
|
339
|
+
className="hover:bg-accent text-muted-foreground hover:text-foreground"
|
|
340
|
+
aria-label="Sair"
|
|
341
|
+
>
|
|
342
|
+
<LogOut className="w-5 h-5" />
|
|
343
|
+
</Button>
|
|
344
|
+
)}
|
|
345
|
+
</div>
|
|
346
|
+
</div>
|
|
347
|
+
</header>
|
|
348
|
+
);
|
|
349
|
+
}
|