xertica-ui 2.5.3 → 2.7.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 (635) hide show
  1. package/CHANGELOG.md +705 -664
  2. package/README.md +482 -482
  3. package/assets/xertica-logo.svg +37 -37
  4. package/assets/xertica-x-logo.svg +20 -20
  5. package/bin/cli.ts +1293 -1256
  6. package/bin/generate-tokens.ts +256 -262
  7. package/bin/language-config.test.ts +32 -0
  8. package/bin/language-config.ts +384 -359
  9. package/components/Introduction.mdx +121 -121
  10. package/components/assistant/code-block/CodeBlock.tsx +7 -6
  11. package/components/assistant/code-block/code-block.mdx +38 -38
  12. package/components/assistant/code-block/code-block.test.tsx +2 -1
  13. package/components/assistant/formatted-document/FormattedDocument.tsx +3 -0
  14. package/components/assistant/formatted-document/formatted-document.mdx +31 -31
  15. package/components/assistant/formatted-document/formatted-document.test.tsx +5 -4
  16. package/components/assistant/markdown-message/MarkdownMessage.tsx +1 -1
  17. package/components/assistant/markdown-message/markdown-message.mdx +44 -44
  18. package/components/assistant/modern-chat-input/modern-chat-input.mdx +71 -71
  19. package/components/assistant/modern-chat-input/modern-chat-input.test.tsx +3 -2
  20. package/components/assistant/xertica-assistant/parts/AssistantMessageBubble.tsx +1 -1
  21. package/components/assistant/xertica-assistant/types.ts +3 -2
  22. package/components/assistant/xertica-assistant/use-assistant.ts +10 -10
  23. package/components/assistant/xertica-assistant/xertica-assistant.mdx +66 -66
  24. package/components/assistant/xertica-assistant/xertica-assistant.test.tsx +2 -1
  25. package/{templates/src/features/auth/ui → components/blocks/auth}/AuthPageShell.tsx +37 -32
  26. package/components/blocks/auth/PasswordStrengthMeter.tsx +41 -0
  27. package/components/blocks/auth/SocialLoginButtons.tsx +95 -0
  28. package/components/blocks/auth/index.ts +11 -0
  29. package/components/blocks/auth/usePasswordStrength.ts +13 -0
  30. package/components/blocks/card-patterns/card-patterns.mdx +123 -123
  31. package/components/blocks/index.ts +1 -0
  32. package/components/brand/branding/branding.mdx +27 -27
  33. package/components/brand/language-selector/language-selector.mdx +126 -126
  34. package/components/brand/theme-toggle/theme-toggle.mdx +47 -47
  35. package/components/brand/theme-toggle/theme-toggle.test.tsx +6 -2
  36. package/components/brand/xertica-logo/xertica-logo.mdx +56 -56
  37. package/components/brand/xertica-orbe/xertica-orbe.mdx +38 -38
  38. package/components/brand/xertica-provider/XerticaProvider.tsx +112 -112
  39. package/components/brand/xertica-provider/xertica-provider.mdx +61 -61
  40. package/components/brand/xertica-provider/xertica-provider.test.tsx +25 -13
  41. package/components/brand/xertica-xlogo/xertica-xlogo.mdx +55 -55
  42. package/components/examples/DrawingMapExample.tsx +1 -4
  43. package/components/layout/header/header.mdx +117 -117
  44. package/components/layout/header/header.test.tsx +2 -1
  45. package/components/layout/sidebar/sidebar.mdx +99 -99
  46. package/components/layout/sidebar/sidebar.stories.tsx +1033 -1033
  47. package/components/layout/sidebar/sidebar.test.tsx +2 -1
  48. package/components/layout/sidebar/sidebar.tsx +1509 -1506
  49. package/components/media/audio-player/AudioPlayer.mdx +67 -67
  50. package/components/media/audio-player/AudioPlayer.test.tsx +2 -1
  51. package/components/media/floating-media-wrapper.mdx +74 -74
  52. package/components/media/video-player/VideoPlayer.mdx +102 -102
  53. package/components/media/video-player/VideoPlayer.test.tsx +3 -2
  54. package/components/pages/forgot-password-page/ForgotPasswordPage.tsx +94 -188
  55. package/components/pages/forgot-password-page/forgot-password-page.mdx +60 -60
  56. package/components/pages/forgot-password-page/forgot-password-page.test.tsx +2 -1
  57. package/components/pages/home-content/HomeContent.tsx +119 -119
  58. package/components/pages/home-content/home-content.mdx +62 -62
  59. package/components/pages/home-page/HomePage.stories.tsx +8 -15
  60. package/components/pages/home-page/home-page.mdx +53 -53
  61. package/components/pages/home-page/home-page.test.tsx +2 -1
  62. package/components/pages/login-page/LoginPage.mdx +31 -31
  63. package/components/pages/login-page/LoginPage.tsx +125 -218
  64. package/components/pages/login-page/login-page.test.tsx +2 -1
  65. package/components/pages/reset-password-page/ResetPasswordPage.tsx +153 -243
  66. package/components/pages/reset-password-page/reset-password-page.mdx +63 -63
  67. package/components/pages/template-content/TemplateContent.tsx +1353 -1353
  68. package/components/pages/template-content/template-content.mdx +61 -61
  69. package/components/pages/template-page/TemplatePage.stories.tsx +32 -32
  70. package/components/pages/template-page/template-page.mdx +53 -53
  71. package/components/pages/template-page/template-page.test.tsx +2 -1
  72. package/components/pages/verify-email-page/VerifyEmailPage.tsx +104 -206
  73. package/components/pages/verify-email-page/verify-email-page.mdx +55 -55
  74. package/components/public-api-smoke.test.tsx +10 -6
  75. package/components/shared/assistant-utils.ts +3 -2
  76. package/components/shared/navigation.ts +2 -2
  77. package/components/ui/accordion/accordion.mdx +29 -29
  78. package/components/ui/alert/alert.mdx +29 -29
  79. package/components/ui/alert-dialog/alert-dialog.mdx +26 -26
  80. package/components/ui/aspect-ratio/aspect-ratio.mdx +25 -25
  81. package/components/ui/assistant-chart/AssistantChart.tsx +8 -2
  82. package/components/ui/assistant-chart/assistant-chart.mdx +25 -25
  83. package/components/ui/avatar/avatar.mdx +26 -26
  84. package/components/ui/badge/badge.mdx +28 -28
  85. package/components/ui/breadcrumb/breadcrumb.mdx +26 -26
  86. package/components/ui/button/button.mdx +29 -29
  87. package/components/ui/calendar/calendar.mdx +26 -26
  88. package/components/ui/card/card.mdx +26 -26
  89. package/components/ui/carousel/carousel.mdx +26 -26
  90. package/components/ui/chart/chart.mdx +26 -26
  91. package/components/ui/chart/chart.test.tsx +178 -178
  92. package/components/ui/chart/chart.tsx +2252 -2245
  93. package/components/ui/checkbox/checkbox.mdx +26 -26
  94. package/components/ui/collapsible/collapsible.mdx +25 -25
  95. package/components/ui/command/command.mdx +26 -26
  96. package/components/ui/context-menu/context-menu.mdx +26 -26
  97. package/components/ui/dialog/dialog.mdx +26 -26
  98. package/components/ui/drawer/drawer.mdx +26 -26
  99. package/components/ui/dropdown-menu/dropdown-menu.mdx +26 -26
  100. package/components/ui/empty/empty.mdx +26 -26
  101. package/components/ui/file-upload/file-upload.mdx +26 -26
  102. package/components/ui/form/form.mdx +20 -20
  103. package/components/ui/google-maps-loader/google-maps-loader.mdx +68 -68
  104. package/components/ui/hover-card/hover-card.mdx +26 -26
  105. package/components/ui/input/input.mdx +29 -29
  106. package/components/ui/input-otp/input-otp.mdx +26 -26
  107. package/components/ui/label/label.mdx +25 -25
  108. package/components/ui/map/map.mdx +26 -26
  109. package/components/ui/map/map.tsx +6 -1
  110. package/components/ui/menubar/menubar.mdx +26 -26
  111. package/components/ui/navigation-menu/navigation-menu.mdx +26 -26
  112. package/components/ui/notification-badge/notification-badge.mdx +26 -26
  113. package/components/ui/page-header/page-header.mdx +44 -44
  114. package/components/ui/pagination/pagination.mdx +26 -26
  115. package/components/ui/popover/popover.mdx +26 -26
  116. package/components/ui/progress/progress.mdx +25 -25
  117. package/components/ui/radio-group/radio-group.mdx +26 -26
  118. package/components/ui/rating/rating.mdx +26 -26
  119. package/components/ui/resizable/resizable.mdx +26 -26
  120. package/components/ui/resizable/resizable.tsx +13 -8
  121. package/components/ui/rich-text-editor/rich-text-editor.mdx +47 -47
  122. package/components/ui/route-map/route-map.mdx +26 -26
  123. package/components/ui/scroll-area/scroll-area.mdx +25 -25
  124. package/components/ui/search/search.mdx +27 -27
  125. package/components/ui/select/select.mdx +26 -26
  126. package/components/ui/separator/separator.mdx +25 -25
  127. package/components/ui/sheet/sheet.mdx +26 -26
  128. package/components/ui/simple-map/simple-map.mdx +25 -25
  129. package/components/ui/skeleton/skeleton.mdx +25 -25
  130. package/components/ui/slider/slider.mdx +26 -26
  131. package/components/ui/sonner/sonner.mdx +26 -26
  132. package/components/ui/stats-card/stats-card.mdx +26 -26
  133. package/components/ui/stats-card/stats-card.stories.tsx +117 -117
  134. package/components/ui/stats-card/stats-card.tsx +109 -109
  135. package/components/ui/stepper/stepper.mdx +26 -26
  136. package/components/ui/switch/switch.mdx +25 -25
  137. package/components/ui/table/table.mdx +27 -27
  138. package/components/ui/tabs/tabs.mdx +26 -26
  139. package/components/ui/textarea/textarea.mdx +25 -25
  140. package/components/ui/timeline/timeline.mdx +26 -26
  141. package/components/ui/toggle/toggle.mdx +26 -26
  142. package/components/ui/toggle-group/toggle-group.mdx +26 -26
  143. package/components/ui/tooltip/tooltip.mdx +26 -26
  144. package/components/ui/tree-view/tree-view.mdx +26 -26
  145. package/components.json +511 -511
  146. package/contexts/BrandColorsContext.tsx +282 -282
  147. package/contexts/i18n-singleton.test.tsx +57 -0
  148. package/contexts/theme-data.ts +391 -391
  149. package/dist/{AssistantChart-DNdwuS-t.js → AssistantChart-BMNSA_Pk.js} +4 -4
  150. package/dist/{AssistantChart-COGiOV-g.cjs → AssistantChart-BzM7plyc.cjs} +31 -21
  151. package/dist/{AssistantChart-CWX1OWNM.js → AssistantChart-C842evTi.js} +31 -21
  152. package/dist/{AssistantChart-D0A1FPYt.cjs → AssistantChart-CImCNLfD.cjs} +150 -114
  153. package/dist/{AssistantChart-BW9JK6jw.cjs → AssistantChart-CVF2uh37.cjs} +4 -4
  154. package/dist/{AssistantChart-BXU1ACnh.js → AssistantChart-DfdIfmQr.js} +134 -240
  155. package/dist/{AssistantChart-BZTPJ5dP.cjs → AssistantChart-JooMdVQU.cjs} +5 -5
  156. package/dist/{AssistantChart-DMJJ_Amf.js → AssistantChart-KHS-tp-L.js} +5 -5
  157. package/dist/{BrandColorsContext-BwY-b6M4.cjs → BrandColorsContext-B4_81eas.cjs} +2 -2
  158. package/dist/{BrandColorsContext-BMRJ04Wf.js → BrandColorsContext-DbK5LnQ_.js} +2 -2
  159. package/dist/{CodeBlock-CjeFavqV.js → CodeBlock-DiKO8ocT.js} +11 -11
  160. package/dist/{CodeBlock-CV6dtsTM.cjs → CodeBlock-ZYThr7Kn.cjs} +12 -9
  161. package/dist/{FeatureCard-Cfs6Ishq.js → FeatureCard-BhpfmPPx.js} +20 -20
  162. package/dist/{FeatureCard-ie3L8Fpr.cjs → FeatureCard-D-5yS_OD.cjs} +31 -18
  163. package/dist/{progress-DDeuWPZw.cjs → ImageWithFallback-CfkAkctC.cjs} +34 -9
  164. package/dist/{progress-Cs9i4DPx.js → ImageWithFallback-bw-CxxDc.js} +27 -10
  165. package/dist/LanguageContext-CX_zdxre.js +1912 -0
  166. package/dist/LanguageContext-CjhSSqJT.cjs +1917 -0
  167. package/dist/LanguageSelector-BR3Ss0k_.js +46 -0
  168. package/dist/LanguageSelector-CHOLPmHr.cjs +48 -0
  169. package/dist/{XerticaXLogo-mqjoBiLI.js → LanguageSelector-CmTj3lWq.js} +85 -82
  170. package/dist/{XerticaXLogo-BX3ueACh.js → LanguageSelector-DxW6o7bt.js} +81 -81
  171. package/dist/{XerticaXLogo-uQgwns_E.cjs → LanguageSelector-Sw73qvWV.cjs} +84 -81
  172. package/dist/PasswordStrengthMeter-C8irs0G1.js +173 -0
  173. package/dist/PasswordStrengthMeter-MLzhax-d.cjs +179 -0
  174. package/dist/{ThemeContext-BgclCB35.js → ThemeContext-BGeh_Kdr.js} +290 -212
  175. package/dist/{ThemeContext-bSzuOit2.cjs → ThemeContext-CEY9pCn-.cjs} +15 -10
  176. package/dist/{ThemeContext-BblcjQup.cjs → ThemeContext-D50irx5T.cjs} +291 -205
  177. package/dist/{ThemeContext-RTy1m2Uq.js → ThemeContext-Dk3tH7Ym.js} +14 -13
  178. package/dist/{XerticaXLogo-CFuIlYFH.js → ThemeToggle-BpM_iHh8.js} +56 -93
  179. package/dist/{XerticaXLogo-CziKMQil.cjs → ThemeToggle-CZRlv0d4.cjs} +62 -85
  180. package/dist/{VerifyEmailPage-C_Zk6Gen.cjs → VerifyEmailPage-B6bOrybJ.cjs} +17 -17
  181. package/dist/VerifyEmailPage-BKiaw2YK.js +2954 -0
  182. package/dist/{VerifyEmailPage-B31mCrMc.js → VerifyEmailPage-BRE5Fz59.js} +8 -8
  183. package/dist/{VerifyEmailPage-Cyl55sJb.js → VerifyEmailPage-BcCluouh.js} +135 -65
  184. package/dist/VerifyEmailPage-Beaicc6V.cjs +2963 -0
  185. package/dist/VerifyEmailPage-BehPBp0F.cjs +2963 -0
  186. package/dist/VerifyEmailPage-Bx1sr0uQ.cjs +3298 -0
  187. package/dist/{VerifyEmailPage-Bci0bA-P.js → VerifyEmailPage-DUYyXCX9.js} +3 -3
  188. package/dist/VerifyEmailPage-DXXMHbzq.js +3289 -0
  189. package/dist/VerifyEmailPage-Djb6hthM.js +2954 -0
  190. package/dist/{VerifyEmailPage-u_Dn7t1U.cjs → VerifyEmailPage-DpYtFk35.cjs} +21 -21
  191. package/dist/{VerifyEmailPage-X14vhdyl.js → VerifyEmailPage-NXKWW3Dk.js} +12 -12
  192. package/dist/{VerifyEmailPage-C7KiYXrm.cjs → VerifyEmailPage-QrCz4Wqr.cjs} +11 -11
  193. package/dist/{VerifyEmailPage-Bv8Ah_TK.cjs → VerifyEmailPage-ZmQra0Wi.cjs} +144 -74
  194. package/dist/{XerticaProvider-BErr83Bg.js → XerticaProvider-BF3q_myt.js} +5 -4
  195. package/dist/{XerticaProvider-B8CaV7xu.cjs → XerticaProvider-BijpC_py.cjs} +18 -11
  196. package/dist/{XerticaProvider-DQtvJU7m.js → XerticaProvider-C2wDRQhT.js} +17 -13
  197. package/dist/{XerticaProvider-CeS5G_n5.cjs → XerticaProvider-C_JSOz1U.cjs} +2 -2
  198. package/dist/{XerticaProvider-CwOkHxiT.cjs → XerticaProvider-D5zjrqZq.cjs} +5 -4
  199. package/dist/{XerticaProvider-ra2NciRq.js → XerticaProvider-KTGl4Cn1.js} +2 -2
  200. package/dist/{alert-dialog-DqlRW_An.js → alert-dialog-BrpwXKwS.js} +3 -3
  201. package/dist/{alert-dialog-yckpaOpy.cjs → alert-dialog-BzIcTKn_.cjs} +173 -166
  202. package/dist/{alert-dialog-DhwPioBa.cjs → alert-dialog-CZU1Zase.cjs} +3 -3
  203. package/dist/{alert-dialog-KpoabzJb.js → alert-dialog-ClRoLH7l.js} +40 -56
  204. package/dist/{alert-dialog-B4M3vQKS.cjs → alert-dialog-DBBqvU-V.cjs} +53 -38
  205. package/dist/{alert-dialog-iDe5VE5o.js → alert-dialog-kty5pxQp.js} +160 -183
  206. package/dist/assistant.cjs.js +2 -2
  207. package/dist/assistant.es.js +2 -2
  208. package/dist/blocks.cjs.js +7 -3
  209. package/dist/blocks.es.js +2 -2
  210. package/dist/brand.cjs.js +7 -6
  211. package/dist/brand.es.js +3 -2
  212. package/dist/cli.js +63 -21
  213. package/dist/components/assistant/code-block/CodeBlock.d.ts +2 -1
  214. package/dist/components/assistant/formatted-document/FormattedDocument.d.ts +2 -1
  215. package/dist/components/assistant/markdown-message/MarkdownMessage.d.ts +2 -1
  216. package/dist/components/assistant/modern-chat-input/ModernChatInput.d.ts +2 -1
  217. package/dist/components/assistant/xertica-assistant/parts/AssistantCollapsedView.d.ts +2 -1
  218. package/dist/components/assistant/xertica-assistant/parts/AssistantConversationList.d.ts +2 -1
  219. package/dist/components/assistant/xertica-assistant/parts/AssistantDocumentEditor.d.ts +2 -1
  220. package/dist/components/assistant/xertica-assistant/parts/AssistantFeedbackDialog.d.ts +2 -1
  221. package/dist/components/assistant/xertica-assistant/parts/AssistantHeader.d.ts +2 -1
  222. package/dist/components/assistant/xertica-assistant/parts/AssistantMessageBubble.d.ts +2 -1
  223. package/dist/components/assistant/xertica-assistant/parts/AssistantTabBar.d.ts +2 -1
  224. package/dist/components/assistant/xertica-assistant/parts/AssistantTypingIndicator.d.ts +2 -1
  225. package/dist/components/assistant/xertica-assistant/parts/AssistantWelcomeScreen.d.ts +2 -1
  226. package/dist/components/assistant/xertica-assistant/types.d.ts +3 -2
  227. package/dist/components/assistant/xertica-assistant/use-assistant.d.ts +1 -1
  228. package/dist/components/assistant/xertica-assistant/xertica-assistant.d.ts +2 -1
  229. package/dist/components/blocks/auth/AuthPageShell.d.ts +12 -0
  230. package/dist/components/blocks/auth/PasswordStrengthMeter.d.ts +7 -0
  231. package/dist/components/blocks/auth/SocialLoginButtons.d.ts +8 -0
  232. package/dist/components/blocks/auth/index.d.ts +8 -0
  233. package/dist/components/blocks/auth/usePasswordStrength.d.ts +3 -0
  234. package/dist/components/blocks/card-patterns/ActivityCard.d.ts +1 -1
  235. package/dist/components/blocks/card-patterns/ActivityCardSkeleton.d.ts +1 -1
  236. package/dist/components/blocks/card-patterns/FeatureCard.d.ts +1 -1
  237. package/dist/components/blocks/card-patterns/FeatureCardSkeleton.d.ts +1 -1
  238. package/dist/components/blocks/card-patterns/NotificationCard.d.ts +1 -1
  239. package/dist/components/blocks/card-patterns/NotificationCardSkeleton.d.ts +1 -1
  240. package/dist/components/blocks/card-patterns/ProfileCard.d.ts +1 -1
  241. package/dist/components/blocks/card-patterns/ProfileCardSkeleton.d.ts +1 -1
  242. package/dist/components/blocks/card-patterns/ProjectCard.d.ts +1 -1
  243. package/dist/components/blocks/card-patterns/ProjectCardSkeleton.d.ts +1 -1
  244. package/dist/components/blocks/card-patterns/QuickActionCard.d.ts +1 -1
  245. package/dist/components/blocks/card-patterns/QuickActionCardSkeleton.d.ts +1 -1
  246. package/dist/components/blocks/index.d.ts +1 -0
  247. package/dist/components/brand/language-selector/LanguageSelector.d.ts +2 -1
  248. package/dist/components/brand/theme-toggle/ThemeToggle.d.ts +2 -1
  249. package/dist/components/brand/xertica-logo/XerticaLogo.d.ts +2 -1
  250. package/dist/components/brand/xertica-orbe/XerticaOrbe.d.ts +2 -1
  251. package/dist/components/brand/xertica-provider/XerticaProvider.d.ts +1 -1
  252. package/dist/components/brand/xertica-xlogo/XerticaXLogo.d.ts +2 -1
  253. package/dist/components/examples/DrawingMapExample.d.ts +2 -1
  254. package/dist/components/examples/FilterableMapExample.d.ts +1 -1
  255. package/dist/components/examples/MapShowcase.d.ts +2 -1
  256. package/dist/components/examples/SimpleFilterableMap.d.ts +2 -1
  257. package/dist/components/figma/ImageWithFallback.d.ts +1 -1
  258. package/dist/components/layout/header/header.d.ts +1 -1
  259. package/dist/components/layout/sidebar/sidebar.d.ts +25 -13
  260. package/dist/components/media/FloatingMediaWrapper.d.ts +1 -1
  261. package/dist/components/media/audio-player/AudioPlayer.d.ts +2 -1
  262. package/dist/components/media/video-player/VideoPlayer.d.ts +2 -1
  263. package/dist/components/pages/forgot-password-page/ForgotPasswordPage.d.ts +2 -1
  264. package/dist/components/pages/home-content/HomeContent.d.ts +2 -1
  265. package/dist/components/pages/home-page/HomePage.d.ts +2 -1
  266. package/dist/components/pages/login-page/LoginPage.d.ts +2 -1
  267. package/dist/components/pages/reset-password-page/ResetPasswordPage.d.ts +3 -2
  268. package/dist/components/pages/template-content/TemplateContent.d.ts +2 -1
  269. package/dist/components/pages/template-page/TemplatePage.d.ts +2 -1
  270. package/dist/components/pages/verify-email-page/VerifyEmailPage.d.ts +2 -1
  271. package/dist/components/shared/CustomTooltipContent.d.ts +1 -1
  272. package/dist/components/shared/assistant-utils.d.ts +3 -2
  273. package/dist/components/shared/error-boundary.d.ts +4 -4
  274. package/dist/components/shared/error-fallbacks.d.ts +4 -3
  275. package/dist/components/shared/navigation.d.ts +6 -2
  276. package/dist/components/ui/accordion/accordion.d.ts +4 -4
  277. package/dist/components/ui/alert/alert.d.ts +3 -3
  278. package/dist/components/ui/alert-dialog/alert-dialog.d.ts +10 -10
  279. package/dist/components/ui/aspect-ratio/aspect-ratio.d.ts +1 -1
  280. package/dist/components/ui/assistant-chart/AssistantChart.d.ts +4 -3
  281. package/dist/components/ui/avatar/avatar.d.ts +3 -3
  282. package/dist/components/ui/badge/badge.d.ts +1 -1
  283. package/dist/components/ui/breadcrumb/breadcrumb.d.ts +7 -7
  284. package/dist/components/ui/calendar/calendar.d.ts +2 -2
  285. package/dist/components/ui/card/card.d.ts +7 -7
  286. package/dist/components/ui/carousel/carousel.d.ts +5 -5
  287. package/dist/components/ui/chart/chart.d.ts +16 -16
  288. package/dist/components/ui/collapsible/collapsible.d.ts +3 -3
  289. package/dist/components/ui/command/command.d.ts +9 -9
  290. package/dist/components/ui/context-menu/context-menu.d.ts +15 -15
  291. package/dist/components/ui/dialog/dialog.d.ts +9 -9
  292. package/dist/components/ui/drawer/drawer.d.ts +10 -10
  293. package/dist/components/ui/dropdown-menu/dropdown-menu.d.ts +15 -15
  294. package/dist/components/ui/form/form.d.ts +7 -7
  295. package/dist/components/ui/google-maps-loader/google-maps-loader.d.ts +3 -3
  296. package/dist/components/ui/hover-card/hover-card.d.ts +3 -3
  297. package/dist/components/ui/input-otp/input-otp.d.ts +4 -4
  298. package/dist/components/ui/label/label.d.ts +1 -1
  299. package/dist/components/ui/menubar/menubar.d.ts +16 -16
  300. package/dist/components/ui/navigation-menu/navigation-menu.d.ts +8 -8
  301. package/dist/components/ui/page-header/page-header.d.ts +3 -3
  302. package/dist/components/ui/pagination/pagination.d.ts +7 -7
  303. package/dist/components/ui/popover/popover.d.ts +4 -4
  304. package/dist/components/ui/progress/progress.d.ts +1 -1
  305. package/dist/components/ui/resizable/resizable.d.ts +11 -7
  306. package/dist/components/ui/rich-text-editor/rich-text-editor.d.ts +1 -1
  307. package/dist/components/ui/scroll-area/scroll-area.d.ts +2 -2
  308. package/dist/components/ui/separator/separator.d.ts +1 -1
  309. package/dist/components/ui/sheet/sheet.d.ts +10 -10
  310. package/dist/components/ui/skeleton/skeleton.d.ts +1 -1
  311. package/dist/components/ui/sonner/sonner.d.ts +2 -1
  312. package/dist/components/ui/stats-card/stats-card-skeleton.d.ts +1 -1
  313. package/dist/components/ui/table/table.d.ts +8 -8
  314. package/dist/components/ui/tabs/tabs.d.ts +4 -4
  315. package/dist/components/ui/tooltip/tooltip.d.ts +4 -4
  316. package/dist/contexts/ApiKeyContext.d.ts +2 -2
  317. package/dist/contexts/AssistenteContext.d.ts +1 -1
  318. package/dist/contexts/AuthContext.d.ts +1 -1
  319. package/dist/contexts/LanguageContext.d.ts +2 -2
  320. package/dist/contexts/LayoutContext.d.ts +2 -2
  321. package/dist/contexts/ThemeContext.d.ts +1 -1
  322. package/dist/features/assistant/hooks/useAssistantConfig.d.ts +1 -1
  323. package/dist/features/home/hooks/useDashboardStats.d.ts +1 -1
  324. package/dist/features/home/hooks/useFeatureCards.d.ts +1 -1
  325. package/dist/features/home/hooks/useTeamMembers.d.ts +1 -1
  326. package/dist/{google-maps-loader-BCe58h9D.js → google-maps-loader-BOug999f.js} +0 -4
  327. package/dist/{google-maps-loader-casMyxlo.cjs → google-maps-loader-DfeBRI8Q.cjs} +0 -5
  328. package/dist/hooks.cjs.js +6 -5
  329. package/dist/hooks.es.js +3 -2
  330. package/dist/{index-9GWd0qxq.cjs → index-BQjx1Mdf.cjs} +1 -1
  331. package/dist/index-Bei5DzAL.js +6 -0
  332. package/dist/index.cjs.js +32 -27
  333. package/dist/index.es.js +15 -14
  334. package/dist/layout.cjs.js +1 -1
  335. package/dist/layout.es.js +1 -1
  336. package/dist/pages.cjs.js +1 -1
  337. package/dist/pages.es.js +1 -1
  338. package/dist/{rich-text-editor-B2CKz7nx.cjs → rich-text-editor-BuqSu718.cjs} +68 -3
  339. package/dist/{rich-text-editor-DloeW0wc.js → rich-text-editor-CV8FtA_l.js} +66 -4
  340. package/dist/{sidebar-B4ZWaMrE.js → sidebar-B7YzwAp3.js} +365 -6
  341. package/dist/{sidebar-CLmIjgNd.cjs → sidebar-BGJ0j567.cjs} +84 -67
  342. package/dist/{sidebar-Duermn32.js → sidebar-BI6mZlC8.js} +81 -64
  343. package/dist/{sidebar-BS1p2V7t.cjs → sidebar-BtmotOg-.cjs} +367 -9
  344. package/dist/{sidebar-DyYvgyBj.cjs → sidebar-Cb0U7NsV.cjs} +368 -9
  345. package/dist/{sidebar-QwCoeoZ_.js → sidebar-D3EgGVxF.js} +1 -1
  346. package/dist/{sidebar-CQn_rwxP.cjs → sidebar-DDTqMGnR.cjs} +4 -4
  347. package/dist/{sidebar-3XyzjVBw.js → sidebar-I7EXyf5D.js} +364 -6
  348. package/dist/ui.cjs.js +9 -9
  349. package/dist/ui.es.js +5 -5
  350. package/dist/{xertica-assistant-BbgzsgsG.js → xertica-assistant-8fh8KA2K.js} +60 -51
  351. package/dist/{xertica-assistant-d2qs2Vd9.cjs → xertica-assistant-BjfG3zyL.cjs} +63 -46
  352. package/dist/{xertica-assistant-B687qEPU.js → xertica-assistant-CJVnvMqU.js} +17 -8
  353. package/dist/{xertica-assistant-sOHwTgIP.cjs → xertica-assistant-CKPtc1z5.cjs} +19 -10
  354. package/dist/{xertica-assistant-QFUnv5I2.cjs → xertica-assistant-DER0brPQ.cjs} +6 -5
  355. package/dist/{xertica-assistant-CyikE3N_.js → xertica-assistant-DQCjpk5M.js} +4 -3
  356. package/dist/{xertica-assistant-B1NaSFFj.js → xertica-assistant-Dk-9AJzw.js} +6 -5
  357. package/dist/{xertica-assistant-CIaUlbIt.cjs → xertica-assistant-DxhIKvuY.cjs} +8 -7
  358. package/dist/xertica-ui.css +2 -2
  359. package/docs/components/audio-player.md +1 -1
  360. package/docs/components/sidebar.md +331 -331
  361. package/docs/components/stats-card.md +138 -138
  362. package/docs/components/toggle.md +12 -0
  363. package/docs/doc-audit.md +35 -229
  364. package/docs/i18n.md +33 -10
  365. package/docs/llms.md +6 -4
  366. package/llms-compact.txt +444 -444
  367. package/llms-full.txt +12144 -12144
  368. package/llms.txt +187 -187
  369. package/package.json +223 -219
  370. package/scripts/a11y-audit.mjs +162 -162
  371. package/scripts/fix-stories.cjs +19 -19
  372. package/styles/globals.css +0 -1
  373. package/styles/xertica/base.css +8 -0
  374. package/styles/xertica/tokens.css +240 -240
  375. package/templates/.env.example +2 -2
  376. package/templates/.prettierignore +4 -4
  377. package/templates/.prettierrc +10 -10
  378. package/templates/guidelines/Guidelines.md +865 -865
  379. package/templates/index.html +13 -13
  380. package/templates/package.json +69 -69
  381. package/templates/src/app/components/AuthGuard.tsx +11 -0
  382. package/templates/src/features/auth/ui/ForgotPasswordContent.tsx +1 -2
  383. package/templates/src/features/auth/ui/LoginContent.tsx +1 -2
  384. package/templates/src/features/auth/ui/ResetPasswordContent.tsx +3 -57
  385. package/templates/src/features/auth/ui/VerifyEmailContent.tsx +1 -2
  386. package/templates/src/features/home/index.ts +0 -10
  387. package/templates/src/features/home/ui/HomeContent.tsx +62 -116
  388. package/templates/src/features/settings/index.ts +2 -0
  389. package/templates/src/features/settings/ui/SettingsContent.tsx +134 -0
  390. package/templates/src/features/template/index.ts +0 -4
  391. package/templates/src/features/template/ui/TemplateContent.tsx +68 -1321
  392. package/templates/src/i18n.ts +36 -13
  393. package/templates/src/locales/en/pages/settings.json +15 -0
  394. package/templates/src/locales/en/pages/templates.json +5 -313
  395. package/templates/src/locales/es/pages/settings.json +15 -0
  396. package/templates/src/locales/es/pages/templates.json +5 -313
  397. package/templates/src/locales/pt-BR/pages/settings.json +15 -0
  398. package/templates/src/locales/pt-BR/pages/templates.json +5 -313
  399. package/templates/src/pages/SettingsPage.tsx +28 -0
  400. package/templates/src/shared/config/navigation.ts +2 -2
  401. package/templates/src/styles/xertica/tokens.css +240 -240
  402. package/utils/gemini.ts +2 -2
  403. package/dist/AssistantChart-9w31gdAb.cjs +0 -3363
  404. package/dist/AssistantChart-BAudAfne.cjs +0 -3591
  405. package/dist/AssistantChart-BAx9VQvb.cjs +0 -3374
  406. package/dist/AssistantChart-BP8upjMk.js +0 -3565
  407. package/dist/AssistantChart-CVko2A1W.js +0 -3348
  408. package/dist/AssistantChart-CVzmmhx4.js +0 -3337
  409. package/dist/AssistantChart-CeU2dIb6.js +0 -3469
  410. package/dist/AssistantChart-DO5UuX4J.cjs +0 -3495
  411. package/dist/AudioPlayer-1ypwE2Wh.cjs +0 -936
  412. package/dist/AudioPlayer-BJ2IuRQW.cjs +0 -1275
  413. package/dist/AudioPlayer-BWDW6TN9.cjs +0 -1279
  414. package/dist/AudioPlayer-CM962GEh.js +0 -1280
  415. package/dist/AudioPlayer-CbZId7cj.cjs +0 -998
  416. package/dist/AudioPlayer-DU8zt8-z.js +0 -999
  417. package/dist/AudioPlayer-DuKXrCfy.js +0 -937
  418. package/dist/AudioPlayer-Xxma6_-H.js +0 -1276
  419. package/dist/BrandColorsContext-DLVJgtmH.js +0 -666
  420. package/dist/BrandColorsContext-DZT7JjeD.js +0 -659
  421. package/dist/BrandColorsContext-GUyFmkX0.cjs +0 -665
  422. package/dist/BrandColorsContext-awnBCmC4.cjs +0 -666
  423. package/dist/CodeBlock-C2ZUXt8V.js +0 -219
  424. package/dist/CodeBlock-C5oYnLQp.cjs +0 -218
  425. package/dist/CodeBlock-DuxdtN-l.js +0 -219
  426. package/dist/CodeBlock-POVYONvC.cjs +0 -218
  427. package/dist/CustomTooltipContent-BT6brkVJ.cjs +0 -49
  428. package/dist/CustomTooltipContent-CfOfikhq.js +0 -33
  429. package/dist/CustomTooltipContent-DHjkY0ww.js +0 -40
  430. package/dist/CustomTooltipContent-c_K-DWRr.cjs +0 -56
  431. package/dist/FeatureCard-9GhnlgL3.js +0 -336
  432. package/dist/FeatureCard-Bcb3Zi54.js +0 -302
  433. package/dist/FeatureCard-CkPd2psQ.cjs +0 -301
  434. package/dist/FeatureCard-Dkp-xmzM.cjs +0 -335
  435. package/dist/FeatureCardSkeleton-CAgu8stE.js +0 -27
  436. package/dist/FeatureCardSkeleton-mO3Bdm_V.cjs +0 -26
  437. package/dist/LanguageContext-BwhwC3G2.js +0 -657
  438. package/dist/LanguageContext-DvUt5jBg.cjs +0 -656
  439. package/dist/LayoutContext-BDmcZfMH.cjs +0 -84
  440. package/dist/LayoutContext-C4kKN9RV.cjs +0 -93
  441. package/dist/LayoutContext-CGEe1oPq.js +0 -94
  442. package/dist/LayoutContext-CwT5KLiW.cjs +0 -104
  443. package/dist/LayoutContext-DVLCsoQn.js +0 -105
  444. package/dist/LayoutContext-dbQvdC4O.js +0 -85
  445. package/dist/ThemeContext-BbBNoFTG.js +0 -735
  446. package/dist/ThemeContext-Bo-W2WZH.js +0 -1856
  447. package/dist/ThemeContext-CP3a0jxy.cjs +0 -1855
  448. package/dist/ThemeContext-Cmr8Ex8H.cjs +0 -734
  449. package/dist/ThemeContext-CpqYShLq.cjs +0 -324
  450. package/dist/ThemeContext-D3LzacmG.js +0 -188
  451. package/dist/ThemeContext-DQUOeziy.cjs +0 -1855
  452. package/dist/ThemeContext-Du2nE1PL.js +0 -325
  453. package/dist/ThemeContext-GeEBTJ3q.cjs +0 -1621
  454. package/dist/ThemeContext-JyLK9B1o.js +0 -1622
  455. package/dist/ThemeContext-U4dEYc6C.cjs +0 -187
  456. package/dist/ThemeContext-ept8jhXI.js +0 -1856
  457. package/dist/VerifyEmailPage-BE-L9mB7.js +0 -2828
  458. package/dist/VerifyEmailPage-BIBOKV7Z.js +0 -3214
  459. package/dist/VerifyEmailPage-BJjAMUTW.js +0 -3223
  460. package/dist/VerifyEmailPage-BRSP-Pwt.cjs +0 -3196
  461. package/dist/VerifyEmailPage-Bae2cBXT.cjs +0 -2827
  462. package/dist/VerifyEmailPage-BiRm7Nh4.cjs +0 -3213
  463. package/dist/VerifyEmailPage-Bvfv8HVQ.js +0 -3214
  464. package/dist/VerifyEmailPage-CR7kb5df.cjs +0 -2827
  465. package/dist/VerifyEmailPage-C_ihbcth.js +0 -2828
  466. package/dist/VerifyEmailPage-CbgjOF0v.js +0 -2828
  467. package/dist/VerifyEmailPage-CdYPSJoO.js +0 -2828
  468. package/dist/VerifyEmailPage-CkBYfsNy.cjs +0 -3232
  469. package/dist/VerifyEmailPage-D-FRj5TU.cjs +0 -3213
  470. package/dist/VerifyEmailPage-DF2ilhum.cjs +0 -3210
  471. package/dist/VerifyEmailPage-DMBh4NM9.cjs +0 -2827
  472. package/dist/VerifyEmailPage-DTtFfC-J.js +0 -3197
  473. package/dist/VerifyEmailPage-Dt7zgA4w.cjs +0 -2827
  474. package/dist/VerifyEmailPage-EhudUdqF.js +0 -3211
  475. package/dist/VerifyEmailPage-RrUApqBN.js +0 -3214
  476. package/dist/VerifyEmailPage-VoMI7MYH.cjs +0 -3213
  477. package/dist/VerifyEmailPage-hdB8JQGv.cjs +0 -3213
  478. package/dist/VerifyEmailPage-vYHbYK3q.js +0 -3214
  479. package/dist/XerticaOrbe-BCUVSPPB.cjs +0 -1924
  480. package/dist/XerticaOrbe-BGIB1CTK.js +0 -1355
  481. package/dist/XerticaOrbe-By8eEvR-.js +0 -1925
  482. package/dist/XerticaOrbe-FWGjBj0U.cjs +0 -1354
  483. package/dist/XerticaProvider-AChwphCO.cjs +0 -48
  484. package/dist/XerticaProvider-AbWlr7Af.cjs +0 -48
  485. package/dist/XerticaProvider-BITjgC5p.js +0 -39
  486. package/dist/XerticaProvider-BSyFrmC0.js +0 -49
  487. package/dist/XerticaProvider-By8q3Roe.cjs +0 -38
  488. package/dist/XerticaProvider-CUYJZc32.js +0 -49
  489. package/dist/XerticaProvider-CW9hpCdF.cjs +0 -39
  490. package/dist/XerticaProvider-CWgby5mY.js +0 -49
  491. package/dist/XerticaProvider-CWs6EwNa.js +0 -49
  492. package/dist/XerticaProvider-CiNKjMx1.cjs +0 -48
  493. package/dist/XerticaProvider-CjQAQPcn.cjs +0 -48
  494. package/dist/XerticaProvider-D5lLumH-.js +0 -49
  495. package/dist/XerticaProvider-DUOJg9iX.js +0 -49
  496. package/dist/XerticaProvider-Dl_b72_l.cjs +0 -51
  497. package/dist/XerticaProvider-qQUDop71.cjs +0 -48
  498. package/dist/XerticaProvider-siSt9uG2.js +0 -40
  499. package/dist/XerticaXLogo-8TTzBjHw.cjs +0 -251
  500. package/dist/XerticaXLogo-B2svDGZh.cjs +0 -251
  501. package/dist/XerticaXLogo-BWaag64t.js +0 -252
  502. package/dist/XerticaXLogo-CU-U-GP4.cjs +0 -251
  503. package/dist/XerticaXLogo-ChryA6xj.js +0 -252
  504. package/dist/XerticaXLogo-CowGv7BC.js +0 -252
  505. package/dist/XerticaXLogo-D8jf0SNv.cjs +0 -214
  506. package/dist/XerticaXLogo-DHz5SugF.js +0 -252
  507. package/dist/XerticaXLogo-DTee_y8X.cjs +0 -251
  508. package/dist/XerticaXLogo-DfUvz-lD.js +0 -243
  509. package/dist/XerticaXLogo-DzXKZBtG.js +0 -231
  510. package/dist/XerticaXLogo-fAJMy3H4.js +0 -215
  511. package/dist/XerticaXLogo-kslQ8Tk_.cjs +0 -251
  512. package/dist/XerticaXLogo-xWbElCZj.cjs +0 -230
  513. package/dist/avatar-Cq5_E8r9.cjs +0 -78
  514. package/dist/avatar-CuYu2MKt.cjs +0 -72
  515. package/dist/avatar-Cxyofu1H.js +0 -56
  516. package/dist/avatar-DSBfJMRJ.js +0 -62
  517. package/dist/breadcrumb-CVzzzqfo.js +0 -103
  518. package/dist/breadcrumb-DIJ0X3Ot.js +0 -96
  519. package/dist/breadcrumb-DjSxkjlQ.cjs +0 -95
  520. package/dist/breadcrumb-DnDlQFg2.cjs +0 -102
  521. package/dist/button-0CXwCRTm.cjs +0 -85
  522. package/dist/button-Bnv9SvYK.cjs +0 -79
  523. package/dist/button-C6uvh0rV.js +0 -63
  524. package/dist/button-qkz7Icqf.js +0 -69
  525. package/dist/card-B8-Gl5DL.js +0 -73
  526. package/dist/card-Bv_c57KU.cjs +0 -72
  527. package/dist/card-DJTsYhLL.cjs +0 -89
  528. package/dist/card-fi8zAN-I.js +0 -90
  529. package/dist/dropdown-menu-B_uEXNc4.cjs +0 -220
  530. package/dist/dropdown-menu-CFuCssWA.js +0 -204
  531. package/dist/dropdown-menu-Ze1YZFyc.cjs +0 -247
  532. package/dist/dropdown-menu-nc_Lvg-u.js +0 -231
  533. package/dist/google-maps-loader-BVoVhUwA.js +0 -316
  534. package/dist/google-maps-loader-BqsYL48U.cjs +0 -285
  535. package/dist/google-maps-loader-DjJaYhV6.cjs +0 -316
  536. package/dist/google-maps-loader-t2IlYBzw.js +0 -286
  537. package/dist/index-B7A523O_.js +0 -8
  538. package/dist/index-BabBx2pa.js +0 -6
  539. package/dist/index-CkTUgOwX.js +0 -8
  540. package/dist/index-D3RLKRAs.cjs +0 -7
  541. package/dist/index-DmHhnb7a.cjs +0 -7
  542. package/dist/index.umd.js +0 -13712
  543. package/dist/input-CNFHVKvo.cjs +0 -145
  544. package/dist/input-CPl84zAx.cjs +0 -151
  545. package/dist/input-C_UiS2Py.cjs +0 -152
  546. package/dist/input-D-6IsAca.js +0 -133
  547. package/dist/input-cc-PTD4R.js +0 -123
  548. package/dist/input-wPYg0d0P.js +0 -127
  549. package/dist/progress-BLwqortq.cjs +0 -105
  550. package/dist/progress-D9mtsf6j.js +0 -89
  551. package/dist/rich-text-editor-1UW3Y2JK.js +0 -2891
  552. package/dist/rich-text-editor-BM-LPpTh.js +0 -2902
  553. package/dist/rich-text-editor-BmsjY03B.js +0 -2949
  554. package/dist/rich-text-editor-BrdC5evx.js +0 -2244
  555. package/dist/rich-text-editor-CyggTOLQ.cjs +0 -2908
  556. package/dist/rich-text-editor-DbV-S7Fi.cjs +0 -2261
  557. package/dist/rich-text-editor-DoCkKhzk.cjs +0 -2919
  558. package/dist/rich-text-editor-DqLICivI.js +0 -2832
  559. package/dist/rich-text-editor-DxO1Hz3a.cjs +0 -2903
  560. package/dist/rich-text-editor-GS2kpTAK.cjs +0 -2966
  561. package/dist/routes.d.ts +0 -10
  562. package/dist/select-Cmb8zF7w.cjs +0 -156
  563. package/dist/select-CprSNX0z.js +0 -139
  564. package/dist/select-DT7Zjn42.cjs +0 -162
  565. package/dist/select-En8DkoaQ.js +0 -145
  566. package/dist/sidebar-B3EYhli0.cjs +0 -800
  567. package/dist/sidebar-B9NR0lCe.cjs +0 -800
  568. package/dist/sidebar-BcJ6LxvX.cjs +0 -733
  569. package/dist/sidebar-BvF5I2Ue.cjs +0 -800
  570. package/dist/sidebar-C5B_LHek.cjs +0 -795
  571. package/dist/sidebar-CA6_ek3f.js +0 -801
  572. package/dist/sidebar-CRMiBtAi.js +0 -801
  573. package/dist/sidebar-CVUGHOS_.cjs +0 -756
  574. package/dist/sidebar-CZ2mWaMM.cjs +0 -800
  575. package/dist/sidebar-CmvwjnVb.js +0 -757
  576. package/dist/sidebar-CplprZpM.js +0 -801
  577. package/dist/sidebar-Dz7bd3zP.js +0 -796
  578. package/dist/sidebar-KIS0C2JH.js +0 -801
  579. package/dist/sidebar-OTO_up7Z.js +0 -801
  580. package/dist/sidebar-WoKvFWCN.js +0 -717
  581. package/dist/sidebar-zowjejT2.cjs +0 -800
  582. package/dist/skeleton-4zoHiFJ_.cjs +0 -83
  583. package/dist/skeleton-C4bHqUBf.js +0 -84
  584. package/dist/slider-C0JKA9k3.js +0 -56
  585. package/dist/slider-CPmwzm_3.cjs +0 -73
  586. package/dist/slider-DcJharR9.cjs +0 -73
  587. package/dist/slider-Pay3fka2.js +0 -56
  588. package/dist/sonner-DeUIj0Zg.cjs +0 -63
  589. package/dist/sonner-g9RIfi35.js +0 -47
  590. package/dist/tooltip-CNtsL5cB.cjs +0 -71
  591. package/dist/tooltip-CTyZCD8h.js +0 -55
  592. package/dist/tooltip-CwgSdy3h.cjs +0 -67
  593. package/dist/tooltip-D-OrYnKO.js +0 -51
  594. package/dist/use-audio-player-BJFV24XW.js +0 -188
  595. package/dist/use-audio-player-Bkh23vQ3.js +0 -177
  596. package/dist/use-audio-player-Dn1NR9xN.cjs +0 -176
  597. package/dist/use-audio-player-DyVYlOnR.cjs +0 -187
  598. package/dist/use-mobile-BB4M_4Ru.cjs +0 -47
  599. package/dist/use-mobile-CLu9nqGL.js +0 -31
  600. package/dist/use-mobile-CNwiBNxu.js +0 -33
  601. package/dist/use-mobile-Dlf74ufz.cjs +0 -49
  602. package/dist/xertica-assistant-B1IaHXnB.cjs +0 -1894
  603. package/dist/xertica-assistant-BMqdyRVi.js +0 -2082
  604. package/dist/xertica-assistant-Bj3vBCq_.cjs +0 -2081
  605. package/dist/xertica-assistant-CfBCo21g.js +0 -2148
  606. package/dist/xertica-assistant-DIM_Do1k.js +0 -1866
  607. package/dist/xertica-assistant-DPsESB6t.js +0 -1878
  608. package/dist/xertica-assistant-DrsRwla1.cjs +0 -2147
  609. package/dist/xertica-assistant-Qp3ydksa.cjs +0 -1882
  610. package/dist/xertica-assistant-gnCJdcZY.js +0 -1866
  611. package/dist/xertica-assistant-yyrR0JKl.cjs +0 -1882
  612. package/styles/xertica/app-overrides/scrollbar.css +0 -33
  613. package/templates/src/features/auth/ui/SocialLoginButtons.tsx +0 -78
  614. package/templates/src/features/home/data/mock.ts +0 -41
  615. package/templates/src/features/home/hooks/useFeatureCards.ts +0 -20
  616. package/templates/src/features/home/store/dashboardStore.ts +0 -25
  617. package/templates/src/features/template/ui/CrudTemplate.tsx +0 -112
  618. package/templates/src/features/template/ui/DashboardTemplate.tsx +0 -110
  619. package/templates/src/features/template/ui/FormTemplate.tsx +0 -117
  620. package/templates/src/features/template/ui/LoginTemplate.tsx +0 -59
  621. package/templates/src/locales/en/pages/crudTemplate.json +0 -25
  622. package/templates/src/locales/en/pages/dashboardTemplate.json +0 -20
  623. package/templates/src/locales/en/pages/formTemplate.json +0 -16
  624. package/templates/src/locales/en/pages/loginTemplate.json +0 -9
  625. package/templates/src/locales/es/pages/crudTemplate.json +0 -25
  626. package/templates/src/locales/es/pages/dashboardTemplate.json +0 -20
  627. package/templates/src/locales/es/pages/formTemplate.json +0 -16
  628. package/templates/src/locales/es/pages/loginTemplate.json +0 -9
  629. package/templates/src/locales/pt-BR/pages/crudTemplate.json +0 -25
  630. package/templates/src/locales/pt-BR/pages/dashboardTemplate.json +0 -20
  631. package/templates/src/locales/pt-BR/pages/formTemplate.json +0 -16
  632. package/templates/src/locales/pt-BR/pages/loginTemplate.json +0 -9
  633. package/templates/vite.config.d.ts +0 -2
  634. package/templates/vite.config.js +0 -20
  635. package/dist/{XerticaXLogo-qBPhwK3g.cjs → LanguageSelector-1cINLJ23.cjs} +80 -80
@@ -1,865 +1,865 @@
1
- # Project Guidelines — Xertica UI App
2
-
3
- > **Scope**: These guidelines apply to any React application scaffolded with `npx xertica-ui@latest init`. They define architecture, import conventions, component rules, state management, and AI agent behavior.
4
- >
5
- > **AI agents — reading order**:
6
- > 1. This file (architecture + rules)
7
- > 2. `node_modules/xertica-ui/llms-compact.txt` (component catalog + quick reference)
8
- > 3. `node_modules/xertica-ui/docs/decision-tree.md` (when choosing between similar components)
9
- > 4. `node_modules/xertica-ui/docs/components/<name>.md` (when you need a specific component's full props)
10
- > 5. `node_modules/xertica-ui/docs/ai-usage.md` (mandatory constraint list)
11
-
12
- ---
13
-
14
- ## 1. Architecture — Feature-Sliced Design + Feature-Driven Architecture
15
-
16
- This project follows **FSD (Feature-Sliced Design)** layered architecture combined with **FDA (Feature-Driven Architecture)** vertical slicing. **Layers can only import from layers below them.**
17
-
18
- ```
19
- src/
20
- ├── app/ # Layer 1 — Application shell (imports from all layers)
21
- │ ├── App.tsx # XerticaProvider + BrowserRouter + AuthGuard (CLI-generated)
22
- │ ├── context/
23
- │ │ └── AuthContext.tsx # AuthProvider + useAuth() hook
24
- │ └── components/
25
- │ ├── AppLayout.tsx # Sidebar + children + optional XerticaAssistant
26
- │ └── AuthGuard.tsx # All route definitions + route guard components
27
-
28
- ├── shared/ # Layer 2 — Shared utilities (no business logic)
29
- │ ├── config/
30
- │ │ └── navigation.ts # RouteConfig type, routes[], getRoutesByRole()
31
- │ ├── mock/ # Domain mock data (TypeScript static arrays + helpers)
32
- │ ├── lib/
33
- │ │ └── auth.ts # getStoredUser, storeUser, clearStoredUser
34
- │ └── types/
35
- │ └── auth.ts # User interface + UserRole type
36
-
37
- ├── features/ # Layer 3 — Vertical slices by business capability
38
- │ ├── auth/ # Login, ForgotPassword, VerifyEmail, ResetPassword
39
- │ ├── home/ # Post-login hub (FeatureCards grid)
40
- │ │ ├── data/mock.ts # Types + async fetch + factory functions (getMockXxx)
41
- │ │ ├── hooks/useFeatureCards.ts # React Query, queryKey includes `language`
42
- │ │ ├── store/dashboardStore.ts # Zustand UI state (no server data)
43
- │ │ ├── ui/HomeContent.tsx
44
- │ │ └── index.ts
45
- │ ├── assistant/ # XerticaAssistant — AppLayout depends on it
46
- │ │ ├── data/mock.ts
47
- │ │ ├── hooks/useAssistantConfig.ts
48
- │ │ └── index.ts
49
- │ └── <domain>/ # One slice per business domain
50
- │ ├── data/mock.ts # Domain types + mock fetch functions
51
- │ ├── hooks/use<Domain>.ts # React Query wrapper
52
- │ ├── store/<domain>Store.ts # Zustand UI state (optional)
53
- │ ├── ui/<Domain>Content.tsx # Page content component
54
- │ └── index.ts # Barrel — ONLY public interface for this feature
55
-
56
- ├── pages/ # Layer 4 — Thin route wrappers only
57
- │ └── <Name>Page.tsx # AppLayout + <NameContent> + optional XerticaAssistant
58
-
59
- ├── i18n.ts # i18next setup (CLI-generated — do not hand-edit)
60
- ├── locales/
61
- │ ├── .languages.json # CLI-managed language selection
62
- │ └── pt-BR/ # One folder per language
63
- │ ├── common.json # Shared action labels
64
- │ ├── nav.json # Navigation labels
65
- │ ├── errors.json # Error boundary UI
66
- │ ├── pages/ # Per-page namespaces
67
- │ └── components/ # Per-component namespaces
68
- └── styles/
69
- ├── index.css # Imports: xertica-ui/style.css, tokens.css, @source
70
- └── xertica/tokens.css # Brand CSS variables — customize here only
71
- ```
72
-
73
- ### Layer Import Rules
74
-
75
- - `app/` → can import from all layers
76
- - `shared/` → cannot import from `features/` or `pages/`
77
- - `features/<a>/` → cannot import from `features/<b>/` — extract shared code to `shared/`
78
- - `pages/` → imports only from `features/` barrels and `app/`
79
-
80
- ### Feature Barrel Rule
81
-
82
- The `index.ts` is the **only** public interface of a feature. Always import from the barrel, never from internal paths:
83
-
84
- ```tsx
85
- // ✅ Correct
86
- import { LoginContent } from '../features/auth';
87
-
88
- // ❌ Wrong — never import from internal paths
89
- import { LoginContent } from '../features/auth/ui/LoginContent';
90
- ```
91
-
92
- ---
93
-
94
- ## 2. Import Rules
95
-
96
- Always use the correct `xertica-ui` subpath for the domain you need:
97
-
98
- ```tsx
99
- // UI primitives — buttons, inputs, dialogs, tables, badges, etc.
100
- import {
101
- Button, Input, Textarea, Select, SelectContent, SelectItem, SelectTrigger, SelectValue,
102
- Card, CardContent, CardHeader, CardTitle, CardDescription, CardFooter,
103
- Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter,
104
- AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader,
105
- AlertDialogTitle, AlertDialogDescription, AlertDialogFooter,
106
- AlertDialogCancel, AlertDialogAction,
107
- Table, TableBody, TableCell, TableHead, TableHeader, TableRow,
108
- Badge, Progress, ScrollArea, Separator, Skeleton, Label, Switch,
109
- Tabs, TabsContent, TabsList, TabsTrigger,
110
- Collapsible, CollapsibleContent, CollapsibleTrigger,
111
- Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage,
112
- Tooltip, TooltipContent, TooltipProvider, TooltipTrigger,
113
- Popover, PopoverContent, PopoverTrigger,
114
- Sheet, SheetContent, SheetHeader, SheetTitle, SheetDescription,
115
- Alert, AlertDescription, Drawer,
116
- } from 'xertica-ui/ui';
117
-
118
- // Composed high-level block components
119
- import {
120
- FeatureCard, FeatureCardSkeleton,
121
- QuickActionCard, QuickActionCardSkeleton,
122
- ProjectCard, ProjectCardSkeleton,
123
- ActivityCard, ActivityCardSkeleton,
124
- NotificationCard, NotificationCardSkeleton,
125
- ProfileCard, ProfileCardSkeleton,
126
- StatsCard, StatsCardSkeleton,
127
- } from 'xertica-ui/blocks';
128
-
129
- // Application shell
130
- import { Sidebar, Header } from 'xertica-ui/layout';
131
-
132
- // Brand / providers
133
- import { XerticaProvider, XerticaLogo, ThemeToggle, LanguageSelector } from 'xertica-ui/brand';
134
-
135
- // AI assistant
136
- import { XerticaAssistant, generateDemoResponse } from 'xertica-ui/assistant';
137
-
138
- // Media players
139
- import { VideoPlayer, AudioPlayer } from 'xertica-ui/media';
140
-
141
- // Hooks
142
- import { useLayout, useOptionalLayout, useTheme, useLanguage } from 'xertica-ui/hooks';
143
-
144
- // Icons — ALWAYS from lucide-react, NEVER from xertica-ui or inline SVG
145
- import { Home, Settings, Plus, Trash2, ChevronRight, Search } from 'lucide-react';
146
-
147
- // Charts — use recharts (pre-installed)
148
- import {
149
- BarChart, Bar, LineChart, Line, PieChart, Pie, Cell,
150
- XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer,
151
- } from 'recharts';
152
-
153
- // Toast
154
- import { toast } from 'sonner';
155
-
156
- // Form validation
157
- import { useForm } from 'react-hook-form';
158
- import { zodResolver } from '@hookform/resolvers/zod';
159
- import * as z from 'zod';
160
-
161
- // i18n
162
- import { useTranslation } from 'react-i18next';
163
- ```
164
-
165
- > **Never import from `xertica-ui` root barrel in FSD/FDA projects.** Always use the granular subpaths above — they produce smaller bundles and prevent accidental cross-domain coupling.
166
-
167
- ---
168
-
169
- ## 3. Non-Negotiable Rules
170
-
171
- ### 3.1 No Raw HTML for UI Surfaces
172
-
173
- | ❌ Never | ✅ Always |
174
- |---|---|
175
- | `<button>` | `<Button>` from `xertica-ui/ui` |
176
- | `<input>` | `<Input>` from `xertica-ui/ui` |
177
- | `<select>` | `<Select>` from `xertica-ui/ui` |
178
- | `<textarea>` | `<Textarea>` from `xertica-ui/ui` |
179
- | `<div class="card ...">` | `<Card>` from `xertica-ui/ui` |
180
- | Custom scrollable `<div>` | `<ScrollArea>` from `xertica-ui/ui` |
181
- | Raw `<progress>` | `<Progress>` from `xertica-ui/ui` |
182
- | Inline SVG `<svg><path .../></svg>` | `import { IconName } from 'lucide-react'` |
183
-
184
- ### 3.2 Color Rules
185
-
186
- **Always forbidden:**
187
- ```tsx
188
- // ❌ Never — raw values are non-themeable
189
- style={{ backgroundColor: '#3B82F6' }}
190
- style={{ color: 'rgb(59,130,246)' }}
191
- className="text-[#ffffff]"
192
- ```
193
-
194
- **Required for semantic/status contexts** (errors, warnings, success, danger actions, status badges):
195
- ```tsx
196
- // ❌ Wrong — Tailwind color for semantic state
197
- <div className="bg-red-500">Error</div>
198
-
199
- // ✅ Required — token adapts to theme and dark mode
200
- <div className="bg-destructive text-destructive-foreground">Error</div>
201
- ```
202
-
203
- **Acceptable for non-semantic layout** (spacing, decorative elements, charts):
204
- ```tsx
205
- // ✅ OK — non-semantic context, no theme dependency
206
- <div className="bg-blue-500/15 border-gray-200">Decorative</div>
207
- ```
208
-
209
- Semantic token reference:
210
- | Intent | Token class |
211
- |---|---|
212
- | Error / Danger | `bg-destructive` / `text-destructive` |
213
- | Warning | `bg-warning` / `text-warning` |
214
- | Success | `bg-success` / `text-success` |
215
- | Informational | `bg-info` / `text-info` |
216
- | Neutral/secondary | `bg-secondary` / `text-secondary-foreground` |
217
- | Primary action | `bg-primary` / `text-primary-foreground` |
218
- | Muted background | `bg-muted` / `text-muted-foreground` |
219
-
220
- ### 3.3 Border Radius — Never Hardcode
221
-
222
- ```tsx
223
- // ❌ Wrong
224
- className="rounded-lg"
225
- className="rounded-xl"
226
-
227
- // ✅ Correct — inherits the project's configured radius token
228
- className="rounded-[var(--radius)]"
229
- ```
230
-
231
- ### 3.4 Layout State — Never Hardcode
232
-
233
- ```tsx
234
- // ❌ Wrong — breaks when sidebar width changes
235
- <div style={{ paddingLeft: '280px' }}>
236
-
237
- // ✅ Correct — always from context
238
- const { sidebarExpanded, sidebarWidth } = useLayout();
239
- <div style={{ paddingLeft: sidebarExpanded ? `${sidebarWidth}px` : '80px' }}>
240
- ```
241
-
242
- `80px` is the fixed collapsed sidebar width. The expanded value (`sidebarWidth`) defaults to `280px` but is configurable. Never hardcode either value.
243
-
244
- ### 3.5 Destructive Actions — Always Confirm with AlertDialog
245
-
246
- ```tsx
247
- <AlertDialog>
248
- <AlertDialogTrigger asChild>
249
- <Button variant="destructive">Delete Record</Button>
250
- </AlertDialogTrigger>
251
- <AlertDialogContent>
252
- <AlertDialogHeader>
253
- <AlertDialogTitle>Are you sure?</AlertDialogTitle>
254
- <AlertDialogDescription>This action cannot be undone.</AlertDialogDescription>
255
- </AlertDialogHeader>
256
- <AlertDialogFooter>
257
- <AlertDialogCancel>Cancel</AlertDialogCancel>
258
- <AlertDialogAction onClick={handleDelete}>Delete</AlertDialogAction>
259
- </AlertDialogFooter>
260
- </AlertDialogContent>
261
- </AlertDialog>
262
- ```
263
-
264
- ### 3.6 Toast Notifications
265
-
266
- Use `toast` from `sonner` for ephemeral action feedback. Never render `<Toaster>` manually — it is auto-injected by `<XerticaProvider>`.
267
-
268
- ```tsx
269
- import { toast } from 'sonner';
270
-
271
- toast.success(t('users.createSuccess'));
272
- toast.error(t('errors.somethingWentWrong'));
273
- toast.info(t('feature.inDevelopment'));
274
- toast.warning(t('billing.syncConflict'));
275
- ```
276
-
277
- ### 3.7 Form Validation — react-hook-form + zod
278
-
279
- Never implement manual validation with `useState` + conditional checks:
280
-
281
- ```tsx
282
- // ❌ Wrong — manual validation
283
- const [error, setError] = useState('');
284
- if (!email.includes('@')) setError('Invalid email');
285
-
286
- // ✅ Correct — declarative schema, errors flow automatically
287
- const schema = z.object({
288
- email: z.string().email('Invalid email address'),
289
- name: z.string().min(2, 'Name must be at least 2 characters'),
290
- });
291
-
292
- const form = useForm({ resolver: zodResolver(schema) });
293
- // Error messages render automatically via <FormMessage />
294
- ```
295
-
296
- ### 3.8 Mock Data Belongs in `data/mock.ts`
297
-
298
- Never hardcode data arrays inside component files:
299
-
300
- ```tsx
301
- // ❌ Wrong — data inside the component
302
- const users = [{ id: 1, name: 'Alice' }, ...];
303
-
304
- // ✅ Correct — data in features/<domain>/data/mock.ts
305
- export async function fetchUsers(): Promise<User[]> {
306
- await new Promise(r => setTimeout(r, 300)); // simulate network
307
- return MOCK_USERS;
308
- }
309
- ```
310
-
311
- ---
312
-
313
- ## 4. Page Structure — Standard Shell
314
-
315
- Every content component follows this exact shell. No exceptions:
316
-
317
- ```tsx
318
- import { Link } from 'react-router-dom';
319
- import { Header } from 'xertica-ui/layout';
320
- import { ScrollArea } from 'xertica-ui/ui';
321
- import { useLayout } from 'xertica-ui/hooks';
322
- import { useTranslation } from 'react-i18next';
323
-
324
- export function ExampleContent() {
325
- const { t } = useTranslation();
326
- const { sidebarExpanded, sidebarWidth } = useLayout();
327
-
328
- return (
329
- <div
330
- style={{ paddingLeft: sidebarExpanded ? `${sidebarWidth}px` : '80px' }}
331
- className="flex-1 flex flex-col overflow-hidden transition-all duration-300"
332
- >
333
- {/* Header with breadcrumbs + theme/language controls */}
334
- <Header
335
- showThemeToggle
336
- showLanguageSelector
337
- breadcrumbs={[
338
- { label: t('nav.home', 'App'), href: '/home' },
339
- { label: t('nav.thisPage', 'This Page') },
340
- ]}
341
- renderLink={(href, props) => <Link to={href} {...props} />}
342
- />
343
-
344
- {/* Scrollable main content */}
345
- <main className="flex-1 overflow-hidden bg-muted">
346
- <ScrollArea className="h-full">
347
- <div className="p-4 md:p-6">
348
- <div className="max-w-7xl mx-auto space-y-6">
349
- {/* 1. KPI StatsCards row (if applicable) */}
350
- {/* 2. Main content cards */}
351
- {/* 3. Tables with filters */}
352
- </div>
353
- </div>
354
- </ScrollArea>
355
- </main>
356
-
357
- {/* Dialogs / Sheets rendered OUTSIDE <main> */}
358
- </div>
359
- );
360
- }
361
- ```
362
-
363
- ### Pages Are Thin Wrappers
364
-
365
- ```tsx
366
- // pages/ExamplePage.tsx — thin wrapper only, no logic
367
- export function ExamplePage() {
368
- return (
369
- <AppLayout>
370
- <ExampleContent />
371
- </AppLayout>
372
- );
373
- }
374
- ```
375
-
376
- ---
377
-
378
- ## 5. Adding a New Route (Step-by-Step)
379
-
380
- 1. **Create feature content**: `src/features/<name>/ui/<NameContent>.tsx`
381
- 2. **Export from the barrel**: `src/features/<name>/index.ts`
382
- 3. **Create the page**: `src/pages/<NamePage>.tsx` (thin AppLayout wrapper)
383
- 4. **Register the route** in `src/shared/config/navigation.ts`:
384
- ```ts
385
- import { IconName } from 'lucide-react';
386
-
387
- { path: '/route', label: 'Label', labelKey: 'nav.keyName',
388
- icon: IconName, allowedRoles: ['admin', 'parceira'], group: 'groupName' }
389
- ```
390
- 5. **Register the `<Route>`** in `src/app/components/AuthGuard.tsx`:
391
- ```tsx
392
- <Route path="/route" element={
393
- <RoleRoute allowedRoles={['admin', 'parceira']}>
394
- <NamePage />
395
- </RoleRoute>
396
- } />
397
- ```
398
- 6. **Add the i18n key** to `src/locales/<lang>/nav.json` for every configured language
399
- 7. **Add a navigation card** to `HomeContent.tsx` if this is a primary module
400
-
401
- ---
402
-
403
- ## 6. Authentication Pattern
404
-
405
- Auth state lives in `src/app/context/AuthContext.tsx` via `useAuth()`:
406
-
407
- ```tsx
408
- const { user, isLoading, login, logout } = useAuth();
409
-
410
- // isLoading: true while localStorage is being read — ALWAYS check before redirecting
411
- // user: null when not authenticated; User object when authenticated
412
- // login(email, password): returns boolean — true on success
413
- // logout(): clears storage, navigates to /login
414
- ```
415
-
416
- ### Route Guards
417
-
418
- Three guard components are defined in `AuthGuard.tsx`:
419
-
420
- | Guard | Behavior |
421
- |---|---|
422
- | `<GuestRoute>` | Auth pages only. Redirects authenticated users to `getRoleHome(role)` |
423
- | `<ProtectedRoute>` | Any authenticated user. Redirects unauthenticated to `/login` |
424
- | `<RoleRoute allowedRoles={[]}>` | Role-specific. Unauthorized roles redirect to `getRoleHome(role)` — never to `/login` |
425
-
426
- ```tsx
427
- // getRoleHome(role) — determines post-login landing per role
428
- // Default pattern: most roles → '/home', restricted roles → their designated page
429
- ```
430
-
431
- ### MOCK_USERS in AuthContext
432
-
433
- For prototypes, credentials are stored in `MOCK_USERS` in `AuthContext.tsx`. Each entry maps email → `{ password, name, role, avatar?, clienteId? }`. The `clienteId` field is used for data isolation (e.g., a client user who can only see their own records).
434
-
435
- ---
436
-
437
- ## 7. Navigation and Sidebar Configuration
438
-
439
- ### `RouteConfig` Shape (`src/shared/config/navigation.ts`)
440
-
441
- ```ts
442
- export interface RouteConfig {
443
- path: string;
444
- label: string; // Fallback display label
445
- labelKey: string; // i18n key: 'nav.myRoute'
446
- icon: ComponentType<any>; // lucide-react icon
447
- allowedRoles: UserRole[];
448
- group?: string; // Groups routes visually in the sidebar
449
- }
450
- ```
451
-
452
- ### Filtering Routes by Role
453
-
454
- `AppLayout.tsx` uses `getRoutesByRole(user.role)` to pass only accessible routes to `<Sidebar>`. Each route's `allowedRoles` controls visibility — it mirrors `<RoleRoute>` in `AuthGuard.tsx`.
455
-
456
- ### Dynamic Label Enrichment
457
-
458
- The sidebar `label` string can be enriched at runtime (e.g., adding a pending count badge). Do this in `AppLayout.tsx` via a `routes.map()` before passing to `<Sidebar>`:
459
-
460
- ```tsx
461
- const allowedRoutes = baseRoutes.map(route => {
462
- if (route.path === '/target' && count > 0) {
463
- return { ...route, label: `${route.label} (${count})` };
464
- }
465
- return route;
466
- });
467
- ```
468
-
469
- ---
470
-
471
- ## 8. State Management
472
-
473
- | Layer | Tool | Use for |
474
- |---|---|---|
475
- | Server state | React Query (`useQuery`) | Data from APIs / mock fetch functions |
476
- | Client UI state | Zustand | Filters, tabs, toggles shared across components |
477
- | Auth state | `AuthContext` / `useAuth()` | Current user, login, logout |
478
- | Layout state | `LayoutContext` / `useLayout()` | Sidebar width, assistant panel |
479
- | Local component state | `useState` | Dialogs open/closed, inline edits, ephemeral form state |
480
-
481
- ### React Query — Required Pattern
482
-
483
- ```ts
484
- // features/<domain>/hooks/use<Domain>.ts
485
- import { useQuery } from '@tanstack/react-query';
486
- import { useLanguage } from 'xertica-ui/hooks';
487
- import { fetchItems, type Item } from '../data/mock';
488
-
489
- export function useItems() {
490
- const { language } = useLanguage(); // include language when response has translated strings
491
- return useQuery<Item[]>({
492
- queryKey: ['items', language],
493
- queryFn: fetchItems,
494
- staleTime: 5 * 60 * 1000, // set appropriate staleTime — never leave at default 0
495
- });
496
- }
497
- ```
498
-
499
- ### Zustand — Required Pattern
500
-
501
- ```ts
502
- // features/<domain>/store/<domain>Store.ts
503
- import { create } from 'zustand';
504
-
505
- interface MyStore {
506
- activeTab: string;
507
- setActiveTab: (tab: string) => void;
508
- }
509
-
510
- export const useMyStore = create<MyStore>(set => ({
511
- activeTab: 'overview',
512
- setActiveTab: tab => set({ activeTab: tab }),
513
- }));
514
-
515
- // In component — always subscribe with a selector to avoid unnecessary re-renders:
516
- const activeTab = useMyStore(s => s.activeTab); // ✅ selector
517
- const store = useMyStore(); // ❌ subscribes to everything
518
- ```
519
-
520
- ### Swap Pattern — Replacing Mock with Real API
521
-
522
- Replace only the fetch function body in `data/mock.ts`. The hook, component, and type contract are unchanged:
523
-
524
- ```ts
525
- // Before (mock)
526
- export async function fetchItems(): Promise<Item[]> {
527
- await new Promise(r => setTimeout(r, 300));
528
- return MOCK_ITEMS;
529
- }
530
-
531
- // After (real API)
532
- export async function fetchItems(): Promise<Item[]> {
533
- const res = await fetch('/api/items', {
534
- headers: { 'Accept-Language': i18n.language },
535
- });
536
- if (!res.ok) throw new Error('Failed to fetch');
537
- return res.json();
538
- }
539
- ```
540
-
541
- ---
542
-
543
- ## 9. Loading States — Skeletons
544
-
545
- Always render a skeleton — never a spinner alone — for data-bearing surfaces. Spinners are acceptable only for inline actions (button submitting, "saving…"):
546
-
547
- ```tsx
548
- // Cards grid
549
- {isLoading
550
- ? Array.from({ length: 6 }).map((_, i) => <FeatureCardSkeleton key={i} showAction />)
551
- : items.map(item => <FeatureCard key={item.id} {...item} />)
552
- }
553
-
554
- // Tables
555
- {isLoading
556
- ? Array.from({ length: 5 }).map((_, i) => (
557
- <TableRow key={i}>
558
- <TableCell><Skeleton className="h-3.5 w-28" /></TableCell>
559
- <TableCell><Skeleton className="h-5 w-20 rounded-full" /></TableCell>
560
- <TableCell><Skeleton className="h-3.5 w-16" /></TableCell>
561
- </TableRow>
562
- ))
563
- : rows.map(row => <TableRow key={row.id}>{/* cells */}</TableRow>)
564
- }
565
-
566
- // StatsCards row
567
- {isLoading
568
- ? Array.from({ length: 4 }).map((_, i) => <StatsCardSkeleton key={i} />)
569
- : stats.map(s => <StatsCard key={s.id} {...s} />)
570
- }
571
- ```
572
-
573
- Skeleton companions available: `FeatureCardSkeleton`, `QuickActionCardSkeleton`, `ProjectCardSkeleton`, `ActivityCardSkeleton`, `NotificationCardSkeleton`, `ProfileCardSkeleton`, `StatsCardSkeleton`.
574
-
575
- ---
576
-
577
- ## 10. Internationalization
578
-
579
- ### Setup (CLI-generated — do not hand-edit)
580
-
581
- `src/i18n.ts` uses `import.meta.glob` to auto-discover all JSON files under `src/locales/<lang>/`. Adding a new JSON file requires no changes to `i18n.ts`.
582
-
583
- ### Using Translations in Components
584
-
585
- ```tsx
586
- import { useTranslation } from 'react-i18next';
587
-
588
- function MyComponent() {
589
- const { t } = useTranslation();
590
- return (
591
- <div>
592
- <h1>{t('home.welcome')}</h1>
593
- <Button>{t('common.save')}</Button>
594
- </div>
595
- );
596
- }
597
- ```
598
-
599
- Applies to **all** user-facing strings: labels, placeholders, `aria-label`, toast messages, error text, dropdown items, tooltips.
600
-
601
- ### Using Translations Outside Components
602
-
603
- In `data/mock.ts` and utility files, use the `i18n` instance directly (not the hook):
604
-
605
- ```ts
606
- import i18n from '../../../i18n';
607
-
608
- export async function fetchFeatureCards() {
609
- return [{ title: i18n.t('home.cardsTitle') }]; // evaluated at query time
610
- }
611
- ```
612
-
613
- ### Frozen Constants vs Factory Functions
614
-
615
- ```ts
616
- // ❌ Wrong — frozen at module load time in the initial language
617
- export const OPTIONS = [i18n.t('option.first'), i18n.t('option.second')];
618
-
619
- // ✅ Correct — re-evaluated on every call, always returns current language
620
- export function getOptions() {
621
- return [i18n.t('option.first'), i18n.t('option.second')];
622
- }
623
- ```
624
-
625
- ### Language-Aware queryKey (Mandatory)
626
-
627
- Every React Query hook whose response contains translated strings must include `language` in its `queryKey`:
628
-
629
- ```ts
630
- const { language } = useLanguage();
631
- return useQuery({ queryKey: ['items', language], queryFn: fetchItems });
632
- ```
633
-
634
- ### Monolingual Projects
635
-
636
- When only one language is configured, `<LanguageSelector>` auto-hides. To force it visible: `<LanguageSelector showWhenMonolingual />`.
637
-
638
- ### Adding / Removing Languages
639
-
640
- ```bash
641
- npx xertica-ui update
642
- # → select "Languages"
643
- ```
644
-
645
- ---
646
-
647
- ## 11. Component Selection Guide
648
-
649
- For a full decision tree see `node_modules/xertica-ui/docs/decision-tree.md`. Key shortcuts:
650
-
651
- | Scenario | Component |
652
- |---|---|
653
- | "Are you sure you want to delete?" (blocking) | `AlertDialog` |
654
- | Compact form or detail view in overlay | `Dialog` |
655
- | Wide edit form or detail panel | `Sheet` |
656
- | Action feedback (auto-dismisses) | `toast.success/error/info/warning()` |
657
- | Persistent inline warning / status banner | `Alert variant="warning"` |
658
- | KPI number cards | `StatsCard` |
659
- | Feature/module navigation cards | `FeatureCard` |
660
- | Project status with progress bar | `ProjectCard` |
661
- | Chronological event list | `ActivityCard` |
662
- | Icon button label (hover) | `Tooltip` |
663
- | User profile preview (hover) | `HoverCard` |
664
- | Date picker | `Calendar` inside `Popover` |
665
- | Filter panel (click-triggered) | `Popover` |
666
- | Page sections (horizontal switch) | `Tabs` |
667
- | Expandable single section | `Collapsible` |
668
- | Settings with multiple expandable groups | `Accordion` |
669
- | Rich text editing | `RichTextEditor` |
670
- | OTP / 2FA code input | `InputOTP` |
671
- | Step-by-step flow | `Stepper` |
672
- | Known % completion progress | `Progress` |
673
- | Unknown completion (page/card loading) | `Skeleton` |
674
- | Tabular records | `Table` + `Pagination` |
675
-
676
- ---
677
-
678
- ## 12. Page Patterns (from `docs/patterns/`)
679
-
680
- ### Dashboard Pattern
681
-
682
- ```tsx
683
- <div className="flex flex-col gap-6 p-6 max-w-[1400px] mx-auto">
684
- {/* 1 — Page title + CTA */}
685
- <div className="flex items-center justify-between">
686
- <h1 className="text-2xl font-bold tracking-tight">Dashboard</h1>
687
- <Button>Download Report</Button>
688
- </div>
689
-
690
- {/* 2 — KPI Stats Row */}
691
- <div className="grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-4">
692
- <StatsCard title="Revenue" value="$45,231" icon={<DollarSign className="size-4" />} />
693
- {/* ... */}
694
- </div>
695
-
696
- {/* 3 — Chart + Feed in 7-column grid */}
697
- <div className="grid gap-4 grid-cols-1 lg:grid-cols-7">
698
- <Card className="col-span-1 lg:col-span-4"> {/* Chart */} </Card>
699
- <Card className="col-span-1 lg:col-span-3"> {/* Activity feed */} </Card>
700
- </div>
701
- </div>
702
- ```
703
-
704
- ### Form Pattern (react-hook-form + zod)
705
-
706
- ```tsx
707
- const schema = z.object({
708
- name: z.string().min(2),
709
- email: z.string().email(),
710
- role: z.enum(['admin', 'user']),
711
- });
712
-
713
- function MyForm() {
714
- const form = useForm({ resolver: zodResolver(schema) });
715
-
716
- return (
717
- <Form {...form}>
718
- <form onSubmit={form.handleSubmit(onSubmit)}>
719
- <FormField control={form.control} name="name" render={({ field }) => (
720
- <FormItem>
721
- <FormLabel>Name</FormLabel>
722
- <FormControl><Input {...field} /></FormControl>
723
- <FormMessage />
724
- </FormItem>
725
- )} />
726
- <Button type="submit">Save</Button>
727
- </form>
728
- </Form>
729
- );
730
- }
731
- ```
732
-
733
- ### CRUD Table Pattern
734
-
735
- ```tsx
736
- <Card>
737
- <CardHeader className="flex flex-row items-center justify-between">
738
- <CardTitle>Records</CardTitle>
739
- <Button size="sm"><Plus className="size-4 mr-2" />New Record</Button>
740
- </CardHeader>
741
- <CardContent>
742
- {/* Search + Filters */}
743
- <div className="flex gap-2 mb-4">
744
- <Input placeholder="Search..." className="max-w-sm" />
745
- <Select><SelectTrigger><SelectValue placeholder="Status" /></SelectTrigger>...</Select>
746
- </div>
747
- {/* Table */}
748
- <Table>
749
- <TableHeader>
750
- <TableRow>
751
- <TableHead>Name</TableHead>
752
- <TableHead>Status</TableHead>
753
- <TableHead className="text-right">Actions</TableHead>
754
- </TableRow>
755
- </TableHeader>
756
- <TableBody>
757
- {isLoading
758
- ? Array.from({ length: 5 }).map((_, i) => (
759
- <TableRow key={i}>
760
- <TableCell><Skeleton className="h-4 w-32" /></TableCell>
761
- <TableCell><Skeleton className="h-5 w-16 rounded-full" /></TableCell>
762
- <TableCell className="text-right"><Skeleton className="h-8 w-8 ml-auto" /></TableCell>
763
- </TableRow>
764
- ))
765
- : rows.map(row => <TableRow key={row.id}>{/* ... */}</TableRow>)
766
- }
767
- </TableBody>
768
- </Table>
769
- </CardContent>
770
- </Card>
771
- ```
772
-
773
- ---
774
-
775
- ## 13. Error Boundaries
776
-
777
- Three pre-configured wrappers for granular error isolation:
778
-
779
- ```tsx
780
- import { AppErrorBoundary, PageErrorBoundary, SectionErrorBoundary }
781
- from '../shared/error-boundary';
782
-
783
- // App.tsx — wraps the entire application
784
- <AppErrorBoundary>
785
- <QueryClientProvider>
786
- <XerticaProvider>
787
- <Router>
788
- <AuthProvider>
789
- <PageErrorBoundary> {/* wraps the route tree */}
790
- <Suspense fallback={null}>
791
- <AuthGuard />
792
- </Suspense>
793
- </PageErrorBoundary>
794
- </AuthProvider>
795
- </Router>
796
- </XerticaProvider>
797
- </QueryClientProvider>
798
- </AppErrorBoundary>
799
-
800
- // Inside pages — wraps data-dependent sections
801
- <SectionErrorBoundary>
802
- <MyDataDrivenComponent />
803
- </SectionErrorBoundary>
804
- ```
805
-
806
- ---
807
-
808
- ## 14. Theme and Token Customization
809
-
810
- Edit only `src/styles/xertica/tokens.css` — never modify anything in `node_modules/xertica-ui/styles/`.
811
-
812
- To switch themes via CLI:
813
- ```bash
814
- npx xertica-ui update
815
- # → select "Theme only"
816
- ```
817
-
818
- The token file uses HSL values and supports both light and dark modes via the `.dark` class on `<html>`. CSS variable names follow the shadcn convention: `--background`, `--foreground`, `--primary`, `--destructive`, etc.
819
-
820
- ---
821
-
822
- ## 15. AI Agent Reference
823
-
824
- | What you need | Where to read |
825
- |---|---|
826
- | Complete component catalog | `node_modules/xertica-ui/llms-compact.txt` |
827
- | Full component API with all props | `node_modules/xertica-ui/llms-full.txt` |
828
- | "Dialog or Sheet? Tooltip or Popover?" | `node_modules/xertica-ui/docs/decision-tree.md` |
829
- | Specific component props | `node_modules/xertica-ui/docs/components/<name>.md` |
830
- | Mandatory constraint list for AI | `node_modules/xertica-ui/docs/ai-usage.md` |
831
- | i18n setup and language switching | `node_modules/xertica-ui/docs/i18n.md` |
832
- | State management patterns | `node_modules/xertica-ui/docs/state-management.md` |
833
- | Layout system (sidebar width, assistant) | `node_modules/xertica-ui/docs/layout.md` |
834
- | Page-level composition patterns | `node_modules/xertica-ui/docs/patterns/*.md` |
835
- | This project's architecture rules | `guidelines/Guidelines.md` (you are here) |
836
-
837
- ---
838
-
839
- ## 16. Development Checklist
840
-
841
- Before completing any feature:
842
-
843
- - [ ] Feature content is in `src/features/<name>/ui/`
844
- - [ ] Feature barrel at `src/features/<name>/index.ts` exports everything
845
- - [ ] Page is a thin wrapper in `src/pages/` — no logic, no state
846
- - [ ] Route registered in `src/shared/config/navigation.ts` with `label`, `labelKey`, `icon`, `allowedRoles`, `group`
847
- - [ ] Route registered in `src/app/components/AuthGuard.tsx` with correct guard (`ProtectedRoute` or `RoleRoute`)
848
- - [ ] i18n key added to `src/locales/<lang>/nav.json` for **all** configured languages
849
- - [ ] Navigation card added to `HomeContent.tsx` if this is a primary module
850
- - [ ] All data arrays live in `features/<name>/data/mock.ts`, not in components
851
- - [ ] Server state fetched via React Query hook — not `useState` + `useEffect`
852
- - [ ] React Query `queryKey` includes `language` when response contains translated strings
853
- - [ ] `staleTime` is set on every `useQuery` call — never left at default `0`
854
- - [ ] Client UI state (filters, tabs) uses Zustand with selectors — not prop drilling
855
- - [ ] Only `xertica-ui` components used — no raw HTML elements
856
- - [ ] No raw hex/rgb/hsl values in `className` or `style` — semantic tokens for status contexts
857
- - [ ] No hardcoded border radii — `rounded-[var(--radius)]`
858
- - [ ] Icons from `lucide-react` only — no inline SVG
859
- - [ ] Layout state from `useLayout()` — no hardcoded `padding-left` or sidebar widths
860
- - [ ] Destructive actions wrapped in `<AlertDialog>` with explicit confirm/cancel
861
- - [ ] Forms use `react-hook-form` + `zod` — no manual `useState` + if-validation
862
- - [ ] Loading states render a `*Skeleton` component, not a blank space or spinner alone
863
- - [ ] All user-facing strings go through `useTranslation()` — no hardcoded UI text
864
- - [ ] `toast` used for action feedback — message goes through `t()`
865
- - [ ] Responsive: tested on mobile (< 640px), tablet (640–1024px), desktop (> 1024px)
1
+ # Project Guidelines — Xertica UI App
2
+
3
+ > **Scope**: These guidelines apply to any React application scaffolded with `npx xertica-ui@latest init`. They define architecture, import conventions, component rules, state management, and AI agent behavior.
4
+ >
5
+ > **AI agents — reading order**:
6
+ > 1. This file (architecture + rules)
7
+ > 2. `node_modules/xertica-ui/llms-compact.txt` (component catalog + quick reference)
8
+ > 3. `node_modules/xertica-ui/docs/decision-tree.md` (when choosing between similar components)
9
+ > 4. `node_modules/xertica-ui/docs/components/<name>.md` (when you need a specific component's full props)
10
+ > 5. `node_modules/xertica-ui/docs/ai-usage.md` (mandatory constraint list)
11
+
12
+ ---
13
+
14
+ ## 1. Architecture — Feature-Sliced Design + Feature-Driven Architecture
15
+
16
+ This project follows **FSD (Feature-Sliced Design)** layered architecture combined with **FDA (Feature-Driven Architecture)** vertical slicing. **Layers can only import from layers below them.**
17
+
18
+ ```
19
+ src/
20
+ ├── app/ # Layer 1 — Application shell (imports from all layers)
21
+ │ ├── App.tsx # XerticaProvider + BrowserRouter + AuthGuard (CLI-generated)
22
+ │ ├── context/
23
+ │ │ └── AuthContext.tsx # AuthProvider + useAuth() hook
24
+ │ └── components/
25
+ │ ├── AppLayout.tsx # Sidebar + children + optional XerticaAssistant
26
+ │ └── AuthGuard.tsx # All route definitions + route guard components
27
+
28
+ ├── shared/ # Layer 2 — Shared utilities (no business logic)
29
+ │ ├── config/
30
+ │ │ └── navigation.ts # RouteConfig type, routes[], getRoutesByRole()
31
+ │ ├── mock/ # Domain mock data (TypeScript static arrays + helpers)
32
+ │ ├── lib/
33
+ │ │ └── auth.ts # getStoredUser, storeUser, clearStoredUser
34
+ │ └── types/
35
+ │ └── auth.ts # User interface + UserRole type
36
+
37
+ ├── features/ # Layer 3 — Vertical slices by business capability
38
+ │ ├── auth/ # Login, ForgotPassword, VerifyEmail, ResetPassword
39
+ │ ├── home/ # Post-login hub (FeatureCards grid)
40
+ │ │ ├── data/mock.ts # Types + async fetch + factory functions (getMockXxx)
41
+ │ │ ├── hooks/useFeatureCards.ts # React Query, queryKey includes `language`
42
+ │ │ ├── store/dashboardStore.ts # Zustand UI state (no server data)
43
+ │ │ ├── ui/HomeContent.tsx
44
+ │ │ └── index.ts
45
+ │ ├── assistant/ # XerticaAssistant — AppLayout depends on it
46
+ │ │ ├── data/mock.ts
47
+ │ │ ├── hooks/useAssistantConfig.ts
48
+ │ │ └── index.ts
49
+ │ └── <domain>/ # One slice per business domain
50
+ │ ├── data/mock.ts # Domain types + mock fetch functions
51
+ │ ├── hooks/use<Domain>.ts # React Query wrapper
52
+ │ ├── store/<domain>Store.ts # Zustand UI state (optional)
53
+ │ ├── ui/<Domain>Content.tsx # Page content component
54
+ │ └── index.ts # Barrel — ONLY public interface for this feature
55
+
56
+ ├── pages/ # Layer 4 — Thin route wrappers only
57
+ │ └── <Name>Page.tsx # AppLayout + <NameContent> + optional XerticaAssistant
58
+
59
+ ├── i18n.ts # i18next setup (CLI-generated — do not hand-edit)
60
+ ├── locales/
61
+ │ ├── .languages.json # CLI-managed language selection
62
+ │ └── pt-BR/ # One folder per language
63
+ │ ├── common.json # Shared action labels
64
+ │ ├── nav.json # Navigation labels
65
+ │ ├── errors.json # Error boundary UI
66
+ │ ├── pages/ # Per-page namespaces
67
+ │ └── components/ # Per-component namespaces
68
+ └── styles/
69
+ ├── index.css # Imports: xertica-ui/style.css, tokens.css, @source
70
+ └── xertica/tokens.css # Brand CSS variables — customize here only
71
+ ```
72
+
73
+ ### Layer Import Rules
74
+
75
+ - `app/` → can import from all layers
76
+ - `shared/` → cannot import from `features/` or `pages/`
77
+ - `features/<a>/` → cannot import from `features/<b>/` — extract shared code to `shared/`
78
+ - `pages/` → imports only from `features/` barrels and `app/`
79
+
80
+ ### Feature Barrel Rule
81
+
82
+ The `index.ts` is the **only** public interface of a feature. Always import from the barrel, never from internal paths:
83
+
84
+ ```tsx
85
+ // ✅ Correct
86
+ import { LoginContent } from '../features/auth';
87
+
88
+ // ❌ Wrong — never import from internal paths
89
+ import { LoginContent } from '../features/auth/ui/LoginContent';
90
+ ```
91
+
92
+ ---
93
+
94
+ ## 2. Import Rules
95
+
96
+ Always use the correct `xertica-ui` subpath for the domain you need:
97
+
98
+ ```tsx
99
+ // UI primitives — buttons, inputs, dialogs, tables, badges, etc.
100
+ import {
101
+ Button, Input, Textarea, Select, SelectContent, SelectItem, SelectTrigger, SelectValue,
102
+ Card, CardContent, CardHeader, CardTitle, CardDescription, CardFooter,
103
+ Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter,
104
+ AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader,
105
+ AlertDialogTitle, AlertDialogDescription, AlertDialogFooter,
106
+ AlertDialogCancel, AlertDialogAction,
107
+ Table, TableBody, TableCell, TableHead, TableHeader, TableRow,
108
+ Badge, Progress, ScrollArea, Separator, Skeleton, Label, Switch,
109
+ Tabs, TabsContent, TabsList, TabsTrigger,
110
+ Collapsible, CollapsibleContent, CollapsibleTrigger,
111
+ Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage,
112
+ Tooltip, TooltipContent, TooltipProvider, TooltipTrigger,
113
+ Popover, PopoverContent, PopoverTrigger,
114
+ Sheet, SheetContent, SheetHeader, SheetTitle, SheetDescription,
115
+ Alert, AlertDescription, Drawer,
116
+ } from 'xertica-ui/ui';
117
+
118
+ // Composed high-level block components
119
+ import {
120
+ FeatureCard, FeatureCardSkeleton,
121
+ QuickActionCard, QuickActionCardSkeleton,
122
+ ProjectCard, ProjectCardSkeleton,
123
+ ActivityCard, ActivityCardSkeleton,
124
+ NotificationCard, NotificationCardSkeleton,
125
+ ProfileCard, ProfileCardSkeleton,
126
+ StatsCard, StatsCardSkeleton,
127
+ } from 'xertica-ui/blocks';
128
+
129
+ // Application shell
130
+ import { Sidebar, Header } from 'xertica-ui/layout';
131
+
132
+ // Brand / providers
133
+ import { XerticaProvider, XerticaLogo, ThemeToggle, LanguageSelector } from 'xertica-ui/brand';
134
+
135
+ // AI assistant
136
+ import { XerticaAssistant, generateDemoResponse } from 'xertica-ui/assistant';
137
+
138
+ // Media players
139
+ import { VideoPlayer, AudioPlayer } from 'xertica-ui/media';
140
+
141
+ // Hooks
142
+ import { useLayout, useOptionalLayout, useTheme, useLanguage } from 'xertica-ui/hooks';
143
+
144
+ // Icons — ALWAYS from lucide-react, NEVER from xertica-ui or inline SVG
145
+ import { Home, Settings, Plus, Trash2, ChevronRight, Search } from 'lucide-react';
146
+
147
+ // Charts — use recharts (pre-installed)
148
+ import {
149
+ BarChart, Bar, LineChart, Line, PieChart, Pie, Cell,
150
+ XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer,
151
+ } from 'recharts';
152
+
153
+ // Toast
154
+ import { toast } from 'sonner';
155
+
156
+ // Form validation
157
+ import { useForm } from 'react-hook-form';
158
+ import { zodResolver } from '@hookform/resolvers/zod';
159
+ import * as z from 'zod';
160
+
161
+ // i18n
162
+ import { useTranslation } from 'react-i18next';
163
+ ```
164
+
165
+ > **Never import from `xertica-ui` root barrel in FSD/FDA projects.** Always use the granular subpaths above — they produce smaller bundles and prevent accidental cross-domain coupling.
166
+
167
+ ---
168
+
169
+ ## 3. Non-Negotiable Rules
170
+
171
+ ### 3.1 No Raw HTML for UI Surfaces
172
+
173
+ | ❌ Never | ✅ Always |
174
+ |---|---|
175
+ | `<button>` | `<Button>` from `xertica-ui/ui` |
176
+ | `<input>` | `<Input>` from `xertica-ui/ui` |
177
+ | `<select>` | `<Select>` from `xertica-ui/ui` |
178
+ | `<textarea>` | `<Textarea>` from `xertica-ui/ui` |
179
+ | `<div class="card ...">` | `<Card>` from `xertica-ui/ui` |
180
+ | Custom scrollable `<div>` | `<ScrollArea>` from `xertica-ui/ui` |
181
+ | Raw `<progress>` | `<Progress>` from `xertica-ui/ui` |
182
+ | Inline SVG `<svg><path .../></svg>` | `import { IconName } from 'lucide-react'` |
183
+
184
+ ### 3.2 Color Rules
185
+
186
+ **Always forbidden:**
187
+ ```tsx
188
+ // ❌ Never — raw values are non-themeable
189
+ style={{ backgroundColor: '#3B82F6' }}
190
+ style={{ color: 'rgb(59,130,246)' }}
191
+ className="text-[#ffffff]"
192
+ ```
193
+
194
+ **Required for semantic/status contexts** (errors, warnings, success, danger actions, status badges):
195
+ ```tsx
196
+ // ❌ Wrong — Tailwind color for semantic state
197
+ <div className="bg-red-500">Error</div>
198
+
199
+ // ✅ Required — token adapts to theme and dark mode
200
+ <div className="bg-destructive text-destructive-foreground">Error</div>
201
+ ```
202
+
203
+ **Acceptable for non-semantic layout** (spacing, decorative elements, charts):
204
+ ```tsx
205
+ // ✅ OK — non-semantic context, no theme dependency
206
+ <div className="bg-blue-500/15 border-gray-200">Decorative</div>
207
+ ```
208
+
209
+ Semantic token reference:
210
+ | Intent | Token class |
211
+ |---|---|
212
+ | Error / Danger | `bg-destructive` / `text-destructive` |
213
+ | Warning | `bg-warning` / `text-warning` |
214
+ | Success | `bg-success` / `text-success` |
215
+ | Informational | `bg-info` / `text-info` |
216
+ | Neutral/secondary | `bg-secondary` / `text-secondary-foreground` |
217
+ | Primary action | `bg-primary` / `text-primary-foreground` |
218
+ | Muted background | `bg-muted` / `text-muted-foreground` |
219
+
220
+ ### 3.3 Border Radius — Never Hardcode
221
+
222
+ ```tsx
223
+ // ❌ Wrong
224
+ className="rounded-lg"
225
+ className="rounded-xl"
226
+
227
+ // ✅ Correct — inherits the project's configured radius token
228
+ className="rounded-[var(--radius)]"
229
+ ```
230
+
231
+ ### 3.4 Layout State — Never Hardcode
232
+
233
+ ```tsx
234
+ // ❌ Wrong — breaks when sidebar width changes
235
+ <div style={{ paddingLeft: '280px' }}>
236
+
237
+ // ✅ Correct — always from context
238
+ const { sidebarExpanded, sidebarWidth } = useLayout();
239
+ <div style={{ paddingLeft: sidebarExpanded ? `${sidebarWidth}px` : '80px' }}>
240
+ ```
241
+
242
+ `80px` is the fixed collapsed sidebar width. The expanded value (`sidebarWidth`) defaults to `280px` but is configurable. Never hardcode either value.
243
+
244
+ ### 3.5 Destructive Actions — Always Confirm with AlertDialog
245
+
246
+ ```tsx
247
+ <AlertDialog>
248
+ <AlertDialogTrigger asChild>
249
+ <Button variant="destructive">Delete Record</Button>
250
+ </AlertDialogTrigger>
251
+ <AlertDialogContent>
252
+ <AlertDialogHeader>
253
+ <AlertDialogTitle>Are you sure?</AlertDialogTitle>
254
+ <AlertDialogDescription>This action cannot be undone.</AlertDialogDescription>
255
+ </AlertDialogHeader>
256
+ <AlertDialogFooter>
257
+ <AlertDialogCancel>Cancel</AlertDialogCancel>
258
+ <AlertDialogAction onClick={handleDelete}>Delete</AlertDialogAction>
259
+ </AlertDialogFooter>
260
+ </AlertDialogContent>
261
+ </AlertDialog>
262
+ ```
263
+
264
+ ### 3.6 Toast Notifications
265
+
266
+ Use `toast` from `sonner` for ephemeral action feedback. Never render `<Toaster>` manually — it is auto-injected by `<XerticaProvider>`.
267
+
268
+ ```tsx
269
+ import { toast } from 'sonner';
270
+
271
+ toast.success(t('users.createSuccess'));
272
+ toast.error(t('errors.somethingWentWrong'));
273
+ toast.info(t('feature.inDevelopment'));
274
+ toast.warning(t('billing.syncConflict'));
275
+ ```
276
+
277
+ ### 3.7 Form Validation — react-hook-form + zod
278
+
279
+ Never implement manual validation with `useState` + conditional checks:
280
+
281
+ ```tsx
282
+ // ❌ Wrong — manual validation
283
+ const [error, setError] = useState('');
284
+ if (!email.includes('@')) setError('Invalid email');
285
+
286
+ // ✅ Correct — declarative schema, errors flow automatically
287
+ const schema = z.object({
288
+ email: z.string().email('Invalid email address'),
289
+ name: z.string().min(2, 'Name must be at least 2 characters'),
290
+ });
291
+
292
+ const form = useForm({ resolver: zodResolver(schema) });
293
+ // Error messages render automatically via <FormMessage />
294
+ ```
295
+
296
+ ### 3.8 Mock Data Belongs in `data/mock.ts`
297
+
298
+ Never hardcode data arrays inside component files:
299
+
300
+ ```tsx
301
+ // ❌ Wrong — data inside the component
302
+ const users = [{ id: 1, name: 'Alice' }, ...];
303
+
304
+ // ✅ Correct — data in features/<domain>/data/mock.ts
305
+ export async function fetchUsers(): Promise<User[]> {
306
+ await new Promise(r => setTimeout(r, 300)); // simulate network
307
+ return MOCK_USERS;
308
+ }
309
+ ```
310
+
311
+ ---
312
+
313
+ ## 4. Page Structure — Standard Shell
314
+
315
+ Every content component follows this exact shell. No exceptions:
316
+
317
+ ```tsx
318
+ import { Link } from 'react-router-dom';
319
+ import { Header } from 'xertica-ui/layout';
320
+ import { ScrollArea } from 'xertica-ui/ui';
321
+ import { useLayout } from 'xertica-ui/hooks';
322
+ import { useTranslation } from 'react-i18next';
323
+
324
+ export function ExampleContent() {
325
+ const { t } = useTranslation();
326
+ const { sidebarExpanded, sidebarWidth } = useLayout();
327
+
328
+ return (
329
+ <div
330
+ style={{ paddingLeft: sidebarExpanded ? `${sidebarWidth}px` : '80px' }}
331
+ className="flex-1 flex flex-col overflow-hidden transition-all duration-300"
332
+ >
333
+ {/* Header with breadcrumbs + theme/language controls */}
334
+ <Header
335
+ showThemeToggle
336
+ showLanguageSelector
337
+ breadcrumbs={[
338
+ { label: t('nav.home', 'App'), href: '/home' },
339
+ { label: t('nav.thisPage', 'This Page') },
340
+ ]}
341
+ renderLink={(href, props) => <Link to={href} {...props} />}
342
+ />
343
+
344
+ {/* Scrollable main content */}
345
+ <main className="flex-1 overflow-hidden bg-muted">
346
+ <ScrollArea className="h-full">
347
+ <div className="p-4 md:p-6">
348
+ <div className="max-w-7xl mx-auto space-y-6">
349
+ {/* 1. KPI StatsCards row (if applicable) */}
350
+ {/* 2. Main content cards */}
351
+ {/* 3. Tables with filters */}
352
+ </div>
353
+ </div>
354
+ </ScrollArea>
355
+ </main>
356
+
357
+ {/* Dialogs / Sheets rendered OUTSIDE <main> */}
358
+ </div>
359
+ );
360
+ }
361
+ ```
362
+
363
+ ### Pages Are Thin Wrappers
364
+
365
+ ```tsx
366
+ // pages/ExamplePage.tsx — thin wrapper only, no logic
367
+ export function ExamplePage() {
368
+ return (
369
+ <AppLayout>
370
+ <ExampleContent />
371
+ </AppLayout>
372
+ );
373
+ }
374
+ ```
375
+
376
+ ---
377
+
378
+ ## 5. Adding a New Route (Step-by-Step)
379
+
380
+ 1. **Create feature content**: `src/features/<name>/ui/<NameContent>.tsx`
381
+ 2. **Export from the barrel**: `src/features/<name>/index.ts`
382
+ 3. **Create the page**: `src/pages/<NamePage>.tsx` (thin AppLayout wrapper)
383
+ 4. **Register the route** in `src/shared/config/navigation.ts`:
384
+ ```ts
385
+ import { IconName } from 'lucide-react';
386
+
387
+ { path: '/route', label: 'Label', labelKey: 'nav.keyName',
388
+ icon: IconName, allowedRoles: ['admin', 'parceira'], group: 'groupName' }
389
+ ```
390
+ 5. **Register the `<Route>`** in `src/app/components/AuthGuard.tsx`:
391
+ ```tsx
392
+ <Route path="/route" element={
393
+ <RoleRoute allowedRoles={['admin', 'parceira']}>
394
+ <NamePage />
395
+ </RoleRoute>
396
+ } />
397
+ ```
398
+ 6. **Add the i18n key** to `src/locales/<lang>/nav.json` for every configured language
399
+ 7. **Add a navigation card** to `HomeContent.tsx` if this is a primary module
400
+
401
+ ---
402
+
403
+ ## 6. Authentication Pattern
404
+
405
+ Auth state lives in `src/app/context/AuthContext.tsx` via `useAuth()`:
406
+
407
+ ```tsx
408
+ const { user, isLoading, login, logout } = useAuth();
409
+
410
+ // isLoading: true while localStorage is being read — ALWAYS check before redirecting
411
+ // user: null when not authenticated; User object when authenticated
412
+ // login(email, password): returns boolean — true on success
413
+ // logout(): clears storage, navigates to /login
414
+ ```
415
+
416
+ ### Route Guards
417
+
418
+ Three guard components are defined in `AuthGuard.tsx`:
419
+
420
+ | Guard | Behavior |
421
+ |---|---|
422
+ | `<GuestRoute>` | Auth pages only. Redirects authenticated users to `getRoleHome(role)` |
423
+ | `<ProtectedRoute>` | Any authenticated user. Redirects unauthenticated to `/login` |
424
+ | `<RoleRoute allowedRoles={[]}>` | Role-specific. Unauthorized roles redirect to `getRoleHome(role)` — never to `/login` |
425
+
426
+ ```tsx
427
+ // getRoleHome(role) — determines post-login landing per role
428
+ // Default pattern: most roles → '/home', restricted roles → their designated page
429
+ ```
430
+
431
+ ### MOCK_USERS in AuthContext
432
+
433
+ For prototypes, credentials are stored in `MOCK_USERS` in `AuthContext.tsx`. Each entry maps email → `{ password, name, role, avatar?, clienteId? }`. The `clienteId` field is used for data isolation (e.g., a client user who can only see their own records).
434
+
435
+ ---
436
+
437
+ ## 7. Navigation and Sidebar Configuration
438
+
439
+ ### `RouteConfig` Shape (`src/shared/config/navigation.ts`)
440
+
441
+ ```ts
442
+ export interface RouteConfig {
443
+ path: string;
444
+ label: string; // Fallback display label
445
+ labelKey: string; // i18n key: 'nav.myRoute'
446
+ icon: ComponentType<any>; // lucide-react icon
447
+ allowedRoles: UserRole[];
448
+ group?: string; // Groups routes visually in the sidebar
449
+ }
450
+ ```
451
+
452
+ ### Filtering Routes by Role
453
+
454
+ `AppLayout.tsx` uses `getRoutesByRole(user.role)` to pass only accessible routes to `<Sidebar>`. Each route's `allowedRoles` controls visibility — it mirrors `<RoleRoute>` in `AuthGuard.tsx`.
455
+
456
+ ### Dynamic Label Enrichment
457
+
458
+ The sidebar `label` string can be enriched at runtime (e.g., adding a pending count badge). Do this in `AppLayout.tsx` via a `routes.map()` before passing to `<Sidebar>`:
459
+
460
+ ```tsx
461
+ const allowedRoutes = baseRoutes.map(route => {
462
+ if (route.path === '/target' && count > 0) {
463
+ return { ...route, label: `${route.label} (${count})` };
464
+ }
465
+ return route;
466
+ });
467
+ ```
468
+
469
+ ---
470
+
471
+ ## 8. State Management
472
+
473
+ | Layer | Tool | Use for |
474
+ |---|---|---|
475
+ | Server state | React Query (`useQuery`) | Data from APIs / mock fetch functions |
476
+ | Client UI state | Zustand | Filters, tabs, toggles shared across components |
477
+ | Auth state | `AuthContext` / `useAuth()` | Current user, login, logout |
478
+ | Layout state | `LayoutContext` / `useLayout()` | Sidebar width, assistant panel |
479
+ | Local component state | `useState` | Dialogs open/closed, inline edits, ephemeral form state |
480
+
481
+ ### React Query — Required Pattern
482
+
483
+ ```ts
484
+ // features/<domain>/hooks/use<Domain>.ts
485
+ import { useQuery } from '@tanstack/react-query';
486
+ import { useLanguage } from 'xertica-ui/hooks';
487
+ import { fetchItems, type Item } from '../data/mock';
488
+
489
+ export function useItems() {
490
+ const { language } = useLanguage(); // include language when response has translated strings
491
+ return useQuery<Item[]>({
492
+ queryKey: ['items', language],
493
+ queryFn: fetchItems,
494
+ staleTime: 5 * 60 * 1000, // set appropriate staleTime — never leave at default 0
495
+ });
496
+ }
497
+ ```
498
+
499
+ ### Zustand — Required Pattern
500
+
501
+ ```ts
502
+ // features/<domain>/store/<domain>Store.ts
503
+ import { create } from 'zustand';
504
+
505
+ interface MyStore {
506
+ activeTab: string;
507
+ setActiveTab: (tab: string) => void;
508
+ }
509
+
510
+ export const useMyStore = create<MyStore>(set => ({
511
+ activeTab: 'overview',
512
+ setActiveTab: tab => set({ activeTab: tab }),
513
+ }));
514
+
515
+ // In component — always subscribe with a selector to avoid unnecessary re-renders:
516
+ const activeTab = useMyStore(s => s.activeTab); // ✅ selector
517
+ const store = useMyStore(); // ❌ subscribes to everything
518
+ ```
519
+
520
+ ### Swap Pattern — Replacing Mock with Real API
521
+
522
+ Replace only the fetch function body in `data/mock.ts`. The hook, component, and type contract are unchanged:
523
+
524
+ ```ts
525
+ // Before (mock)
526
+ export async function fetchItems(): Promise<Item[]> {
527
+ await new Promise(r => setTimeout(r, 300));
528
+ return MOCK_ITEMS;
529
+ }
530
+
531
+ // After (real API)
532
+ export async function fetchItems(): Promise<Item[]> {
533
+ const res = await fetch('/api/items', {
534
+ headers: { 'Accept-Language': i18n.language },
535
+ });
536
+ if (!res.ok) throw new Error('Failed to fetch');
537
+ return res.json();
538
+ }
539
+ ```
540
+
541
+ ---
542
+
543
+ ## 9. Loading States — Skeletons
544
+
545
+ Always render a skeleton — never a spinner alone — for data-bearing surfaces. Spinners are acceptable only for inline actions (button submitting, "saving…"):
546
+
547
+ ```tsx
548
+ // Cards grid
549
+ {isLoading
550
+ ? Array.from({ length: 6 }).map((_, i) => <FeatureCardSkeleton key={i} showAction />)
551
+ : items.map(item => <FeatureCard key={item.id} {...item} />)
552
+ }
553
+
554
+ // Tables
555
+ {isLoading
556
+ ? Array.from({ length: 5 }).map((_, i) => (
557
+ <TableRow key={i}>
558
+ <TableCell><Skeleton className="h-3.5 w-28" /></TableCell>
559
+ <TableCell><Skeleton className="h-5 w-20 rounded-full" /></TableCell>
560
+ <TableCell><Skeleton className="h-3.5 w-16" /></TableCell>
561
+ </TableRow>
562
+ ))
563
+ : rows.map(row => <TableRow key={row.id}>{/* cells */}</TableRow>)
564
+ }
565
+
566
+ // StatsCards row
567
+ {isLoading
568
+ ? Array.from({ length: 4 }).map((_, i) => <StatsCardSkeleton key={i} />)
569
+ : stats.map(s => <StatsCard key={s.id} {...s} />)
570
+ }
571
+ ```
572
+
573
+ Skeleton companions available: `FeatureCardSkeleton`, `QuickActionCardSkeleton`, `ProjectCardSkeleton`, `ActivityCardSkeleton`, `NotificationCardSkeleton`, `ProfileCardSkeleton`, `StatsCardSkeleton`.
574
+
575
+ ---
576
+
577
+ ## 10. Internationalization
578
+
579
+ ### Setup (CLI-generated — do not hand-edit)
580
+
581
+ `src/i18n.ts` uses `import.meta.glob` to auto-discover all JSON files under `src/locales/<lang>/`. Adding a new JSON file requires no changes to `i18n.ts`.
582
+
583
+ ### Using Translations in Components
584
+
585
+ ```tsx
586
+ import { useTranslation } from 'react-i18next';
587
+
588
+ function MyComponent() {
589
+ const { t } = useTranslation();
590
+ return (
591
+ <div>
592
+ <h1>{t('home.welcome')}</h1>
593
+ <Button>{t('common.save')}</Button>
594
+ </div>
595
+ );
596
+ }
597
+ ```
598
+
599
+ Applies to **all** user-facing strings: labels, placeholders, `aria-label`, toast messages, error text, dropdown items, tooltips.
600
+
601
+ ### Using Translations Outside Components
602
+
603
+ In `data/mock.ts` and utility files, use the `i18n` instance directly (not the hook):
604
+
605
+ ```ts
606
+ import i18n from '../../../i18n';
607
+
608
+ export async function fetchFeatureCards() {
609
+ return [{ title: i18n.t('home.cardsTitle') }]; // evaluated at query time
610
+ }
611
+ ```
612
+
613
+ ### Frozen Constants vs Factory Functions
614
+
615
+ ```ts
616
+ // ❌ Wrong — frozen at module load time in the initial language
617
+ export const OPTIONS = [i18n.t('option.first'), i18n.t('option.second')];
618
+
619
+ // ✅ Correct — re-evaluated on every call, always returns current language
620
+ export function getOptions() {
621
+ return [i18n.t('option.first'), i18n.t('option.second')];
622
+ }
623
+ ```
624
+
625
+ ### Language-Aware queryKey (Mandatory)
626
+
627
+ Every React Query hook whose response contains translated strings must include `language` in its `queryKey`:
628
+
629
+ ```ts
630
+ const { language } = useLanguage();
631
+ return useQuery({ queryKey: ['items', language], queryFn: fetchItems });
632
+ ```
633
+
634
+ ### Monolingual Projects
635
+
636
+ When only one language is configured, `<LanguageSelector>` auto-hides. To force it visible: `<LanguageSelector showWhenMonolingual />`.
637
+
638
+ ### Adding / Removing Languages
639
+
640
+ ```bash
641
+ npx xertica-ui update
642
+ # → select "Languages"
643
+ ```
644
+
645
+ ---
646
+
647
+ ## 11. Component Selection Guide
648
+
649
+ For a full decision tree see `node_modules/xertica-ui/docs/decision-tree.md`. Key shortcuts:
650
+
651
+ | Scenario | Component |
652
+ |---|---|
653
+ | "Are you sure you want to delete?" (blocking) | `AlertDialog` |
654
+ | Compact form or detail view in overlay | `Dialog` |
655
+ | Wide edit form or detail panel | `Sheet` |
656
+ | Action feedback (auto-dismisses) | `toast.success/error/info/warning()` |
657
+ | Persistent inline warning / status banner | `Alert variant="warning"` |
658
+ | KPI number cards | `StatsCard` |
659
+ | Feature/module navigation cards | `FeatureCard` |
660
+ | Project status with progress bar | `ProjectCard` |
661
+ | Chronological event list | `ActivityCard` |
662
+ | Icon button label (hover) | `Tooltip` |
663
+ | User profile preview (hover) | `HoverCard` |
664
+ | Date picker | `Calendar` inside `Popover` |
665
+ | Filter panel (click-triggered) | `Popover` |
666
+ | Page sections (horizontal switch) | `Tabs` |
667
+ | Expandable single section | `Collapsible` |
668
+ | Settings with multiple expandable groups | `Accordion` |
669
+ | Rich text editing | `RichTextEditor` |
670
+ | OTP / 2FA code input | `InputOTP` |
671
+ | Step-by-step flow | `Stepper` |
672
+ | Known % completion progress | `Progress` |
673
+ | Unknown completion (page/card loading) | `Skeleton` |
674
+ | Tabular records | `Table` + `Pagination` |
675
+
676
+ ---
677
+
678
+ ## 12. Page Patterns (from `docs/patterns/`)
679
+
680
+ ### Dashboard Pattern
681
+
682
+ ```tsx
683
+ <div className="flex flex-col gap-6 p-6 max-w-[1400px] mx-auto">
684
+ {/* 1 — Page title + CTA */}
685
+ <div className="flex items-center justify-between">
686
+ <h1 className="text-2xl font-bold tracking-tight">Dashboard</h1>
687
+ <Button>Download Report</Button>
688
+ </div>
689
+
690
+ {/* 2 — KPI Stats Row */}
691
+ <div className="grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-4">
692
+ <StatsCard title="Revenue" value="$45,231" icon={<DollarSign className="size-4" />} />
693
+ {/* ... */}
694
+ </div>
695
+
696
+ {/* 3 — Chart + Feed in 7-column grid */}
697
+ <div className="grid gap-4 grid-cols-1 lg:grid-cols-7">
698
+ <Card className="col-span-1 lg:col-span-4"> {/* Chart */} </Card>
699
+ <Card className="col-span-1 lg:col-span-3"> {/* Activity feed */} </Card>
700
+ </div>
701
+ </div>
702
+ ```
703
+
704
+ ### Form Pattern (react-hook-form + zod)
705
+
706
+ ```tsx
707
+ const schema = z.object({
708
+ name: z.string().min(2),
709
+ email: z.string().email(),
710
+ role: z.enum(['admin', 'user']),
711
+ });
712
+
713
+ function MyForm() {
714
+ const form = useForm({ resolver: zodResolver(schema) });
715
+
716
+ return (
717
+ <Form {...form}>
718
+ <form onSubmit={form.handleSubmit(onSubmit)}>
719
+ <FormField control={form.control} name="name" render={({ field }) => (
720
+ <FormItem>
721
+ <FormLabel>Name</FormLabel>
722
+ <FormControl><Input {...field} /></FormControl>
723
+ <FormMessage />
724
+ </FormItem>
725
+ )} />
726
+ <Button type="submit">Save</Button>
727
+ </form>
728
+ </Form>
729
+ );
730
+ }
731
+ ```
732
+
733
+ ### CRUD Table Pattern
734
+
735
+ ```tsx
736
+ <Card>
737
+ <CardHeader className="flex flex-row items-center justify-between">
738
+ <CardTitle>Records</CardTitle>
739
+ <Button size="sm"><Plus className="size-4 mr-2" />New Record</Button>
740
+ </CardHeader>
741
+ <CardContent>
742
+ {/* Search + Filters */}
743
+ <div className="flex gap-2 mb-4">
744
+ <Input placeholder="Search..." className="max-w-sm" />
745
+ <Select><SelectTrigger><SelectValue placeholder="Status" /></SelectTrigger>...</Select>
746
+ </div>
747
+ {/* Table */}
748
+ <Table>
749
+ <TableHeader>
750
+ <TableRow>
751
+ <TableHead>Name</TableHead>
752
+ <TableHead>Status</TableHead>
753
+ <TableHead className="text-right">Actions</TableHead>
754
+ </TableRow>
755
+ </TableHeader>
756
+ <TableBody>
757
+ {isLoading
758
+ ? Array.from({ length: 5 }).map((_, i) => (
759
+ <TableRow key={i}>
760
+ <TableCell><Skeleton className="h-4 w-32" /></TableCell>
761
+ <TableCell><Skeleton className="h-5 w-16 rounded-full" /></TableCell>
762
+ <TableCell className="text-right"><Skeleton className="h-8 w-8 ml-auto" /></TableCell>
763
+ </TableRow>
764
+ ))
765
+ : rows.map(row => <TableRow key={row.id}>{/* ... */}</TableRow>)
766
+ }
767
+ </TableBody>
768
+ </Table>
769
+ </CardContent>
770
+ </Card>
771
+ ```
772
+
773
+ ---
774
+
775
+ ## 13. Error Boundaries
776
+
777
+ Three pre-configured wrappers for granular error isolation:
778
+
779
+ ```tsx
780
+ import { AppErrorBoundary, PageErrorBoundary, SectionErrorBoundary }
781
+ from '../shared/error-boundary';
782
+
783
+ // App.tsx — wraps the entire application
784
+ <AppErrorBoundary>
785
+ <QueryClientProvider>
786
+ <XerticaProvider>
787
+ <Router>
788
+ <AuthProvider>
789
+ <PageErrorBoundary> {/* wraps the route tree */}
790
+ <Suspense fallback={null}>
791
+ <AuthGuard />
792
+ </Suspense>
793
+ </PageErrorBoundary>
794
+ </AuthProvider>
795
+ </Router>
796
+ </XerticaProvider>
797
+ </QueryClientProvider>
798
+ </AppErrorBoundary>
799
+
800
+ // Inside pages — wraps data-dependent sections
801
+ <SectionErrorBoundary>
802
+ <MyDataDrivenComponent />
803
+ </SectionErrorBoundary>
804
+ ```
805
+
806
+ ---
807
+
808
+ ## 14. Theme and Token Customization
809
+
810
+ Edit only `src/styles/xertica/tokens.css` — never modify anything in `node_modules/xertica-ui/styles/`.
811
+
812
+ To switch themes via CLI:
813
+ ```bash
814
+ npx xertica-ui update
815
+ # → select "Theme only"
816
+ ```
817
+
818
+ The token file uses HSL values and supports both light and dark modes via the `.dark` class on `<html>`. CSS variable names follow the shadcn convention: `--background`, `--foreground`, `--primary`, `--destructive`, etc.
819
+
820
+ ---
821
+
822
+ ## 15. AI Agent Reference
823
+
824
+ | What you need | Where to read |
825
+ |---|---|
826
+ | Complete component catalog | `node_modules/xertica-ui/llms-compact.txt` |
827
+ | Full component API with all props | `node_modules/xertica-ui/llms-full.txt` |
828
+ | "Dialog or Sheet? Tooltip or Popover?" | `node_modules/xertica-ui/docs/decision-tree.md` |
829
+ | Specific component props | `node_modules/xertica-ui/docs/components/<name>.md` |
830
+ | Mandatory constraint list for AI | `node_modules/xertica-ui/docs/ai-usage.md` |
831
+ | i18n setup and language switching | `node_modules/xertica-ui/docs/i18n.md` |
832
+ | State management patterns | `node_modules/xertica-ui/docs/state-management.md` |
833
+ | Layout system (sidebar width, assistant) | `node_modules/xertica-ui/docs/layout.md` |
834
+ | Page-level composition patterns | `node_modules/xertica-ui/docs/patterns/*.md` |
835
+ | This project's architecture rules | `guidelines/Guidelines.md` (you are here) |
836
+
837
+ ---
838
+
839
+ ## 16. Development Checklist
840
+
841
+ Before completing any feature:
842
+
843
+ - [ ] Feature content is in `src/features/<name>/ui/`
844
+ - [ ] Feature barrel at `src/features/<name>/index.ts` exports everything
845
+ - [ ] Page is a thin wrapper in `src/pages/` — no logic, no state
846
+ - [ ] Route registered in `src/shared/config/navigation.ts` with `label`, `labelKey`, `icon`, `allowedRoles`, `group`
847
+ - [ ] Route registered in `src/app/components/AuthGuard.tsx` with correct guard (`ProtectedRoute` or `RoleRoute`)
848
+ - [ ] i18n key added to `src/locales/<lang>/nav.json` for **all** configured languages
849
+ - [ ] Navigation card added to `HomeContent.tsx` if this is a primary module
850
+ - [ ] All data arrays live in `features/<name>/data/mock.ts`, not in components
851
+ - [ ] Server state fetched via React Query hook — not `useState` + `useEffect`
852
+ - [ ] React Query `queryKey` includes `language` when response contains translated strings
853
+ - [ ] `staleTime` is set on every `useQuery` call — never left at default `0`
854
+ - [ ] Client UI state (filters, tabs) uses Zustand with selectors — not prop drilling
855
+ - [ ] Only `xertica-ui` components used — no raw HTML elements
856
+ - [ ] No raw hex/rgb/hsl values in `className` or `style` — semantic tokens for status contexts
857
+ - [ ] No hardcoded border radii — `rounded-[var(--radius)]`
858
+ - [ ] Icons from `lucide-react` only — no inline SVG
859
+ - [ ] Layout state from `useLayout()` — no hardcoded `padding-left` or sidebar widths
860
+ - [ ] Destructive actions wrapped in `<AlertDialog>` with explicit confirm/cancel
861
+ - [ ] Forms use `react-hook-form` + `zod` — no manual `useState` + if-validation
862
+ - [ ] Loading states render a `*Skeleton` component, not a blank space or spinner alone
863
+ - [ ] All user-facing strings go through `useTranslation()` — no hardcoded UI text
864
+ - [ ] `toast` used for action feedback — message goes through `t()`
865
+ - [ ] Responsive: tested on mobile (< 640px), tablet (640–1024px), desktop (> 1024px)