xertica-ui 2.0.4 → 2.0.6

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 (305) hide show
  1. package/CHANGELOG.md +298 -220
  2. package/README.md +73 -31
  3. package/bin/cli.ts +1 -1
  4. package/components/assistant/xertica-assistant/xertica-assistant.tsx +2 -3
  5. package/components/blocks/card-patterns/ActivityCard.tsx +72 -0
  6. package/components/blocks/card-patterns/FeatureCard.tsx +100 -0
  7. package/components/blocks/card-patterns/NotificationCard.tsx +127 -0
  8. package/components/blocks/card-patterns/ProfileCard.tsx +84 -0
  9. package/components/blocks/card-patterns/ProjectCard.tsx +89 -0
  10. package/components/blocks/card-patterns/QuickActionCard.tsx +62 -0
  11. package/components/blocks/card-patterns/card-patterns.stories.tsx +445 -0
  12. package/components/blocks/card-patterns/index.ts +17 -0
  13. package/components/blocks/index.ts +1 -0
  14. package/components/brand/xertica-provider/XerticaProvider.tsx +48 -20
  15. package/components/brand/xertica-provider/xertica-provider.mdx +61 -59
  16. package/components/brand/xertica-provider/xertica-provider.test.tsx +52 -7
  17. package/components/index.ts +3 -0
  18. package/components/layout/header/header.test.tsx +8 -2
  19. package/components/layout/header/header.tsx +4 -3
  20. package/components/layout/sidebar/sidebar.stories.tsx +6 -6
  21. package/components/layout/sidebar/sidebar.test.tsx +11 -5
  22. package/components/layout/sidebar/sidebar.tsx +34 -36
  23. package/components/media/FloatingMediaWrapper.tsx +11 -8
  24. package/components/media/audio-player/AudioPlayer.tsx +22 -14
  25. package/components/pages/home-content/HomeContent.tsx +7 -5
  26. package/components/pages/home-content/home-content.mdx +62 -63
  27. package/components/pages/home-page/HomePage.tsx +12 -5
  28. package/components/pages/home-page/home-page.mdx +10 -13
  29. package/components/pages/template-content/TemplateContent.tsx +10 -4
  30. package/components/pages/template-content/template-content.mdx +61 -62
  31. package/components/pages/template-page/TemplatePage.tsx +11 -4
  32. package/components/pages/template-page/template-page.mdx +10 -11
  33. package/components/public-api-smoke.test.tsx +45 -0
  34. package/components/shared/assistant-utils.ts +43 -11
  35. package/components/ui/accordion/accordion.mdx +8 -20
  36. package/components/ui/accordion/accordion.stories.tsx +27 -13
  37. package/components/ui/alert/alert.mdx +8 -24
  38. package/components/ui/alert/alert.stories.tsx +1 -0
  39. package/components/ui/alert-dialog/alert-dialog.mdx +8 -13
  40. package/components/ui/alert-dialog/alert-dialog.stories.tsx +1 -0
  41. package/components/ui/aspect-ratio/aspect-ratio.mdx +8 -20
  42. package/components/ui/aspect-ratio/aspect-ratio.stories.tsx +1 -0
  43. package/components/ui/assistant-chart/assistant-chart.mdx +8 -13
  44. package/components/ui/assistant-chart/assistant-chart.stories.tsx +1 -0
  45. package/components/ui/avatar/avatar.mdx +8 -28
  46. package/components/ui/avatar/avatar.stories.tsx +1 -0
  47. package/components/ui/badge/badge.mdx +8 -23
  48. package/components/ui/badge/badge.stories.tsx +1 -0
  49. package/components/ui/badge/badge.tsx +9 -9
  50. package/components/ui/breadcrumb/breadcrumb.mdx +8 -20
  51. package/components/ui/breadcrumb/breadcrumb.stories.tsx +1 -0
  52. package/components/ui/button/button.mdx +8 -52
  53. package/components/ui/button/button.stories.tsx +1 -0
  54. package/components/ui/calendar/calendar.mdx +8 -27
  55. package/components/ui/calendar/calendar.stories.tsx +31 -4
  56. package/components/ui/calendar/calendar.test.tsx +6 -0
  57. package/components/ui/calendar/calendar.tsx +258 -249
  58. package/components/ui/card/card.mdx +8 -27
  59. package/components/ui/card/card.stories.tsx +245 -103
  60. package/components/ui/carousel/carousel.mdx +8 -20
  61. package/components/ui/carousel/carousel.stories.tsx +1 -0
  62. package/components/ui/chart/chart.mdx +8 -20
  63. package/components/ui/chart/chart.stories.tsx +277 -24
  64. package/components/ui/chart/chart.test.tsx +154 -20
  65. package/components/ui/chart/chart.tsx +1494 -368
  66. package/components/ui/checkbox/checkbox.mdx +8 -27
  67. package/components/ui/checkbox/checkbox.stories.tsx +1 -0
  68. package/components/ui/collapsible/collapsible.mdx +8 -13
  69. package/components/ui/collapsible/collapsible.stories.tsx +1 -0
  70. package/components/ui/command/command.mdx +8 -20
  71. package/components/ui/command/command.stories.tsx +1 -0
  72. package/components/ui/context-menu/context-menu.mdx +8 -13
  73. package/components/ui/context-menu/context-menu.stories.tsx +1 -0
  74. package/components/ui/dialog/dialog.mdx +8 -20
  75. package/components/ui/dialog/dialog.stories.tsx +1 -0
  76. package/components/ui/drawer/drawer.mdx +8 -13
  77. package/components/ui/drawer/drawer.stories.tsx +1 -0
  78. package/components/ui/dropdown-menu/dropdown-menu.mdx +8 -22
  79. package/components/ui/dropdown-menu/dropdown-menu.stories.tsx +1 -0
  80. package/components/ui/empty/empty.mdx +8 -27
  81. package/components/ui/empty/empty.stories.tsx +1 -0
  82. package/components/ui/file-upload/file-upload.mdx +8 -20
  83. package/components/ui/file-upload/file-upload.stories.tsx +1 -0
  84. package/components/ui/form/form.stories.tsx +1 -0
  85. package/components/ui/google-maps-loader/google-maps-loader.tsx +2 -2
  86. package/components/ui/hover-card/hover-card.mdx +8 -13
  87. package/components/ui/hover-card/hover-card.stories.tsx +1 -0
  88. package/components/ui/index.ts +41 -16
  89. package/components/ui/input/input.mdx +8 -46
  90. package/components/ui/input/input.stories.tsx +1 -0
  91. package/components/ui/input-otp/input-otp.mdx +8 -27
  92. package/components/ui/input-otp/input-otp.stories.tsx +7 -6
  93. package/components/ui/label/label.mdx +8 -27
  94. package/components/ui/label/label.stories.tsx +1 -0
  95. package/components/ui/map/map.mdx +8 -20
  96. package/components/ui/map/map.stories.tsx +51 -30
  97. package/components/ui/map/map.tsx +2 -2
  98. package/components/ui/menubar/menubar.mdx +8 -13
  99. package/components/ui/menubar/menubar.stories.tsx +1 -0
  100. package/components/ui/navigation-menu/navigation-menu.mdx +8 -13
  101. package/components/ui/navigation-menu/navigation-menu.stories.tsx +1 -0
  102. package/components/ui/notification-badge/notification-badge.mdx +8 -20
  103. package/components/ui/notification-badge/notification-badge.stories.tsx +1 -0
  104. package/components/ui/page-header/page-header.stories.tsx +1 -0
  105. package/components/ui/pagination/pagination.mdx +8 -20
  106. package/components/ui/pagination/pagination.stories.tsx +11 -8
  107. package/components/ui/popover/popover.mdx +8 -20
  108. package/components/ui/popover/popover.stories.tsx +1 -0
  109. package/components/ui/progress/progress.mdx +8 -16
  110. package/components/ui/progress/progress.stories.tsx +1 -0
  111. package/components/ui/radio-group/radio-group.mdx +8 -27
  112. package/components/ui/radio-group/radio-group.stories.tsx +1 -0
  113. package/components/ui/rating/rating.mdx +8 -20
  114. package/components/ui/rating/rating.stories.tsx +1 -0
  115. package/components/ui/resizable/resizable.mdx +8 -20
  116. package/components/ui/resizable/resizable.stories.tsx +1 -0
  117. package/components/ui/rich-text-editor/rich-text-editor.stories.tsx +1 -0
  118. package/components/ui/rich-text-editor/rich-text-editor.tsx +2 -2
  119. package/components/ui/route-map/route-map.mdx +8 -20
  120. package/components/ui/route-map/route-map.stories.tsx +1 -0
  121. package/components/ui/route-map/route-map.tsx +2 -2
  122. package/components/ui/scroll-area/scroll-area.mdx +8 -13
  123. package/components/ui/scroll-area/scroll-area.stories.tsx +1 -0
  124. package/components/ui/search/search.mdx +8 -20
  125. package/components/ui/search/search.stories.tsx +1 -0
  126. package/components/ui/select/select.mdx +8 -27
  127. package/components/ui/select/select.stories.tsx +10 -9
  128. package/components/ui/separator/separator.mdx +8 -20
  129. package/components/ui/separator/separator.stories.tsx +1 -0
  130. package/components/ui/sheet/sheet.mdx +8 -20
  131. package/components/ui/sheet/sheet.stories.tsx +1 -0
  132. package/components/ui/simple-map/simple-map.mdx +8 -20
  133. package/components/ui/simple-map/simple-map.stories.tsx +1 -0
  134. package/components/ui/skeleton/skeleton.mdx +8 -20
  135. package/components/ui/skeleton/skeleton.stories.tsx +1 -0
  136. package/components/ui/slider/slider.mdx +8 -20
  137. package/components/ui/slider/slider.stories.tsx +1 -0
  138. package/components/ui/sonner/sonner.mdx +8 -13
  139. package/components/ui/sonner/sonner.stories.tsx +1 -0
  140. package/components/ui/stats-card/stats-card.mdx +8 -20
  141. package/components/ui/stats-card/stats-card.stories.tsx +1 -0
  142. package/components/ui/stepper/stepper.mdx +8 -13
  143. package/components/ui/stepper/stepper.stories.tsx +1 -0
  144. package/components/ui/switch/switch.mdx +8 -27
  145. package/components/ui/switch/switch.stories.tsx +1 -0
  146. package/components/ui/table/table.mdx +8 -13
  147. package/components/ui/table/table.stories.tsx +1 -0
  148. package/components/ui/tabs/tabs.mdx +8 -20
  149. package/components/ui/tabs/tabs.stories.tsx +1 -0
  150. package/components/ui/textarea/textarea.mdx +8 -20
  151. package/components/ui/textarea/textarea.stories.tsx +1 -0
  152. package/components/ui/timeline/timeline.mdx +8 -13
  153. package/components/ui/timeline/timeline.stories.tsx +1 -0
  154. package/components/ui/toggle/toggle.mdx +8 -20
  155. package/components/ui/toggle/toggle.stories.tsx +1 -0
  156. package/components/ui/toggle-group/toggle-group.mdx +8 -20
  157. package/components/ui/toggle-group/toggle-group.stories.tsx +1 -0
  158. package/components/ui/tooltip/tooltip.mdx +8 -27
  159. package/components/ui/tooltip/tooltip.stories.tsx +1 -0
  160. package/components/ui/tree-view/tree-view.mdx +8 -13
  161. package/components/ui/tree-view/tree-view.stories.tsx +1 -0
  162. package/components.json +7 -3
  163. package/contexts/ApiKeyContext.tsx +72 -26
  164. package/contexts/BrandColorsContext.tsx +26 -23
  165. package/contexts/LanguageContext.tsx +13 -10
  166. package/contexts/LayoutContext.test.tsx +11 -5
  167. package/contexts/LayoutContext.tsx +29 -21
  168. package/contexts/ThemeContext.tsx +26 -22
  169. package/contexts/theme-data.ts +4 -4
  170. package/dist/AudioPlayer-B1lt5cPl.cjs +989 -0
  171. package/dist/AudioPlayer-C12BjQBV.cjs +997 -0
  172. package/dist/AudioPlayer-DMcG_c7L.js +990 -0
  173. package/dist/AudioPlayer-DcFKRJE_.js +998 -0
  174. package/dist/CodeBlock-7TTgmdGG.cjs +2094 -0
  175. package/dist/CodeBlock-BeSt1h5P.js +2078 -0
  176. package/dist/CodeBlock-BgfYL_rD.cjs +2094 -0
  177. package/dist/CodeBlock-BlcqlA9M.cjs +2094 -0
  178. package/dist/CodeBlock-Bnmeu5ez.cjs +2094 -0
  179. package/dist/CodeBlock-BtfPlbAI.js +2078 -0
  180. package/dist/CodeBlock-CIySIuYr.js +2078 -0
  181. package/dist/CodeBlock-D8dcwbit.cjs +2094 -0
  182. package/dist/CodeBlock-DMZrFnlw.cjs +2094 -0
  183. package/dist/CodeBlock-DlBehYN8.js +2078 -0
  184. package/dist/CodeBlock-DnYNI8rQ.js +2078 -0
  185. package/dist/CodeBlock-DvKWbSnE.cjs +2094 -0
  186. package/dist/CodeBlock-DwMCfkFY.js +2078 -0
  187. package/dist/CodeBlock-Dy6CNYyj.js +2078 -0
  188. package/dist/CodeBlock-U1pPOQI7.cjs +2094 -0
  189. package/dist/CodeBlock-f_GpNhEB.js +2078 -0
  190. package/dist/CodeBlock-oB6u8nI1.js +2078 -0
  191. package/dist/CodeBlock-tZC31B73.cjs +2094 -0
  192. package/dist/LayoutContext-CwT5KLiW.cjs +104 -0
  193. package/dist/LayoutContext-DVLCsoQn.js +105 -0
  194. package/dist/ThemeContext-BoH4NLfN.js +734 -0
  195. package/dist/ThemeContext-C2EwAPDt.js +735 -0
  196. package/dist/ThemeContext-r69W20Xg.cjs +733 -0
  197. package/dist/ThemeContext-vTjumZeM.cjs +734 -0
  198. package/dist/XerticaProvider-BlY2limY.cjs +38 -0
  199. package/dist/XerticaProvider-DDuiIcKo.js +39 -0
  200. package/dist/XerticaProvider-cI9hSs27.cjs +38 -0
  201. package/dist/XerticaProvider-hSwhNQex.js +39 -0
  202. package/dist/assistant.cjs.js +1 -1
  203. package/dist/assistant.es.js +1 -1
  204. package/dist/brand.cjs.js +1 -1
  205. package/dist/brand.es.js +1 -1
  206. package/dist/cli.js +5 -5
  207. package/dist/components/assistant/xertica-assistant/xertica-assistant.d.ts +1 -1
  208. package/dist/components/blocks/card-patterns/ActivityCard.d.ts +20 -0
  209. package/dist/components/blocks/card-patterns/FeatureCard.d.ts +16 -0
  210. package/dist/components/blocks/card-patterns/NotificationCard.d.ts +24 -0
  211. package/dist/components/blocks/card-patterns/ProfileCard.d.ts +22 -0
  212. package/dist/components/blocks/card-patterns/ProjectCard.d.ts +18 -0
  213. package/dist/components/blocks/card-patterns/QuickActionCard.d.ts +15 -0
  214. package/dist/components/blocks/card-patterns/index.d.ts +12 -0
  215. package/dist/components/blocks/index.d.ts +1 -0
  216. package/dist/components/brand/xertica-provider/XerticaProvider.d.ts +1 -1
  217. package/dist/components/index.d.ts +1 -0
  218. package/dist/components/shared/assistant-utils.d.ts +35 -5
  219. package/dist/components/ui/alert/alert.d.ts +1 -1
  220. package/dist/components/ui/badge/badge.d.ts +1 -1
  221. package/dist/components/ui/button/button.d.ts +2 -2
  222. package/dist/components/ui/calendar/calendar.d.ts +4 -3
  223. package/dist/components/ui/chart/chart.d.ts +109 -1
  224. package/dist/components/ui/dialog/dialog.d.ts +1 -1
  225. package/dist/components/ui/index.d.ts +4 -2
  226. package/dist/contexts/ApiKeyContext.d.ts +6 -2
  227. package/dist/contexts/LayoutContext.d.ts +1 -0
  228. package/dist/google-maps-loader-CTYySAun.js +290 -0
  229. package/dist/google-maps-loader-Y-QkD-Li.cjs +290 -0
  230. package/dist/header-Cgy6vYPk.cjs +731 -0
  231. package/dist/header-DRlT4jgI.js +715 -0
  232. package/dist/header-WfEywpyc.cjs +731 -0
  233. package/dist/header-tifNQn2U.js +715 -0
  234. package/dist/hooks.cjs.js +13 -684
  235. package/dist/hooks.es.js +13 -684
  236. package/dist/index-COtD8bRW.cjs +7 -0
  237. package/dist/index-DW5tYe26.js +8 -0
  238. package/dist/index.cjs.js +520 -192
  239. package/dist/index.es.js +557 -228
  240. package/dist/layout.cjs.js +1 -1
  241. package/dist/layout.es.js +1 -1
  242. package/dist/media.cjs.js +1 -1
  243. package/dist/media.es.js +1 -1
  244. package/dist/rich-text-editor-0mraWT5y.cjs +2376 -0
  245. package/dist/rich-text-editor-B6jMRLzk.cjs +1939 -0
  246. package/dist/rich-text-editor-B8_oYcIR.js +1730 -0
  247. package/dist/rich-text-editor-BYuRBNBU.js +2373 -0
  248. package/dist/rich-text-editor-Bb9pySTs.cjs +2374 -0
  249. package/dist/rich-text-editor-BcL6L3cm.cjs +2374 -0
  250. package/dist/rich-text-editor-BoVZYtTs.cjs +2391 -0
  251. package/dist/rich-text-editor-CPV1lEPH.cjs +1748 -0
  252. package/dist/rich-text-editor-CoKqbCtu.cjs +1799 -0
  253. package/dist/rich-text-editor-Cw56T_mB.js +2356 -0
  254. package/dist/rich-text-editor-Cyt8qs2b.js +1921 -0
  255. package/dist/rich-text-editor-D76gD-QI.js +2328 -0
  256. package/dist/rich-text-editor-DKkokOnA.js +1781 -0
  257. package/dist/rich-text-editor-DNsdpN64.cjs +2359 -0
  258. package/dist/rich-text-editor-DfG8bCyY.js +2358 -0
  259. package/dist/rich-text-editor-Dxjw31Z4.js +2341 -0
  260. package/dist/rich-text-editor-DzP0Epmb.js +2356 -0
  261. package/dist/rich-text-editor-skplNlBM.cjs +2345 -0
  262. package/dist/ui.cjs.js +57 -47
  263. package/dist/ui.es.js +241 -231
  264. package/dist/use-mobile-B0hNy_Y6.cjs +4303 -0
  265. package/dist/use-mobile-BXuYROXM.js +4202 -0
  266. package/dist/use-mobile-Bbd51ASU.cjs +4392 -0
  267. package/dist/use-mobile-Bk6CX-TC.js +4359 -0
  268. package/dist/use-mobile-BvYdisLP.js +4202 -0
  269. package/dist/use-mobile-BzuxjzNX.cjs +4392 -0
  270. package/dist/use-mobile-CG2-SdXV.cjs +4235 -0
  271. package/dist/use-mobile-CKb5pqTs.js +4269 -0
  272. package/dist/use-mobile-CYuAuGDl.js +4202 -0
  273. package/dist/use-mobile-CbrYgJGJ.js +4203 -0
  274. package/dist/use-mobile-DRB3BQgD.cjs +4235 -0
  275. package/dist/use-mobile-DZvv7QMR.js +4359 -0
  276. package/dist/use-mobile-DdI_TXam.cjs +4235 -0
  277. package/dist/use-mobile-DlceKf8a.js +4359 -0
  278. package/dist/use-mobile-DsOnow1o.cjs +4236 -0
  279. package/dist/use-mobile-Kcj6jSnK.cjs +4392 -0
  280. package/dist/use-mobile-bnKcua_i.js +4202 -0
  281. package/dist/use-mobile-ncXBeE2z.cjs +4235 -0
  282. package/dist/xertica-ui.css +1 -1
  283. package/docs/architecture.md +20 -2
  284. package/docs/components/calendar.md +154 -99
  285. package/docs/components/card-patterns.md +337 -0
  286. package/docs/components/card.md +235 -162
  287. package/docs/components/chart.md +186 -4
  288. package/docs/components/map.md +84 -76
  289. package/docs/components/xertica-provider.md +24 -12
  290. package/docs/llms.md +2 -2
  291. package/llms-compact.txt +1 -1
  292. package/llms.txt +3 -3
  293. package/package.json +2 -2
  294. package/styles/xertica/tokens.css +12 -12
  295. package/templates/CLAUDE.md +16 -4
  296. package/templates/guidelines/Guidelines.md +6 -2
  297. package/templates/package.json +19 -2
  298. package/templates/src/app/App.tsx +8 -17
  299. package/templates/src/features/template/ui/CrudTemplate.tsx +3 -3
  300. package/templates/src/features/template/ui/DashboardTemplate.tsx +3 -3
  301. package/templates/src/features/template/ui/FormTemplate.tsx +1 -1
  302. package/templates/src/features/template/ui/LoginTemplate.tsx +3 -3
  303. package/templates/tsconfig.json +5 -4
  304. package/templates/vite.config.js +21 -5
  305. package/templates/vite.config.ts +20 -5
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **Enterprise-grade React design system** built on Tailwind CSS v4, Radix UI, and Lucide Icons — with a robust AI-first documentation layer for precise LLM-driven composition and autonomous agent interaction.
4
4
 
5
- [![npm version](https://img.shields.io/badge/npm-2.0.3-blue)](https://www.npmjs.com/package/xertica-ui)
5
+ [![npm version](https://img.shields.io/badge/npm-2.0.6-blue)](https://www.npmjs.com/package/xertica-ui)
6
6
  [![license](https://img.shields.io/badge/license-proprietary-red)](./LICENSE)
7
7
 
8
8
  ---
@@ -14,7 +14,8 @@ Xertica UI is specifically designed to be consumed by AI Agents (LLMs, code assi
14
14
  | File | Purpose |
15
15
  |---|---|
16
16
  | [`llms.txt`](./llms.txt) | Standard index for AI crawlers and context-aware agents. |
17
- | [`llms-full.txt`](./llms-full.txt) | **Complete documentation** of all 96 components in a single file for large-context LLMs. |
17
+ | [`llms-compact.txt`](./llms-compact.txt) | **Compact documentation** of all components in a single file for LLMs with limited context. |
18
+ | [`llms-full.txt`](./llms-full.txt) | **Complete documentation** of all components in a single file for LLMs with large-context. |
18
19
  | `docs/llms.md` | Master index for agents to navigate the documentation folder. |
19
20
 
20
21
  ---
@@ -31,6 +32,8 @@ npm run dev
31
32
 
32
33
  The CLI scaffolds a complete Vite + React + TypeScript project with Portuguese UI localization and English AI-ready documentation.
33
34
 
35
+ > **Note:** Always use `@latest` with npx. Without it, npx may execute a locally cached older version instead of fetching the latest from the registry.
36
+
34
37
  ---
35
38
 
36
39
  ## 📦 Installation as a Library
@@ -47,10 +50,24 @@ npm install xertica-ui
47
50
  import 'xertica-ui/style.css';
48
51
  ```
49
52
 
50
- **2. Wrap your app** with `XerticaProvider`:
51
-
52
- ```tsx
53
- import { XerticaProvider } from 'xertica-ui/brand';
53
+ **2. Import components from the matching subpath**:
54
+
55
+ ```tsx
56
+ import { Button, Card } from 'xertica-ui/ui';
57
+
58
+ export function Example() {
59
+ return (
60
+ <Card className="p-4">
61
+ <Button>Continue</Button>
62
+ </Card>
63
+ );
64
+ }
65
+ ```
66
+
67
+ **3. Optionally wrap your app** with `XerticaProvider` when you want coordinated theme, layout, assistant, maps, tooltip, API-key, and toast services:
68
+
69
+ ```tsx
70
+ import { XerticaProvider } from 'xertica-ui/brand';
54
71
 
55
72
  function App() {
56
73
  return (
@@ -70,16 +87,24 @@ Xertica UI v2 exposes **granular subpath entries** — import only what your lay
70
87
  ```tsx
71
88
  import { Button, Card, Input } from 'xertica-ui/ui'; // shared/ui — primitives
72
89
  import { Sidebar, Header } from 'xertica-ui/layout'; // layout shell
73
- import { XerticaProvider } from 'xertica-ui/brand'; // app-level — providers & brand
74
- import { XerticaAssistant } from 'xertica-ui/assistant'; // feature — AI assistant
75
- import { VideoPlayer, AudioPlayer } from 'xertica-ui/media'; // feature — media players
76
- import { useLayout, useTheme } from 'xertica-ui/hooks'; // shared/lib — hooks & contexts
77
- import 'xertica-ui/style.css'; // styles — import once at root
78
- ```
79
-
80
- The root `from 'xertica-ui'` barrel remains available for full backward compatibility.
81
-
82
- > **TypeScript**: requires `"moduleResolution": "bundler"` (or `"node16"` / `"nodenext"`) in `tsconfig.json` to resolve subpath exports.
90
+ import { XerticaProvider } from 'xertica-ui/brand'; // app-level — providers & brand
91
+ import { XerticaAssistant } from 'xertica-ui/assistant'; // feature — AI assistant
92
+ import { VideoPlayer, AudioPlayer } from 'xertica-ui/media'; // feature — media players
93
+ import { useLayout, useOptionalLayout, useTheme } from 'xertica-ui/hooks'; // shared/lib — hooks & contexts
94
+ import 'xertica-ui/style.css'; // styles — import once at root
95
+ ```
96
+
97
+ The root `from 'xertica-ui'` barrel remains available for full backward compatibility.
98
+
99
+ > **TypeScript**: requires `"moduleResolution": "bundler"` (or `"node16"` / `"nodenext"`) in `tsconfig.json` to resolve subpath exports.
100
+
101
+ ### Component Independence Contract
102
+
103
+ `xertica-ui/style.css` is the only required global import. Public components are designed to render independently whenever possible, so importing one component into a consumer project should also bring the runtime logic that component needs.
104
+
105
+ `XerticaProvider` remains the recommended app-level convenience wrapper, but it is not required for most primitives. It composes the library providers for theme, brand colors, language, layout, assistant state, API keys, Google Maps, tooltips, and toasts.
106
+
107
+ Components with unavoidable external configuration, such as Google Maps, should render a configuration or error state instead of crashing the app.
83
108
 
84
109
  ---
85
110
 
@@ -108,13 +133,22 @@ export function MyPage() {
108
133
  }
109
134
  ```
110
135
 
111
- ### `useLayout()` Hook
112
- Access the sidebar state, width, and toggle functions anywhere in the component tree:
113
- ```tsx
114
- import { useLayout } from 'xertica-ui/hooks';
115
-
116
- const { sidebarWidth, isSidebarOpen, toggleSidebar } = useLayout();
117
- ```
136
+ ### `useLayout()` Hook
137
+ Access the sidebar state, width, and toggle functions anywhere in the component tree:
138
+ ```tsx
139
+ import { useLayout } from 'xertica-ui/hooks';
140
+
141
+ const { sidebarWidth, isSidebarOpen, toggleSidebar } = useLayout();
142
+ ```
143
+
144
+ Use `useLayout()` when a page must fail early without a layout provider. Use `useOptionalLayout()` inside reusable components that should still render with internal fallbacks when imported in isolation.
145
+
146
+ ```tsx
147
+ import { useOptionalLayout } from 'xertica-ui/hooks';
148
+
149
+ const layout = useOptionalLayout();
150
+ const sidebarWidth = layout?.sidebarWidth ?? 0;
151
+ ```
118
152
 
119
153
  ---
120
154
 
@@ -160,7 +194,7 @@ Each feature only imports from `shared/` or its own domain. Pages only compose f
160
194
 
161
195
  ---
162
196
 
163
- ## 🌟 Specialized Modules
197
+ ## 🌟 Specialized Modules
164
198
 
165
199
  ### 🤖 AI Assistant
166
200
  Integrated AI chat panel with workspace support.
@@ -170,12 +204,20 @@ Integrated AI chat panel with workspace support.
170
204
  First-class Google Maps integration.
171
205
  - `Map` · `RouteMap` · `SimpleMap` · `GoogleMapsLoader`
172
206
 
173
- ### 🎙️ Media
174
- - `AudioPlayer` · `VideoPlayer` · `FloatingMediaWrapper`
175
-
176
- ---
177
-
178
- ## 🎨 Design Tokens
207
+ ### 🎙️ Media
208
+ - `AudioPlayer` · `VideoPlayer` · `FloatingMediaWrapper`
209
+
210
+ ---
211
+
212
+ ## 📚 Storybook Documentation
213
+
214
+ Storybook Docs pages use each component's real story variations instead of repeating a single usage example. UI component MDX files now render the story list directly, so docs stay aligned with the component's public stories.
215
+
216
+ Map stories use a wider responsive preview frame, making `Map`, `RouteMap`, and related map examples readable in the Docs canvas.
217
+
218
+ ---
219
+
220
+ ## 🎨 Design Tokens
179
221
 
180
222
  Xertica UI uses semantic CSS tokens. **Never use raw colors or generic Tailwind color classes**:
181
223
 
@@ -225,5 +267,5 @@ Border: border-border
225
267
 
226
268
  ## ⚖️ License
227
269
 
228
- Proprietary — Xertica AI Team.
270
+ Proprietary — Xertica.ai Team.
229
271
 
package/bin/cli.ts CHANGED
@@ -18,7 +18,7 @@ const program = new Command();
18
18
  program
19
19
  .name('xertica-ui')
20
20
  .description('CLI to initialize Xertica UI projects')
21
- .version('2.0.4');
21
+ .version('2.0.6');
22
22
 
23
23
  program
24
24
  .command('init')
@@ -241,8 +241,7 @@ export type AssistantTab = 'chat' | 'historico' | 'favoritos';
241
241
  // Component Props
242
242
  // ============================================================================
243
243
 
244
- import type { MockResponse } from '../../../contexts/AssistenteContext';
245
- import { gerarResposta } from '../../shared/assistant-utils';
244
+ import { gerarResposta, type MockResponse } from '../../shared/assistant-utils';
246
245
 
247
246
  export interface XerticaAssistantProps {
248
247
  /**
@@ -1861,4 +1860,4 @@ export function XerticaAssistant({
1861
1860
  </Dialog>
1862
1861
  </>
1863
1862
  );
1864
- }
1863
+ }
@@ -0,0 +1,72 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { Card, CardHeader, CardTitle, CardContent, CardAction } from "../../ui/card"
5
+ import { Avatar, AvatarFallback, AvatarImage } from "../../ui/avatar"
6
+ import { Badge } from "../../ui/badge"
7
+ import { cn } from "../../shared/utils"
8
+
9
+ export interface ActivityItem {
10
+ id: string
11
+ user: { name: string; avatar?: string; initials: string }
12
+ action: string
13
+ target: string
14
+ time: string
15
+ type?: "create" | "update" | "delete" | "comment" | "deploy"
16
+ }
17
+
18
+ export interface ActivityCardProps extends React.HTMLAttributes<HTMLDivElement> {
19
+ title?: string
20
+ items: ActivityItem[]
21
+ action?: React.ReactNode
22
+ maxItems?: number
23
+ }
24
+
25
+ const activityTypeBadge: Record<NonNullable<ActivityItem["type"]>, { label: string; variant: React.ComponentProps<typeof Badge>["variant"] }> = {
26
+ create: { label: "Criado", variant: "success" },
27
+ update: { label: "Atualizado", variant: "info" },
28
+ delete: { label: "Removido", variant: "destructive" },
29
+ comment: { label: "Comentou", variant: "secondary" },
30
+ deploy: { label: "Deploy", variant: "default" },
31
+ }
32
+
33
+ export function ActivityCard({ title = "Atividade Recente", items, action, maxItems = 5, className, ...props }: ActivityCardProps) {
34
+ const visible = items.slice(0, maxItems)
35
+
36
+ return (
37
+ <Card className={cn("w-full", className)} {...props}>
38
+ <CardHeader>
39
+ <CardTitle>{title}</CardTitle>
40
+ {action && <CardAction>{action}</CardAction>}
41
+ </CardHeader>
42
+ <CardContent className="px-6 pb-6">
43
+ <ul className="space-y-4">
44
+ {visible.map((item) => {
45
+ const badge = item.type ? activityTypeBadge[item.type] : null
46
+ return (
47
+ <li key={item.id} className="flex items-start gap-3">
48
+ <Avatar className="size-8 shrink-0">
49
+ {item.user.avatar && <AvatarImage src={item.user.avatar} alt={item.user.name} />}
50
+ <AvatarFallback className="text-xs">{item.user.initials}</AvatarFallback>
51
+ </Avatar>
52
+ <div className="flex-1 min-w-0">
53
+ <p className="text-sm leading-snug">
54
+ <span className="font-medium">{item.user.name}</span>
55
+ {" "}{item.action}{" "}
56
+ <span className="font-medium">{item.target}</span>
57
+ </p>
58
+ <p className="text-xs text-muted-foreground mt-0.5">{item.time}</p>
59
+ </div>
60
+ {badge && (
61
+ <Badge variant={badge.variant} className="shrink-0 text-xs">
62
+ {badge.label}
63
+ </Badge>
64
+ )}
65
+ </li>
66
+ )
67
+ })}
68
+ </ul>
69
+ </CardContent>
70
+ </Card>
71
+ )
72
+ }
@@ -0,0 +1,100 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "../../ui/card"
5
+ import { Button } from "../../ui/button"
6
+ import { Badge } from "../../ui/badge"
7
+ import { cn } from "../../shared/utils"
8
+
9
+ export type FeatureCardColor =
10
+ | "primary"
11
+ | "chart-1"
12
+ | "chart-2"
13
+ | "chart-3"
14
+ | "chart-4"
15
+ | "chart-5"
16
+ | "success"
17
+ | "info"
18
+ | "warning"
19
+ | "destructive"
20
+
21
+ const colorTokens: Record<FeatureCardColor, { bg: string; icon: string }> = {
22
+ primary: { bg: "bg-primary/10", icon: "text-primary" },
23
+ "chart-1": { bg: "bg-[var(--chart-1)]/15", icon: "text-[var(--chart-1)]" },
24
+ "chart-2": { bg: "bg-[var(--chart-2)]/15", icon: "text-[var(--chart-2)]" },
25
+ "chart-3": { bg: "bg-[var(--chart-3)]/15", icon: "text-[var(--chart-3)]" },
26
+ "chart-4": { bg: "bg-[var(--chart-4)]/15", icon: "text-[var(--chart-4)]" },
27
+ "chart-5": { bg: "bg-[var(--chart-5)]/15", icon: "text-[var(--chart-5)]" },
28
+ success: { bg: "bg-success/10", icon: "text-success" },
29
+ info: { bg: "bg-info/10", icon: "text-info" },
30
+ warning: { bg: "bg-warning/10", icon: "text-warning" },
31
+ destructive: { bg: "bg-destructive/10", icon: "text-destructive" },
32
+ }
33
+
34
+ export interface FeatureCardProps extends React.HTMLAttributes<HTMLDivElement> {
35
+ title: string
36
+ description: string
37
+ icon: React.ReactNode
38
+ color?: FeatureCardColor
39
+ badge?: string
40
+ badgeVariant?: React.ComponentProps<typeof Badge>["variant"]
41
+ actionLabel?: string
42
+ actionVariant?: React.ComponentProps<typeof Button>["variant"]
43
+ onAction?: () => void
44
+ }
45
+
46
+ export function FeatureCard({
47
+ title,
48
+ description,
49
+ icon,
50
+ color = "primary",
51
+ badge,
52
+ badgeVariant = "default",
53
+ actionLabel,
54
+ actionVariant = "outline",
55
+ onAction,
56
+ className,
57
+ ...props
58
+ }: FeatureCardProps) {
59
+ const { bg, icon: iconColor } = colorTokens[color]
60
+
61
+ return (
62
+ <Card
63
+ className={cn(
64
+ "flex flex-col h-full hover:shadow-md transition-shadow duration-200",
65
+ className,
66
+ )}
67
+ {...props}
68
+ >
69
+ <CardHeader>
70
+ <div className="flex items-center gap-3">
71
+ <div className={cn("p-2 rounded-[var(--radius)] shrink-0", bg)}>
72
+ <div className={cn("size-6 flex items-center justify-center [&>svg]:size-6", iconColor)}>
73
+ {icon}
74
+ </div>
75
+ </div>
76
+ <div className="flex flex-wrap items-center gap-x-2 gap-y-1 min-w-0">
77
+ <CardTitle className="text-sm">{title}</CardTitle>
78
+ {badge && (
79
+ <Badge variant={badgeVariant} className="text-xs">
80
+ {badge}
81
+ </Badge>
82
+ )}
83
+ </div>
84
+ </div>
85
+ </CardHeader>
86
+
87
+ <CardContent className="flex-1">
88
+ <CardDescription className="text-sm leading-relaxed">{description}</CardDescription>
89
+ </CardContent>
90
+
91
+ {actionLabel && (
92
+ <CardFooter>
93
+ <Button variant={actionVariant} className="w-full" onClick={onAction}>
94
+ {actionLabel}
95
+ </Button>
96
+ </CardFooter>
97
+ )}
98
+ </Card>
99
+ )
100
+ }
@@ -0,0 +1,127 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { Card, CardHeader, CardTitle, CardContent, CardFooter, CardAction } from "../../ui/card"
5
+ import { Avatar, AvatarFallback, AvatarImage } from "../../ui/avatar"
6
+ import { Badge } from "../../ui/badge"
7
+ import { Button } from "../../ui/button"
8
+ import { cn } from "../../shared/utils"
9
+
10
+ export type NotificationType = "info" | "warning" | "success" | "error" | "default"
11
+
12
+ export interface NotificationItem {
13
+ id: string
14
+ title: string
15
+ message: string
16
+ time: string
17
+ read?: boolean
18
+ type?: NotificationType
19
+ user?: { name: string; initials: string; avatar?: string }
20
+ }
21
+
22
+ export interface NotificationCardProps extends React.HTMLAttributes<HTMLDivElement> {
23
+ title?: string
24
+ items: NotificationItem[]
25
+ unreadCount?: number
26
+ onMarkAllRead?: () => void
27
+ onViewAll?: () => void
28
+ maxItems?: number
29
+ }
30
+
31
+ const typeVariant: Record<NotificationType, React.ComponentProps<typeof Badge>["variant"]> = {
32
+ info: "info",
33
+ warning: "warning",
34
+ success: "success",
35
+ error: "destructive",
36
+ default: "secondary",
37
+ }
38
+
39
+ export function NotificationCard({
40
+ title = "Notificações",
41
+ items,
42
+ unreadCount,
43
+ onMarkAllRead,
44
+ onViewAll,
45
+ maxItems = 4,
46
+ className,
47
+ ...props
48
+ }: NotificationCardProps) {
49
+ const visible = items.slice(0, maxItems)
50
+ const count = unreadCount ?? items.filter((i) => !i.read).length
51
+
52
+ return (
53
+ <Card className={cn("w-full", className)} {...props}>
54
+ <CardHeader>
55
+ <div className="flex items-center gap-2">
56
+ <CardTitle>{title}</CardTitle>
57
+ {count > 0 && (
58
+ <Badge variant="destructive" className="h-5 text-[11px] px-1.5">{count}</Badge>
59
+ )}
60
+ </div>
61
+ {onMarkAllRead && count > 0 && (
62
+ <CardAction>
63
+ <Button variant="ghost" size="sm" className="text-xs h-7" onClick={onMarkAllRead}>
64
+ Marcar todas como lidas
65
+ </Button>
66
+ </CardAction>
67
+ )}
68
+ </CardHeader>
69
+
70
+ <CardContent className="px-0 pb-0">
71
+ <ul className="divide-y divide-border">
72
+ {visible.map((item) => (
73
+ <li
74
+ key={item.id}
75
+ className={cn(
76
+ "flex items-start gap-3 px-6 py-3 transition-colors",
77
+ !item.read && "bg-muted/40",
78
+ )}
79
+ >
80
+ {item.user ? (
81
+ <Avatar className="size-8 shrink-0 mt-0.5">
82
+ {item.user.avatar && <AvatarImage src={item.user.avatar} alt={item.user.name} />}
83
+ <AvatarFallback className="text-xs">{item.user.initials}</AvatarFallback>
84
+ </Avatar>
85
+ ) : (
86
+ <div className="size-8 shrink-0 mt-0.5 rounded-full bg-muted flex items-center justify-center">
87
+ <div className={cn(
88
+ "size-2 rounded-full",
89
+ item.type === "error" ? "bg-destructive" :
90
+ item.type === "warning" ? "bg-warning" :
91
+ item.type === "success" ? "bg-success" :
92
+ item.type === "info" ? "bg-info" : "bg-muted-foreground",
93
+ )} />
94
+ </div>
95
+ )}
96
+
97
+ <div className="flex-1 min-w-0">
98
+ <div className="flex items-center justify-between gap-2">
99
+ <p className="text-sm font-medium truncate">{item.title}</p>
100
+ {item.type && item.type !== "default" && (
101
+ <Badge variant={typeVariant[item.type]} className="text-[10px] px-1.5 h-4 shrink-0">
102
+ {item.type}
103
+ </Badge>
104
+ )}
105
+ </div>
106
+ <p className="text-xs text-muted-foreground line-clamp-2 mt-0.5">{item.message}</p>
107
+ <p className="text-[11px] text-muted-foreground/70 mt-1">{item.time}</p>
108
+ </div>
109
+
110
+ {!item.read && (
111
+ <div className="size-2 rounded-full bg-primary shrink-0 mt-2" />
112
+ )}
113
+ </li>
114
+ ))}
115
+ </ul>
116
+ </CardContent>
117
+
118
+ {onViewAll && (
119
+ <CardFooter className="pt-2">
120
+ <Button variant="ghost" size="sm" className="w-full text-xs" onClick={onViewAll}>
121
+ Ver todas as notificações
122
+ </Button>
123
+ </CardFooter>
124
+ )}
125
+ </Card>
126
+ )
127
+ }
@@ -0,0 +1,84 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { Card, CardContent } from "../../ui/card"
5
+ import { Avatar, AvatarFallback, AvatarImage } from "../../ui/avatar"
6
+ import { Badge } from "../../ui/badge"
7
+ import { Button } from "../../ui/button"
8
+ import { cn } from "../../shared/utils"
9
+
10
+ export interface ProfileCardProps extends React.HTMLAttributes<HTMLDivElement> {
11
+ name: string
12
+ role: string
13
+ department?: string
14
+ avatar?: string
15
+ initials: string
16
+ status?: "online" | "offline" | "away" | "busy"
17
+ stats?: Array<{ label: string; value: string | number }>
18
+ primaryAction?: { label: string; onClick?: () => void }
19
+ secondaryAction?: { label: string; onClick?: () => void }
20
+ }
21
+
22
+ const statusConfig = {
23
+ online: { label: "Online", variant: "success" as const },
24
+ offline: { label: "Offline", variant: "secondary" as const },
25
+ away: { label: "Ausente", variant: "warning" as const },
26
+ busy: { label: "Ocupado", variant: "destructive" as const },
27
+ }
28
+
29
+ export function ProfileCard({
30
+ name, role, department, avatar, initials, status,
31
+ stats, primaryAction, secondaryAction, className, ...props
32
+ }: ProfileCardProps) {
33
+ const s = status ? statusConfig[status] : null
34
+
35
+ return (
36
+ <Card className={cn("w-full", className)} {...props}>
37
+ <CardContent className="pt-6 flex flex-col items-center text-center gap-3">
38
+ <div className="relative">
39
+ <Avatar className="size-16">
40
+ {avatar && <AvatarImage src={avatar} alt={name} />}
41
+ <AvatarFallback className="text-lg font-semibold">{initials}</AvatarFallback>
42
+ </Avatar>
43
+ {s && (
44
+ <span className="absolute -bottom-0.5 -right-0.5">
45
+ <Badge variant={s.variant} className="text-[10px] px-1.5 py-0 h-5">{s.label}</Badge>
46
+ </span>
47
+ )}
48
+ </div>
49
+
50
+ <div className="space-y-0.5">
51
+ <p className="font-semibold text-base leading-tight">{name}</p>
52
+ <p className="text-sm text-muted-foreground">{role}</p>
53
+ {department && <p className="text-xs text-muted-foreground">{department}</p>}
54
+ </div>
55
+
56
+ {stats && stats.length > 0 && (
57
+ <div className="w-full grid grid-cols-3 divide-x divide-border border-y border-border py-3 mt-1">
58
+ {stats.map((stat) => (
59
+ <div key={stat.label} className="flex flex-col items-center gap-0.5 px-2">
60
+ <span className="text-base font-bold">{stat.value}</span>
61
+ <span className="text-[11px] text-muted-foreground">{stat.label}</span>
62
+ </div>
63
+ ))}
64
+ </div>
65
+ )}
66
+
67
+ {(primaryAction || secondaryAction) && (
68
+ <div className="flex gap-2 w-full">
69
+ {secondaryAction && (
70
+ <Button variant="outline" className="flex-1" size="sm" onClick={secondaryAction.onClick}>
71
+ {secondaryAction.label}
72
+ </Button>
73
+ )}
74
+ {primaryAction && (
75
+ <Button className="flex-1" size="sm" onClick={primaryAction.onClick}>
76
+ {primaryAction.label}
77
+ </Button>
78
+ )}
79
+ </div>
80
+ )}
81
+ </CardContent>
82
+ </Card>
83
+ )
84
+ }
@@ -0,0 +1,89 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter, CardAction } from "../../ui/card"
5
+ import { Avatar, AvatarFallback, AvatarImage } from "../../ui/avatar"
6
+ import { Badge } from "../../ui/badge"
7
+ import { Progress } from "../../ui/progress"
8
+ import { cn } from "../../shared/utils"
9
+ import type { ProgressVariant } from "../../ui/progress"
10
+
11
+ export type ProjectStatus = "active" | "review" | "done" | "paused" | "at-risk"
12
+
13
+ export interface ProjectMember {
14
+ name: string
15
+ initials: string
16
+ avatar?: string
17
+ }
18
+
19
+ export interface ProjectCardProps extends React.HTMLAttributes<HTMLDivElement> {
20
+ title: string
21
+ description?: string
22
+ status: ProjectStatus
23
+ progress: number
24
+ dueDate?: string
25
+ members?: ProjectMember[]
26
+ maxMembers?: number
27
+ action?: React.ReactNode
28
+ }
29
+
30
+ const statusConfig: Record<ProjectStatus, { label: string; variant: React.ComponentProps<typeof Badge>["variant"]; progressVariant: ProgressVariant }> = {
31
+ active: { label: "Em andamento", variant: "info", progressVariant: "info" },
32
+ review: { label: "Em revisão", variant: "warning", progressVariant: "warning" },
33
+ done: { label: "Concluído", variant: "success", progressVariant: "success" },
34
+ paused: { label: "Pausado", variant: "secondary", progressVariant: "default" },
35
+ "at-risk":{ label: "Em risco", variant: "destructive", progressVariant: "destructive" },
36
+ }
37
+
38
+ export function ProjectCard({
39
+ title, description, status, progress, dueDate,
40
+ members = [], maxMembers = 4, action, className, ...props
41
+ }: ProjectCardProps) {
42
+ const { label, variant, progressVariant } = statusConfig[status]
43
+ const visible = members.slice(0, maxMembers)
44
+ const overflow = members.length - maxMembers
45
+
46
+ return (
47
+ <Card className={cn("w-full", className)} {...props}>
48
+ <CardHeader>
49
+ <div className="flex flex-col gap-1 min-w-0">
50
+ <CardTitle className="truncate">{title}</CardTitle>
51
+ {description && <CardDescription className="line-clamp-2">{description}</CardDescription>}
52
+ </div>
53
+ <CardAction className="flex items-center gap-2">
54
+ <Badge variant={variant}>{label}</Badge>
55
+ {action}
56
+ </CardAction>
57
+ </CardHeader>
58
+
59
+ <CardContent className="space-y-4">
60
+ <div className="space-y-1.5">
61
+ <div className="flex justify-between text-xs text-muted-foreground">
62
+ <span>Progresso</span>
63
+ <span>{progress}%</span>
64
+ </div>
65
+ <Progress value={progress} variant={progressVariant} className="h-2" />
66
+ </div>
67
+ </CardContent>
68
+
69
+ <CardFooter className="flex items-center justify-between">
70
+ <div className="flex -space-x-2">
71
+ {visible.map((m) => (
72
+ <Avatar key={m.name} className="size-7 border-2 border-background">
73
+ {m.avatar && <AvatarImage src={m.avatar} alt={m.name} />}
74
+ <AvatarFallback className="text-[10px]">{m.initials}</AvatarFallback>
75
+ </Avatar>
76
+ ))}
77
+ {overflow > 0 && (
78
+ <div className="size-7 rounded-full border-2 border-background bg-muted flex items-center justify-center text-[10px] font-medium text-muted-foreground">
79
+ +{overflow}
80
+ </div>
81
+ )}
82
+ </div>
83
+ {dueDate && (
84
+ <span className="text-xs text-muted-foreground">{dueDate}</span>
85
+ )}
86
+ </CardFooter>
87
+ </Card>
88
+ )
89
+ }