xertica-ui 2.2.1 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (708) hide show
  1. package/CHANGELOG.md +564 -525
  2. package/README.md +417 -382
  3. package/bin/cli.ts +1244 -748
  4. package/bin/generate-tokens.ts +262 -262
  5. package/bin/language-config.ts +5 -8
  6. package/components/assets/xertica-orbe-animation.ts +1162 -1162
  7. package/components/assistant/code-block/CodeBlock.tsx +268 -268
  8. package/components/assistant/code-block/code-block.stories.tsx +57 -57
  9. package/components/assistant/code-block/code-block.test.tsx +44 -44
  10. package/components/assistant/code-block/index.ts +1 -1
  11. package/components/assistant/formatted-document/FormattedDocument.tsx +147 -147
  12. package/components/assistant/formatted-document/formatted-document.stories.tsx +51 -51
  13. package/components/assistant/formatted-document/formatted-document.test.tsx +42 -42
  14. package/components/assistant/formatted-document/index.ts +1 -1
  15. package/components/assistant/index.ts +6 -6
  16. package/components/assistant/markdown-message/MarkdownMessage.tsx +152 -152
  17. package/components/assistant/markdown-message/index.ts +1 -1
  18. package/components/assistant/markdown-message/markdown-message.stories.tsx +50 -50
  19. package/components/assistant/markdown-message/markdown-message.test.tsx +33 -33
  20. package/components/assistant/modern-chat-input/ModernChatInput.tsx +17 -7
  21. package/components/assistant/modern-chat-input/index.ts +1 -1
  22. package/components/assistant/modern-chat-input/modern-chat-input.stories.tsx +131 -131
  23. package/components/assistant/modern-chat-input/modern-chat-input.test.tsx +79 -79
  24. package/components/assistant/xertica-assistant/index.ts +3 -3
  25. package/components/assistant/xertica-assistant/parts/AssistantCollapsedView.tsx +99 -99
  26. package/components/assistant/xertica-assistant/parts/AssistantConversationList.tsx +104 -106
  27. package/components/assistant/xertica-assistant/parts/AssistantDocumentEditor.tsx +81 -81
  28. package/components/assistant/xertica-assistant/parts/AssistantFeedbackDialog.tsx +88 -78
  29. package/components/assistant/xertica-assistant/parts/AssistantHeader.tsx +75 -75
  30. package/components/assistant/xertica-assistant/parts/AssistantMessageBubble.tsx +564 -560
  31. package/components/assistant/xertica-assistant/parts/AssistantTabBar.tsx +67 -67
  32. package/components/assistant/xertica-assistant/parts/AssistantTypingIndicator.tsx +41 -41
  33. package/components/assistant/xertica-assistant/parts/AssistantWelcomeScreen.tsx +103 -103
  34. package/components/assistant/xertica-assistant/parts/index.ts +16 -16
  35. package/components/assistant/xertica-assistant/types.ts +134 -134
  36. package/components/assistant/xertica-assistant/use-assistant.ts +615 -615
  37. package/components/assistant/xertica-assistant/xertica-assistant.stories.tsx +407 -407
  38. package/components/assistant/xertica-assistant/xertica-assistant.test.tsx +65 -65
  39. package/components/assistant/xertica-assistant/xertica-assistant.tsx +611 -613
  40. package/components/blocks/card-patterns/ActivityCard.tsx +100 -100
  41. package/components/blocks/card-patterns/FeatureCard.tsx +109 -109
  42. package/components/blocks/card-patterns/FeatureCardSkeleton.tsx +1 -6
  43. package/components/blocks/card-patterns/NotificationCard.tsx +140 -140
  44. package/components/blocks/card-patterns/ProfileCard.tsx +112 -114
  45. package/components/blocks/card-patterns/ProjectCard.tsx +123 -123
  46. package/components/blocks/card-patterns/ProjectCardSkeleton.tsx +1 -6
  47. package/components/blocks/card-patterns/QuickActionCard.tsx +68 -68
  48. package/components/blocks/card-patterns/card-patterns.mdx +123 -123
  49. package/components/blocks/card-patterns/card-patterns.stories.tsx +594 -594
  50. package/components/blocks/card-patterns/index.ts +29 -29
  51. package/components/blocks/index.ts +1 -1
  52. package/components/brand/branding/branding.stories.tsx +57 -57
  53. package/components/brand/index.ts +6 -6
  54. package/components/brand/language-selector/index.ts +1 -1
  55. package/components/brand/language-selector/language-selector.mdx +126 -126
  56. package/components/brand/language-selector/language-selector.stories.tsx +1 -4
  57. package/components/brand/theme-toggle/ThemeToggle.tsx +74 -70
  58. package/components/brand/theme-toggle/index.ts +1 -1
  59. package/components/brand/theme-toggle/theme-toggle.stories.tsx +34 -34
  60. package/components/brand/theme-toggle/theme-toggle.test.tsx +34 -34
  61. package/components/brand/xertica-logo/XerticaLogo.stories.tsx +82 -82
  62. package/components/brand/xertica-logo/XerticaLogo.tsx +104 -104
  63. package/components/brand/xertica-logo/index.ts +1 -1
  64. package/components/brand/xertica-logo/xertica-logo.test.tsx +26 -26
  65. package/components/brand/xertica-orbe/XerticaOrbe.tsx +1927 -1927
  66. package/components/brand/xertica-orbe/index.ts +1 -1
  67. package/components/brand/xertica-orbe/xertica-orbe.stories.tsx +40 -40
  68. package/components/brand/xertica-orbe/xertica-orbe.test.tsx +19 -19
  69. package/components/brand/xertica-provider/XerticaProvider.tsx +1 -4
  70. package/components/brand/xertica-provider/index.ts +1 -1
  71. package/components/brand/xertica-provider/xertica-provider.test.tsx +74 -74
  72. package/components/brand/xertica-xlogo/XerticaXLogo.stories.tsx +79 -79
  73. package/components/brand/xertica-xlogo/XerticaXLogo.tsx +65 -65
  74. package/components/brand/xertica-xlogo/index.ts +1 -1
  75. package/components/brand/xertica-xlogo/xertica-xlogo.test.tsx +16 -16
  76. package/components/examples/ApiKeyMapExample.tsx +71 -71
  77. package/components/examples/DrawingMapExample.tsx +565 -565
  78. package/components/examples/FilterableMapExample.tsx +393 -393
  79. package/components/examples/LocationPickerExample.tsx +348 -348
  80. package/components/examples/MapExamples.tsx +268 -268
  81. package/components/examples/MapGmpExample.tsx +169 -169
  82. package/components/examples/MapShowcase.tsx +471 -471
  83. package/components/examples/RouteMapExamples.tsx +329 -329
  84. package/components/examples/SidebarLogoExample.tsx +65 -65
  85. package/components/examples/SimpleFilterableMap.tsx +219 -219
  86. package/components/examples/index.ts +45 -45
  87. package/components/figma/ImageWithFallback.tsx +27 -27
  88. package/components/hooks/index.ts +13 -13
  89. package/components/hooks/use-layout-shortcuts.ts +43 -43
  90. package/components/index.ts +86 -90
  91. package/components/layout/header/header.stories.tsx +204 -204
  92. package/components/layout/header/header.test.tsx +75 -75
  93. package/components/layout/header/header.tsx +349 -349
  94. package/components/layout/header/index.ts +1 -1
  95. package/components/layout/index.ts +2 -2
  96. package/components/layout/sidebar/index.ts +3 -3
  97. package/components/layout/sidebar/sidebar.stories.tsx +586 -586
  98. package/components/layout/sidebar/sidebar.test.tsx +76 -76
  99. package/components/layout/sidebar/sidebar.tsx +1079 -1073
  100. package/components/layout/sidebar/use-sidebar.ts +104 -104
  101. package/components/media/FloatingMediaWrapper.tsx +371 -371
  102. package/components/media/audio-player/AudioPlayer.stories.tsx +124 -124
  103. package/components/media/audio-player/AudioPlayer.test.tsx +106 -106
  104. package/components/media/audio-player/AudioPlayer.tsx +767 -765
  105. package/components/media/audio-player/index.ts +1 -1
  106. package/components/media/audio-player/use-audio-player.ts +312 -312
  107. package/components/media/index.ts +3 -3
  108. package/components/media/video-player/VideoPlayer.stories.tsx +98 -98
  109. package/components/media/video-player/VideoPlayer.test.tsx +73 -73
  110. package/components/media/video-player/VideoPlayer.tsx +310 -310
  111. package/components/media/video-player/index.ts +1 -1
  112. package/components/pages/forgot-password-page/ForgotPasswordPage.stories.tsx +24 -24
  113. package/components/pages/forgot-password-page/ForgotPasswordPage.tsx +188 -188
  114. package/components/pages/forgot-password-page/forgot-password-page.test.tsx +45 -45
  115. package/components/pages/forgot-password-page/index.ts +1 -1
  116. package/components/pages/home-content/HomeContent.stories.tsx +43 -43
  117. package/components/pages/home-content/HomeContent.tsx +120 -120
  118. package/components/pages/home-content/index.ts +1 -1
  119. package/components/pages/home-page/HomePage.stories.tsx +39 -39
  120. package/components/pages/home-page/HomePage.tsx +78 -74
  121. package/components/pages/home-page/home-page.test.tsx +53 -53
  122. package/components/pages/home-page/index.ts +1 -1
  123. package/components/pages/index.ts +8 -8
  124. package/components/pages/login-page/LoginPage.stories.tsx +39 -39
  125. package/components/pages/login-page/LoginPage.tsx +218 -216
  126. package/components/pages/login-page/index.ts +1 -1
  127. package/components/pages/login-page/login-page.test.tsx +63 -63
  128. package/components/pages/reset-password-page/ResetPasswordPage.stories.tsx +24 -24
  129. package/components/pages/reset-password-page/ResetPasswordPage.tsx +243 -239
  130. package/components/pages/reset-password-page/index.ts +1 -1
  131. package/components/pages/template-content/TemplateContent.stories.tsx +43 -43
  132. package/components/pages/template-content/TemplateContent.tsx +1354 -1235
  133. package/components/pages/template-content/index.ts +1 -1
  134. package/components/pages/template-page/TemplatePage.stories.tsx +39 -39
  135. package/components/pages/template-page/TemplatePage.tsx +62 -62
  136. package/components/pages/template-page/index.ts +1 -1
  137. package/components/pages/template-page/template-page.test.tsx +52 -52
  138. package/components/pages/verify-email-page/VerifyEmailPage.stories.tsx +41 -41
  139. package/components/pages/verify-email-page/VerifyEmailPage.tsx +206 -206
  140. package/components/pages/verify-email-page/index.ts +1 -1
  141. package/components/public-api-smoke.test.tsx +52 -52
  142. package/components/shared/CustomTooltipContent.tsx +48 -48
  143. package/components/shared/assistant-utils.test.ts +16 -16
  144. package/components/shared/assistant-utils.ts +225 -225
  145. package/components/shared/error-boundary.stories.tsx +114 -132
  146. package/components/shared/error-boundary.tsx +150 -154
  147. package/components/shared/error-fallbacks.tsx +222 -226
  148. package/components/shared/layout-constants.ts +8 -8
  149. package/components/shared/navigation.ts +35 -35
  150. package/components/shared/use-mobile.test.ts +16 -16
  151. package/components/shared/use-mobile.ts +36 -36
  152. package/components/shared/utils.test.ts +14 -14
  153. package/components/shared/utils.ts +6 -6
  154. package/components/ui/accordion/accordion.stories.tsx +105 -105
  155. package/components/ui/accordion/accordion.test.tsx +59 -59
  156. package/components/ui/accordion/accordion.tsx +77 -77
  157. package/components/ui/accordion/index.ts +1 -1
  158. package/components/ui/alert/alert.stories.tsx +86 -86
  159. package/components/ui/alert/alert.test.tsx +53 -53
  160. package/components/ui/alert/alert.tsx +93 -93
  161. package/components/ui/alert/index.ts +1 -1
  162. package/components/ui/alert-dialog/alert-dialog.stories.tsx +84 -84
  163. package/components/ui/alert-dialog/alert-dialog.test.tsx +70 -70
  164. package/components/ui/alert-dialog/alert-dialog.tsx +149 -149
  165. package/components/ui/alert-dialog/index.ts +1 -1
  166. package/components/ui/aspect-ratio/aspect-ratio.stories.tsx +46 -46
  167. package/components/ui/aspect-ratio/aspect-ratio.test.tsx +28 -28
  168. package/components/ui/aspect-ratio/aspect-ratio.tsx +20 -20
  169. package/components/ui/aspect-ratio/index.ts +1 -1
  170. package/components/ui/assistant-chart/AssistantChart.tsx +64 -64
  171. package/components/ui/assistant-chart/assistant-chart.stories.tsx +44 -44
  172. package/components/ui/assistant-chart/assistant-chart.test.tsx +46 -46
  173. package/components/ui/assistant-chart/index.ts +1 -1
  174. package/components/ui/avatar/avatar.stories.tsx +86 -86
  175. package/components/ui/avatar/avatar.test.tsx +55 -55
  176. package/components/ui/avatar/avatar.tsx +71 -71
  177. package/components/ui/avatar/index.ts +1 -1
  178. package/components/ui/badge/badge.stories.tsx +72 -72
  179. package/components/ui/badge/badge.test.tsx +40 -40
  180. package/components/ui/badge/badge.tsx +58 -58
  181. package/components/ui/badge/index.ts +1 -1
  182. package/components/ui/breadcrumb/breadcrumb.stories.tsx +123 -123
  183. package/components/ui/breadcrumb/breadcrumb.test.tsx +70 -70
  184. package/components/ui/breadcrumb/breadcrumb.tsx +114 -114
  185. package/components/ui/breadcrumb/index.ts +1 -1
  186. package/components/ui/button/button.stories.tsx +183 -183
  187. package/components/ui/button/button.test.tsx +64 -64
  188. package/components/ui/button/button.tsx +98 -98
  189. package/components/ui/button/index.ts +1 -1
  190. package/components/ui/calendar/calendar.stories.tsx +108 -108
  191. package/components/ui/calendar/calendar.test.tsx +53 -53
  192. package/components/ui/calendar/calendar.tsx +230 -230
  193. package/components/ui/calendar/index.ts +1 -1
  194. package/components/ui/card/card.stories.tsx +301 -301
  195. package/components/ui/card/card.test.tsx +55 -55
  196. package/components/ui/card/card.tsx +83 -83
  197. package/components/ui/card/index.ts +1 -1
  198. package/components/ui/carousel/carousel.stories.tsx +80 -80
  199. package/components/ui/carousel/carousel.test.tsx +75 -75
  200. package/components/ui/carousel/carousel.tsx +242 -242
  201. package/components/ui/carousel/index.ts +1 -1
  202. package/components/ui/chart/chart.stories.tsx +1328 -1328
  203. package/components/ui/chart/chart.test.tsx +178 -178
  204. package/components/ui/chart/chart.tsx +2232 -2232
  205. package/components/ui/chart/index.ts +1 -1
  206. package/components/ui/checkbox/checkbox.stories.tsx +109 -109
  207. package/components/ui/checkbox/checkbox.test.tsx +49 -49
  208. package/components/ui/checkbox/checkbox.tsx +68 -68
  209. package/components/ui/checkbox/index.ts +1 -1
  210. package/components/ui/collapsible/collapsible.stories.tsx +45 -45
  211. package/components/ui/collapsible/collapsible.test.tsx +51 -51
  212. package/components/ui/collapsible/collapsible.tsx +32 -32
  213. package/components/ui/collapsible/index.ts +1 -1
  214. package/components/ui/command/command.stories.tsx +134 -134
  215. package/components/ui/command/command.test.tsx +48 -48
  216. package/components/ui/command/command.tsx +163 -163
  217. package/components/ui/command/index.ts +1 -1
  218. package/components/ui/context-menu/context-menu.stories.tsx +76 -76
  219. package/components/ui/context-menu/context-menu.test.tsx +61 -61
  220. package/components/ui/context-menu/context-menu.tsx +236 -236
  221. package/components/ui/context-menu/index.ts +1 -1
  222. package/components/ui/dialog/dialog.stories.tsx +174 -174
  223. package/components/ui/dialog/dialog.test.tsx +78 -78
  224. package/components/ui/dialog/dialog.tsx +189 -189
  225. package/components/ui/dialog/index.ts +1 -1
  226. package/components/ui/drawer/drawer.stories.tsx +71 -71
  227. package/components/ui/drawer/drawer.test.tsx +67 -67
  228. package/components/ui/drawer/drawer.tsx +146 -146
  229. package/components/ui/drawer/index.ts +1 -1
  230. package/components/ui/dropdown-menu/dropdown-menu.stories.tsx +156 -156
  231. package/components/ui/dropdown-menu/dropdown-menu.test.tsx +62 -62
  232. package/components/ui/dropdown-menu/dropdown-menu.tsx +240 -240
  233. package/components/ui/dropdown-menu/index.ts +1 -1
  234. package/components/ui/empty/empty.stories.tsx +85 -85
  235. package/components/ui/empty/empty.test.tsx +31 -31
  236. package/components/ui/empty/empty.tsx +88 -88
  237. package/components/ui/empty/index.ts +1 -1
  238. package/components/ui/file-upload/file-upload.stories.tsx +144 -144
  239. package/components/ui/file-upload/file-upload.test.tsx +65 -65
  240. package/components/ui/file-upload/file-upload.tsx +142 -142
  241. package/components/ui/file-upload/index.ts +2 -2
  242. package/components/ui/file-upload/use-file-upload.ts +177 -177
  243. package/components/ui/form/form.stories.tsx +85 -85
  244. package/components/ui/form/form.test.tsx +75 -75
  245. package/components/ui/form/form.tsx +163 -163
  246. package/components/ui/form/index.ts +1 -1
  247. package/components/ui/google-maps-loader/google-maps-loader.test.tsx +35 -35
  248. package/components/ui/google-maps-loader/google-maps-loader.tsx +465 -465
  249. package/components/ui/google-maps-loader/index.ts +1 -1
  250. package/components/ui/hover-card/hover-card.stories.tsx +61 -61
  251. package/components/ui/hover-card/hover-card.test.tsx +48 -48
  252. package/components/ui/hover-card/hover-card.tsx +50 -50
  253. package/components/ui/hover-card/index.ts +1 -1
  254. package/components/ui/index.ts +400 -400
  255. package/components/ui/input/index.ts +1 -1
  256. package/components/ui/input/input.stories.tsx +153 -153
  257. package/components/ui/input/input.test.tsx +47 -47
  258. package/components/ui/input/input.tsx +57 -57
  259. package/components/ui/input-otp/index.ts +1 -1
  260. package/components/ui/input-otp/input-otp.stories.tsx +120 -120
  261. package/components/ui/input-otp/input-otp.test.tsx +74 -74
  262. package/components/ui/input-otp/input-otp.tsx +101 -101
  263. package/components/ui/label/index.ts +1 -1
  264. package/components/ui/label/label.stories.tsx +74 -74
  265. package/components/ui/label/label.test.tsx +45 -45
  266. package/components/ui/label/label.tsx +53 -53
  267. package/components/ui/map/index.ts +1 -1
  268. package/components/ui/map/map.stories.tsx +86 -86
  269. package/components/ui/map/map.test.tsx +82 -82
  270. package/components/ui/map/map.tsx +506 -506
  271. package/components/ui/map/mock.test.tsx +13 -13
  272. package/components/ui/map-config/index.ts +1 -1
  273. package/components/ui/map-config/map-config.ts +18 -18
  274. package/components/ui/map-layers/index.ts +1 -1
  275. package/components/ui/map-layers/map-layers.test.tsx +48 -48
  276. package/components/ui/map-layers/map-layers.tsx +126 -126
  277. package/components/ui/map.exports/index.ts +1 -1
  278. package/components/ui/map.exports/map.exports.ts +31 -31
  279. package/components/ui/menubar/index.ts +1 -1
  280. package/components/ui/menubar/menubar.stories.tsx +130 -130
  281. package/components/ui/menubar/menubar.test.tsx +53 -53
  282. package/components/ui/menubar/menubar.tsx +265 -265
  283. package/components/ui/navigation-menu/index.ts +1 -1
  284. package/components/ui/navigation-menu/navigation-menu.stories.tsx +126 -126
  285. package/components/ui/navigation-menu/navigation-menu.test.tsx +47 -47
  286. package/components/ui/navigation-menu/navigation-menu.tsx +165 -165
  287. package/components/ui/notification-badge/index.ts +1 -1
  288. package/components/ui/notification-badge/notification-badge.stories.tsx +66 -66
  289. package/components/ui/notification-badge/notification-badge.test.tsx +61 -61
  290. package/components/ui/notification-badge/notification-badge.tsx +91 -91
  291. package/components/ui/page-header/index.ts +1 -1
  292. package/components/ui/page-header/page-header.stories.tsx +69 -69
  293. package/components/ui/page-header/page-header.test.tsx +37 -37
  294. package/components/ui/page-header/page-header.tsx +124 -124
  295. package/components/ui/pagination/index.ts +3 -3
  296. package/components/ui/pagination/pagination.stories.tsx +210 -210
  297. package/components/ui/pagination/pagination.test.tsx +63 -63
  298. package/components/ui/pagination/pagination.tsx +140 -140
  299. package/components/ui/pagination/use-pagination.ts +173 -173
  300. package/components/ui/popover/index.ts +1 -1
  301. package/components/ui/popover/popover.stories.tsx +73 -73
  302. package/components/ui/popover/popover.test.tsx +48 -48
  303. package/components/ui/popover/popover.tsx +54 -54
  304. package/components/ui/progress/index.ts +1 -1
  305. package/components/ui/progress/progress.stories.tsx +55 -55
  306. package/components/ui/progress/progress.test.tsx +23 -23
  307. package/components/ui/progress/progress.tsx +68 -68
  308. package/components/ui/radio-group/index.ts +1 -1
  309. package/components/ui/radio-group/radio-group.stories.tsx +114 -114
  310. package/components/ui/radio-group/radio-group.test.tsx +78 -78
  311. package/components/ui/radio-group/radio-group.tsx +93 -93
  312. package/components/ui/rating/index.ts +1 -1
  313. package/components/ui/rating/rating.stories.tsx +50 -50
  314. package/components/ui/rating/rating.test.tsx +48 -48
  315. package/components/ui/rating/rating.tsx +145 -145
  316. package/components/ui/resizable/index.ts +1 -1
  317. package/components/ui/resizable/resizable.stories.tsx +88 -88
  318. package/components/ui/resizable/resizable.test.tsx +61 -61
  319. package/components/ui/resizable/resizable.tsx +452 -452
  320. package/components/ui/rich-text-editor/index.ts +7 -7
  321. package/components/ui/rich-text-editor/rich-text-editor.stories.tsx +290 -290
  322. package/components/ui/rich-text-editor/rich-text-editor.test.tsx +86 -86
  323. package/components/ui/rich-text-editor/rich-text-editor.tsx +634 -634
  324. package/components/ui/rich-text-editor/use-rich-text-editor.ts +453 -453
  325. package/components/ui/route-map/index.ts +1 -1
  326. package/components/ui/route-map/route-map.stories.tsx +48 -48
  327. package/components/ui/route-map/route-map.test.tsx +108 -108
  328. package/components/ui/route-map/route-map.tsx +349 -349
  329. package/components/ui/scroll-area/index.ts +1 -1
  330. package/components/ui/scroll-area/scroll-area.stories.tsx +31 -31
  331. package/components/ui/scroll-area/scroll-area.test.tsx +27 -27
  332. package/components/ui/scroll-area/scroll-area.tsx +70 -70
  333. package/components/ui/search/index.ts +1 -1
  334. package/components/ui/search/search.stories.tsx +107 -107
  335. package/components/ui/search/search.test.tsx +67 -67
  336. package/components/ui/search/search.tsx +141 -141
  337. package/components/ui/select/index.ts +1 -1
  338. package/components/ui/select/select.stories.tsx +163 -163
  339. package/components/ui/select/select.test.tsx +99 -99
  340. package/components/ui/select/select.tsx +195 -195
  341. package/components/ui/separator/index.ts +1 -1
  342. package/components/ui/separator/separator.stories.tsx +55 -55
  343. package/components/ui/separator/separator.test.tsx +23 -23
  344. package/components/ui/separator/separator.tsx +39 -39
  345. package/components/ui/sheet/index.ts +1 -1
  346. package/components/ui/sheet/sheet.stories.tsx +93 -93
  347. package/components/ui/sheet/sheet.test.tsx +62 -62
  348. package/components/ui/sheet/sheet.tsx +149 -149
  349. package/components/ui/simple-map/index.ts +1 -1
  350. package/components/ui/simple-map/simple-map.stories.tsx +44 -44
  351. package/components/ui/simple-map/simple-map.test.tsx +36 -36
  352. package/components/ui/simple-map/simple-map.tsx +92 -92
  353. package/components/ui/skeleton/index.ts +1 -1
  354. package/components/ui/skeleton/skeleton.stories.tsx +36 -36
  355. package/components/ui/skeleton/skeleton.test.tsx +19 -19
  356. package/components/ui/skeleton/skeleton.tsx +25 -25
  357. package/components/ui/slider/index.ts +1 -1
  358. package/components/ui/slider/slider.stories.tsx +44 -44
  359. package/components/ui/slider/slider.test.tsx +25 -25
  360. package/components/ui/slider/slider.tsx +66 -66
  361. package/components/ui/sonner/index.ts +1 -1
  362. package/components/ui/sonner/sonner.stories.tsx +41 -41
  363. package/components/ui/sonner/sonner.test.tsx +24 -24
  364. package/components/ui/sonner/sonner.tsx +74 -74
  365. package/components/ui/stats-card/index.ts +2 -2
  366. package/components/ui/stats-card/stats-card-skeleton.tsx +1 -3
  367. package/components/ui/stats-card/stats-card.stories.tsx +99 -99
  368. package/components/ui/stats-card/stats-card.test.tsx +34 -34
  369. package/components/ui/stats-card/stats-card.tsx +93 -93
  370. package/components/ui/stepper/index.ts +3 -3
  371. package/components/ui/stepper/stepper.stories.tsx +171 -171
  372. package/components/ui/stepper/stepper.test.tsx +47 -47
  373. package/components/ui/stepper/stepper.tsx +190 -190
  374. package/components/ui/stepper/use-stepper.ts +139 -139
  375. package/components/ui/switch/index.ts +1 -1
  376. package/components/ui/switch/switch.stories.tsx +93 -93
  377. package/components/ui/switch/switch.test.tsx +44 -44
  378. package/components/ui/switch/switch.tsx +70 -70
  379. package/components/ui/table/index.ts +1 -1
  380. package/components/ui/table/table.stories.tsx +114 -114
  381. package/components/ui/table/table.test.tsx +43 -43
  382. package/components/ui/table/table.tsx +104 -104
  383. package/components/ui/tabs/index.ts +1 -1
  384. package/components/ui/tabs/tabs.stories.tsx +140 -140
  385. package/components/ui/tabs/tabs.test.tsx +50 -50
  386. package/components/ui/tabs/tabs.tsx +66 -66
  387. package/components/ui/textarea/index.ts +1 -1
  388. package/components/ui/textarea/textarea.stories.tsx +69 -69
  389. package/components/ui/textarea/textarea.test.tsx +41 -41
  390. package/components/ui/textarea/textarea.tsx +61 -61
  391. package/components/ui/timeline/index.ts +1 -1
  392. package/components/ui/timeline/timeline.stories.tsx +97 -97
  393. package/components/ui/timeline/timeline.test.tsx +53 -53
  394. package/components/ui/timeline/timeline.tsx +124 -124
  395. package/components/ui/toggle/index.ts +1 -1
  396. package/components/ui/toggle/toggle.stories.tsx +56 -56
  397. package/components/ui/toggle/toggle.test.tsx +32 -32
  398. package/components/ui/toggle/toggle.tsx +55 -55
  399. package/components/ui/toggle-group/index.ts +1 -1
  400. package/components/ui/toggle-group/toggle-group.stories.tsx +66 -66
  401. package/components/ui/toggle-group/toggle-group.test.tsx +47 -47
  402. package/components/ui/toggle-group/toggle-group.tsx +79 -79
  403. package/components/ui/tooltip/index.ts +1 -1
  404. package/components/ui/tooltip/tooltip.stories.tsx +83 -83
  405. package/components/ui/tooltip/tooltip.test.tsx +39 -39
  406. package/components/ui/tooltip/tooltip.tsx +69 -69
  407. package/components/ui/tree-view/index.ts +4 -4
  408. package/components/ui/tree-view/tree-view.stories.tsx +154 -154
  409. package/components/ui/tree-view/tree-view.test.tsx +58 -58
  410. package/components/ui/tree-view/tree-view.tsx +171 -171
  411. package/components/ui/tree-view/use-tree-view.ts +237 -237
  412. package/components.json +892 -892
  413. package/contexts/ApiKeyContext.test.tsx +26 -26
  414. package/contexts/ApiKeyContext.tsx +196 -196
  415. package/contexts/AssistenteContext.test.tsx +17 -17
  416. package/contexts/AssistenteContext.tsx +113 -113
  417. package/contexts/AuthContext.tsx +121 -118
  418. package/contexts/BrandColorsContext.test.tsx +21 -21
  419. package/contexts/BrandColorsContext.tsx +251 -251
  420. package/contexts/LanguageContext.tsx +1 -2
  421. package/contexts/LayoutContext.test.tsx +29 -29
  422. package/contexts/LayoutContext.tsx +140 -140
  423. package/contexts/ThemeContext.test.tsx +38 -38
  424. package/contexts/ThemeContext.tsx +111 -111
  425. package/contexts/index.ts +8 -8
  426. package/contexts/theme-data.ts +340 -340
  427. package/dist/AssistantChart-COGiOV-g.cjs +3541 -0
  428. package/dist/AssistantChart-CWX1OWNM.js +3373 -0
  429. package/dist/AudioPlayer-9psiEucT.cjs +1282 -0
  430. package/dist/AudioPlayer-Dp2bD1Gk.js +1278 -0
  431. package/dist/BrandColorsContext-DZT7JjeD.js +659 -0
  432. package/dist/BrandColorsContext-awnBCmC4.cjs +666 -0
  433. package/dist/CodeBlock-DYkTfR0f.js +221 -0
  434. package/dist/CodeBlock-EOvp9cVu.cjs +223 -0
  435. package/dist/CustomTooltipContent-BhdIeBEg.cjs +54 -0
  436. package/dist/CustomTooltipContent-CNbVB2NS.js +33 -0
  437. package/dist/FeatureCard-BZ4CYxFf.cjs +497 -0
  438. package/dist/FeatureCard-DNycVGwT.js +485 -0
  439. package/dist/FeatureCardSkeleton-DZqc96mt.js +27 -0
  440. package/dist/FeatureCardSkeleton-pTa0YNKP.cjs +29 -0
  441. package/dist/LayoutContext-BEq_-n98.cjs +96 -0
  442. package/dist/LayoutContext-DNl1xSoX.js +92 -0
  443. package/dist/ThemeContext-CMD3z2Dz.cjs +1930 -0
  444. package/dist/ThemeContext-x_F2zsnv.js +1923 -0
  445. package/dist/VerifyEmailPage-BJjAMUTW.js +3223 -0
  446. package/dist/VerifyEmailPage-Bv8Ah_TK.cjs +3235 -0
  447. package/dist/VerifyEmailPage-CkBYfsNy.cjs +3232 -0
  448. package/dist/VerifyEmailPage-Cyl55sJb.js +3226 -0
  449. package/dist/VerifyEmailPage-X14vhdyl.js +3296 -0
  450. package/dist/VerifyEmailPage-u_Dn7t1U.cjs +3305 -0
  451. package/dist/XerticaOrbe-Uk2JML1-.cjs +1927 -0
  452. package/dist/XerticaOrbe-jA5T2iOk.js +1925 -0
  453. package/dist/XerticaProvider-BErr83Bg.js +42 -0
  454. package/dist/XerticaProvider-CwOkHxiT.cjs +44 -0
  455. package/dist/XerticaProvider-DUOJg9iX.js +49 -0
  456. package/dist/XerticaProvider-Dl_b72_l.cjs +51 -0
  457. package/dist/XerticaXLogo-BX3ueACh.js +255 -0
  458. package/dist/XerticaXLogo-mqjoBiLI.js +252 -0
  459. package/dist/XerticaXLogo-qBPhwK3g.cjs +260 -0
  460. package/dist/XerticaXLogo-uQgwns_E.cjs +257 -0
  461. package/dist/alert-dialog-DhwPioBa.cjs +885 -0
  462. package/dist/alert-dialog-DqlRW_An.js +831 -0
  463. package/dist/assistant.cjs.js +8 -4
  464. package/dist/assistant.es.js +5 -11
  465. package/dist/avatar-3kO2Anrp.js +54 -0
  466. package/dist/avatar-BCM7YQRC.cjs +77 -0
  467. package/dist/blocks.cjs.js +9 -4
  468. package/dist/blocks.es.js +2 -16
  469. package/dist/brand.cjs.js +10 -5
  470. package/dist/brand.es.js +3 -11
  471. package/dist/breadcrumb-BKtHF4gk.cjs +98 -0
  472. package/dist/breadcrumb-ifNsA7Zl.js +90 -0
  473. package/dist/button-0BlA47It.cjs +85 -0
  474. package/dist/button-DZHzN1Gd.js +62 -0
  475. package/dist/cli.js +471 -93
  476. package/dist/components/brand/theme-toggle/ThemeToggle.d.ts +1 -1
  477. package/dist/components/index.d.ts +1 -1
  478. package/dist/dropdown-menu-BMcykFDf.cjs +225 -0
  479. package/dist/dropdown-menu-Dn_eV2Xb.js +190 -0
  480. package/dist/google-maps-loader-BCe58h9D.js +308 -0
  481. package/dist/google-maps-loader-casMyxlo.cjs +316 -0
  482. package/dist/hooks.cjs.js +12 -8
  483. package/dist/hooks.es.js +10 -27
  484. package/dist/index-9GWd0qxq.cjs +12 -0
  485. package/dist/index-BabBx2pa.js +6 -0
  486. package/dist/index.cjs.js +37 -32
  487. package/dist/index.es.js +30 -363
  488. package/dist/input-C_UiS2Py.cjs +152 -0
  489. package/dist/input-cc-PTD4R.js +123 -0
  490. package/dist/layout.cjs.js +10 -6
  491. package/dist/layout.es.js +7 -9
  492. package/dist/media.cjs.js +8 -3
  493. package/dist/media.es.js +1 -6
  494. package/dist/pages.cjs.js +8 -3
  495. package/dist/pages.es.js +1 -11
  496. package/dist/progress-C7Lti5wo.js +80 -0
  497. package/dist/progress-Cqwxbqs1.cjs +103 -0
  498. package/dist/rich-text-editor-DqLICivI.js +2832 -0
  499. package/dist/rich-text-editor-DxO1Hz3a.cjs +2903 -0
  500. package/dist/select-CH6v_KcQ.cjs +161 -0
  501. package/dist/select-D-xvCZK2.js +130 -0
  502. package/dist/sidebar-3XyzjVBw.js +792 -0
  503. package/dist/sidebar-B4ZWaMrE.js +792 -0
  504. package/dist/sidebar-BS1p2V7t.cjs +795 -0
  505. package/dist/sidebar-DyYvgyBj.cjs +795 -0
  506. package/dist/skeleton-DjiHerJn.cjs +87 -0
  507. package/dist/skeleton-DtR5tkYe.js +78 -0
  508. package/dist/slider-B00b9SVK.cjs +78 -0
  509. package/dist/slider-DQCNUUMj.js +56 -0
  510. package/dist/sonner-B-jWlik1.cjs +68 -0
  511. package/dist/sonner-C9tiqj4f.js +47 -0
  512. package/dist/tooltip-D8n9UYoU.cjs +72 -0
  513. package/dist/tooltip-RtbSmPYJ.js +48 -0
  514. package/dist/ui.cjs.js +23 -18
  515. package/dist/ui.es.js +16 -303
  516. package/dist/use-audio-player-B78fd2ct.js +188 -0
  517. package/dist/use-audio-player-DGvhPrgR.cjs +190 -0
  518. package/dist/use-mobile-BdXTRb0Z.cjs +51 -0
  519. package/dist/use-mobile-Ce2cBAQe.js +29 -0
  520. package/dist/xertica-assistant-B1NaSFFj.js +2173 -0
  521. package/dist/xertica-assistant-B687qEPU.js +2165 -0
  522. package/dist/xertica-assistant-CIaUlbIt.cjs +2180 -0
  523. package/dist/xertica-assistant-sOHwTgIP.cjs +2172 -0
  524. package/dist/xertica-ui.css +1 -1
  525. package/docs/ai-usage.md +195 -195
  526. package/docs/architecture-improvements.md +456 -456
  527. package/docs/architecture.md +312 -306
  528. package/docs/components/accordion.md +109 -109
  529. package/docs/components/alert-dialog.md +127 -127
  530. package/docs/components/alert.md +106 -106
  531. package/docs/components/aspect-ratio.md +58 -58
  532. package/docs/components/assistant-chart.md +47 -47
  533. package/docs/components/assistant.md +428 -426
  534. package/docs/components/audio-player.md +167 -167
  535. package/docs/components/avatar.md +101 -101
  536. package/docs/components/badge.md +84 -84
  537. package/docs/components/branding.md +252 -252
  538. package/docs/components/breadcrumb.md +104 -104
  539. package/docs/components/button.md +156 -156
  540. package/docs/components/calendar.md +141 -141
  541. package/docs/components/card-patterns.md +447 -445
  542. package/docs/components/card.md +245 -245
  543. package/docs/components/carousel.md +100 -100
  544. package/docs/components/chart.md +638 -638
  545. package/docs/components/checkbox.md +88 -88
  546. package/docs/components/code-block.md +105 -105
  547. package/docs/components/collapsible.md +86 -86
  548. package/docs/components/command.md +113 -113
  549. package/docs/components/context-menu.md +81 -81
  550. package/docs/components/dialog.md +198 -198
  551. package/docs/components/drawer.md +105 -105
  552. package/docs/components/dropdown-menu.md +127 -127
  553. package/docs/components/empty.md +127 -127
  554. package/docs/components/error-boundary.md +201 -191
  555. package/docs/components/file-upload.md +189 -189
  556. package/docs/components/floating-media-wrapper.md +63 -63
  557. package/docs/components/form.md +177 -177
  558. package/docs/components/formatted-document.md +105 -105
  559. package/docs/components/google-maps-loader.md +44 -44
  560. package/docs/components/header.md +177 -177
  561. package/docs/components/hooks.md +432 -430
  562. package/docs/components/hover-card.md +86 -86
  563. package/docs/components/image-with-fallback.md +107 -107
  564. package/docs/components/input-otp.md +95 -95
  565. package/docs/components/input.md +130 -130
  566. package/docs/components/label.md +69 -69
  567. package/docs/components/language-selector.md +20 -16
  568. package/docs/components/map-layers.md +138 -138
  569. package/docs/components/map.md +84 -84
  570. package/docs/components/markdown-message.md +47 -47
  571. package/docs/components/menubar.md +89 -89
  572. package/docs/components/modern-chat-input.md +164 -164
  573. package/docs/components/navigation-menu.md +83 -83
  574. package/docs/components/notification-badge.md +78 -78
  575. package/docs/components/page-header.md +93 -93
  576. package/docs/components/pages.md +323 -309
  577. package/docs/components/pagination.md +334 -334
  578. package/docs/components/popover.md +116 -116
  579. package/docs/components/progress.md +103 -103
  580. package/docs/components/radio-group.md +133 -133
  581. package/docs/components/rating.md +77 -77
  582. package/docs/components/resizable.md +84 -84
  583. package/docs/components/rich-text-editor.md +255 -255
  584. package/docs/components/route-map.md +124 -124
  585. package/docs/components/scroll-area.md +58 -58
  586. package/docs/components/search.md +87 -87
  587. package/docs/components/select.md +144 -144
  588. package/docs/components/separator.md +58 -58
  589. package/docs/components/sheet.md +122 -122
  590. package/docs/components/sidebar.md +314 -314
  591. package/docs/components/simple-map.md +51 -51
  592. package/docs/components/skeleton.md +99 -99
  593. package/docs/components/slider.md +84 -84
  594. package/docs/components/sonner.md +115 -115
  595. package/docs/components/stats-card.md +120 -120
  596. package/docs/components/stepper.md +268 -268
  597. package/docs/components/switch.md +106 -106
  598. package/docs/components/table.md +138 -138
  599. package/docs/components/tabs.md +117 -117
  600. package/docs/components/textarea.md +86 -86
  601. package/docs/components/theme-toggle.md +73 -73
  602. package/docs/components/timeline.md +121 -121
  603. package/docs/components/toggle-group.md +68 -68
  604. package/docs/components/toggle.md +62 -62
  605. package/docs/components/tooltip.md +116 -116
  606. package/docs/components/tree-view.md +238 -238
  607. package/docs/components/use-mobile.md +96 -96
  608. package/docs/components/video-player.md +68 -68
  609. package/docs/components/xertica-logo.md +36 -36
  610. package/docs/components/xertica-orbe.md +35 -35
  611. package/docs/components/xertica-provider.md +65 -65
  612. package/docs/components/xertica-xlogo.md +35 -35
  613. package/docs/decision-tree.md +293 -293
  614. package/docs/doc-audit.md +244 -243
  615. package/docs/form-sizing.md +162 -162
  616. package/docs/getting-started.md +616 -591
  617. package/docs/guidelines.md +330 -328
  618. package/docs/i18n.md +61 -57
  619. package/docs/installation.md +268 -267
  620. package/docs/layout.md +143 -143
  621. package/docs/llms.md +295 -295
  622. package/docs/patterns/analytics.md +194 -194
  623. package/docs/patterns/crud.md +149 -149
  624. package/docs/patterns/dashboard.md +138 -138
  625. package/docs/patterns/detail-page.md +296 -296
  626. package/docs/patterns/form.md +241 -241
  627. package/docs/patterns/login.md +156 -156
  628. package/docs/patterns/settings.md +368 -368
  629. package/docs/patterns/wizard.md +213 -213
  630. package/docs/state-management.md +289 -289
  631. package/guidelines/Guidelines.md +409 -406
  632. package/hooks/useTheme.test.tsx +16 -16
  633. package/hooks/useTheme.ts +4 -4
  634. package/imports/Podcast.tsx +540 -540
  635. package/imports/XerticaAi.tsx +46 -46
  636. package/imports/XerticaX.tsx +15 -15
  637. package/imports/svg-aueiaqngck.ts +20 -20
  638. package/imports/svg-v9krss1ozd.ts +23 -23
  639. package/imports/svg-vhrdofe3qe.ts +6 -6
  640. package/llms-compact.txt +2 -1
  641. package/llms.txt +2 -1
  642. package/mcp/resources.json +22 -22
  643. package/mcp/tools.json +35 -35
  644. package/package.json +219 -213
  645. package/scripts/ai-validator.ts +91 -91
  646. package/scripts/cleanup-case-dupes.ts +62 -62
  647. package/scripts/generate-ai-manifests.ts +107 -107
  648. package/styles/globals.css +13 -13
  649. package/styles/xertica/app-overrides/chat.css +61 -61
  650. package/styles/xertica/app-overrides/scrollbar.css +33 -33
  651. package/styles/xertica/base.css +90 -71
  652. package/styles/xertica/integrations/google-maps.css +76 -76
  653. package/styles/xertica/integrations/sonner.css +73 -73
  654. package/styles/xertica/theme-map.css +102 -99
  655. package/styles/xertica/tokens.css +240 -236
  656. package/templates/CLAUDE.md +16 -1
  657. package/templates/eslint.config.js +26 -26
  658. package/templates/guidelines/Guidelines.md +577 -553
  659. package/templates/package.json +69 -69
  660. package/templates/postcss.config.js +6 -6
  661. package/templates/src/app/App.tsx +46 -46
  662. package/templates/src/app/components/AppLayout.tsx +55 -55
  663. package/templates/src/app/components/AuthGuard.tsx +131 -82
  664. package/templates/src/app/context/AuthContext.tsx +108 -108
  665. package/templates/src/features/assistant/index.ts +5 -5
  666. package/templates/src/features/auth/index.ts +4 -4
  667. package/templates/src/features/auth/ui/AuthPageShell.tsx +32 -32
  668. package/templates/src/features/auth/ui/ForgotPasswordContent.tsx +70 -72
  669. package/templates/src/features/auth/ui/LoginContent.tsx +92 -92
  670. package/templates/src/features/auth/ui/ResetPasswordContent.tsx +6 -2
  671. package/templates/src/features/auth/ui/SocialLoginButtons.tsx +78 -78
  672. package/templates/src/features/auth/ui/VerifyEmailContent.tsx +2 -6
  673. package/templates/src/features/home/data/mock.ts +41 -35
  674. package/templates/src/features/home/index.ts +11 -11
  675. package/templates/src/features/home/store/dashboardStore.ts +25 -25
  676. package/templates/src/features/home/ui/HomeContent.tsx +117 -119
  677. package/templates/src/features/template/index.ts +5 -5
  678. package/templates/src/features/template/ui/CrudTemplate.tsx +1 -4
  679. package/templates/src/features/template/ui/LoginTemplate.tsx +1 -1
  680. package/templates/src/features/template/ui/TemplateContent.tsx +29 -21
  681. package/templates/src/locales/en/pages/templates.json +17 -17
  682. package/templates/src/locales/es/pages/templates.json +17 -17
  683. package/templates/src/locales/pt-BR/pages/templates.json +17 -17
  684. package/templates/src/main.tsx +11 -11
  685. package/templates/src/pages/AssistantPage.tsx +26 -20
  686. package/templates/src/pages/ForgotPasswordPage.tsx +6 -6
  687. package/templates/src/pages/HomePage.tsx +53 -49
  688. package/templates/src/pages/LoginPage.tsx +10 -10
  689. package/templates/src/pages/ResetPasswordPage.tsx +6 -6
  690. package/templates/src/pages/TemplatePage.tsx +28 -28
  691. package/templates/src/pages/VerifyEmailPage.tsx +6 -6
  692. package/templates/src/shared/config/navigation.ts +19 -19
  693. package/templates/src/shared/error-boundary.tsx +150 -154
  694. package/templates/src/shared/error-fallbacks.tsx +222 -226
  695. package/templates/src/shared/lib/auth.ts +20 -20
  696. package/templates/src/shared/types/auth.ts +3 -3
  697. package/templates/src/styles/index.css +95 -95
  698. package/templates/src/styles/xertica/tokens.css +240 -236
  699. package/templates/tsconfig.json +25 -25
  700. package/templates/tsconfig.node.json +12 -12
  701. package/templates/vite-env.d.ts +1 -1
  702. package/templates/vite.config.js +20 -20
  703. package/templates/vite.config.ts +54 -51
  704. package/utils/color-utils.ts +72 -72
  705. package/utils/demo-responses.test.ts +10 -10
  706. package/utils/demo-responses.ts +151 -151
  707. package/utils/gemini.test.ts +25 -25
  708. package/utils/gemini.ts +155 -155
@@ -1,1235 +1,1354 @@
1
- import React, { useState } from 'react';
2
- import { Link, useNavigate } from 'react-router-dom';
3
- import { Button } from '../../ui/button';
4
- import { Input } from '../../ui/input';
5
- import { Label } from '../../ui/label';
6
- import {
7
- Card,
8
- CardHeader,
9
- CardTitle,
10
- CardDescription,
11
- CardContent,
12
- CardFooter,
13
- } from '../../ui/card';
14
- import { Tabs, TabsContent, TabsList, TabsTrigger } from '../../ui/tabs';
15
- import { Badge } from '../../ui/badge';
16
- import { Alert, AlertDescription, AlertTitle } from '../../ui/alert';
17
- import { Checkbox } from '../../ui/checkbox';
18
- import { RadioGroup, RadioGroupItem } from '../../ui/radio-group';
19
- import { Switch } from '../../ui/switch';
20
- import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../ui/select';
21
- import { Textarea } from '../../ui/textarea';
22
- import { Progress } from '../../ui/progress';
23
- import { Separator } from '../../ui/separator';
24
- import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '../../ui/table';
25
- import {
26
- Settings,
27
- User,
28
- Mail,
29
- Phone,
30
- Calendar,
31
- Search,
32
- Menu,
33
- ChevronRight,
34
- Home,
35
- Users,
36
- Plus,
37
- Trash2,
38
- Archive,
39
- ArrowRightLeft,
40
- History,
41
- PanelRight,
42
- FileEdit,
43
- Filter,
44
- Clock,
45
- Map,
46
- Bell,
47
- } from 'lucide-react';
48
- import { Slider } from '../../ui/slider';
49
- import { toast } from 'sonner';
50
- import { ScrollArea } from '../../ui/scroll-area';
51
- import { ThemeToggle } from '../../brand/theme-toggle';
52
- import { LanguageSelector } from '../../brand/language-selector';
53
- import { MapShowcase } from '../../examples/MapShowcase';
54
- import { Header } from '../../layout/header';
55
- import { Sidebar } from '../../layout/sidebar';
56
- import {
57
- Dialog,
58
- DialogTrigger,
59
- DialogContent,
60
- DialogHeader,
61
- DialogTitle,
62
- DialogDescription,
63
- DialogFooter,
64
- } from '../../ui/dialog';
65
- import {
66
- AlertDialog,
67
- AlertDialogTrigger,
68
- AlertDialogContent,
69
- AlertDialogHeader,
70
- AlertDialogTitle,
71
- AlertDialogDescription,
72
- AlertDialogFooter,
73
- AlertDialogAction,
74
- AlertDialogCancel,
75
- } from '../../ui/alert-dialog';
76
- import { PageHeader } from '../../ui/page-header';
77
-
78
- import { useOptionalLayout } from '../../../contexts/LayoutContext';
79
- import { useTeamMembers, useDashboardStore } from '../../../features/home';
80
- import { useTranslation } from 'react-i18next';
81
- import { SectionErrorBoundary } from '../../shared/error-boundary';
82
- import { Skeleton } from '../../ui/skeleton';
83
-
84
- /**
85
- * Comprehensive Showcase and Template Content component.
86
- *
87
- * @description
88
- * This component serves as a living kitchen-sink demonstration of the Xertica UI
89
- * Design System. It showcases almost every UI primitive (Cards, Tabs, Forms,
90
- * Tables, Dialogs, etc.) and layout variation (Header flexibility, Sidebar
91
- * toggling). It's primarily used for development, testing, and as a starting
92
- * point for new pages.
93
- *
94
- * @ai-rules
95
- * 1. Reference: Use this component as the primary source of truth for "how to compose" complex layouts in this library.
96
- * 2. Layout: Adjusts its own padding based on the `useLayout` context's sidebar state.
97
- * 3. Interaction: All showcase interactive elements (buttons, forms) use simple `toast` feedback or local state toggles.
98
- */
99
- export function TemplateContent() {
100
- const { t } = useTranslation();
101
- const layout = useOptionalLayout();
102
- const [localSidebarExpanded, setLocalSidebarExpanded] = useState(false);
103
- const [localSidebarWidth, setLocalSidebarWidth] = useState(280);
104
- const sidebarExpanded = layout?.sidebarExpanded ?? localSidebarExpanded;
105
- const sidebarWidth = layout?.sidebarWidth ?? localSidebarWidth;
106
- const setSidebarWidth = layout?.setSidebarWidth ?? setLocalSidebarWidth;
107
- const toggleSidebar = layout?.toggleSidebar ?? (() => setLocalSidebarExpanded(value => !value));
108
- const navigate = useNavigate();
109
-
110
- // Server state
111
- const { data: teamMembers = [], isLoading: teamLoading } = useTeamMembers();
112
-
113
- // Client-side UI state (Zustand)
114
- const progress = useDashboardStore(s => s.progress);
115
- const setProgress = useDashboardStore(s => s.setProgress);
116
- const sliderValue = useDashboardStore(s => s.sliderValue);
117
- const setSliderValue = useDashboardStore(s => s.setSliderValue);
118
- const switchEnabled = useDashboardStore(s => s.switchEnabled);
119
- const toggleSwitch = useDashboardStore(s => s.toggleSwitch);
120
-
121
- // Local UI-only toggles (no global relevance)
122
- const [showSidebarUser, setShowSidebarUser] = useState(true);
123
- const [showSidebarSettings, setShowSidebarSettings] = useState(true);
124
- const [showSidebarLogout, setShowSidebarLogout] = useState(true);
125
-
126
- // Header State
127
- const [showHeaderActions, setShowHeaderActions] = useState(true);
128
- const [showHeaderBreadcrumbs, setShowHeaderBreadcrumbs] = useState(true);
129
-
130
- const handleFormSubmit = (e: React.FormEvent) => {
131
- e.preventDefault();
132
- toast.success(t('templates.formSubmitSuccess'));
133
- };
134
-
135
- return (
136
- <div
137
- className="flex-1 flex flex-col overflow-hidden transition-all duration-300"
138
- style={{
139
- paddingLeft: sidebarExpanded ? `${sidebarWidth}px` : '80px',
140
- }}
141
- >
142
- {/* Sticky Header */}
143
- <Header
144
- showThemeToggle={true}
145
- showLanguageSelector={true}
146
- breadcrumbs={[
147
- { label: t('nav.designSystem'), href: '/home', icon: <Home className="w-4 h-4" /> },
148
- { label: t('templates.breadcrumb') },
149
- ]}
150
- renderLink={(href, props) => <Link to={href} {...props} />}
151
- />
152
-
153
- {/* Content area */}
154
- <main className="flex-1 overflow-hidden bg-muted">
155
- <ScrollArea className="h-full">
156
- <div className="p-2 sm:p-4 md:p-6">
157
- <div className="max-w-6xl mx-auto space-y-8">
158
- {/* Page header */}
159
- <PageHeader
160
- title={t('templates.title')}
161
- subtitle={t('templates.subtitle')}
162
- />
163
-
164
- {/* Page Header Example */}
165
- <section>
166
- <h3 className="mb-4">{t('templates.headerWithBreadcrumbs.sectionTitle')}</h3>
167
- <Card>
168
- <CardHeader>
169
- <CardTitle>{t('templates.headerWithBreadcrumbs.cardTitle')}</CardTitle>
170
- <CardDescription>{t('templates.headerWithBreadcrumbs.cardDescription')}</CardDescription>
171
- </CardHeader>
172
- <CardContent className="p-0 border-t bg-background overflow-hidden rounded-b-[var(--radius-lg)]">
173
- <Header
174
- className="border-b"
175
- breadcrumbs={[
176
- { label: t('templates.headerWithBreadcrumbs.breadcrumbs.dashboard'), href: '#', icon: <Home className="w-4 h-4" /> },
177
- { label: t('templates.headerWithBreadcrumbs.breadcrumbs.settings'), href: '#', icon: <Settings className="w-4 h-4" /> },
178
- { label: t('templates.headerWithBreadcrumbs.breadcrumbs.users'), href: '#', icon: <Users className="w-4 h-4" /> },
179
- { label: t('templates.headerWithBreadcrumbs.breadcrumbs.accessProfile') },
180
- ]}
181
- showLanguageSelector={true}
182
- showThemeToggle={true}
183
- />
184
- <div className="p-6 min-h-[200px]">
185
- <h4 className="text-lg font-semibold mb-2">{t('templates.headerWithBreadcrumbs.exampleContentTitle')}</h4>
186
- <p className="text-muted-foreground">
187
- {t('templates.headerWithBreadcrumbs.exampleContentDescriptionPart1')}
188
- <strong>Header</strong>
189
- {t('templates.headerWithBreadcrumbs.exampleContentDescriptionPart2')}
190
- </p>
191
- </div>
192
- </CardContent>
193
- </Card>
194
- </section>
195
-
196
- <Separator className="my-8" />
197
-
198
- {/* Alert Examples */}
199
- <section>
200
- <h3 className="mb-4">{t('templates.sections.alerts')}</h3>
201
- <div className="grid gap-4 md:grid-cols-2">
202
- <Alert variant="info">
203
- <AlertTitle>{t('templates.alerts.infoTitle')}</AlertTitle>
204
- <AlertDescription>{t('templates.alerts.infoDescription')}</AlertDescription>
205
- </Alert>
206
-
207
- <Alert variant="destructive">
208
- <AlertTitle>{t('templates.alerts.errorTitle')}</AlertTitle>
209
- <AlertDescription>{t('templates.alerts.errorDescription')}</AlertDescription>
210
- </Alert>
211
-
212
- <Alert variant="success">
213
- <AlertTitle>{t('templates.alerts.successTitle')}</AlertTitle>
214
- <AlertDescription>{t('templates.alerts.successDescription')}</AlertDescription>
215
- </Alert>
216
-
217
- <Alert variant="warning">
218
- <AlertTitle>{t('templates.alerts.warningTitle')}</AlertTitle>
219
- <AlertDescription>{t('templates.alerts.warningDescription')}</AlertDescription>
220
- </Alert>
221
- </div>
222
- </section>
223
-
224
- <Separator className="my-8" />
225
-
226
- {/* Cards & Tabs */}
227
- <section>
228
- <h3 className="mb-4">{t('templates.sections.cardsAndTabs')}</h3>
229
-
230
- <Tabs defaultValue="overview" className="w-full">
231
- <TabsList className="grid w-full grid-cols-4">
232
- <TabsTrigger value="overview">{t('templates.tabs.overview')}</TabsTrigger>
233
- <TabsTrigger value="forms">{t('templates.tabs.forms')}</TabsTrigger>
234
- <TabsTrigger value="data">{t('templates.tabs.data')}</TabsTrigger>
235
- <TabsTrigger value="settings">{t('templates.tabs.settings')}</TabsTrigger>
236
- </TabsList>
237
-
238
- {/* Overview Tab */}
239
- <TabsContent value="overview" className="space-y-4">
240
- <div className="grid gap-4 md:grid-cols-3">
241
- <Card>
242
- <CardHeader>
243
- <CardTitle>{t('stats.totalUsers')}</CardTitle>
244
- <CardDescription>{t('stats.last30Days')}</CardDescription>
245
- </CardHeader>
246
- <CardContent>
247
- <div className="text-foreground">
248
- <span className="[font-size:var(--text-stats)] [font-weight:var(--font-weight-bold)]">
249
- 1,234
250
- </span>
251
- <Badge variant="default" className="ml-2">
252
- +12%
253
- </Badge>
254
- </div>
255
- </CardContent>
256
- </Card>
257
-
258
- <Card>
259
- <CardHeader>
260
- <CardTitle>{t('stats.totalRevenue')}</CardTitle>
261
- <CardDescription>{t('stats.currentMonth')}</CardDescription>
262
- </CardHeader>
263
- <CardContent>
264
- <div className="text-foreground">
265
- <span className="[font-size:var(--text-stats)] [font-weight:var(--font-weight-bold)]">
266
- $ 45.2k
267
- </span>
268
- <Badge variant="secondary" className="ml-2">
269
- +8%
270
- </Badge>
271
- </div>
272
- </CardContent>
273
- </Card>
274
-
275
- <Card>
276
- <CardHeader>
277
- <CardTitle>{t('stats.conversionRate')}</CardTitle>
278
- <CardDescription>{t('stats.currentWeek')}</CardDescription>
279
- </CardHeader>
280
- <CardContent>
281
- <div className="text-foreground">
282
- <span className="[font-size:var(--text-stats)] [font-weight:var(--font-weight-bold)]">
283
- 3.2%
284
- </span>
285
- <Badge variant="outline" className="ml-2">
286
- -2%
287
- </Badge>
288
- </div>
289
- </CardContent>
290
- </Card>
291
- </div>
292
-
293
- <Card>
294
- <CardHeader>
295
- <CardTitle>{t('templates.overview.progressTitle')}</CardTitle>
296
- <CardDescription>{t('templates.overview.progressDescription')}</CardDescription>
297
- </CardHeader>
298
- <CardContent className="space-y-6">
299
- <div className="space-y-2">
300
- <div className="flex items-center justify-between">
301
- <Label>{t('templates.overview.projectProgress')}</Label>
302
- <span className="[font-size:var(--text-small)] text-muted-foreground">
303
- {progress}%
304
- </span>
305
- </div>
306
- <Progress value={progress} className="w-full" />
307
- <div className="flex gap-2">
308
- <Button
309
- size="sm"
310
- onClick={() => setProgress(Math.max(0, progress - 10))}
311
- >
312
- -10%
313
- </Button>
314
- <Button
315
- size="sm"
316
- onClick={() => setProgress(Math.min(100, progress + 10))}
317
- >
318
- +10%
319
- </Button>
320
- </div>
321
- </div>
322
-
323
- <Separator />
324
-
325
- <div className="space-y-2">
326
- <div className="flex items-center justify-between">
327
- <Label>{t('templates.overview.volume')}</Label>
328
- <span className="[font-size:var(--text-small)] text-muted-foreground">
329
- {sliderValue[0]}%
330
- </span>
331
- </div>
332
- <Slider
333
- value={sliderValue}
334
- onValueChange={setSliderValue}
335
- min={0}
336
- max={100}
337
- step={1}
338
- className="w-full"
339
- aria-label={t('templates.overview.volume')}
340
- />
341
- </div>
342
- </CardContent>
343
- </Card>
344
- </TabsContent>
345
-
346
- {/* Forms Tab */}
347
- <TabsContent value="forms" className="space-y-4">
348
- <Card>
349
- <CardHeader>
350
- <CardTitle>{t('templates.forms.registrationTitle')}</CardTitle>
351
- <CardDescription>{t('templates.forms.registrationDescription')}</CardDescription>
352
- </CardHeader>
353
- <CardContent>
354
- <form onSubmit={handleFormSubmit} className="space-y-4">
355
- <div className="grid gap-4 md:grid-cols-2">
356
- <div className="space-y-2">
357
- <Label htmlFor="firstName">{t('templates.forms.firstName')}</Label>
358
- <Input id="firstName" placeholder={t('templates.forms.firstNamePlaceholder')} />
359
- </div>
360
- <div className="space-y-2">
361
- <Label htmlFor="lastName">{t('templates.forms.lastName')}</Label>
362
- <Input id="lastName" placeholder={t('templates.forms.lastNamePlaceholder')} />
363
- </div>
364
- </div>
365
-
366
- <div className="space-y-2">
367
- <Label htmlFor="email">{t('templates.forms.email')}</Label>
368
- <div className="relative">
369
- <Mail className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
370
- <Input
371
- id="email"
372
- type="email"
373
- placeholder={t('templates.forms.emailPlaceholder')}
374
- className="pl-10"
375
- />
376
- </div>
377
- </div>
378
-
379
- <div className="space-y-2">
380
- <Label htmlFor="phone">{t('templates.forms.phone')}</Label>
381
- <div className="relative">
382
- <Phone className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
383
- <Input
384
- id="phone"
385
- type="tel"
386
- placeholder={t('templates.forms.phonePlaceholder')}
387
- className="pl-10"
388
- />
389
- </div>
390
- </div>
391
-
392
- <div className="space-y-2">
393
- <Label htmlFor="role">{t('templates.forms.role')}</Label>
394
- <Select>
395
- <SelectTrigger id="role">
396
- <SelectValue placeholder={t('templates.forms.rolePlaceholder')} />
397
- </SelectTrigger>
398
- <SelectContent>
399
- <SelectItem value="developer">{t('templates.forms.roles.developer')}</SelectItem>
400
- <SelectItem value="designer">{t('templates.forms.roles.designer')}</SelectItem>
401
- <SelectItem value="manager">{t('templates.forms.roles.manager')}</SelectItem>
402
- <SelectItem value="analyst">{t('templates.forms.roles.analyst')}</SelectItem>
403
- </SelectContent>
404
- </Select>
405
- </div>
406
-
407
- <div className="space-y-2">
408
- <Label htmlFor="bio">{t('templates.forms.bio')}</Label>
409
- <Textarea
410
- id="bio"
411
- placeholder={t('templates.forms.bioPlaceholder')}
412
- rows={4}
413
- />
414
- </div>
415
-
416
- <Separator />
417
-
418
- <div className="space-y-4">
419
- <h4>{t('templates.forms.preferences')}</h4>
420
-
421
- <div className="space-y-3">
422
- <div className="flex items-center space-x-2">
423
- <Checkbox id="newsletter" />
424
- <Label htmlFor="newsletter" className="font-normal">
425
- {t('templates.forms.newsletter')}
426
- </Label>
427
- </div>
428
-
429
- <div className="flex items-center space-x-2">
430
- <Checkbox id="notifications" />
431
- <Label htmlFor="notifications" className="font-normal">
432
- {t('templates.forms.pushNotifications')}
433
- </Label>
434
- </div>
435
-
436
- <div className="flex items-center space-x-2">
437
- <Checkbox id="updates" />
438
- <Label htmlFor="updates" className="font-normal">
439
- {t('templates.forms.featureUpdates')}
440
- </Label>
441
- </div>
442
- </div>
443
-
444
- <Separator />
445
-
446
- <div className="space-y-3">
447
- <Label>{t('templates.forms.accountType')}</Label>
448
- <RadioGroup defaultValue="personal" aria-label={t('templates.forms.accountType')}>
449
- <div className="flex items-center space-x-2">
450
- <RadioGroupItem value="personal" id="personal" />
451
- <Label htmlFor="personal" className="font-normal">
452
- {t('templates.forms.accountPersonal')}
453
- </Label>
454
- </div>
455
- <div className="flex items-center space-x-2">
456
- <RadioGroupItem value="business" id="business" />
457
- <Label htmlFor="business" className="font-normal">
458
- {t('templates.forms.accountBusiness')}
459
- </Label>
460
- </div>
461
- <div className="flex items-center space-x-2">
462
- <RadioGroupItem value="enterprise" id="enterprise" />
463
- <Label htmlFor="enterprise" className="font-normal">
464
- {t('templates.forms.accountEnterprise')}
465
- </Label>
466
- </div>
467
- </RadioGroup>
468
- </div>
469
- </div>
470
- </form>
471
- </CardContent>
472
- <CardFooter className="flex justify-between">
473
- <Button variant="outline">{t('templates.forms.cancel')}</Button>
474
- <Button onClick={handleFormSubmit}>{t('templates.forms.createAccount')}</Button>
475
- </CardFooter>
476
- </Card>
477
- </TabsContent>
478
-
479
- {/* Data Tab */}
480
- <TabsContent value="data" className="space-y-4">
481
- <SectionErrorBoundary>
482
- <Card>
483
- <CardHeader>
484
- <CardTitle>{t('templates.data.title')}</CardTitle>
485
- <CardDescription>{t('templates.data.description')}</CardDescription>
486
- </CardHeader>
487
- <CardContent>
488
- <div className="mb-4">
489
- <div className="relative">
490
- <Search className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
491
- <Input
492
- placeholder={t('templates.data.searchPlaceholder')}
493
- aria-label={t('templates.data.searchPlaceholder')}
494
- className="pl-10"
495
- />
496
- </div>
497
- </div>
498
-
499
- <div className="rounded-[var(--radius-lg)] border border-border overflow-hidden">
500
- <Table>
501
- <TableHeader>
502
- <TableRow>
503
- <TableHead>{t('team.name')}</TableHead>
504
- <TableHead>{t('team.email')}</TableHead>
505
- <TableHead>{t('team.role')}</TableHead>
506
- <TableHead>{t('team.status')}</TableHead>
507
- <TableHead className="text-right">{t('team.actions')}</TableHead>
508
- </TableRow>
509
- </TableHeader>
510
- <TableBody>
511
- {teamLoading ? (
512
- <>
513
- {Array.from({ length: 5 }).map((_, i) => (
514
- <TableRow key={i}>
515
- <TableCell>
516
- <div className="flex items-center gap-2">
517
- <Skeleton className="size-8 rounded-full shrink-0" />
518
- <Skeleton className="h-3.5 w-28" />
519
- </div>
520
- </TableCell>
521
- <TableCell><Skeleton className="h-3.5 w-36" /></TableCell>
522
- <TableCell><Skeleton className="h-3.5 w-20" /></TableCell>
523
- <TableCell><Skeleton className="h-5 w-16 rounded-full" /></TableCell>
524
- <TableCell className="text-right"><Skeleton className="h-7 w-14 ml-auto" /></TableCell>
525
- </TableRow>
526
- ))}
527
- </>
528
- ) : (
529
- teamMembers.map(member => (
530
- <TableRow key={member.id}>
531
- <TableCell>{member.name}</TableCell>
532
- <TableCell>{member.email}</TableCell>
533
- <TableCell>{t(`team.roles.${member.role}`)}</TableCell>
534
- <TableCell>
535
- <Badge
536
- variant={
537
- member.status === 'active'
538
- ? 'default'
539
- : member.status === 'away'
540
- ? 'secondary'
541
- : 'outline'
542
- }
543
- >
544
- {t(`common.${member.status}`)}
545
- </Badge>
546
- </TableCell>
547
- <TableCell className="text-right">
548
- <Button variant="ghost" size="sm">
549
- {t('common.edit')}
550
- </Button>
551
- </TableCell>
552
- </TableRow>
553
- ))
554
- )}
555
- </TableBody>
556
- </Table>
557
- </div>
558
- </CardContent>
559
- <CardFooter className="flex justify-between items-center">
560
- <p className="text-muted-foreground">
561
- {t('team.showing', { count: teamMembers.length, total: teamMembers.length })}
562
- </p>
563
- <div className="flex gap-2">
564
- <Button variant="outline" size="sm">
565
- {t('common.previous')}
566
- </Button>
567
- <Button variant="outline" size="sm">
568
- {t('common.next')}
569
- </Button>
570
- </div>
571
- </CardFooter>
572
- </Card>
573
- </SectionErrorBoundary>
574
- </TabsContent>
575
-
576
- {/* Settings Tab */}
577
- <TabsContent value="settings" className="space-y-4">
578
- <Card>
579
- <CardHeader>
580
- <CardTitle>{t('templates.settings.title')}</CardTitle>
581
- <CardDescription>{t('templates.settings.description')}</CardDescription>
582
- </CardHeader>
583
- <CardContent className="space-y-6">
584
- <div className="flex items-center justify-between">
585
- <div className="space-y-1">
586
- <Label htmlFor="dark-mode">{t('templates.settings.darkMode')}</Label>
587
- <p className="text-muted-foreground">
588
- {t('templates.settings.darkModeDescription')}
589
- </p>
590
- </div>
591
- <Switch
592
- id="dark-mode"
593
- checked={switchEnabled}
594
- onCheckedChange={toggleSwitch}
595
- />
596
- </div>
597
-
598
- <Separator />
599
-
600
- <div className="flex items-center justify-between">
601
- <div className="space-y-1">
602
- <Label htmlFor="email-notifications">{t('templates.settings.emailNotifications')}</Label>
603
- <p className="text-muted-foreground">
604
- {t('templates.settings.emailNotificationsDescription')}
605
- </p>
606
- </div>
607
- <Switch id="email-notifications" defaultChecked />
608
- </div>
609
-
610
- <Separator />
611
-
612
- <div className="flex items-center justify-between">
613
- <div className="space-y-1">
614
- <Label htmlFor="push-notifications">{t('templates.settings.pushNotifications')}</Label>
615
- <p className="text-muted-foreground">
616
- {t('templates.settings.pushNotificationsDescription')}
617
- </p>
618
- </div>
619
- <Switch id="push-notifications" />
620
- </div>
621
-
622
- <Separator />
623
-
624
- <div className="space-y-3">
625
- <Label>{t('templates.settings.language')}</Label>
626
- <Select defaultValue="pt-br">
627
- <SelectTrigger aria-label={t('templates.settings.language')}>
628
- <SelectValue />
629
- </SelectTrigger>
630
- <SelectContent>
631
- <SelectItem value="pt-br">{t('templates.settings.languages.ptBR')}</SelectItem>
632
- <SelectItem value="en">{t('templates.settings.languages.en')}</SelectItem>
633
- <SelectItem value="es">{t('templates.settings.languages.es')}</SelectItem>
634
- </SelectContent>
635
- </Select>
636
- </div>
637
-
638
- <Separator />
639
-
640
- <div className="space-y-3">
641
- <Label>{t('templates.settings.timezone')}</Label>
642
- <Select defaultValue="america-sao-paulo">
643
- <SelectTrigger aria-label={t('templates.settings.timezone')}>
644
- <SelectValue />
645
- </SelectTrigger>
646
- <SelectContent>
647
- <SelectItem value="america-sao-paulo">
648
- {t('templates.settings.timezones.saoPaulo')}
649
- </SelectItem>
650
- <SelectItem value="america-new-york">
651
- {t('templates.settings.timezones.newYork')}
652
- </SelectItem>
653
- <SelectItem value="europe-london">{t('templates.settings.timezones.london')}</SelectItem>
654
- </SelectContent>
655
- </Select>
656
- </div>
657
- </CardContent>
658
- <CardFooter className="flex justify-between">
659
- <Button variant="outline">{t('templates.settings.restoreDefaults')}</Button>
660
- <Button>{t('templates.settings.saveChanges')}</Button>
661
- </CardFooter>
662
- </Card>
663
- </TabsContent>
664
- </Tabs>
665
- </section>
666
-
667
- <Separator className="my-8" />
668
-
669
- {/* Button Variants */}
670
- <section>
671
- <h3 className="mb-4">{t('templates.sections.buttons')}</h3>
672
- <Card>
673
- <CardHeader>
674
- <CardTitle>{t('templates.buttons.title')}</CardTitle>
675
- <CardDescription>{t('templates.buttons.description')}</CardDescription>
676
- </CardHeader>
677
- <CardContent className="space-y-6">
678
- <div className="space-y-3">
679
- <Label>{t('templates.buttons.variants')}</Label>
680
- <div className="flex flex-wrap gap-3">
681
- <Button variant="default">Default</Button>
682
- <Button variant="secondary">Secondary</Button>
683
- <Button variant="outline">Outline</Button>
684
- <Button variant="ghost">Ghost</Button>
685
- <Button variant="link">Link</Button>
686
- <Button variant="destructive">Destructive</Button>
687
- </div>
688
- </div>
689
-
690
- <Separator />
691
-
692
- <div className="space-y-3">
693
- <Label>{t('templates.buttons.sizes')}</Label>
694
- <div className="flex flex-wrap items-center gap-3">
695
- <Button size="sm">Small</Button>
696
- <Button size="default">Default</Button>
697
- <Button size="lg">Large</Button>
698
- <Button size="icon" aria-label={t('nav.settings')}>
699
- <Settings className="h-4 w-4" />
700
- </Button>
701
- </div>
702
- </div>
703
-
704
- <Separator />
705
-
706
- <div className="space-y-3">
707
- <Label>{t('templates.buttons.withIcons')}</Label>
708
- <div className="flex flex-wrap gap-3">
709
- <Button>
710
- <User className="mr-2 h-4 w-4" />
711
- {t('templates.buttons.profile')}
712
- </Button>
713
- <Button variant="secondary">
714
- <Mail className="mr-2 h-4 w-4" />
715
- {t('templates.buttons.messages')}
716
- </Button>
717
- <Button variant="outline">
718
- <Calendar className="mr-2 h-4 w-4" />
719
- {t('templates.buttons.schedule')}
720
- </Button>
721
- </div>
722
- </div>
723
-
724
- <Separator />
725
-
726
- <div className="space-y-3">
727
- <Label>{t('templates.buttons.states')}</Label>
728
- <div className="flex flex-wrap gap-3">
729
- <Button disabled>{t('templates.buttons.disabled')}</Button>
730
- <Button variant="outline" disabled>
731
- {t('templates.buttons.outlineDisabled')}
732
- </Button>
733
- </div>
734
- </div>
735
- </CardContent>
736
- </Card>
737
- </section>
738
-
739
- <Separator className="my-8" />
740
-
741
- {/* Badges */}
742
- <section>
743
- <h3 className="mb-4">{t('templates.sections.badges')}</h3>
744
- <Card>
745
- <CardHeader>
746
- <CardTitle>{t('templates.badges.title')}</CardTitle>
747
- <CardDescription>{t('templates.badges.description')}</CardDescription>
748
- </CardHeader>
749
- <CardContent>
750
- <div className="flex flex-wrap gap-3">
751
- <Badge variant="default">Default</Badge>
752
- <Badge variant="secondary">Secondary</Badge>
753
- <Badge variant="outline">Outline</Badge>
754
- <Badge variant="destructive">Destructive</Badge>
755
- <Badge className="bg-success text-success-foreground">Success</Badge>
756
- <Badge className="bg-warning text-warning-foreground">Warning</Badge>
757
- <Badge className="bg-info text-info-foreground">Info</Badge>
758
- </div>
759
- </CardContent>
760
- </Card>
761
- </section>
762
-
763
- <Separator className="my-8" />
764
-
765
- {/* Dialogs */}
766
- <section>
767
- <h3 className="mb-4">{t('templates.sections.dialogs')}</h3>
768
- <div className="grid gap-4 md:grid-cols-2">
769
- <Card>
770
- <CardHeader>
771
- <CardTitle>{t('templates.dialogs.dialogTitle')}</CardTitle>
772
- <CardDescription>{t('templates.dialogs.dialogDescription')}</CardDescription>
773
- </CardHeader>
774
- <CardContent className="flex justify-center py-6">
775
- <Dialog>
776
- <DialogTrigger asChild>
777
- <Button variant="outline">{t('templates.dialogs.editProfile')}</Button>
778
- </DialogTrigger>
779
- <DialogContent className="sm:max-w-[425px]">
780
- <DialogHeader>
781
- <DialogTitle>{t('templates.dialogs.editProfile')}</DialogTitle>
782
- <DialogDescription>
783
- {t('templates.dialogs.editProfileDescription')}
784
- </DialogDescription>
785
- </DialogHeader>
786
- <div className="grid gap-4 py-4">
787
- <div className="grid grid-cols-4 items-center gap-4">
788
- <Label htmlFor="name" className="text-right">
789
- {t('templates.dialogs.name')}
790
- </Label>
791
- <Input id="name" defaultValue="John Doe" className="col-span-3" />
792
- </div>
793
- <div className="grid grid-cols-4 items-center gap-4">
794
- <Label htmlFor="username" className="text-right">
795
- {t('templates.dialogs.username')}
796
- </Label>
797
- <Input id="username" defaultValue="@johndoe" className="col-span-3" />
798
- </div>
799
- </div>
800
- <DialogFooter>
801
- <Button type="submit">{t('templates.dialogs.update')}</Button>
802
- </DialogFooter>
803
- </DialogContent>
804
- </Dialog>
805
- </CardContent>
806
- </Card>
807
-
808
- <Card>
809
- <CardHeader>
810
- <CardTitle>{t('templates.dialogs.alertDialogTitle')}</CardTitle>
811
- <CardDescription>{t('templates.dialogs.alertDialogDescription')}</CardDescription>
812
- </CardHeader>
813
- <CardContent className="flex justify-center py-6">
814
- <AlertDialog>
815
- <AlertDialogTrigger asChild>
816
- <Button variant="destructive">{t('templates.dialogs.deleteAccount')}</Button>
817
- </AlertDialogTrigger>
818
- <AlertDialogContent className="sm:max-w-[425px]">
819
- <AlertDialogHeader>
820
- <AlertDialogTitle>{t('templates.dialogs.areYouSure')}</AlertDialogTitle>
821
- <AlertDialogDescription>
822
- {t('templates.dialogs.deleteWarning')}
823
- </AlertDialogDescription>
824
- </AlertDialogHeader>
825
- <AlertDialogFooter>
826
- <AlertDialogCancel>{t('templates.dialogs.cancel')}</AlertDialogCancel>
827
- <AlertDialogAction className="bg-destructive text-destructive-foreground hover:bg-destructive/90">
828
- {t('templates.dialogs.continue')}
829
- </AlertDialogAction>
830
- </AlertDialogFooter>
831
- </AlertDialogContent>
832
- </AlertDialog>
833
- </CardContent>
834
- </Card>
835
- </div>
836
- </section>
837
-
838
- <Separator className="my-8" />
839
-
840
- {/* Maps */}
841
- <section>
842
- <MapShowcase />
843
- </section>
844
-
845
- <Separator className="my-8" />
846
-
847
- {/* Header Variations */}
848
- <section>
849
- <h3 className="mb-4">{t('templates.headerVariations.sectionTitle')}</h3>
850
- <Card>
851
- <CardHeader>
852
- <CardTitle>{t('templates.headerVariations.cardTitle')}</CardTitle>
853
- <CardDescription>{t('templates.headerVariations.cardDescription')}</CardDescription>
854
- </CardHeader>
855
- <CardContent className="space-y-6">
856
- <div className="p-4 border rounded-[var(--radius-lg)] bg-muted/30">
857
- <h4 className="text-sm font-semibold mb-4">{t('templates.headerVariations.visibleElements')}</h4>
858
- <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-6">
859
- <div className="flex items-center space-x-2">
860
- <Switch
861
- id="header-actions"
862
- checked={showHeaderActions}
863
- onCheckedChange={setShowHeaderActions}
864
- />
865
- <Label htmlFor="header-actions" className="cursor-pointer">
866
- {t('templates.headerVariations.actionButtons')}
867
- </Label>
868
- </div>
869
- <div className="flex items-center space-x-2">
870
- <Switch
871
- id="header-bread"
872
- checked={showHeaderBreadcrumbs}
873
- onCheckedChange={setShowHeaderBreadcrumbs}
874
- />
875
- <Label htmlFor="header-bread" className="cursor-pointer">
876
- {t('templates.headerVariations.breadcrumbsLabel')}
877
- </Label>
878
- </div>
879
- </div>
880
- </div>
881
-
882
- <div className="relative border rounded-[var(--radius-lg)] bg-muted/10 overflow-hidden shadow-inner">
883
- <div className="p-4 bg-background/50 border-b text-xs font-mono text-muted-foreground">
884
- {t('templates.headerVariations.preview')}
885
- </div>
886
- <Header
887
- title={!showHeaderBreadcrumbs ? t('templates.headerVariations.currentPage') : undefined}
888
- breadcrumbs={
889
- showHeaderBreadcrumbs
890
- ? [
891
- {
892
- label: t('templates.headerVariations.breadcrumbBrand'),
893
- href: '#',
894
- icon: <Home className="w-4 h-4" />,
895
- },
896
- { label: t('templates.headerVariations.breadcrumbSettings'), href: '#' },
897
- { label: t('templates.headerVariations.breadcrumbProfile') },
898
- ]
899
- : undefined
900
- }
901
- actions={
902
- showHeaderActions
903
- ? [
904
- {
905
- id: 'notify',
906
- icon: <Bell className="w-5 h-5" />,
907
- onClick: () => toast(t('templates.headerVariations.notificationsOpenedToast')),
908
- },
909
- {
910
- id: 'mail',
911
- label: t('templates.headerVariations.messagesLabel'),
912
- icon: <Mail className="w-5 h-5" />,
913
- onClick: () => toast(t('templates.headerVariations.messagesOpenedToast')),
914
- },
915
- ]
916
- : undefined
917
- }
918
- />
919
- <div className="h-32 flex items-center justify-center text-muted-foreground text-sm italic">
920
- {t('templates.headerVariations.contentArea')}
921
- </div>
922
- </div>
923
- </CardContent>
924
- </Card>
925
- </section>
926
-
927
- <Separator className="my-8" />
928
-
929
- {/* Sidebar Variations */}
930
- <section>
931
- <h3 className="mb-4">{t('templates.sections.sidebarVariations')}</h3>
932
- <Card>
933
- <CardHeader>
934
- <CardTitle>{t('templates.sidebar.title')}</CardTitle>
935
- <CardDescription>{t('templates.sidebar.description')}</CardDescription>
936
- </CardHeader>
937
- <CardContent>
938
- <Tabs defaultValue="assistant" className="w-full">
939
- <TabsList className="mb-4">
940
- <TabsTrigger value="assistant">{t('templates.sidebar.assistantMode')}</TabsTrigger>
941
- <TabsTrigger value="default">{t('templates.sidebar.defaultMode')}</TabsTrigger>
942
- </TabsList>
943
-
944
- <div className="mb-6 p-4 border rounded-[var(--radius-lg)] bg-muted/30">
945
- <h4 className="text-sm font-semibold mb-4">{t('templates.sidebarControls.footerSettings')}</h4>
946
- <div className="flex flex-wrap gap-6 mt-2">
947
- <div className="flex items-center space-x-2">
948
- <Switch
949
- id="show-user"
950
- checked={showSidebarUser}
951
- onCheckedChange={setShowSidebarUser}
952
- />
953
- <Label htmlFor="show-user" className="cursor-pointer">
954
- {t('templates.sidebarControls.userProfile')}
955
- </Label>
956
- </div>
957
- <div className="flex items-center space-x-2">
958
- <Switch
959
- id="show-settings"
960
- checked={showSidebarSettings}
961
- onCheckedChange={setShowSidebarSettings}
962
- />
963
- <Label htmlFor="show-settings" className="cursor-pointer">
964
- {t('templates.sidebarControls.settings')}
965
- </Label>
966
- </div>
967
- <div className="flex items-center space-x-2">
968
- <Switch
969
- id="show-logout"
970
- checked={showSidebarLogout}
971
- onCheckedChange={setShowSidebarLogout}
972
- />
973
- <Label htmlFor="show-logout" className="cursor-pointer">
974
- {t('templates.sidebarControls.logoutButton')}
975
- </Label>
976
- </div>
977
- </div>
978
-
979
- <div className="mt-6 pt-6 border-t">
980
- <div className="flex items-center justify-between mb-4">
981
- <h4 className="text-sm font-semibold">{t('templates.sidebarControls.sidebarWidthDesktop')}</h4>
982
- <span className="text-xs font-mono bg-muted px-2 py-1 rounded">
983
- {sidebarWidth}px
984
- </span>
985
- </div>
986
- <div className="flex items-center gap-4">
987
- <span className="text-xs text-muted-foreground w-12 text-right">
988
- 240px
989
- </span>
990
- <Slider
991
- value={[sidebarWidth]}
992
- onValueChange={val => setSidebarWidth(val[0])}
993
- min={240}
994
- max={450}
995
- step={10}
996
- className="flex-1"
997
- aria-label={t('templates.sidebarControls.sidebarWidthAriaLabel')}
998
- />
999
- <span className="text-xs text-muted-foreground w-12">450px</span>
1000
- </div>
1001
- </div>
1002
- </div>
1003
-
1004
- <TabsContent value="assistant">
1005
- <div
1006
- className="relative h-[600px] border rounded-[var(--radius-lg)] bg-muted/20 overflow-hidden"
1007
- style={{ transform: 'translateZ(0)' }}
1008
- >
1009
- <Sidebar
1010
- expanded={true}
1011
- width={sidebarWidth}
1012
- onToggle={() => {}}
1013
- user={{ email: 'admin@xertica.com' }}
1014
- onLogout={() => toast(t('templates.sidebar.logoutToast'))}
1015
- location={{ pathname: '/assistant/current' }}
1016
- navigate={() => {}}
1017
- variant="assistant"
1018
- search={{
1019
- show: true,
1020
- placeholder: t('templates.sidebar.searchTopicsPlaceholder'),
1021
- filter: {
1022
- show: true,
1023
- content: (
1024
- <div className="p-2 space-y-2">
1025
- <div className="text-xs font-semibold uppercase text-muted-foreground px-2">
1026
- {t('templates.sidebarControls.filterByStatus')}
1027
- </div>
1028
- <div className="flex flex-wrap gap-2 p-1">
1029
- <Badge className="bg-sidebar-foreground/20 text-sidebar-foreground border-none cursor-pointer hover:bg-sidebar-foreground/30">
1030
- {t('templates.sidebarControls.filterActive')}
1031
- </Badge>
1032
- <Badge
1033
- variant="outline"
1034
- className="text-sidebar-foreground/70 border-sidebar-foreground/20 cursor-pointer hover:bg-sidebar-foreground/10"
1035
- >
1036
- {t('templates.sidebarControls.filterArchived')}
1037
- </Badge>
1038
- <Badge
1039
- variant="outline"
1040
- className="text-sidebar-foreground/70 border-sidebar-foreground/20 cursor-pointer hover:bg-sidebar-foreground/10"
1041
- >
1042
- {t('templates.sidebarControls.filterPending')}
1043
- </Badge>
1044
- </div>
1045
- </div>
1046
- ),
1047
- },
1048
- }}
1049
- fixedArea={{
1050
- show: true,
1051
- content: (
1052
- <Button className="w-full bg-sidebar-primary hover:bg-sidebar-primary/90 text-sidebar-primary-foreground shadow-lg font-bold border-none transition-all duration-300 transform hover:scale-[1.02] active:scale-[0.98]">
1053
- <Plus className="w-4 h-4 mr-2" />
1054
- {t('templates.sidebar.newConversation')}
1055
- </Button>
1056
- ),
1057
- }}
1058
- navigationGroups={[
1059
- {
1060
- id: 'recent',
1061
- label: t('templates.sidebar.recent'),
1062
- icon: Clock,
1063
- items: [
1064
- {
1065
- path: '/assistant/refatoracao',
1066
- label: t('templates.sidebar.items.sidebarRefactor'),
1067
- description: t('templates.sidebar.items.sidebarRefactorDescription'),
1068
- actions: [
1069
- {
1070
- label: t('templates.sidebar.actions.rename'),
1071
- icon: FileEdit,
1072
- onClick: () => toast(t('templates.sidebar.actions.renameToast')),
1073
- },
1074
- {
1075
- label: t('templates.sidebar.actions.move'),
1076
- icon: ArrowRightLeft,
1077
- children: [
1078
- {
1079
- label: t('templates.sidebar.actions.moveActive'),
1080
- onClick: () => toast(t('templates.sidebar.actions.moveActiveToast')),
1081
- },
1082
- {
1083
- label: t('templates.sidebar.actions.moveMonitoring'),
1084
- onClick: () => toast(t('templates.sidebar.actions.moveMonitoringToast')),
1085
- },
1086
- {
1087
- label: t('templates.sidebar.actions.moveArchive'),
1088
- onClick: () => toast(t('templates.sidebar.actions.moveArchiveToast')),
1089
- },
1090
- ],
1091
- },
1092
- {
1093
- label: t('templates.sidebar.actions.clear'),
1094
- icon: Trash2,
1095
- onClick: () => toast(t('templates.sidebar.actions.clearToast')),
1096
- variant: 'destructive',
1097
- },
1098
- ],
1099
- },
1100
- ],
1101
- },
1102
- {
1103
- id: 'projects',
1104
- label: t('templates.sidebar.constructionMonitoring'),
1105
- icon: Map,
1106
- actions: [
1107
- {
1108
- label: t('templates.sidebar.actions.newCategory'),
1109
- icon: Plus,
1110
- onClick: () => toast(t('templates.sidebar.actions.newCategoryToast')),
1111
- },
1112
- {
1113
- label: t('templates.sidebar.actions.archiveGroup'),
1114
- icon: Archive,
1115
- onClick: () => toast(t('templates.sidebar.actions.archiveGroupToast')),
1116
- },
1117
- ],
1118
- items: [
1119
- {
1120
- path: '/assistant/br163',
1121
- label: t('templates.sidebar.items.br163Restoration'),
1122
- icon: () => (
1123
- <div className="w-2 h-2 rounded-full bg-yellow-500" />
1124
- ),
1125
- description: (
1126
- <div className="space-y-1.5 min-w-[160px]">
1127
- <Progress
1128
- value={67}
1129
- className="h-1.5 bg-sidebar-foreground/10"
1130
- />
1131
- <div className="flex justify-between items-center text-[10px] text-sidebar-foreground/60">
1132
- <span>{t('templates.sidebar.items.br163Location')}</span>
1133
- <span>67%</span>
1134
- </div>
1135
- </div>
1136
- ),
1137
- },
1138
- ],
1139
- },
1140
- ]}
1141
- footer={{
1142
- showUser: showSidebarUser,
1143
- showSettings: showSidebarSettings,
1144
- showLogout: showSidebarLogout,
1145
- }}
1146
- />
1147
- <div
1148
- className="absolute inset-y-0 right-0 p-8 flex items-center justify-center transition-all duration-300"
1149
- style={{ left: `${sidebarWidth}px` }}
1150
- >
1151
- <p className="text-muted-foreground text-center">
1152
- {t('templates.sidebar.assistantContent')}
1153
- </p>
1154
- </div>
1155
- </div>
1156
- </TabsContent>
1157
-
1158
- <TabsContent value="default">
1159
- <div
1160
- className="relative h-[600px] border rounded-[var(--radius-lg)] bg-muted/20 overflow-hidden"
1161
- style={{ transform: 'translateZ(0)' }}
1162
- >
1163
- <Sidebar
1164
- expanded={true}
1165
- width={sidebarWidth}
1166
- onToggle={() => {}}
1167
- user={{
1168
- name: 'Ariel Santos',
1169
- email: 'admin@xertica.com',
1170
- avatar: 'https://github.com/shadcn.png',
1171
- }}
1172
- onLogout={() => toast(t('templates.sidebar.logoutToast'))}
1173
- onSettingsClick={() => toast(t('templates.sidebar.settingsClickedToast'))}
1174
- location={{ pathname: '/home' }}
1175
- navigate={() => {}}
1176
- variant="default"
1177
- routes={[
1178
- { path: '/home', label: t('templates.sidebar.routes.home'), icon: Home },
1179
- { path: '/dashboard', label: t('templates.sidebar.routes.dashboard'), icon: Users },
1180
- { path: '/settings', label: t('templates.sidebar.routes.settings'), icon: Settings },
1181
- ]}
1182
- footer={{
1183
- showUser: showSidebarUser,
1184
- showSettings: showSidebarSettings,
1185
- showLogout: showSidebarLogout,
1186
- }}
1187
- />
1188
- <div
1189
- className="absolute inset-y-0 right-0 p-8 flex items-center justify-center transition-all duration-300"
1190
- style={{ left: `${sidebarWidth}px` }}
1191
- >
1192
- <p className="text-muted-foreground text-center">
1193
- {t('templates.sidebar.defaultContent')}
1194
- </p>
1195
- </div>
1196
- </div>
1197
- </TabsContent>
1198
- </Tabs>
1199
- </CardContent>
1200
- </Card>
1201
- </section>
1202
-
1203
- <Separator className="my-8" />
1204
-
1205
- {/* Footer Note */}
1206
- <Card className="mt-8">
1207
- <CardHeader>
1208
- <CardTitle>{t('templates.footer.title')}</CardTitle>
1209
- <CardDescription>{t('templates.footer.subtitle')}</CardDescription>
1210
- </CardHeader>
1211
- <CardContent className="space-y-4">
1212
- <p className="text-muted-foreground">
1213
- {t('templates.footer.descriptionPart1')}
1214
- <code className="bg-muted px-2 py-1 rounded-[var(--radius-sm)] [font-size:var(--text-small)]">
1215
- xertica-ui
1216
- </code>
1217
- {t('templates.footer.descriptionPart2')}
1218
- </p>
1219
- <Alert variant="info">
1220
- <AlertTitle>{t('templates.footer.tipTitle')}</AlertTitle>
1221
- <AlertDescription>
1222
- {t('templates.footer.tipDescriptionPart1')}
1223
- <code className="bg-muted px-1 rounded">styles/xertica/tokens.css</code>
1224
- {t('templates.footer.tipDescriptionPart2')}
1225
- </AlertDescription>
1226
- </Alert>
1227
- </CardContent>
1228
- </Card>
1229
- </div>
1230
- </div>
1231
- </ScrollArea>
1232
- </main>
1233
- </div>
1234
- );
1235
- }
1
+ import React, { useState } from 'react';
2
+ import { Link, useNavigate } from 'react-router-dom';
3
+ import { Button } from '../../ui/button';
4
+ import { Input } from '../../ui/input';
5
+ import { Label } from '../../ui/label';
6
+ import {
7
+ Card,
8
+ CardHeader,
9
+ CardTitle,
10
+ CardDescription,
11
+ CardContent,
12
+ CardFooter,
13
+ } from '../../ui/card';
14
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from '../../ui/tabs';
15
+ import { Badge } from '../../ui/badge';
16
+ import { Alert, AlertDescription, AlertTitle } from '../../ui/alert';
17
+ import { Checkbox } from '../../ui/checkbox';
18
+ import { RadioGroup, RadioGroupItem } from '../../ui/radio-group';
19
+ import { Switch } from '../../ui/switch';
20
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../ui/select';
21
+ import { Textarea } from '../../ui/textarea';
22
+ import { Progress } from '../../ui/progress';
23
+ import { Separator } from '../../ui/separator';
24
+ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '../../ui/table';
25
+ import {
26
+ Settings,
27
+ User,
28
+ Mail,
29
+ Phone,
30
+ Calendar,
31
+ Search,
32
+ Menu,
33
+ ChevronRight,
34
+ Home,
35
+ Users,
36
+ Plus,
37
+ Trash2,
38
+ Archive,
39
+ ArrowRightLeft,
40
+ History,
41
+ PanelRight,
42
+ FileEdit,
43
+ Filter,
44
+ Clock,
45
+ Map,
46
+ Bell,
47
+ } from 'lucide-react';
48
+ import { Slider } from '../../ui/slider';
49
+ import { toast } from 'sonner';
50
+ import { ScrollArea } from '../../ui/scroll-area';
51
+ import { ThemeToggle } from '../../brand/theme-toggle';
52
+ import { LanguageSelector } from '../../brand/language-selector';
53
+ import { MapShowcase } from '../../examples/MapShowcase';
54
+ import { Header } from '../../layout/header';
55
+ import { Sidebar } from '../../layout/sidebar';
56
+ import {
57
+ Dialog,
58
+ DialogTrigger,
59
+ DialogContent,
60
+ DialogHeader,
61
+ DialogTitle,
62
+ DialogDescription,
63
+ DialogFooter,
64
+ } from '../../ui/dialog';
65
+ import {
66
+ AlertDialog,
67
+ AlertDialogTrigger,
68
+ AlertDialogContent,
69
+ AlertDialogHeader,
70
+ AlertDialogTitle,
71
+ AlertDialogDescription,
72
+ AlertDialogFooter,
73
+ AlertDialogAction,
74
+ AlertDialogCancel,
75
+ } from '../../ui/alert-dialog';
76
+ import { PageHeader } from '../../ui/page-header';
77
+
78
+ import { useOptionalLayout } from '../../../contexts/LayoutContext';
79
+ import { useTheme } from '../../../contexts/ThemeContext';
80
+ import { useTeamMembers, useDashboardStore } from '../../../features/home';
81
+ import { useTranslation } from 'react-i18next';
82
+ import { SectionErrorBoundary } from '../../shared/error-boundary';
83
+ import { Skeleton } from '../../ui/skeleton';
84
+
85
+ /**
86
+ * Comprehensive Showcase and Template Content component.
87
+ *
88
+ * @description
89
+ * This component serves as a living kitchen-sink demonstration of the Xertica UI
90
+ * Design System. It showcases almost every UI primitive (Cards, Tabs, Forms,
91
+ * Tables, Dialogs, etc.) and layout variation (Header flexibility, Sidebar
92
+ * toggling). It's primarily used for development, testing, and as a starting
93
+ * point for new pages.
94
+ *
95
+ * @ai-rules
96
+ * 1. Reference: Use this component as the primary source of truth for "how to compose" complex layouts in this library.
97
+ * 2. Layout: Adjusts its own padding based on the `useLayout` context's sidebar state.
98
+ * 3. Interaction: All showcase interactive elements (buttons, forms) use simple `toast` feedback or local state toggles.
99
+ */
100
+ export function TemplateContent() {
101
+ const { t } = useTranslation();
102
+ const layout = useOptionalLayout();
103
+ const { disableDarkMode } = useTheme();
104
+ const [localSidebarExpanded, setLocalSidebarExpanded] = useState(false);
105
+ const [localSidebarWidth, setLocalSidebarWidth] = useState(280);
106
+ const sidebarExpanded = layout?.sidebarExpanded ?? localSidebarExpanded;
107
+ const sidebarWidth = layout?.sidebarWidth ?? localSidebarWidth;
108
+ const setSidebarWidth = layout?.setSidebarWidth ?? setLocalSidebarWidth;
109
+ const toggleSidebar = layout?.toggleSidebar ?? (() => setLocalSidebarExpanded(value => !value));
110
+ const navigate = useNavigate();
111
+
112
+ // Server state
113
+ const { data: teamMembers = [], isLoading: teamLoading } = useTeamMembers();
114
+
115
+ // Client-side UI state (Zustand)
116
+ const progress = useDashboardStore(s => s.progress);
117
+ const setProgress = useDashboardStore(s => s.setProgress);
118
+ const sliderValue = useDashboardStore(s => s.sliderValue);
119
+ const setSliderValue = useDashboardStore(s => s.setSliderValue);
120
+ const switchEnabled = useDashboardStore(s => s.switchEnabled);
121
+ const toggleSwitch = useDashboardStore(s => s.toggleSwitch);
122
+
123
+ // Local UI-only toggles (no global relevance)
124
+ const [showSidebarUser, setShowSidebarUser] = useState(true);
125
+ const [showSidebarSettings, setShowSidebarSettings] = useState(true);
126
+ const [showSidebarLogout, setShowSidebarLogout] = useState(true);
127
+
128
+ // Header State
129
+ const [showHeaderActions, setShowHeaderActions] = useState(true);
130
+ const [showHeaderBreadcrumbs, setShowHeaderBreadcrumbs] = useState(true);
131
+
132
+ const handleFormSubmit = (e: React.FormEvent) => {
133
+ e.preventDefault();
134
+ toast.success(t('templates.formSubmitSuccess'));
135
+ };
136
+
137
+ return (
138
+ <div
139
+ className="flex-1 flex flex-col overflow-hidden transition-all duration-300"
140
+ style={{
141
+ paddingLeft: sidebarExpanded ? `${sidebarWidth}px` : '80px',
142
+ }}
143
+ >
144
+ {/* Sticky Header */}
145
+ <Header
146
+ showThemeToggle={true}
147
+ showLanguageSelector={true}
148
+ breadcrumbs={[
149
+ { label: t('nav.designSystem'), href: '/home', icon: <Home className="w-4 h-4" /> },
150
+ { label: t('templates.breadcrumb') },
151
+ ]}
152
+ renderLink={(href, props) => <Link to={href} {...props} />}
153
+ />
154
+
155
+ {/* Content area */}
156
+ <main className="flex-1 overflow-hidden bg-muted">
157
+ <ScrollArea className="h-full">
158
+ <div className="p-5 sm:p-4 md:p-6">
159
+ <div className="max-w-6xl mx-auto space-y-8">
160
+ {/* Page header */}
161
+ <PageHeader title={t('templates.title')} subtitle={t('templates.subtitle')} />
162
+
163
+ {/* Page Header Example */}
164
+ <section>
165
+ <h3 className="mb-4">{t('templates.headerWithBreadcrumbs.sectionTitle')}</h3>
166
+ <Card>
167
+ <CardHeader>
168
+ <CardTitle>{t('templates.headerWithBreadcrumbs.cardTitle')}</CardTitle>
169
+ <CardDescription>
170
+ {t('templates.headerWithBreadcrumbs.cardDescription')}
171
+ </CardDescription>
172
+ </CardHeader>
173
+ <CardContent className="p-0 border-t bg-background overflow-hidden rounded-b-[var(--radius-lg)]">
174
+ <Header
175
+ className="border-b"
176
+ breadcrumbs={[
177
+ {
178
+ label: t('templates.headerWithBreadcrumbs.breadcrumbs.dashboard'),
179
+ href: '#',
180
+ icon: <Home className="w-4 h-4" />,
181
+ },
182
+ {
183
+ label: t('templates.headerWithBreadcrumbs.breadcrumbs.settings'),
184
+ href: '#',
185
+ icon: <Settings className="w-4 h-4" />,
186
+ },
187
+ {
188
+ label: t('templates.headerWithBreadcrumbs.breadcrumbs.users'),
189
+ href: '#',
190
+ icon: <Users className="w-4 h-4" />,
191
+ },
192
+ { label: t('templates.headerWithBreadcrumbs.breadcrumbs.accessProfile') },
193
+ ]}
194
+ showLanguageSelector={true}
195
+ showThemeToggle={true}
196
+ />
197
+ <div className="p-6 min-h-[200px]">
198
+ <h4 className="text-lg font-semibold mb-2">
199
+ {t('templates.headerWithBreadcrumbs.exampleContentTitle')}
200
+ </h4>
201
+ <p className="text-muted-foreground">
202
+ {t('templates.headerWithBreadcrumbs.exampleContentDescriptionPart1')}
203
+ <strong>Header</strong>
204
+ {t('templates.headerWithBreadcrumbs.exampleContentDescriptionPart2')}
205
+ </p>
206
+ </div>
207
+ </CardContent>
208
+ </Card>
209
+ </section>
210
+
211
+ <Separator className="my-8" />
212
+
213
+ {/* Alert Examples */}
214
+ <section>
215
+ <h3 className="mb-4">{t('templates.sections.alerts')}</h3>
216
+ <div className="grid gap-4 md:grid-cols-2">
217
+ <Alert variant="info">
218
+ <AlertTitle>{t('templates.alerts.infoTitle')}</AlertTitle>
219
+ <AlertDescription>{t('templates.alerts.infoDescription')}</AlertDescription>
220
+ </Alert>
221
+
222
+ <Alert variant="destructive">
223
+ <AlertTitle>{t('templates.alerts.errorTitle')}</AlertTitle>
224
+ <AlertDescription>{t('templates.alerts.errorDescription')}</AlertDescription>
225
+ </Alert>
226
+
227
+ <Alert variant="success">
228
+ <AlertTitle>{t('templates.alerts.successTitle')}</AlertTitle>
229
+ <AlertDescription>{t('templates.alerts.successDescription')}</AlertDescription>
230
+ </Alert>
231
+
232
+ <Alert variant="warning">
233
+ <AlertTitle>{t('templates.alerts.warningTitle')}</AlertTitle>
234
+ <AlertDescription>{t('templates.alerts.warningDescription')}</AlertDescription>
235
+ </Alert>
236
+ </div>
237
+ </section>
238
+
239
+ <Separator className="my-8" />
240
+
241
+ {/* Cards & Tabs */}
242
+ <section>
243
+ <h3 className="mb-4">{t('templates.sections.cardsAndTabs')}</h3>
244
+
245
+ <Tabs defaultValue="overview" className="w-full">
246
+ <TabsList className="grid w-full grid-cols-4">
247
+ <TabsTrigger value="overview">{t('templates.tabs.overview')}</TabsTrigger>
248
+ <TabsTrigger value="forms">{t('templates.tabs.forms')}</TabsTrigger>
249
+ <TabsTrigger value="data">{t('templates.tabs.data')}</TabsTrigger>
250
+ <TabsTrigger value="settings">{t('templates.tabs.settings')}</TabsTrigger>
251
+ </TabsList>
252
+
253
+ {/* Overview Tab */}
254
+ <TabsContent value="overview" className="space-y-4">
255
+ <div className="grid gap-4 md:grid-cols-3">
256
+ <Card>
257
+ <CardHeader>
258
+ <CardTitle>{t('stats.totalUsers')}</CardTitle>
259
+ <CardDescription>{t('stats.last30Days')}</CardDescription>
260
+ </CardHeader>
261
+ <CardContent>
262
+ <div className="text-foreground">
263
+ <span className="[font-size:var(--text-stats)] [font-weight:var(--font-weight-bold)]">
264
+ 1,234
265
+ </span>
266
+ <Badge variant="default" className="ml-2">
267
+ +12%
268
+ </Badge>
269
+ </div>
270
+ </CardContent>
271
+ </Card>
272
+
273
+ <Card>
274
+ <CardHeader>
275
+ <CardTitle>{t('stats.totalRevenue')}</CardTitle>
276
+ <CardDescription>{t('stats.currentMonth')}</CardDescription>
277
+ </CardHeader>
278
+ <CardContent>
279
+ <div className="text-foreground">
280
+ <span className="[font-size:var(--text-stats)] [font-weight:var(--font-weight-bold)]">
281
+ $ 45.2k
282
+ </span>
283
+ <Badge variant="secondary" className="ml-2">
284
+ +8%
285
+ </Badge>
286
+ </div>
287
+ </CardContent>
288
+ </Card>
289
+
290
+ <Card>
291
+ <CardHeader>
292
+ <CardTitle>{t('stats.conversionRate')}</CardTitle>
293
+ <CardDescription>{t('stats.currentWeek')}</CardDescription>
294
+ </CardHeader>
295
+ <CardContent>
296
+ <div className="text-foreground">
297
+ <span className="[font-size:var(--text-stats)] [font-weight:var(--font-weight-bold)]">
298
+ 3.2%
299
+ </span>
300
+ <Badge variant="outline" className="ml-2">
301
+ -2%
302
+ </Badge>
303
+ </div>
304
+ </CardContent>
305
+ </Card>
306
+ </div>
307
+
308
+ <Card>
309
+ <CardHeader>
310
+ <CardTitle>{t('templates.overview.progressTitle')}</CardTitle>
311
+ <CardDescription>
312
+ {t('templates.overview.progressDescription')}
313
+ </CardDescription>
314
+ </CardHeader>
315
+ <CardContent className="space-y-6">
316
+ <div className="space-y-2">
317
+ <div className="flex items-center justify-between">
318
+ <Label>{t('templates.overview.projectProgress')}</Label>
319
+ <span className="[font-size:var(--text-small)] text-muted-foreground">
320
+ {progress}%
321
+ </span>
322
+ </div>
323
+ <Progress value={progress} className="w-full" />
324
+ <div className="flex gap-2">
325
+ <Button
326
+ size="sm"
327
+ onClick={() => setProgress(Math.max(0, progress - 10))}
328
+ >
329
+ -10%
330
+ </Button>
331
+ <Button
332
+ size="sm"
333
+ onClick={() => setProgress(Math.min(100, progress + 10))}
334
+ >
335
+ +10%
336
+ </Button>
337
+ </div>
338
+ </div>
339
+
340
+ <Separator />
341
+
342
+ <div className="space-y-2">
343
+ <div className="flex items-center justify-between">
344
+ <Label>{t('templates.overview.volume')}</Label>
345
+ <span className="[font-size:var(--text-small)] text-muted-foreground">
346
+ {sliderValue[0]}%
347
+ </span>
348
+ </div>
349
+ <Slider
350
+ value={sliderValue}
351
+ onValueChange={setSliderValue}
352
+ min={0}
353
+ max={100}
354
+ step={1}
355
+ className="w-full"
356
+ aria-label={t('templates.overview.volume')}
357
+ />
358
+ </div>
359
+ </CardContent>
360
+ </Card>
361
+ </TabsContent>
362
+
363
+ {/* Forms Tab */}
364
+ <TabsContent value="forms" className="space-y-4">
365
+ <Card>
366
+ <CardHeader>
367
+ <CardTitle>{t('templates.forms.registrationTitle')}</CardTitle>
368
+ <CardDescription>
369
+ {t('templates.forms.registrationDescription')}
370
+ </CardDescription>
371
+ </CardHeader>
372
+ <CardContent>
373
+ <form onSubmit={handleFormSubmit} className="space-y-4">
374
+ <div className="grid gap-4 md:grid-cols-2">
375
+ <div className="space-y-2">
376
+ <Label htmlFor="firstName">{t('templates.forms.firstName')}</Label>
377
+ <Input
378
+ id="firstName"
379
+ placeholder={t('templates.forms.firstNamePlaceholder')}
380
+ />
381
+ </div>
382
+ <div className="space-y-2">
383
+ <Label htmlFor="lastName">{t('templates.forms.lastName')}</Label>
384
+ <Input
385
+ id="lastName"
386
+ placeholder={t('templates.forms.lastNamePlaceholder')}
387
+ />
388
+ </div>
389
+ </div>
390
+
391
+ <div className="space-y-2">
392
+ <Label htmlFor="email">{t('templates.forms.email')}</Label>
393
+ <div className="relative">
394
+ <Mail className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
395
+ <Input
396
+ id="email"
397
+ type="email"
398
+ placeholder={t('templates.forms.emailPlaceholder')}
399
+ className="pl-10"
400
+ />
401
+ </div>
402
+ </div>
403
+
404
+ <div className="space-y-2">
405
+ <Label htmlFor="phone">{t('templates.forms.phone')}</Label>
406
+ <div className="relative">
407
+ <Phone className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
408
+ <Input
409
+ id="phone"
410
+ type="tel"
411
+ placeholder={t('templates.forms.phonePlaceholder')}
412
+ className="pl-10"
413
+ />
414
+ </div>
415
+ </div>
416
+
417
+ <div className="space-y-2">
418
+ <Label htmlFor="role">{t('templates.forms.role')}</Label>
419
+ <Select>
420
+ <SelectTrigger id="role">
421
+ <SelectValue placeholder={t('templates.forms.rolePlaceholder')} />
422
+ </SelectTrigger>
423
+ <SelectContent>
424
+ <SelectItem value="developer">
425
+ {t('templates.forms.roles.developer')}
426
+ </SelectItem>
427
+ <SelectItem value="designer">
428
+ {t('templates.forms.roles.designer')}
429
+ </SelectItem>
430
+ <SelectItem value="manager">
431
+ {t('templates.forms.roles.manager')}
432
+ </SelectItem>
433
+ <SelectItem value="analyst">
434
+ {t('templates.forms.roles.analyst')}
435
+ </SelectItem>
436
+ </SelectContent>
437
+ </Select>
438
+ </div>
439
+
440
+ <div className="space-y-2">
441
+ <Label htmlFor="bio">{t('templates.forms.bio')}</Label>
442
+ <Textarea
443
+ id="bio"
444
+ placeholder={t('templates.forms.bioPlaceholder')}
445
+ rows={4}
446
+ />
447
+ </div>
448
+
449
+ <Separator />
450
+
451
+ <div className="space-y-4">
452
+ <h4>{t('templates.forms.preferences')}</h4>
453
+
454
+ <div className="space-y-3">
455
+ <div className="flex items-center space-x-2">
456
+ <Checkbox id="newsletter" />
457
+ <Label htmlFor="newsletter" className="font-normal">
458
+ {t('templates.forms.newsletter')}
459
+ </Label>
460
+ </div>
461
+
462
+ <div className="flex items-center space-x-2">
463
+ <Checkbox id="notifications" />
464
+ <Label htmlFor="notifications" className="font-normal">
465
+ {t('templates.forms.pushNotifications')}
466
+ </Label>
467
+ </div>
468
+
469
+ <div className="flex items-center space-x-2">
470
+ <Checkbox id="updates" />
471
+ <Label htmlFor="updates" className="font-normal">
472
+ {t('templates.forms.featureUpdates')}
473
+ </Label>
474
+ </div>
475
+ </div>
476
+
477
+ <Separator />
478
+
479
+ <div className="space-y-3">
480
+ <Label>{t('templates.forms.accountType')}</Label>
481
+ <RadioGroup
482
+ defaultValue="personal"
483
+ aria-label={t('templates.forms.accountType')}
484
+ >
485
+ <div className="flex items-center space-x-2">
486
+ <RadioGroupItem value="personal" id="personal" />
487
+ <Label htmlFor="personal" className="font-normal">
488
+ {t('templates.forms.accountPersonal')}
489
+ </Label>
490
+ </div>
491
+ <div className="flex items-center space-x-2">
492
+ <RadioGroupItem value="business" id="business" />
493
+ <Label htmlFor="business" className="font-normal">
494
+ {t('templates.forms.accountBusiness')}
495
+ </Label>
496
+ </div>
497
+ <div className="flex items-center space-x-2">
498
+ <RadioGroupItem value="enterprise" id="enterprise" />
499
+ <Label htmlFor="enterprise" className="font-normal">
500
+ {t('templates.forms.accountEnterprise')}
501
+ </Label>
502
+ </div>
503
+ </RadioGroup>
504
+ </div>
505
+ </div>
506
+ </form>
507
+ </CardContent>
508
+ <CardFooter className="flex justify-between">
509
+ <Button variant="outline">{t('templates.forms.cancel')}</Button>
510
+ <Button onClick={handleFormSubmit}>
511
+ {t('templates.forms.createAccount')}
512
+ </Button>
513
+ </CardFooter>
514
+ </Card>
515
+ </TabsContent>
516
+
517
+ {/* Data Tab */}
518
+ <TabsContent value="data" className="space-y-4">
519
+ <SectionErrorBoundary>
520
+ <Card>
521
+ <CardHeader>
522
+ <CardTitle>{t('templates.data.title')}</CardTitle>
523
+ <CardDescription>{t('templates.data.description')}</CardDescription>
524
+ </CardHeader>
525
+ <CardContent>
526
+ <div className="mb-4">
527
+ <div className="relative">
528
+ <Search className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
529
+ <Input
530
+ placeholder={t('templates.data.searchPlaceholder')}
531
+ aria-label={t('templates.data.searchPlaceholder')}
532
+ className="pl-10"
533
+ />
534
+ </div>
535
+ </div>
536
+
537
+ <div className="rounded-[var(--radius-lg)] border border-border overflow-hidden">
538
+ <Table>
539
+ <TableHeader>
540
+ <TableRow>
541
+ <TableHead>{t('team.name')}</TableHead>
542
+ <TableHead>{t('team.email')}</TableHead>
543
+ <TableHead>{t('team.role')}</TableHead>
544
+ <TableHead>{t('team.status')}</TableHead>
545
+ <TableHead className="text-right">{t('team.actions')}</TableHead>
546
+ </TableRow>
547
+ </TableHeader>
548
+ <TableBody>
549
+ {teamLoading ? (
550
+ <>
551
+ {Array.from({ length: 5 }).map((_, i) => (
552
+ <TableRow key={i}>
553
+ <TableCell>
554
+ <div className="flex items-center gap-2">
555
+ <Skeleton className="size-8 rounded-full shrink-0" />
556
+ <Skeleton className="h-3.5 w-28" />
557
+ </div>
558
+ </TableCell>
559
+ <TableCell>
560
+ <Skeleton className="h-3.5 w-36" />
561
+ </TableCell>
562
+ <TableCell>
563
+ <Skeleton className="h-3.5 w-20" />
564
+ </TableCell>
565
+ <TableCell>
566
+ <Skeleton className="h-5 w-16 rounded-full" />
567
+ </TableCell>
568
+ <TableCell className="text-right">
569
+ <Skeleton className="h-7 w-14 ml-auto" />
570
+ </TableCell>
571
+ </TableRow>
572
+ ))}
573
+ </>
574
+ ) : (
575
+ teamMembers.map(member => (
576
+ <TableRow key={member.id}>
577
+ <TableCell>{member.name}</TableCell>
578
+ <TableCell>{member.email}</TableCell>
579
+ <TableCell>{t(`team.roles.${member.role}`)}</TableCell>
580
+ <TableCell>
581
+ <Badge
582
+ variant={
583
+ member.status === 'active'
584
+ ? 'default'
585
+ : member.status === 'away'
586
+ ? 'secondary'
587
+ : 'outline'
588
+ }
589
+ >
590
+ {t(`common.${member.status}`)}
591
+ </Badge>
592
+ </TableCell>
593
+ <TableCell className="text-right">
594
+ <Button variant="ghost" size="sm">
595
+ {t('common.edit')}
596
+ </Button>
597
+ </TableCell>
598
+ </TableRow>
599
+ ))
600
+ )}
601
+ </TableBody>
602
+ </Table>
603
+ </div>
604
+ </CardContent>
605
+ <CardFooter className="flex justify-between items-center">
606
+ <p className="text-muted-foreground">
607
+ {t('team.showing', {
608
+ count: teamMembers.length,
609
+ total: teamMembers.length,
610
+ })}
611
+ </p>
612
+ <div className="flex gap-2">
613
+ <Button variant="outline" size="sm">
614
+ {t('common.previous')}
615
+ </Button>
616
+ <Button variant="outline" size="sm">
617
+ {t('common.next')}
618
+ </Button>
619
+ </div>
620
+ </CardFooter>
621
+ </Card>
622
+ </SectionErrorBoundary>
623
+ </TabsContent>
624
+
625
+ {/* Settings Tab */}
626
+ <TabsContent value="settings" className="space-y-4">
627
+ <Card>
628
+ <CardHeader>
629
+ <CardTitle>{t('templates.settings.title')}</CardTitle>
630
+ <CardDescription>{t('templates.settings.description')}</CardDescription>
631
+ </CardHeader>
632
+ <CardContent className="space-y-6">
633
+ {!disableDarkMode && (
634
+ <>
635
+ <div className="flex items-center justify-between">
636
+ <div className="space-y-1">
637
+ <Label htmlFor="dark-mode">
638
+ {t('templates.settings.darkMode')}
639
+ </Label>
640
+ <p className="text-muted-foreground">
641
+ {t('templates.settings.darkModeDescription')}
642
+ </p>
643
+ </div>
644
+ <Switch
645
+ id="dark-mode"
646
+ checked={switchEnabled}
647
+ onCheckedChange={toggleSwitch}
648
+ />
649
+ </div>
650
+
651
+ <Separator />
652
+ </>
653
+ )}
654
+
655
+ <div className="flex items-center justify-between">
656
+ <div className="space-y-1">
657
+ <Label htmlFor="email-notifications">
658
+ {t('templates.settings.emailNotifications')}
659
+ </Label>
660
+ <p className="text-muted-foreground">
661
+ {t('templates.settings.emailNotificationsDescription')}
662
+ </p>
663
+ </div>
664
+ <Switch id="email-notifications" defaultChecked />
665
+ </div>
666
+
667
+ <Separator />
668
+
669
+ <div className="flex items-center justify-between">
670
+ <div className="space-y-1">
671
+ <Label htmlFor="push-notifications">
672
+ {t('templates.settings.pushNotifications')}
673
+ </Label>
674
+ <p className="text-muted-foreground">
675
+ {t('templates.settings.pushNotificationsDescription')}
676
+ </p>
677
+ </div>
678
+ <Switch id="push-notifications" />
679
+ </div>
680
+
681
+ <Separator />
682
+
683
+ <div className="space-y-3">
684
+ <Label>{t('templates.settings.language')}</Label>
685
+ <Select defaultValue="pt-br">
686
+ <SelectTrigger aria-label={t('templates.settings.language')}>
687
+ <SelectValue />
688
+ </SelectTrigger>
689
+ <SelectContent>
690
+ <SelectItem value="pt-br">
691
+ {t('templates.settings.languages.ptBR')}
692
+ </SelectItem>
693
+ <SelectItem value="en">
694
+ {t('templates.settings.languages.en')}
695
+ </SelectItem>
696
+ <SelectItem value="es">
697
+ {t('templates.settings.languages.es')}
698
+ </SelectItem>
699
+ </SelectContent>
700
+ </Select>
701
+ </div>
702
+
703
+ <Separator />
704
+
705
+ <div className="space-y-3">
706
+ <Label>{t('templates.settings.timezone')}</Label>
707
+ <Select defaultValue="america-sao-paulo">
708
+ <SelectTrigger aria-label={t('templates.settings.timezone')}>
709
+ <SelectValue />
710
+ </SelectTrigger>
711
+ <SelectContent>
712
+ <SelectItem value="america-sao-paulo">
713
+ {t('templates.settings.timezones.saoPaulo')}
714
+ </SelectItem>
715
+ <SelectItem value="america-new-york">
716
+ {t('templates.settings.timezones.newYork')}
717
+ </SelectItem>
718
+ <SelectItem value="europe-london">
719
+ {t('templates.settings.timezones.london')}
720
+ </SelectItem>
721
+ </SelectContent>
722
+ </Select>
723
+ </div>
724
+ </CardContent>
725
+ <CardFooter className="flex justify-between">
726
+ <Button variant="outline">{t('templates.settings.restoreDefaults')}</Button>
727
+ <Button>{t('templates.settings.saveChanges')}</Button>
728
+ </CardFooter>
729
+ </Card>
730
+ </TabsContent>
731
+ </Tabs>
732
+ </section>
733
+
734
+ <Separator className="my-8" />
735
+
736
+ {/* Button Variants */}
737
+ <section>
738
+ <h3 className="mb-4">{t('templates.sections.buttons')}</h3>
739
+ <Card>
740
+ <CardHeader>
741
+ <CardTitle>{t('templates.buttons.title')}</CardTitle>
742
+ <CardDescription>{t('templates.buttons.description')}</CardDescription>
743
+ </CardHeader>
744
+ <CardContent className="space-y-6">
745
+ <div className="space-y-3">
746
+ <Label>{t('templates.buttons.variants')}</Label>
747
+ <div className="flex flex-wrap gap-3">
748
+ <Button variant="default">Default</Button>
749
+ <Button variant="secondary">Secondary</Button>
750
+ <Button variant="outline">Outline</Button>
751
+ <Button variant="ghost">Ghost</Button>
752
+ <Button variant="link">Link</Button>
753
+ <Button variant="destructive">Destructive</Button>
754
+ </div>
755
+ </div>
756
+
757
+ <Separator />
758
+
759
+ <div className="space-y-3">
760
+ <Label>{t('templates.buttons.sizes')}</Label>
761
+ <div className="flex flex-wrap items-center gap-3">
762
+ <Button size="sm">Small</Button>
763
+ <Button size="default">Default</Button>
764
+ <Button size="lg">Large</Button>
765
+ <Button size="icon" aria-label={t('nav.settings')}>
766
+ <Settings className="h-4 w-4" />
767
+ </Button>
768
+ </div>
769
+ </div>
770
+
771
+ <Separator />
772
+
773
+ <div className="space-y-3">
774
+ <Label>{t('templates.buttons.withIcons')}</Label>
775
+ <div className="flex flex-wrap gap-3">
776
+ <Button>
777
+ <User className="mr-2 h-4 w-4" />
778
+ {t('templates.buttons.profile')}
779
+ </Button>
780
+ <Button variant="secondary">
781
+ <Mail className="mr-2 h-4 w-4" />
782
+ {t('templates.buttons.messages')}
783
+ </Button>
784
+ <Button variant="outline">
785
+ <Calendar className="mr-2 h-4 w-4" />
786
+ {t('templates.buttons.schedule')}
787
+ </Button>
788
+ </div>
789
+ </div>
790
+
791
+ <Separator />
792
+
793
+ <div className="space-y-3">
794
+ <Label>{t('templates.buttons.states')}</Label>
795
+ <div className="flex flex-wrap gap-3">
796
+ <Button disabled>{t('templates.buttons.disabled')}</Button>
797
+ <Button variant="outline" disabled>
798
+ {t('templates.buttons.outlineDisabled')}
799
+ </Button>
800
+ </div>
801
+ </div>
802
+ </CardContent>
803
+ </Card>
804
+ </section>
805
+
806
+ <Separator className="my-8" />
807
+
808
+ {/* Badges */}
809
+ <section>
810
+ <h3 className="mb-4">{t('templates.sections.badges')}</h3>
811
+ <Card>
812
+ <CardHeader>
813
+ <CardTitle>{t('templates.badges.title')}</CardTitle>
814
+ <CardDescription>{t('templates.badges.description')}</CardDescription>
815
+ </CardHeader>
816
+ <CardContent>
817
+ <div className="flex flex-wrap gap-3">
818
+ <Badge variant="default">Default</Badge>
819
+ <Badge variant="secondary">Secondary</Badge>
820
+ <Badge variant="outline">Outline</Badge>
821
+ <Badge variant="destructive">Destructive</Badge>
822
+ <Badge className="bg-success text-success-foreground">Success</Badge>
823
+ <Badge className="bg-warning text-warning-foreground">Warning</Badge>
824
+ <Badge className="bg-info text-info-foreground">Info</Badge>
825
+ </div>
826
+ </CardContent>
827
+ </Card>
828
+ </section>
829
+
830
+ <Separator className="my-8" />
831
+
832
+ {/* Dialogs */}
833
+ <section>
834
+ <h3 className="mb-4">{t('templates.sections.dialogs')}</h3>
835
+ <div className="grid gap-4 md:grid-cols-2">
836
+ <Card>
837
+ <CardHeader>
838
+ <CardTitle>{t('templates.dialogs.dialogTitle')}</CardTitle>
839
+ <CardDescription>{t('templates.dialogs.dialogDescription')}</CardDescription>
840
+ </CardHeader>
841
+ <CardContent className="flex justify-center py-6">
842
+ <Dialog>
843
+ <DialogTrigger asChild>
844
+ <Button variant="outline">{t('templates.dialogs.editProfile')}</Button>
845
+ </DialogTrigger>
846
+ <DialogContent className="sm:max-w-[425px]">
847
+ <DialogHeader>
848
+ <DialogTitle>{t('templates.dialogs.editProfile')}</DialogTitle>
849
+ <DialogDescription>
850
+ {t('templates.dialogs.editProfileDescription')}
851
+ </DialogDescription>
852
+ </DialogHeader>
853
+ <div className="grid gap-4 py-4">
854
+ <div className="grid grid-cols-4 items-center gap-4">
855
+ <Label htmlFor="name" className="text-right">
856
+ {t('templates.dialogs.name')}
857
+ </Label>
858
+ <Input id="name" defaultValue="John Doe" className="col-span-3" />
859
+ </div>
860
+ <div className="grid grid-cols-4 items-center gap-4">
861
+ <Label htmlFor="username" className="text-right">
862
+ {t('templates.dialogs.username')}
863
+ </Label>
864
+ <Input id="username" defaultValue="@johndoe" className="col-span-3" />
865
+ </div>
866
+ </div>
867
+ <DialogFooter>
868
+ <Button type="submit">{t('templates.dialogs.update')}</Button>
869
+ </DialogFooter>
870
+ </DialogContent>
871
+ </Dialog>
872
+ </CardContent>
873
+ </Card>
874
+
875
+ <Card>
876
+ <CardHeader>
877
+ <CardTitle>{t('templates.dialogs.alertDialogTitle')}</CardTitle>
878
+ <CardDescription>
879
+ {t('templates.dialogs.alertDialogDescription')}
880
+ </CardDescription>
881
+ </CardHeader>
882
+ <CardContent className="flex justify-center py-6">
883
+ <AlertDialog>
884
+ <AlertDialogTrigger asChild>
885
+ <Button variant="destructive">
886
+ {t('templates.dialogs.deleteAccount')}
887
+ </Button>
888
+ </AlertDialogTrigger>
889
+ <AlertDialogContent className="sm:max-w-[425px]">
890
+ <AlertDialogHeader>
891
+ <AlertDialogTitle>{t('templates.dialogs.areYouSure')}</AlertDialogTitle>
892
+ <AlertDialogDescription>
893
+ {t('templates.dialogs.deleteWarning')}
894
+ </AlertDialogDescription>
895
+ </AlertDialogHeader>
896
+ <AlertDialogFooter>
897
+ <AlertDialogCancel>{t('templates.dialogs.cancel')}</AlertDialogCancel>
898
+ <AlertDialogAction className="bg-destructive text-destructive-foreground hover:bg-destructive/90">
899
+ {t('templates.dialogs.continue')}
900
+ </AlertDialogAction>
901
+ </AlertDialogFooter>
902
+ </AlertDialogContent>
903
+ </AlertDialog>
904
+ </CardContent>
905
+ </Card>
906
+ </div>
907
+ </section>
908
+
909
+ <Separator className="my-8" />
910
+
911
+ {/* Maps */}
912
+ <section>
913
+ <MapShowcase />
914
+ </section>
915
+
916
+ <Separator className="my-8" />
917
+
918
+ {/* Header Variations */}
919
+ <section>
920
+ <h3 className="mb-4">{t('templates.headerVariations.sectionTitle')}</h3>
921
+ <Card>
922
+ <CardHeader>
923
+ <CardTitle>{t('templates.headerVariations.cardTitle')}</CardTitle>
924
+ <CardDescription>
925
+ {t('templates.headerVariations.cardDescription')}
926
+ </CardDescription>
927
+ </CardHeader>
928
+ <CardContent className="space-y-6">
929
+ <div className="p-4 border rounded-[var(--radius-lg)] bg-muted/30">
930
+ <h4 className="text-sm font-semibold mb-4">
931
+ {t('templates.headerVariations.visibleElements')}
932
+ </h4>
933
+ <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-6">
934
+ <div className="flex items-center space-x-2">
935
+ <Switch
936
+ id="header-actions"
937
+ checked={showHeaderActions}
938
+ onCheckedChange={setShowHeaderActions}
939
+ />
940
+ <Label htmlFor="header-actions" className="cursor-pointer">
941
+ {t('templates.headerVariations.actionButtons')}
942
+ </Label>
943
+ </div>
944
+ <div className="flex items-center space-x-2">
945
+ <Switch
946
+ id="header-bread"
947
+ checked={showHeaderBreadcrumbs}
948
+ onCheckedChange={setShowHeaderBreadcrumbs}
949
+ />
950
+ <Label htmlFor="header-bread" className="cursor-pointer">
951
+ {t('templates.headerVariations.breadcrumbsLabel')}
952
+ </Label>
953
+ </div>
954
+ </div>
955
+ </div>
956
+
957
+ <div className="relative border rounded-[var(--radius-lg)] bg-muted/10 overflow-hidden shadow-inner">
958
+ <div className="p-4 bg-background/50 border-b text-xs font-mono text-muted-foreground">
959
+ {t('templates.headerVariations.preview')}
960
+ </div>
961
+ <Header
962
+ title={
963
+ !showHeaderBreadcrumbs
964
+ ? t('templates.headerVariations.currentPage')
965
+ : undefined
966
+ }
967
+ breadcrumbs={
968
+ showHeaderBreadcrumbs
969
+ ? [
970
+ {
971
+ label: t('templates.headerVariations.breadcrumbBrand'),
972
+ href: '#',
973
+ icon: <Home className="w-4 h-4" />,
974
+ },
975
+ {
976
+ label: t('templates.headerVariations.breadcrumbSettings'),
977
+ href: '#',
978
+ },
979
+ { label: t('templates.headerVariations.breadcrumbProfile') },
980
+ ]
981
+ : undefined
982
+ }
983
+ actions={
984
+ showHeaderActions
985
+ ? [
986
+ {
987
+ id: 'notify',
988
+ icon: <Bell className="w-5 h-5" />,
989
+ onClick: () =>
990
+ toast(t('templates.headerVariations.notificationsOpenedToast')),
991
+ },
992
+ {
993
+ id: 'mail',
994
+ label: t('templates.headerVariations.messagesLabel'),
995
+ icon: <Mail className="w-5 h-5" />,
996
+ onClick: () =>
997
+ toast(t('templates.headerVariations.messagesOpenedToast')),
998
+ },
999
+ ]
1000
+ : undefined
1001
+ }
1002
+ />
1003
+ <div className="h-32 flex items-center justify-center text-muted-foreground text-sm italic">
1004
+ {t('templates.headerVariations.contentArea')}
1005
+ </div>
1006
+ </div>
1007
+ </CardContent>
1008
+ </Card>
1009
+ </section>
1010
+
1011
+ <Separator className="my-8" />
1012
+
1013
+ {/* Sidebar Variations */}
1014
+ <section>
1015
+ <h3 className="mb-4">{t('templates.sections.sidebarVariations')}</h3>
1016
+ <Card>
1017
+ <CardHeader>
1018
+ <CardTitle>{t('templates.sidebar.title')}</CardTitle>
1019
+ <CardDescription>{t('templates.sidebar.description')}</CardDescription>
1020
+ </CardHeader>
1021
+ <CardContent>
1022
+ <Tabs defaultValue="assistant" className="w-full">
1023
+ <TabsList className="mb-4">
1024
+ <TabsTrigger value="assistant">
1025
+ {t('templates.sidebar.assistantMode')}
1026
+ </TabsTrigger>
1027
+ <TabsTrigger value="default">
1028
+ {t('templates.sidebar.defaultMode')}
1029
+ </TabsTrigger>
1030
+ </TabsList>
1031
+
1032
+ <div className="mb-6 p-4 border rounded-[var(--radius-lg)] bg-muted/30">
1033
+ <h4 className="text-sm font-semibold mb-4">
1034
+ {t('templates.sidebarControls.footerSettings')}
1035
+ </h4>
1036
+ <div className="flex flex-wrap gap-6 mt-2">
1037
+ <div className="flex items-center space-x-2">
1038
+ <Switch
1039
+ id="show-user"
1040
+ checked={showSidebarUser}
1041
+ onCheckedChange={setShowSidebarUser}
1042
+ />
1043
+ <Label htmlFor="show-user" className="cursor-pointer">
1044
+ {t('templates.sidebarControls.userProfile')}
1045
+ </Label>
1046
+ </div>
1047
+ <div className="flex items-center space-x-2">
1048
+ <Switch
1049
+ id="show-settings"
1050
+ checked={showSidebarSettings}
1051
+ onCheckedChange={setShowSidebarSettings}
1052
+ />
1053
+ <Label htmlFor="show-settings" className="cursor-pointer">
1054
+ {t('templates.sidebarControls.settings')}
1055
+ </Label>
1056
+ </div>
1057
+ <div className="flex items-center space-x-2">
1058
+ <Switch
1059
+ id="show-logout"
1060
+ checked={showSidebarLogout}
1061
+ onCheckedChange={setShowSidebarLogout}
1062
+ />
1063
+ <Label htmlFor="show-logout" className="cursor-pointer">
1064
+ {t('templates.sidebarControls.logoutButton')}
1065
+ </Label>
1066
+ </div>
1067
+ </div>
1068
+
1069
+ <div className="mt-6 pt-6 border-t">
1070
+ <div className="flex items-center justify-between mb-4">
1071
+ <h4 className="text-sm font-semibold">
1072
+ {t('templates.sidebarControls.sidebarWidthDesktop')}
1073
+ </h4>
1074
+ <span className="text-xs font-mono bg-muted px-2 py-1 rounded">
1075
+ {sidebarWidth}px
1076
+ </span>
1077
+ </div>
1078
+ <div className="flex items-center gap-4">
1079
+ <span className="text-xs text-muted-foreground w-12 text-right">
1080
+ 240px
1081
+ </span>
1082
+ <Slider
1083
+ value={[sidebarWidth]}
1084
+ onValueChange={val => setSidebarWidth(val[0])}
1085
+ min={240}
1086
+ max={450}
1087
+ step={10}
1088
+ className="flex-1"
1089
+ aria-label={t('templates.sidebarControls.sidebarWidthAriaLabel')}
1090
+ />
1091
+ <span className="text-xs text-muted-foreground w-12">450px</span>
1092
+ </div>
1093
+ </div>
1094
+ </div>
1095
+
1096
+ <TabsContent value="assistant">
1097
+ <div
1098
+ className="relative h-[600px] border rounded-[var(--radius-lg)] bg-muted/20 overflow-hidden"
1099
+ style={{ transform: 'translateZ(0)' }}
1100
+ >
1101
+ <Sidebar
1102
+ expanded={true}
1103
+ width={sidebarWidth}
1104
+ onToggle={() => {}}
1105
+ user={{ email: 'admin@xertica.com' }}
1106
+ onLogout={() => toast(t('templates.sidebar.logoutToast'))}
1107
+ location={{ pathname: '/assistant/current' }}
1108
+ navigate={() => {}}
1109
+ variant="assistant"
1110
+ search={{
1111
+ show: true,
1112
+ placeholder: t('templates.sidebar.searchTopicsPlaceholder'),
1113
+ filter: {
1114
+ show: true,
1115
+ content: (
1116
+ <div className="p-2 space-y-2">
1117
+ <div className="text-xs font-semibold uppercase text-muted-foreground px-2">
1118
+ {t('templates.sidebarControls.filterByStatus')}
1119
+ </div>
1120
+ <div className="flex flex-wrap gap-2 p-1">
1121
+ <Badge className="bg-sidebar-foreground/20 text-sidebar-foreground border-none cursor-pointer hover:bg-sidebar-foreground/30">
1122
+ {t('templates.sidebarControls.filterActive')}
1123
+ </Badge>
1124
+ <Badge
1125
+ variant="outline"
1126
+ className="text-sidebar-foreground/70 border-sidebar-foreground/20 cursor-pointer hover:bg-sidebar-foreground/10"
1127
+ >
1128
+ {t('templates.sidebarControls.filterArchived')}
1129
+ </Badge>
1130
+ <Badge
1131
+ variant="outline"
1132
+ className="text-sidebar-foreground/70 border-sidebar-foreground/20 cursor-pointer hover:bg-sidebar-foreground/10"
1133
+ >
1134
+ {t('templates.sidebarControls.filterPending')}
1135
+ </Badge>
1136
+ </div>
1137
+ </div>
1138
+ ),
1139
+ },
1140
+ }}
1141
+ fixedArea={{
1142
+ show: true,
1143
+ content: (
1144
+ <Button className="w-full bg-sidebar-primary hover:bg-sidebar-primary/90 text-sidebar-primary-foreground shadow-lg font-bold border-none transition-all duration-300 transform hover:scale-[1.02] active:scale-[0.98]">
1145
+ <Plus className="w-4 h-4 mr-2" />
1146
+ {t('templates.sidebar.newConversation')}
1147
+ </Button>
1148
+ ),
1149
+ }}
1150
+ navigationGroups={[
1151
+ {
1152
+ id: 'recent',
1153
+ label: t('templates.sidebar.recent'),
1154
+ icon: Clock,
1155
+ items: [
1156
+ {
1157
+ path: '/assistant/refatoracao',
1158
+ label: t('templates.sidebar.items.sidebarRefactor'),
1159
+ description: t(
1160
+ 'templates.sidebar.items.sidebarRefactorDescription'
1161
+ ),
1162
+ actions: [
1163
+ {
1164
+ label: t('templates.sidebar.actions.rename'),
1165
+ icon: FileEdit,
1166
+ onClick: () =>
1167
+ toast(t('templates.sidebar.actions.renameToast')),
1168
+ },
1169
+ {
1170
+ label: t('templates.sidebar.actions.move'),
1171
+ icon: ArrowRightLeft,
1172
+ children: [
1173
+ {
1174
+ label: t('templates.sidebar.actions.moveActive'),
1175
+ onClick: () =>
1176
+ toast(t('templates.sidebar.actions.moveActiveToast')),
1177
+ },
1178
+ {
1179
+ label: t('templates.sidebar.actions.moveMonitoring'),
1180
+ onClick: () =>
1181
+ toast(
1182
+ t('templates.sidebar.actions.moveMonitoringToast')
1183
+ ),
1184
+ },
1185
+ {
1186
+ label: t('templates.sidebar.actions.moveArchive'),
1187
+ onClick: () =>
1188
+ toast(
1189
+ t('templates.sidebar.actions.moveArchiveToast')
1190
+ ),
1191
+ },
1192
+ ],
1193
+ },
1194
+ {
1195
+ label: t('templates.sidebar.actions.clear'),
1196
+ icon: Trash2,
1197
+ onClick: () =>
1198
+ toast(t('templates.sidebar.actions.clearToast')),
1199
+ variant: 'destructive',
1200
+ },
1201
+ ],
1202
+ },
1203
+ ],
1204
+ },
1205
+ {
1206
+ id: 'projects',
1207
+ label: t('templates.sidebar.constructionMonitoring'),
1208
+ icon: Map,
1209
+ actions: [
1210
+ {
1211
+ label: t('templates.sidebar.actions.newCategory'),
1212
+ icon: Plus,
1213
+ onClick: () =>
1214
+ toast(t('templates.sidebar.actions.newCategoryToast')),
1215
+ },
1216
+ {
1217
+ label: t('templates.sidebar.actions.archiveGroup'),
1218
+ icon: Archive,
1219
+ onClick: () =>
1220
+ toast(t('templates.sidebar.actions.archiveGroupToast')),
1221
+ },
1222
+ ],
1223
+ items: [
1224
+ {
1225
+ path: '/assistant/br163',
1226
+ label: t('templates.sidebar.items.br163Restoration'),
1227
+ icon: () => (
1228
+ <div className="w-2 h-2 rounded-full bg-yellow-500" />
1229
+ ),
1230
+ description: (
1231
+ <div className="space-y-1.5 min-w-[160px]">
1232
+ <Progress
1233
+ value={67}
1234
+ className="h-1.5 bg-sidebar-foreground/10"
1235
+ />
1236
+ <div className="flex justify-between items-center text-[10px] text-sidebar-foreground/60">
1237
+ <span>{t('templates.sidebar.items.br163Location')}</span>
1238
+ <span>67%</span>
1239
+ </div>
1240
+ </div>
1241
+ ),
1242
+ },
1243
+ ],
1244
+ },
1245
+ ]}
1246
+ footer={{
1247
+ showUser: showSidebarUser,
1248
+ showSettings: showSidebarSettings,
1249
+ showLogout: showSidebarLogout,
1250
+ }}
1251
+ />
1252
+ <div
1253
+ className="absolute inset-y-0 right-0 p-8 flex items-center justify-center transition-all duration-300"
1254
+ style={{ left: `${sidebarWidth}px` }}
1255
+ >
1256
+ <p className="text-muted-foreground text-center">
1257
+ {t('templates.sidebar.assistantContent')}
1258
+ </p>
1259
+ </div>
1260
+ </div>
1261
+ </TabsContent>
1262
+
1263
+ <TabsContent value="default">
1264
+ <div
1265
+ className="relative h-[600px] border rounded-[var(--radius-lg)] bg-muted/20 overflow-hidden"
1266
+ style={{ transform: 'translateZ(0)' }}
1267
+ >
1268
+ <Sidebar
1269
+ expanded={true}
1270
+ width={sidebarWidth}
1271
+ onToggle={() => {}}
1272
+ user={{
1273
+ name: 'Ariel Santos',
1274
+ email: 'admin@xertica.com',
1275
+ avatar: 'https://github.com/shadcn.png',
1276
+ }}
1277
+ onLogout={() => toast(t('templates.sidebar.logoutToast'))}
1278
+ onSettingsClick={() =>
1279
+ toast(t('templates.sidebar.settingsClickedToast'))
1280
+ }
1281
+ location={{ pathname: '/home' }}
1282
+ navigate={() => {}}
1283
+ variant="default"
1284
+ routes={[
1285
+ {
1286
+ path: '/home',
1287
+ label: t('templates.sidebar.routes.home'),
1288
+ icon: Home,
1289
+ },
1290
+ {
1291
+ path: '/dashboard',
1292
+ label: t('templates.sidebar.routes.dashboard'),
1293
+ icon: Users,
1294
+ },
1295
+ {
1296
+ path: '/settings',
1297
+ label: t('templates.sidebar.routes.settings'),
1298
+ icon: Settings,
1299
+ },
1300
+ ]}
1301
+ footer={{
1302
+ showUser: showSidebarUser,
1303
+ showSettings: showSidebarSettings,
1304
+ showLogout: showSidebarLogout,
1305
+ }}
1306
+ />
1307
+ <div
1308
+ className="absolute inset-y-0 right-0 p-8 flex items-center justify-center transition-all duration-300"
1309
+ style={{ left: `${sidebarWidth}px` }}
1310
+ >
1311
+ <p className="text-muted-foreground text-center">
1312
+ {t('templates.sidebar.defaultContent')}
1313
+ </p>
1314
+ </div>
1315
+ </div>
1316
+ </TabsContent>
1317
+ </Tabs>
1318
+ </CardContent>
1319
+ </Card>
1320
+ </section>
1321
+
1322
+ <Separator className="my-8" />
1323
+
1324
+ {/* Footer Note */}
1325
+ <Card className="mt-8">
1326
+ <CardHeader>
1327
+ <CardTitle>{t('templates.footer.title')}</CardTitle>
1328
+ <CardDescription>{t('templates.footer.subtitle')}</CardDescription>
1329
+ </CardHeader>
1330
+ <CardContent className="space-y-4">
1331
+ <p className="text-muted-foreground">
1332
+ {t('templates.footer.descriptionPart1')}
1333
+ <code className="bg-muted px-2 py-1 rounded-[var(--radius-sm)] [font-size:var(--text-small)]">
1334
+ xertica-ui
1335
+ </code>
1336
+ {t('templates.footer.descriptionPart2')}
1337
+ </p>
1338
+ <Alert variant="info">
1339
+ <AlertTitle>{t('templates.footer.tipTitle')}</AlertTitle>
1340
+ <AlertDescription>
1341
+ {t('templates.footer.tipDescriptionPart1')}
1342
+ <code className="bg-muted px-1 rounded">styles/xertica/tokens.css</code>
1343
+ {t('templates.footer.tipDescriptionPart2')}
1344
+ </AlertDescription>
1345
+ </Alert>
1346
+ </CardContent>
1347
+ </Card>
1348
+ </div>
1349
+ </div>
1350
+ </ScrollArea>
1351
+ </main>
1352
+ </div>
1353
+ );
1354
+ }