@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,124 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import {
5
+ AreaChart,
6
+ Area,
7
+ XAxis,
8
+ YAxis,
9
+ CartesianGrid,
10
+ Tooltip,
11
+ ResponsiveContainer,
12
+ } from "recharts"
13
+
14
+ import { cn } from "../lib/utils"
15
+ import { CHART_TOOLTIP_STYLE } from "./chart-tooltip"
16
+
17
+ export interface VolumeDataKey {
18
+ key: string
19
+ color: string
20
+ }
21
+
22
+ export interface VolumeAnalysisChartProps {
23
+ data: Record<string, unknown>[]
24
+ dataKeys: VolumeDataKey[]
25
+ height?: number
26
+ xAxisKey?: string
27
+ stacked?: boolean
28
+ title?: string
29
+ subtitle?: string
30
+ className?: string
31
+ }
32
+
33
+ export function VolumeAnalysisChart({
34
+ data,
35
+ dataKeys,
36
+ height = 250,
37
+ xAxisKey = "date",
38
+ stacked = true,
39
+ title,
40
+ subtitle,
41
+ className,
42
+ }: VolumeAnalysisChartProps) {
43
+ const chartId = React.useId().replace(/:/g, "")
44
+
45
+ return (
46
+ <div className={cn("w-full", className)}>
47
+ {(title || subtitle) ? (
48
+ <div className="mb-4">
49
+ {title ? (
50
+ <h3 className="text-base font-semibold text-foreground">{title}</h3>
51
+ ) : null}
52
+ {subtitle ? (
53
+ <p className="mt-0.5 text-sm text-muted-foreground">{subtitle}</p>
54
+ ) : null}
55
+ </div>
56
+ ) : null}
57
+
58
+ <div className="w-full" style={{ height }}>
59
+ <ResponsiveContainer width="100%" height="100%">
60
+ <AreaChart
61
+ data={data}
62
+ margin={{ top: 10, right: 10, left: -20, bottom: 0 }}
63
+ >
64
+ <defs>
65
+ {dataKeys.map((item, i) => (
66
+ <linearGradient
67
+ key={item.key}
68
+ id={`vol-${chartId}-${i}`}
69
+ x1="0"
70
+ y1="0"
71
+ x2="0"
72
+ y2="1"
73
+ >
74
+ <stop
75
+ offset="5%"
76
+ stopColor={item.color}
77
+ stopOpacity={0.8}
78
+ />
79
+ <stop
80
+ offset="95%"
81
+ stopColor={item.color}
82
+ stopOpacity={0.1}
83
+ />
84
+ </linearGradient>
85
+ ))}
86
+ </defs>
87
+ <CartesianGrid
88
+ strokeDasharray="3 3"
89
+ vertical={false}
90
+ stroke="#f1f5f9"
91
+ />
92
+ <XAxis
93
+ dataKey={xAxisKey}
94
+ axisLine={false}
95
+ tickLine={false}
96
+ tick={{ fill: "#64748B", fontSize: 12 }}
97
+ dy={10}
98
+ />
99
+ <YAxis
100
+ axisLine={false}
101
+ tickLine={false}
102
+ tick={{ fill: "#64748B", fontSize: 12 }}
103
+ />
104
+ <Tooltip
105
+ contentStyle={CHART_TOOLTIP_STYLE}
106
+ itemStyle={{ fontSize: "12px", fontWeight: 600 }}
107
+ />
108
+ {dataKeys.map((item, i) => (
109
+ <Area
110
+ key={item.key}
111
+ type="linear"
112
+ dataKey={item.key}
113
+ stackId={stacked ? "1" : undefined}
114
+ stroke={item.color}
115
+ fill={`url(#vol-${chartId}-${i})`}
116
+ strokeWidth={2}
117
+ />
118
+ ))}
119
+ </AreaChart>
120
+ </ResponsiveContainer>
121
+ </div>
122
+ </div>
123
+ )
124
+ }
@@ -0,0 +1,233 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { ArrowLeft, ExternalLink, ChevronDown, ChevronUp } from "lucide-react"
5
+ import { Badge } from "./badge"
6
+
7
+ export interface ActivityThreadMessage {
8
+ id: string
9
+ sender: string
10
+ time: string
11
+ content: string
12
+ isCurrent?: boolean
13
+ to?: string
14
+ cc?: string
15
+ subject?: string
16
+ }
17
+
18
+ export interface ActivityParticipant {
19
+ name: string
20
+ role?: string
21
+ }
22
+
23
+ export interface ActivityDetailData {
24
+ icon: React.ReactNode
25
+ title: string
26
+ details: string
27
+ content?: string
28
+ time: string
29
+ source: string
30
+ sourceIcon?: React.ReactNode
31
+ type?: "email" | "call" | "meeting" | "signal"
32
+ thread?: ActivityThreadMessage[]
33
+ participants?: ActivityParticipant[]
34
+ tags?: string[]
35
+ externalUrl?: string
36
+ }
37
+
38
+ export interface ActivityDetailProps {
39
+ activity: ActivityDetailData
40
+ onBack?: () => void
41
+ actions?: React.ReactNode
42
+ }
43
+
44
+ function EmailMessage({ msg, defaultExpanded }: { msg: ActivityThreadMessage; defaultExpanded: boolean }) {
45
+ const [expanded, setExpanded] = React.useState(defaultExpanded)
46
+
47
+ return (
48
+ <div className="border-b border-border/20 last:border-0">
49
+ <button
50
+ onClick={() => setExpanded(!expanded)}
51
+ className="w-full text-left py-2.5 hover:bg-muted/10 transition-colors"
52
+ >
53
+ <div className="flex items-center justify-between">
54
+ <div className="flex items-center gap-2 min-w-0">
55
+ <span className="text-xs font-semibold text-foreground shrink-0">{msg.sender}</span>
56
+ {!expanded && (
57
+ <span className="text-xs text-muted-foreground truncate">&mdash; {msg.content.slice(0, 80)}{msg.content.length > 80 ? "..." : ""}</span>
58
+ )}
59
+ </div>
60
+ <div className="flex items-center gap-2 shrink-0 ml-2">
61
+ <span className="text-xs text-muted-foreground/60">{msg.time}</span>
62
+ {expanded ? <ChevronUp className="w-3 h-3 text-muted-foreground/40" /> : <ChevronDown className="w-3 h-3 text-muted-foreground/40" />}
63
+ </div>
64
+ </div>
65
+ </button>
66
+
67
+ {expanded && (
68
+ <div className="pb-3 animate-in fade-in duration-150">
69
+ {(msg.to || msg.cc) && (
70
+ <div className="text-xs text-muted-foreground/60 space-y-0.5 mb-2">
71
+ {msg.to && <p>To: {msg.to}</p>}
72
+ {msg.cc && <p>Cc: {msg.cc}</p>}
73
+ </div>
74
+ )}
75
+ <div className="text-sm text-foreground/90 leading-relaxed whitespace-pre-line">{msg.content}</div>
76
+ </div>
77
+ )}
78
+ </div>
79
+ )
80
+ }
81
+
82
+ export function ActivityDetail({ activity, onBack, actions }: ActivityDetailProps) {
83
+ const [threadExpanded, setThreadExpanded] = React.useState(false)
84
+ const hasThread = activity.thread && activity.thread.length > 0
85
+ const isEmail = activity.type === "email"
86
+
87
+ return (
88
+ <div className="space-y-0 animate-in fade-in slide-in-from-right-2 duration-200">
89
+ {/* Back + header */}
90
+ <div className="flex items-center justify-between mb-4">
91
+ {onBack && (
92
+ <button
93
+ onClick={onBack}
94
+ className="flex items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground transition-colors"
95
+ >
96
+ <ArrowLeft className="w-3.5 h-3.5" />
97
+ Back to activity
98
+ </button>
99
+ )}
100
+ {activity.externalUrl && (
101
+ <a
102
+ href={activity.externalUrl}
103
+ target="_blank"
104
+ rel="noopener noreferrer"
105
+ className="flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground transition-colors"
106
+ >
107
+ Open in {activity.source}
108
+ <ExternalLink className="w-3 h-3" />
109
+ </a>
110
+ )}
111
+ </div>
112
+
113
+ {/* Title block */}
114
+ <div className="flex items-start gap-3 pb-4 border-b border-border/30">
115
+ <div className="mt-0.5 w-8 h-8 rounded-md border border-border/60 bg-muted/30 flex items-center justify-center shrink-0 text-muted-foreground">
116
+ {activity.sourceIcon ?? activity.icon}
117
+ </div>
118
+ <div className="flex-1 min-w-0">
119
+ <h3 className="font-medium text-sm text-foreground leading-snug">{activity.title}</h3>
120
+ <p className="text-xs text-muted-foreground/60 mt-1">{activity.time} &middot; {activity.source}</p>
121
+ </div>
122
+ </div>
123
+
124
+ {/* Tags */}
125
+ {activity.tags && activity.tags.length > 0 && (
126
+ <div className="flex flex-wrap gap-1.5 py-3 border-b border-border/30">
127
+ {activity.tags.map((tag) => (
128
+ <Badge
129
+ key={tag}
130
+ variant="outline"
131
+ className="shadow-none px-2 py-0 text-[11px] font-medium text-muted-foreground border-border"
132
+ >
133
+ {tag}
134
+ </Badge>
135
+ ))}
136
+ </div>
137
+ )}
138
+
139
+ {/* Participants (non-email only; email shows to/cc per message) */}
140
+ {!isEmail && activity.participants && activity.participants.length > 0 && (
141
+ <div className="py-3 border-b border-border/30">
142
+ <span className="text-[11px] font-bold text-muted-foreground/70 uppercase tracking-wider">Participants</span>
143
+ <div className="mt-2 space-y-1">
144
+ {activity.participants.map((p, i) => (
145
+ <div key={i} className="flex items-center gap-2 text-sm">
146
+ <span className="font-medium text-foreground">{p.name}</span>
147
+ {p.role && (
148
+ <>
149
+ <span className="text-muted-foreground/40">&middot;</span>
150
+ <span className="text-muted-foreground">{p.role}</span>
151
+ </>
152
+ )}
153
+ </div>
154
+ ))}
155
+ </div>
156
+ </div>
157
+ )}
158
+
159
+ {/* Body content (non-email, or email summary) */}
160
+ {(!isEmail || !hasThread) && (
161
+ <div className="py-4 border-b border-border/30">
162
+ <p className="text-sm text-foreground/90 leading-relaxed">{activity.details}</p>
163
+ {activity.content && (
164
+ <div className="mt-3 text-sm text-muted-foreground leading-relaxed whitespace-pre-line">
165
+ {activity.content}
166
+ </div>
167
+ )}
168
+ </div>
169
+ )}
170
+
171
+ {/* Email context line when thread exists */}
172
+ {isEmail && hasThread && (
173
+ <div className="py-3 border-b border-border/30">
174
+ <p className="text-sm text-muted-foreground leading-snug">{activity.details}</p>
175
+ </div>
176
+ )}
177
+
178
+ {/* Thread: email vs generic */}
179
+ {hasThread && isEmail ? (
180
+ <div className="py-3 border-b border-border/30">
181
+ <div className="flex items-center justify-between mb-3">
182
+ <span className="text-[11px] font-bold text-muted-foreground/70 uppercase tracking-wider">
183
+ {activity.thread!.length} messages
184
+ </span>
185
+ </div>
186
+ <div className="space-y-0">
187
+ {activity.thread!.map((msg, i) => (
188
+ <EmailMessage
189
+ key={msg.id}
190
+ msg={msg}
191
+ defaultExpanded={i === activity.thread!.length - 1}
192
+ />
193
+ ))}
194
+ </div>
195
+ </div>
196
+ ) : hasThread ? (
197
+ <div className="py-3 border-b border-border/30">
198
+ <button
199
+ onClick={() => setThreadExpanded(!threadExpanded)}
200
+ className="flex items-center gap-1.5 text-[11px] font-bold text-muted-foreground/70 hover:text-foreground transition-colors uppercase tracking-wider"
201
+ >
202
+ Thread &middot; {activity.thread!.length} messages
203
+ <ChevronDown className={`w-3.5 h-3.5 transition-transform duration-200 ${threadExpanded ? "rotate-180" : ""}`} />
204
+ </button>
205
+
206
+ {threadExpanded && (
207
+ <div className="mt-3 space-y-0 animate-in fade-in slide-in-from-top-1 duration-200">
208
+ {activity.thread!.map((msg) => (
209
+ <div
210
+ key={msg.id}
211
+ className={`py-2.5 border-b border-border/20 last:border-0 ${msg.isCurrent ? "bg-muted/20 -mx-2 px-2 rounded-sm" : ""}`}
212
+ >
213
+ <div className="flex items-center justify-between mb-1">
214
+ <span className="text-xs font-semibold text-foreground">{msg.sender}</span>
215
+ <span className="text-xs text-muted-foreground/60">{msg.time}</span>
216
+ </div>
217
+ <p className="text-sm text-muted-foreground leading-snug">{msg.content}</p>
218
+ </div>
219
+ ))}
220
+ </div>
221
+ )}
222
+ </div>
223
+ ) : null}
224
+
225
+ {/* Actions */}
226
+ {actions && (
227
+ <div className="pt-4">
228
+ {actions}
229
+ </div>
230
+ )}
231
+ </div>
232
+ )
233
+ }
@@ -0,0 +1,89 @@
1
+ import * as React from "react"
2
+ import { Activity, Scale, Heart, MessageSquare, ArrowRight, ChevronDown } from "lucide-react"
3
+ import { format } from "date-fns"
4
+
5
+
6
+ export interface ActivityLogItem {
7
+ id: string
8
+ type: "workout" | "weighin" | "biometric" | "checkin" | string
9
+ title: string
10
+ details: string
11
+ date: string
12
+ time: string
13
+ }
14
+
15
+ export interface ActivityLogProps {
16
+ items: ActivityLogItem[]
17
+ title?: string
18
+ initialLimit?: number
19
+ }
20
+
21
+ const getIcon = (type: string) => {
22
+ switch (type) {
23
+ case "workout":
24
+ return <Activity size={16} className="text-orange-500" />
25
+ case "weighin":
26
+ return <Scale size={16} className="text-blue-500" />
27
+ case "biometric":
28
+ return <Heart size={16} className="text-rose-500" />
29
+ case "checkin":
30
+ return <MessageSquare size={16} className="text-indigo-500" />
31
+ default:
32
+ return <Activity size={16} className="text-gray-500" />
33
+ }
34
+ }
35
+
36
+ export function ActivityRow({ item }: { item: ActivityLogItem }) {
37
+ return (
38
+ <div className="flex items-center gap-4 py-3 border-b border-gray-100 last:border-0 hover:bg-gray-50 px-2 -mx-2 rounded-md transition-colors group">
39
+ <div className="flex-shrink-0 w-8 h-8 rounded-full bg-gray-50 border border-gray-200 flex items-center justify-center">
40
+ {getIcon(item.type)}
41
+ </div>
42
+
43
+ <div className="flex-1 min-w-0 flex flex-col sm:flex-row sm:items-center gap-1 sm:gap-2">
44
+ <span className="font-medium text-sm text-gray-900">{item.title}</span>
45
+ <span className="hidden sm:inline text-gray-300">•</span>
46
+ <span className="text-xs text-gray-500 truncate">{item.details}</span>
47
+
48
+ {item.type === "checkin" && (
49
+ <button className="ml-auto sm:ml-2 text-xs text-indigo-600 hover:text-indigo-800 font-medium flex items-center gap-0.5 opacity-0 group-hover:opacity-100 transition-opacity">
50
+ view <ArrowRight size={10} />
51
+ </button>
52
+ )}
53
+ </div>
54
+
55
+ <div className="text-right flex-shrink-0">
56
+ <div className="text-xs text-gray-500">{format(new Date(item.date), "MMM d")}</div>
57
+ <div className="text-[10px] text-gray-400">{item.time}</div>
58
+ </div>
59
+ </div>
60
+ )
61
+ }
62
+
63
+ export function ActivityLog({ items, title = "Recent Activity", initialLimit = 5 }: ActivityLogProps) {
64
+ const [limit, setLimit] = React.useState(initialLimit)
65
+ const displayedLogs = items.slice(0, limit)
66
+ const hasMore = limit < items.length
67
+
68
+ return (
69
+ <div className="bg-white rounded-xl border border-gray-200 p-6 shadow-sm">
70
+ <h2 className="text-lg font-semibold text-gray-900 mb-4">{title}</h2>
71
+
72
+ <div className="flex flex-col">
73
+ {displayedLogs.map((item) => (
74
+ <ActivityRow key={item.id} item={item} />
75
+ ))}
76
+ </div>
77
+
78
+ {hasMore && (
79
+ <button
80
+ onClick={() => setLimit((prev) => prev + 5)}
81
+ className="w-full mt-4 py-2 flex items-center justify-center gap-2 text-sm text-gray-500 hover:text-gray-900 hover:bg-gray-50 rounded-md transition-colors border border-dashed border-gray-200"
82
+ >
83
+ <ChevronDown size={14} />
84
+ Show more
85
+ </button>
86
+ )}
87
+ </div>
88
+ )
89
+ }