xertica-ui 2.5.3 → 2.6.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 (583) hide show
  1. package/CHANGELOG.md +687 -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 +5 -4
  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/components/blocks/card-patterns/card-patterns.mdx +123 -123
  26. package/components/brand/branding/branding.mdx +27 -27
  27. package/components/brand/language-selector/language-selector.mdx +126 -126
  28. package/components/brand/theme-toggle/theme-toggle.mdx +47 -47
  29. package/components/brand/theme-toggle/theme-toggle.test.tsx +6 -2
  30. package/components/brand/xertica-logo/xertica-logo.mdx +56 -56
  31. package/components/brand/xertica-orbe/xertica-orbe.mdx +38 -38
  32. package/components/brand/xertica-provider/XerticaProvider.tsx +112 -112
  33. package/components/brand/xertica-provider/xertica-provider.mdx +61 -61
  34. package/components/brand/xertica-provider/xertica-provider.test.tsx +25 -13
  35. package/components/brand/xertica-xlogo/xertica-xlogo.mdx +55 -55
  36. package/components/examples/DrawingMapExample.tsx +1 -4
  37. package/components/layout/header/header.mdx +117 -117
  38. package/components/layout/header/header.test.tsx +2 -1
  39. package/components/layout/sidebar/sidebar.mdx +99 -99
  40. package/components/layout/sidebar/sidebar.stories.tsx +1033 -1033
  41. package/components/layout/sidebar/sidebar.test.tsx +2 -1
  42. package/components/layout/sidebar/sidebar.tsx +1509 -1506
  43. package/components/media/audio-player/AudioPlayer.mdx +67 -67
  44. package/components/media/audio-player/AudioPlayer.test.tsx +2 -1
  45. package/components/media/floating-media-wrapper.mdx +74 -74
  46. package/components/media/video-player/VideoPlayer.mdx +102 -102
  47. package/components/media/video-player/VideoPlayer.test.tsx +3 -2
  48. package/components/pages/forgot-password-page/ForgotPasswordPage.tsx +188 -188
  49. package/components/pages/forgot-password-page/forgot-password-page.mdx +60 -60
  50. package/components/pages/forgot-password-page/forgot-password-page.test.tsx +2 -1
  51. package/components/pages/home-content/HomeContent.tsx +119 -119
  52. package/components/pages/home-content/home-content.mdx +62 -62
  53. package/components/pages/home-page/HomePage.stories.tsx +8 -15
  54. package/components/pages/home-page/home-page.mdx +53 -53
  55. package/components/pages/home-page/home-page.test.tsx +2 -1
  56. package/components/pages/login-page/LoginPage.mdx +31 -31
  57. package/components/pages/login-page/LoginPage.tsx +218 -218
  58. package/components/pages/login-page/login-page.test.tsx +2 -1
  59. package/components/pages/reset-password-page/ResetPasswordPage.tsx +243 -243
  60. package/components/pages/reset-password-page/reset-password-page.mdx +63 -63
  61. package/components/pages/template-content/TemplateContent.tsx +1353 -1353
  62. package/components/pages/template-content/template-content.mdx +61 -61
  63. package/components/pages/template-page/TemplatePage.stories.tsx +32 -32
  64. package/components/pages/template-page/template-page.mdx +53 -53
  65. package/components/pages/template-page/template-page.test.tsx +2 -1
  66. package/components/pages/verify-email-page/VerifyEmailPage.tsx +206 -206
  67. package/components/pages/verify-email-page/verify-email-page.mdx +55 -55
  68. package/components/public-api-smoke.test.tsx +10 -6
  69. package/components/shared/assistant-utils.ts +3 -2
  70. package/components/shared/navigation.ts +2 -2
  71. package/components/ui/accordion/accordion.mdx +29 -29
  72. package/components/ui/alert/alert.mdx +29 -29
  73. package/components/ui/alert-dialog/alert-dialog.mdx +26 -26
  74. package/components/ui/aspect-ratio/aspect-ratio.mdx +25 -25
  75. package/components/ui/assistant-chart/AssistantChart.tsx +8 -2
  76. package/components/ui/assistant-chart/assistant-chart.mdx +25 -25
  77. package/components/ui/avatar/avatar.mdx +26 -26
  78. package/components/ui/badge/badge.mdx +28 -28
  79. package/components/ui/breadcrumb/breadcrumb.mdx +26 -26
  80. package/components/ui/button/button.mdx +29 -29
  81. package/components/ui/calendar/calendar.mdx +26 -26
  82. package/components/ui/card/card.mdx +26 -26
  83. package/components/ui/carousel/carousel.mdx +26 -26
  84. package/components/ui/chart/chart.mdx +26 -26
  85. package/components/ui/chart/chart.test.tsx +178 -178
  86. package/components/ui/chart/chart.tsx +2252 -2245
  87. package/components/ui/checkbox/checkbox.mdx +26 -26
  88. package/components/ui/collapsible/collapsible.mdx +25 -25
  89. package/components/ui/command/command.mdx +26 -26
  90. package/components/ui/context-menu/context-menu.mdx +26 -26
  91. package/components/ui/dialog/dialog.mdx +26 -26
  92. package/components/ui/drawer/drawer.mdx +26 -26
  93. package/components/ui/dropdown-menu/dropdown-menu.mdx +26 -26
  94. package/components/ui/empty/empty.mdx +26 -26
  95. package/components/ui/file-upload/file-upload.mdx +26 -26
  96. package/components/ui/form/form.mdx +20 -20
  97. package/components/ui/google-maps-loader/google-maps-loader.mdx +68 -68
  98. package/components/ui/hover-card/hover-card.mdx +26 -26
  99. package/components/ui/input/input.mdx +29 -29
  100. package/components/ui/input-otp/input-otp.mdx +26 -26
  101. package/components/ui/label/label.mdx +25 -25
  102. package/components/ui/map/map.mdx +26 -26
  103. package/components/ui/map/map.tsx +6 -1
  104. package/components/ui/menubar/menubar.mdx +26 -26
  105. package/components/ui/navigation-menu/navigation-menu.mdx +26 -26
  106. package/components/ui/notification-badge/notification-badge.mdx +26 -26
  107. package/components/ui/page-header/page-header.mdx +44 -44
  108. package/components/ui/pagination/pagination.mdx +26 -26
  109. package/components/ui/popover/popover.mdx +26 -26
  110. package/components/ui/progress/progress.mdx +25 -25
  111. package/components/ui/radio-group/radio-group.mdx +26 -26
  112. package/components/ui/rating/rating.mdx +26 -26
  113. package/components/ui/resizable/resizable.mdx +26 -26
  114. package/components/ui/resizable/resizable.tsx +13 -8
  115. package/components/ui/rich-text-editor/rich-text-editor.mdx +47 -47
  116. package/components/ui/route-map/route-map.mdx +26 -26
  117. package/components/ui/scroll-area/scroll-area.mdx +25 -25
  118. package/components/ui/search/search.mdx +27 -27
  119. package/components/ui/select/select.mdx +26 -26
  120. package/components/ui/separator/separator.mdx +25 -25
  121. package/components/ui/sheet/sheet.mdx +26 -26
  122. package/components/ui/simple-map/simple-map.mdx +25 -25
  123. package/components/ui/skeleton/skeleton.mdx +25 -25
  124. package/components/ui/slider/slider.mdx +26 -26
  125. package/components/ui/sonner/sonner.mdx +26 -26
  126. package/components/ui/stats-card/stats-card.mdx +26 -26
  127. package/components/ui/stats-card/stats-card.stories.tsx +117 -117
  128. package/components/ui/stats-card/stats-card.tsx +109 -109
  129. package/components/ui/stepper/stepper.mdx +26 -26
  130. package/components/ui/switch/switch.mdx +25 -25
  131. package/components/ui/table/table.mdx +27 -27
  132. package/components/ui/tabs/tabs.mdx +26 -26
  133. package/components/ui/textarea/textarea.mdx +25 -25
  134. package/components/ui/timeline/timeline.mdx +26 -26
  135. package/components/ui/toggle/toggle.mdx +26 -26
  136. package/components/ui/toggle-group/toggle-group.mdx +26 -26
  137. package/components/ui/tooltip/tooltip.mdx +26 -26
  138. package/components/ui/tree-view/tree-view.mdx +26 -26
  139. package/components.json +511 -511
  140. package/contexts/BrandColorsContext.tsx +282 -282
  141. package/contexts/i18n-singleton.test.tsx +57 -0
  142. package/contexts/theme-data.ts +391 -391
  143. package/dist/{AssistantChart-DNdwuS-t.js → AssistantChart-BMNSA_Pk.js} +4 -4
  144. package/dist/{AssistantChart-COGiOV-g.cjs → AssistantChart-BzM7plyc.cjs} +31 -21
  145. package/dist/{AssistantChart-CWX1OWNM.js → AssistantChart-C842evTi.js} +31 -21
  146. package/dist/{AssistantChart-BW9JK6jw.cjs → AssistantChart-CVF2uh37.cjs} +4 -4
  147. package/dist/{AssistantChart-BZTPJ5dP.cjs → AssistantChart-JooMdVQU.cjs} +5 -5
  148. package/dist/{AssistantChart-DMJJ_Amf.js → AssistantChart-KHS-tp-L.js} +5 -5
  149. package/dist/{BrandColorsContext-BwY-b6M4.cjs → BrandColorsContext-B4_81eas.cjs} +2 -2
  150. package/dist/{BrandColorsContext-BMRJ04Wf.js → BrandColorsContext-DbK5LnQ_.js} +2 -2
  151. package/dist/{CodeBlock-CjeFavqV.js → CodeBlock-DiKO8ocT.js} +11 -11
  152. package/dist/{CodeBlock-CV6dtsTM.cjs → CodeBlock-ZYThr7Kn.cjs} +12 -9
  153. package/dist/{XerticaXLogo-mqjoBiLI.js → LanguageSelector-CmTj3lWq.js} +85 -82
  154. package/dist/{XerticaXLogo-BX3ueACh.js → LanguageSelector-DxW6o7bt.js} +81 -81
  155. package/dist/{XerticaXLogo-uQgwns_E.cjs → LanguageSelector-Sw73qvWV.cjs} +84 -81
  156. package/dist/{ThemeContext-BgclCB35.js → ThemeContext-BGeh_Kdr.js} +290 -212
  157. package/dist/{ThemeContext-BblcjQup.cjs → ThemeContext-D50irx5T.cjs} +291 -205
  158. package/dist/{VerifyEmailPage-C_Zk6Gen.cjs → VerifyEmailPage-B6bOrybJ.cjs} +17 -17
  159. package/dist/{VerifyEmailPage-B31mCrMc.js → VerifyEmailPage-BRE5Fz59.js} +8 -8
  160. package/dist/{VerifyEmailPage-Cyl55sJb.js → VerifyEmailPage-BcCluouh.js} +135 -65
  161. package/dist/VerifyEmailPage-Bx1sr0uQ.cjs +3298 -0
  162. package/dist/{VerifyEmailPage-Bci0bA-P.js → VerifyEmailPage-DUYyXCX9.js} +3 -3
  163. package/dist/VerifyEmailPage-DXXMHbzq.js +3289 -0
  164. package/dist/{VerifyEmailPage-u_Dn7t1U.cjs → VerifyEmailPage-DpYtFk35.cjs} +21 -21
  165. package/dist/{VerifyEmailPage-X14vhdyl.js → VerifyEmailPage-NXKWW3Dk.js} +12 -12
  166. package/dist/{VerifyEmailPage-C7KiYXrm.cjs → VerifyEmailPage-QrCz4Wqr.cjs} +11 -11
  167. package/dist/{VerifyEmailPage-Bv8Ah_TK.cjs → VerifyEmailPage-ZmQra0Wi.cjs} +144 -74
  168. package/dist/{XerticaProvider-BErr83Bg.js → XerticaProvider-BF3q_myt.js} +5 -4
  169. package/dist/{XerticaProvider-CeS5G_n5.cjs → XerticaProvider-C_JSOz1U.cjs} +2 -2
  170. package/dist/{XerticaProvider-CwOkHxiT.cjs → XerticaProvider-D5zjrqZq.cjs} +5 -4
  171. package/dist/{XerticaProvider-ra2NciRq.js → XerticaProvider-KTGl4Cn1.js} +2 -2
  172. package/dist/{alert-dialog-DqlRW_An.js → alert-dialog-BrpwXKwS.js} +3 -3
  173. package/dist/{alert-dialog-DhwPioBa.cjs → alert-dialog-CZU1Zase.cjs} +3 -3
  174. package/dist/{alert-dialog-KpoabzJb.js → alert-dialog-ClRoLH7l.js} +40 -56
  175. package/dist/{alert-dialog-B4M3vQKS.cjs → alert-dialog-DBBqvU-V.cjs} +53 -38
  176. package/dist/assistant.cjs.js +2 -2
  177. package/dist/assistant.es.js +2 -2
  178. package/dist/brand.cjs.js +6 -6
  179. package/dist/brand.es.js +2 -2
  180. package/dist/cli.js +63 -21
  181. package/dist/components/assistant/code-block/CodeBlock.d.ts +2 -1
  182. package/dist/components/assistant/formatted-document/FormattedDocument.d.ts +2 -1
  183. package/dist/components/assistant/markdown-message/MarkdownMessage.d.ts +2 -1
  184. package/dist/components/assistant/modern-chat-input/ModernChatInput.d.ts +2 -1
  185. package/dist/components/assistant/xertica-assistant/parts/AssistantCollapsedView.d.ts +2 -1
  186. package/dist/components/assistant/xertica-assistant/parts/AssistantConversationList.d.ts +2 -1
  187. package/dist/components/assistant/xertica-assistant/parts/AssistantDocumentEditor.d.ts +2 -1
  188. package/dist/components/assistant/xertica-assistant/parts/AssistantFeedbackDialog.d.ts +2 -1
  189. package/dist/components/assistant/xertica-assistant/parts/AssistantHeader.d.ts +2 -1
  190. package/dist/components/assistant/xertica-assistant/parts/AssistantMessageBubble.d.ts +2 -1
  191. package/dist/components/assistant/xertica-assistant/parts/AssistantTabBar.d.ts +2 -1
  192. package/dist/components/assistant/xertica-assistant/parts/AssistantTypingIndicator.d.ts +2 -1
  193. package/dist/components/assistant/xertica-assistant/parts/AssistantWelcomeScreen.d.ts +2 -1
  194. package/dist/components/assistant/xertica-assistant/types.d.ts +3 -2
  195. package/dist/components/assistant/xertica-assistant/use-assistant.d.ts +1 -1
  196. package/dist/components/assistant/xertica-assistant/xertica-assistant.d.ts +2 -1
  197. package/dist/components/blocks/card-patterns/ActivityCard.d.ts +1 -1
  198. package/dist/components/blocks/card-patterns/ActivityCardSkeleton.d.ts +1 -1
  199. package/dist/components/blocks/card-patterns/FeatureCard.d.ts +1 -1
  200. package/dist/components/blocks/card-patterns/FeatureCardSkeleton.d.ts +1 -1
  201. package/dist/components/blocks/card-patterns/NotificationCard.d.ts +1 -1
  202. package/dist/components/blocks/card-patterns/NotificationCardSkeleton.d.ts +1 -1
  203. package/dist/components/blocks/card-patterns/ProfileCard.d.ts +1 -1
  204. package/dist/components/blocks/card-patterns/ProfileCardSkeleton.d.ts +1 -1
  205. package/dist/components/blocks/card-patterns/ProjectCard.d.ts +1 -1
  206. package/dist/components/blocks/card-patterns/ProjectCardSkeleton.d.ts +1 -1
  207. package/dist/components/blocks/card-patterns/QuickActionCard.d.ts +1 -1
  208. package/dist/components/blocks/card-patterns/QuickActionCardSkeleton.d.ts +1 -1
  209. package/dist/components/brand/language-selector/LanguageSelector.d.ts +2 -1
  210. package/dist/components/brand/theme-toggle/ThemeToggle.d.ts +2 -1
  211. package/dist/components/brand/xertica-logo/XerticaLogo.d.ts +2 -1
  212. package/dist/components/brand/xertica-orbe/XerticaOrbe.d.ts +2 -1
  213. package/dist/components/brand/xertica-provider/XerticaProvider.d.ts +1 -1
  214. package/dist/components/brand/xertica-xlogo/XerticaXLogo.d.ts +2 -1
  215. package/dist/components/examples/DrawingMapExample.d.ts +2 -1
  216. package/dist/components/examples/FilterableMapExample.d.ts +1 -1
  217. package/dist/components/examples/MapShowcase.d.ts +2 -1
  218. package/dist/components/examples/SimpleFilterableMap.d.ts +2 -1
  219. package/dist/components/figma/ImageWithFallback.d.ts +1 -1
  220. package/dist/components/layout/header/header.d.ts +1 -1
  221. package/dist/components/layout/sidebar/sidebar.d.ts +25 -13
  222. package/dist/components/media/FloatingMediaWrapper.d.ts +1 -1
  223. package/dist/components/media/audio-player/AudioPlayer.d.ts +2 -1
  224. package/dist/components/media/video-player/VideoPlayer.d.ts +2 -1
  225. package/dist/components/pages/forgot-password-page/ForgotPasswordPage.d.ts +2 -1
  226. package/dist/components/pages/home-content/HomeContent.d.ts +2 -1
  227. package/dist/components/pages/home-page/HomePage.d.ts +2 -1
  228. package/dist/components/pages/login-page/LoginPage.d.ts +2 -1
  229. package/dist/components/pages/reset-password-page/ResetPasswordPage.d.ts +2 -1
  230. package/dist/components/pages/template-content/TemplateContent.d.ts +2 -1
  231. package/dist/components/pages/template-page/TemplatePage.d.ts +2 -1
  232. package/dist/components/pages/verify-email-page/VerifyEmailPage.d.ts +2 -1
  233. package/dist/components/shared/CustomTooltipContent.d.ts +1 -1
  234. package/dist/components/shared/assistant-utils.d.ts +3 -2
  235. package/dist/components/shared/error-boundary.d.ts +4 -4
  236. package/dist/components/shared/error-fallbacks.d.ts +4 -3
  237. package/dist/components/shared/navigation.d.ts +6 -2
  238. package/dist/components/ui/accordion/accordion.d.ts +4 -4
  239. package/dist/components/ui/alert/alert.d.ts +3 -3
  240. package/dist/components/ui/alert-dialog/alert-dialog.d.ts +10 -10
  241. package/dist/components/ui/aspect-ratio/aspect-ratio.d.ts +1 -1
  242. package/dist/components/ui/assistant-chart/AssistantChart.d.ts +4 -3
  243. package/dist/components/ui/avatar/avatar.d.ts +3 -3
  244. package/dist/components/ui/badge/badge.d.ts +1 -1
  245. package/dist/components/ui/breadcrumb/breadcrumb.d.ts +7 -7
  246. package/dist/components/ui/calendar/calendar.d.ts +2 -2
  247. package/dist/components/ui/card/card.d.ts +7 -7
  248. package/dist/components/ui/carousel/carousel.d.ts +5 -5
  249. package/dist/components/ui/chart/chart.d.ts +16 -16
  250. package/dist/components/ui/collapsible/collapsible.d.ts +3 -3
  251. package/dist/components/ui/command/command.d.ts +9 -9
  252. package/dist/components/ui/context-menu/context-menu.d.ts +15 -15
  253. package/dist/components/ui/dialog/dialog.d.ts +9 -9
  254. package/dist/components/ui/drawer/drawer.d.ts +10 -10
  255. package/dist/components/ui/dropdown-menu/dropdown-menu.d.ts +15 -15
  256. package/dist/components/ui/form/form.d.ts +7 -7
  257. package/dist/components/ui/google-maps-loader/google-maps-loader.d.ts +3 -3
  258. package/dist/components/ui/hover-card/hover-card.d.ts +3 -3
  259. package/dist/components/ui/input-otp/input-otp.d.ts +4 -4
  260. package/dist/components/ui/label/label.d.ts +1 -1
  261. package/dist/components/ui/menubar/menubar.d.ts +16 -16
  262. package/dist/components/ui/navigation-menu/navigation-menu.d.ts +8 -8
  263. package/dist/components/ui/page-header/page-header.d.ts +3 -3
  264. package/dist/components/ui/pagination/pagination.d.ts +7 -7
  265. package/dist/components/ui/popover/popover.d.ts +4 -4
  266. package/dist/components/ui/progress/progress.d.ts +1 -1
  267. package/dist/components/ui/resizable/resizable.d.ts +11 -7
  268. package/dist/components/ui/rich-text-editor/rich-text-editor.d.ts +1 -1
  269. package/dist/components/ui/scroll-area/scroll-area.d.ts +2 -2
  270. package/dist/components/ui/separator/separator.d.ts +1 -1
  271. package/dist/components/ui/sheet/sheet.d.ts +10 -10
  272. package/dist/components/ui/skeleton/skeleton.d.ts +1 -1
  273. package/dist/components/ui/sonner/sonner.d.ts +2 -1
  274. package/dist/components/ui/stats-card/stats-card-skeleton.d.ts +1 -1
  275. package/dist/components/ui/table/table.d.ts +8 -8
  276. package/dist/components/ui/tabs/tabs.d.ts +4 -4
  277. package/dist/components/ui/tooltip/tooltip.d.ts +4 -4
  278. package/dist/contexts/ApiKeyContext.d.ts +2 -2
  279. package/dist/contexts/AssistenteContext.d.ts +1 -1
  280. package/dist/contexts/AuthContext.d.ts +1 -1
  281. package/dist/contexts/LanguageContext.d.ts +2 -2
  282. package/dist/contexts/LayoutContext.d.ts +2 -2
  283. package/dist/contexts/ThemeContext.d.ts +1 -1
  284. package/dist/features/assistant/hooks/useAssistantConfig.d.ts +1 -1
  285. package/dist/features/home/hooks/useDashboardStats.d.ts +1 -1
  286. package/dist/features/home/hooks/useFeatureCards.d.ts +1 -1
  287. package/dist/features/home/hooks/useTeamMembers.d.ts +1 -1
  288. package/dist/{google-maps-loader-BCe58h9D.js → google-maps-loader-BOug999f.js} +0 -4
  289. package/dist/{google-maps-loader-casMyxlo.cjs → google-maps-loader-DfeBRI8Q.cjs} +0 -5
  290. package/dist/hooks.cjs.js +2 -2
  291. package/dist/hooks.es.js +2 -2
  292. package/dist/{index-9GWd0qxq.cjs → index-BQjx1Mdf.cjs} +1 -1
  293. package/dist/index-Bei5DzAL.js +6 -0
  294. package/dist/index.cjs.js +15 -15
  295. package/dist/index.es.js +11 -11
  296. package/dist/layout.cjs.js +1 -1
  297. package/dist/layout.es.js +1 -1
  298. package/dist/pages.cjs.js +1 -1
  299. package/dist/pages.es.js +1 -1
  300. package/dist/{rich-text-editor-B2CKz7nx.cjs → rich-text-editor-BuqSu718.cjs} +68 -3
  301. package/dist/{rich-text-editor-DloeW0wc.js → rich-text-editor-CV8FtA_l.js} +66 -4
  302. package/dist/{sidebar-CLmIjgNd.cjs → sidebar-BGJ0j567.cjs} +84 -67
  303. package/dist/{sidebar-Duermn32.js → sidebar-BI6mZlC8.js} +81 -64
  304. package/dist/{sidebar-BS1p2V7t.cjs → sidebar-BtmotOg-.cjs} +367 -9
  305. package/dist/{sidebar-QwCoeoZ_.js → sidebar-D3EgGVxF.js} +1 -1
  306. package/dist/{sidebar-CQn_rwxP.cjs → sidebar-DDTqMGnR.cjs} +4 -4
  307. package/dist/{sidebar-3XyzjVBw.js → sidebar-I7EXyf5D.js} +364 -6
  308. package/dist/ui.cjs.js +4 -4
  309. package/dist/ui.es.js +4 -4
  310. package/dist/{xertica-assistant-B687qEPU.js → xertica-assistant-CJVnvMqU.js} +17 -8
  311. package/dist/{xertica-assistant-sOHwTgIP.cjs → xertica-assistant-CKPtc1z5.cjs} +19 -10
  312. package/dist/{xertica-assistant-QFUnv5I2.cjs → xertica-assistant-DER0brPQ.cjs} +6 -5
  313. package/dist/{xertica-assistant-CyikE3N_.js → xertica-assistant-DQCjpk5M.js} +4 -3
  314. package/dist/{xertica-assistant-B1NaSFFj.js → xertica-assistant-Dk-9AJzw.js} +6 -5
  315. package/dist/{xertica-assistant-CIaUlbIt.cjs → xertica-assistant-DxhIKvuY.cjs} +8 -7
  316. package/dist/xertica-ui.css +2 -2
  317. package/docs/components/audio-player.md +1 -1
  318. package/docs/components/sidebar.md +331 -331
  319. package/docs/components/stats-card.md +138 -138
  320. package/docs/components/toggle.md +12 -0
  321. package/docs/doc-audit.md +35 -229
  322. package/docs/i18n.md +31 -10
  323. package/docs/llms.md +6 -4
  324. package/llms-compact.txt +444 -444
  325. package/llms-full.txt +12144 -12144
  326. package/llms.txt +187 -187
  327. package/package.json +223 -219
  328. package/scripts/a11y-audit.mjs +162 -162
  329. package/scripts/fix-stories.cjs +19 -19
  330. package/styles/globals.css +0 -1
  331. package/styles/xertica/base.css +8 -0
  332. package/styles/xertica/tokens.css +240 -240
  333. package/templates/.env.example +2 -2
  334. package/templates/.prettierignore +4 -4
  335. package/templates/.prettierrc +10 -10
  336. package/templates/guidelines/Guidelines.md +865 -865
  337. package/templates/index.html +13 -13
  338. package/templates/package.json +69 -69
  339. package/templates/src/app/components/AuthGuard.tsx +11 -0
  340. package/templates/src/features/auth/ui/AuthPageShell.tsx +32 -32
  341. package/templates/src/features/home/ui/HomeContent.tsx +116 -116
  342. package/templates/src/features/settings/index.ts +2 -0
  343. package/templates/src/features/settings/ui/SettingsContent.tsx +134 -0
  344. package/templates/src/features/template/ui/TemplateContent.tsx +1321 -1321
  345. package/templates/src/i18n.ts +36 -13
  346. package/templates/src/locales/en/pages/settings.json +15 -0
  347. package/templates/src/locales/es/pages/settings.json +15 -0
  348. package/templates/src/locales/pt-BR/pages/settings.json +15 -0
  349. package/templates/src/pages/SettingsPage.tsx +28 -0
  350. package/templates/src/shared/config/navigation.ts +2 -2
  351. package/templates/src/styles/xertica/tokens.css +240 -240
  352. package/templates/vite.config.d.ts +2 -2
  353. package/templates/vite.config.js +20 -20
  354. package/utils/gemini.ts +2 -2
  355. package/dist/AssistantChart-9w31gdAb.cjs +0 -3363
  356. package/dist/AssistantChart-BAudAfne.cjs +0 -3591
  357. package/dist/AssistantChart-BAx9VQvb.cjs +0 -3374
  358. package/dist/AssistantChart-BP8upjMk.js +0 -3565
  359. package/dist/AssistantChart-BXU1ACnh.js +0 -3489
  360. package/dist/AssistantChart-CVko2A1W.js +0 -3348
  361. package/dist/AssistantChart-CVzmmhx4.js +0 -3337
  362. package/dist/AssistantChart-CeU2dIb6.js +0 -3469
  363. package/dist/AssistantChart-D0A1FPYt.cjs +0 -3515
  364. package/dist/AssistantChart-DO5UuX4J.cjs +0 -3495
  365. package/dist/AudioPlayer-1ypwE2Wh.cjs +0 -936
  366. package/dist/AudioPlayer-BJ2IuRQW.cjs +0 -1275
  367. package/dist/AudioPlayer-BWDW6TN9.cjs +0 -1279
  368. package/dist/AudioPlayer-CM962GEh.js +0 -1280
  369. package/dist/AudioPlayer-CbZId7cj.cjs +0 -998
  370. package/dist/AudioPlayer-DU8zt8-z.js +0 -999
  371. package/dist/AudioPlayer-DuKXrCfy.js +0 -937
  372. package/dist/AudioPlayer-Xxma6_-H.js +0 -1276
  373. package/dist/BrandColorsContext-DLVJgtmH.js +0 -666
  374. package/dist/BrandColorsContext-DZT7JjeD.js +0 -659
  375. package/dist/BrandColorsContext-GUyFmkX0.cjs +0 -665
  376. package/dist/BrandColorsContext-awnBCmC4.cjs +0 -666
  377. package/dist/CodeBlock-C2ZUXt8V.js +0 -219
  378. package/dist/CodeBlock-C5oYnLQp.cjs +0 -218
  379. package/dist/CodeBlock-DuxdtN-l.js +0 -219
  380. package/dist/CodeBlock-POVYONvC.cjs +0 -218
  381. package/dist/CustomTooltipContent-BT6brkVJ.cjs +0 -49
  382. package/dist/CustomTooltipContent-CfOfikhq.js +0 -33
  383. package/dist/CustomTooltipContent-DHjkY0ww.js +0 -40
  384. package/dist/CustomTooltipContent-c_K-DWRr.cjs +0 -56
  385. package/dist/FeatureCard-9GhnlgL3.js +0 -336
  386. package/dist/FeatureCard-Bcb3Zi54.js +0 -302
  387. package/dist/FeatureCard-Cfs6Ishq.js +0 -485
  388. package/dist/FeatureCard-CkPd2psQ.cjs +0 -301
  389. package/dist/FeatureCard-Dkp-xmzM.cjs +0 -335
  390. package/dist/FeatureCard-ie3L8Fpr.cjs +0 -484
  391. package/dist/FeatureCardSkeleton-CAgu8stE.js +0 -27
  392. package/dist/FeatureCardSkeleton-mO3Bdm_V.cjs +0 -26
  393. package/dist/LanguageContext-BwhwC3G2.js +0 -657
  394. package/dist/LanguageContext-DvUt5jBg.cjs +0 -656
  395. package/dist/LayoutContext-BDmcZfMH.cjs +0 -84
  396. package/dist/LayoutContext-C4kKN9RV.cjs +0 -93
  397. package/dist/LayoutContext-CGEe1oPq.js +0 -94
  398. package/dist/LayoutContext-CwT5KLiW.cjs +0 -104
  399. package/dist/LayoutContext-DVLCsoQn.js +0 -105
  400. package/dist/LayoutContext-dbQvdC4O.js +0 -85
  401. package/dist/ThemeContext-BbBNoFTG.js +0 -735
  402. package/dist/ThemeContext-Bo-W2WZH.js +0 -1856
  403. package/dist/ThemeContext-CP3a0jxy.cjs +0 -1855
  404. package/dist/ThemeContext-Cmr8Ex8H.cjs +0 -734
  405. package/dist/ThemeContext-CpqYShLq.cjs +0 -324
  406. package/dist/ThemeContext-D3LzacmG.js +0 -188
  407. package/dist/ThemeContext-DQUOeziy.cjs +0 -1855
  408. package/dist/ThemeContext-Du2nE1PL.js +0 -325
  409. package/dist/ThemeContext-GeEBTJ3q.cjs +0 -1621
  410. package/dist/ThemeContext-JyLK9B1o.js +0 -1622
  411. package/dist/ThemeContext-RTy1m2Uq.js +0 -82
  412. package/dist/ThemeContext-U4dEYc6C.cjs +0 -187
  413. package/dist/ThemeContext-bSzuOit2.cjs +0 -81
  414. package/dist/ThemeContext-ept8jhXI.js +0 -1856
  415. package/dist/VerifyEmailPage-BE-L9mB7.js +0 -2828
  416. package/dist/VerifyEmailPage-BIBOKV7Z.js +0 -3214
  417. package/dist/VerifyEmailPage-BJjAMUTW.js +0 -3223
  418. package/dist/VerifyEmailPage-BRSP-Pwt.cjs +0 -3196
  419. package/dist/VerifyEmailPage-Bae2cBXT.cjs +0 -2827
  420. package/dist/VerifyEmailPage-BiRm7Nh4.cjs +0 -3213
  421. package/dist/VerifyEmailPage-Bvfv8HVQ.js +0 -3214
  422. package/dist/VerifyEmailPage-CR7kb5df.cjs +0 -2827
  423. package/dist/VerifyEmailPage-C_ihbcth.js +0 -2828
  424. package/dist/VerifyEmailPage-CbgjOF0v.js +0 -2828
  425. package/dist/VerifyEmailPage-CdYPSJoO.js +0 -2828
  426. package/dist/VerifyEmailPage-CkBYfsNy.cjs +0 -3232
  427. package/dist/VerifyEmailPage-D-FRj5TU.cjs +0 -3213
  428. package/dist/VerifyEmailPage-DF2ilhum.cjs +0 -3210
  429. package/dist/VerifyEmailPage-DMBh4NM9.cjs +0 -2827
  430. package/dist/VerifyEmailPage-DTtFfC-J.js +0 -3197
  431. package/dist/VerifyEmailPage-Dt7zgA4w.cjs +0 -2827
  432. package/dist/VerifyEmailPage-EhudUdqF.js +0 -3211
  433. package/dist/VerifyEmailPage-RrUApqBN.js +0 -3214
  434. package/dist/VerifyEmailPage-VoMI7MYH.cjs +0 -3213
  435. package/dist/VerifyEmailPage-hdB8JQGv.cjs +0 -3213
  436. package/dist/VerifyEmailPage-vYHbYK3q.js +0 -3214
  437. package/dist/XerticaOrbe-BCUVSPPB.cjs +0 -1924
  438. package/dist/XerticaOrbe-BGIB1CTK.js +0 -1355
  439. package/dist/XerticaOrbe-By8eEvR-.js +0 -1925
  440. package/dist/XerticaOrbe-FWGjBj0U.cjs +0 -1354
  441. package/dist/XerticaProvider-AChwphCO.cjs +0 -48
  442. package/dist/XerticaProvider-AbWlr7Af.cjs +0 -48
  443. package/dist/XerticaProvider-B8CaV7xu.cjs +0 -39
  444. package/dist/XerticaProvider-BITjgC5p.js +0 -39
  445. package/dist/XerticaProvider-BSyFrmC0.js +0 -49
  446. package/dist/XerticaProvider-By8q3Roe.cjs +0 -38
  447. package/dist/XerticaProvider-CUYJZc32.js +0 -49
  448. package/dist/XerticaProvider-CW9hpCdF.cjs +0 -39
  449. package/dist/XerticaProvider-CWgby5mY.js +0 -49
  450. package/dist/XerticaProvider-CWs6EwNa.js +0 -49
  451. package/dist/XerticaProvider-CiNKjMx1.cjs +0 -48
  452. package/dist/XerticaProvider-CjQAQPcn.cjs +0 -48
  453. package/dist/XerticaProvider-D5lLumH-.js +0 -49
  454. package/dist/XerticaProvider-DQtvJU7m.js +0 -40
  455. package/dist/XerticaProvider-DUOJg9iX.js +0 -49
  456. package/dist/XerticaProvider-Dl_b72_l.cjs +0 -51
  457. package/dist/XerticaProvider-qQUDop71.cjs +0 -48
  458. package/dist/XerticaProvider-siSt9uG2.js +0 -40
  459. package/dist/XerticaXLogo-8TTzBjHw.cjs +0 -251
  460. package/dist/XerticaXLogo-B2svDGZh.cjs +0 -251
  461. package/dist/XerticaXLogo-BWaag64t.js +0 -252
  462. package/dist/XerticaXLogo-CFuIlYFH.js +0 -252
  463. package/dist/XerticaXLogo-CU-U-GP4.cjs +0 -251
  464. package/dist/XerticaXLogo-ChryA6xj.js +0 -252
  465. package/dist/XerticaXLogo-CowGv7BC.js +0 -252
  466. package/dist/XerticaXLogo-CziKMQil.cjs +0 -242
  467. package/dist/XerticaXLogo-D8jf0SNv.cjs +0 -214
  468. package/dist/XerticaXLogo-DHz5SugF.js +0 -252
  469. package/dist/XerticaXLogo-DTee_y8X.cjs +0 -251
  470. package/dist/XerticaXLogo-DfUvz-lD.js +0 -243
  471. package/dist/XerticaXLogo-DzXKZBtG.js +0 -231
  472. package/dist/XerticaXLogo-fAJMy3H4.js +0 -215
  473. package/dist/XerticaXLogo-kslQ8Tk_.cjs +0 -251
  474. package/dist/XerticaXLogo-xWbElCZj.cjs +0 -230
  475. package/dist/alert-dialog-iDe5VE5o.js +0 -842
  476. package/dist/alert-dialog-yckpaOpy.cjs +0 -865
  477. package/dist/avatar-Cq5_E8r9.cjs +0 -78
  478. package/dist/avatar-CuYu2MKt.cjs +0 -72
  479. package/dist/avatar-Cxyofu1H.js +0 -56
  480. package/dist/avatar-DSBfJMRJ.js +0 -62
  481. package/dist/breadcrumb-CVzzzqfo.js +0 -103
  482. package/dist/breadcrumb-DIJ0X3Ot.js +0 -96
  483. package/dist/breadcrumb-DjSxkjlQ.cjs +0 -95
  484. package/dist/breadcrumb-DnDlQFg2.cjs +0 -102
  485. package/dist/button-0CXwCRTm.cjs +0 -85
  486. package/dist/button-Bnv9SvYK.cjs +0 -79
  487. package/dist/button-C6uvh0rV.js +0 -63
  488. package/dist/button-qkz7Icqf.js +0 -69
  489. package/dist/card-B8-Gl5DL.js +0 -73
  490. package/dist/card-Bv_c57KU.cjs +0 -72
  491. package/dist/card-DJTsYhLL.cjs +0 -89
  492. package/dist/card-fi8zAN-I.js +0 -90
  493. package/dist/dropdown-menu-B_uEXNc4.cjs +0 -220
  494. package/dist/dropdown-menu-CFuCssWA.js +0 -204
  495. package/dist/dropdown-menu-Ze1YZFyc.cjs +0 -247
  496. package/dist/dropdown-menu-nc_Lvg-u.js +0 -231
  497. package/dist/google-maps-loader-BVoVhUwA.js +0 -316
  498. package/dist/google-maps-loader-BqsYL48U.cjs +0 -285
  499. package/dist/google-maps-loader-DjJaYhV6.cjs +0 -316
  500. package/dist/google-maps-loader-t2IlYBzw.js +0 -286
  501. package/dist/index-B7A523O_.js +0 -8
  502. package/dist/index-BabBx2pa.js +0 -6
  503. package/dist/index-CkTUgOwX.js +0 -8
  504. package/dist/index-D3RLKRAs.cjs +0 -7
  505. package/dist/index-DmHhnb7a.cjs +0 -7
  506. package/dist/index.umd.js +0 -13712
  507. package/dist/input-CNFHVKvo.cjs +0 -145
  508. package/dist/input-CPl84zAx.cjs +0 -151
  509. package/dist/input-C_UiS2Py.cjs +0 -152
  510. package/dist/input-D-6IsAca.js +0 -133
  511. package/dist/input-cc-PTD4R.js +0 -123
  512. package/dist/input-wPYg0d0P.js +0 -127
  513. package/dist/progress-BLwqortq.cjs +0 -105
  514. package/dist/progress-Cs9i4DPx.js +0 -81
  515. package/dist/progress-D9mtsf6j.js +0 -89
  516. package/dist/progress-DDeuWPZw.cjs +0 -97
  517. package/dist/rich-text-editor-1UW3Y2JK.js +0 -2891
  518. package/dist/rich-text-editor-BM-LPpTh.js +0 -2902
  519. package/dist/rich-text-editor-BmsjY03B.js +0 -2949
  520. package/dist/rich-text-editor-BrdC5evx.js +0 -2244
  521. package/dist/rich-text-editor-CyggTOLQ.cjs +0 -2908
  522. package/dist/rich-text-editor-DbV-S7Fi.cjs +0 -2261
  523. package/dist/rich-text-editor-DoCkKhzk.cjs +0 -2919
  524. package/dist/rich-text-editor-DqLICivI.js +0 -2832
  525. package/dist/rich-text-editor-DxO1Hz3a.cjs +0 -2903
  526. package/dist/rich-text-editor-GS2kpTAK.cjs +0 -2966
  527. package/dist/routes.d.ts +0 -10
  528. package/dist/select-Cmb8zF7w.cjs +0 -156
  529. package/dist/select-CprSNX0z.js +0 -139
  530. package/dist/select-DT7Zjn42.cjs +0 -162
  531. package/dist/select-En8DkoaQ.js +0 -145
  532. package/dist/sidebar-B3EYhli0.cjs +0 -800
  533. package/dist/sidebar-B4ZWaMrE.js +0 -792
  534. package/dist/sidebar-B9NR0lCe.cjs +0 -800
  535. package/dist/sidebar-BcJ6LxvX.cjs +0 -733
  536. package/dist/sidebar-BvF5I2Ue.cjs +0 -800
  537. package/dist/sidebar-C5B_LHek.cjs +0 -795
  538. package/dist/sidebar-CA6_ek3f.js +0 -801
  539. package/dist/sidebar-CRMiBtAi.js +0 -801
  540. package/dist/sidebar-CVUGHOS_.cjs +0 -756
  541. package/dist/sidebar-CZ2mWaMM.cjs +0 -800
  542. package/dist/sidebar-CmvwjnVb.js +0 -757
  543. package/dist/sidebar-CplprZpM.js +0 -801
  544. package/dist/sidebar-DyYvgyBj.cjs +0 -795
  545. package/dist/sidebar-Dz7bd3zP.js +0 -796
  546. package/dist/sidebar-KIS0C2JH.js +0 -801
  547. package/dist/sidebar-OTO_up7Z.js +0 -801
  548. package/dist/sidebar-WoKvFWCN.js +0 -717
  549. package/dist/sidebar-zowjejT2.cjs +0 -800
  550. package/dist/skeleton-4zoHiFJ_.cjs +0 -83
  551. package/dist/skeleton-C4bHqUBf.js +0 -84
  552. package/dist/slider-C0JKA9k3.js +0 -56
  553. package/dist/slider-CPmwzm_3.cjs +0 -73
  554. package/dist/slider-DcJharR9.cjs +0 -73
  555. package/dist/slider-Pay3fka2.js +0 -56
  556. package/dist/sonner-DeUIj0Zg.cjs +0 -63
  557. package/dist/sonner-g9RIfi35.js +0 -47
  558. package/dist/tooltip-CNtsL5cB.cjs +0 -71
  559. package/dist/tooltip-CTyZCD8h.js +0 -55
  560. package/dist/tooltip-CwgSdy3h.cjs +0 -67
  561. package/dist/tooltip-D-OrYnKO.js +0 -51
  562. package/dist/use-audio-player-BJFV24XW.js +0 -188
  563. package/dist/use-audio-player-Bkh23vQ3.js +0 -177
  564. package/dist/use-audio-player-Dn1NR9xN.cjs +0 -176
  565. package/dist/use-audio-player-DyVYlOnR.cjs +0 -187
  566. package/dist/use-mobile-BB4M_4Ru.cjs +0 -47
  567. package/dist/use-mobile-CLu9nqGL.js +0 -31
  568. package/dist/use-mobile-CNwiBNxu.js +0 -33
  569. package/dist/use-mobile-Dlf74ufz.cjs +0 -49
  570. package/dist/xertica-assistant-B1IaHXnB.cjs +0 -1894
  571. package/dist/xertica-assistant-BMqdyRVi.js +0 -2082
  572. package/dist/xertica-assistant-BbgzsgsG.js +0 -2164
  573. package/dist/xertica-assistant-Bj3vBCq_.cjs +0 -2081
  574. package/dist/xertica-assistant-CfBCo21g.js +0 -2148
  575. package/dist/xertica-assistant-DIM_Do1k.js +0 -1866
  576. package/dist/xertica-assistant-DPsESB6t.js +0 -1878
  577. package/dist/xertica-assistant-DrsRwla1.cjs +0 -2147
  578. package/dist/xertica-assistant-Qp3ydksa.cjs +0 -1882
  579. package/dist/xertica-assistant-d2qs2Vd9.cjs +0 -2163
  580. package/dist/xertica-assistant-gnCJdcZY.js +0 -1866
  581. package/dist/xertica-assistant-yyrR0JKl.cjs +0 -1882
  582. package/styles/xertica/app-overrides/scrollbar.css +0 -33
  583. 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)