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,97 @@
1
+ "use client";
2
+
3
+ import { useId, useState, type FormEvent } from "react";
4
+ import { Button } from "../../Button";
5
+ import { Drawer } from "../../Drawer";
6
+ import { Field } from "../../Field";
7
+ import { FieldSet } from "../../FieldSet";
8
+ import { Input } from "../../Input";
9
+ import { Textarea } from "../../Textarea";
10
+ import type { InboxMessage } from "./inbox-data";
11
+
12
+ export function InboxReplyDrawer({
13
+ message,
14
+ open,
15
+ onClose,
16
+ onSend,
17
+ }: {
18
+ message: InboxMessage | null;
19
+ open: boolean;
20
+ onClose: () => void;
21
+ onSend: () => void;
22
+ }) {
23
+ const baseId = useId();
24
+ const toId = `${baseId}-to`;
25
+ const subjectId = `${baseId}-subject`;
26
+ const replyId = `${baseId}-reply`;
27
+ const [error, setError] = useState<string | undefined>();
28
+
29
+ function close() {
30
+ setError(undefined);
31
+ onClose();
32
+ }
33
+
34
+ function send() {
35
+ const reply = (document.getElementById(replyId) as HTMLTextAreaElement | null)?.value.trim() ?? "";
36
+ if (!reply) {
37
+ setError("Write a reply before sending.");
38
+ return;
39
+ }
40
+ onSend();
41
+ setError(undefined);
42
+ onClose();
43
+ }
44
+
45
+ function handleSubmit(event: FormEvent<HTMLFormElement>) {
46
+ event.preventDefault();
47
+ send();
48
+ }
49
+
50
+ return (
51
+ <Drawer
52
+ open={open && Boolean(message)}
53
+ title={message ? `Reply to ${message.from}` : "Reply"}
54
+ description={message?.subject}
55
+ onClose={close}
56
+ footer={
57
+ message ? (
58
+ <>
59
+ <Button variant="primary" block onClick={send}>
60
+ Send reply
61
+ </Button>
62
+ <Button variant="secondary" block onClick={close}>
63
+ Cancel
64
+ </Button>
65
+ </>
66
+ ) : null
67
+ }
68
+ >
69
+ {message ? (
70
+ <form onSubmit={handleSubmit}>
71
+ <FieldSet key={message.id} legend="Reply" description="This goes back to the thread.">
72
+ <Field label="To" htmlFor={toId}>
73
+ <Input id={toId} name="to" defaultValue={message.from} />
74
+ </Field>
75
+ <Field label="Subject" htmlFor={subjectId}>
76
+ <Input id={subjectId} name="subject" defaultValue={`Re: ${message.subject}`} />
77
+ </Field>
78
+ <Field
79
+ label="Message"
80
+ htmlFor={replyId}
81
+ hint="Keep it short. They already have the thread."
82
+ error={error}
83
+ >
84
+ <Textarea
85
+ id={replyId}
86
+ name="reply"
87
+ rows={6}
88
+ placeholder="Write a reply..."
89
+ error={Boolean(error)}
90
+ />
91
+ </Field>
92
+ </FieldSet>
93
+ </form>
94
+ ) : null}
95
+ </Drawer>
96
+ );
97
+ }
@@ -0,0 +1,101 @@
1
+ import type { BadgeTone } from "../../Badge";
2
+
3
+ export type InboxKind = "Comment" | "Mention" | "Request" | "Status" | "Alert";
4
+
5
+ export interface InboxMessage {
6
+ id: string;
7
+ from: string;
8
+ fromSrc?: string;
9
+ subject: string;
10
+ body: string;
11
+ kind: InboxKind;
12
+ kindTone: BadgeTone;
13
+ when: string;
14
+ unread: boolean;
15
+ }
16
+
17
+ export const INBOX: InboxMessage[] = [
18
+ {
19
+ id: "maya-comment",
20
+ from: "Maya Chen",
21
+ fromSrc: "/faces/maya-chen.jpg",
22
+ subject: "Comments on Launch brief",
23
+ body: "Two notes on positioning. Close them before the freeze so copy can lock.",
24
+ kind: "Comment",
25
+ kindTone: "info",
26
+ when: "2h ago",
27
+ unread: true,
28
+ },
29
+ {
30
+ id: "qa-alert",
31
+ from: "Unassigned",
32
+ subject: "QA checklist is still blocked",
33
+ body: "No owner for 2 days. Assign someone before Thursday's review.",
34
+ kind: "Alert",
35
+ kindTone: "danger",
36
+ when: "4h ago",
37
+ unread: true,
38
+ },
39
+ {
40
+ id: "alex-reply",
41
+ from: "Alex Rivera",
42
+ fromSrc: "/faces/alex-rivera.jpg",
43
+ subject: "Replied on Support macros",
44
+ body: "Refund and delay macros are drafted. Escalation paths still need a pass.",
45
+ kind: "Comment",
46
+ kindTone: "info",
47
+ when: "5h ago",
48
+ unread: true,
49
+ },
50
+ {
51
+ id: "maya-mention",
52
+ from: "Maya Chen",
53
+ fromSrc: "/faces/maya-chen.jpg",
54
+ subject: "Mentioned you in Launch brief",
55
+ body: "Can you confirm the hero line before legal looks at the brief?",
56
+ kind: "Mention",
57
+ kindTone: "brand",
58
+ when: "Yesterday",
59
+ unread: true,
60
+ },
61
+ {
62
+ id: "jordan-status",
63
+ from: "Jordan Lee",
64
+ fromSrc: "/faces/jordan-lee.jpg",
65
+ subject: "Release notes moved to Ready",
66
+ body: "Changelog is drafted. Confirm the known-issues list before we tag.",
67
+ kind: "Status",
68
+ kindTone: "success",
69
+ when: "Yesterday",
70
+ unread: true,
71
+ },
72
+ {
73
+ id: "iris-request",
74
+ from: "Iris Okafor",
75
+ fromSrc: "/faces/iris-okafor.jpg",
76
+ subject: "Review User research",
77
+ body: "Five interviews are in. Need a read on the onboarding friction before Friday.",
78
+ kind: "Request",
79
+ kindTone: "warning",
80
+ when: "Mon",
81
+ unread: true,
82
+ },
83
+ {
84
+ id: "noah-request",
85
+ from: "Noah Williams",
86
+ fromSrc: "/faces/noah-williams.jpg",
87
+ subject: "Legal sign-off on QA",
88
+ body: "The last two device passes are still open. Legal will not sign until they close.",
89
+ kind: "Request",
90
+ kindTone: "warning",
91
+ when: "Mon",
92
+ unread: true,
93
+ },
94
+ ];
95
+
96
+ export function filterMessages(messages: InboxMessage[], tab: string): InboxMessage[] {
97
+ if (tab === "unread") return messages.filter((item) => item.unread);
98
+ if (tab === "mentions") return messages.filter((item) => item.kind === "Mention");
99
+ if (tab === "requests") return messages.filter((item) => item.kind === "Request");
100
+ return messages;
101
+ }
@@ -0,0 +1,2 @@
1
+ export { InboxPattern } from "./InboxPattern";
2
+ export type { InboxPatternProps } from "./InboxPattern";
@@ -0,0 +1,148 @@
1
+ "use client";
2
+
3
+ import { useId, useState, type FormEvent } from "react";
4
+ import { AvatarGroup } from "../../AvatarGroup";
5
+ import { Button } from "../../Button";
6
+ import { ButtonGroup } from "../../ButtonGroup";
7
+ import { Empty } from "../../Empty";
8
+ import { Field } from "../../Field";
9
+ import { FieldSet } from "../../FieldSet";
10
+ import { Input } from "../../Input";
11
+ import { Modal } from "../../Modal";
12
+ import { PageHeader } from "../../PageHeader";
13
+ import type { PageHeaderProps } from "../../PageHeader";
14
+ import { RadioGroup } from "../../RadioGroup";
15
+ import { Toast } from "../../Toast";
16
+
17
+ const TEAM = [
18
+ { name: "Maya Chen", src: "/faces/maya-chen.jpg" },
19
+ { name: "Noah Williams", src: "/faces/noah-williams.jpg" },
20
+ { name: "Iris Okafor", src: "/faces/iris-okafor.jpg" },
21
+ ];
22
+
23
+ const ROLE_OPTIONS = [
24
+ { value: "admin", label: "Admin" },
25
+ { value: "member", label: "Member" },
26
+ { value: "viewer", label: "Viewer" },
27
+ ];
28
+
29
+ export interface InviteMembersPatternProps {
30
+ breadcrumbs?: PageHeaderProps["breadcrumbs"];
31
+ onInvite?: (payload: { email: string; role: string }) => void;
32
+ }
33
+
34
+ export function InviteMembersPattern({ breadcrumbs, onInvite }: InviteMembersPatternProps) {
35
+ const uid = useId();
36
+ const [open, setOpen] = useState(false);
37
+ const [email, setEmail] = useState("");
38
+ const [role, setRole] = useState("member");
39
+ const [emailError, setEmailError] = useState<string | undefined>();
40
+ const [toastOpen, setToastOpen] = useState(false);
41
+ const [sentTo, setSentTo] = useState("");
42
+
43
+ const emailId = `${uid}-email`;
44
+ const roleName = `${uid}-role`;
45
+
46
+ function close() {
47
+ setOpen(false);
48
+ setEmailError(undefined);
49
+ }
50
+
51
+ function send() {
52
+ const nextEmail = email.trim();
53
+ if (!nextEmail || !nextEmail.includes("@")) {
54
+ setEmailError("Enter a work email.");
55
+ return;
56
+ }
57
+
58
+ onInvite?.({ email: nextEmail, role });
59
+ setSentTo(nextEmail);
60
+ setEmail("");
61
+ setRole("member");
62
+ setEmailError(undefined);
63
+ setOpen(false);
64
+ setToastOpen(true);
65
+ }
66
+
67
+ function handleSubmit(event: FormEvent<HTMLFormElement>) {
68
+ event.preventDefault();
69
+ send();
70
+ }
71
+
72
+ return (
73
+ <div className="layout-canvas layout-canvas--sticky-header">
74
+ <div className="layout-header">
75
+ <PageHeader
76
+ title="Invite members"
77
+ subtitle="Add people to this workspace so review comments have owners."
78
+ breadcrumbs={breadcrumbs}
79
+ />
80
+ </div>
81
+ <div className="layout-content">
82
+ <Empty
83
+ title="No pending invites"
84
+ description="Maya, Noah, and Iris are in this workspace. Three seats are open for design and QA."
85
+ media={<AvatarGroup ariaLabel="Current members" items={TEAM} max={3} />}
86
+ outlined
87
+ actions={
88
+ <Button variant="primary" size="md" onClick={() => setOpen(true)}>
89
+ Invite members
90
+ </Button>
91
+ }
92
+ />
93
+ </div>
94
+ <Modal
95
+ open={open}
96
+ title="Invite members"
97
+ description="Send an email invite. They join with the role you pick."
98
+ size="md"
99
+ onClose={close}
100
+ footer={
101
+ <ButtonGroup ariaLabel="Invite actions">
102
+ <Button variant="secondary" size="md" onClick={close}>
103
+ Cancel
104
+ </Button>
105
+ <Button variant="primary" size="md" onClick={send}>
106
+ Send invite
107
+ </Button>
108
+ </ButtonGroup>
109
+ }
110
+ >
111
+ <form onSubmit={handleSubmit}>
112
+ <FieldSet legend="New member" description="They get access to Sprint 24 projects.">
113
+ <Field label="Email" htmlFor={emailId} hint="Work email they already use" error={emailError}>
114
+ <Input
115
+ id={emailId}
116
+ type="email"
117
+ iconStart="Mail"
118
+ placeholder="name@company.com"
119
+ value={email}
120
+ onChange={(value) => {
121
+ setEmail(value);
122
+ if (emailError) setEmailError(undefined);
123
+ }}
124
+ />
125
+ </Field>
126
+ <RadioGroup
127
+ name={roleName}
128
+ legend="Role"
129
+ orientation="horizontal"
130
+ options={ROLE_OPTIONS}
131
+ value={role}
132
+ onChange={setRole}
133
+ />
134
+ </FieldSet>
135
+ </form>
136
+ </Modal>
137
+ <Toast
138
+ open={toastOpen}
139
+ title="Invite sent"
140
+ description={sentTo ? `We'll email ${sentTo} a link to join this workspace.` : undefined}
141
+ status="success"
142
+ duration={3000}
143
+ onClose={() => setToastOpen(false)}
144
+ onOpenChange={setToastOpen}
145
+ />
146
+ </div>
147
+ );
148
+ }
@@ -0,0 +1,2 @@
1
+ export { InviteMembersPattern } from "./InviteMembersPattern";
2
+ export type { InviteMembersPatternProps } from "./InviteMembersPattern";
@@ -0,0 +1,34 @@
1
+ .shell {
2
+ display: grid;
3
+ grid-template-columns: max-content minmax(0, 1fr);
4
+ gap: var(--layout-gutter-md);
5
+ align-items: start;
6
+ min-width: 0;
7
+ }
8
+
9
+ .main {
10
+ display: grid;
11
+ gap: var(--space-stack-md);
12
+ min-width: 0;
13
+ overflow-x: auto;
14
+ }
15
+
16
+ .main :global(section) {
17
+ margin-bottom: 0;
18
+ }
19
+
20
+ .detail {
21
+ display: flex;
22
+ flex-direction: column;
23
+ align-items: flex-start;
24
+ gap: var(--space-3);
25
+ max-width: 36rem;
26
+ }
27
+
28
+ .body {
29
+ margin: 0;
30
+ font-family: var(--font-sans);
31
+ font-size: var(--type-size-body);
32
+ line-height: var(--type-line-body);
33
+ color: var(--text-primary);
34
+ }
@@ -0,0 +1,145 @@
1
+ "use client";
2
+
3
+ import { useEffect, useMemo, useState } from "react";
4
+ import { AppNav } from "../../AppNav";
5
+ import { Badge } from "../../Badge";
6
+ import type { BadgeTone } from "../../Badge";
7
+ import { PageHeader } from "../../PageHeader";
8
+ import type { PageHeaderProps } from "../../PageHeader";
9
+ import { Section } from "../../Section";
10
+ import { Table } from "../../Table";
11
+ import styles from "./ListDetailPattern.module.css";
12
+
13
+ export interface ListDetailItem {
14
+ id: string;
15
+ name: string;
16
+ owner: string;
17
+ status: string;
18
+ statusTone: BadgeTone;
19
+ updated: string;
20
+ body: string;
21
+ }
22
+
23
+ export interface ListDetailPatternProps {
24
+ breadcrumbs?: PageHeaderProps["breadcrumbs"];
25
+ selectedId?: string;
26
+ }
27
+
28
+ const PROJECTS: ListDetailItem[] = [
29
+ {
30
+ id: "launch-brief",
31
+ name: "Launch brief",
32
+ owner: "Maya Chen",
33
+ status: "In review",
34
+ statusTone: "warning",
35
+ updated: "2h ago",
36
+ body: "Two notes on positioning. Close them before the freeze so copy can lock.",
37
+ },
38
+ {
39
+ id: "qa-checklist",
40
+ name: "QA checklist",
41
+ owner: "Unassigned",
42
+ status: "Blocked",
43
+ statusTone: "danger",
44
+ updated: "4h ago",
45
+ body: "No owner for 2 days. Assign someone before Thursday's review.",
46
+ },
47
+ {
48
+ id: "release-notes",
49
+ name: "Release notes",
50
+ owner: "Jordan Lee",
51
+ status: "Ready",
52
+ statusTone: "success",
53
+ updated: "Yesterday",
54
+ body: "Changelog is drafted. Confirm the known-issues list before we tag.",
55
+ },
56
+ {
57
+ id: "support-macros",
58
+ name: "Support macros",
59
+ owner: "Alex Rivera",
60
+ status: "In progress",
61
+ statusTone: "info",
62
+ updated: "5h ago",
63
+ body: "Refund and delay macros are drafted. Escalation paths still need a pass.",
64
+ },
65
+ ];
66
+
67
+ const COLUMNS = [
68
+ { key: "name", header: "Project", emphasis: true },
69
+ { key: "owner", header: "Owner" },
70
+ { key: "status", header: "Status" },
71
+ { key: "updated", header: "Updated" },
72
+ ];
73
+
74
+ function projectById(id: string | undefined): ListDetailItem {
75
+ return PROJECTS.find((item) => item.id === id) ?? PROJECTS[0];
76
+ }
77
+
78
+ export function ListDetailPattern({ breadcrumbs, selectedId }: ListDetailPatternProps) {
79
+ const [activeId, setActiveId] = useState(projectById(selectedId).id);
80
+
81
+ useEffect(() => {
82
+ if (selectedId) setActiveId(projectById(selectedId).id);
83
+ }, [selectedId]);
84
+
85
+ useEffect(() => {
86
+ const apply = () => {
87
+ const hash = window.location.hash.replace(/^#/, "");
88
+ if (PROJECTS.some((item) => item.id === hash)) setActiveId(hash);
89
+ };
90
+ apply();
91
+ window.addEventListener("hashchange", apply);
92
+ return () => window.removeEventListener("hashchange", apply);
93
+ }, []);
94
+
95
+ const selected = projectById(activeId);
96
+
97
+ const navItems = useMemo(
98
+ () =>
99
+ PROJECTS.map((item) => ({
100
+ href: `#${item.id}`,
101
+ label: item.name,
102
+ active: item.id === selected.id,
103
+ })),
104
+ [selected.id],
105
+ );
106
+
107
+ const rows = PROJECTS.map((item) => ({
108
+ name: item.name,
109
+ owner: item.owner,
110
+ status: (
111
+ <Badge tone={item.statusTone} size="sm">
112
+ {item.status}
113
+ </Badge>
114
+ ),
115
+ updated: item.updated,
116
+ }));
117
+
118
+ return (
119
+ <div className="layout-canvas layout-canvas--sticky-header">
120
+ <div className="layout-header">
121
+ <PageHeader
122
+ title="Projects"
123
+ subtitle="Sprint 24 files and their current status."
124
+ breadcrumbs={breadcrumbs}
125
+ />
126
+ </div>
127
+ <div className="layout-content">
128
+ <div className={styles.shell}>
129
+ <AppNav title="Files" items={navItems} />
130
+ <div className={styles.main}>
131
+ <Section title="Projects" description="Select a file in the list to view details">
132
+ <Table columns={COLUMNS} rows={rows} caption="Sprint 24 projects" />
133
+ </Section>
134
+ <Section title={selected.name} description={`${selected.owner} · ${selected.updated}`}>
135
+ <div className={styles.detail}>
136
+ <Badge tone={selected.statusTone}>{selected.status}</Badge>
137
+ <p className={styles.body}>{selected.body}</p>
138
+ </div>
139
+ </Section>
140
+ </div>
141
+ </div>
142
+ </div>
143
+ </div>
144
+ );
145
+ }
@@ -0,0 +1,2 @@
1
+ export { ListDetailPattern } from "./ListDetailPattern";
2
+ export type { ListDetailItem, ListDetailPatternProps } from "./ListDetailPattern";
@@ -0,0 +1,12 @@
1
+ .form {
2
+ display: flex;
3
+ flex-direction: column;
4
+ gap: var(--space-4);
5
+ max-width: 28rem;
6
+ }
7
+
8
+ .actions {
9
+ display: flex;
10
+ flex-wrap: wrap;
11
+ gap: var(--space-3);
12
+ }
@@ -0,0 +1,89 @@
1
+ "use client";
2
+
3
+ import { useId, useState, type FormEvent } from "react";
4
+ import { Button } from "../../Button";
5
+ import { Checkbox } from "../../Checkbox";
6
+ import { Field } from "../../Field";
7
+ import { Input } from "../../Input";
8
+ import { PageHeader } from "../../PageHeader";
9
+ import type { PageHeaderProps } from "../../PageHeader";
10
+ import { Section } from "../../Section";
11
+ import { Select } from "../../Select";
12
+ import { Toast } from "../../Toast";
13
+ import formStyles from "./SettingsFormPattern.module.css";
14
+
15
+ export interface SettingsFormPatternProps {
16
+ breadcrumbs?: PageHeaderProps["breadcrumbs"];
17
+ onCancel?: () => void;
18
+ onSave?: () => void;
19
+ }
20
+
21
+ export function SettingsFormPattern({ breadcrumbs, onCancel, onSave }: SettingsFormPatternProps) {
22
+ const uid = useId();
23
+ const [toastOpen, setToastOpen] = useState(false);
24
+
25
+ function handleSubmit(event: FormEvent<HTMLFormElement>) {
26
+ event.preventDefault();
27
+ onSave?.();
28
+ setToastOpen(true);
29
+ }
30
+
31
+ return (
32
+ <div className="layout-canvas layout-canvas--sticky-header">
33
+ <div className="layout-header">
34
+ <PageHeader
35
+ title="Settings"
36
+ subtitle="Manage workspace profile and notification preferences."
37
+ breadcrumbs={breadcrumbs}
38
+ eyebrow={breadcrumbs ? undefined : "Account"}
39
+ />
40
+ </div>
41
+ <form className="layout-content" onSubmit={handleSubmit}>
42
+ <Section title="Profile" description="Basic information visible to collaborators">
43
+ <div className={formStyles.form}>
44
+ <Field label="Display name" htmlFor={`${uid}-display-name`} hint="Shown on shared projects">
45
+ <Input id={`${uid}-display-name`} defaultValue="Maya Chen" />
46
+ </Field>
47
+ <Field label="Email" htmlFor={`${uid}-email`}>
48
+ <Input id={`${uid}-email`} type="email" defaultValue="maya@agentix.dev" />
49
+ </Field>
50
+ <Field label="Timezone" htmlFor={`${uid}-timezone`}>
51
+ <Select
52
+ id={`${uid}-timezone`}
53
+ options={[
54
+ { value: "utc", label: "UTC" },
55
+ { value: "cet", label: "Central European Time" },
56
+ { value: "est", label: "Eastern Time" },
57
+ ]}
58
+ defaultValue="cet"
59
+ />
60
+ </Field>
61
+ </div>
62
+ </Section>
63
+ <Section title="Notifications">
64
+ <div className={formStyles.form}>
65
+ <Checkbox id={`${uid}-email-updates`} label="Email me weekly summaries" defaultChecked />
66
+ <Checkbox id={`${uid}-product-news`} label="Product news and tips" />
67
+ </div>
68
+ </Section>
69
+ <div className={formStyles.actions}>
70
+ <Button variant="primary" size="md" type="submit">
71
+ Save changes
72
+ </Button>
73
+ <Button variant="secondary" size="md" type="button" onClick={onCancel}>
74
+ Cancel
75
+ </Button>
76
+ </div>
77
+ <Toast
78
+ open={toastOpen}
79
+ title="Settings saved"
80
+ description="Workspace profile and preferences are up to date."
81
+ status="success"
82
+ duration={3000}
83
+ onClose={() => setToastOpen(false)}
84
+ onOpenChange={setToastOpen}
85
+ />
86
+ </form>
87
+ </div>
88
+ );
89
+ }
@@ -0,0 +1,3 @@
1
+ export { SettingsFormPattern } from "./SettingsFormPattern";
2
+ export type { SettingsFormPatternProps } from "./SettingsFormPattern";
3
+