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.
Files changed (559) hide show
  1. package/CHANGELOG.md +621 -564
  2. package/README.md +443 -417
  3. package/assets/xertica-logo.svg +37 -37
  4. package/assets/xertica-x-logo.svg +20 -20
  5. package/bin/cli.ts +1244 -1244
  6. package/bin/generate-tokens.ts +9 -9
  7. package/bin/language-config.ts +358 -358
  8. package/components/assistant/code-block/CodeBlock.tsx +268 -268
  9. package/components/assistant/formatted-document/FormattedDocument.tsx +147 -147
  10. package/components/assistant/modern-chat-input/ModernChatInput.tsx +564 -564
  11. package/components/assistant/xertica-assistant/parts/AssistantCollapsedView.tsx +99 -99
  12. package/components/assistant/xertica-assistant/parts/AssistantConversationList.tsx +104 -104
  13. package/components/assistant/xertica-assistant/parts/AssistantDocumentEditor.tsx +81 -81
  14. package/components/assistant/xertica-assistant/parts/AssistantFeedbackDialog.tsx +88 -88
  15. package/components/assistant/xertica-assistant/parts/AssistantHeader.tsx +75 -75
  16. package/components/assistant/xertica-assistant/parts/AssistantMessageBubble.tsx +564 -564
  17. package/components/assistant/xertica-assistant/parts/AssistantTabBar.tsx +67 -67
  18. package/components/assistant/xertica-assistant/parts/AssistantWelcomeScreen.tsx +103 -103
  19. package/components/assistant/xertica-assistant/use-assistant.ts +615 -615
  20. package/components/assistant/xertica-assistant/xertica-assistant.tsx +611 -611
  21. package/components/blocks/card-patterns/ActivityCard.tsx +100 -100
  22. package/components/blocks/card-patterns/ActivityCardSkeleton.tsx +56 -56
  23. package/components/blocks/card-patterns/FeatureCardSkeleton.tsx +58 -58
  24. package/components/blocks/card-patterns/NotificationCard.tsx +140 -140
  25. package/components/blocks/card-patterns/NotificationCardSkeleton.tsx +81 -81
  26. package/components/blocks/card-patterns/ProfileCard.tsx +112 -112
  27. package/components/blocks/card-patterns/ProfileCardSkeleton.tsx +69 -69
  28. package/components/blocks/card-patterns/ProjectCard.tsx +123 -123
  29. package/components/blocks/card-patterns/ProjectCardSkeleton.tsx +67 -67
  30. package/components/blocks/card-patterns/QuickActionCardSkeleton.tsx +44 -44
  31. package/components/blocks/card-patterns/card-patterns.stories.tsx +594 -594
  32. package/components/blocks/card-patterns/index.ts +29 -29
  33. package/components/brand/language-selector/LanguageSelector.tsx +102 -102
  34. package/components/brand/language-selector/language-selector.stories.tsx +111 -111
  35. package/components/brand/language-selector/language-selector.test.tsx +101 -101
  36. package/components/brand/theme-toggle/ThemeToggle.tsx +74 -74
  37. package/components/brand/xertica-provider/XerticaProvider.tsx +112 -109
  38. package/components/brand/xertica-provider/xertica-provider.mdx +61 -61
  39. package/components/index.ts +86 -86
  40. package/components/layout/sidebar/sidebar.mdx +1 -1
  41. package/components/layout/sidebar/sidebar.stories.tsx +201 -0
  42. package/components/layout/sidebar/sidebar.tsx +1164 -1079
  43. package/components/media/FloatingMediaWrapper.tsx +371 -371
  44. package/components/media/audio-player/AudioPlayer.tsx +768 -768
  45. package/components/media/video-player/VideoPlayer.tsx +310 -310
  46. package/components/pages/forgot-password-page/ForgotPasswordPage.tsx +188 -188
  47. package/components/pages/home-content/HomeContent.tsx +120 -120
  48. package/components/pages/home-content/home-content.mdx +62 -62
  49. package/components/pages/home-page/HomePage.tsx +78 -78
  50. package/components/pages/home-page/home-page.mdx +53 -53
  51. package/components/pages/login-page/LoginPage.tsx +218 -218
  52. package/components/pages/reset-password-page/ResetPasswordPage.tsx +243 -243
  53. package/components/pages/template-content/TemplateContent.tsx +1354 -1354
  54. package/components/pages/template-content/template-content.mdx +61 -61
  55. package/components/pages/template-page/TemplatePage.stories.tsx +8 -15
  56. package/components/pages/template-page/template-page.mdx +53 -53
  57. package/components/pages/verify-email-page/VerifyEmailPage.tsx +206 -206
  58. package/components/shared/error-boundary.stories.tsx +114 -114
  59. package/components/shared/error-boundary.tsx +150 -150
  60. package/components/shared/error-fallbacks.tsx +222 -222
  61. package/components/ui/accordion/accordion.mdx +8 -8
  62. package/components/ui/alert/alert.mdx +8 -8
  63. package/components/ui/alert-dialog/alert-dialog.mdx +8 -8
  64. package/components/ui/aspect-ratio/aspect-ratio.mdx +8 -8
  65. package/components/ui/assistant-chart/assistant-chart.mdx +8 -8
  66. package/components/ui/avatar/avatar.mdx +8 -8
  67. package/components/ui/badge/badge.mdx +8 -8
  68. package/components/ui/breadcrumb/breadcrumb.mdx +8 -8
  69. package/components/ui/button/button.mdx +8 -8
  70. package/components/ui/calendar/calendar.mdx +8 -8
  71. package/components/ui/card/card.mdx +8 -8
  72. package/components/ui/carousel/carousel.mdx +8 -8
  73. package/components/ui/chart/chart.mdx +8 -8
  74. package/components/ui/chart/chart.test.tsx +1 -1
  75. package/components/ui/chart/chart.tsx +13 -6
  76. package/components/ui/checkbox/checkbox.mdx +8 -8
  77. package/components/ui/collapsible/collapsible.mdx +8 -8
  78. package/components/ui/command/command.mdx +8 -8
  79. package/components/ui/context-menu/context-menu.mdx +8 -8
  80. package/components/ui/dialog/dialog.mdx +8 -8
  81. package/components/ui/drawer/drawer.mdx +8 -8
  82. package/components/ui/dropdown-menu/dropdown-menu.mdx +8 -8
  83. package/components/ui/empty/empty.mdx +8 -8
  84. package/components/ui/file-upload/file-upload.mdx +8 -8
  85. package/components/ui/hover-card/hover-card.mdx +8 -8
  86. package/components/ui/input/input.mdx +8 -8
  87. package/components/ui/input-otp/input-otp.mdx +8 -8
  88. package/components/ui/label/label.mdx +8 -8
  89. package/components/ui/map/map.mdx +8 -8
  90. package/components/ui/menubar/menubar.mdx +8 -8
  91. package/components/ui/navigation-menu/navigation-menu.mdx +8 -8
  92. package/components/ui/notification-badge/notification-badge.mdx +8 -8
  93. package/components/ui/pagination/pagination.mdx +8 -8
  94. package/components/ui/popover/popover.mdx +8 -8
  95. package/components/ui/progress/progress.mdx +8 -8
  96. package/components/ui/radio-group/radio-group.mdx +8 -8
  97. package/components/ui/rating/rating.mdx +8 -8
  98. package/components/ui/resizable/resizable.mdx +8 -8
  99. package/components/ui/route-map/route-map.mdx +8 -8
  100. package/components/ui/scroll-area/scroll-area.mdx +8 -8
  101. package/components/ui/search/search.mdx +8 -8
  102. package/components/ui/select/select.mdx +8 -8
  103. package/components/ui/separator/separator.mdx +8 -8
  104. package/components/ui/sheet/sheet.mdx +8 -8
  105. package/components/ui/simple-map/simple-map.mdx +8 -8
  106. package/components/ui/skeleton/skeleton.mdx +8 -8
  107. package/components/ui/slider/slider.mdx +8 -8
  108. package/components/ui/sonner/sonner.mdx +8 -8
  109. package/components/ui/stats-card/index.ts +2 -2
  110. package/components/ui/stats-card/stats-card-skeleton.tsx +60 -60
  111. package/components/ui/stats-card/stats-card.mdx +8 -8
  112. package/components/ui/stats-card/stats-card.stories.tsx +117 -99
  113. package/components/ui/stats-card/stats-card.tsx +18 -2
  114. package/components/ui/stepper/stepper.mdx +8 -8
  115. package/components/ui/switch/switch.mdx +8 -8
  116. package/components/ui/table/table.mdx +8 -8
  117. package/components/ui/tabs/tabs.mdx +8 -8
  118. package/components/ui/textarea/textarea.mdx +8 -8
  119. package/components/ui/timeline/timeline.mdx +8 -8
  120. package/components/ui/toggle/toggle.mdx +8 -8
  121. package/components/ui/toggle-group/toggle-group.mdx +8 -8
  122. package/components/ui/tooltip/tooltip.mdx +8 -8
  123. package/components/ui/tree-view/tree-view.mdx +8 -8
  124. package/components.json +153 -533
  125. package/contexts/AuthContext.tsx +121 -121
  126. package/contexts/BrandColorsContext.tsx +39 -8
  127. package/contexts/LanguageContext.test.tsx +121 -121
  128. package/contexts/LanguageContext.tsx +250 -250
  129. package/contexts/theme-data.ts +51 -0
  130. package/dist/AssistantChart-BKVtGUKF.js +3383 -0
  131. package/dist/AssistantChart-BZTPJ5dP.cjs +3551 -0
  132. package/dist/{AssistantChart-BAx9VQvb.cjs → AssistantChart-Bdd44uBn.cjs} +388 -127
  133. package/dist/{AssistantChart-CVko2A1W.js → AssistantChart-CFhDdGyU.js} +391 -130
  134. package/dist/{AssistantChart-CVzmmhx4.js → AssistantChart-C_hwFRRr.js} +4 -4
  135. package/dist/{AssistantChart-BAudAfne.cjs → AssistantChart-CldVCVDe.cjs} +5 -5
  136. package/dist/{AssistantChart-BP8upjMk.js → AssistantChart-Cu3m7RBo.js} +5 -5
  137. package/dist/AssistantChart-CxGjH7Qk.js +3477 -0
  138. package/dist/AssistantChart-DIpshm3i.js +4784 -0
  139. package/dist/AssistantChart-DMJJ_Amf.js +3383 -0
  140. package/dist/AssistantChart-D_PTeu8P.cjs +3503 -0
  141. package/dist/{AssistantChart-9w31gdAb.cjs → AssistantChart-DoZCyS5r.cjs} +4 -4
  142. package/dist/AssistantChart-WeycT5Pd.cjs +3551 -0
  143. package/dist/AssistantChart-zjsy2GaZ.cjs +4810 -0
  144. package/dist/AudioPlayer-B1lt5cPl.cjs +989 -0
  145. package/dist/AudioPlayer-BZ7bibzU.cjs +982 -0
  146. package/dist/AudioPlayer-BpRPS4-1.cjs +1277 -0
  147. package/dist/AudioPlayer-C12BjQBV.cjs +997 -0
  148. package/dist/{AudioPlayer-1ypwE2Wh.cjs → AudioPlayer-CFeV8t-5.cjs} +1 -1
  149. package/dist/{AudioPlayer-DuKXrCfy.js → AudioPlayer-CGRUtUdN.js} +1 -1
  150. package/dist/AudioPlayer-Coly3q5R.js +1278 -0
  151. package/dist/AudioPlayer-CySJIyvL.js +937 -0
  152. package/dist/AudioPlayer-DMcG_c7L.js +990 -0
  153. package/dist/AudioPlayer-DcFKRJE_.js +998 -0
  154. package/dist/AudioPlayer-IAU5q5T1.cjs +936 -0
  155. package/dist/AudioPlayer-e8LfNoqO.js +983 -0
  156. package/dist/BrandColorsContext-565dDHd5.js +660 -0
  157. package/dist/BrandColorsContext-BMRJ04Wf.js +718 -0
  158. package/dist/BrandColorsContext-BcJbtkqn.cjs +659 -0
  159. package/dist/BrandColorsContext-BwY-b6M4.cjs +725 -0
  160. package/dist/{xertica-assistant-Qp3ydksa.cjs → CodeBlock-7TTgmdGG.cjs} +263 -51
  161. package/dist/{xertica-assistant-gnCJdcZY.js → CodeBlock-BeSt1h5P.js} +219 -7
  162. package/dist/CodeBlock-BgfYL_rD.cjs +2094 -0
  163. package/dist/CodeBlock-BlcqlA9M.cjs +2094 -0
  164. package/dist/CodeBlock-Bnmeu5ez.cjs +2094 -0
  165. package/dist/CodeBlock-BtfPlbAI.js +2078 -0
  166. package/dist/CodeBlock-CIySIuYr.js +2078 -0
  167. package/dist/CodeBlock-CuPtUM-7.cjs +2094 -0
  168. package/dist/CodeBlock-D6ffWXgc.js +2078 -0
  169. package/dist/CodeBlock-D8dcwbit.cjs +2094 -0
  170. package/dist/CodeBlock-DMZrFnlw.cjs +2094 -0
  171. package/dist/CodeBlock-DlBehYN8.js +2078 -0
  172. package/dist/CodeBlock-DnYNI8rQ.js +2078 -0
  173. package/dist/CodeBlock-DvKWbSnE.cjs +2094 -0
  174. package/dist/CodeBlock-DwMCfkFY.js +2078 -0
  175. package/dist/CodeBlock-Dy6CNYyj.js +2078 -0
  176. package/dist/CodeBlock-U1pPOQI7.cjs +2094 -0
  177. package/dist/CodeBlock-f_GpNhEB.js +2078 -0
  178. package/dist/CodeBlock-oB6u8nI1.js +2078 -0
  179. package/dist/CodeBlock-tZC31B73.cjs +2094 -0
  180. package/dist/FeatureCard-CxC-7C-C.cjs +300 -0
  181. package/dist/FeatureCard-DbHWCb4E.js +301 -0
  182. package/dist/ImageWithFallback-CGtidP6B.cjs +4542 -0
  183. package/dist/ImageWithFallback-lsg3pdFg.js +4508 -0
  184. package/dist/{LanguageContext-DvUt5jBg.cjs → LanguageContext-B_KFTCzT.cjs} +2 -2
  185. package/dist/{LanguageContext-BwhwC3G2.js → LanguageContext-CS14yCpi.js} +2 -2
  186. package/dist/{XerticaXLogo-DHz5SugF.js → LanguageSelector-B5YfbHra.js} +115 -136
  187. package/dist/{XerticaXLogo-DTee_y8X.cjs → LanguageSelector-D6uacAIM.cjs} +115 -136
  188. package/dist/LayoutContext-B45-e9DI.cjs +93 -0
  189. package/dist/LayoutContext-BAql6ZRY.js +97 -0
  190. package/dist/LayoutContext-Bav3UMEA.js +94 -0
  191. package/dist/LayoutContext-BvK-ggDa.cjs +96 -0
  192. package/dist/{ThemeContext-Bo-W2WZH.js → ThemeContext-BWq9ACPo.js} +8 -13
  193. package/dist/{ThemeContext-ept8jhXI.js → ThemeContext-BXjrgUjW.js} +261 -200
  194. package/dist/{ThemeContext-BblcjQup.cjs → ThemeContext-Bmod0Cg2.cjs} +8 -13
  195. package/dist/ThemeContext-BoH4NLfN.js +734 -0
  196. package/dist/{ThemeContext-BbBNoFTG.js → ThemeContext-C2EwAPDt.js} +2 -2
  197. package/dist/{ThemeContext-U4dEYc6C.cjs → ThemeContext-CGk3KK0k.cjs} +1 -8
  198. package/dist/{ThemeContext-D3LzacmG.js → ThemeContext-CQSo4Iwc.js} +1 -8
  199. package/dist/{ThemeContext-CP3a0jxy.cjs → ThemeContext-j5aGtPky.cjs} +262 -193
  200. package/dist/ThemeContext-r69W20Xg.cjs +733 -0
  201. package/dist/{ThemeContext-Cmr8Ex8H.cjs → ThemeContext-vTjumZeM.cjs} +2 -2
  202. package/dist/{VerifyEmailPage-BRSP-Pwt.cjs → VerifyEmailPage--1Vurewl.cjs} +3 -3
  203. package/dist/{VerifyEmailPage-CbgjOF0v.js → VerifyEmailPage-1WwWczAn.js} +12 -22
  204. package/dist/{VerifyEmailPage-DF2ilhum.cjs → VerifyEmailPage-B4peJjAT.cjs} +356 -334
  205. package/dist/{VerifyEmailPage-CR7kb5df.cjs → VerifyEmailPage-BComraR7.cjs} +12 -22
  206. package/dist/{VerifyEmailPage-u_Dn7t1U.cjs → VerifyEmailPage-Bp1XXl3H.cjs} +4 -4
  207. package/dist/{VerifyEmailPage-CkBYfsNy.cjs → VerifyEmailPage-By3Jf__L.cjs} +4 -4
  208. package/dist/{VerifyEmailPage-Bv8Ah_TK.cjs → VerifyEmailPage-ByerOcm4.cjs} +20 -23
  209. package/dist/{VerifyEmailPage-BE-L9mB7.js → VerifyEmailPage-C0c2e5n0.js} +7 -7
  210. package/dist/{VerifyEmailPage-EhudUdqF.js → VerifyEmailPage-C5TNQTBa.js} +355 -343
  211. package/dist/{VerifyEmailPage-Dt7zgA4w.cjs → VerifyEmailPage-CFLMls1p.cjs} +4 -4
  212. package/dist/{VerifyEmailPage-Bvfv8HVQ.js → VerifyEmailPage-CGIwmWrm.js} +461 -379
  213. package/dist/{VerifyEmailPage-Cyl55sJb.js → VerifyEmailPage-CJLz3jrn.js} +20 -23
  214. package/dist/VerifyEmailPage-COiyNl1y.js +2825 -0
  215. package/dist/{VerifyEmailPage-DMBh4NM9.cjs → VerifyEmailPage-CYXtbKi3.cjs} +1 -1
  216. package/dist/{VerifyEmailPage-DTtFfC-J.js → VerifyEmailPage-CgMxRb4z.js} +3 -3
  217. package/dist/VerifyEmailPage-CpqqpLpo.cjs +3305 -0
  218. package/dist/VerifyEmailPage-CqKsR2v8.js +2827 -0
  219. package/dist/{VerifyEmailPage-Bae2cBXT.cjs → VerifyEmailPage-Cwi3kbol.cjs} +7 -7
  220. package/dist/{VerifyEmailPage-X14vhdyl.js → VerifyEmailPage-DGhuIqkb.js} +4 -4
  221. package/dist/{VerifyEmailPage-BIBOKV7Z.js → VerifyEmailPage-DSBMRHtl.js} +36 -41
  222. package/dist/{VerifyEmailPage-D-FRj5TU.cjs → VerifyEmailPage-De6bQjrz.cjs} +36 -41
  223. package/dist/{VerifyEmailPage-BJjAMUTW.js → VerifyEmailPage-DgIid028.js} +4 -4
  224. package/dist/VerifyEmailPage-DjQKRlUS.cjs +2824 -0
  225. package/dist/{VerifyEmailPage-CdYPSJoO.js → VerifyEmailPage-DvMLZgFt.js} +1 -1
  226. package/dist/{VerifyEmailPage-C_ihbcth.js → VerifyEmailPage-MTD7AG1Z.js} +4 -4
  227. package/dist/VerifyEmailPage-s-1X3LDJ.cjs +2826 -0
  228. package/dist/XerticaOrbe-KL1RBHzw.cjs +1354 -0
  229. package/dist/XerticaOrbe-zwS1p2a8.js +1355 -0
  230. package/dist/XerticaProvider-6btlAlzc.js +17 -0
  231. package/dist/{XerticaProvider-siSt9uG2.js → XerticaProvider-B7EVH-NF.js} +2 -2
  232. package/dist/{XerticaProvider-AbWlr7Af.cjs → XerticaProvider-BIrqfZ-i.cjs} +11 -8
  233. package/dist/XerticaProvider-BNoNOxQ5.cjs +16 -0
  234. package/dist/XerticaProvider-BlY2limY.cjs +38 -0
  235. package/dist/{XerticaProvider-CWgby5mY.js → XerticaProvider-C1DKnvLh.js} +4 -4
  236. package/dist/{XerticaProvider-AChwphCO.cjs → XerticaProvider-CBGc4EMA.cjs} +4 -4
  237. package/dist/{XerticaProvider-BITjgC5p.js → XerticaProvider-CEoWMTxu.js} +2 -2
  238. package/dist/XerticaProvider-CeS5G_n5.cjs +45 -0
  239. package/dist/{XerticaProvider-By8q3Roe.cjs → XerticaProvider-CllrbMEJ.cjs} +2 -2
  240. package/dist/{XerticaProvider-B8CaV7xu.cjs → XerticaProvider-D-yNhF94.cjs} +1 -1
  241. package/dist/XerticaProvider-DDuiIcKo.js +39 -0
  242. package/dist/{XerticaProvider-DQtvJU7m.js → XerticaProvider-DYq4JWtg.js} +1 -1
  243. package/dist/{XerticaProvider-CWs6EwNa.js → XerticaProvider-Dt5HEzbQ.js} +10 -10
  244. package/dist/{XerticaProvider-CW9hpCdF.cjs → XerticaProvider-ET0ihewn.cjs} +2 -2
  245. package/dist/XerticaProvider-cI9hSs27.cjs +38 -0
  246. package/dist/XerticaProvider-hSwhNQex.js +39 -0
  247. package/dist/XerticaProvider-ra2NciRq.js +43 -0
  248. package/dist/{XerticaXLogo-ChryA6xj.js → XerticaXLogo-B7xQ5dhi.js} +1 -1
  249. package/dist/{XerticaXLogo-CziKMQil.cjs → XerticaXLogo-CQUUjXoH.cjs} +8 -8
  250. package/dist/{XerticaXLogo-DfUvz-lD.js → XerticaXLogo-Cmsp-Eey.js} +9 -9
  251. package/dist/{XerticaXLogo-CFuIlYFH.js → XerticaXLogo-DZbo4vOE.js} +12 -12
  252. package/dist/{XerticaXLogo-8TTzBjHw.cjs → XerticaXLogo-Zw2B276b.cjs} +1 -1
  253. package/dist/{XerticaXLogo-kslQ8Tk_.cjs → XerticaXLogo-bvZSgwGF.cjs} +13 -7
  254. package/dist/alert-dialog-BOje--vD.js +847 -0
  255. package/dist/alert-dialog-BtEuQqrg.cjs +870 -0
  256. package/dist/{alert-dialog-yckpaOpy.cjs → alert-dialog-DSKByiKZ.cjs} +3 -3
  257. package/dist/{alert-dialog-iDe5VE5o.js → alert-dialog-s-vmNkJ_.js} +3 -3
  258. package/dist/assistant.cjs.js +1 -1
  259. package/dist/assistant.es.js +1 -1
  260. package/dist/brand.cjs.js +1 -1
  261. package/dist/brand.es.js +1 -1
  262. package/dist/breadcrumb-CqJ7bHY5.js +161 -0
  263. package/dist/breadcrumb-m9Hb2_XN.cjs +177 -0
  264. package/dist/cli.js +45 -9
  265. package/dist/components/assistant/xertica-assistant/hooks/index.d.ts +6 -0
  266. package/dist/components/assistant/xertica-assistant/hooks/use-assistant-conversations.d.ts +21 -0
  267. package/dist/components/assistant/xertica-assistant/hooks/use-assistant-messages.d.ts +49 -0
  268. package/dist/components/assistant/xertica-assistant/hooks/use-assistant-suggestions.d.ts +16 -0
  269. package/dist/components/blocks/audio-player/AudioPlayer.d.ts +35 -0
  270. package/dist/components/blocks/audio-player/index.d.ts +1 -0
  271. package/dist/components/blocks/document-editor/DocumentEditor.d.ts +26 -0
  272. package/dist/components/blocks/document-editor/index.d.ts +1 -0
  273. package/dist/components/blocks/podcast-player/PodcastPlayer.d.ts +41 -0
  274. package/dist/components/blocks/podcast-player/index.d.ts +1 -0
  275. package/dist/components/brand/xertica-provider/XerticaProvider.d.ts +3 -1
  276. package/dist/components/ui/chart/chart.d.ts +12 -3
  277. package/dist/components/ui/chart/parts/chart-dashboard.d.ts +113 -0
  278. package/dist/components/ui/chart/parts/chart-metric.d.ts +118 -0
  279. package/dist/components/ui/chart/parts/chart-primitives.d.ts +101 -0
  280. package/dist/components/ui/chart/parts/chart-shared.d.ts +20 -0
  281. package/dist/components/ui/chart/parts/chart-utils.d.ts +12 -0
  282. package/dist/components/ui/chart/parts/index.d.ts +5 -0
  283. package/dist/components/ui/stats-card/stats-card.d.ts +10 -0
  284. package/dist/contexts/theme-data.d.ts +4 -0
  285. package/dist/dropdown-menu-BDB5CmQs.cjs +247 -0
  286. package/dist/dropdown-menu-DQidbKBD.js +231 -0
  287. package/dist/google-maps-loader-BFWp6VPd.js +287 -0
  288. package/dist/google-maps-loader-BKcdgFbu.cjs +312 -0
  289. package/dist/{google-maps-loader-t2IlYBzw.js → google-maps-loader-CTYySAun.js} +4 -0
  290. package/dist/google-maps-loader-CumCNXeG.js +312 -0
  291. package/dist/{google-maps-loader-BqsYL48U.cjs → google-maps-loader-Y-QkD-Li.cjs} +5 -0
  292. package/dist/google-maps-loader-eS3uQ5TA.cjs +287 -0
  293. package/dist/header-Cgy6vYPk.cjs +731 -0
  294. package/dist/header-DRlT4jgI.js +715 -0
  295. package/dist/header-Dux00SI4.cjs +731 -0
  296. package/dist/header-EkGKXPsD.js +715 -0
  297. package/dist/header-WfEywpyc.cjs +731 -0
  298. package/dist/header-tifNQn2U.js +715 -0
  299. package/dist/hooks.cjs.js +1 -1
  300. package/dist/hooks.es.js +1 -1
  301. package/dist/index-BhapVLVj.js +8 -0
  302. package/dist/{index-D3RLKRAs.cjs → index-COtD8bRW.cjs} +1 -1
  303. package/dist/index-D6fxYEY8.cjs +7 -0
  304. package/dist/index-DAIp0_HK.js +8 -0
  305. package/dist/index-DW5tYe26.js +8 -0
  306. package/dist/index-GA__GvnG.cjs +7 -0
  307. package/dist/index.cjs.js +6 -6
  308. package/dist/index.es.js +6 -6
  309. package/dist/index.umd.js +1043 -470
  310. package/dist/input-2R4loU86.js +127 -0
  311. package/dist/input-DWANSKGb.cjs +145 -0
  312. package/dist/layout.cjs.js +1 -1
  313. package/dist/layout.es.js +1 -1
  314. package/dist/pages.cjs.js +1 -1
  315. package/dist/pages.es.js +1 -1
  316. package/dist/progress-DPtzoVV8.js +175 -0
  317. package/dist/progress-EeaoqqUs.cjs +191 -0
  318. package/dist/rich-text-editor-0mraWT5y.cjs +2376 -0
  319. package/dist/rich-text-editor-B-IkcPD0.js +2874 -0
  320. package/dist/rich-text-editor-B2CKz7nx.cjs +2903 -0
  321. package/dist/rich-text-editor-B6jMRLzk.cjs +1939 -0
  322. package/dist/rich-text-editor-B8_oYcIR.js +1730 -0
  323. package/dist/rich-text-editor-B9UbSXNb.js +1203 -0
  324. package/dist/rich-text-editor-BYuRBNBU.js +2373 -0
  325. package/dist/rich-text-editor-Bb9pySTs.cjs +2374 -0
  326. package/dist/rich-text-editor-BcL6L3cm.cjs +2374 -0
  327. package/dist/rich-text-editor-BoVZYtTs.cjs +2391 -0
  328. package/dist/rich-text-editor-Bp3zQqMC.js +2954 -0
  329. package/dist/rich-text-editor-CMgSN_w2.js +1189 -0
  330. package/dist/rich-text-editor-CPV1lEPH.cjs +1748 -0
  331. package/dist/rich-text-editor-CeucBdIv.cjs +2971 -0
  332. package/dist/rich-text-editor-CoKqbCtu.cjs +1799 -0
  333. package/dist/rich-text-editor-Cw56T_mB.js +2356 -0
  334. package/dist/rich-text-editor-Cyt8qs2b.js +1921 -0
  335. package/dist/rich-text-editor-D6H84OcX.cjs +1220 -0
  336. package/dist/rich-text-editor-D76gD-QI.js +2328 -0
  337. package/dist/rich-text-editor-DKkokOnA.js +1781 -0
  338. package/dist/rich-text-editor-DNsdpN64.cjs +2359 -0
  339. package/dist/rich-text-editor-DfG8bCyY.js +2358 -0
  340. package/dist/rich-text-editor-DloeW0wc.js +2832 -0
  341. package/dist/rich-text-editor-Dxjw31Z4.js +2341 -0
  342. package/dist/rich-text-editor-DzP0Epmb.js +2356 -0
  343. package/dist/rich-text-editor-bRkNoeZY.cjs +2891 -0
  344. package/dist/rich-text-editor-lyYE2ZG5.cjs +1207 -0
  345. package/dist/rich-text-editor-skplNlBM.cjs +2345 -0
  346. package/dist/select-Bkbr0f-Z.cjs +162 -0
  347. package/dist/select-CvIVdX2n.js +145 -0
  348. package/dist/{sidebar-CplprZpM.js → sidebar-0ocFLSks.js} +127 -50
  349. package/dist/{sidebar-CA6_ek3f.js → sidebar-B6SlKZYN.js} +40 -49
  350. package/dist/{sidebar-CmvwjnVb.js → sidebar-BViy8Eeu.js} +17 -9
  351. package/dist/{sidebar-Dz7bd3zP.js → sidebar-BbVIQvlP.js} +1 -1
  352. package/dist/{sidebar-CVUGHOS_.cjs → sidebar-BxGXsDAd.cjs} +16 -8
  353. package/dist/sidebar-CK_0ZQHj.cjs +803 -0
  354. package/dist/sidebar-CUuOvYhK.js +787 -0
  355. package/dist/{sidebar-B3EYhli0.cjs → sidebar-CeTMuzOx.cjs} +128 -47
  356. package/dist/{sidebar-KIS0C2JH.js → sidebar-CrQDDdcz.js} +24 -33
  357. package/dist/{sidebar-zowjejT2.cjs → sidebar-DAaY8bRU.cjs} +24 -33
  358. package/dist/{sidebar-B9NR0lCe.cjs → sidebar-DQj1z3jG.cjs} +227 -269
  359. package/dist/sidebar-Djn5syhi.cjs +786 -0
  360. package/dist/sidebar-LluMXfam.js +759 -0
  361. package/dist/sidebar-_rT7rBMk.js +787 -0
  362. package/dist/{sidebar-BvF5I2Ue.cjs → sidebar-nzPoVHBQ.cjs} +41 -46
  363. package/dist/{sidebar-C5B_LHek.cjs → sidebar-q7P2Godd.cjs} +1 -1
  364. package/dist/slider-Bc5Hd0y1.js +56 -0
  365. package/dist/slider-N7hFFj6X.cjs +73 -0
  366. package/dist/tooltip-Ded96neP.cjs +137 -0
  367. package/dist/tooltip-HDOoD2-0.js +120 -0
  368. package/dist/ui.cjs.js +2 -2
  369. package/dist/ui.es.js +2 -2
  370. package/dist/use-audio-player-B31J-aqh.cjs +187 -0
  371. package/dist/use-audio-player-BkmEmj8Q.js +185 -0
  372. package/dist/use-audio-player-CLFTWFW1.cjs +184 -0
  373. package/dist/use-audio-player-CLLn00I6.js +188 -0
  374. package/dist/{use-audio-player-Dn1NR9xN.cjs → use-audio-player-NKsWyjWu.cjs} +7 -3
  375. package/dist/{use-audio-player-Bkh23vQ3.js → use-audio-player-nv8ZSGa1.js} +7 -3
  376. package/dist/use-file-upload-BcjEo2S5.js +404 -0
  377. package/dist/use-file-upload-CRJR68Tj.cjs +403 -0
  378. package/dist/use-mobile-B0hNy_Y6.cjs +4303 -0
  379. package/dist/use-mobile-BXuYROXM.js +4202 -0
  380. package/dist/use-mobile-Bbd51ASU.cjs +4392 -0
  381. package/dist/use-mobile-Bk6CX-TC.js +4359 -0
  382. package/dist/use-mobile-BvYdisLP.js +4202 -0
  383. package/dist/use-mobile-BzuxjzNX.cjs +4392 -0
  384. package/dist/use-mobile-CG2-SdXV.cjs +4235 -0
  385. package/dist/use-mobile-CKb5pqTs.js +4269 -0
  386. package/dist/use-mobile-CYuAuGDl.js +4202 -0
  387. package/dist/use-mobile-CaENcqm-.js +4508 -0
  388. package/dist/use-mobile-CbrYgJGJ.js +4203 -0
  389. package/dist/use-mobile-Cd4xPrKq.cjs +46 -0
  390. package/dist/use-mobile-DMOvImGQ.cjs +4542 -0
  391. package/dist/use-mobile-DRB3BQgD.cjs +4235 -0
  392. package/dist/use-mobile-DZvv7QMR.js +4359 -0
  393. package/dist/use-mobile-DdI_TXam.cjs +4235 -0
  394. package/dist/use-mobile-DlceKf8a.js +4359 -0
  395. package/dist/use-mobile-DsOnow1o.cjs +4236 -0
  396. package/dist/use-mobile-Kcj6jSnK.cjs +4392 -0
  397. package/dist/use-mobile-bnKcua_i.js +4202 -0
  398. package/dist/use-mobile-j4w2Jrf1.js +30 -0
  399. package/dist/use-mobile-ncXBeE2z.cjs +4235 -0
  400. package/dist/use-rich-text-editor-DjiddBGv.js +282 -0
  401. package/dist/use-rich-text-editor-lpeswbCs.cjs +281 -0
  402. package/dist/xertica-assistant-BdiZag0h.js +2187 -0
  403. package/dist/xertica-assistant-CrgTb6Hs.cjs +2155 -0
  404. package/dist/xertica-assistant-CyikE3N_.js +2173 -0
  405. package/dist/xertica-assistant-DCsnQyi5.js +2156 -0
  406. package/dist/xertica-assistant-DUBpmEgo.cjs +2186 -0
  407. package/dist/xertica-assistant-QFUnv5I2.cjs +2180 -0
  408. package/dist/{xertica-assistant-Bj3vBCq_.cjs → xertica-assistant-V_IdW4WF.cjs} +27 -9
  409. package/dist/{xertica-assistant-BMqdyRVi.js → xertica-assistant-ciJaWqm1.js} +28 -10
  410. package/dist/{xertica-assistant-B1IaHXnB.cjs → xertica-assistant-dyP7KHM5.cjs} +533 -392
  411. package/dist/{xertica-assistant-DPsESB6t.js → xertica-assistant-yX1CFBBo.js} +535 -394
  412. package/dist/xertica-ui.css +2 -2
  413. package/docs/architecture-improvements.md +456 -456
  414. package/docs/architecture.md +312 -312
  415. package/docs/components/assistant.md +428 -428
  416. package/docs/components/branding.md +252 -252
  417. package/docs/components/card-patterns.md +447 -447
  418. package/docs/components/error-boundary.md +201 -201
  419. package/docs/components/hooks.md +432 -432
  420. package/docs/components/language-selector.md +176 -176
  421. package/docs/components/pages.md +323 -323
  422. package/docs/components/sidebar.md +19 -2
  423. package/docs/components/stats-card.md +20 -2
  424. package/docs/doc-audit.md +244 -244
  425. package/docs/getting-started.md +616 -616
  426. package/docs/guidelines.md +330 -330
  427. package/docs/i18n.md +480 -480
  428. package/docs/installation.md +268 -268
  429. package/docs/llms.md +295 -295
  430. package/docs/state-management.md +289 -289
  431. package/guidelines/Guidelines.md +409 -409
  432. package/llms-compact.txt +30 -1
  433. package/llms-full.txt +11553 -7133
  434. package/llms.txt +1 -1
  435. package/package.json +219 -219
  436. package/styles/xertica/base.css +90 -90
  437. package/styles/xertica/tokens.css +9 -9
  438. package/templates/.prettierignore +4 -4
  439. package/templates/.prettierrc +10 -10
  440. package/templates/CLAUDE.md +180 -180
  441. package/templates/guidelines/Guidelines.md +865 -577
  442. package/templates/package.json +69 -69
  443. package/templates/src/app/App.tsx +46 -46
  444. package/templates/src/app/components/AuthGuard.tsx +131 -131
  445. package/templates/src/features/assistant/data/mock.ts +75 -75
  446. package/templates/src/features/assistant/hooks/useAssistantConfig.ts +20 -20
  447. package/templates/src/features/assistant/index.ts +5 -5
  448. package/templates/src/features/auth/ui/AuthPageShell.tsx +32 -32
  449. package/templates/src/features/auth/ui/ForgotPasswordContent.tsx +70 -70
  450. package/templates/src/features/auth/ui/LoginContent.tsx +92 -92
  451. package/templates/src/features/auth/ui/ResetPasswordContent.tsx +183 -183
  452. package/templates/src/features/auth/ui/SocialLoginButtons.tsx +78 -78
  453. package/templates/src/features/auth/ui/VerifyEmailContent.tsx +80 -80
  454. package/templates/src/features/home/data/mock.ts +41 -41
  455. package/templates/src/features/home/hooks/useFeatureCards.ts +20 -20
  456. package/templates/src/features/home/index.ts +11 -11
  457. package/templates/src/features/home/ui/HomeContent.tsx +117 -117
  458. package/templates/src/features/template/ui/CrudTemplate.tsx +112 -112
  459. package/templates/src/features/template/ui/DashboardTemplate.tsx +110 -110
  460. package/templates/src/features/template/ui/FormTemplate.tsx +117 -117
  461. package/templates/src/features/template/ui/LoginTemplate.tsx +59 -59
  462. package/templates/src/features/template/ui/TemplateContent.tsx +1322 -1322
  463. package/templates/src/i18n.ts +124 -124
  464. package/templates/src/locales/en/common.json +21 -21
  465. package/templates/src/locales/en/components/activityCard.json +10 -10
  466. package/templates/src/locales/en/components/assistant.json +119 -119
  467. package/templates/src/locales/en/components/media.json +29 -29
  468. package/templates/src/locales/en/components/notificationCard.json +5 -5
  469. package/templates/src/locales/en/components/profileCard.json +8 -8
  470. package/templates/src/locales/en/components/projectCard.json +10 -10
  471. package/templates/src/locales/en/components/sidebar.json +14 -14
  472. package/templates/src/locales/en/components/stats.json +8 -8
  473. package/templates/src/locales/en/components/team.json +14 -14
  474. package/templates/src/locales/en/errors.json +9 -9
  475. package/templates/src/locales/en/languageSelector.json +7 -7
  476. package/templates/src/locales/en/nav.json +6 -6
  477. package/templates/src/locales/en/pages/crudTemplate.json +25 -25
  478. package/templates/src/locales/en/pages/dashboardTemplate.json +20 -20
  479. package/templates/src/locales/en/pages/forgotPassword.json +10 -10
  480. package/templates/src/locales/en/pages/formTemplate.json +16 -16
  481. package/templates/src/locales/en/pages/home.json +7 -7
  482. package/templates/src/locales/en/pages/login.json +15 -15
  483. package/templates/src/locales/en/pages/loginTemplate.json +9 -9
  484. package/templates/src/locales/en/pages/resetPassword.json +18 -18
  485. package/templates/src/locales/en/pages/templates.json +317 -317
  486. package/templates/src/locales/en/pages/verifyEmail.json +12 -12
  487. package/templates/src/locales/en/themeToggle.json +6 -6
  488. package/templates/src/locales/es/common.json +21 -21
  489. package/templates/src/locales/es/components/activityCard.json +10 -10
  490. package/templates/src/locales/es/components/assistant.json +119 -119
  491. package/templates/src/locales/es/components/media.json +29 -29
  492. package/templates/src/locales/es/components/notificationCard.json +5 -5
  493. package/templates/src/locales/es/components/profileCard.json +8 -8
  494. package/templates/src/locales/es/components/projectCard.json +10 -10
  495. package/templates/src/locales/es/components/sidebar.json +14 -14
  496. package/templates/src/locales/es/components/stats.json +8 -8
  497. package/templates/src/locales/es/components/team.json +14 -14
  498. package/templates/src/locales/es/errors.json +9 -9
  499. package/templates/src/locales/es/languageSelector.json +7 -7
  500. package/templates/src/locales/es/nav.json +6 -6
  501. package/templates/src/locales/es/pages/crudTemplate.json +25 -25
  502. package/templates/src/locales/es/pages/dashboardTemplate.json +20 -20
  503. package/templates/src/locales/es/pages/forgotPassword.json +10 -10
  504. package/templates/src/locales/es/pages/formTemplate.json +16 -16
  505. package/templates/src/locales/es/pages/home.json +7 -7
  506. package/templates/src/locales/es/pages/login.json +15 -15
  507. package/templates/src/locales/es/pages/loginTemplate.json +9 -9
  508. package/templates/src/locales/es/pages/resetPassword.json +18 -18
  509. package/templates/src/locales/es/pages/templates.json +317 -317
  510. package/templates/src/locales/es/pages/verifyEmail.json +12 -12
  511. package/templates/src/locales/es/themeToggle.json +6 -6
  512. package/templates/src/locales/pt-BR/common.json +21 -21
  513. package/templates/src/locales/pt-BR/components/activityCard.json +10 -10
  514. package/templates/src/locales/pt-BR/components/assistant.json +119 -119
  515. package/templates/src/locales/pt-BR/components/media.json +29 -29
  516. package/templates/src/locales/pt-BR/components/notificationCard.json +5 -5
  517. package/templates/src/locales/pt-BR/components/profileCard.json +8 -8
  518. package/templates/src/locales/pt-BR/components/projectCard.json +10 -10
  519. package/templates/src/locales/pt-BR/components/sidebar.json +14 -14
  520. package/templates/src/locales/pt-BR/components/stats.json +8 -8
  521. package/templates/src/locales/pt-BR/components/team.json +14 -14
  522. package/templates/src/locales/pt-BR/errors.json +9 -9
  523. package/templates/src/locales/pt-BR/languageSelector.json +7 -7
  524. package/templates/src/locales/pt-BR/nav.json +6 -6
  525. package/templates/src/locales/pt-BR/pages/crudTemplate.json +25 -25
  526. package/templates/src/locales/pt-BR/pages/dashboardTemplate.json +20 -20
  527. package/templates/src/locales/pt-BR/pages/forgotPassword.json +10 -10
  528. package/templates/src/locales/pt-BR/pages/formTemplate.json +16 -16
  529. package/templates/src/locales/pt-BR/pages/home.json +7 -7
  530. package/templates/src/locales/pt-BR/pages/login.json +15 -15
  531. package/templates/src/locales/pt-BR/pages/loginTemplate.json +9 -9
  532. package/templates/src/locales/pt-BR/pages/resetPassword.json +18 -18
  533. package/templates/src/locales/pt-BR/pages/templates.json +317 -317
  534. package/templates/src/locales/pt-BR/pages/verifyEmail.json +12 -12
  535. package/templates/src/locales/pt-BR/themeToggle.json +6 -6
  536. package/templates/src/pages/AssistantPage.tsx +470 -470
  537. package/templates/src/pages/HomePage.tsx +53 -53
  538. package/templates/src/shared/error-boundary.tsx +150 -150
  539. package/templates/src/shared/error-fallbacks.tsx +222 -222
  540. package/templates/src/styles/xertica/tokens.css +9 -9
  541. package/templates/vite.config.js +20 -20
  542. package/templates/vite.config.ts +55 -55
  543. package/dist/ThemeContext-CpqYShLq.cjs +0 -324
  544. package/dist/ThemeContext-Du2nE1PL.js +0 -325
  545. package/dist/ThemeContext-GeEBTJ3q.cjs +0 -1621
  546. package/dist/ThemeContext-JyLK9B1o.js +0 -1622
  547. package/dist/VerifyEmailPage-BiRm7Nh4.cjs +0 -3213
  548. package/dist/VerifyEmailPage-hdB8JQGv.cjs +0 -3213
  549. package/dist/VerifyEmailPage-vYHbYK3q.js +0 -3214
  550. package/dist/XerticaProvider-CUYJZc32.js +0 -49
  551. package/dist/XerticaProvider-CjQAQPcn.cjs +0 -48
  552. package/dist/XerticaProvider-D5lLumH-.js +0 -49
  553. package/dist/XerticaProvider-qQUDop71.cjs +0 -48
  554. package/dist/XerticaXLogo-BWaag64t.js +0 -252
  555. package/dist/XerticaXLogo-CU-U-GP4.cjs +0 -251
  556. package/dist/index-CkTUgOwX.js +0 -8
  557. package/dist/sidebar-OTO_up7Z.js +0 -801
  558. package/dist/{rich-text-editor-BmsjY03B.js → rich-text-editor-DgF8s7xW.js} +26 -26
  559. 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 applications scaffolded with `npx xertica-ui@latest init`. They define the FSD/FDA architecture, import conventions, component rules, and AI agent behavior for this project.
4
- >
5
- > **AI agents**: Read this file first. Then read `node_modules/xertica-ui/llms-compact.txt` for component reference, and `node_modules/xertica-ui/docs/decision-tree.md` before choosing between similar components.
6
-
7
- ---
8
-
9
- ## 1. Architecture Feature-Sliced Design + Feature-Driven Architecture
10
-
11
- 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.
12
-
13
- ```
14
- src/
15
- ├── app/ # Layer 1 — Application shell (imports from all layers)
16
- │ ├── App.tsx # XerticaProvider + BrowserRouter + AuthGuard (GENERATED do not hand-edit)
17
- │ ├── context/
18
- │ │ └── AuthContext.tsx # AuthProvider + useAuth() hook
19
- │ └── components/
20
- ├── AppLayout.tsx # Sidebar + children + optional XerticaAssistant
21
- └── AuthGuard.tsx # Route definitions
22
-
23
- ├── shared/ # Layer 2 — Shared utilities (no business domain)
24
- ├── config/
25
- │ └── navigation.ts # RouteConfig type, routes[], getRouteByPath()
26
- ├── lib/
27
- │ └── auth.ts # getStoredUser, storeUser, clearStoredUser
28
- │ └── types/
29
- └── auth.ts # User interface
30
-
31
- ├── features/ # Layer 3 Vertical slices by business capability
32
- │ ├── auth/
33
- │ │ ├── index.ts # Public barrel — import from here, never from /ui/*
34
- └── ui/
35
- ├── AuthPageShell.tsx # Split-screen layout for auth pages
36
- │ ├── SocialLoginButtons.tsx # Google / MT Login / gov.br buttons
37
- │ │ ├── LoginContent.tsx
38
- ├── ForgotPasswordContent.tsx
39
- ├── VerifyEmailContent.tsx
40
- │ │ └── ResetPasswordContent.tsx
41
- │ ├── home/
42
- │ │ ├── data/mock.ts # Types + async fetch + factory functions (getMockXxx)
43
- │ │ ├── hooks/useFeatureCards.ts # React Query, queryKey includes `language`
44
- │ │ ├── store/dashboardStore.ts # Zustand UI state (no server data)
45
- ├── ui/HomeContent.tsx
46
- │ │ └── index.ts
47
- │ ├── template/
48
- │ │ ├── ui/TemplateContent.tsx
49
- └── index.ts
50
- └── assistant/ # Always present AppLayout depends on it
51
- │ ├── data/mock.ts # AssistantConfig + getMockRichSuggestions() / getMockFeedbackOptions()
52
- │ ├── hooks/useAssistantConfig.ts
53
- └── index.ts
54
-
55
- ├── pages/ # Layer 4 — Route entrypoints (thin wrappers only)
56
- ├── LoginPage.tsx
57
- ├── ForgotPasswordPage.tsx
58
- ├── VerifyEmailPage.tsx
59
- ├── ResetPasswordPage.tsx
60
- ├── HomePage.tsx # AppLayout + HomeContent + XerticaAssistant
61
- │ ├── TemplatePage.tsx # AppLayout + TemplateContent + XerticaAssistant
62
- │ └── AssistantPage.tsx
63
-
64
- ├── i18n.ts # i18next setup (GENERATED — covers only your selected languages)
65
- ├── locales/
66
- ├── .languages.json # CLI-managed selection ({ "version": 1, "codes": [...] })
67
- ├── pt-BR/ # one folder per language — only your selected languages exist
68
- │ │ ├── common.json
69
- │ │ ├── nav.json
70
- │ │ ├── errors.json
71
- │ │ ├── languageSelector.json
72
- │ │ ├── themeToggle.json
73
- │ │ ├── pages/
74
- │ │ │ └── home.json, login.json, templates.json, resetPassword.json, verifyEmail.json,
75
- │ │ │ loginTemplate.json, formTemplate.json, dashboardTemplate.json, crudTemplate.json
76
- │ │ └── components/
77
- │ │ └── assistant.json, sidebar.json, media.json, projectCard.json, ...
78
- │ ├── en/ # same structure
79
- │ └── es/ # same structure
80
- └── styles/ # Visual tokens and Tailwind entry
81
- ├── index.css # Imports: xertica-ui/style.css, tokens.css, @source
82
- └── xertica/
83
- └── tokens.css # Brand CSS variables — edit here to customize theme
84
- ```
85
-
86
- > **Files generated by the CLI** (`App.tsx`, `i18n.ts`, `locales/.languages.json`) are rewritten by `npx xertica-ui update`. Avoid hand-editing them; use the CLI to add/remove languages and let it regenerate them.
87
-
88
- ---
89
-
90
- ## 2. Layer Responsibilities
91
-
92
- ### `app/`
93
-
94
- Initializes the application. Contains only providers, the router, `AuthGuard` (auth state + routes), and `AppLayout` (layout shell). No business logic here.
95
-
96
- ### `shared/`
97
-
98
- Framework-agnostic code with no business domain: primitive types, localStorage helpers, navigation config. Importable by any layer. Must not import from `features/` or `pages/`.
99
-
100
- ### `features/`
101
-
102
- Each feature is a self-contained vertical slice. The `index.ts` is the only public interface — always import from the barrel, never from internal paths:
103
-
104
- ```tsx
105
- // Correct
106
- import { LoginContent } from '../features/auth';
107
-
108
- // Wrong never import from internal feature paths
109
- import { LoginContent } from '../features/auth/ui/LoginContent';
110
- ```
111
-
112
- Features must not import from each other. If two features share code, extract it to `shared/`.
113
-
114
- ### `pages/`
115
-
116
- Thin route wrappers that compose `AppLayout` + feature content + optional `XerticaAssistant`. No logic, no state, no API calls here:
117
-
118
- ```tsx
119
- // ✅ Correct — thin wrapper
120
- export function HomePage({ user, onLogout }: PageProps) {
121
- const { assistenteExpanded, toggleAssistente } = useLayout();
122
- return (
123
- <AppLayout user={user} onLogout={onLogout} assistant={<XerticaAssistant ... />}>
124
- <HomeContent user={user} onLogout={onLogout} />
125
- </AppLayout>
126
- );
127
- }
128
- ```
129
-
130
- ---
131
-
132
- ## 3. Import Rules
133
-
134
- Always use the correct `xertica-ui` subpath for the layer you are in:
135
-
136
- ```tsx
137
- // shared/ui → UI primitives
138
- import { Button, Card, Input, Badge, Table, Dialog, Select } from 'xertica-ui/ui';
139
-
140
- // app layer → providers and brand
141
- import { XerticaProvider, XerticaLogo, ThemeToggle } from 'xertica-ui/brand';
142
-
143
- // features/layout → navigation shell
144
- import { Sidebar, Header } from 'xertica-ui/layout';
145
-
146
- // features/assistant → AI assistant
147
- import { XerticaAssistant, generateDemoResponse } from 'xertica-ui/assistant';
148
-
149
- // features/media media players
150
- import { VideoPlayer, AudioPlayer } from 'xertica-ui/media';
151
-
152
- // shared/lib → hooks and contexts
153
- import { useLayout, useOptionalLayout, useTheme } from 'xertica-ui/hooks';
154
-
155
- // styles → imported once by src/styles/index.css
156
- import 'xertica-ui/style.css';
157
- ```
158
-
159
- Icons always come from `lucide-react` — never from `xertica-ui`:
160
-
161
- ```tsx
162
- import { Home, Settings, Plus, Trash2, ChevronRight } from 'lucide-react';
163
- ```
164
-
165
- ---
166
-
167
- ## 4. Adding a New Route (Step-by-Step)
168
-
169
- 1. **Create the feature content** — `src/features/<name>/ui/<NameContent>.tsx`
170
- 2. **Export from the barrel** — add to `src/features/<name>/index.ts`
171
- 3. **Create the page** `src/pages/<NamePage>.tsx` (thin AppLayout wrapper)
172
- 4. **Register the route** — add to `routes` array in `src/shared/config/navigation.ts`:
173
-
174
- ```ts
175
- import { MyIcon } from 'lucide-react';
176
-
177
- export const routes: RouteConfig[] = [
178
- { path: '/home', label: 'Home', icon: Home },
179
- { path: '/my-feature', label: 'My Feature', icon: MyIcon }, // ← add here
180
- ];
181
- ```
182
-
183
- 5. **Register the `<Route>`** — add to `src/app/components/AuthGuard.tsx`:
184
-
185
- ```tsx
186
- import { MyFeaturePage } from '../../pages/MyFeaturePage';
187
-
188
- // inside <Routes>:
189
- <Route
190
- path="/my-feature"
191
- element={
192
- <ProtectedRoute user={user}>
193
- <MyFeaturePage user={user} onLogout={handleLogout} />
194
- </ProtectedRoute>
195
- }
196
- />;
197
- ```
198
-
199
- 6. **Add a navigation card** to `HomeContent.tsx` if it's a primary module.
200
-
201
- ---
202
-
203
- ## 5. Non-Negotiable Rules
204
-
205
- ### HTMLnever use raw elements for UI
206
-
207
- | ❌ Never | ✅ Always |
208
- | -------------------------------- | ------------------------------------------------------ |
209
- | `<button>` | `<Button>` from `xertica-ui/ui` |
210
- | `<input>` | `<Input>` from `xertica-ui/ui` |
211
- | `<select>` | `<Select>` from `xertica-ui/ui` |
212
- | `<h1>` / `<h2>` for page headers | `<PageHeader><PageHeaderHeading>` from `xertica-ui/ui` |
213
- | `<div class="card ...">` | `<Card>` from `xertica-ui/ui` |
214
- | custom scrollable div | `<ScrollArea>` from `xertica-ui/ui` |
215
-
216
- ### Colors context-dependent rules
217
-
218
- | Never (any context) | Reason |
219
- | ------------------------------------------ | -------------------------- |
220
- | `#3b82f6`, `rgb(59, 130, 246)`, `hsl(...)` | Raw values non-themeable |
221
- | `style={{ color: '#...' }}` for theming | Non-themeable inline style |
222
-
223
- | ❌ Wrong for semantic/status contexts | ✅ Required instead |
224
- | ---------------------------------------- | ------------------------------------- |
225
- | `bg-red-500` / `text-red-500` for errors | `bg-destructive` / `text-destructive` |
226
- | `bg-green-500` for success states | `bg-success` |
227
- | `bg-yellow-500` for warnings | `bg-warning` |
228
-
229
- > For **layout, spacing, and general non-semantic UI** (custom components, decorative elements where no semantic token applies), standard Tailwind color utilities like `bg-blue-500` or `text-gray-700` are acceptable.
230
-
231
- | Never | ✅ Always |
232
- | -------------------------- | ------------------------- |
233
- | `rounded-lg`, `rounded-xl` | `rounded-[var(--radius)]` |
234
-
235
- ### Layout state never hardcode
236
-
237
- ```tsx
238
- // Correct
239
- const { sidebarExpanded, sidebarWidth } = useLayout();
240
- <div style={{ paddingLeft: sidebarExpanded ? `${sidebarWidth}px` : '80px' }}>
241
-
242
- // Correct for reusable components that may render outside XerticaProvider
243
- const layout = useOptionalLayout();
244
- const fallbackSidebarWidth = layout?.sidebarWidth ?? 80;
245
-
246
- // ❌ Wrong
247
- <div style={{ paddingLeft: '256px' }}>
248
- ```
249
-
250
- ### Destructive actions — always confirm
251
-
252
- ```tsx
253
- // Always wrap in AlertDialog
254
- <AlertDialog>
255
- <AlertDialogTrigger asChild>
256
- <Button variant="destructive">Delete</Button>
257
- </AlertDialogTrigger>
258
- <AlertDialogContent>
259
- <AlertDialogHeader>
260
- <AlertDialogTitle>Are you sure?</AlertDialogTitle>
261
- <AlertDialogDescription>This action cannot be undone.</AlertDialogDescription>
262
- </AlertDialogHeader>
263
- <AlertDialogFooter>
264
- <AlertDialogCancel>Cancel</AlertDialogCancel>
265
- <AlertDialogAction onClick={handleDelete}>Delete</AlertDialogAction>
266
- </AlertDialogFooter>
267
- </AlertDialogContent>
268
- </AlertDialog>
269
- ```
270
-
271
- ### Page structure — always use PageHeader
272
-
273
- Every page must use `<PageHeader>` for its title and primary actions. Never use raw `<h1>` or `<h2>`:
274
-
275
- ```tsx
276
- <PageHeader>
277
- <PageHeaderHeading>Users</PageHeaderHeading>
278
- <PageHeaderDescription>Manage your team members.</PageHeaderDescription>
279
- <Button>
280
- <Plus className="size-4 mr-2" />
281
- New User
282
- </Button>
283
- </PageHeader>
284
- ```
285
-
286
- ### Toast notifications
287
-
288
- ```tsx
289
- import { toast } from 'sonner';
290
- import { useTranslation } from 'react-i18next';
291
-
292
- const { t } = useTranslation();
293
- toast.success(t('users.createSuccess'));
294
- toast.error(t('errors.somethingWentWrong'));
295
- ```
296
-
297
- Never render `<Toaster>` manually — it is auto-injected by `<XerticaProvider>` in `App.tsx`. Always translate the message text through `t()`.
298
-
299
- ### Translations — never hardcode strings
300
-
301
- Every user-facing string must come from `useTranslation()`. Add new keys to the appropriate split JSON file under `src/locales/<lang>/` for all configured languages:
302
-
303
- ```tsx
304
- // Wrong
305
- <Button aria-label="Save">Save</Button>;
306
-
307
- // ✅ Correct
308
- const { t } = useTranslation();
309
- <Button aria-label={t('common.save')}>{t('common.save')}</Button>;
310
- ```
311
-
312
- This applies to `aria-label`, `placeholder`, `title`, toast messages, error text, dropdown items — everything the user can read.
313
-
314
- ---
315
-
316
- ## 6. Internationalization
317
-
318
- ### Selecting languages on init
319
-
320
- The CLI's `init` command asks which languages your app should support (`pt-BR`, `en`, `es`). Pick **1, 2, or 3**. The CLI:
321
-
322
- - Copies only the locale **folders** for the languages you chose (each is a directory tree with split JSON files)
323
- - Generates `src/i18n.ts` with `import.meta.glob` calls for exactly those languages — Vite auto-discovers all JSON files in the folder at build time
324
- - Injects the `availableLanguages` prop into `src/app/App.tsx` (omitted when all 3 defaults are selected)
325
- - Persists the selection in `src/locales/.languages.json`
326
-
327
- ### Monolingual mode
328
-
329
- When you select only one language, the `<LanguageSelector>` automatically renders `null` (there is nothing to switch to). A header comment in the generated `App.tsx` documents this. To force the selector visible anyway:
330
-
331
- ```tsx
332
- <LanguageSelector showWhenMonolingual />
333
- ```
334
-
335
- ### Adding or removing languages later
336
-
337
- ```bash
338
- npx xertica-ui update
339
- # select "Languages"
340
- ```
341
-
342
- The CLI shows your current selection, prompts for the new set, displays the diff (`+ es`, `- en`), and on confirm:
343
-
344
- - copies any newly-added locale JSONs from `node_modules/xertica-ui/templates/src/locales/`
345
- - removes JSONs of unselected languages
346
- - regenerates `src/i18n.ts` and `src/app/App.tsx`
347
- - updates `src/locales/.languages.json`
348
-
349
- > The `update` → **Project files** flow also reads `.languages.json` and preserves your selection. Updating App.tsx and i18n.ts won't reset your languages.
350
-
351
- ### Enabling or disabling Dark Mode support later
352
-
353
- ```bash
354
- npx xertica-ui update
355
- # → select "Dark Mode"
356
- ```
357
-
358
- The CLI reads your current setting from `.xertica.json` and prompts you to enable or disable dark mode. On confirmation, it updates `.xertica.json` and regenerates `App.tsx` to set `disableDarkMode={true}` or `false`.
359
-
360
- ### Adding or removing the AI Assistant later
361
-
362
- ```bash
363
- npx xertica-ui update
364
- # → select "Assistant"
365
- ```
366
-
367
- The CLI detects whether the assistant is currently active (via `.xertica.json` or page presence) and prompts to add or remove the feature. It automatically copies/deletes the feature files and updates `AuthGuard.tsx`, `HomePage.tsx`, and `TemplatePage.tsx` to reflect the change.
368
-
369
- ### Using translations in components
370
-
371
- ```tsx
372
- import { useTranslation } from 'react-i18next';
373
-
374
- function MyComponent() {
375
- const { t } = useTranslation();
376
- return <h1>{t('home.welcome')}</h1>;
377
- }
378
- ```
379
-
380
- ### Reading the configured language set
381
-
382
- ```tsx
383
- import { useLanguage } from 'xertica-ui/hooks';
384
-
385
- const { language, setLanguage, availableLanguages, isMonolingual } = useLanguage();
386
- ```
387
-
388
- - Never hardcode the language list when building a custom settings UI — iterate over `availableLanguages` so it stays in sync with whatever you configured.
389
-
390
- ### Factory functions for translated mock data
391
-
392
- Outside the React render cycle (mock fetch functions, fallback options), use **functions** so `i18n.t()` re-runs on every call instead of being frozen at module-load time:
393
-
394
- ```tsx
395
- // ❌ Wrong — frozen in initial language
396
- export const MOCK_OPTIONS = [i18n.t('feedback.notWhatIWanted')];
397
-
398
- // Correct re-evaluated every call
399
- export function getMockOptions() {
400
- return [i18n.t('feedback.notWhatIWanted')];
401
- }
402
- ```
403
-
404
- Inside components, build label maps for enums with `useMemo([..., t])`:
405
-
406
- ```tsx
407
- const statusLabels = useMemo(
408
- () => ({
409
- active: t('status.active'),
410
- inactive: t('status.inactive'),
411
- }),
412
- [t]
413
- );
414
- ```
415
-
416
- ---
417
-
418
- ## 7. Server State (React Query)
419
-
420
- Each feature has its own `data/mock.ts` (typed fetch functions) and `hooks/use<Xxx>.ts` (React Query wrappers). Replace the mock fetch with a real API call without touching the consumer code.
421
-
422
- ### Language-aware queryKey mandatory
423
-
424
- Every hook whose response contains translated strings **must** include the active language in its `queryKey`:
425
-
426
- ```tsx
427
- // features/home/hooks/useFeatureCards.ts
428
- import { useQuery } from '@tanstack/react-query';
429
- import { useLanguage } from 'xertica-ui/hooks';
430
- import { fetchFeatureCards, type FeatureCard } from '../data/mock';
431
-
432
- export function useFeatureCards() {
433
- const { language } = useLanguage();
434
- return useQuery<FeatureCard[]>({
435
- queryKey: ['home', 'feature-cards', language], // ← language as third element
436
- queryFn: fetchFeatureCards,
437
- staleTime: 10 * 60 * 1000,
438
- });
439
- }
440
- ```
441
-
442
- Switching language creates a new cache key → cache miss → automatic refetch in the new locale. Switching back is an instant cache hit. No page reload required.
443
-
444
- ### Connecting to a real API
445
-
446
- Replace only the `fetch*` function in `data/mock.ts` — the hook and the components stay unchanged:
447
-
448
- ```ts
449
- // data/mock.ts — after
450
- export async function fetchFeatureCards(): Promise<FeatureCard[]> {
451
- const res = await fetch('/api/feature-cards', {
452
- headers: { 'Accept-Language': i18n.language },
453
- });
454
- if (!res.ok) throw new Error('Failed');
455
- return res.json();
456
- }
457
- ```
458
-
459
- Pass `Accept-Language: i18n.language` so the backend returns localized strings — mirroring the mock pattern.
460
-
461
- ---
462
-
463
- ## 8. Loading States Skeletons
464
-
465
- Always render a skeleton placeholder — never a spinner — for data-bearing surfaces. Spinner-only loading is acceptable **only** for inline actions (button submit, "saving…" state).
466
-
467
- Every card pattern ships with a matching `*Skeleton`:
468
-
469
- ```tsx
470
- import { ActivityCard, ActivityCardSkeleton } from 'xertica-ui';
471
-
472
- {
473
- isLoading ? <ActivityCardSkeleton rows={5} /> : <ActivityCard items={items} />;
474
- }
475
- ```
476
-
477
- Available skeleton companions: `ActivityCardSkeleton`, `ProfileCardSkeleton`, `ProjectCardSkeleton`, `NotificationCardSkeleton`, `QuickActionCardSkeleton`, `FeatureCardSkeleton`, `StatsCardSkeleton`.
478
-
479
- For grids, render one skeleton per expected card:
480
-
481
- ```tsx
482
- {
483
- isLoading ? (
484
- <>
485
- <FeatureCardSkeleton showAction />
486
- <FeatureCardSkeleton showAction />
487
- <FeatureCardSkeleton showAction />
488
- </>
489
- ) : (
490
- data.map(item => <FeatureCard key={item.id} {...item} />)
491
- );
492
- }
493
- ```
494
-
495
- For tables, render skeleton rows with the `<Skeleton>` primitive (from `xertica-ui/ui`):
496
-
497
- ```tsx
498
- {isLoading
499
- ? Array.from({ length: 5 }).map((_, i) => (
500
- <TableRow key={i}>
501
- <TableCell><Skeleton className="h-3.5 w-28" /></TableCell>
502
- <TableCell><Skeleton className="h-5 w-16 rounded-full" /></TableCell>
503
- </TableRow>
504
- ))
505
- : rows.map(...)}
506
- ```
507
-
508
- Pass `rows={maxItems}` to list-style skeletons so the placeholder height matches the loaded state's row count.
509
-
510
- ---
511
-
512
- ## 9. Theme & Token Customization
513
-
514
- To change the color scheme, edit `src/styles/xertica/tokens.css`. To switch themes via CLI:
515
-
516
- ```bash
517
- npx xertica-ui update
518
- # → select "Theme only"
519
- ```
520
-
521
- The token file uses HSL values and supports both light and dark modes via the `.dark` class on `<html>`.
522
-
523
- Never import or modify anything inside `node_modules/xertica-ui/styles/` — override via `tokens.css` only.
524
-
525
- ---
526
-
527
- ## 10. Authentication Pattern
528
-
529
- The auth flow is managed in `src/app/context/AuthContext.tsx` via the `useAuth()` hook:
530
-
531
- - `getStoredUser()` / `storeUser()` / `clearStoredUser()` — from `src/shared/lib/auth.ts`
532
- - Auth pages (`/login`, `/forgot-password`, etc.) redirect to `/home` when user is already logged in
533
- - Protected routes use `<ProtectedRoute>` wrapper that redirects to `/login` if user is null
534
- - `useAuth().login(email, password)` stores the user
535
- - `useAuth().logout()` clears storage and navigates to `/login`
536
-
537
- To add social login, extend the `login` logic in `AuthContext.tsx` and wire the provider button in `SocialLoginButtons.tsx`.
538
-
539
- ---
540
-
541
- ## 11. AI Agent Documentation Reference
542
-
543
- | What you need | Where to read |
544
- | ----------------------------------- | --------------------------------------------------- |
545
- | Quick import + rules reference | `node_modules/xertica-ui/llms-compact.txt` |
546
- | Full component API | `node_modules/xertica-ui/llms-full.txt` |
547
- | "Should I use Dialog or Sheet?" | `node_modules/xertica-ui/docs/decision-tree.md` |
548
- | Specific component props | `node_modules/xertica-ui/docs/components/[name].md` |
549
- | All components + their imports | `node_modules/xertica-ui/components.json` |
550
- | Mandatory AI rules | `node_modules/xertica-ui/docs/ai-usage.md` |
551
- | i18n & language configuration | `node_modules/xertica-ui/docs/i18n.md` |
552
- | State management (React Query) | `node_modules/xertica-ui/docs/state-management.md` |
553
- | This project's rules (you are here) | `CLAUDE.md` at project root |
554
-
555
- ---
556
-
557
- ## 12. Development Checklist
558
-
559
- Before completing any feature:
560
-
561
- - [ ] Feature content is in `src/features/<name>/ui/`
562
- - [ ] Feature exports via `src/features/<name>/index.ts`
563
- - [ ] Page is a thin wrapper in `src/pages/`
564
- - [ ] Route registered in `src/shared/config/navigation.ts`
565
- - [ ] Route registered in `src/app/components/AuthGuard.tsx`
566
- - [ ] Home navigation card added (if primary module)
567
- - [ ] Only `xertica-ui` components used — no raw HTML elements
568
- - [ ] No raw hex/rgb values semantic tokens for semantic/status contexts; Tailwind utilities acceptable for non-semantic layout
569
- - [ ] No hardcoded radii — use `rounded-[var(--radius)]`
570
- - [ ] Icons from `lucide-react` only
571
- - [ ] Destructive actions wrapped in `<AlertDialog>`
572
- - [ ] Layout state from `useLayout()` — no hardcoded widths
573
- - [ ] Toast used for action feedback (`toast.success`, `toast.error`) — message translated via `t()`
574
- - [ ] **All user-facing strings go through `useTranslation()`** — added to all configured `locales/*.json`
575
- - [ ] **Server-state hooks include `language` in their `queryKey`** when the response contains translated strings
576
- - [ ] **Loading states render a `*Skeleton`** (not just a spinner) for cards/lists/tables
577
- - [ ] Responsive on mobile, tablet, and desktop
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 RadiusNever 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)