xertica-ui 2.4.0 → 2.5.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 +621 -564
- package/README.md +443 -417
- package/assets/xertica-logo.svg +37 -37
- package/assets/xertica-x-logo.svg +20 -20
- package/bin/cli.ts +1244 -1244
- package/bin/generate-tokens.ts +9 -9
- package/bin/language-config.ts +358 -358
- package/components/assistant/code-block/CodeBlock.tsx +268 -268
- package/components/assistant/formatted-document/FormattedDocument.tsx +147 -147
- package/components/assistant/modern-chat-input/ModernChatInput.tsx +564 -564
- package/components/assistant/xertica-assistant/parts/AssistantCollapsedView.tsx +99 -99
- package/components/assistant/xertica-assistant/parts/AssistantConversationList.tsx +104 -104
- package/components/assistant/xertica-assistant/parts/AssistantDocumentEditor.tsx +81 -81
- package/components/assistant/xertica-assistant/parts/AssistantFeedbackDialog.tsx +88 -88
- package/components/assistant/xertica-assistant/parts/AssistantHeader.tsx +75 -75
- package/components/assistant/xertica-assistant/parts/AssistantMessageBubble.tsx +564 -564
- package/components/assistant/xertica-assistant/parts/AssistantTabBar.tsx +67 -67
- package/components/assistant/xertica-assistant/parts/AssistantWelcomeScreen.tsx +103 -103
- package/components/assistant/xertica-assistant/use-assistant.ts +615 -615
- package/components/assistant/xertica-assistant/xertica-assistant.tsx +611 -611
- package/components/blocks/card-patterns/ActivityCard.tsx +100 -100
- package/components/blocks/card-patterns/ActivityCardSkeleton.tsx +56 -56
- package/components/blocks/card-patterns/FeatureCardSkeleton.tsx +58 -58
- package/components/blocks/card-patterns/NotificationCard.tsx +140 -140
- package/components/blocks/card-patterns/NotificationCardSkeleton.tsx +81 -81
- package/components/blocks/card-patterns/ProfileCard.tsx +112 -112
- package/components/blocks/card-patterns/ProfileCardSkeleton.tsx +69 -69
- package/components/blocks/card-patterns/ProjectCard.tsx +123 -123
- package/components/blocks/card-patterns/ProjectCardSkeleton.tsx +67 -67
- package/components/blocks/card-patterns/QuickActionCardSkeleton.tsx +44 -44
- package/components/blocks/card-patterns/card-patterns.stories.tsx +594 -594
- package/components/blocks/card-patterns/index.ts +29 -29
- package/components/brand/language-selector/LanguageSelector.tsx +102 -102
- package/components/brand/language-selector/language-selector.stories.tsx +111 -111
- package/components/brand/language-selector/language-selector.test.tsx +101 -101
- package/components/brand/theme-toggle/ThemeToggle.tsx +74 -74
- package/components/brand/xertica-provider/XerticaProvider.tsx +112 -109
- package/components/brand/xertica-provider/xertica-provider.mdx +61 -61
- package/components/index.ts +86 -86
- package/components/layout/sidebar/sidebar.mdx +1 -1
- package/components/layout/sidebar/sidebar.stories.tsx +201 -0
- package/components/layout/sidebar/sidebar.tsx +1164 -1079
- package/components/media/FloatingMediaWrapper.tsx +371 -371
- package/components/media/audio-player/AudioPlayer.tsx +768 -768
- package/components/media/video-player/VideoPlayer.tsx +310 -310
- package/components/pages/forgot-password-page/ForgotPasswordPage.tsx +188 -188
- package/components/pages/home-content/HomeContent.tsx +120 -120
- package/components/pages/home-content/home-content.mdx +62 -62
- package/components/pages/home-page/HomePage.tsx +78 -78
- package/components/pages/home-page/home-page.mdx +53 -53
- package/components/pages/login-page/LoginPage.tsx +218 -218
- package/components/pages/reset-password-page/ResetPasswordPage.tsx +243 -243
- package/components/pages/template-content/TemplateContent.tsx +1354 -1354
- package/components/pages/template-content/template-content.mdx +61 -61
- package/components/pages/template-page/TemplatePage.stories.tsx +8 -15
- package/components/pages/template-page/template-page.mdx +53 -53
- package/components/pages/verify-email-page/VerifyEmailPage.tsx +206 -206
- package/components/shared/error-boundary.stories.tsx +114 -114
- package/components/shared/error-boundary.tsx +150 -150
- package/components/shared/error-fallbacks.tsx +222 -222
- package/components/ui/accordion/accordion.mdx +8 -8
- package/components/ui/alert/alert.mdx +8 -8
- package/components/ui/alert-dialog/alert-dialog.mdx +8 -8
- package/components/ui/aspect-ratio/aspect-ratio.mdx +8 -8
- package/components/ui/assistant-chart/assistant-chart.mdx +8 -8
- package/components/ui/avatar/avatar.mdx +8 -8
- package/components/ui/badge/badge.mdx +8 -8
- package/components/ui/breadcrumb/breadcrumb.mdx +8 -8
- package/components/ui/button/button.mdx +8 -8
- package/components/ui/calendar/calendar.mdx +8 -8
- package/components/ui/card/card.mdx +8 -8
- package/components/ui/carousel/carousel.mdx +8 -8
- package/components/ui/chart/chart.mdx +8 -8
- package/components/ui/chart/chart.test.tsx +1 -1
- package/components/ui/chart/chart.tsx +13 -6
- package/components/ui/checkbox/checkbox.mdx +8 -8
- package/components/ui/collapsible/collapsible.mdx +8 -8
- package/components/ui/command/command.mdx +8 -8
- package/components/ui/context-menu/context-menu.mdx +8 -8
- package/components/ui/dialog/dialog.mdx +8 -8
- package/components/ui/drawer/drawer.mdx +8 -8
- package/components/ui/dropdown-menu/dropdown-menu.mdx +8 -8
- package/components/ui/empty/empty.mdx +8 -8
- package/components/ui/file-upload/file-upload.mdx +8 -8
- package/components/ui/hover-card/hover-card.mdx +8 -8
- package/components/ui/input/input.mdx +8 -8
- package/components/ui/input-otp/input-otp.mdx +8 -8
- package/components/ui/label/label.mdx +8 -8
- package/components/ui/map/map.mdx +8 -8
- package/components/ui/menubar/menubar.mdx +8 -8
- package/components/ui/navigation-menu/navigation-menu.mdx +8 -8
- package/components/ui/notification-badge/notification-badge.mdx +8 -8
- package/components/ui/pagination/pagination.mdx +8 -8
- package/components/ui/popover/popover.mdx +8 -8
- package/components/ui/progress/progress.mdx +8 -8
- package/components/ui/radio-group/radio-group.mdx +8 -8
- package/components/ui/rating/rating.mdx +8 -8
- package/components/ui/resizable/resizable.mdx +8 -8
- package/components/ui/route-map/route-map.mdx +8 -8
- package/components/ui/scroll-area/scroll-area.mdx +8 -8
- package/components/ui/search/search.mdx +8 -8
- package/components/ui/select/select.mdx +8 -8
- package/components/ui/separator/separator.mdx +8 -8
- package/components/ui/sheet/sheet.mdx +8 -8
- package/components/ui/simple-map/simple-map.mdx +8 -8
- package/components/ui/skeleton/skeleton.mdx +8 -8
- package/components/ui/slider/slider.mdx +8 -8
- package/components/ui/sonner/sonner.mdx +8 -8
- package/components/ui/stats-card/index.ts +2 -2
- package/components/ui/stats-card/stats-card-skeleton.tsx +60 -60
- package/components/ui/stats-card/stats-card.mdx +8 -8
- package/components/ui/stats-card/stats-card.stories.tsx +117 -99
- package/components/ui/stats-card/stats-card.tsx +18 -2
- package/components/ui/stepper/stepper.mdx +8 -8
- package/components/ui/switch/switch.mdx +8 -8
- package/components/ui/table/table.mdx +8 -8
- package/components/ui/tabs/tabs.mdx +8 -8
- package/components/ui/textarea/textarea.mdx +8 -8
- package/components/ui/timeline/timeline.mdx +8 -8
- package/components/ui/toggle/toggle.mdx +8 -8
- package/components/ui/toggle-group/toggle-group.mdx +8 -8
- package/components/ui/tooltip/tooltip.mdx +8 -8
- package/components/ui/tree-view/tree-view.mdx +8 -8
- package/components.json +153 -533
- package/contexts/AuthContext.tsx +121 -121
- package/contexts/BrandColorsContext.tsx +39 -8
- package/contexts/LanguageContext.test.tsx +121 -121
- package/contexts/LanguageContext.tsx +250 -250
- package/contexts/theme-data.ts +51 -0
- package/dist/AssistantChart-BKVtGUKF.js +3383 -0
- package/dist/AssistantChart-BZTPJ5dP.cjs +3551 -0
- package/dist/{AssistantChart-BAx9VQvb.cjs → AssistantChart-Bdd44uBn.cjs} +388 -127
- package/dist/{AssistantChart-CVko2A1W.js → AssistantChart-CFhDdGyU.js} +391 -130
- package/dist/{AssistantChart-CVzmmhx4.js → AssistantChart-C_hwFRRr.js} +4 -4
- package/dist/{AssistantChart-BAudAfne.cjs → AssistantChart-CldVCVDe.cjs} +5 -5
- package/dist/{AssistantChart-BP8upjMk.js → AssistantChart-Cu3m7RBo.js} +5 -5
- package/dist/AssistantChart-CxGjH7Qk.js +3477 -0
- package/dist/AssistantChart-DIpshm3i.js +4784 -0
- package/dist/AssistantChart-DMJJ_Amf.js +3383 -0
- package/dist/AssistantChart-D_PTeu8P.cjs +3503 -0
- package/dist/{AssistantChart-9w31gdAb.cjs → AssistantChart-DoZCyS5r.cjs} +4 -4
- package/dist/AssistantChart-WeycT5Pd.cjs +3551 -0
- package/dist/AssistantChart-zjsy2GaZ.cjs +4810 -0
- package/dist/AudioPlayer-B1lt5cPl.cjs +989 -0
- package/dist/AudioPlayer-BZ7bibzU.cjs +982 -0
- package/dist/AudioPlayer-BpRPS4-1.cjs +1277 -0
- package/dist/AudioPlayer-C12BjQBV.cjs +997 -0
- package/dist/{AudioPlayer-1ypwE2Wh.cjs → AudioPlayer-CFeV8t-5.cjs} +1 -1
- package/dist/{AudioPlayer-DuKXrCfy.js → AudioPlayer-CGRUtUdN.js} +1 -1
- package/dist/AudioPlayer-Coly3q5R.js +1278 -0
- package/dist/AudioPlayer-CySJIyvL.js +937 -0
- package/dist/AudioPlayer-DMcG_c7L.js +990 -0
- package/dist/AudioPlayer-DcFKRJE_.js +998 -0
- package/dist/AudioPlayer-IAU5q5T1.cjs +936 -0
- package/dist/AudioPlayer-e8LfNoqO.js +983 -0
- package/dist/BrandColorsContext-565dDHd5.js +660 -0
- package/dist/BrandColorsContext-BMRJ04Wf.js +718 -0
- package/dist/BrandColorsContext-BcJbtkqn.cjs +659 -0
- package/dist/BrandColorsContext-BwY-b6M4.cjs +725 -0
- package/dist/{xertica-assistant-Qp3ydksa.cjs → CodeBlock-7TTgmdGG.cjs} +263 -51
- package/dist/{xertica-assistant-gnCJdcZY.js → CodeBlock-BeSt1h5P.js} +219 -7
- package/dist/CodeBlock-BgfYL_rD.cjs +2094 -0
- package/dist/CodeBlock-BlcqlA9M.cjs +2094 -0
- package/dist/CodeBlock-Bnmeu5ez.cjs +2094 -0
- package/dist/CodeBlock-BtfPlbAI.js +2078 -0
- package/dist/CodeBlock-CIySIuYr.js +2078 -0
- package/dist/CodeBlock-CuPtUM-7.cjs +2094 -0
- package/dist/CodeBlock-D6ffWXgc.js +2078 -0
- package/dist/CodeBlock-D8dcwbit.cjs +2094 -0
- package/dist/CodeBlock-DMZrFnlw.cjs +2094 -0
- package/dist/CodeBlock-DlBehYN8.js +2078 -0
- package/dist/CodeBlock-DnYNI8rQ.js +2078 -0
- package/dist/CodeBlock-DvKWbSnE.cjs +2094 -0
- package/dist/CodeBlock-DwMCfkFY.js +2078 -0
- package/dist/CodeBlock-Dy6CNYyj.js +2078 -0
- package/dist/CodeBlock-U1pPOQI7.cjs +2094 -0
- package/dist/CodeBlock-f_GpNhEB.js +2078 -0
- package/dist/CodeBlock-oB6u8nI1.js +2078 -0
- package/dist/CodeBlock-tZC31B73.cjs +2094 -0
- package/dist/FeatureCard-CxC-7C-C.cjs +300 -0
- package/dist/FeatureCard-DbHWCb4E.js +301 -0
- package/dist/ImageWithFallback-CGtidP6B.cjs +4542 -0
- package/dist/ImageWithFallback-lsg3pdFg.js +4508 -0
- package/dist/{LanguageContext-DvUt5jBg.cjs → LanguageContext-B_KFTCzT.cjs} +2 -2
- package/dist/{LanguageContext-BwhwC3G2.js → LanguageContext-CS14yCpi.js} +2 -2
- package/dist/{XerticaXLogo-DHz5SugF.js → LanguageSelector-B5YfbHra.js} +115 -136
- package/dist/{XerticaXLogo-DTee_y8X.cjs → LanguageSelector-D6uacAIM.cjs} +115 -136
- package/dist/LayoutContext-B45-e9DI.cjs +93 -0
- package/dist/LayoutContext-BAql6ZRY.js +97 -0
- package/dist/LayoutContext-Bav3UMEA.js +94 -0
- package/dist/LayoutContext-BvK-ggDa.cjs +96 -0
- package/dist/{ThemeContext-Bo-W2WZH.js → ThemeContext-BWq9ACPo.js} +8 -13
- package/dist/{ThemeContext-ept8jhXI.js → ThemeContext-BXjrgUjW.js} +261 -200
- package/dist/{ThemeContext-BblcjQup.cjs → ThemeContext-Bmod0Cg2.cjs} +8 -13
- package/dist/ThemeContext-BoH4NLfN.js +734 -0
- package/dist/{ThemeContext-BbBNoFTG.js → ThemeContext-C2EwAPDt.js} +2 -2
- package/dist/{ThemeContext-U4dEYc6C.cjs → ThemeContext-CGk3KK0k.cjs} +1 -8
- package/dist/{ThemeContext-D3LzacmG.js → ThemeContext-CQSo4Iwc.js} +1 -8
- package/dist/{ThemeContext-CP3a0jxy.cjs → ThemeContext-j5aGtPky.cjs} +262 -193
- package/dist/ThemeContext-r69W20Xg.cjs +733 -0
- package/dist/{ThemeContext-Cmr8Ex8H.cjs → ThemeContext-vTjumZeM.cjs} +2 -2
- package/dist/{VerifyEmailPage-BRSP-Pwt.cjs → VerifyEmailPage--1Vurewl.cjs} +3 -3
- package/dist/{VerifyEmailPage-CbgjOF0v.js → VerifyEmailPage-1WwWczAn.js} +12 -22
- package/dist/{VerifyEmailPage-DF2ilhum.cjs → VerifyEmailPage-B4peJjAT.cjs} +356 -334
- package/dist/{VerifyEmailPage-CR7kb5df.cjs → VerifyEmailPage-BComraR7.cjs} +12 -22
- package/dist/{VerifyEmailPage-u_Dn7t1U.cjs → VerifyEmailPage-Bp1XXl3H.cjs} +4 -4
- package/dist/{VerifyEmailPage-CkBYfsNy.cjs → VerifyEmailPage-By3Jf__L.cjs} +4 -4
- package/dist/{VerifyEmailPage-Bv8Ah_TK.cjs → VerifyEmailPage-ByerOcm4.cjs} +20 -23
- package/dist/{VerifyEmailPage-BE-L9mB7.js → VerifyEmailPage-C0c2e5n0.js} +7 -7
- package/dist/{VerifyEmailPage-EhudUdqF.js → VerifyEmailPage-C5TNQTBa.js} +355 -343
- package/dist/{VerifyEmailPage-Dt7zgA4w.cjs → VerifyEmailPage-CFLMls1p.cjs} +4 -4
- package/dist/{VerifyEmailPage-Bvfv8HVQ.js → VerifyEmailPage-CGIwmWrm.js} +461 -379
- package/dist/{VerifyEmailPage-Cyl55sJb.js → VerifyEmailPage-CJLz3jrn.js} +20 -23
- package/dist/VerifyEmailPage-COiyNl1y.js +2825 -0
- package/dist/{VerifyEmailPage-DMBh4NM9.cjs → VerifyEmailPage-CYXtbKi3.cjs} +1 -1
- package/dist/{VerifyEmailPage-DTtFfC-J.js → VerifyEmailPage-CgMxRb4z.js} +3 -3
- package/dist/VerifyEmailPage-CpqqpLpo.cjs +3305 -0
- package/dist/VerifyEmailPage-CqKsR2v8.js +2827 -0
- package/dist/{VerifyEmailPage-Bae2cBXT.cjs → VerifyEmailPage-Cwi3kbol.cjs} +7 -7
- package/dist/{VerifyEmailPage-X14vhdyl.js → VerifyEmailPage-DGhuIqkb.js} +4 -4
- package/dist/{VerifyEmailPage-BIBOKV7Z.js → VerifyEmailPage-DSBMRHtl.js} +36 -41
- package/dist/{VerifyEmailPage-D-FRj5TU.cjs → VerifyEmailPage-De6bQjrz.cjs} +36 -41
- package/dist/{VerifyEmailPage-BJjAMUTW.js → VerifyEmailPage-DgIid028.js} +4 -4
- package/dist/VerifyEmailPage-DjQKRlUS.cjs +2824 -0
- package/dist/{VerifyEmailPage-CdYPSJoO.js → VerifyEmailPage-DvMLZgFt.js} +1 -1
- package/dist/{VerifyEmailPage-C_ihbcth.js → VerifyEmailPage-MTD7AG1Z.js} +4 -4
- package/dist/VerifyEmailPage-s-1X3LDJ.cjs +2826 -0
- package/dist/XerticaOrbe-KL1RBHzw.cjs +1354 -0
- package/dist/XerticaOrbe-zwS1p2a8.js +1355 -0
- package/dist/XerticaProvider-6btlAlzc.js +17 -0
- package/dist/{XerticaProvider-siSt9uG2.js → XerticaProvider-B7EVH-NF.js} +2 -2
- package/dist/{XerticaProvider-AbWlr7Af.cjs → XerticaProvider-BIrqfZ-i.cjs} +11 -8
- package/dist/XerticaProvider-BNoNOxQ5.cjs +16 -0
- package/dist/XerticaProvider-BlY2limY.cjs +38 -0
- package/dist/{XerticaProvider-CWgby5mY.js → XerticaProvider-C1DKnvLh.js} +4 -4
- package/dist/{XerticaProvider-AChwphCO.cjs → XerticaProvider-CBGc4EMA.cjs} +4 -4
- package/dist/{XerticaProvider-BITjgC5p.js → XerticaProvider-CEoWMTxu.js} +2 -2
- package/dist/XerticaProvider-CeS5G_n5.cjs +45 -0
- package/dist/{XerticaProvider-By8q3Roe.cjs → XerticaProvider-CllrbMEJ.cjs} +2 -2
- package/dist/{XerticaProvider-B8CaV7xu.cjs → XerticaProvider-D-yNhF94.cjs} +1 -1
- package/dist/XerticaProvider-DDuiIcKo.js +39 -0
- package/dist/{XerticaProvider-DQtvJU7m.js → XerticaProvider-DYq4JWtg.js} +1 -1
- package/dist/{XerticaProvider-CWs6EwNa.js → XerticaProvider-Dt5HEzbQ.js} +10 -10
- package/dist/{XerticaProvider-CW9hpCdF.cjs → XerticaProvider-ET0ihewn.cjs} +2 -2
- package/dist/XerticaProvider-cI9hSs27.cjs +38 -0
- package/dist/XerticaProvider-hSwhNQex.js +39 -0
- package/dist/XerticaProvider-ra2NciRq.js +43 -0
- package/dist/{XerticaXLogo-ChryA6xj.js → XerticaXLogo-B7xQ5dhi.js} +1 -1
- package/dist/{XerticaXLogo-CziKMQil.cjs → XerticaXLogo-CQUUjXoH.cjs} +8 -8
- package/dist/{XerticaXLogo-DfUvz-lD.js → XerticaXLogo-Cmsp-Eey.js} +9 -9
- package/dist/{XerticaXLogo-CFuIlYFH.js → XerticaXLogo-DZbo4vOE.js} +12 -12
- package/dist/{XerticaXLogo-8TTzBjHw.cjs → XerticaXLogo-Zw2B276b.cjs} +1 -1
- package/dist/{XerticaXLogo-kslQ8Tk_.cjs → XerticaXLogo-bvZSgwGF.cjs} +13 -7
- package/dist/alert-dialog-BOje--vD.js +847 -0
- package/dist/alert-dialog-BtEuQqrg.cjs +870 -0
- package/dist/{alert-dialog-yckpaOpy.cjs → alert-dialog-DSKByiKZ.cjs} +3 -3
- package/dist/{alert-dialog-iDe5VE5o.js → alert-dialog-s-vmNkJ_.js} +3 -3
- package/dist/assistant.cjs.js +1 -1
- package/dist/assistant.es.js +1 -1
- package/dist/brand.cjs.js +1 -1
- package/dist/brand.es.js +1 -1
- package/dist/breadcrumb-CqJ7bHY5.js +161 -0
- package/dist/breadcrumb-m9Hb2_XN.cjs +177 -0
- package/dist/cli.js +45 -9
- package/dist/components/assistant/xertica-assistant/hooks/index.d.ts +6 -0
- package/dist/components/assistant/xertica-assistant/hooks/use-assistant-conversations.d.ts +21 -0
- package/dist/components/assistant/xertica-assistant/hooks/use-assistant-messages.d.ts +49 -0
- package/dist/components/assistant/xertica-assistant/hooks/use-assistant-suggestions.d.ts +16 -0
- package/dist/components/blocks/audio-player/AudioPlayer.d.ts +35 -0
- package/dist/components/blocks/audio-player/index.d.ts +1 -0
- package/dist/components/blocks/document-editor/DocumentEditor.d.ts +26 -0
- package/dist/components/blocks/document-editor/index.d.ts +1 -0
- package/dist/components/blocks/podcast-player/PodcastPlayer.d.ts +41 -0
- package/dist/components/blocks/podcast-player/index.d.ts +1 -0
- package/dist/components/brand/xertica-provider/XerticaProvider.d.ts +3 -1
- package/dist/components/ui/chart/chart.d.ts +12 -3
- package/dist/components/ui/chart/parts/chart-dashboard.d.ts +113 -0
- package/dist/components/ui/chart/parts/chart-metric.d.ts +118 -0
- package/dist/components/ui/chart/parts/chart-primitives.d.ts +101 -0
- package/dist/components/ui/chart/parts/chart-shared.d.ts +20 -0
- package/dist/components/ui/chart/parts/chart-utils.d.ts +12 -0
- package/dist/components/ui/chart/parts/index.d.ts +5 -0
- package/dist/components/ui/stats-card/stats-card.d.ts +10 -0
- package/dist/contexts/theme-data.d.ts +4 -0
- package/dist/dropdown-menu-BDB5CmQs.cjs +247 -0
- package/dist/dropdown-menu-DQidbKBD.js +231 -0
- package/dist/google-maps-loader-BFWp6VPd.js +287 -0
- package/dist/google-maps-loader-BKcdgFbu.cjs +312 -0
- package/dist/{google-maps-loader-t2IlYBzw.js → google-maps-loader-CTYySAun.js} +4 -0
- package/dist/google-maps-loader-CumCNXeG.js +312 -0
- package/dist/{google-maps-loader-BqsYL48U.cjs → google-maps-loader-Y-QkD-Li.cjs} +5 -0
- package/dist/google-maps-loader-eS3uQ5TA.cjs +287 -0
- package/dist/header-Cgy6vYPk.cjs +731 -0
- package/dist/header-DRlT4jgI.js +715 -0
- package/dist/header-Dux00SI4.cjs +731 -0
- package/dist/header-EkGKXPsD.js +715 -0
- package/dist/header-WfEywpyc.cjs +731 -0
- package/dist/header-tifNQn2U.js +715 -0
- package/dist/hooks.cjs.js +1 -1
- package/dist/hooks.es.js +1 -1
- package/dist/index-BhapVLVj.js +8 -0
- package/dist/{index-D3RLKRAs.cjs → index-COtD8bRW.cjs} +1 -1
- package/dist/index-D6fxYEY8.cjs +7 -0
- package/dist/index-DAIp0_HK.js +8 -0
- package/dist/index-DW5tYe26.js +8 -0
- package/dist/index-GA__GvnG.cjs +7 -0
- package/dist/index.cjs.js +6 -6
- package/dist/index.es.js +6 -6
- package/dist/index.umd.js +1043 -470
- package/dist/input-2R4loU86.js +127 -0
- package/dist/input-DWANSKGb.cjs +145 -0
- package/dist/layout.cjs.js +1 -1
- package/dist/layout.es.js +1 -1
- package/dist/pages.cjs.js +1 -1
- package/dist/pages.es.js +1 -1
- package/dist/progress-DPtzoVV8.js +175 -0
- package/dist/progress-EeaoqqUs.cjs +191 -0
- package/dist/rich-text-editor-0mraWT5y.cjs +2376 -0
- package/dist/rich-text-editor-B-IkcPD0.js +2874 -0
- package/dist/rich-text-editor-B2CKz7nx.cjs +2903 -0
- package/dist/rich-text-editor-B6jMRLzk.cjs +1939 -0
- package/dist/rich-text-editor-B8_oYcIR.js +1730 -0
- package/dist/rich-text-editor-B9UbSXNb.js +1203 -0
- package/dist/rich-text-editor-BYuRBNBU.js +2373 -0
- package/dist/rich-text-editor-Bb9pySTs.cjs +2374 -0
- package/dist/rich-text-editor-BcL6L3cm.cjs +2374 -0
- package/dist/rich-text-editor-BoVZYtTs.cjs +2391 -0
- package/dist/rich-text-editor-Bp3zQqMC.js +2954 -0
- package/dist/rich-text-editor-CMgSN_w2.js +1189 -0
- package/dist/rich-text-editor-CPV1lEPH.cjs +1748 -0
- package/dist/rich-text-editor-CeucBdIv.cjs +2971 -0
- package/dist/rich-text-editor-CoKqbCtu.cjs +1799 -0
- package/dist/rich-text-editor-Cw56T_mB.js +2356 -0
- package/dist/rich-text-editor-Cyt8qs2b.js +1921 -0
- package/dist/rich-text-editor-D6H84OcX.cjs +1220 -0
- package/dist/rich-text-editor-D76gD-QI.js +2328 -0
- package/dist/rich-text-editor-DKkokOnA.js +1781 -0
- package/dist/rich-text-editor-DNsdpN64.cjs +2359 -0
- package/dist/rich-text-editor-DfG8bCyY.js +2358 -0
- package/dist/rich-text-editor-DloeW0wc.js +2832 -0
- package/dist/rich-text-editor-Dxjw31Z4.js +2341 -0
- package/dist/rich-text-editor-DzP0Epmb.js +2356 -0
- package/dist/rich-text-editor-bRkNoeZY.cjs +2891 -0
- package/dist/rich-text-editor-lyYE2ZG5.cjs +1207 -0
- package/dist/rich-text-editor-skplNlBM.cjs +2345 -0
- package/dist/select-Bkbr0f-Z.cjs +162 -0
- package/dist/select-CvIVdX2n.js +145 -0
- package/dist/{sidebar-CplprZpM.js → sidebar-0ocFLSks.js} +127 -50
- package/dist/{sidebar-CA6_ek3f.js → sidebar-B6SlKZYN.js} +40 -49
- package/dist/{sidebar-CmvwjnVb.js → sidebar-BViy8Eeu.js} +17 -9
- package/dist/{sidebar-Dz7bd3zP.js → sidebar-BbVIQvlP.js} +1 -1
- package/dist/{sidebar-CVUGHOS_.cjs → sidebar-BxGXsDAd.cjs} +16 -8
- package/dist/sidebar-CK_0ZQHj.cjs +803 -0
- package/dist/sidebar-CUuOvYhK.js +787 -0
- package/dist/{sidebar-B3EYhli0.cjs → sidebar-CeTMuzOx.cjs} +128 -47
- package/dist/{sidebar-KIS0C2JH.js → sidebar-CrQDDdcz.js} +24 -33
- package/dist/{sidebar-zowjejT2.cjs → sidebar-DAaY8bRU.cjs} +24 -33
- package/dist/{sidebar-B9NR0lCe.cjs → sidebar-DQj1z3jG.cjs} +227 -269
- package/dist/sidebar-Djn5syhi.cjs +786 -0
- package/dist/sidebar-LluMXfam.js +759 -0
- package/dist/sidebar-_rT7rBMk.js +787 -0
- package/dist/{sidebar-BvF5I2Ue.cjs → sidebar-nzPoVHBQ.cjs} +41 -46
- package/dist/{sidebar-C5B_LHek.cjs → sidebar-q7P2Godd.cjs} +1 -1
- package/dist/slider-Bc5Hd0y1.js +56 -0
- package/dist/slider-N7hFFj6X.cjs +73 -0
- package/dist/tooltip-Ded96neP.cjs +137 -0
- package/dist/tooltip-HDOoD2-0.js +120 -0
- package/dist/ui.cjs.js +2 -2
- package/dist/ui.es.js +2 -2
- package/dist/use-audio-player-B31J-aqh.cjs +187 -0
- package/dist/use-audio-player-BkmEmj8Q.js +185 -0
- package/dist/use-audio-player-CLFTWFW1.cjs +184 -0
- package/dist/use-audio-player-CLLn00I6.js +188 -0
- package/dist/{use-audio-player-Dn1NR9xN.cjs → use-audio-player-NKsWyjWu.cjs} +7 -3
- package/dist/{use-audio-player-Bkh23vQ3.js → use-audio-player-nv8ZSGa1.js} +7 -3
- package/dist/use-file-upload-BcjEo2S5.js +404 -0
- package/dist/use-file-upload-CRJR68Tj.cjs +403 -0
- package/dist/use-mobile-B0hNy_Y6.cjs +4303 -0
- package/dist/use-mobile-BXuYROXM.js +4202 -0
- package/dist/use-mobile-Bbd51ASU.cjs +4392 -0
- package/dist/use-mobile-Bk6CX-TC.js +4359 -0
- package/dist/use-mobile-BvYdisLP.js +4202 -0
- package/dist/use-mobile-BzuxjzNX.cjs +4392 -0
- package/dist/use-mobile-CG2-SdXV.cjs +4235 -0
- package/dist/use-mobile-CKb5pqTs.js +4269 -0
- package/dist/use-mobile-CYuAuGDl.js +4202 -0
- package/dist/use-mobile-CaENcqm-.js +4508 -0
- package/dist/use-mobile-CbrYgJGJ.js +4203 -0
- package/dist/use-mobile-Cd4xPrKq.cjs +46 -0
- package/dist/use-mobile-DMOvImGQ.cjs +4542 -0
- package/dist/use-mobile-DRB3BQgD.cjs +4235 -0
- package/dist/use-mobile-DZvv7QMR.js +4359 -0
- package/dist/use-mobile-DdI_TXam.cjs +4235 -0
- package/dist/use-mobile-DlceKf8a.js +4359 -0
- package/dist/use-mobile-DsOnow1o.cjs +4236 -0
- package/dist/use-mobile-Kcj6jSnK.cjs +4392 -0
- package/dist/use-mobile-bnKcua_i.js +4202 -0
- package/dist/use-mobile-j4w2Jrf1.js +30 -0
- package/dist/use-mobile-ncXBeE2z.cjs +4235 -0
- package/dist/use-rich-text-editor-DjiddBGv.js +282 -0
- package/dist/use-rich-text-editor-lpeswbCs.cjs +281 -0
- package/dist/xertica-assistant-BdiZag0h.js +2187 -0
- package/dist/xertica-assistant-CrgTb6Hs.cjs +2155 -0
- package/dist/xertica-assistant-CyikE3N_.js +2173 -0
- package/dist/xertica-assistant-DCsnQyi5.js +2156 -0
- package/dist/xertica-assistant-DUBpmEgo.cjs +2186 -0
- package/dist/xertica-assistant-QFUnv5I2.cjs +2180 -0
- package/dist/{xertica-assistant-Bj3vBCq_.cjs → xertica-assistant-V_IdW4WF.cjs} +27 -9
- package/dist/{xertica-assistant-BMqdyRVi.js → xertica-assistant-ciJaWqm1.js} +28 -10
- package/dist/{xertica-assistant-B1IaHXnB.cjs → xertica-assistant-dyP7KHM5.cjs} +533 -392
- package/dist/{xertica-assistant-DPsESB6t.js → xertica-assistant-yX1CFBBo.js} +535 -394
- package/dist/xertica-ui.css +2 -2
- package/docs/architecture-improvements.md +456 -456
- package/docs/architecture.md +312 -312
- package/docs/components/assistant.md +428 -428
- package/docs/components/branding.md +252 -252
- package/docs/components/card-patterns.md +447 -447
- package/docs/components/error-boundary.md +201 -201
- package/docs/components/hooks.md +432 -432
- package/docs/components/language-selector.md +176 -176
- package/docs/components/pages.md +323 -323
- package/docs/components/sidebar.md +19 -2
- package/docs/components/stats-card.md +20 -2
- package/docs/doc-audit.md +244 -244
- package/docs/getting-started.md +616 -616
- package/docs/guidelines.md +330 -330
- package/docs/i18n.md +480 -480
- package/docs/installation.md +268 -268
- package/docs/llms.md +295 -295
- package/docs/state-management.md +289 -289
- package/guidelines/Guidelines.md +409 -409
- package/llms-compact.txt +30 -1
- package/llms-full.txt +11553 -7133
- package/llms.txt +1 -1
- package/package.json +219 -219
- package/styles/xertica/base.css +90 -90
- package/styles/xertica/tokens.css +9 -9
- package/templates/.prettierignore +4 -4
- package/templates/.prettierrc +10 -10
- package/templates/CLAUDE.md +180 -180
- package/templates/guidelines/Guidelines.md +865 -577
- package/templates/package.json +69 -69
- package/templates/src/app/App.tsx +46 -46
- package/templates/src/app/components/AuthGuard.tsx +131 -131
- package/templates/src/features/assistant/data/mock.ts +75 -75
- package/templates/src/features/assistant/hooks/useAssistantConfig.ts +20 -20
- package/templates/src/features/assistant/index.ts +5 -5
- package/templates/src/features/auth/ui/AuthPageShell.tsx +32 -32
- package/templates/src/features/auth/ui/ForgotPasswordContent.tsx +70 -70
- package/templates/src/features/auth/ui/LoginContent.tsx +92 -92
- package/templates/src/features/auth/ui/ResetPasswordContent.tsx +183 -183
- package/templates/src/features/auth/ui/SocialLoginButtons.tsx +78 -78
- package/templates/src/features/auth/ui/VerifyEmailContent.tsx +80 -80
- package/templates/src/features/home/data/mock.ts +41 -41
- package/templates/src/features/home/hooks/useFeatureCards.ts +20 -20
- package/templates/src/features/home/index.ts +11 -11
- package/templates/src/features/home/ui/HomeContent.tsx +117 -117
- package/templates/src/features/template/ui/CrudTemplate.tsx +112 -112
- package/templates/src/features/template/ui/DashboardTemplate.tsx +110 -110
- package/templates/src/features/template/ui/FormTemplate.tsx +117 -117
- package/templates/src/features/template/ui/LoginTemplate.tsx +59 -59
- package/templates/src/features/template/ui/TemplateContent.tsx +1322 -1322
- package/templates/src/i18n.ts +124 -124
- package/templates/src/locales/en/common.json +21 -21
- package/templates/src/locales/en/components/activityCard.json +10 -10
- package/templates/src/locales/en/components/assistant.json +119 -119
- package/templates/src/locales/en/components/media.json +29 -29
- package/templates/src/locales/en/components/notificationCard.json +5 -5
- package/templates/src/locales/en/components/profileCard.json +8 -8
- package/templates/src/locales/en/components/projectCard.json +10 -10
- package/templates/src/locales/en/components/sidebar.json +14 -14
- package/templates/src/locales/en/components/stats.json +8 -8
- package/templates/src/locales/en/components/team.json +14 -14
- package/templates/src/locales/en/errors.json +9 -9
- package/templates/src/locales/en/languageSelector.json +7 -7
- package/templates/src/locales/en/nav.json +6 -6
- package/templates/src/locales/en/pages/crudTemplate.json +25 -25
- package/templates/src/locales/en/pages/dashboardTemplate.json +20 -20
- package/templates/src/locales/en/pages/forgotPassword.json +10 -10
- package/templates/src/locales/en/pages/formTemplate.json +16 -16
- package/templates/src/locales/en/pages/home.json +7 -7
- package/templates/src/locales/en/pages/login.json +15 -15
- package/templates/src/locales/en/pages/loginTemplate.json +9 -9
- package/templates/src/locales/en/pages/resetPassword.json +18 -18
- package/templates/src/locales/en/pages/templates.json +317 -317
- package/templates/src/locales/en/pages/verifyEmail.json +12 -12
- package/templates/src/locales/en/themeToggle.json +6 -6
- package/templates/src/locales/es/common.json +21 -21
- package/templates/src/locales/es/components/activityCard.json +10 -10
- package/templates/src/locales/es/components/assistant.json +119 -119
- package/templates/src/locales/es/components/media.json +29 -29
- package/templates/src/locales/es/components/notificationCard.json +5 -5
- package/templates/src/locales/es/components/profileCard.json +8 -8
- package/templates/src/locales/es/components/projectCard.json +10 -10
- package/templates/src/locales/es/components/sidebar.json +14 -14
- package/templates/src/locales/es/components/stats.json +8 -8
- package/templates/src/locales/es/components/team.json +14 -14
- package/templates/src/locales/es/errors.json +9 -9
- package/templates/src/locales/es/languageSelector.json +7 -7
- package/templates/src/locales/es/nav.json +6 -6
- package/templates/src/locales/es/pages/crudTemplate.json +25 -25
- package/templates/src/locales/es/pages/dashboardTemplate.json +20 -20
- package/templates/src/locales/es/pages/forgotPassword.json +10 -10
- package/templates/src/locales/es/pages/formTemplate.json +16 -16
- package/templates/src/locales/es/pages/home.json +7 -7
- package/templates/src/locales/es/pages/login.json +15 -15
- package/templates/src/locales/es/pages/loginTemplate.json +9 -9
- package/templates/src/locales/es/pages/resetPassword.json +18 -18
- package/templates/src/locales/es/pages/templates.json +317 -317
- package/templates/src/locales/es/pages/verifyEmail.json +12 -12
- package/templates/src/locales/es/themeToggle.json +6 -6
- package/templates/src/locales/pt-BR/common.json +21 -21
- package/templates/src/locales/pt-BR/components/activityCard.json +10 -10
- package/templates/src/locales/pt-BR/components/assistant.json +119 -119
- package/templates/src/locales/pt-BR/components/media.json +29 -29
- package/templates/src/locales/pt-BR/components/notificationCard.json +5 -5
- package/templates/src/locales/pt-BR/components/profileCard.json +8 -8
- package/templates/src/locales/pt-BR/components/projectCard.json +10 -10
- package/templates/src/locales/pt-BR/components/sidebar.json +14 -14
- package/templates/src/locales/pt-BR/components/stats.json +8 -8
- package/templates/src/locales/pt-BR/components/team.json +14 -14
- package/templates/src/locales/pt-BR/errors.json +9 -9
- package/templates/src/locales/pt-BR/languageSelector.json +7 -7
- package/templates/src/locales/pt-BR/nav.json +6 -6
- package/templates/src/locales/pt-BR/pages/crudTemplate.json +25 -25
- package/templates/src/locales/pt-BR/pages/dashboardTemplate.json +20 -20
- package/templates/src/locales/pt-BR/pages/forgotPassword.json +10 -10
- package/templates/src/locales/pt-BR/pages/formTemplate.json +16 -16
- package/templates/src/locales/pt-BR/pages/home.json +7 -7
- package/templates/src/locales/pt-BR/pages/login.json +15 -15
- package/templates/src/locales/pt-BR/pages/loginTemplate.json +9 -9
- package/templates/src/locales/pt-BR/pages/resetPassword.json +18 -18
- package/templates/src/locales/pt-BR/pages/templates.json +317 -317
- package/templates/src/locales/pt-BR/pages/verifyEmail.json +12 -12
- package/templates/src/locales/pt-BR/themeToggle.json +6 -6
- package/templates/src/pages/AssistantPage.tsx +470 -470
- package/templates/src/pages/HomePage.tsx +53 -53
- package/templates/src/shared/error-boundary.tsx +150 -150
- package/templates/src/shared/error-fallbacks.tsx +222 -222
- package/templates/src/styles/xertica/tokens.css +9 -9
- package/templates/vite.config.js +20 -20
- package/templates/vite.config.ts +55 -55
- package/dist/ThemeContext-CpqYShLq.cjs +0 -324
- package/dist/ThemeContext-Du2nE1PL.js +0 -325
- package/dist/ThemeContext-GeEBTJ3q.cjs +0 -1621
- package/dist/ThemeContext-JyLK9B1o.js +0 -1622
- package/dist/VerifyEmailPage-BiRm7Nh4.cjs +0 -3213
- package/dist/VerifyEmailPage-hdB8JQGv.cjs +0 -3213
- package/dist/VerifyEmailPage-vYHbYK3q.js +0 -3214
- package/dist/XerticaProvider-CUYJZc32.js +0 -49
- package/dist/XerticaProvider-CjQAQPcn.cjs +0 -48
- package/dist/XerticaProvider-D5lLumH-.js +0 -49
- package/dist/XerticaProvider-qQUDop71.cjs +0 -48
- package/dist/XerticaXLogo-BWaag64t.js +0 -252
- package/dist/XerticaXLogo-CU-U-GP4.cjs +0 -251
- package/dist/index-CkTUgOwX.js +0 -8
- package/dist/sidebar-OTO_up7Z.js +0 -801
- package/dist/{rich-text-editor-BmsjY03B.js → rich-text-editor-DgF8s7xW.js} +26 -26
- package/dist/{rich-text-editor-GS2kpTAK.cjs → rich-text-editor-mWoaSCE4.cjs} +26 -26
|
@@ -1,577 +1,865 @@
|
|
|
1
|
-
# Project Guidelines — Xertica UI App
|
|
2
|
-
|
|
3
|
-
> **Scope**: These guidelines apply to React
|
|
4
|
-
>
|
|
5
|
-
> **AI agents
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
│
|
|
22
|
-
│
|
|
23
|
-
|
|
24
|
-
│
|
|
25
|
-
│
|
|
26
|
-
│
|
|
27
|
-
│
|
|
28
|
-
|
|
29
|
-
│
|
|
30
|
-
│
|
|
31
|
-
├──
|
|
32
|
-
│ ├──
|
|
33
|
-
│ │
|
|
34
|
-
│
|
|
35
|
-
│
|
|
36
|
-
│
|
|
37
|
-
|
|
38
|
-
│
|
|
39
|
-
│
|
|
40
|
-
│ │
|
|
41
|
-
│ ├──
|
|
42
|
-
│ │ ├──
|
|
43
|
-
│ │ ├──
|
|
44
|
-
│ │
|
|
45
|
-
│
|
|
46
|
-
│ │
|
|
47
|
-
│ ├──
|
|
48
|
-
│ │
|
|
49
|
-
│
|
|
50
|
-
│
|
|
51
|
-
│ ├──
|
|
52
|
-
│ ├──
|
|
53
|
-
│
|
|
54
|
-
│
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
│
|
|
58
|
-
│
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
│ ├──
|
|
62
|
-
│ └──
|
|
63
|
-
│
|
|
64
|
-
├──
|
|
65
|
-
├──
|
|
66
|
-
│
|
|
67
|
-
│
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
import {
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
3.
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
|
211
|
-
|
|
212
|
-
|
|
|
213
|
-
|
|
|
214
|
-
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
<
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
<
|
|
255
|
-
|
|
256
|
-
<
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
const
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
//
|
|
305
|
-
<
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
-
|
|
346
|
-
-
|
|
347
|
-
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
)
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
```tsx
|
|
427
|
-
//
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
```
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
1
|
+
# Project Guidelines — Xertica UI App
|
|
2
|
+
|
|
3
|
+
> **Scope**: These guidelines apply to any React application scaffolded with `npx xertica-ui@latest init`. They define architecture, import conventions, component rules, state management, and AI agent behavior.
|
|
4
|
+
>
|
|
5
|
+
> **AI agents — reading order**:
|
|
6
|
+
> 1. This file (architecture + rules)
|
|
7
|
+
> 2. `node_modules/xertica-ui/llms-compact.txt` (component catalog + quick reference)
|
|
8
|
+
> 3. `node_modules/xertica-ui/docs/decision-tree.md` (when choosing between similar components)
|
|
9
|
+
> 4. `node_modules/xertica-ui/docs/components/<name>.md` (when you need a specific component's full props)
|
|
10
|
+
> 5. `node_modules/xertica-ui/docs/ai-usage.md` (mandatory constraint list)
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 1. Architecture — Feature-Sliced Design + Feature-Driven Architecture
|
|
15
|
+
|
|
16
|
+
This project follows **FSD (Feature-Sliced Design)** layered architecture combined with **FDA (Feature-Driven Architecture)** vertical slicing. **Layers can only import from layers below them.**
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
src/
|
|
20
|
+
├── app/ # Layer 1 — Application shell (imports from all layers)
|
|
21
|
+
│ ├── App.tsx # XerticaProvider + BrowserRouter + AuthGuard (CLI-generated)
|
|
22
|
+
│ ├── context/
|
|
23
|
+
│ │ └── AuthContext.tsx # AuthProvider + useAuth() hook
|
|
24
|
+
│ └── components/
|
|
25
|
+
│ ├── AppLayout.tsx # Sidebar + children + optional XerticaAssistant
|
|
26
|
+
│ └── AuthGuard.tsx # All route definitions + route guard components
|
|
27
|
+
│
|
|
28
|
+
├── shared/ # Layer 2 — Shared utilities (no business logic)
|
|
29
|
+
│ ├── config/
|
|
30
|
+
│ │ └── navigation.ts # RouteConfig type, routes[], getRoutesByRole()
|
|
31
|
+
│ ├── mock/ # Domain mock data (TypeScript static arrays + helpers)
|
|
32
|
+
│ ├── lib/
|
|
33
|
+
│ │ └── auth.ts # getStoredUser, storeUser, clearStoredUser
|
|
34
|
+
│ └── types/
|
|
35
|
+
│ └── auth.ts # User interface + UserRole type
|
|
36
|
+
│
|
|
37
|
+
├── features/ # Layer 3 — Vertical slices by business capability
|
|
38
|
+
│ ├── auth/ # Login, ForgotPassword, VerifyEmail, ResetPassword
|
|
39
|
+
│ ├── home/ # Post-login hub (FeatureCards grid)
|
|
40
|
+
│ │ ├── data/mock.ts # Types + async fetch + factory functions (getMockXxx)
|
|
41
|
+
│ │ ├── hooks/useFeatureCards.ts # React Query, queryKey includes `language`
|
|
42
|
+
│ │ ├── store/dashboardStore.ts # Zustand UI state (no server data)
|
|
43
|
+
│ │ ├── ui/HomeContent.tsx
|
|
44
|
+
│ │ └── index.ts
|
|
45
|
+
│ ├── assistant/ # XerticaAssistant — AppLayout depends on it
|
|
46
|
+
│ │ ├── data/mock.ts
|
|
47
|
+
│ │ ├── hooks/useAssistantConfig.ts
|
|
48
|
+
│ │ └── index.ts
|
|
49
|
+
│ └── <domain>/ # One slice per business domain
|
|
50
|
+
│ ├── data/mock.ts # Domain types + mock fetch functions
|
|
51
|
+
│ ├── hooks/use<Domain>.ts # React Query wrapper
|
|
52
|
+
│ ├── store/<domain>Store.ts # Zustand UI state (optional)
|
|
53
|
+
│ ├── ui/<Domain>Content.tsx # Page content component
|
|
54
|
+
│ └── index.ts # Barrel — ONLY public interface for this feature
|
|
55
|
+
│
|
|
56
|
+
├── pages/ # Layer 4 — Thin route wrappers only
|
|
57
|
+
│ └── <Name>Page.tsx # AppLayout + <NameContent> + optional XerticaAssistant
|
|
58
|
+
│
|
|
59
|
+
├── i18n.ts # i18next setup (CLI-generated — do not hand-edit)
|
|
60
|
+
├── locales/
|
|
61
|
+
│ ├── .languages.json # CLI-managed language selection
|
|
62
|
+
│ └── pt-BR/ # One folder per language
|
|
63
|
+
│ ├── common.json # Shared action labels
|
|
64
|
+
│ ├── nav.json # Navigation labels
|
|
65
|
+
│ ├── errors.json # Error boundary UI
|
|
66
|
+
│ ├── pages/ # Per-page namespaces
|
|
67
|
+
│ └── components/ # Per-component namespaces
|
|
68
|
+
└── styles/
|
|
69
|
+
├── index.css # Imports: xertica-ui/style.css, tokens.css, @source
|
|
70
|
+
└── xertica/tokens.css # Brand CSS variables — customize here only
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Layer Import Rules
|
|
74
|
+
|
|
75
|
+
- `app/` → can import from all layers
|
|
76
|
+
- `shared/` → cannot import from `features/` or `pages/`
|
|
77
|
+
- `features/<a>/` → cannot import from `features/<b>/` — extract shared code to `shared/`
|
|
78
|
+
- `pages/` → imports only from `features/` barrels and `app/`
|
|
79
|
+
|
|
80
|
+
### Feature Barrel Rule
|
|
81
|
+
|
|
82
|
+
The `index.ts` is the **only** public interface of a feature. Always import from the barrel, never from internal paths:
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
// ✅ Correct
|
|
86
|
+
import { LoginContent } from '../features/auth';
|
|
87
|
+
|
|
88
|
+
// ❌ Wrong — never import from internal paths
|
|
89
|
+
import { LoginContent } from '../features/auth/ui/LoginContent';
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## 2. Import Rules
|
|
95
|
+
|
|
96
|
+
Always use the correct `xertica-ui` subpath for the domain you need:
|
|
97
|
+
|
|
98
|
+
```tsx
|
|
99
|
+
// UI primitives — buttons, inputs, dialogs, tables, badges, etc.
|
|
100
|
+
import {
|
|
101
|
+
Button, Input, Textarea, Select, SelectContent, SelectItem, SelectTrigger, SelectValue,
|
|
102
|
+
Card, CardContent, CardHeader, CardTitle, CardDescription, CardFooter,
|
|
103
|
+
Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter,
|
|
104
|
+
AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader,
|
|
105
|
+
AlertDialogTitle, AlertDialogDescription, AlertDialogFooter,
|
|
106
|
+
AlertDialogCancel, AlertDialogAction,
|
|
107
|
+
Table, TableBody, TableCell, TableHead, TableHeader, TableRow,
|
|
108
|
+
Badge, Progress, ScrollArea, Separator, Skeleton, Label, Switch,
|
|
109
|
+
Tabs, TabsContent, TabsList, TabsTrigger,
|
|
110
|
+
Collapsible, CollapsibleContent, CollapsibleTrigger,
|
|
111
|
+
Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage,
|
|
112
|
+
Tooltip, TooltipContent, TooltipProvider, TooltipTrigger,
|
|
113
|
+
Popover, PopoverContent, PopoverTrigger,
|
|
114
|
+
Sheet, SheetContent, SheetHeader, SheetTitle, SheetDescription,
|
|
115
|
+
Alert, AlertDescription, Drawer,
|
|
116
|
+
} from 'xertica-ui/ui';
|
|
117
|
+
|
|
118
|
+
// Composed high-level block components
|
|
119
|
+
import {
|
|
120
|
+
FeatureCard, FeatureCardSkeleton,
|
|
121
|
+
QuickActionCard, QuickActionCardSkeleton,
|
|
122
|
+
ProjectCard, ProjectCardSkeleton,
|
|
123
|
+
ActivityCard, ActivityCardSkeleton,
|
|
124
|
+
NotificationCard, NotificationCardSkeleton,
|
|
125
|
+
ProfileCard, ProfileCardSkeleton,
|
|
126
|
+
StatsCard, StatsCardSkeleton,
|
|
127
|
+
} from 'xertica-ui/blocks';
|
|
128
|
+
|
|
129
|
+
// Application shell
|
|
130
|
+
import { Sidebar, Header } from 'xertica-ui/layout';
|
|
131
|
+
|
|
132
|
+
// Brand / providers
|
|
133
|
+
import { XerticaProvider, XerticaLogo, ThemeToggle, LanguageSelector } from 'xertica-ui/brand';
|
|
134
|
+
|
|
135
|
+
// AI assistant
|
|
136
|
+
import { XerticaAssistant, generateDemoResponse } from 'xertica-ui/assistant';
|
|
137
|
+
|
|
138
|
+
// Media players
|
|
139
|
+
import { VideoPlayer, AudioPlayer } from 'xertica-ui/media';
|
|
140
|
+
|
|
141
|
+
// Hooks
|
|
142
|
+
import { useLayout, useOptionalLayout, useTheme, useLanguage } from 'xertica-ui/hooks';
|
|
143
|
+
|
|
144
|
+
// Icons — ALWAYS from lucide-react, NEVER from xertica-ui or inline SVG
|
|
145
|
+
import { Home, Settings, Plus, Trash2, ChevronRight, Search } from 'lucide-react';
|
|
146
|
+
|
|
147
|
+
// Charts — use recharts (pre-installed)
|
|
148
|
+
import {
|
|
149
|
+
BarChart, Bar, LineChart, Line, PieChart, Pie, Cell,
|
|
150
|
+
XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer,
|
|
151
|
+
} from 'recharts';
|
|
152
|
+
|
|
153
|
+
// Toast
|
|
154
|
+
import { toast } from 'sonner';
|
|
155
|
+
|
|
156
|
+
// Form validation
|
|
157
|
+
import { useForm } from 'react-hook-form';
|
|
158
|
+
import { zodResolver } from '@hookform/resolvers/zod';
|
|
159
|
+
import * as z from 'zod';
|
|
160
|
+
|
|
161
|
+
// i18n
|
|
162
|
+
import { useTranslation } from 'react-i18next';
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
> **Never import from `xertica-ui` root barrel in FSD/FDA projects.** Always use the granular subpaths above — they produce smaller bundles and prevent accidental cross-domain coupling.
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## 3. Non-Negotiable Rules
|
|
170
|
+
|
|
171
|
+
### 3.1 No Raw HTML for UI Surfaces
|
|
172
|
+
|
|
173
|
+
| ❌ Never | ✅ Always |
|
|
174
|
+
|---|---|
|
|
175
|
+
| `<button>` | `<Button>` from `xertica-ui/ui` |
|
|
176
|
+
| `<input>` | `<Input>` from `xertica-ui/ui` |
|
|
177
|
+
| `<select>` | `<Select>` from `xertica-ui/ui` |
|
|
178
|
+
| `<textarea>` | `<Textarea>` from `xertica-ui/ui` |
|
|
179
|
+
| `<div class="card ...">` | `<Card>` from `xertica-ui/ui` |
|
|
180
|
+
| Custom scrollable `<div>` | `<ScrollArea>` from `xertica-ui/ui` |
|
|
181
|
+
| Raw `<progress>` | `<Progress>` from `xertica-ui/ui` |
|
|
182
|
+
| Inline SVG `<svg><path .../></svg>` | `import { IconName } from 'lucide-react'` |
|
|
183
|
+
|
|
184
|
+
### 3.2 Color Rules
|
|
185
|
+
|
|
186
|
+
**Always forbidden:**
|
|
187
|
+
```tsx
|
|
188
|
+
// ❌ Never — raw values are non-themeable
|
|
189
|
+
style={{ backgroundColor: '#3B82F6' }}
|
|
190
|
+
style={{ color: 'rgb(59,130,246)' }}
|
|
191
|
+
className="text-[#ffffff]"
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**Required for semantic/status contexts** (errors, warnings, success, danger actions, status badges):
|
|
195
|
+
```tsx
|
|
196
|
+
// ❌ Wrong — Tailwind color for semantic state
|
|
197
|
+
<div className="bg-red-500">Error</div>
|
|
198
|
+
|
|
199
|
+
// ✅ Required — token adapts to theme and dark mode
|
|
200
|
+
<div className="bg-destructive text-destructive-foreground">Error</div>
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**Acceptable for non-semantic layout** (spacing, decorative elements, charts):
|
|
204
|
+
```tsx
|
|
205
|
+
// ✅ OK — non-semantic context, no theme dependency
|
|
206
|
+
<div className="bg-blue-500/15 border-gray-200">Decorative</div>
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Semantic token reference:
|
|
210
|
+
| Intent | Token class |
|
|
211
|
+
|---|---|
|
|
212
|
+
| Error / Danger | `bg-destructive` / `text-destructive` |
|
|
213
|
+
| Warning | `bg-warning` / `text-warning` |
|
|
214
|
+
| Success | `bg-success` / `text-success` |
|
|
215
|
+
| Informational | `bg-info` / `text-info` |
|
|
216
|
+
| Neutral/secondary | `bg-secondary` / `text-secondary-foreground` |
|
|
217
|
+
| Primary action | `bg-primary` / `text-primary-foreground` |
|
|
218
|
+
| Muted background | `bg-muted` / `text-muted-foreground` |
|
|
219
|
+
|
|
220
|
+
### 3.3 Border Radius — Never Hardcode
|
|
221
|
+
|
|
222
|
+
```tsx
|
|
223
|
+
// ❌ Wrong
|
|
224
|
+
className="rounded-lg"
|
|
225
|
+
className="rounded-xl"
|
|
226
|
+
|
|
227
|
+
// ✅ Correct — inherits the project's configured radius token
|
|
228
|
+
className="rounded-[var(--radius)]"
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### 3.4 Layout State — Never Hardcode
|
|
232
|
+
|
|
233
|
+
```tsx
|
|
234
|
+
// ❌ Wrong — breaks when sidebar width changes
|
|
235
|
+
<div style={{ paddingLeft: '280px' }}>
|
|
236
|
+
|
|
237
|
+
// ✅ Correct — always from context
|
|
238
|
+
const { sidebarExpanded, sidebarWidth } = useLayout();
|
|
239
|
+
<div style={{ paddingLeft: sidebarExpanded ? `${sidebarWidth}px` : '80px' }}>
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
`80px` is the fixed collapsed sidebar width. The expanded value (`sidebarWidth`) defaults to `280px` but is configurable. Never hardcode either value.
|
|
243
|
+
|
|
244
|
+
### 3.5 Destructive Actions — Always Confirm with AlertDialog
|
|
245
|
+
|
|
246
|
+
```tsx
|
|
247
|
+
<AlertDialog>
|
|
248
|
+
<AlertDialogTrigger asChild>
|
|
249
|
+
<Button variant="destructive">Delete Record</Button>
|
|
250
|
+
</AlertDialogTrigger>
|
|
251
|
+
<AlertDialogContent>
|
|
252
|
+
<AlertDialogHeader>
|
|
253
|
+
<AlertDialogTitle>Are you sure?</AlertDialogTitle>
|
|
254
|
+
<AlertDialogDescription>This action cannot be undone.</AlertDialogDescription>
|
|
255
|
+
</AlertDialogHeader>
|
|
256
|
+
<AlertDialogFooter>
|
|
257
|
+
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
|
258
|
+
<AlertDialogAction onClick={handleDelete}>Delete</AlertDialogAction>
|
|
259
|
+
</AlertDialogFooter>
|
|
260
|
+
</AlertDialogContent>
|
|
261
|
+
</AlertDialog>
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### 3.6 Toast Notifications
|
|
265
|
+
|
|
266
|
+
Use `toast` from `sonner` for ephemeral action feedback. Never render `<Toaster>` manually — it is auto-injected by `<XerticaProvider>`.
|
|
267
|
+
|
|
268
|
+
```tsx
|
|
269
|
+
import { toast } from 'sonner';
|
|
270
|
+
|
|
271
|
+
toast.success(t('users.createSuccess'));
|
|
272
|
+
toast.error(t('errors.somethingWentWrong'));
|
|
273
|
+
toast.info(t('feature.inDevelopment'));
|
|
274
|
+
toast.warning(t('billing.syncConflict'));
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### 3.7 Form Validation — react-hook-form + zod
|
|
278
|
+
|
|
279
|
+
Never implement manual validation with `useState` + conditional checks:
|
|
280
|
+
|
|
281
|
+
```tsx
|
|
282
|
+
// ❌ Wrong — manual validation
|
|
283
|
+
const [error, setError] = useState('');
|
|
284
|
+
if (!email.includes('@')) setError('Invalid email');
|
|
285
|
+
|
|
286
|
+
// ✅ Correct — declarative schema, errors flow automatically
|
|
287
|
+
const schema = z.object({
|
|
288
|
+
email: z.string().email('Invalid email address'),
|
|
289
|
+
name: z.string().min(2, 'Name must be at least 2 characters'),
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
const form = useForm({ resolver: zodResolver(schema) });
|
|
293
|
+
// Error messages render automatically via <FormMessage />
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### 3.8 Mock Data Belongs in `data/mock.ts`
|
|
297
|
+
|
|
298
|
+
Never hardcode data arrays inside component files:
|
|
299
|
+
|
|
300
|
+
```tsx
|
|
301
|
+
// ❌ Wrong — data inside the component
|
|
302
|
+
const users = [{ id: 1, name: 'Alice' }, ...];
|
|
303
|
+
|
|
304
|
+
// ✅ Correct — data in features/<domain>/data/mock.ts
|
|
305
|
+
export async function fetchUsers(): Promise<User[]> {
|
|
306
|
+
await new Promise(r => setTimeout(r, 300)); // simulate network
|
|
307
|
+
return MOCK_USERS;
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## 4. Page Structure — Standard Shell
|
|
314
|
+
|
|
315
|
+
Every content component follows this exact shell. No exceptions:
|
|
316
|
+
|
|
317
|
+
```tsx
|
|
318
|
+
import { Link } from 'react-router-dom';
|
|
319
|
+
import { Header } from 'xertica-ui/layout';
|
|
320
|
+
import { ScrollArea } from 'xertica-ui/ui';
|
|
321
|
+
import { useLayout } from 'xertica-ui/hooks';
|
|
322
|
+
import { useTranslation } from 'react-i18next';
|
|
323
|
+
|
|
324
|
+
export function ExampleContent() {
|
|
325
|
+
const { t } = useTranslation();
|
|
326
|
+
const { sidebarExpanded, sidebarWidth } = useLayout();
|
|
327
|
+
|
|
328
|
+
return (
|
|
329
|
+
<div
|
|
330
|
+
style={{ paddingLeft: sidebarExpanded ? `${sidebarWidth}px` : '80px' }}
|
|
331
|
+
className="flex-1 flex flex-col overflow-hidden transition-all duration-300"
|
|
332
|
+
>
|
|
333
|
+
{/* Header with breadcrumbs + theme/language controls */}
|
|
334
|
+
<Header
|
|
335
|
+
showThemeToggle
|
|
336
|
+
showLanguageSelector
|
|
337
|
+
breadcrumbs={[
|
|
338
|
+
{ label: t('nav.home', 'App'), href: '/home' },
|
|
339
|
+
{ label: t('nav.thisPage', 'This Page') },
|
|
340
|
+
]}
|
|
341
|
+
renderLink={(href, props) => <Link to={href} {...props} />}
|
|
342
|
+
/>
|
|
343
|
+
|
|
344
|
+
{/* Scrollable main content */}
|
|
345
|
+
<main className="flex-1 overflow-hidden bg-muted">
|
|
346
|
+
<ScrollArea className="h-full">
|
|
347
|
+
<div className="p-4 md:p-6">
|
|
348
|
+
<div className="max-w-7xl mx-auto space-y-6">
|
|
349
|
+
{/* 1. KPI StatsCards row (if applicable) */}
|
|
350
|
+
{/* 2. Main content cards */}
|
|
351
|
+
{/* 3. Tables with filters */}
|
|
352
|
+
</div>
|
|
353
|
+
</div>
|
|
354
|
+
</ScrollArea>
|
|
355
|
+
</main>
|
|
356
|
+
|
|
357
|
+
{/* Dialogs / Sheets rendered OUTSIDE <main> */}
|
|
358
|
+
</div>
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### Pages Are Thin Wrappers
|
|
364
|
+
|
|
365
|
+
```tsx
|
|
366
|
+
// pages/ExamplePage.tsx — thin wrapper only, no logic
|
|
367
|
+
export function ExamplePage() {
|
|
368
|
+
return (
|
|
369
|
+
<AppLayout>
|
|
370
|
+
<ExampleContent />
|
|
371
|
+
</AppLayout>
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
---
|
|
377
|
+
|
|
378
|
+
## 5. Adding a New Route (Step-by-Step)
|
|
379
|
+
|
|
380
|
+
1. **Create feature content**: `src/features/<name>/ui/<NameContent>.tsx`
|
|
381
|
+
2. **Export from the barrel**: `src/features/<name>/index.ts`
|
|
382
|
+
3. **Create the page**: `src/pages/<NamePage>.tsx` (thin AppLayout wrapper)
|
|
383
|
+
4. **Register the route** in `src/shared/config/navigation.ts`:
|
|
384
|
+
```ts
|
|
385
|
+
import { IconName } from 'lucide-react';
|
|
386
|
+
|
|
387
|
+
{ path: '/route', label: 'Label', labelKey: 'nav.keyName',
|
|
388
|
+
icon: IconName, allowedRoles: ['admin', 'parceira'], group: 'groupName' }
|
|
389
|
+
```
|
|
390
|
+
5. **Register the `<Route>`** in `src/app/components/AuthGuard.tsx`:
|
|
391
|
+
```tsx
|
|
392
|
+
<Route path="/route" element={
|
|
393
|
+
<RoleRoute allowedRoles={['admin', 'parceira']}>
|
|
394
|
+
<NamePage />
|
|
395
|
+
</RoleRoute>
|
|
396
|
+
} />
|
|
397
|
+
```
|
|
398
|
+
6. **Add the i18n key** to `src/locales/<lang>/nav.json` for every configured language
|
|
399
|
+
7. **Add a navigation card** to `HomeContent.tsx` if this is a primary module
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
403
|
+
## 6. Authentication Pattern
|
|
404
|
+
|
|
405
|
+
Auth state lives in `src/app/context/AuthContext.tsx` via `useAuth()`:
|
|
406
|
+
|
|
407
|
+
```tsx
|
|
408
|
+
const { user, isLoading, login, logout } = useAuth();
|
|
409
|
+
|
|
410
|
+
// isLoading: true while localStorage is being read — ALWAYS check before redirecting
|
|
411
|
+
// user: null when not authenticated; User object when authenticated
|
|
412
|
+
// login(email, password): returns boolean — true on success
|
|
413
|
+
// logout(): clears storage, navigates to /login
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
### Route Guards
|
|
417
|
+
|
|
418
|
+
Three guard components are defined in `AuthGuard.tsx`:
|
|
419
|
+
|
|
420
|
+
| Guard | Behavior |
|
|
421
|
+
|---|---|
|
|
422
|
+
| `<GuestRoute>` | Auth pages only. Redirects authenticated users to `getRoleHome(role)` |
|
|
423
|
+
| `<ProtectedRoute>` | Any authenticated user. Redirects unauthenticated to `/login` |
|
|
424
|
+
| `<RoleRoute allowedRoles={[]}>` | Role-specific. Unauthorized roles redirect to `getRoleHome(role)` — never to `/login` |
|
|
425
|
+
|
|
426
|
+
```tsx
|
|
427
|
+
// getRoleHome(role) — determines post-login landing per role
|
|
428
|
+
// Default pattern: most roles → '/home', restricted roles → their designated page
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
### MOCK_USERS in AuthContext
|
|
432
|
+
|
|
433
|
+
For prototypes, credentials are stored in `MOCK_USERS` in `AuthContext.tsx`. Each entry maps email → `{ password, name, role, avatar?, clienteId? }`. The `clienteId` field is used for data isolation (e.g., a client user who can only see their own records).
|
|
434
|
+
|
|
435
|
+
---
|
|
436
|
+
|
|
437
|
+
## 7. Navigation and Sidebar Configuration
|
|
438
|
+
|
|
439
|
+
### `RouteConfig` Shape (`src/shared/config/navigation.ts`)
|
|
440
|
+
|
|
441
|
+
```ts
|
|
442
|
+
export interface RouteConfig {
|
|
443
|
+
path: string;
|
|
444
|
+
label: string; // Fallback display label
|
|
445
|
+
labelKey: string; // i18n key: 'nav.myRoute'
|
|
446
|
+
icon: ComponentType<any>; // lucide-react icon
|
|
447
|
+
allowedRoles: UserRole[];
|
|
448
|
+
group?: string; // Groups routes visually in the sidebar
|
|
449
|
+
}
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
### Filtering Routes by Role
|
|
453
|
+
|
|
454
|
+
`AppLayout.tsx` uses `getRoutesByRole(user.role)` to pass only accessible routes to `<Sidebar>`. Each route's `allowedRoles` controls visibility — it mirrors `<RoleRoute>` in `AuthGuard.tsx`.
|
|
455
|
+
|
|
456
|
+
### Dynamic Label Enrichment
|
|
457
|
+
|
|
458
|
+
The sidebar `label` string can be enriched at runtime (e.g., adding a pending count badge). Do this in `AppLayout.tsx` via a `routes.map()` before passing to `<Sidebar>`:
|
|
459
|
+
|
|
460
|
+
```tsx
|
|
461
|
+
const allowedRoutes = baseRoutes.map(route => {
|
|
462
|
+
if (route.path === '/target' && count > 0) {
|
|
463
|
+
return { ...route, label: `${route.label} (${count})` };
|
|
464
|
+
}
|
|
465
|
+
return route;
|
|
466
|
+
});
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
---
|
|
470
|
+
|
|
471
|
+
## 8. State Management
|
|
472
|
+
|
|
473
|
+
| Layer | Tool | Use for |
|
|
474
|
+
|---|---|---|
|
|
475
|
+
| Server state | React Query (`useQuery`) | Data from APIs / mock fetch functions |
|
|
476
|
+
| Client UI state | Zustand | Filters, tabs, toggles shared across components |
|
|
477
|
+
| Auth state | `AuthContext` / `useAuth()` | Current user, login, logout |
|
|
478
|
+
| Layout state | `LayoutContext` / `useLayout()` | Sidebar width, assistant panel |
|
|
479
|
+
| Local component state | `useState` | Dialogs open/closed, inline edits, ephemeral form state |
|
|
480
|
+
|
|
481
|
+
### React Query — Required Pattern
|
|
482
|
+
|
|
483
|
+
```ts
|
|
484
|
+
// features/<domain>/hooks/use<Domain>.ts
|
|
485
|
+
import { useQuery } from '@tanstack/react-query';
|
|
486
|
+
import { useLanguage } from 'xertica-ui/hooks';
|
|
487
|
+
import { fetchItems, type Item } from '../data/mock';
|
|
488
|
+
|
|
489
|
+
export function useItems() {
|
|
490
|
+
const { language } = useLanguage(); // include language when response has translated strings
|
|
491
|
+
return useQuery<Item[]>({
|
|
492
|
+
queryKey: ['items', language],
|
|
493
|
+
queryFn: fetchItems,
|
|
494
|
+
staleTime: 5 * 60 * 1000, // set appropriate staleTime — never leave at default 0
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
### Zustand — Required Pattern
|
|
500
|
+
|
|
501
|
+
```ts
|
|
502
|
+
// features/<domain>/store/<domain>Store.ts
|
|
503
|
+
import { create } from 'zustand';
|
|
504
|
+
|
|
505
|
+
interface MyStore {
|
|
506
|
+
activeTab: string;
|
|
507
|
+
setActiveTab: (tab: string) => void;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
export const useMyStore = create<MyStore>(set => ({
|
|
511
|
+
activeTab: 'overview',
|
|
512
|
+
setActiveTab: tab => set({ activeTab: tab }),
|
|
513
|
+
}));
|
|
514
|
+
|
|
515
|
+
// In component — always subscribe with a selector to avoid unnecessary re-renders:
|
|
516
|
+
const activeTab = useMyStore(s => s.activeTab); // ✅ selector
|
|
517
|
+
const store = useMyStore(); // ❌ subscribes to everything
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
### Swap Pattern — Replacing Mock with Real API
|
|
521
|
+
|
|
522
|
+
Replace only the fetch function body in `data/mock.ts`. The hook, component, and type contract are unchanged:
|
|
523
|
+
|
|
524
|
+
```ts
|
|
525
|
+
// Before (mock)
|
|
526
|
+
export async function fetchItems(): Promise<Item[]> {
|
|
527
|
+
await new Promise(r => setTimeout(r, 300));
|
|
528
|
+
return MOCK_ITEMS;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// After (real API)
|
|
532
|
+
export async function fetchItems(): Promise<Item[]> {
|
|
533
|
+
const res = await fetch('/api/items', {
|
|
534
|
+
headers: { 'Accept-Language': i18n.language },
|
|
535
|
+
});
|
|
536
|
+
if (!res.ok) throw new Error('Failed to fetch');
|
|
537
|
+
return res.json();
|
|
538
|
+
}
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
---
|
|
542
|
+
|
|
543
|
+
## 9. Loading States — Skeletons
|
|
544
|
+
|
|
545
|
+
Always render a skeleton — never a spinner alone — for data-bearing surfaces. Spinners are acceptable only for inline actions (button submitting, "saving…"):
|
|
546
|
+
|
|
547
|
+
```tsx
|
|
548
|
+
// Cards grid
|
|
549
|
+
{isLoading
|
|
550
|
+
? Array.from({ length: 6 }).map((_, i) => <FeatureCardSkeleton key={i} showAction />)
|
|
551
|
+
: items.map(item => <FeatureCard key={item.id} {...item} />)
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// Tables
|
|
555
|
+
{isLoading
|
|
556
|
+
? Array.from({ length: 5 }).map((_, i) => (
|
|
557
|
+
<TableRow key={i}>
|
|
558
|
+
<TableCell><Skeleton className="h-3.5 w-28" /></TableCell>
|
|
559
|
+
<TableCell><Skeleton className="h-5 w-20 rounded-full" /></TableCell>
|
|
560
|
+
<TableCell><Skeleton className="h-3.5 w-16" /></TableCell>
|
|
561
|
+
</TableRow>
|
|
562
|
+
))
|
|
563
|
+
: rows.map(row => <TableRow key={row.id}>{/* cells */}</TableRow>)
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
// StatsCards row
|
|
567
|
+
{isLoading
|
|
568
|
+
? Array.from({ length: 4 }).map((_, i) => <StatsCardSkeleton key={i} />)
|
|
569
|
+
: stats.map(s => <StatsCard key={s.id} {...s} />)
|
|
570
|
+
}
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
Skeleton companions available: `FeatureCardSkeleton`, `QuickActionCardSkeleton`, `ProjectCardSkeleton`, `ActivityCardSkeleton`, `NotificationCardSkeleton`, `ProfileCardSkeleton`, `StatsCardSkeleton`.
|
|
574
|
+
|
|
575
|
+
---
|
|
576
|
+
|
|
577
|
+
## 10. Internationalization
|
|
578
|
+
|
|
579
|
+
### Setup (CLI-generated — do not hand-edit)
|
|
580
|
+
|
|
581
|
+
`src/i18n.ts` uses `import.meta.glob` to auto-discover all JSON files under `src/locales/<lang>/`. Adding a new JSON file requires no changes to `i18n.ts`.
|
|
582
|
+
|
|
583
|
+
### Using Translations in Components
|
|
584
|
+
|
|
585
|
+
```tsx
|
|
586
|
+
import { useTranslation } from 'react-i18next';
|
|
587
|
+
|
|
588
|
+
function MyComponent() {
|
|
589
|
+
const { t } = useTranslation();
|
|
590
|
+
return (
|
|
591
|
+
<div>
|
|
592
|
+
<h1>{t('home.welcome')}</h1>
|
|
593
|
+
<Button>{t('common.save')}</Button>
|
|
594
|
+
</div>
|
|
595
|
+
);
|
|
596
|
+
}
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
Applies to **all** user-facing strings: labels, placeholders, `aria-label`, toast messages, error text, dropdown items, tooltips.
|
|
600
|
+
|
|
601
|
+
### Using Translations Outside Components
|
|
602
|
+
|
|
603
|
+
In `data/mock.ts` and utility files, use the `i18n` instance directly (not the hook):
|
|
604
|
+
|
|
605
|
+
```ts
|
|
606
|
+
import i18n from '../../../i18n';
|
|
607
|
+
|
|
608
|
+
export async function fetchFeatureCards() {
|
|
609
|
+
return [{ title: i18n.t('home.cardsTitle') }]; // evaluated at query time
|
|
610
|
+
}
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
### Frozen Constants vs Factory Functions
|
|
614
|
+
|
|
615
|
+
```ts
|
|
616
|
+
// ❌ Wrong — frozen at module load time in the initial language
|
|
617
|
+
export const OPTIONS = [i18n.t('option.first'), i18n.t('option.second')];
|
|
618
|
+
|
|
619
|
+
// ✅ Correct — re-evaluated on every call, always returns current language
|
|
620
|
+
export function getOptions() {
|
|
621
|
+
return [i18n.t('option.first'), i18n.t('option.second')];
|
|
622
|
+
}
|
|
623
|
+
```
|
|
624
|
+
|
|
625
|
+
### Language-Aware queryKey (Mandatory)
|
|
626
|
+
|
|
627
|
+
Every React Query hook whose response contains translated strings must include `language` in its `queryKey`:
|
|
628
|
+
|
|
629
|
+
```ts
|
|
630
|
+
const { language } = useLanguage();
|
|
631
|
+
return useQuery({ queryKey: ['items', language], queryFn: fetchItems });
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
### Monolingual Projects
|
|
635
|
+
|
|
636
|
+
When only one language is configured, `<LanguageSelector>` auto-hides. To force it visible: `<LanguageSelector showWhenMonolingual />`.
|
|
637
|
+
|
|
638
|
+
### Adding / Removing Languages
|
|
639
|
+
|
|
640
|
+
```bash
|
|
641
|
+
npx xertica-ui update
|
|
642
|
+
# → select "Languages"
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
---
|
|
646
|
+
|
|
647
|
+
## 11. Component Selection Guide
|
|
648
|
+
|
|
649
|
+
For a full decision tree see `node_modules/xertica-ui/docs/decision-tree.md`. Key shortcuts:
|
|
650
|
+
|
|
651
|
+
| Scenario | Component |
|
|
652
|
+
|---|---|
|
|
653
|
+
| "Are you sure you want to delete?" (blocking) | `AlertDialog` |
|
|
654
|
+
| Compact form or detail view in overlay | `Dialog` |
|
|
655
|
+
| Wide edit form or detail panel | `Sheet` |
|
|
656
|
+
| Action feedback (auto-dismisses) | `toast.success/error/info/warning()` |
|
|
657
|
+
| Persistent inline warning / status banner | `Alert variant="warning"` |
|
|
658
|
+
| KPI number cards | `StatsCard` |
|
|
659
|
+
| Feature/module navigation cards | `FeatureCard` |
|
|
660
|
+
| Project status with progress bar | `ProjectCard` |
|
|
661
|
+
| Chronological event list | `ActivityCard` |
|
|
662
|
+
| Icon button label (hover) | `Tooltip` |
|
|
663
|
+
| User profile preview (hover) | `HoverCard` |
|
|
664
|
+
| Date picker | `Calendar` inside `Popover` |
|
|
665
|
+
| Filter panel (click-triggered) | `Popover` |
|
|
666
|
+
| Page sections (horizontal switch) | `Tabs` |
|
|
667
|
+
| Expandable single section | `Collapsible` |
|
|
668
|
+
| Settings with multiple expandable groups | `Accordion` |
|
|
669
|
+
| Rich text editing | `RichTextEditor` |
|
|
670
|
+
| OTP / 2FA code input | `InputOTP` |
|
|
671
|
+
| Step-by-step flow | `Stepper` |
|
|
672
|
+
| Known % completion progress | `Progress` |
|
|
673
|
+
| Unknown completion (page/card loading) | `Skeleton` |
|
|
674
|
+
| Tabular records | `Table` + `Pagination` |
|
|
675
|
+
|
|
676
|
+
---
|
|
677
|
+
|
|
678
|
+
## 12. Page Patterns (from `docs/patterns/`)
|
|
679
|
+
|
|
680
|
+
### Dashboard Pattern
|
|
681
|
+
|
|
682
|
+
```tsx
|
|
683
|
+
<div className="flex flex-col gap-6 p-6 max-w-[1400px] mx-auto">
|
|
684
|
+
{/* 1 — Page title + CTA */}
|
|
685
|
+
<div className="flex items-center justify-between">
|
|
686
|
+
<h1 className="text-2xl font-bold tracking-tight">Dashboard</h1>
|
|
687
|
+
<Button>Download Report</Button>
|
|
688
|
+
</div>
|
|
689
|
+
|
|
690
|
+
{/* 2 — KPI Stats Row */}
|
|
691
|
+
<div className="grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-4">
|
|
692
|
+
<StatsCard title="Revenue" value="$45,231" icon={<DollarSign className="size-4" />} />
|
|
693
|
+
{/* ... */}
|
|
694
|
+
</div>
|
|
695
|
+
|
|
696
|
+
{/* 3 — Chart + Feed in 7-column grid */}
|
|
697
|
+
<div className="grid gap-4 grid-cols-1 lg:grid-cols-7">
|
|
698
|
+
<Card className="col-span-1 lg:col-span-4"> {/* Chart */} </Card>
|
|
699
|
+
<Card className="col-span-1 lg:col-span-3"> {/* Activity feed */} </Card>
|
|
700
|
+
</div>
|
|
701
|
+
</div>
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
### Form Pattern (react-hook-form + zod)
|
|
705
|
+
|
|
706
|
+
```tsx
|
|
707
|
+
const schema = z.object({
|
|
708
|
+
name: z.string().min(2),
|
|
709
|
+
email: z.string().email(),
|
|
710
|
+
role: z.enum(['admin', 'user']),
|
|
711
|
+
});
|
|
712
|
+
|
|
713
|
+
function MyForm() {
|
|
714
|
+
const form = useForm({ resolver: zodResolver(schema) });
|
|
715
|
+
|
|
716
|
+
return (
|
|
717
|
+
<Form {...form}>
|
|
718
|
+
<form onSubmit={form.handleSubmit(onSubmit)}>
|
|
719
|
+
<FormField control={form.control} name="name" render={({ field }) => (
|
|
720
|
+
<FormItem>
|
|
721
|
+
<FormLabel>Name</FormLabel>
|
|
722
|
+
<FormControl><Input {...field} /></FormControl>
|
|
723
|
+
<FormMessage />
|
|
724
|
+
</FormItem>
|
|
725
|
+
)} />
|
|
726
|
+
<Button type="submit">Save</Button>
|
|
727
|
+
</form>
|
|
728
|
+
</Form>
|
|
729
|
+
);
|
|
730
|
+
}
|
|
731
|
+
```
|
|
732
|
+
|
|
733
|
+
### CRUD Table Pattern
|
|
734
|
+
|
|
735
|
+
```tsx
|
|
736
|
+
<Card>
|
|
737
|
+
<CardHeader className="flex flex-row items-center justify-between">
|
|
738
|
+
<CardTitle>Records</CardTitle>
|
|
739
|
+
<Button size="sm"><Plus className="size-4 mr-2" />New Record</Button>
|
|
740
|
+
</CardHeader>
|
|
741
|
+
<CardContent>
|
|
742
|
+
{/* Search + Filters */}
|
|
743
|
+
<div className="flex gap-2 mb-4">
|
|
744
|
+
<Input placeholder="Search..." className="max-w-sm" />
|
|
745
|
+
<Select><SelectTrigger><SelectValue placeholder="Status" /></SelectTrigger>...</Select>
|
|
746
|
+
</div>
|
|
747
|
+
{/* Table */}
|
|
748
|
+
<Table>
|
|
749
|
+
<TableHeader>
|
|
750
|
+
<TableRow>
|
|
751
|
+
<TableHead>Name</TableHead>
|
|
752
|
+
<TableHead>Status</TableHead>
|
|
753
|
+
<TableHead className="text-right">Actions</TableHead>
|
|
754
|
+
</TableRow>
|
|
755
|
+
</TableHeader>
|
|
756
|
+
<TableBody>
|
|
757
|
+
{isLoading
|
|
758
|
+
? Array.from({ length: 5 }).map((_, i) => (
|
|
759
|
+
<TableRow key={i}>
|
|
760
|
+
<TableCell><Skeleton className="h-4 w-32" /></TableCell>
|
|
761
|
+
<TableCell><Skeleton className="h-5 w-16 rounded-full" /></TableCell>
|
|
762
|
+
<TableCell className="text-right"><Skeleton className="h-8 w-8 ml-auto" /></TableCell>
|
|
763
|
+
</TableRow>
|
|
764
|
+
))
|
|
765
|
+
: rows.map(row => <TableRow key={row.id}>{/* ... */}</TableRow>)
|
|
766
|
+
}
|
|
767
|
+
</TableBody>
|
|
768
|
+
</Table>
|
|
769
|
+
</CardContent>
|
|
770
|
+
</Card>
|
|
771
|
+
```
|
|
772
|
+
|
|
773
|
+
---
|
|
774
|
+
|
|
775
|
+
## 13. Error Boundaries
|
|
776
|
+
|
|
777
|
+
Three pre-configured wrappers for granular error isolation:
|
|
778
|
+
|
|
779
|
+
```tsx
|
|
780
|
+
import { AppErrorBoundary, PageErrorBoundary, SectionErrorBoundary }
|
|
781
|
+
from '../shared/error-boundary';
|
|
782
|
+
|
|
783
|
+
// App.tsx — wraps the entire application
|
|
784
|
+
<AppErrorBoundary>
|
|
785
|
+
<QueryClientProvider>
|
|
786
|
+
<XerticaProvider>
|
|
787
|
+
<Router>
|
|
788
|
+
<AuthProvider>
|
|
789
|
+
<PageErrorBoundary> {/* wraps the route tree */}
|
|
790
|
+
<Suspense fallback={null}>
|
|
791
|
+
<AuthGuard />
|
|
792
|
+
</Suspense>
|
|
793
|
+
</PageErrorBoundary>
|
|
794
|
+
</AuthProvider>
|
|
795
|
+
</Router>
|
|
796
|
+
</XerticaProvider>
|
|
797
|
+
</QueryClientProvider>
|
|
798
|
+
</AppErrorBoundary>
|
|
799
|
+
|
|
800
|
+
// Inside pages — wraps data-dependent sections
|
|
801
|
+
<SectionErrorBoundary>
|
|
802
|
+
<MyDataDrivenComponent />
|
|
803
|
+
</SectionErrorBoundary>
|
|
804
|
+
```
|
|
805
|
+
|
|
806
|
+
---
|
|
807
|
+
|
|
808
|
+
## 14. Theme and Token Customization
|
|
809
|
+
|
|
810
|
+
Edit only `src/styles/xertica/tokens.css` — never modify anything in `node_modules/xertica-ui/styles/`.
|
|
811
|
+
|
|
812
|
+
To switch themes via CLI:
|
|
813
|
+
```bash
|
|
814
|
+
npx xertica-ui update
|
|
815
|
+
# → select "Theme only"
|
|
816
|
+
```
|
|
817
|
+
|
|
818
|
+
The token file uses HSL values and supports both light and dark modes via the `.dark` class on `<html>`. CSS variable names follow the shadcn convention: `--background`, `--foreground`, `--primary`, `--destructive`, etc.
|
|
819
|
+
|
|
820
|
+
---
|
|
821
|
+
|
|
822
|
+
## 15. AI Agent Reference
|
|
823
|
+
|
|
824
|
+
| What you need | Where to read |
|
|
825
|
+
|---|---|
|
|
826
|
+
| Complete component catalog | `node_modules/xertica-ui/llms-compact.txt` |
|
|
827
|
+
| Full component API with all props | `node_modules/xertica-ui/llms-full.txt` |
|
|
828
|
+
| "Dialog or Sheet? Tooltip or Popover?" | `node_modules/xertica-ui/docs/decision-tree.md` |
|
|
829
|
+
| Specific component props | `node_modules/xertica-ui/docs/components/<name>.md` |
|
|
830
|
+
| Mandatory constraint list for AI | `node_modules/xertica-ui/docs/ai-usage.md` |
|
|
831
|
+
| i18n setup and language switching | `node_modules/xertica-ui/docs/i18n.md` |
|
|
832
|
+
| State management patterns | `node_modules/xertica-ui/docs/state-management.md` |
|
|
833
|
+
| Layout system (sidebar width, assistant) | `node_modules/xertica-ui/docs/layout.md` |
|
|
834
|
+
| Page-level composition patterns | `node_modules/xertica-ui/docs/patterns/*.md` |
|
|
835
|
+
| This project's architecture rules | `guidelines/Guidelines.md` (you are here) |
|
|
836
|
+
|
|
837
|
+
---
|
|
838
|
+
|
|
839
|
+
## 16. Development Checklist
|
|
840
|
+
|
|
841
|
+
Before completing any feature:
|
|
842
|
+
|
|
843
|
+
- [ ] Feature content is in `src/features/<name>/ui/`
|
|
844
|
+
- [ ] Feature barrel at `src/features/<name>/index.ts` exports everything
|
|
845
|
+
- [ ] Page is a thin wrapper in `src/pages/` — no logic, no state
|
|
846
|
+
- [ ] Route registered in `src/shared/config/navigation.ts` with `label`, `labelKey`, `icon`, `allowedRoles`, `group`
|
|
847
|
+
- [ ] Route registered in `src/app/components/AuthGuard.tsx` with correct guard (`ProtectedRoute` or `RoleRoute`)
|
|
848
|
+
- [ ] i18n key added to `src/locales/<lang>/nav.json` for **all** configured languages
|
|
849
|
+
- [ ] Navigation card added to `HomeContent.tsx` if this is a primary module
|
|
850
|
+
- [ ] All data arrays live in `features/<name>/data/mock.ts`, not in components
|
|
851
|
+
- [ ] Server state fetched via React Query hook — not `useState` + `useEffect`
|
|
852
|
+
- [ ] React Query `queryKey` includes `language` when response contains translated strings
|
|
853
|
+
- [ ] `staleTime` is set on every `useQuery` call — never left at default `0`
|
|
854
|
+
- [ ] Client UI state (filters, tabs) uses Zustand with selectors — not prop drilling
|
|
855
|
+
- [ ] Only `xertica-ui` components used — no raw HTML elements
|
|
856
|
+
- [ ] No raw hex/rgb/hsl values in `className` or `style` — semantic tokens for status contexts
|
|
857
|
+
- [ ] No hardcoded border radii — `rounded-[var(--radius)]`
|
|
858
|
+
- [ ] Icons from `lucide-react` only — no inline SVG
|
|
859
|
+
- [ ] Layout state from `useLayout()` — no hardcoded `padding-left` or sidebar widths
|
|
860
|
+
- [ ] Destructive actions wrapped in `<AlertDialog>` with explicit confirm/cancel
|
|
861
|
+
- [ ] Forms use `react-hook-form` + `zod` — no manual `useState` + if-validation
|
|
862
|
+
- [ ] Loading states render a `*Skeleton` component, not a blank space or spinner alone
|
|
863
|
+
- [ ] All user-facing strings go through `useTranslation()` — no hardcoded UI text
|
|
864
|
+
- [ ] `toast` used for action feedback — message goes through `t()`
|
|
865
|
+
- [ ] Responsive: tested on mobile (< 640px), tablet (640–1024px), desktop (> 1024px)
|