@handled-ai/design-system 0.8.0 → 0.9.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 (336) hide show
  1. package/README.md +14 -4
  2. package/dist/charts/bar-chart-component.d.ts +24 -0
  3. package/dist/charts/bar-chart-component.js +123 -0
  4. package/dist/charts/bar-chart-component.js.map +1 -0
  5. package/dist/charts/chart-tooltip.d.ts +26 -0
  6. package/dist/charts/chart-tooltip.js +69 -0
  7. package/dist/charts/chart-tooltip.js.map +1 -0
  8. package/dist/charts/chart.d.ts +64 -0
  9. package/dist/charts/chart.js +285 -0
  10. package/dist/charts/chart.js.map +1 -0
  11. package/dist/charts/donut-chart.d.ts +21 -0
  12. package/dist/charts/donut-chart.js +96 -0
  13. package/dist/charts/donut-chart.js.map +1 -0
  14. package/dist/charts/index.d.ts +11 -0
  15. package/dist/charts/index.js +10 -0
  16. package/dist/charts/index.js.map +1 -0
  17. package/dist/charts/pipeline-overview.d.ts +76 -0
  18. package/dist/charts/pipeline-overview.js +372 -0
  19. package/dist/charts/pipeline-overview.js.map +1 -0
  20. package/dist/charts/sankey-chart.d.ts +52 -0
  21. package/dist/charts/sankey-chart.js +219 -0
  22. package/dist/charts/sankey-chart.js.map +1 -0
  23. package/dist/charts/top-line-metrics.d.ts +26 -0
  24. package/dist/charts/top-line-metrics.js +224 -0
  25. package/dist/charts/top-line-metrics.js.map +1 -0
  26. package/dist/charts/trend-area-chart.d.ts +21 -0
  27. package/dist/charts/trend-area-chart.js +150 -0
  28. package/dist/charts/trend-area-chart.js.map +1 -0
  29. package/dist/charts/volume-analysis-chart.d.ts +19 -0
  30. package/dist/charts/volume-analysis-chart.js +121 -0
  31. package/dist/charts/volume-analysis-chart.js.map +1 -0
  32. package/dist/components/activity-detail.d.ts +38 -0
  33. package/dist/components/activity-detail.js +163 -0
  34. package/dist/components/activity-detail.js.map +1 -0
  35. package/dist/components/activity-log.d.ts +21 -0
  36. package/dist/components/activity-log.js +61 -0
  37. package/dist/components/activity-log.js.map +1 -0
  38. package/dist/components/agent-popover.d.ts +71 -0
  39. package/dist/components/agent-popover.js +282 -0
  40. package/dist/components/agent-popover.js.map +1 -0
  41. package/dist/components/agent-widget.d.ts +24 -0
  42. package/dist/components/agent-widget.js +117 -0
  43. package/dist/components/agent-widget.js.map +1 -0
  44. package/dist/components/avatar.d.ts +13 -0
  45. package/dist/components/avatar.js +140 -0
  46. package/dist/components/avatar.js.map +1 -0
  47. package/dist/components/badge.d.ts +12 -0
  48. package/dist/components/badge.js +75 -0
  49. package/dist/components/badge.js.map +1 -0
  50. package/dist/components/button.d.ts +13 -0
  51. package/dist/components/button.js +83 -0
  52. package/dist/components/button.js.map +1 -0
  53. package/dist/components/card.d.ts +11 -0
  54. package/dist/components/card.js +119 -0
  55. package/dist/components/card.js.map +1 -0
  56. package/dist/components/contact-list.d.ts +34 -0
  57. package/dist/components/contact-list.js +84 -0
  58. package/dist/components/contact-list.js.map +1 -0
  59. package/dist/components/dashboard-cards.d.ts +10 -0
  60. package/dist/components/dashboard-cards.js +164 -0
  61. package/dist/components/dashboard-cards.js.map +1 -0
  62. package/dist/components/data-table-display.d.ts +19 -0
  63. package/dist/components/data-table-display.js +109 -0
  64. package/dist/components/data-table-display.js.map +1 -0
  65. package/dist/components/data-table-filter.d.ts +18 -0
  66. package/dist/components/data-table-filter.js +107 -0
  67. package/dist/components/data-table-filter.js.map +1 -0
  68. package/dist/components/data-table-quick-views.d.ts +13 -0
  69. package/dist/components/data-table-quick-views.js +90 -0
  70. package/dist/components/data-table-quick-views.js.map +1 -0
  71. package/dist/components/data-table-toolbar.d.ts +18 -0
  72. package/dist/components/data-table-toolbar.js +45 -0
  73. package/dist/components/data-table-toolbar.js.map +1 -0
  74. package/dist/components/data-table.d.ts +39 -0
  75. package/dist/components/data-table.js +821 -0
  76. package/dist/components/data-table.js.map +1 -0
  77. package/dist/components/detail-view.d.ts +44 -0
  78. package/dist/components/detail-view.js +165 -0
  79. package/dist/components/detail-view.js.map +1 -0
  80. package/dist/components/dialog.d.ts +19 -0
  81. package/dist/components/dialog.js +188 -0
  82. package/dist/components/dialog.js.map +1 -0
  83. package/dist/components/dropdown-menu.d.ts +27 -0
  84. package/dist/components/dropdown-menu.js +279 -0
  85. package/dist/components/dropdown-menu.js.map +1 -0
  86. package/dist/components/entity-panel.d.ts +69 -0
  87. package/dist/components/entity-panel.js +584 -0
  88. package/dist/components/entity-panel.js.map +1 -0
  89. package/dist/components/inbox-row.d.ts +27 -0
  90. package/dist/components/inbox-row.js +139 -0
  91. package/dist/components/inbox-row.js.map +1 -0
  92. package/dist/components/inbox-toolbar.d.ts +21 -0
  93. package/dist/components/inbox-toolbar.js +203 -0
  94. package/dist/components/inbox-toolbar.js.map +1 -0
  95. package/dist/components/input.d.ts +5 -0
  96. package/dist/components/input.js +50 -0
  97. package/dist/components/input.js.map +1 -0
  98. package/dist/components/insights-filter-bar.d.ts +21 -0
  99. package/dist/components/insights-filter-bar.js +99 -0
  100. package/dist/components/insights-filter-bar.js.map +1 -0
  101. package/dist/components/item-list-display.d.ts +22 -0
  102. package/dist/components/item-list-display.js +240 -0
  103. package/dist/components/item-list-display.js.map +1 -0
  104. package/dist/components/item-list-filter.d.ts +16 -0
  105. package/dist/components/item-list-filter.js +87 -0
  106. package/dist/components/item-list-filter.js.map +1 -0
  107. package/dist/components/item-list-toolbar.d.ts +25 -0
  108. package/dist/components/item-list-toolbar.js +79 -0
  109. package/dist/components/item-list-toolbar.js.map +1 -0
  110. package/dist/components/item-list.d.ts +20 -0
  111. package/dist/components/item-list.js +702 -0
  112. package/dist/components/item-list.js.map +1 -0
  113. package/dist/components/label.d.ts +6 -0
  114. package/dist/components/label.js +55 -0
  115. package/dist/components/label.js.map +1 -0
  116. package/dist/components/message.d.ts +23 -0
  117. package/dist/components/message.js +117 -0
  118. package/dist/components/message.js.map +1 -0
  119. package/dist/components/metric-card.d.ts +25 -0
  120. package/dist/components/metric-card.js +107 -0
  121. package/dist/components/metric-card.js.map +1 -0
  122. package/dist/components/performance-metrics-table.d.ts +38 -0
  123. package/dist/components/performance-metrics-table.js +342 -0
  124. package/dist/components/performance-metrics-table.js.map +1 -0
  125. package/dist/components/preview-list.d.ts +14 -0
  126. package/dist/components/preview-list.js +83 -0
  127. package/dist/components/preview-list.js.map +1 -0
  128. package/dist/components/progress.d.ts +6 -0
  129. package/dist/components/progress.js +69 -0
  130. package/dist/components/progress.js.map +1 -0
  131. package/dist/components/quick-action-chat-area.d.ts +24 -0
  132. package/dist/components/quick-action-chat-area.js +178 -0
  133. package/dist/components/quick-action-chat-area.js.map +1 -0
  134. package/dist/components/quick-action-modal.d.ts +30 -0
  135. package/dist/components/quick-action-modal.js +288 -0
  136. package/dist/components/quick-action-modal.js.map +1 -0
  137. package/dist/components/quick-action-sidebar-nav.d.ts +51 -0
  138. package/dist/components/quick-action-sidebar-nav.js +528 -0
  139. package/dist/components/quick-action-sidebar-nav.js.map +1 -0
  140. package/dist/components/recommended-actions-section.d.ts +23 -0
  141. package/dist/components/recommended-actions-section.js +215 -0
  142. package/dist/components/recommended-actions-section.js.map +1 -0
  143. package/dist/components/report-card.d.ts +26 -0
  144. package/dist/components/report-card.js +69 -0
  145. package/dist/components/report-card.js.map +1 -0
  146. package/dist/components/score-analysis-modal.d.ts +26 -0
  147. package/dist/components/score-analysis-modal.js +141 -0
  148. package/dist/components/score-analysis-modal.js.map +1 -0
  149. package/dist/components/score-breakdown.d.ts +17 -0
  150. package/dist/components/score-breakdown.js +162 -0
  151. package/dist/components/score-breakdown.js.map +1 -0
  152. package/dist/components/score-feedback.d.ts +40 -0
  153. package/dist/components/score-feedback.js +209 -0
  154. package/dist/components/score-feedback.js.map +1 -0
  155. package/dist/components/score-ring.d.ts +14 -0
  156. package/dist/components/score-ring.js +79 -0
  157. package/dist/components/score-ring.js.map +1 -0
  158. package/dist/components/scroll-area.d.ts +7 -0
  159. package/dist/components/scroll-area.js +101 -0
  160. package/dist/components/scroll-area.js.map +1 -0
  161. package/dist/components/select.d.ts +17 -0
  162. package/dist/components/select.js +228 -0
  163. package/dist/components/select.js.map +1 -0
  164. package/dist/components/separator.d.ts +6 -0
  165. package/dist/components/separator.js +61 -0
  166. package/dist/components/separator.js.map +1 -0
  167. package/dist/components/sheet.d.ts +16 -0
  168. package/dist/components/sheet.js +168 -0
  169. package/dist/components/sheet.js.map +1 -0
  170. package/dist/components/sidebar.d.ts +73 -0
  171. package/dist/components/sidebar.js +723 -0
  172. package/dist/components/sidebar.js.map +1 -0
  173. package/dist/components/signal-feedback-inline.d.ts +51 -0
  174. package/dist/components/signal-feedback-inline.js +548 -0
  175. package/dist/components/signal-feedback-inline.js.map +1 -0
  176. package/dist/components/simple-data-table.d.ts +15 -0
  177. package/dist/components/simple-data-table.js +91 -0
  178. package/dist/components/simple-data-table.js.map +1 -0
  179. package/dist/components/skeleton.d.ts +5 -0
  180. package/dist/components/skeleton.js +44 -0
  181. package/dist/components/skeleton.js.map +1 -0
  182. package/dist/components/status-badge.d.ts +10 -0
  183. package/dist/components/status-badge.js +82 -0
  184. package/dist/components/status-badge.js.map +1 -0
  185. package/dist/components/styled-bar-list.d.ts +20 -0
  186. package/dist/components/styled-bar-list.js +59 -0
  187. package/dist/components/styled-bar-list.js.map +1 -0
  188. package/dist/components/suggested-actions.d.ts +110 -0
  189. package/dist/components/suggested-actions.js +1538 -0
  190. package/dist/components/suggested-actions.js.map +1 -0
  191. package/dist/components/table.d.ts +12 -0
  192. package/dist/components/table.js +147 -0
  193. package/dist/components/table.js.map +1 -0
  194. package/dist/components/tabs.d.ts +14 -0
  195. package/dist/components/tabs.js +129 -0
  196. package/dist/components/tabs.js.map +1 -0
  197. package/dist/components/textarea.d.ts +5 -0
  198. package/dist/components/textarea.js +47 -0
  199. package/dist/components/textarea.js.map +1 -0
  200. package/dist/components/timeline-activity.d.ts +34 -0
  201. package/dist/components/timeline-activity.js +181 -0
  202. package/dist/components/timeline-activity.js.map +1 -0
  203. package/dist/components/tooltip.d.ts +9 -0
  204. package/dist/components/tooltip.js +93 -0
  205. package/dist/components/tooltip.js.map +1 -0
  206. package/dist/components/view-mode-toggle.d.ts +16 -0
  207. package/dist/components/view-mode-toggle.js +24 -0
  208. package/dist/components/view-mode-toggle.js.map +1 -0
  209. package/dist/hooks/use-mobile.d.ts +3 -0
  210. package/dist/hooks/use-mobile.js +21 -0
  211. package/dist/hooks/use-mobile.js.map +1 -0
  212. package/dist/index.d.ts +68 -1878
  213. package/dist/index.js +69 -10918
  214. package/dist/index.js.map +1 -1
  215. package/dist/lib/icons.d.ts +18 -0
  216. package/dist/lib/icons.js +21 -0
  217. package/dist/lib/icons.js.map +1 -0
  218. package/dist/lib/utils.d.ts +5 -0
  219. package/dist/lib/utils.js +9 -0
  220. package/dist/lib/utils.js.map +1 -0
  221. package/dist/prototype/index.d.ts +20 -0
  222. package/dist/prototype/index.js +8 -0
  223. package/dist/prototype/index.js.map +1 -0
  224. package/dist/prototype/prototype-accounts-view.d.ts +22 -0
  225. package/dist/prototype/prototype-accounts-view.js +70 -0
  226. package/dist/prototype/prototype-accounts-view.js.map +1 -0
  227. package/dist/prototype/prototype-admin-view.d.ts +21 -0
  228. package/dist/prototype/prototype-admin-view.js +53 -0
  229. package/dist/prototype/prototype-admin-view.js.map +1 -0
  230. package/dist/prototype/prototype-config.d.ts +226 -0
  231. package/dist/prototype/prototype-config.js +1 -0
  232. package/dist/prototype/prototype-config.js.map +1 -0
  233. package/dist/prototype/prototype-inbox-view.d.ts +48 -0
  234. package/dist/prototype/prototype-inbox-view.js +701 -0
  235. package/dist/prototype/prototype-inbox-view.js.map +1 -0
  236. package/dist/prototype/prototype-insights-view.d.ts +23 -0
  237. package/dist/prototype/prototype-insights-view.js +335 -0
  238. package/dist/prototype/prototype-insights-view.js.map +1 -0
  239. package/dist/prototype/prototype-shell.d.ts +40 -0
  240. package/dist/prototype/prototype-shell.js +190 -0
  241. package/dist/prototype/prototype-shell.js.map +1 -0
  242. package/dist/prototype/prototype-work-queue-view.d.ts +8 -0
  243. package/dist/prototype/prototype-work-queue-view.js +17 -0
  244. package/dist/prototype/prototype-work-queue-view.js.map +1 -0
  245. package/dist/three/agent-orb.d.ts +39 -0
  246. package/dist/three/agent-orb.js +500 -0
  247. package/dist/three/agent-orb.js.map +1 -0
  248. package/dist/three/index.d.ts +2 -0
  249. package/dist/three/index.js +2 -0
  250. package/dist/three/index.js.map +1 -0
  251. package/package.json +98 -17
  252. package/src/charts/bar-chart-component.tsx +150 -0
  253. package/src/charts/chart-tooltip.tsx +86 -0
  254. package/src/charts/chart.tsx +371 -0
  255. package/src/charts/donut-chart.tsx +112 -0
  256. package/src/charts/index.ts +13 -0
  257. package/src/charts/pipeline-overview.tsx +476 -0
  258. package/src/charts/sankey-chart.tsx +290 -0
  259. package/src/charts/top-line-metrics.tsx +261 -0
  260. package/src/charts/trend-area-chart.tsx +150 -0
  261. package/src/charts/volume-analysis-chart.tsx +124 -0
  262. package/src/components/activity-detail.tsx +233 -0
  263. package/src/components/activity-log.tsx +89 -0
  264. package/src/components/agent-popover.tsx +373 -0
  265. package/src/components/agent-widget.tsx +163 -0
  266. package/src/components/avatar.tsx +109 -0
  267. package/src/components/badge.tsx +48 -0
  268. package/src/components/button.tsx +59 -0
  269. package/src/components/card.tsx +92 -0
  270. package/src/components/contact-list.tsx +121 -0
  271. package/src/components/dashboard-cards.tsx +170 -0
  272. package/src/components/data-table-display.tsx +139 -0
  273. package/src/components/data-table-filter.tsx +138 -0
  274. package/src/components/data-table-quick-views.tsx +103 -0
  275. package/src/components/data-table-toolbar.tsx +56 -0
  276. package/src/components/data-table.tsx +915 -0
  277. package/src/components/detail-view.tsx +237 -0
  278. package/src/components/dialog.tsx +158 -0
  279. package/src/components/dropdown-menu.tsx +257 -0
  280. package/src/components/entity-panel.tsx +767 -0
  281. package/src/components/inbox-row.tsx +132 -0
  282. package/src/components/inbox-toolbar.tsx +213 -0
  283. package/src/components/input.tsx +21 -0
  284. package/src/components/insights-filter-bar.tsx +132 -0
  285. package/src/components/item-list-display.tsx +278 -0
  286. package/src/components/item-list-filter.tsx +118 -0
  287. package/src/components/item-list-toolbar.tsx +97 -0
  288. package/src/components/item-list.tsx +843 -0
  289. package/src/components/label.tsx +24 -0
  290. package/src/components/message.tsx +83 -0
  291. package/src/components/metric-card.tsx +178 -0
  292. package/src/components/performance-metrics-table.tsx +442 -0
  293. package/src/components/preview-list.tsx +62 -0
  294. package/src/components/progress.tsx +31 -0
  295. package/src/components/quick-action-chat-area.tsx +156 -0
  296. package/src/components/quick-action-modal.tsx +331 -0
  297. package/src/components/quick-action-sidebar-nav.tsx +592 -0
  298. package/src/components/recommended-actions-section.tsx +258 -0
  299. package/src/components/report-card.tsx +106 -0
  300. package/src/components/score-analysis-modal.tsx +172 -0
  301. package/src/components/score-breakdown.tsx +179 -0
  302. package/src/components/score-feedback.tsx +288 -0
  303. package/src/components/score-ring.tsx +87 -0
  304. package/src/components/scroll-area.tsx +58 -0
  305. package/src/components/select.tsx +190 -0
  306. package/src/components/separator.tsx +28 -0
  307. package/src/components/sheet.tsx +143 -0
  308. package/src/components/sidebar.tsx +726 -0
  309. package/src/components/signal-feedback-inline.tsx +591 -0
  310. package/src/components/simple-data-table.tsx +124 -0
  311. package/src/components/skeleton.tsx +15 -0
  312. package/src/components/status-badge.tsx +63 -0
  313. package/src/components/styled-bar-list.tsx +70 -0
  314. package/src/components/suggested-actions.tsx +1985 -0
  315. package/src/components/table.tsx +116 -0
  316. package/src/components/tabs.tsx +91 -0
  317. package/src/components/textarea.tsx +18 -0
  318. package/src/components/timeline-activity.tsx +234 -0
  319. package/src/components/tooltip.tsx +57 -0
  320. package/src/components/view-mode-toggle.tsx +39 -0
  321. package/src/hooks/use-mobile.ts +21 -0
  322. package/src/index.ts +77 -0
  323. package/src/lib/icons.ts +18 -0
  324. package/src/lib/utils.ts +6 -0
  325. package/src/prototype/index.ts +11 -0
  326. package/src/prototype/prototype-accounts-view.tsx +112 -0
  327. package/src/prototype/prototype-admin-view.tsx +67 -0
  328. package/src/prototype/prototype-config.ts +243 -0
  329. package/src/prototype/prototype-inbox-view.tsx +810 -0
  330. package/src/prototype/prototype-insights-view.tsx +379 -0
  331. package/src/prototype/prototype-shell.tsx +219 -0
  332. package/src/prototype/prototype-work-queue-view.tsx +30 -0
  333. package/src/styles/globals.css +299 -0
  334. package/src/three/agent-orb.tsx +557 -0
  335. package/src/three/index.ts +5 -0
  336. package/src/types/r3f.d.ts +8 -0
@@ -0,0 +1,442 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import {
5
+ AlertTriangle,
6
+ CheckCircle2,
7
+ ChevronDown,
8
+ ChevronLeft,
9
+ ChevronRight,
10
+ } from "lucide-react"
11
+
12
+ import { cn } from "../lib/utils"
13
+ import { Avatar, AvatarFallback } from "./avatar"
14
+ import { Button } from "./button"
15
+ import {
16
+ DropdownMenu,
17
+ DropdownMenuContent,
18
+ DropdownMenuItem,
19
+ DropdownMenuTrigger,
20
+ } from "./dropdown-menu"
21
+ import { Input } from "./input"
22
+ import { ScrollArea, ScrollBar } from "./scroll-area"
23
+ import {
24
+ Table,
25
+ TableBody,
26
+ TableCell,
27
+ TableHead,
28
+ TableHeader,
29
+ TableRow,
30
+ } from "./table"
31
+
32
+ export interface PerformanceMetricsTableRow {
33
+ id: string
34
+ label: string
35
+ avatarFallback: string
36
+ role?: string
37
+ primaryValue: number
38
+ primaryTarget: number
39
+ ratePercent: number
40
+ metricOne: number
41
+ metricTwo: string
42
+ metricThree: number
43
+ metricFour: number
44
+ }
45
+
46
+ export interface PerformanceMetricsTableSortOption {
47
+ id: "primary-desc" | "primary-asc" | "rate-desc" | "metric-four-desc"
48
+ label: string
49
+ }
50
+
51
+ interface PerformanceMetricsTableProps {
52
+ title?: string
53
+ entityColumnLabel?: string
54
+ primaryMetricColumnLabel?: string
55
+ rateColumnLabel?: string
56
+ metricOneColumnLabel?: string
57
+ metricTwoColumnLabel?: string
58
+ metricThreeColumnLabel?: string
59
+ metricFourColumnLabel?: string
60
+ viewOptions?: string[]
61
+ roleOptions?: string[]
62
+ sortOptions?: PerformanceMetricsTableSortOption[]
63
+ rows?: PerformanceMetricsTableRow[]
64
+ pageSize?: number
65
+ searchPlaceholder?: string
66
+ }
67
+
68
+ const DEFAULT_ROWS: PerformanceMetricsTableRow[] = [
69
+ {
70
+ id: "member-1",
71
+ label: "Jennifer Davis",
72
+ avatarFallback: "JD",
73
+ role: "Senior Coordinator",
74
+ primaryValue: 188,
75
+ primaryTarget: 200,
76
+ ratePercent: 78,
77
+ metricOne: 256,
78
+ metricTwo: "8.5h",
79
+ metricThree: 401,
80
+ metricFour: 42,
81
+ },
82
+ {
83
+ id: "member-2",
84
+ label: "Robert Taylor",
85
+ avatarFallback: "RT",
86
+ role: "Coordinator",
87
+ primaryValue: 168,
88
+ primaryTarget: 200,
89
+ ratePercent: 70,
90
+ metricOne: 210,
91
+ metricTwo: "7.4h",
92
+ metricThree: 330,
93
+ metricFour: 36,
94
+ },
95
+ {
96
+ id: "member-3",
97
+ label: "Karen Park",
98
+ avatarFallback: "KP",
99
+ role: "Coordinator",
100
+ primaryValue: 165,
101
+ primaryTarget: 200,
102
+ ratePercent: 68,
103
+ metricOne: 195,
104
+ metricTwo: "6.9h",
105
+ metricThree: 298,
106
+ metricFour: 33,
107
+ },
108
+ {
109
+ id: "member-4",
110
+ label: "Alex Chen",
111
+ avatarFallback: "AC",
112
+ role: "Junior Coordinator",
113
+ primaryValue: 142,
114
+ primaryTarget: 200,
115
+ ratePercent: 65,
116
+ metricOne: 201,
117
+ metricTwo: "7.2h",
118
+ metricThree: 315,
119
+ metricFour: 29,
120
+ },
121
+ {
122
+ id: "member-5",
123
+ label: "Sarah Mitchell",
124
+ avatarFallback: "SM",
125
+ role: "Senior Coordinator",
126
+ primaryValue: 130,
127
+ primaryTarget: 200,
128
+ ratePercent: 76,
129
+ metricOne: 247,
130
+ metricTwo: "8.2h",
131
+ metricThree: 389,
132
+ metricFour: 31,
133
+ },
134
+ {
135
+ id: "member-6",
136
+ label: "Mike Rodriguez",
137
+ avatarFallback: "MR",
138
+ role: "Coordinator",
139
+ primaryValue: 115,
140
+ primaryTarget: 200,
141
+ ratePercent: 72,
142
+ metricOne: 218,
143
+ metricTwo: "7.8h",
144
+ metricThree: 342,
145
+ metricFour: 25,
146
+ },
147
+ ]
148
+
149
+ const DEFAULT_SORT_OPTIONS: PerformanceMetricsTableSortOption[] = [
150
+ { id: "primary-desc", label: "Primary Metric (High to Low)" },
151
+ { id: "primary-asc", label: "Primary Metric (Low to High)" },
152
+ { id: "rate-desc", label: "Rate (High to Low)" },
153
+ { id: "metric-four-desc", label: "Metric Four (High to Low)" },
154
+ ]
155
+
156
+ function getProgressStatus(value: number, target: number) {
157
+ const percent = (value / target) * 100
158
+
159
+ if (percent >= 80) {
160
+ return {
161
+ color: "bg-emerald-500",
162
+ textColor: "text-emerald-700",
163
+ icon: <CheckCircle2 className="h-3.5 w-3.5 text-emerald-600" />,
164
+ }
165
+ }
166
+
167
+ if (percent >= 65) {
168
+ return {
169
+ color: "bg-amber-500",
170
+ textColor: "text-amber-700",
171
+ icon: <AlertTriangle className="h-3.5 w-3.5 text-amber-600" />,
172
+ }
173
+ }
174
+
175
+ return {
176
+ color: "bg-red-500",
177
+ textColor: "text-red-700",
178
+ icon: <AlertTriangle className="h-3.5 w-3.5 text-red-600" />,
179
+ }
180
+ }
181
+
182
+ function sortRows(
183
+ rows: PerformanceMetricsTableRow[],
184
+ sortId: PerformanceMetricsTableSortOption["id"]
185
+ ) {
186
+ const copy = [...rows]
187
+ switch (sortId) {
188
+ case "primary-asc":
189
+ return copy.sort((a, b) => a.primaryValue - b.primaryValue)
190
+ case "rate-desc":
191
+ return copy.sort((a, b) => b.ratePercent - a.ratePercent)
192
+ case "metric-four-desc":
193
+ return copy.sort((a, b) => b.metricFour - a.metricFour)
194
+ case "primary-desc":
195
+ default:
196
+ return copy.sort((a, b) => b.primaryValue - a.primaryValue)
197
+ }
198
+ }
199
+
200
+ export function PerformanceMetricsTable({
201
+ title = "Performance Table",
202
+ entityColumnLabel = "Entity",
203
+ primaryMetricColumnLabel = "Primary Goal",
204
+ rateColumnLabel = "Rate",
205
+ metricOneColumnLabel = "Metric One",
206
+ metricTwoColumnLabel = "Metric Two",
207
+ metricThreeColumnLabel = "Metric Three",
208
+ metricFourColumnLabel = "Metric Four",
209
+ viewOptions = ["By Entity"],
210
+ roleOptions = ["All", "Senior Coordinator", "Coordinator", "Junior Coordinator"],
211
+ sortOptions = DEFAULT_SORT_OPTIONS,
212
+ rows = DEFAULT_ROWS,
213
+ pageSize = 6,
214
+ searchPlaceholder = "Search rows...",
215
+ }: PerformanceMetricsTableProps) {
216
+ const [view, setView] = React.useState(viewOptions[0] ?? "By Entity")
217
+ const [sortId, setSortId] =
218
+ React.useState<PerformanceMetricsTableSortOption["id"]>(
219
+ sortOptions[0]?.id ?? "primary-desc"
220
+ )
221
+ const [roleFilter, setRoleFilter] = React.useState(roleOptions[0] ?? "All")
222
+ const [search, setSearch] = React.useState("")
223
+ const [page, setPage] = React.useState(1)
224
+
225
+ const filteredRows = React.useMemo(() => {
226
+ const normalized = search.trim().toLowerCase()
227
+ return rows.filter((row) => {
228
+ if (roleFilter !== "All" && row.role !== roleFilter) {
229
+ return false
230
+ }
231
+ if (!normalized) {
232
+ return true
233
+ }
234
+ return row.label.toLowerCase().includes(normalized)
235
+ })
236
+ }, [roleFilter, rows, search])
237
+
238
+ const sortedRows = React.useMemo(
239
+ () => sortRows(filteredRows, sortId),
240
+ [filteredRows, sortId]
241
+ )
242
+
243
+ const pageCount = Math.max(1, Math.ceil(sortedRows.length / pageSize))
244
+ const start = (page - 1) * pageSize
245
+ const paginatedRows = sortedRows.slice(start, start + pageSize)
246
+
247
+ React.useEffect(() => {
248
+ setPage(1)
249
+ }, [search, roleFilter, sortId, view])
250
+
251
+ React.useEffect(() => {
252
+ setPage((previous) => Math.min(previous, pageCount))
253
+ }, [pageCount])
254
+
255
+ const sortLabel =
256
+ sortOptions.find((option) => option.id === sortId)?.label ?? "Sort"
257
+
258
+ return (
259
+ <div className="overflow-hidden rounded-xl border border-border bg-card">
260
+ <div className="flex items-center justify-between border-b border-border px-4 py-3">
261
+ <h3 className="text-sm font-semibold text-foreground">{title}</h3>
262
+ <div className="flex items-center gap-2">
263
+ <DropdownMenu>
264
+ <DropdownMenuTrigger asChild>
265
+ <Button variant="outline" size="sm" className="h-8 text-xs">
266
+ {view}
267
+ <ChevronDown className="ml-2 h-3.5 w-3.5" />
268
+ </Button>
269
+ </DropdownMenuTrigger>
270
+ <DropdownMenuContent>
271
+ {viewOptions.map((option) => (
272
+ <DropdownMenuItem key={option} onClick={() => setView(option)}>
273
+ {option}
274
+ </DropdownMenuItem>
275
+ ))}
276
+ </DropdownMenuContent>
277
+ </DropdownMenu>
278
+
279
+ <DropdownMenu>
280
+ <DropdownMenuTrigger asChild>
281
+ <Button variant="outline" size="sm" className="h-8 text-xs">
282
+ Sort: {sortLabel.replace(/\s*\(.+\)/, "")}
283
+ <ChevronDown className="ml-2 h-3.5 w-3.5" />
284
+ </Button>
285
+ </DropdownMenuTrigger>
286
+ <DropdownMenuContent align="end" className="w-56">
287
+ {sortOptions.map((option) => (
288
+ <DropdownMenuItem key={option.id} onClick={() => setSortId(option.id)}>
289
+ {option.label}
290
+ </DropdownMenuItem>
291
+ ))}
292
+ </DropdownMenuContent>
293
+ </DropdownMenu>
294
+
295
+ <DropdownMenu>
296
+ <DropdownMenuTrigger asChild>
297
+ <Button variant="outline" size="sm" className="h-8 text-xs">
298
+ Role: {roleFilter}
299
+ <ChevronDown className="ml-2 h-3.5 w-3.5" />
300
+ </Button>
301
+ </DropdownMenuTrigger>
302
+ <DropdownMenuContent align="end">
303
+ {roleOptions.map((option) => (
304
+ <DropdownMenuItem key={option} onClick={() => setRoleFilter(option)}>
305
+ {option}
306
+ </DropdownMenuItem>
307
+ ))}
308
+ </DropdownMenuContent>
309
+ </DropdownMenu>
310
+
311
+ <Input
312
+ value={search}
313
+ onChange={(event) => setSearch(event.target.value)}
314
+ placeholder={searchPlaceholder}
315
+ className="h-8 w-48 text-xs"
316
+ />
317
+ </div>
318
+ </div>
319
+
320
+ <ScrollArea>
321
+ <div className="min-w-[1180px]">
322
+ <Table>
323
+ <TableHeader className="bg-muted/30">
324
+ <TableRow className="hover:bg-transparent">
325
+ <TableHead className="px-4 py-3 text-xs font-semibold uppercase tracking-wider text-muted-foreground">
326
+ {entityColumnLabel}
327
+ </TableHead>
328
+ <TableHead className="w-[260px] px-4 py-3 text-xs font-semibold uppercase tracking-wider text-muted-foreground">
329
+ {primaryMetricColumnLabel}
330
+ </TableHead>
331
+ <TableHead className="px-4 py-3 text-right text-xs font-semibold uppercase tracking-wider text-muted-foreground">
332
+ {rateColumnLabel}
333
+ </TableHead>
334
+ <TableHead className="px-4 py-3 text-right text-xs font-semibold uppercase tracking-wider text-muted-foreground">
335
+ {metricOneColumnLabel}
336
+ </TableHead>
337
+ <TableHead className="px-4 py-3 text-right text-xs font-semibold uppercase tracking-wider text-muted-foreground">
338
+ {metricTwoColumnLabel}
339
+ </TableHead>
340
+ <TableHead className="px-4 py-3 text-right text-xs font-semibold uppercase tracking-wider text-muted-foreground">
341
+ {metricThreeColumnLabel}
342
+ </TableHead>
343
+ <TableHead className="px-4 py-3 text-right text-xs font-semibold uppercase tracking-wider text-muted-foreground">
344
+ {metricFourColumnLabel}
345
+ </TableHead>
346
+ </TableRow>
347
+ </TableHeader>
348
+ <TableBody>
349
+ {paginatedRows.map((row) => {
350
+ const percentage = (row.primaryValue / row.primaryTarget) * 100
351
+ const progress = getProgressStatus(row.primaryValue, row.primaryTarget)
352
+
353
+ return (
354
+ <TableRow key={row.id} className="hover:bg-muted/30">
355
+ <TableCell className="px-4 py-3">
356
+ <div className="flex items-center gap-3">
357
+ <Avatar className="h-8 w-8 border border-border">
358
+ <AvatarFallback className="bg-emerald-100 text-[11px] font-medium text-emerald-700">
359
+ {row.avatarFallback}
360
+ </AvatarFallback>
361
+ </Avatar>
362
+ <span className="text-sm font-medium text-foreground">{row.label}</span>
363
+ </div>
364
+ </TableCell>
365
+
366
+ <TableCell className="px-4 py-3">
367
+ <div className="flex items-center gap-2">
368
+ <span className="shrink-0">{progress.icon}</span>
369
+ <div className="w-full max-w-[180px]">
370
+ <div className="mb-1 text-sm font-bold text-foreground">
371
+ {row.primaryValue}/{row.primaryTarget}
372
+ </div>
373
+ <div className="h-1.5 w-full overflow-hidden rounded-full bg-muted">
374
+ <div
375
+ className={cn("h-full rounded-full", progress.color)}
376
+ style={{ width: `${Math.min(100, percentage)}%` }}
377
+ />
378
+ </div>
379
+ <div className={cn("mt-1 text-xs font-medium", progress.textColor)}>
380
+ {Math.round(percentage)}%
381
+ </div>
382
+ </div>
383
+ </div>
384
+ </TableCell>
385
+
386
+ <TableCell className="px-4 py-3 text-right text-sm font-semibold text-emerald-600">
387
+ {row.ratePercent}%
388
+ </TableCell>
389
+ <TableCell className="px-4 py-3 text-right text-sm font-medium text-foreground">
390
+ {row.metricOne}
391
+ </TableCell>
392
+ <TableCell className="px-4 py-3 text-right text-sm text-muted-foreground">
393
+ {row.metricTwo}
394
+ </TableCell>
395
+ <TableCell className="px-4 py-3 text-right text-sm font-medium text-foreground">
396
+ {row.metricThree}
397
+ </TableCell>
398
+ <TableCell className="px-4 py-3 text-right text-sm font-medium text-foreground">
399
+ {row.metricFour}
400
+ </TableCell>
401
+ </TableRow>
402
+ )
403
+ })}
404
+ </TableBody>
405
+ </Table>
406
+ </div>
407
+ <ScrollBar orientation="horizontal" />
408
+ </ScrollArea>
409
+
410
+ <div className="flex items-center justify-between border-t border-border bg-muted/20 px-4 py-3">
411
+ <span className="text-xs text-muted-foreground">
412
+ Showing {sortedRows.length === 0 ? 0 : start + 1} to{" "}
413
+ {Math.min(start + pageSize, sortedRows.length)} of {sortedRows.length} rows
414
+ </span>
415
+ <div className="flex items-center gap-2">
416
+ <Button
417
+ variant="outline"
418
+ size="sm"
419
+ className="h-7 text-xs"
420
+ disabled={page <= 1}
421
+ onClick={() => setPage((previous) => Math.max(previous - 1, 1))}
422
+ >
423
+ <ChevronLeft className="mr-1 h-3.5 w-3.5" />
424
+ Previous
425
+ </Button>
426
+ <Button
427
+ variant="outline"
428
+ size="sm"
429
+ className="h-7 text-xs"
430
+ disabled={page >= pageCount}
431
+ onClick={() =>
432
+ setPage((previous) => Math.min(previous + 1, pageCount))
433
+ }
434
+ >
435
+ Next
436
+ <ChevronRight className="ml-1 h-3.5 w-3.5" />
437
+ </Button>
438
+ </div>
439
+ </div>
440
+ </div>
441
+ )
442
+ }
@@ -0,0 +1,62 @@
1
+ import * as React from "react"
2
+ import { cn } from "../lib/utils"
3
+
4
+ export function PreviewList({
5
+ children,
6
+ className,
7
+ ...props
8
+ }: React.HTMLAttributes<HTMLDivElement>) {
9
+ const items = React.Children.toArray(children)
10
+ const visibleItems = items.slice(0, 8)
11
+
12
+ return (
13
+ <div className={cn("flex flex-col", className)} {...props}>
14
+ {visibleItems}
15
+ </div>
16
+ )
17
+ }
18
+
19
+ export interface PreviewListItemProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'title'> {
20
+ icon?: React.ReactNode
21
+ title: React.ReactNode
22
+ subtitle?: React.ReactNode
23
+ meta?: React.ReactNode // e.g. time, badges on the right
24
+ action?: React.ReactNode // hover action like a "Join" button
25
+ isHoverable?: boolean
26
+ }
27
+
28
+ export const PreviewListItem = React.forwardRef<HTMLDivElement, PreviewListItemProps>(
29
+ ({ className, icon, title, subtitle, meta, action, isHoverable = true, ...props }, ref) => {
30
+ return (
31
+ <div
32
+ ref={ref}
33
+ className={cn(
34
+ "flex items-center justify-between group relative bg-background transition-colors",
35
+ "px-6 h-16 border-b border-border last:border-0",
36
+ isHoverable && "hover:bg-muted/30 cursor-pointer",
37
+ className
38
+ )}
39
+ {...props}
40
+ >
41
+ <div className="flex items-center gap-3 overflow-hidden min-w-0 h-full py-2">
42
+ {icon && <div className="shrink-0 flex items-center justify-center">{icon}</div>}
43
+ <div className="min-w-0 flex flex-col justify-center gap-1">
44
+ <div className="text-sm font-semibold text-foreground truncate leading-snug">{title}</div>
45
+ {subtitle && <div className="text-xs text-muted-foreground truncate leading-snug">{subtitle}</div>}
46
+ </div>
47
+ </div>
48
+
49
+ <div className="flex items-center gap-4 shrink-0 pl-4">
50
+ {meta && <div className={cn("flex items-center gap-2", action && "group-hover:opacity-0 transition-opacity")}>{meta}</div>}
51
+
52
+ {action && (
53
+ <div className="absolute right-4 opacity-0 group-hover:opacity-100 transition-opacity flex items-center bg-background/95 backdrop-blur-sm pl-2">
54
+ {action}
55
+ </div>
56
+ )}
57
+ </div>
58
+ </div>
59
+ )
60
+ }
61
+ )
62
+ PreviewListItem.displayName = "PreviewListItem"
@@ -0,0 +1,31 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { Progress as ProgressPrimitive } from "radix-ui"
5
+
6
+ import { cn } from "../lib/utils"
7
+
8
+ function Progress({
9
+ className,
10
+ value,
11
+ ...props
12
+ }: React.ComponentProps<typeof ProgressPrimitive.Root>) {
13
+ return (
14
+ <ProgressPrimitive.Root
15
+ data-slot="progress"
16
+ className={cn(
17
+ "bg-primary/20 relative h-2 w-full overflow-hidden rounded-full",
18
+ className
19
+ )}
20
+ {...props}
21
+ >
22
+ <ProgressPrimitive.Indicator
23
+ data-slot="progress-indicator"
24
+ className="bg-primary h-full w-full flex-1 transition-all"
25
+ style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
26
+ />
27
+ </ProgressPrimitive.Root>
28
+ )
29
+ }
30
+
31
+ export { Progress }
@@ -0,0 +1,156 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { ArrowUp, Paperclip } from "lucide-react"
5
+
6
+ import { cn } from "../lib/utils"
7
+ import { Button } from "./button"
8
+
9
+ export type QuickActionPriority = "normal" | "high" | "urgent"
10
+
11
+ export interface QuickActionSubmitPayload {
12
+ message: string
13
+ priority: QuickActionPriority
14
+ }
15
+
16
+ interface QuickActionChatAreaProps
17
+ extends Omit<React.ComponentProps<"div">, "onSubmit"> {
18
+ placeholder?: string
19
+ submitLabel?: string
20
+ value?: string
21
+ defaultValue?: string
22
+ onValueChange?: (value: string) => void
23
+ priority?: QuickActionPriority
24
+ defaultPriority?: QuickActionPriority
25
+ onPriorityChange?: (priority: QuickActionPriority) => void
26
+ onSubmit: (payload: QuickActionSubmitPayload) => void
27
+ allowEmptySubmit?: boolean
28
+ clearOnSubmit?: boolean
29
+ showEnterHint?: boolean
30
+ }
31
+
32
+ export function QuickActionChatArea({
33
+ className,
34
+ placeholder = "How can I help you today?",
35
+ submitLabel = "Create Task",
36
+ value,
37
+ defaultValue = "",
38
+ onValueChange,
39
+ priority,
40
+ defaultPriority = "normal",
41
+ onPriorityChange,
42
+ onSubmit,
43
+ allowEmptySubmit = false,
44
+ clearOnSubmit = true,
45
+ showEnterHint = true,
46
+ ...props
47
+ }: QuickActionChatAreaProps) {
48
+ const [internalValue, setInternalValue] = React.useState(defaultValue)
49
+ const [internalPriority, setInternalPriority] =
50
+ React.useState<QuickActionPriority>(defaultPriority)
51
+
52
+ const composerValue = value ?? internalValue
53
+ const selectedPriority = priority ?? internalPriority
54
+
55
+ const setComposerValue = React.useCallback(
56
+ (nextValue: string) => {
57
+ if (value === undefined) {
58
+ setInternalValue(nextValue)
59
+ }
60
+
61
+ onValueChange?.(nextValue)
62
+ },
63
+ [onValueChange, value]
64
+ )
65
+
66
+ const setPriorityValue = React.useCallback(
67
+ (nextPriority: QuickActionPriority) => {
68
+ if (priority === undefined) {
69
+ setInternalPriority(nextPriority)
70
+ }
71
+
72
+ onPriorityChange?.(nextPriority)
73
+ },
74
+ [onPriorityChange, priority]
75
+ )
76
+
77
+ const canSubmit = allowEmptySubmit || composerValue.trim().length > 0
78
+
79
+ const handleSubmit = React.useCallback(() => {
80
+ if (!canSubmit) {
81
+ return
82
+ }
83
+
84
+ onSubmit({
85
+ message: composerValue,
86
+ priority: selectedPriority,
87
+ })
88
+
89
+ if (clearOnSubmit) {
90
+ setComposerValue("")
91
+ }
92
+ }, [canSubmit, clearOnSubmit, composerValue, onSubmit, selectedPriority, setComposerValue])
93
+
94
+ return (
95
+ <div
96
+ className={cn("border-t border-border bg-background p-4", className)}
97
+ {...props}
98
+ >
99
+ <div className="mx-auto w-full max-w-2xl overflow-hidden rounded-md border border-border bg-background shadow-sm transition-all focus-within:border-[#1B4332] focus-within:ring-2 focus-within:ring-[#1B4332]/20">
100
+ <textarea
101
+ value={composerValue}
102
+ onChange={(event) => setComposerValue(event.target.value)}
103
+ placeholder={placeholder}
104
+ className="min-h-[80px] w-full resize-none p-4 text-foreground outline-none placeholder:text-muted-foreground"
105
+ onKeyDown={(event) => {
106
+ if (event.key === "Enter" && !event.shiftKey) {
107
+ event.preventDefault()
108
+ handleSubmit()
109
+ }
110
+ }}
111
+ />
112
+ <div className="flex items-center justify-between border-t border-border bg-muted px-3 py-2">
113
+ <div className="flex items-center gap-2">
114
+ <button
115
+ type="button"
116
+ className="rounded-md p-1.5 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground"
117
+ title="Attach file"
118
+ aria-label="Attach file"
119
+ >
120
+ <Paperclip className="h-4 w-4" />
121
+ </button>
122
+ <div className="mx-1 h-4 w-px bg-muted" />
123
+ <select
124
+ value={selectedPriority}
125
+ onChange={(event) =>
126
+ setPriorityValue(event.target.value as QuickActionPriority)
127
+ }
128
+ className="cursor-pointer rounded-md bg-transparent px-2 py-1 text-xs font-medium text-muted-foreground transition-colors hover:bg-muted"
129
+ aria-label="Task priority"
130
+ >
131
+ <option value="normal">Normal</option>
132
+ <option value="high">High</option>
133
+ <option value="urgent">Urgent</option>
134
+ </select>
135
+ </div>
136
+ <div className="flex items-center gap-3">
137
+ {showEnterHint ? (
138
+ <span className="hidden text-xs text-muted-foreground sm:inline">
139
+ Press ⏎ to create
140
+ </span>
141
+ ) : null}
142
+ <Button
143
+ size="sm"
144
+ onClick={handleSubmit}
145
+ disabled={!canSubmit}
146
+ className="gap-2 rounded-md bg-[#1B4332] text-white hover:bg-[#235742] disabled:cursor-not-allowed disabled:opacity-50"
147
+ >
148
+ {submitLabel}
149
+ <ArrowUp className="h-4 w-4" />
150
+ </Button>
151
+ </div>
152
+ </div>
153
+ </div>
154
+ </div>
155
+ )
156
+ }