agentic-ds-kit 0.1.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 (345) hide show
  1. package/AGENTS.md +10 -0
  2. package/CLAUDE.md +1 -0
  3. package/LICENSE +21 -0
  4. package/README.md +38 -0
  5. package/contracts/accordion.json +38 -0
  6. package/contracts/alert.json +57 -0
  7. package/contracts/alertdialog.json +89 -0
  8. package/contracts/appheader.json +140 -0
  9. package/contracts/appnav.json +72 -0
  10. package/contracts/avatar.json +63 -0
  11. package/contracts/avatargroup.json +83 -0
  12. package/contracts/badge.json +92 -0
  13. package/contracts/barchart.json +55 -0
  14. package/contracts/breadcrumb.json +76 -0
  15. package/contracts/button.json +120 -0
  16. package/contracts/buttongroup.json +48 -0
  17. package/contracts/calendar.json +93 -0
  18. package/contracts/card.json +123 -0
  19. package/contracts/carousel.json +98 -0
  20. package/contracts/cell.json +203 -0
  21. package/contracts/chat.json +131 -0
  22. package/contracts/checkbox.json +101 -0
  23. package/contracts/collapsible.json +66 -0
  24. package/contracts/command.json +84 -0
  25. package/contracts/datatable.json +126 -0
  26. package/contracts/datepicker.json +102 -0
  27. package/contracts/drawer.json +93 -0
  28. package/contracts/dropdownmenu.json +190 -0
  29. package/contracts/empty.json +79 -0
  30. package/contracts/field.json +49 -0
  31. package/contracts/fieldset.json +29 -0
  32. package/contracts/headercell.json +107 -0
  33. package/contracts/index.json +478 -0
  34. package/contracts/input.json +119 -0
  35. package/contracts/inputotp.json +119 -0
  36. package/contracts/insightcard.json +130 -0
  37. package/contracts/linechart.json +51 -0
  38. package/contracts/loadinganimation.json +33 -0
  39. package/contracts/modal.json +100 -0
  40. package/contracts/modalcard.json +88 -0
  41. package/contracts/navigationmenu.json +65 -0
  42. package/contracts/numbertransition.json +33 -0
  43. package/contracts/pageheader.json +101 -0
  44. package/contracts/pagination.json +85 -0
  45. package/contracts/patterns/activity.json +30 -0
  46. package/contracts/patterns/assistant-workspace.json +16 -0
  47. package/contracts/patterns/dashboard.json +12 -0
  48. package/contracts/patterns/empty-first-run.json +15 -0
  49. package/contracts/patterns/inbox.json +32 -0
  50. package/contracts/patterns/invite-members.json +14 -0
  51. package/contracts/patterns/list-detail.json +13 -0
  52. package/contracts/patterns/settings-form.json +13 -0
  53. package/contracts/piechart.json +68 -0
  54. package/contracts/progress.json +124 -0
  55. package/contracts/progresssteps.json +91 -0
  56. package/contracts/radiogroup.json +132 -0
  57. package/contracts/scoreboard.json +46 -0
  58. package/contracts/scorecard.json +124 -0
  59. package/contracts/section.json +97 -0
  60. package/contracts/select.json +130 -0
  61. package/contracts/shimmertext.json +33 -0
  62. package/contracts/sidenav.json +133 -0
  63. package/contracts/slider.json +81 -0
  64. package/contracts/spinner.json +52 -0
  65. package/contracts/switch.json +94 -0
  66. package/contracts/table.json +92 -0
  67. package/contracts/tabs.json +90 -0
  68. package/contracts/textarea.json +54 -0
  69. package/contracts/thinkinganimation.json +32 -0
  70. package/contracts/timeline.json +49 -0
  71. package/contracts/toast.json +104 -0
  72. package/contracts/tooltip.json +66 -0
  73. package/lib/tokens.css +637 -0
  74. package/package.json +60 -0
  75. package/skills/prototype-from-kit/SKILL.md +29 -0
  76. package/src/index.ts +71 -0
  77. package/tokens/tokens.json +725 -0
  78. package/ui/Accordion/Accordion.module.css +68 -0
  79. package/ui/Accordion/Accordion.tsx +51 -0
  80. package/ui/Accordion/Accordion.types.ts +10 -0
  81. package/ui/Accordion/index.ts +2 -0
  82. package/ui/Alert/Alert.module.css +62 -0
  83. package/ui/Alert/Alert.tsx +27 -0
  84. package/ui/Alert/Alert.types.ts +7 -0
  85. package/ui/Alert/index.ts +2 -0
  86. package/ui/AlertDialog/AlertDialog.module.css +71 -0
  87. package/ui/AlertDialog/AlertDialog.tsx +109 -0
  88. package/ui/AlertDialog/AlertDialog.types.ts +14 -0
  89. package/ui/AlertDialog/index.ts +6 -0
  90. package/ui/AppHeader/AppHeader.module.css +120 -0
  91. package/ui/AppHeader/AppHeader.tsx +70 -0
  92. package/ui/AppHeader/AppHeader.types.ts +28 -0
  93. package/ui/AppHeader/index.ts +2 -0
  94. package/ui/AppNav/AppNav.module.css +168 -0
  95. package/ui/AppNav/AppNav.tsx +137 -0
  96. package/ui/AppNav/AppNav.types.ts +24 -0
  97. package/ui/AppNav/index.ts +2 -0
  98. package/ui/Avatar/Avatar.module.css +52 -0
  99. package/ui/Avatar/Avatar.tsx +62 -0
  100. package/ui/Avatar/Avatar.types.ts +8 -0
  101. package/ui/Avatar/index.ts +2 -0
  102. package/ui/AvatarGroup/AvatarGroup.module.css +49 -0
  103. package/ui/AvatarGroup/AvatarGroup.tsx +29 -0
  104. package/ui/AvatarGroup/AvatarGroup.types.ts +16 -0
  105. package/ui/AvatarGroup/index.ts +2 -0
  106. package/ui/Badge/Badge.module.css +92 -0
  107. package/ui/Badge/Badge.tsx +43 -0
  108. package/ui/Badge/Badge.types.ts +11 -0
  109. package/ui/Badge/index.ts +2 -0
  110. package/ui/BarChart/BarChart.module.css +56 -0
  111. package/ui/BarChart/BarChart.tsx +380 -0
  112. package/ui/BarChart/BarChart.types.ts +18 -0
  113. package/ui/BarChart/index.ts +2 -0
  114. package/ui/Breadcrumb/Breadcrumb.module.css +64 -0
  115. package/ui/Breadcrumb/Breadcrumb.tsx +89 -0
  116. package/ui/Breadcrumb/Breadcrumb.types.ts +14 -0
  117. package/ui/Breadcrumb/index.ts +2 -0
  118. package/ui/Button/Button.module.css +101 -0
  119. package/ui/Button/Button.tsx +49 -0
  120. package/ui/Button/Button.types.ts +18 -0
  121. package/ui/Button/index.ts +2 -0
  122. package/ui/Button/lucideName.tsx +188 -0
  123. package/ui/ButtonGroup/ButtonGroup.module.css +31 -0
  124. package/ui/ButtonGroup/ButtonGroup.tsx +12 -0
  125. package/ui/ButtonGroup/ButtonGroup.types.ts +6 -0
  126. package/ui/ButtonGroup/index.ts +2 -0
  127. package/ui/Calendar/Calendar.module.css +146 -0
  128. package/ui/Calendar/Calendar.tsx +296 -0
  129. package/ui/Calendar/Calendar.types.ts +11 -0
  130. package/ui/Calendar/index.ts +2 -0
  131. package/ui/Card/Card.module.css +95 -0
  132. package/ui/Card/Card.tsx +69 -0
  133. package/ui/Card/Card.types.ts +23 -0
  134. package/ui/Card/index.ts +2 -0
  135. package/ui/Carousel/Carousel.module.css +114 -0
  136. package/ui/Carousel/Carousel.tsx +152 -0
  137. package/ui/Carousel/Carousel.types.ts +17 -0
  138. package/ui/Carousel/index.ts +7 -0
  139. package/ui/Cell/Cell.module.css +133 -0
  140. package/ui/Cell/Cell.tsx +300 -0
  141. package/ui/Cell/Cell.types.ts +69 -0
  142. package/ui/Cell/index.ts +11 -0
  143. package/ui/Chat/Chat.module.css +149 -0
  144. package/ui/Chat/Chat.tsx +175 -0
  145. package/ui/Chat/Chat.types.ts +39 -0
  146. package/ui/Chat/index.ts +2 -0
  147. package/ui/Checkbox/Checkbox.module.css +135 -0
  148. package/ui/Checkbox/Checkbox.tsx +70 -0
  149. package/ui/Checkbox/Checkbox.types.ts +15 -0
  150. package/ui/Checkbox/index.ts +2 -0
  151. package/ui/Collapsible/Collapsible.module.css +68 -0
  152. package/ui/Collapsible/Collapsible.tsx +59 -0
  153. package/ui/Collapsible/Collapsible.types.ts +9 -0
  154. package/ui/Collapsible/index.ts +2 -0
  155. package/ui/Command/Command.module.css +138 -0
  156. package/ui/Command/Command.tsx +152 -0
  157. package/ui/Command/Command.types.ts +20 -0
  158. package/ui/Command/index.ts +2 -0
  159. package/ui/DataTable/DataTable.module.css +211 -0
  160. package/ui/DataTable/DataTable.tsx +429 -0
  161. package/ui/DataTable/DataTable.types.ts +35 -0
  162. package/ui/DataTable/index.ts +8 -0
  163. package/ui/DatePicker/DatePicker.module.css +44 -0
  164. package/ui/DatePicker/DatePicker.tsx +123 -0
  165. package/ui/DatePicker/DatePicker.types.ts +15 -0
  166. package/ui/DatePicker/index.ts +2 -0
  167. package/ui/Drawer/Drawer.module.css +204 -0
  168. package/ui/Drawer/Drawer.tsx +112 -0
  169. package/ui/Drawer/Drawer.types.ts +14 -0
  170. package/ui/Drawer/index.ts +2 -0
  171. package/ui/DropdownMenu/DropdownMenu.module.css +319 -0
  172. package/ui/DropdownMenu/DropdownMenu.tsx +580 -0
  173. package/ui/DropdownMenu/DropdownMenu.types.ts +48 -0
  174. package/ui/DropdownMenu/index.ts +8 -0
  175. package/ui/Empty/Empty.module.css +68 -0
  176. package/ui/Empty/Empty.tsx +35 -0
  177. package/ui/Empty/Empty.types.ts +10 -0
  178. package/ui/Empty/index.ts +2 -0
  179. package/ui/Field/Field.module.css +66 -0
  180. package/ui/Field/Field.tsx +46 -0
  181. package/ui/Field/Field.types.ts +12 -0
  182. package/ui/Field/index.ts +2 -0
  183. package/ui/FieldSet/FieldSet.module.css +30 -0
  184. package/ui/FieldSet/FieldSet.tsx +14 -0
  185. package/ui/FieldSet/FieldSet.types.ts +7 -0
  186. package/ui/FieldSet/index.ts +2 -0
  187. package/ui/HeaderCell/HeaderCell.module.css +85 -0
  188. package/ui/HeaderCell/HeaderCell.tsx +71 -0
  189. package/ui/HeaderCell/HeaderCell.types.ts +18 -0
  190. package/ui/HeaderCell/index.ts +2 -0
  191. package/ui/Input/Input.module.css +59 -0
  192. package/ui/Input/Input.tsx +65 -0
  193. package/ui/Input/Input.types.ts +22 -0
  194. package/ui/Input/index.ts +2 -0
  195. package/ui/InputOTP/InputOTP.module.css +139 -0
  196. package/ui/InputOTP/InputOTP.tsx +136 -0
  197. package/ui/InputOTP/InputOTP.types.ts +19 -0
  198. package/ui/InputOTP/index.ts +2 -0
  199. package/ui/InsightCard/InsightCard.module.css +166 -0
  200. package/ui/InsightCard/InsightCard.tsx +90 -0
  201. package/ui/InsightCard/InsightCard.types.ts +20 -0
  202. package/ui/InsightCard/index.ts +7 -0
  203. package/ui/LineChart/LineChart.module.css +93 -0
  204. package/ui/LineChart/LineChart.tsx +424 -0
  205. package/ui/LineChart/LineChart.types.ts +19 -0
  206. package/ui/LineChart/index.ts +2 -0
  207. package/ui/LoadingAnimation/LoadingAnimation.module.css +66 -0
  208. package/ui/LoadingAnimation/LoadingAnimation.tsx +41 -0
  209. package/ui/LoadingAnimation/LoadingAnimation.types.ts +9 -0
  210. package/ui/LoadingAnimation/index.ts +6 -0
  211. package/ui/Modal/Modal.module.css +48 -0
  212. package/ui/Modal/Modal.tsx +114 -0
  213. package/ui/Modal/Modal.types.ts +15 -0
  214. package/ui/Modal/index.ts +2 -0
  215. package/ui/ModalCard/ModalCard.module.css +137 -0
  216. package/ui/ModalCard/ModalCard.tsx +58 -0
  217. package/ui/ModalCard/ModalCard.types.ts +15 -0
  218. package/ui/ModalCard/index.ts +2 -0
  219. package/ui/NavigationMenu/NavigationMenu.module.css +31 -0
  220. package/ui/NavigationMenu/NavigationMenu.tsx +57 -0
  221. package/ui/NavigationMenu/NavigationMenu.types.ts +22 -0
  222. package/ui/NavigationMenu/index.ts +7 -0
  223. package/ui/NumberTransition/NumberTransition.module.css +110 -0
  224. package/ui/NumberTransition/NumberTransition.tsx +78 -0
  225. package/ui/NumberTransition/NumberTransition.types.ts +9 -0
  226. package/ui/NumberTransition/index.ts +2 -0
  227. package/ui/PageHeader/PageHeader.module.css +57 -0
  228. package/ui/PageHeader/PageHeader.tsx +39 -0
  229. package/ui/PageHeader/PageHeader.types.ts +12 -0
  230. package/ui/PageHeader/index.ts +2 -0
  231. package/ui/Pagination/Pagination.module.css +19 -0
  232. package/ui/Pagination/Pagination.tsx +147 -0
  233. package/ui/Pagination/Pagination.types.ts +12 -0
  234. package/ui/Pagination/index.ts +2 -0
  235. package/ui/PieChart/PieChart.module.css +116 -0
  236. package/ui/PieChart/PieChart.tsx +293 -0
  237. package/ui/PieChart/PieChart.types.ts +22 -0
  238. package/ui/PieChart/index.ts +2 -0
  239. package/ui/Progress/Progress.module.css +226 -0
  240. package/ui/Progress/Progress.tsx +167 -0
  241. package/ui/Progress/Progress.types.ts +15 -0
  242. package/ui/Progress/index.ts +8 -0
  243. package/ui/ProgressSteps/ProgressSteps.module.css +210 -0
  244. package/ui/ProgressSteps/ProgressSteps.tsx +105 -0
  245. package/ui/ProgressSteps/ProgressSteps.types.ts +19 -0
  246. package/ui/ProgressSteps/index.ts +8 -0
  247. package/ui/RadioGroup/RadioGroup.module.css +284 -0
  248. package/ui/RadioGroup/RadioGroup.tsx +116 -0
  249. package/ui/RadioGroup/RadioGroup.types.ts +30 -0
  250. package/ui/RadioGroup/index.ts +8 -0
  251. package/ui/Scoreboard/Scoreboard.module.css +53 -0
  252. package/ui/Scoreboard/Scoreboard.tsx +41 -0
  253. package/ui/Scoreboard/Scoreboard.types.ts +7 -0
  254. package/ui/Scoreboard/index.ts +2 -0
  255. package/ui/Scorecard/Scorecard.module.css +150 -0
  256. package/ui/Scorecard/Scorecard.tsx +92 -0
  257. package/ui/Scorecard/Scorecard.types.ts +18 -0
  258. package/ui/Scorecard/index.ts +2 -0
  259. package/ui/Section/Section.module.css +104 -0
  260. package/ui/Section/Section.tsx +75 -0
  261. package/ui/Section/Section.types.ts +15 -0
  262. package/ui/Section/index.ts +2 -0
  263. package/ui/Select/Select.module.css +7 -0
  264. package/ui/Select/Select.tsx +113 -0
  265. package/ui/Select/Select.types.ts +26 -0
  266. package/ui/Select/index.ts +2 -0
  267. package/ui/ShimmerText/ShimmerText.module.css +46 -0
  268. package/ui/ShimmerText/ShimmerText.tsx +48 -0
  269. package/ui/ShimmerText/ShimmerText.types.ts +12 -0
  270. package/ui/ShimmerText/index.ts +2 -0
  271. package/ui/SideNav/SideNav.module.css +347 -0
  272. package/ui/SideNav/SideNav.tsx +222 -0
  273. package/ui/SideNav/SideNav.types.ts +42 -0
  274. package/ui/SideNav/index.ts +8 -0
  275. package/ui/Slider/Slider.module.css +105 -0
  276. package/ui/Slider/Slider.tsx +187 -0
  277. package/ui/Slider/Slider.types.ts +11 -0
  278. package/ui/Slider/index.ts +2 -0
  279. package/ui/Spinner/Spinner.module.css +58 -0
  280. package/ui/Spinner/Spinner.tsx +19 -0
  281. package/ui/Spinner/Spinner.types.ts +6 -0
  282. package/ui/Spinner/index.ts +2 -0
  283. package/ui/Switch/Switch.module.css +189 -0
  284. package/ui/Switch/Switch.tsx +65 -0
  285. package/ui/Switch/Switch.types.ts +12 -0
  286. package/ui/Switch/index.ts +2 -0
  287. package/ui/Table/Table.module.css +132 -0
  288. package/ui/Table/Table.tsx +108 -0
  289. package/ui/Table/Table.types.ts +26 -0
  290. package/ui/Table/index.ts +8 -0
  291. package/ui/Tabs/Tabs.module.css +162 -0
  292. package/ui/Tabs/Tabs.tsx +150 -0
  293. package/ui/Tabs/Tabs.types.ts +21 -0
  294. package/ui/Tabs/index.ts +2 -0
  295. package/ui/Textarea/Textarea.module.css +74 -0
  296. package/ui/Textarea/Textarea.tsx +38 -0
  297. package/ui/Textarea/Textarea.types.ts +14 -0
  298. package/ui/Textarea/index.ts +2 -0
  299. package/ui/ThinkingAnimation/ThinkingAnimation.module.css +75 -0
  300. package/ui/ThinkingAnimation/ThinkingAnimation.tsx +31 -0
  301. package/ui/ThinkingAnimation/ThinkingAnimation.types.ts +8 -0
  302. package/ui/ThinkingAnimation/index.ts +2 -0
  303. package/ui/Timeline/Timeline.module.css +99 -0
  304. package/ui/Timeline/Timeline.tsx +47 -0
  305. package/ui/Timeline/Timeline.types.ts +16 -0
  306. package/ui/Timeline/index.ts +2 -0
  307. package/ui/Toast/Toast.module.css +133 -0
  308. package/ui/Toast/Toast.tsx +89 -0
  309. package/ui/Toast/Toast.types.ts +17 -0
  310. package/ui/Toast/index.ts +2 -0
  311. package/ui/Tooltip/Tooltip.module.css +111 -0
  312. package/ui/Tooltip/Tooltip.tsx +101 -0
  313. package/ui/Tooltip/index.ts +2 -0
  314. package/ui/patterns/ActivityPattern/ActivityFeed.tsx +77 -0
  315. package/ui/patterns/ActivityPattern/ActivityPattern.tsx +120 -0
  316. package/ui/patterns/ActivityPattern/ActivityTasks.tsx +86 -0
  317. package/ui/patterns/ActivityPattern/TaskDrawer.module.css +39 -0
  318. package/ui/patterns/ActivityPattern/TaskDrawer.tsx +186 -0
  319. package/ui/patterns/ActivityPattern/index.ts +2 -0
  320. package/ui/patterns/AssistantWorkspacePattern/AssistantWorkspacePattern.module.css +16 -0
  321. package/ui/patterns/AssistantWorkspacePattern/AssistantWorkspacePattern.tsx +159 -0
  322. package/ui/patterns/AssistantWorkspacePattern/index.ts +2 -0
  323. package/ui/patterns/DashboardPattern/DashboardPattern.tsx +102 -0
  324. package/ui/patterns/DashboardPattern/index.ts +1 -0
  325. package/ui/patterns/DashboardPattern/patterns.module.css +6 -0
  326. package/ui/patterns/EmptyFirstRunPattern/EmptyFirstRunPattern.tsx +125 -0
  327. package/ui/patterns/EmptyFirstRunPattern/index.ts +2 -0
  328. package/ui/patterns/InboxPattern/InboxPattern.module.css +40 -0
  329. package/ui/patterns/InboxPattern/InboxPattern.tsx +192 -0
  330. package/ui/patterns/InboxPattern/InboxReplyDrawer.tsx +97 -0
  331. package/ui/patterns/InboxPattern/inbox-data.ts +101 -0
  332. package/ui/patterns/InboxPattern/index.ts +2 -0
  333. package/ui/patterns/InviteMembersPattern/InviteMembersPattern.tsx +148 -0
  334. package/ui/patterns/InviteMembersPattern/index.ts +2 -0
  335. package/ui/patterns/ListDetailPattern/ListDetailPattern.module.css +34 -0
  336. package/ui/patterns/ListDetailPattern/ListDetailPattern.tsx +145 -0
  337. package/ui/patterns/ListDetailPattern/index.ts +2 -0
  338. package/ui/patterns/SettingsFormPattern/SettingsFormPattern.module.css +12 -0
  339. package/ui/patterns/SettingsFormPattern/SettingsFormPattern.tsx +89 -0
  340. package/ui/patterns/SettingsFormPattern/index.ts +3 -0
  341. package/ui/shared/ChartFrame.module.css +295 -0
  342. package/ui/shared/ChartFrame.tsx +87 -0
  343. package/ui/shared/chartMath.ts +228 -0
  344. package/ui/shared/controls.module.css +48 -0
  345. package/ui/shared/useChartSize.ts +22 -0
@@ -0,0 +1,159 @@
1
+ "use client";
2
+
3
+ import { useEffect, useRef, useState } from "react";
4
+ import { Button } from "../../Button";
5
+ import { Chat } from "../../Chat";
6
+ import type { ChatMessage } from "../../Chat";
7
+ import { InsightCard } from "../../InsightCard";
8
+ import type { InsightCardTone } from "../../InsightCard";
9
+ import { PageHeader } from "../../PageHeader";
10
+ import type { PageHeaderProps } from "../../PageHeader";
11
+ import { Section } from "../../Section";
12
+ import styles from "./AssistantWorkspacePattern.module.css";
13
+
14
+ interface Insight {
15
+ id: string;
16
+ title: string;
17
+ description: string;
18
+ tone: InsightCardTone;
19
+ source: string;
20
+ prompt: string;
21
+ reply: string;
22
+ }
23
+
24
+ const INSIGHTS: Insight[] = [
25
+ {
26
+ id: "qa-checklist",
27
+ title: "QA checklist is still blocked",
28
+ description: "Unassigned for 2 days. Assign an owner before Thursday's review.",
29
+ tone: "warning",
30
+ source: "From Open tasks",
31
+ prompt: "Why is QA blocked?",
32
+ reply: "QA checklist has no owner. Assign someone before Thursday so the last two device passes can close.",
33
+ },
34
+ {
35
+ id: "invite-members",
36
+ title: "Invite members is still open",
37
+ description: "Three seats unused. Send invites so review comments have owners.",
38
+ tone: "warning",
39
+ source: "From Workspace",
40
+ prompt: "Who should own invites?",
41
+ reply: "Seats are provisioned. Maya can send the design and QA invites from Invite members so comments have owners.",
42
+ },
43
+ {
44
+ id: "release-notes",
45
+ title: "Release notes are ready to ship",
46
+ description: "Jordan marked this Ready. Confirm the changelog before tag.",
47
+ tone: "opportunity",
48
+ source: "From Open tasks",
49
+ prompt: "Draft a standup update",
50
+ reply: "Release notes are Ready. Confirm the known-issues list, then tag. QA is still blocked and needs an owner today.",
51
+ },
52
+ ];
53
+
54
+ const STARTER: ChatMessage[] = [
55
+ {
56
+ role: "assistant",
57
+ content: "I can explain a blocked task, suggest an owner, or draft a standup update.",
58
+ },
59
+ ];
60
+
61
+ const SUGGESTIONS = INSIGHTS.map((insight) => insight.prompt);
62
+
63
+ function replyFor(message: string): string {
64
+ const hit = INSIGHTS.find(
65
+ (insight) => insight.prompt.toLowerCase() === message.trim().toLowerCase() || insight.id === message,
66
+ );
67
+ if (hit) return hit.reply;
68
+ return `Got it — “${message}”. I can go deeper on owners or next steps.`;
69
+ }
70
+
71
+ export interface AssistantWorkspacePatternProps {
72
+ breadcrumbs?: PageHeaderProps["breadcrumbs"];
73
+ }
74
+
75
+ export function AssistantWorkspacePattern({ breadcrumbs }: AssistantWorkspacePatternProps) {
76
+ const [railOpen, setRailOpen] = useState(true);
77
+ const [messages, setMessages] = useState<ChatMessage[]>(STARTER);
78
+ const [thinking, setThinking] = useState(false);
79
+ const timerRef = useRef<number | null>(null);
80
+
81
+ useEffect(() => {
82
+ return () => {
83
+ if (timerRef.current !== null) window.clearTimeout(timerRef.current);
84
+ };
85
+ }, []);
86
+
87
+ function ask(prompt: string) {
88
+ const next = prompt.trim();
89
+ if (!next || thinking) return;
90
+ setRailOpen(true);
91
+ setMessages((current) => [...current, { role: "user", content: next }]);
92
+ setThinking(true);
93
+ if (timerRef.current !== null) window.clearTimeout(timerRef.current);
94
+ timerRef.current = window.setTimeout(() => {
95
+ setMessages((current) => [...current, { role: "assistant", content: replyFor(next) }]);
96
+ setThinking(false);
97
+ timerRef.current = null;
98
+ }, 1200);
99
+ }
100
+
101
+ return (
102
+ <div
103
+ className={`${railOpen ? "layout-workspace" : "layout-workspace layout-workspace--flush"} ${styles.shell}`}
104
+ >
105
+ <div className="layout-canvas">
106
+ <div className="layout-header">
107
+ <PageHeader
108
+ title="Insights"
109
+ subtitle="Recommendations for Sprint 24, with an assistant on the side."
110
+ breadcrumbs={breadcrumbs}
111
+ actions={
112
+ railOpen ? undefined : (
113
+ <Button variant="primary" size="md" iconStart="Sparkles" onClick={() => setRailOpen(true)}>
114
+ Ask assistant
115
+ </Button>
116
+ )
117
+ }
118
+ />
119
+ </div>
120
+ <div className="layout-content">
121
+ <Section title="Recommended" description="Ask the assistant about a card, or send a prompt in the rail.">
122
+ <div className={`layout-split ${styles.insights}`}>
123
+ {INSIGHTS.map((insight) => (
124
+ <InsightCard
125
+ key={insight.id}
126
+ title={insight.title}
127
+ description={insight.description}
128
+ tone={insight.tone}
129
+ source={insight.source}
130
+ secondaryAction={{
131
+ label: "Ask",
132
+ onClick: () => ask(insight.prompt),
133
+ }}
134
+ />
135
+ ))}
136
+ </div>
137
+ </Section>
138
+ </div>
139
+ </div>
140
+ {railOpen ? (
141
+ <aside className={styles.rail}>
142
+ <Chat
143
+ title="Assistant"
144
+ status="Sprint 24"
145
+ messages={messages}
146
+ suggestions={SUGGESTIONS}
147
+ placeholder="Ask about this sprint"
148
+ emptyState="Ask about a blocked task, a draft, or who should own the next review."
149
+ isThinking={thinking}
150
+ disabled={thinking}
151
+ onSend={ask}
152
+ onClose={() => setRailOpen(false)}
153
+ radius="none"
154
+ />
155
+ </aside>
156
+ ) : null}
157
+ </div>
158
+ );
159
+ }
@@ -0,0 +1,2 @@
1
+ export { AssistantWorkspacePattern } from "./AssistantWorkspacePattern";
2
+ export type { AssistantWorkspacePatternProps } from "./AssistantWorkspacePattern";
@@ -0,0 +1,102 @@
1
+ "use client";
2
+
3
+ import { DataTable } from "../../DataTable";
4
+ import type { DataTableColumn, DataTableRow } from "../../DataTable";
5
+ import { LineChart } from "../../LineChart";
6
+ import { PageHeader } from "../../PageHeader";
7
+ import type { PageHeaderProps } from "../../PageHeader";
8
+ import { Scoreboard } from "../../Scoreboard";
9
+ import { Section } from "../../Section";
10
+ import type { ChartDatum } from "../../shared/chartMath";
11
+
12
+ const SPRINT_METRICS = [
13
+ { label: "Weekly users", value: "1.44k", delta: "+6.2%", trend: "up" as const, hint: "vs last week", size: "lg" as const, badge: "Live", badgeTone: "success" as const },
14
+ { label: "Open tasks", value: "4", delta: "+1", trend: "up" as const, hint: "this sprint", size: "lg" as const, badge: "Sprint", badgeTone: "info" as const },
15
+ { label: "Blocked", value: "1", delta: "0", trend: "flat" as const, hint: "need owner", size: "lg" as const, badge: "At risk", badgeTone: "danger" as const },
16
+ { label: "Ready", value: "1", delta: "+1", trend: "up" as const, hint: "to ship", size: "lg" as const, badge: "Ship", badgeTone: "brand" as const },
17
+ ];
18
+
19
+ const WEEKLY_USERS: ChartDatum[] = [
20
+ { label: "Mon", value: 1280 },
21
+ { label: "Tue", value: 1410 },
22
+ { label: "Wed", value: 1320 },
23
+ { label: "Thu", value: 1480 },
24
+ { label: "Fri", value: 1360 },
25
+ { label: "Sat", value: 1440 },
26
+ { label: "Sun", value: 1390 },
27
+ ];
28
+
29
+ const TASK_COLUMNS: DataTableColumn[] = [
30
+ { key: "task", header: "Task", sortable: true },
31
+ { key: "owner", header: "Owner", sortable: true },
32
+ { key: "status", header: "Status", sortable: true },
33
+ ];
34
+
35
+ const TASK_ROWS: DataTableRow[] = [
36
+ {
37
+ id: "launch-brief",
38
+ task: { type: "file", label: "Launch brief" },
39
+ owner: { type: "avatar", label: "Maya Chen", name: "Maya Chen", src: "/faces/maya-chen.jpg" },
40
+ status: { type: "badge", label: "In review", tone: "warning" },
41
+ },
42
+ {
43
+ id: "qa-checklist",
44
+ task: { type: "file", label: "QA checklist" },
45
+ owner: { type: "avatar", label: "Unassigned", name: "Unassigned" },
46
+ status: { type: "badge", label: "Blocked", tone: "danger" },
47
+ },
48
+ {
49
+ id: "release-notes",
50
+ task: { type: "file", label: "Release notes" },
51
+ owner: { type: "avatar", label: "Jordan Lee", name: "Jordan Lee", src: "/faces/jordan-lee.jpg" },
52
+ status: { type: "badge", label: "Ready", tone: "success" },
53
+ },
54
+ {
55
+ id: "support-macros",
56
+ task: { type: "file", label: "Support macros" },
57
+ owner: { type: "avatar", label: "Alex Rivera", name: "Alex Rivera", src: "/faces/alex-rivera.jpg" },
58
+ status: { type: "badge", label: "In progress", tone: "info" },
59
+ },
60
+ ];
61
+
62
+ export function DashboardPattern({ breadcrumbs }: { breadcrumbs?: PageHeaderProps["breadcrumbs"] }) {
63
+ return (
64
+ <div className="layout-canvas layout-canvas--sticky-header">
65
+ <div className="layout-header">
66
+ <PageHeader
67
+ title="Overview"
68
+ subtitle="Workspace overview for the current team."
69
+ breadcrumbs={breadcrumbs}
70
+ />
71
+ </div>
72
+ <div className="layout-content">
73
+ <Section title="Sprint metrics">
74
+ <Scoreboard
75
+ className="layout-metrics layout-metrics--fixed-4"
76
+ aria-label="Sprint metrics"
77
+ items={SPRINT_METRICS}
78
+ />
79
+ </Section>
80
+ <Section title="Weekly users">
81
+ <LineChart data={WEEKLY_USERS} variant="line" showTable={false} />
82
+ </Section>
83
+ <Section title="Open tasks" description="4 items need attention">
84
+ <DataTable
85
+ caption="Sprint backlog"
86
+ selectable
87
+ toolbar
88
+ cellSize="sm"
89
+ searchPlaceholder="Search tasks..."
90
+ filters={[
91
+ { key: "status", label: "Status" },
92
+ { key: "owner", label: "Owner" },
93
+ ]}
94
+ columnSettings
95
+ columns={TASK_COLUMNS}
96
+ rows={TASK_ROWS}
97
+ />
98
+ </Section>
99
+ </div>
100
+ </div>
101
+ );
102
+ }
@@ -0,0 +1 @@
1
+ export { DashboardPattern } from "./DashboardPattern";
@@ -0,0 +1,6 @@
1
+ .pattern {
2
+ display: grid;
3
+ gap: var(--space-8);
4
+ width: 100%;
5
+ min-width: 0;
6
+ }
@@ -0,0 +1,125 @@
1
+ "use client";
2
+
3
+ import { useId, useState, type FormEvent } from "react";
4
+ import { Button } from "../../Button";
5
+ import { ButtonGroup } from "../../ButtonGroup";
6
+ import { Empty } from "../../Empty";
7
+ import { Field } from "../../Field";
8
+ import { Input } from "../../Input";
9
+ import { Modal } from "../../Modal";
10
+ import { PageHeader } from "../../PageHeader";
11
+ import type { PageHeaderProps } from "../../PageHeader";
12
+ import { Toast } from "../../Toast";
13
+
14
+ export interface EmptyFirstRunPatternProps {
15
+ breadcrumbs?: PageHeaderProps["breadcrumbs"];
16
+ onCreate?: (payload: { title: string }) => void;
17
+ }
18
+
19
+ export function EmptyFirstRunPattern({ breadcrumbs, onCreate }: EmptyFirstRunPatternProps) {
20
+ const uid = useId();
21
+ const titleId = `${uid}-title`;
22
+ const [open, setOpen] = useState(false);
23
+ const [title, setTitle] = useState("");
24
+ const [titleError, setTitleError] = useState<string | undefined>();
25
+ const [toastOpen, setToastOpen] = useState(false);
26
+ const [createdTitle, setCreatedTitle] = useState("");
27
+
28
+ function close() {
29
+ setOpen(false);
30
+ setTitleError(undefined);
31
+ }
32
+
33
+ function create() {
34
+ const nextTitle = title.trim();
35
+ if (!nextTitle) {
36
+ setTitleError("Enter a study name.");
37
+ return;
38
+ }
39
+
40
+ onCreate?.({ title: nextTitle });
41
+ setCreatedTitle(nextTitle);
42
+ setTitle("");
43
+ setTitleError(undefined);
44
+ setOpen(false);
45
+ setToastOpen(true);
46
+ }
47
+
48
+ function handleSubmit(event: FormEvent<HTMLFormElement>) {
49
+ event.preventDefault();
50
+ create();
51
+ }
52
+
53
+ return (
54
+ <div className="layout-canvas layout-canvas--sticky-header">
55
+ <div className="layout-header">
56
+ <PageHeader
57
+ title="User research"
58
+ subtitle="Interview notes and findings for Sprint 24."
59
+ breadcrumbs={breadcrumbs}
60
+ />
61
+ </div>
62
+ <div className="layout-content">
63
+ <Empty
64
+ title="No studies yet"
65
+ description="Add the first study so launch comments have evidence."
66
+ icon="User"
67
+ outlined
68
+ actions={
69
+ <Button variant="primary" size="md" onClick={() => setOpen(true)}>
70
+ New study
71
+ </Button>
72
+ }
73
+ />
74
+ </div>
75
+ <Modal
76
+ open={open}
77
+ title="New study"
78
+ description="Name the study. Notes can come later."
79
+ size="md"
80
+ onClose={close}
81
+ footer={
82
+ <ButtonGroup ariaLabel="Study actions">
83
+ <Button variant="secondary" size="md" onClick={close}>
84
+ Cancel
85
+ </Button>
86
+ <Button variant="primary" size="md" onClick={create}>
87
+ Create study
88
+ </Button>
89
+ </ButtonGroup>
90
+ }
91
+ >
92
+ <form onSubmit={handleSubmit}>
93
+ <Field
94
+ label="Title"
95
+ htmlFor={titleId}
96
+ hint="Something the team will recognize"
97
+ error={titleError}
98
+ >
99
+ <Input
100
+ id={titleId}
101
+ iconStart="Search"
102
+ placeholder="Launch interview round"
103
+ value={title}
104
+ onChange={(value) => {
105
+ setTitle(value);
106
+ if (titleError) setTitleError(undefined);
107
+ }}
108
+ />
109
+ </Field>
110
+ </form>
111
+ </Modal>
112
+ <Toast
113
+ open={toastOpen}
114
+ title="Study added"
115
+ description={
116
+ createdTitle ? `We'll keep “${createdTitle}” in User research.` : undefined
117
+ }
118
+ status="success"
119
+ duration={3000}
120
+ onClose={() => setToastOpen(false)}
121
+ onOpenChange={setToastOpen}
122
+ />
123
+ </div>
124
+ );
125
+ }
@@ -0,0 +1,2 @@
1
+ export { EmptyFirstRunPattern } from "./EmptyFirstRunPattern";
2
+ export type { EmptyFirstRunPatternProps } from "./EmptyFirstRunPattern";
@@ -0,0 +1,40 @@
1
+ .detail {
2
+ display: grid;
3
+ gap: var(--space-stack-lg);
4
+ }
5
+
6
+ .meta {
7
+ display: flex;
8
+ align-items: center;
9
+ gap: var(--space-inline-md);
10
+ min-width: 0;
11
+ }
12
+
13
+ .copy {
14
+ min-width: 0;
15
+ flex: 1;
16
+ }
17
+
18
+ .label {
19
+ margin: 0;
20
+ font-family: var(--font-sans);
21
+ font-size: var(--type-size-caption);
22
+ font-weight: var(--type-weight-caption);
23
+ color: var(--text-secondary);
24
+ }
25
+
26
+ .value {
27
+ margin: 0;
28
+ font-family: var(--font-sans);
29
+ font-size: var(--type-size-body-sm);
30
+ font-weight: var(--type-weight-label);
31
+ color: var(--text-primary);
32
+ }
33
+
34
+ .body {
35
+ margin: 0;
36
+ font-family: var(--font-sans);
37
+ font-size: var(--type-size-body);
38
+ line-height: var(--type-line-body);
39
+ color: var(--text-secondary);
40
+ }
@@ -0,0 +1,192 @@
1
+ "use client";
2
+
3
+ import { useEffect, useState } from "react";
4
+ import { Avatar } from "../../Avatar";
5
+ import { Badge } from "../../Badge";
6
+ import { Button } from "../../Button";
7
+ import { Cell } from "../../Cell";
8
+ import { Empty } from "../../Empty";
9
+ import { PageHeader } from "../../PageHeader";
10
+ import type { PageHeaderProps } from "../../PageHeader";
11
+ import { Scoreboard } from "../../Scoreboard";
12
+ import { Section } from "../../Section";
13
+ import { Table } from "../../Table";
14
+ import { Tabs } from "../../Tabs";
15
+ import { Toast } from "../../Toast";
16
+ import { filterMessages, INBOX, type InboxMessage } from "./inbox-data";
17
+ import { InboxReplyDrawer } from "./InboxReplyDrawer";
18
+ import styles from "./InboxPattern.module.css";
19
+
20
+ const COLUMNS = [
21
+ { key: "from", header: "From", emphasis: true },
22
+ { key: "subject", header: "Subject" },
23
+ { key: "kind", header: "Type" },
24
+ { key: "when", header: "When" },
25
+ { key: "open", header: "" },
26
+ ];
27
+
28
+ function InboxTable({
29
+ messages,
30
+ onOpen,
31
+ }: {
32
+ messages: InboxMessage[];
33
+ onOpen: (id: string) => void;
34
+ }) {
35
+ return (
36
+ <Table
37
+ caption="Inbox"
38
+ size="sm"
39
+ emptyLabel="No messages in this filter."
40
+ columns={COLUMNS}
41
+ rows={messages.map((item) => ({
42
+ from: <Cell type="avatar" size="sm" name={item.from} src={item.fromSrc} label={item.from} />,
43
+ subject: item.subject,
44
+ kind: <Badge tone={item.kindTone} size="sm">{item.kind}</Badge>,
45
+ when: item.when,
46
+ open: (
47
+ <Button variant="tertiary" size="sm" onClick={() => onOpen(item.id)}>
48
+ Open
49
+ </Button>
50
+ ),
51
+ }))}
52
+ />
53
+ );
54
+ }
55
+
56
+ export interface InboxPatternProps {
57
+ breadcrumbs?: PageHeaderProps["breadcrumbs"];
58
+ }
59
+
60
+ export function InboxPattern({ breadcrumbs }: InboxPatternProps) {
61
+ const [messages, setMessages] = useState(INBOX);
62
+ const [tab, setTab] = useState("all");
63
+ const [selectedId, setSelectedId] = useState<string | null>(INBOX[0]?.id ?? null);
64
+ const [drawerOpen, setDrawerOpen] = useState(false);
65
+ const [toastOpen, setToastOpen] = useState(false);
66
+
67
+ const selected = messages.find((item) => item.id === selectedId) ?? null;
68
+ const unread = messages.filter((item) => item.unread).length;
69
+
70
+ useEffect(() => {
71
+ const next = filterMessages(messages, tab);
72
+ if (selectedId && next.some((item) => item.id === selectedId)) return;
73
+ setSelectedId(next[0]?.id ?? null);
74
+ setDrawerOpen(false);
75
+ }, [selectedId, tab, messages]);
76
+
77
+ function archive(id: string) {
78
+ setMessages((current) => current.filter((item) => item.id !== id));
79
+ setDrawerOpen(false);
80
+ }
81
+
82
+ function openMessage(id: string) {
83
+ setSelectedId(id);
84
+ setDrawerOpen(true);
85
+ }
86
+
87
+ function sendReply() {
88
+ if (!selected) return;
89
+ setMessages((current) =>
90
+ current.map((item) => (item.id === selected.id ? { ...item, unread: false } : item)),
91
+ );
92
+ setToastOpen(true);
93
+ }
94
+
95
+ return (
96
+ <div className="layout-canvas layout-canvas--sticky-header">
97
+ <div className="layout-header">
98
+ <PageHeader
99
+ title="Inbox"
100
+ subtitle="Replies, mentions, and requests waiting on you."
101
+ breadcrumbs={breadcrumbs}
102
+ />
103
+ </div>
104
+ <div className="layout-content">
105
+ <Section title="At a glance">
106
+ <Scoreboard
107
+ className="layout-metrics layout-metrics--fixed-4"
108
+ aria-label="Inbox this week"
109
+ items={[
110
+ { label: "Unread", value: String(unread), delta: `+${unread}`, trend: "up" as const, hint: "need a look", size: "lg" as const, badge: "Live", badgeTone: "danger" as const },
111
+ { label: "Mentions", value: String(messages.filter((item) => item.kind === "Mention").length), delta: "+1", trend: "up" as const, hint: "this sprint", size: "lg" as const, badge: "You", badgeTone: "brand" as const },
112
+ { label: "Requests", value: String(messages.filter((item) => item.kind === "Request").length), delta: "+2", trend: "up" as const, hint: "this sprint", size: "lg" as const, badge: "Review", badgeTone: "warning" as const },
113
+ { label: "Open", value: String(messages.length), delta: "0", trend: "flat" as const, hint: "in inbox", size: "lg" as const, badge: "Sprint", badgeTone: "info" as const },
114
+ ]}
115
+ />
116
+ </Section>
117
+ <Section title="Messages" description={`${unread} unread`}>
118
+ <Tabs
119
+ ariaLabel="Inbox type"
120
+ variant="line"
121
+ size="md"
122
+ value={tab}
123
+ onChange={setTab}
124
+ items={[
125
+ { id: "all", label: "All", content: <InboxTable messages={filterMessages(messages, "all")} onOpen={openMessage} /> },
126
+ { id: "unread", label: "Unread", content: <InboxTable messages={filterMessages(messages, "unread")} onOpen={openMessage} /> },
127
+ { id: "mentions", label: "Mentions", content: <InboxTable messages={filterMessages(messages, "mentions")} onOpen={openMessage} /> },
128
+ { id: "requests", label: "Requests", content: <InboxTable messages={filterMessages(messages, "requests")} onOpen={openMessage} /> },
129
+ ]}
130
+ />
131
+ </Section>
132
+ <Section
133
+ title={selected?.subject ?? "Message"}
134
+ description={selected ? `${selected.from} · ${selected.when}` : "Select a row"}
135
+ actions={
136
+ selected ? (
137
+ <>
138
+ <Button variant="secondary" size="sm" onClick={() => archive(selected.id)}>
139
+ Archive
140
+ </Button>
141
+ <Button
142
+ variant={drawerOpen ? "secondary" : "primary"}
143
+ size="sm"
144
+ onClick={() => openMessage(selected.id)}
145
+ >
146
+ Reply
147
+ </Button>
148
+ </>
149
+ ) : undefined
150
+ }
151
+ >
152
+ {selected ? (
153
+ <div className={styles.detail}>
154
+ <div className={styles.meta}>
155
+ <Avatar name={selected.from} src={selected.fromSrc} size="md" />
156
+ <div className={styles.copy}>
157
+ <p className={styles.label}>From</p>
158
+ <p className={styles.value}>{selected.from}</p>
159
+ </div>
160
+ <Badge tone={selected.kindTone}>{selected.kind}</Badge>
161
+ </div>
162
+ <p className={styles.body}>{selected.body}</p>
163
+ </div>
164
+ ) : (
165
+ <Empty
166
+ title="No message selected"
167
+ description="Open a row to read it here."
168
+ icon="Mail"
169
+ outlined
170
+ />
171
+ )}
172
+ </Section>
173
+ </div>
174
+ <InboxReplyDrawer
175
+ key={selected?.id ?? "none"}
176
+ message={selected}
177
+ open={drawerOpen}
178
+ onClose={() => setDrawerOpen(false)}
179
+ onSend={sendReply}
180
+ />
181
+ <Toast
182
+ open={toastOpen}
183
+ title="Reply sent"
184
+ description="It will show up in the thread."
185
+ status="success"
186
+ duration={3000}
187
+ onClose={() => setToastOpen(false)}
188
+ onOpenChange={setToastOpen}
189
+ />
190
+ </div>
191
+ );
192
+ }