@heyramzi/ui 2.0.1 → 2.2.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 (341) hide show
  1. package/package.json +48 -24
  2. package/scripts/sync-shadcn.mjs +3 -4
  3. package/src/agents/agent-avatar.svelte +604 -575
  4. package/src/agents/agent-cast.svelte +179 -183
  5. package/src/agents/demo.svelte +125 -113
  6. package/src/agents/helpers.ts +23 -17
  7. package/src/agents/index.ts +4 -4
  8. package/src/agents/page-state.ts +6 -6
  9. package/src/agents/types.ts +6 -6
  10. package/src/ai/ai-button/AiButton.svelte +4 -12
  11. package/src/ai/generation-progress/GenerationProgress.svelte +10 -3
  12. package/src/ai/prompt-input/PromptInputTextarea.svelte +1 -2
  13. package/src/ai/response/Response.css +2 -3
  14. package/src/animations/avatar-group-hover.css +2 -16
  15. package/src/animations/card-tilt.css +3 -6
  16. package/src/animations/digit-pop-in.css +2 -15
  17. package/src/animations/dropdown.css +4 -17
  18. package/src/animations/input-clear-dissolve.css +5 -18
  19. package/src/animations/input-shake.css +9 -41
  20. package/src/animations/learn-more-hover.css +17 -9
  21. package/src/animations/like-button.css +2 -4
  22. package/src/animations/page-side-by-side.css +2 -10
  23. package/src/animations/plus-menu-morph.css +2 -5
  24. package/src/animations/shimmer-text.css +5 -18
  25. package/src/animations/spinning-counter.css +2 -6
  26. package/src/animations/success-check.css +2 -15
  27. package/src/animations/thinking-states.css +2 -7
  28. package/src/brand/brand.test.ts +21 -5
  29. package/src/brand/index.ts +4 -10
  30. package/src/canvas/README.md +9 -12
  31. package/src/canvas/card/card-frame.svelte +43 -39
  32. package/src/canvas/card/resize-handles.svelte +89 -80
  33. package/src/canvas/chrome/chrome-zoom.svelte +101 -100
  34. package/src/canvas/chrome/lock-badge.svelte +8 -8
  35. package/src/canvas/chrome/side-handles.svelte +24 -19
  36. package/src/canvas/chrome/size-chip.svelte +30 -30
  37. package/src/canvas/chrome/snap-guides.svelte +20 -20
  38. package/src/canvas/components/icons/ToolIcon.svelte +8 -8
  39. package/src/canvas/components/shared/svg/PreviewSvg.svelte +19 -19
  40. package/src/canvas/components/shared/svg/ShapeOutline.svelte +71 -48
  41. package/src/canvas/components/shared/svg/StrokeNode.svelte +21 -27
  42. package/src/canvas/components/shared/svg/TextRule.svelte +25 -17
  43. package/src/canvas/edges/bend-handle.svelte +46 -46
  44. package/src/canvas/edges/edge-gradient.svelte +10 -10
  45. package/src/canvas/edges/gradient-edge.svelte +45 -29
  46. package/src/canvas/editor/lock.test.ts +6 -1
  47. package/src/canvas/editor/style.ts +7 -1
  48. package/src/canvas/headless/svg-figure.test.ts +5 -1
  49. package/src/canvas/lod/lod-switch.svelte +111 -106
  50. package/src/canvas/pen/PenField.svelte +87 -81
  51. package/src/canvas/pen/PenOverlay.svelte +127 -127
  52. package/src/canvas/pen/ShapeNode.svelte +31 -32
  53. package/src/canvas/pen/TextNode.svelte +54 -53
  54. package/src/canvas/pen/host-field.test.svelte +7 -7
  55. package/src/canvas/pen/shapes.ts +7 -1
  56. package/src/canvas/screen/GlyphIcon.svelte +22 -17
  57. package/src/canvas/screen/PartView.svelte +138 -72
  58. package/src/canvas/screen/ScreenBody.svelte +81 -60
  59. package/src/canvas/screen/ScreenCard.svelte +20 -20
  60. package/src/canvas/ui/CanvasToolbar.svelte +173 -85
  61. package/src/canvas/ui/FrameLayer.svelte +59 -59
  62. package/src/canvas/ui/PenLayer.svelte +39 -30
  63. package/src/canvas/ui/StylePanel.svelte +119 -102
  64. package/src/canvas/ui/canvas-grid.svelte +137 -129
  65. package/src/charts/animated-value.svelte +1 -1
  66. package/src/charts/area-chart.css +2 -5
  67. package/src/charts/area-chart.svelte +1 -1
  68. package/src/charts/bar-chart.css +2 -3
  69. package/src/charts/bar-chart.svelte +1 -1
  70. package/src/charts/charts.css +5 -17
  71. package/src/charts/crosshair.svelte +1 -1
  72. package/src/charts/dashboard/dashboard-empty.svelte +25 -25
  73. package/src/charts/dashboard/dashboard-section.svelte +24 -24
  74. package/src/charts/dashboard/data-panel.svelte +50 -50
  75. package/src/charts/dashboard/data-sort-head.svelte +56 -56
  76. package/src/charts/dashboard/data-table.svelte +138 -138
  77. package/src/charts/dashboard/panel-grid.svelte +30 -30
  78. package/src/charts/dashboard/period-filter.svelte +25 -25
  79. package/src/charts/dashboard/rating-chip.svelte +19 -19
  80. package/src/charts/dashboard/stat-band.svelte +32 -32
  81. package/src/charts/dashboard/stat-tile.svelte +106 -99
  82. package/src/charts/donut-chart.svelte +1 -1
  83. package/src/charts/edge-fade.svelte +1 -1
  84. package/src/charts/figure.svelte +1 -1
  85. package/src/charts/gauge-chart.css +4 -7
  86. package/src/charts/gauge-chart.svelte +1 -1
  87. package/src/charts/hover-focus.svelte +1 -1
  88. package/src/charts/legend.css +1 -3
  89. package/src/charts/legend.svelte +1 -1
  90. package/src/charts/line-chart.svelte +1 -1
  91. package/src/charts/number-chart.css +6 -9
  92. package/src/charts/number-chart.svelte +1 -1
  93. package/src/charts/reference-line.svelte +19 -19
  94. package/src/charts/reveal.svelte +1 -1
  95. package/src/charts/ring-chart.css +2 -4
  96. package/src/charts/ring-chart.svelte +1 -1
  97. package/src/charts/sparkline.svelte +5 -2
  98. package/src/charts/stat-card.svelte +1 -1
  99. package/src/charts/time-series-chart.css +2 -5
  100. package/src/charts/trend-pill.css +2 -4
  101. package/src/charts/trend-pill.svelte +1 -1
  102. package/src/components/copy/copy-button.svelte +93 -98
  103. package/src/components/copy/copy-button.test.ts +10 -2
  104. package/src/components/data-table/infinite-scroll.svelte +42 -42
  105. package/src/components/data-table/pagination.svelte +34 -22
  106. package/src/components/data-table/row-arrow.svelte +19 -16
  107. package/src/components/data-table/row-context-menu.svelte +52 -52
  108. package/src/components/data-table/sortable-head.svelte +25 -25
  109. package/src/components/data-table/table-skeleton.svelte +41 -36
  110. package/src/components/docs/doc-page.svelte +18 -9
  111. package/src/components/docs/on-this-page.svelte +16 -3
  112. package/src/components/docs/scroll-spy.svelte.ts +2 -3
  113. package/src/components/field-row/field-row.svelte +10 -8
  114. package/src/components/hold-to-confirm/hold-to-confirm.svelte +5 -1
  115. package/src/components/icon/icon.svelte +14 -14
  116. package/src/components/language-flag/language-flag.svelte +3 -1
  117. package/src/components/list-page/detail-empty.svelte +34 -34
  118. package/src/components/list-page/detail-header.svelte +55 -47
  119. package/src/components/list-page/detail-panel.svelte +51 -59
  120. package/src/components/list-page/detail-row.svelte +19 -19
  121. package/src/components/list-page/detail-stack.svelte +21 -21
  122. package/src/components/list-page/empty-state.svelte +30 -30
  123. package/src/components/list-page/filter-item.svelte +20 -20
  124. package/src/components/list-page/filter-popover.svelte +60 -55
  125. package/src/components/list-page/grouped-list.svelte +4 -2
  126. package/src/components/list-page/index.ts +8 -4
  127. package/src/components/list-page/list-page-shell.svelte +2 -5
  128. package/src/components/list-page/master-detail.svelte +87 -88
  129. package/src/components/list-page/notice-bar.svelte +38 -38
  130. package/src/components/list-page/prev-next.svelte +63 -63
  131. package/src/components/list-page/rail-body.svelte +18 -18
  132. package/src/components/list-page/rail-empty.svelte +23 -30
  133. package/src/components/list-page/rail-head.svelte +24 -24
  134. package/src/components/list-page/rail-row.svelte +77 -73
  135. package/src/components/list-page/section-host.ts +2 -3
  136. package/src/components/locale-switch/locale-switch.svelte +41 -41
  137. package/src/components/mark/mark.svelte +34 -38
  138. package/src/components/open-in/index.ts +1 -5
  139. package/src/components/open-in/open-in.svelte +40 -40
  140. package/src/components/picker/mark-picker.svelte +49 -49
  141. package/src/components/picker/picker.svelte +5 -3
  142. package/src/components/section-header/index.ts +1 -0
  143. package/src/components/section-header/section-header.svelte +1 -1
  144. package/src/components/section-header/section-header.test.ts +7 -1
  145. package/src/components/section-header/section-label.svelte +39 -0
  146. package/src/components/segmented/animated-tabs.svelte +31 -2
  147. package/src/components/segmented/collapse.test.ts +2 -1
  148. package/src/components/segmented/index.ts +2 -0
  149. package/src/components/segmented/segment.svelte +52 -49
  150. package/src/components/segmented/segmented-filter.svelte +79 -80
  151. package/src/components/segmented/segmented-nav.svelte +34 -40
  152. package/src/components/segmented/segmented-overflow.svelte +53 -50
  153. package/src/components/segmented/segmented-track.svelte +62 -46
  154. package/src/components/segmented/segmented.ts +2 -3
  155. package/src/components/star-rating-input/star-rating-input.svelte +103 -103
  156. package/src/components/svg/svg.svelte +4 -4
  157. package/src/components/table-view/table-view.svelte +17 -2
  158. package/src/components/table-view/table-view.test.ts +7 -1
  159. package/src/components/table-view/types.ts +11 -11
  160. package/src/components/tags-input/index.ts +13 -0
  161. package/src/components/tags-input/tags-input.svelte +305 -0
  162. package/src/components/tags-input/tags.test.ts +64 -0
  163. package/src/components/tags-input/tags.ts +142 -0
  164. package/src/components/theme/index.ts +2 -4
  165. package/src/components/theme/theme-provider.svelte +1 -3
  166. package/src/components/toolbar/index.ts +2 -0
  167. package/src/components/{list-page → toolbar}/toolbar-search.svelte +25 -25
  168. package/src/components/toolbar/toolbar.svelte +13 -9
  169. package/src/components/toolbar/toolbar.test.ts +10 -1
  170. package/src/design/index.css +21 -78
  171. package/src/design/polish.css +26 -35
  172. package/src/editor/editor-toolbar.svelte +104 -99
  173. package/src/editor/editor.svelte +296 -266
  174. package/src/editor/image-toolbar.svelte +20 -22
  175. package/src/editor/index.ts +1 -4
  176. package/src/editor/inline-editor.svelte +280 -238
  177. package/src/editor/markdown.ts +15 -15
  178. package/src/editor/renderer.svelte +71 -71
  179. package/src/editor/slash-menu.svelte +24 -27
  180. package/src/effects/animated-beam/diagrams/BeamSvg.svelte +1 -1
  181. package/src/effects/image-comparison/ImageComparison.svelte +11 -1
  182. package/src/effects/interactive-hover-button/InteractiveHoverButton.svelte +59 -46
  183. package/src/effects/magic-card/MagicCard.css +14 -7
  184. package/src/effects/marquee/Marquee.svelte +3 -5
  185. package/src/effects/reveal/observe.ts +0 -3
  186. package/src/effects/spotlight/Spotlight.svelte +1 -1
  187. package/src/effects/theme-toggle/ThemeToggle.css +25 -22
  188. package/src/effects/theme-toggle/ThemeToggle.svelte +6 -7
  189. package/src/gallery.test.ts +14 -4
  190. package/src/inbox/README.md +27 -0
  191. package/src/inbox/inbox.test.ts +214 -0
  192. package/src/inbox/index.ts +31 -0
  193. package/src/inbox/logic.ts +169 -0
  194. package/src/inbox/thread-inbox.svelte +439 -0
  195. package/src/inbox/types.ts +161 -0
  196. package/src/lib/theme-transition.ts +2 -4
  197. package/src/lib/tone.ts +2 -4
  198. package/src/lib/utils.ts +2 -2
  199. package/src/modules.test.ts +105 -0
  200. package/src/onboarding/define-tours.test.ts +55 -40
  201. package/src/onboarding/define-tours.ts +23 -23
  202. package/src/onboarding/demo.svelte +24 -5
  203. package/src/onboarding/index.ts +1 -8
  204. package/src/onboarding/onboarding-provider.svelte +19 -7
  205. package/src/onboarding/onboarding.svelte.ts +16 -16
  206. package/src/onboarding/pick.test.ts +61 -52
  207. package/src/onboarding/pick.ts +16 -13
  208. package/src/onboarding/stores.test.ts +80 -80
  209. package/src/onboarding/stores.ts +41 -39
  210. package/src/onboarding/tour-card.svelte +30 -5
  211. package/src/onboarding/tour-runner.svelte +12 -3
  212. package/src/onboarding/types.ts +20 -12
  213. package/src/onboarding/wait.ts +22 -22
  214. package/src/panel/README.md +5 -0
  215. package/src/panel/index.ts +2 -0
  216. package/src/panel/side-panel.svelte +194 -0
  217. package/src/record/README.md +3 -0
  218. package/src/record/demo-data.ts +352 -0
  219. package/src/record/field-section.svelte +57 -0
  220. package/src/record/fields.ts +194 -0
  221. package/src/record/format.ts +94 -0
  222. package/src/{tasks/record → record}/index.ts +49 -35
  223. package/src/{tasks/record → record}/info-list.svelte +145 -114
  224. package/src/record/kinds.ts +42 -0
  225. package/src/record/logic.ts +326 -0
  226. package/src/record/next-up.svelte +81 -0
  227. package/src/{tasks/record → record}/project-list.svelte +56 -50
  228. package/src/{tasks/record → record}/record-demo.svelte +130 -110
  229. package/src/{tasks/record → record}/record-header.svelte +37 -28
  230. package/src/{tasks/record → record}/record-shell.svelte +54 -54
  231. package/src/record/record-stats.svelte +48 -0
  232. package/src/record/record-timeline.svelte +251 -0
  233. package/src/record/record.test.ts +471 -0
  234. package/src/{tasks/record → record}/steps-rail.svelte +225 -216
  235. package/src/record/types.ts +299 -0
  236. package/src/record/where-we-are.svelte +125 -0
  237. package/src/shadcn/button/button.svelte +1 -1
  238. package/src/shadcn/card/card-title.svelte +1 -5
  239. package/src/shadcn/hooks/use-highlighted-code.svelte.ts +2 -13
  240. package/src/shadcn/sheet/sheet-content.svelte +2 -4
  241. package/src/shadcn/table/table-cell.svelte +2 -3
  242. package/src/shadcn/utilities.css +3 -8
  243. package/src/slides/Controls.svelte +150 -124
  244. package/src/slides/Deck.svelte +243 -238
  245. package/src/slides/Fragment.svelte +64 -57
  246. package/src/slides/Overview.svelte +106 -101
  247. package/src/slides/Presenter.svelte +300 -266
  248. package/src/slides/Slide.svelte +185 -170
  249. package/src/slides/SlideList.svelte +16 -12
  250. package/src/slides/ambient.d.ts +1 -1
  251. package/src/slides/bridges.ts +42 -23
  252. package/src/slides/deck-controller.svelte.ts +47 -35
  253. package/src/slides/demo-slides.svelte +330 -306
  254. package/src/slides/demo.svelte +164 -160
  255. package/src/slides/export/capture.ts +20 -16
  256. package/src/slides/export/ffmpeg.ts +43 -38
  257. package/src/slides/export/index.ts +5 -5
  258. package/src/slides/export/launch.ts +3 -1
  259. package/src/slides/export/pdf.ts +30 -27
  260. package/src/slides/export/types.ts +10 -8
  261. package/src/slides/index.ts +11 -11
  262. package/src/slides/labels.ts +22 -19
  263. package/src/slides/layout.ts +9 -2
  264. package/src/slides/model.ts +4 -4
  265. package/src/slides/navigation.ts +43 -31
  266. package/src/slides/theme.css +5 -7
  267. package/src/slides/types.ts +9 -10
  268. package/src/status/README.md +18 -0
  269. package/src/status/define-statuses.ts +25 -0
  270. package/src/status/index.ts +11 -0
  271. package/src/{tasks → status}/status-badge.svelte +3 -1
  272. package/src/{tasks → status}/status-dot.svelte +1 -3
  273. package/src/{tasks → status}/status-icon.svelte +1 -1
  274. package/src/status/status-types.ts +40 -0
  275. package/src/tasks/README.md +1 -1
  276. package/src/tasks/board-order.ts +2 -4
  277. package/src/tasks/demo.svelte +192 -34
  278. package/src/tasks/detail/detail-demo.svelte +75 -15
  279. package/src/tasks/detail/detail-types.ts +45 -45
  280. package/src/tasks/detail/task-detail.svelte +40 -10
  281. package/src/tasks/detail/task-property.svelte +8 -2
  282. package/src/tasks/detail/task-thread.svelte +53 -12
  283. package/src/tasks/gantt/gantt-bar.svelte +17 -6
  284. package/src/tasks/gantt/gantt-grid.svelte +40 -9
  285. package/src/tasks/gantt/gantt-group-row.svelte +8 -2
  286. package/src/tasks/gantt/gantt-header.svelte +9 -3
  287. package/src/tasks/gantt/gantt-task-row.svelte +26 -6
  288. package/src/tasks/gantt/gantt.css +2 -1
  289. package/src/tasks/gantt/gantt.test.ts +4 -2
  290. package/src/tasks/gantt/logic.test.ts +110 -20
  291. package/src/tasks/gantt/logic.ts +42 -6
  292. package/src/tasks/inbox/inbox-card.svelte +15 -7
  293. package/src/tasks/inbox/inbox-draft.svelte +1 -1
  294. package/src/tasks/inbox/inbox-logic.ts +6 -40
  295. package/src/tasks/inbox/inbox-statuses.ts +24 -24
  296. package/src/tasks/inbox/inbox-trace.svelte +9 -3
  297. package/src/tasks/inbox/inbox-types.ts +54 -58
  298. package/src/tasks/inbox/index.ts +22 -21
  299. package/src/tasks/index.ts +52 -53
  300. package/src/tasks/kanban-board.svelte +16 -12
  301. package/src/tasks/kanban-types.ts +2 -3
  302. package/src/tasks/presets/sales.ts +7 -7
  303. package/src/tasks/task-gantt.svelte +28 -8
  304. package/src/tasks/task-list.svelte +41 -17
  305. package/src/tasks/time/duration.ts +40 -40
  306. package/src/tasks/time/time-chip.svelte +9 -2
  307. package/src/tasks/time/time-dot.svelte +1 -1
  308. package/src/tasks/time/time-ring.svelte +11 -3
  309. package/src/tasks/time/time-tracker.svelte +57 -15
  310. package/src/tasks/time/time-types.ts +57 -57
  311. package/src/tasks/use-kanban-dnd.svelte.ts +2 -3
  312. package/src/thread/README.md +31 -0
  313. package/src/thread/index.ts +12 -0
  314. package/src/thread/logic.ts +61 -0
  315. package/src/thread/thread.svelte +432 -0
  316. package/src/thread/thread.test.ts +73 -0
  317. package/src/thread/types.ts +93 -0
  318. package/src/tokens/craft.css +17 -53
  319. package/src/tokens/index.css +3 -13
  320. package/src/tokens/palette.css +13 -11
  321. package/src/tokens/primitives.css +10 -23
  322. package/src/components/list-page/section-label.svelte +0 -39
  323. package/src/tasks/define-statuses.ts +0 -32
  324. package/src/tasks/inbox/inbox.svelte +0 -203
  325. package/src/tasks/record/demo-data.ts +0 -286
  326. package/src/tasks/record/field-section.svelte +0 -53
  327. package/src/tasks/record/fields.ts +0 -142
  328. package/src/tasks/record/format.ts +0 -87
  329. package/src/tasks/record/kinds.ts +0 -42
  330. package/src/tasks/record/logic.ts +0 -324
  331. package/src/tasks/record/next-up.svelte +0 -70
  332. package/src/tasks/record/record-stats.svelte +0 -48
  333. package/src/tasks/record/record-timeline.svelte +0 -231
  334. package/src/tasks/record/record.test.ts +0 -350
  335. package/src/tasks/record/types.ts +0 -280
  336. package/src/tasks/record/where-we-are.svelte +0 -121
  337. package/src/tasks/side-panel.svelte +0 -193
  338. package/src/tasks/status-types.ts +0 -40
  339. /package/src/components/{list-page → toolbar}/toolbar-trigger.ts +0 -0
  340. /package/src/{tasks → panel}/side-panel-types.ts +0 -0
  341. /package/src/{tasks/record → record}/gutter.ts +0 -0
@@ -4,9 +4,9 @@
4
4
  import TaskGantt from "./task-gantt.svelte";
5
5
  import { SegmentedFilter } from "../components/segmented/index.js";
6
6
  import { ChartBarHorizontal, Kanban, ListBullets } from "phosphor-svelte";
7
- import StatusBadge from "./status-badge.svelte";
8
- import StatusDot from "./status-dot.svelte";
9
- import { defineStatuses } from "./define-statuses.js";
7
+ import StatusBadge from "../status/status-badge.svelte";
8
+ import StatusDot from "../status/status-dot.svelte";
9
+ import { defineStatuses } from "../status/define-statuses.js";
10
10
  import { addDays, dayNumber, todayIso } from "./dates.js";
11
11
  import { salesStatuses } from "./presets/sales.js";
12
12
  import type { KanbanMove } from "./kanban-types.js";
@@ -50,14 +50,91 @@
50
50
  const on = (days: number) => addDays(today, days);
51
51
 
52
52
  let tasks = $state<Task[]>([
53
- { id: "t1", status: "done", title: "Set up analytics", assignee: "Bo", priority: "low", boardOrder: "a0", start: on(-12), end: on(-8) },
54
- { id: "t2", status: "done", title: "Interview five customers", assignee: "Cleo", priority: "medium", boardOrder: "a1", start: on(-10), end: on(-4) },
55
- { id: "t3", status: "review", title: "Write the pricing page", assignee: "Ada", priority: "high", boardOrder: "a0", start: on(-5), end: on(1), dependsOn: ["t2"] },
56
- { id: "t4", status: "doing", title: "Build the onboarding flow", assignee: "Dana", priority: "high", boardOrder: "a0", start: on(-3), end: on(5), dependsOn: ["t1"] },
57
- { id: "t5", status: "doing", title: "Draft the launch email", assignee: "Bo", priority: "medium", boardOrder: "a1", start: on(0), end: on(3), dependsOn: ["t3"] },
58
- { id: "t6", status: "todo", title: "Record the demo video", assignee: "Cleo", priority: "medium", boardOrder: "a0", start: on(4), end: on(8), dependsOn: ["t4"] },
59
- { id: "t7", status: "todo", title: "Pick a shipping date", assignee: "Ada", priority: "low", boardOrder: "a1", start: on(6), end: on(6) },
60
- { id: "t8", status: "todo", title: "Launch on Product Hunt", assignee: "Dana", priority: "high", boardOrder: "a2", start: on(10), end: on(11), dependsOn: ["t5", "t6"] },
53
+ {
54
+ id: "t1",
55
+ status: "done",
56
+ title: "Set up analytics",
57
+ assignee: "Bo",
58
+ priority: "low",
59
+ boardOrder: "a0",
60
+ start: on(-12),
61
+ end: on(-8),
62
+ },
63
+ {
64
+ id: "t2",
65
+ status: "done",
66
+ title: "Interview five customers",
67
+ assignee: "Cleo",
68
+ priority: "medium",
69
+ boardOrder: "a1",
70
+ start: on(-10),
71
+ end: on(-4),
72
+ },
73
+ {
74
+ id: "t3",
75
+ status: "review",
76
+ title: "Write the pricing page",
77
+ assignee: "Ada",
78
+ priority: "high",
79
+ boardOrder: "a0",
80
+ start: on(-5),
81
+ end: on(1),
82
+ dependsOn: ["t2"],
83
+ },
84
+ {
85
+ id: "t4",
86
+ status: "doing",
87
+ title: "Build the onboarding flow",
88
+ assignee: "Dana",
89
+ priority: "high",
90
+ boardOrder: "a0",
91
+ start: on(-3),
92
+ end: on(5),
93
+ dependsOn: ["t1"],
94
+ },
95
+ {
96
+ id: "t5",
97
+ status: "doing",
98
+ title: "Draft the launch email",
99
+ assignee: "Bo",
100
+ priority: "medium",
101
+ boardOrder: "a1",
102
+ start: on(0),
103
+ end: on(3),
104
+ dependsOn: ["t3"],
105
+ },
106
+ {
107
+ id: "t6",
108
+ status: "todo",
109
+ title: "Record the demo video",
110
+ assignee: "Cleo",
111
+ priority: "medium",
112
+ boardOrder: "a0",
113
+ start: on(4),
114
+ end: on(8),
115
+ dependsOn: ["t4"],
116
+ },
117
+ {
118
+ id: "t7",
119
+ status: "todo",
120
+ title: "Pick a shipping date",
121
+ assignee: "Ada",
122
+ priority: "low",
123
+ boardOrder: "a1",
124
+ start: on(6),
125
+ end: on(6),
126
+ },
127
+ {
128
+ id: "t8",
129
+ status: "todo",
130
+ title: "Launch on Product Hunt",
131
+ assignee: "Dana",
132
+ priority: "high",
133
+ boardOrder: "a2",
134
+ start: on(10),
135
+ end: on(11),
136
+ dependsOn: ["t5", "t6"],
137
+ },
61
138
  ]);
62
139
 
63
140
  const views = [
@@ -76,7 +153,11 @@
76
153
 
77
154
  const sortKeys = [
78
155
  { id: "title", label: "Title", compare: (a: Task, b: Task) => a.title.localeCompare(b.title) },
79
- { id: "assignee", label: "Assignee", compare: (a: Task, b: Task) => a.assignee.localeCompare(b.assignee) },
156
+ {
157
+ id: "assignee",
158
+ label: "Assignee",
159
+ compare: (a: Task, b: Task) => a.assignee.localeCompare(b.assignee),
160
+ },
80
161
  { id: "due", label: "Due date", compare: (a: Task, b: Task) => a.end.localeCompare(b.end) },
81
162
  ];
82
163
 
@@ -93,7 +174,11 @@
93
174
  Dana: "oklch(0.72 0.13 20)",
94
175
  };
95
176
 
96
- const dueFormat = new Intl.DateTimeFormat("en-US", { month: "short", day: "numeric", timeZone: "UTC" });
177
+ const dueFormat = new Intl.DateTimeFormat("en-US", {
178
+ month: "short",
179
+ day: "numeric",
180
+ timeZone: "UTC",
181
+ });
97
182
 
98
183
  function due(task: Task): { label: string; late: boolean } {
99
184
  const late = task.status !== "done" && dayNumber(task.end) < dayNumber(today);
@@ -113,7 +198,14 @@
113
198
  }
114
199
 
115
200
  // ---- time tracking, an option the host turns on
116
- type Entry = { id: string; taskId: string; person: string; day: string; minutes: number; note?: string };
201
+ type Entry = {
202
+ id: string;
203
+ taskId: string;
204
+ person: string;
205
+ day: string;
206
+ minutes: number;
207
+ note?: string;
208
+ };
117
209
 
118
210
  const estimates: Record<string, number> = { t3: 360, t4: 480, t5: 180, t6: 240 };
119
211
 
@@ -121,9 +213,30 @@
121
213
  let timeTaskId = $state("t4");
122
214
  let nextEntry = 100;
123
215
  let entries = $state<Entry[]>([
124
- { id: "e1", taskId: "t4", person: "Dana", day: on(-3), minutes: 150, note: "Signup and email step" },
125
- { id: "e2", taskId: "t4", person: "Ada", day: on(-2), minutes: 95, note: "Copy for the welcome screen" },
126
- { id: "e3", taskId: "t4", person: "Dana", day: on(-2), minutes: 125, note: "Progress bar and empty states" },
216
+ {
217
+ id: "e1",
218
+ taskId: "t4",
219
+ person: "Dana",
220
+ day: on(-3),
221
+ minutes: 150,
222
+ note: "Signup and email step",
223
+ },
224
+ {
225
+ id: "e2",
226
+ taskId: "t4",
227
+ person: "Ada",
228
+ day: on(-2),
229
+ minutes: 95,
230
+ note: "Copy for the welcome screen",
231
+ },
232
+ {
233
+ id: "e3",
234
+ taskId: "t4",
235
+ person: "Dana",
236
+ day: on(-2),
237
+ minutes: 125,
238
+ note: "Progress bar and empty states",
239
+ },
127
240
  { id: "e4", taskId: "t4", person: "Dana", day: on(-1), minutes: 80 },
128
241
  { id: "e5", taskId: "t3", person: "Ada", day: on(-5), minutes: 210, note: "First draft" },
129
242
  { id: "e6", taskId: "t3", person: "Bo", day: on(-3), minutes: 95, note: "Pricing table" },
@@ -158,7 +271,8 @@
158
271
  timer = null;
159
272
  }
160
273
 
161
- const listGrid = "grid grid-cols-[minmax(0,1fr)_7rem_5.5rem_4.5rem] items-center gap-3 max-sm:grid-cols-[minmax(0,1fr)_4.5rem]";
274
+ const listGrid =
275
+ "grid grid-cols-[minmax(0,1fr)_7rem_5.5rem_4.5rem] items-center gap-3 max-sm:grid-cols-[minmax(0,1fr)_4.5rem]";
162
276
  </script>
163
277
 
164
278
  {#snippet avatar(name: string)}
@@ -176,12 +290,23 @@
176
290
  <div class="flex flex-wrap items-center gap-2">
177
291
  <SegmentedFilter options={views} bind:value={view} ariaLabel="Task view" block={false} />
178
292
  <div class="ml-auto flex items-center gap-3">
179
- <label class="flex cursor-pointer items-center gap-1.5 text-xs font-medium text-muted-foreground">
180
- <input type="checkbox" bind:checked={tracking} class="size-3.5 accent-[var(--tone-accent,var(--color-primary))]" />
293
+ <label
294
+ class="flex cursor-pointer items-center gap-1.5 text-xs font-medium text-muted-foreground"
295
+ >
296
+ <input
297
+ type="checkbox"
298
+ bind:checked={tracking}
299
+ class="size-3.5 accent-[var(--tone-accent,var(--color-primary))]"
300
+ />
181
301
  Time tracking
182
302
  </label>
183
303
  {#if view === "gantt"}
184
- <SegmentedFilter options={scales} bind:value={scale} ariaLabel="Timeline scale" block={false} />
304
+ <SegmentedFilter
305
+ options={scales}
306
+ bind:value={scale}
307
+ ariaLabel="Timeline scale"
308
+ block={false}
309
+ />
185
310
  {:else}
186
311
  <label for="tasks-sort" class="text-xs font-medium text-muted-foreground">Sort</label>
187
312
  <select
@@ -213,15 +338,27 @@
213
338
  >
214
339
  {#snippet renderCard(task)}
215
340
  {@const d = due(task)}
216
- <article class="rounded-xl border border-border bg-card p-2.5 text-card-foreground shadow-sm">
341
+ <article
342
+ class="rounded-xl border border-border bg-card p-2.5 text-card-foreground shadow-sm"
343
+ >
217
344
  <p class="text-sm leading-snug">{task.title}</p>
218
345
  <div class="mt-2.5 flex items-center gap-2 text-xs">
219
346
  {@render avatar(task.assignee)}
220
- <span class={d.late ? "font-medium text-destructive" : "text-muted-foreground"}>{d.label}</span>
347
+ <span class={d.late ? "font-medium text-destructive" : "text-muted-foreground"}
348
+ >{d.label}</span
349
+ >
221
350
  {#if tracking}
222
- <TimeChip minutes={minutesByTask[task.id] ?? 0} estimate={estimates[task.id]} running={timer?.taskId === task.id} />
351
+ <TimeChip
352
+ minutes={minutesByTask[task.id] ?? 0}
353
+ estimate={estimates[task.id]}
354
+ running={timer?.taskId === task.id}
355
+ />
223
356
  {/if}
224
- <span class="ml-auto rounded-full px-1.5 py-0.5 font-medium capitalize {priorityClass[task.priority]}">
357
+ <span
358
+ class="ml-auto rounded-full px-1.5 py-0.5 font-medium capitalize {priorityClass[
359
+ task.priority
360
+ ]}"
361
+ >
225
362
  {task.priority}
226
363
  </span>
227
364
  </div>
@@ -252,13 +389,21 @@
252
389
  <div class="{listGrid} h-10 px-2 text-sm">
253
390
  <span class="flex min-w-0 items-center gap-2.5">
254
391
  {#key task.status}
255
- <StatusDot statuses={statuses} status={task.status} />
392
+ <StatusDot {statuses} status={task.status} />
256
393
  {/key}
257
- <span class="truncate" class:text-muted-foreground={task.status === "done"} class:line-through={task.status === "done"}>
394
+ <span
395
+ class="truncate"
396
+ class:text-muted-foreground={task.status === "done"}
397
+ class:line-through={task.status === "done"}
398
+ >
258
399
  {task.title}
259
400
  </span>
260
401
  {#if tracking}
261
- <TimeChip minutes={minutesByTask[task.id] ?? 0} estimate={estimates[task.id]} running={timer?.taskId === task.id} />
402
+ <TimeChip
403
+ minutes={minutesByTask[task.id] ?? 0}
404
+ estimate={estimates[task.id]}
405
+ running={timer?.taskId === task.id}
406
+ />
262
407
  {/if}
263
408
  </span>
264
409
  <span class="flex min-w-0 items-center gap-2 text-muted-foreground max-sm:hidden">
@@ -266,11 +411,19 @@
266
411
  <span class="truncate">{task.assignee}</span>
267
412
  </span>
268
413
  <span class="max-sm:hidden">
269
- <span class="rounded-full px-1.5 py-0.5 text-xs font-medium capitalize {priorityClass[task.priority]}">
414
+ <span
415
+ class="rounded-full px-1.5 py-0.5 text-xs font-medium capitalize {priorityClass[
416
+ task.priority
417
+ ]}"
418
+ >
270
419
  {task.priority}
271
420
  </span>
272
421
  </span>
273
- <span class="text-right text-xs tabular-nums {d.late ? 'font-medium text-destructive' : 'text-muted-foreground'}">
422
+ <span
423
+ class="text-right text-xs tabular-nums {d.late
424
+ ? 'font-medium text-destructive'
425
+ : 'text-muted-foreground'}"
426
+ >
274
427
  {d.label}
275
428
  </span>
276
429
  </div>
@@ -293,7 +446,7 @@
293
446
  {onChange}
294
447
  >
295
448
  {#snippet renderLabel(task)}
296
- <StatusDot statuses={statuses} status={task.status} />
449
+ <StatusDot {statuses} status={task.status} />
297
450
  <span class="min-w-0 flex-1 truncate">{task.title}</span>
298
451
  {@render avatar(task.assignee)}
299
452
  {/snippet}
@@ -316,7 +469,9 @@
316
469
  {#if tracking}
317
470
  <section class="flex flex-col gap-3 border-t border-border pt-4">
318
471
  <div class="flex items-center justify-between gap-3">
319
- <h3 class="text-xs font-semibold uppercase tracking-wide text-muted-foreground">Task time</h3>
472
+ <h3 class="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
473
+ Task time
474
+ </h3>
320
475
  <select
321
476
  bind:value={timeTaskId}
322
477
  aria-label="Task"
@@ -350,7 +505,9 @@
350
505
  {/if}
351
506
 
352
507
  <section class="flex flex-col gap-2 border-t border-border pt-4">
353
- <h3 class="text-xs font-semibold uppercase tracking-wide text-muted-foreground">Status badges</h3>
508
+ <h3 class="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
509
+ Status badges
510
+ </h3>
354
511
  <div class="flex flex-wrap items-center gap-2">
355
512
  {#each salesStatuses.ids as id (id)}
356
513
  <StatusBadge statuses={salesStatuses} status={id} />
@@ -370,7 +527,8 @@
370
527
  <style>
371
528
  /* Switching views: the new one rises in with a touch of blur, the old one is gone at once. */
372
529
  .tasks-view {
373
- animation: tasks-view-in var(--duration-fast, 250ms) var(--ease-smooth-out, cubic-bezier(0.22, 1, 0.36, 1)) backwards;
530
+ animation: tasks-view-in var(--duration-fast, 250ms)
531
+ var(--ease-smooth-out, cubic-bezier(0.22, 1, 0.36, 1)) backwards;
374
532
  }
375
533
 
376
534
  @keyframes tasks-view-in {
@@ -4,12 +4,20 @@
4
4
  import TaskProperty from "./task-property.svelte";
5
5
  import TaskChip from "./task-chip.svelte";
6
6
  import TimeTracker from "../time/time-tracker.svelte";
7
- import StatusDot from "../status-dot.svelte";
8
- import { defineStatuses } from "../define-statuses.js";
7
+ import StatusDot from "../../status/status-dot.svelte";
8
+ import { defineStatuses } from "../../status/define-statuses.js";
9
9
  import type { TaskComment } from "./detail-types.js";
10
10
  import type { TimeLogInput, TimeStopInfo } from "../time/time-types.js";
11
11
 
12
- type Scenario = "default" | "long" | "emptyDescription" | "unassigned" | "running" | "busy" | "closed" | "loading";
12
+ type Scenario =
13
+ | "default"
14
+ | "long"
15
+ | "emptyDescription"
16
+ | "unassigned"
17
+ | "running"
18
+ | "busy"
19
+ | "closed"
20
+ | "loading";
13
21
 
14
22
  const statuses = defineStatuses({
15
23
  todo: { label: "To do", tone: "neutral", variant: "open" },
@@ -34,15 +42,35 @@
34
42
  const stamp = (agoHours: number) => new Date(now - agoHours * hour).toISOString();
35
43
 
36
44
  const seed: TaskComment[] = [
37
- { id: "c1", author: "Ada Lovelace", body: "Calls with Yoan: the format that sold the template was simple. A board on why, then the system, then the demo.", createdAt: stamp(30) },
38
- { id: "c2", author: "Planner", agent: true, body: "Reused that shape for the outline. Three sections, the demo last, one call to action at the end.", createdAt: stamp(26) },
39
- { id: "c3", author: "Bo Chen", body: "Looks right. I'll record Thursday.", createdAt: stamp(5), edited: true },
45
+ {
46
+ id: "c1",
47
+ author: "Ada Lovelace",
48
+ body: "Calls with Yoan: the format that sold the template was simple. A board on why, then the system, then the demo.",
49
+ createdAt: stamp(30),
50
+ },
51
+ {
52
+ id: "c2",
53
+ author: "Planner",
54
+ agent: true,
55
+ body: "Reused that shape for the outline. Three sections, the demo last, one call to action at the end.",
56
+ createdAt: stamp(26),
57
+ },
58
+ {
59
+ id: "c3",
60
+ author: "Bo Chen",
61
+ body: "Looks right. I'll record Thursday.",
62
+ createdAt: stamp(5),
63
+ edited: true,
64
+ },
40
65
  ];
41
66
  const crowd: TaskComment[] = Array.from({ length: 24 }, (_, i) => ({
42
67
  id: `b${i}`,
43
- author: i % 4 === 1 ? "Planner" : people[i % people.length] ?? "Ada Lovelace",
68
+ author: i % 4 === 1 ? "Planner" : (people[i % people.length] ?? "Ada Lovelace"),
44
69
  agent: i % 4 === 1,
45
- body: i % 5 === 0 ? "Pushed the second cut. The intro runs 40 seconds, so I trimmed the first example and kept the one with numbers." : "Noted, moving on to the next step.",
70
+ body:
71
+ i % 5 === 0
72
+ ? "Pushed the second cut. The intro runs 40 seconds, so I trimmed the first example and kept the one with numbers."
73
+ : "Noted, moving on to the next step.",
46
74
  createdAt: stamp(60 - i * 2),
47
75
  }));
48
76
 
@@ -59,7 +87,13 @@
59
87
  let done = $state(false);
60
88
  let timer = $state<{ startedAt: number } | null>(null);
61
89
  let entries = $state([
62
- { id: "e1", minutes: 90, day: new Date(now - 24 * hour).toISOString().slice(0, 10), person: "Ada Lovelace", note: "Outline" },
90
+ {
91
+ id: "e1",
92
+ minutes: 90,
93
+ day: new Date(now - 24 * hour).toISOString().slice(0, 10),
94
+ person: "Ada Lovelace",
95
+ note: "Outline",
96
+ },
63
97
  ]);
64
98
 
65
99
  $effect(() => {
@@ -76,7 +110,16 @@
76
110
  let statusLabel = $derived(statuses.label(status));
77
111
 
78
112
  function onLog(input: TimeLogInput) {
79
- entries = [{ id: `e${entries.length + 1}`, minutes: input.minutes, day: input.day, person: "Ada Lovelace", note: input.note ?? "" }, ...entries];
113
+ entries = [
114
+ {
115
+ id: `e${entries.length + 1}`,
116
+ minutes: input.minutes,
117
+ day: input.day,
118
+ person: "Ada Lovelace",
119
+ note: input.note ?? "",
120
+ },
121
+ ...entries,
122
+ ];
80
123
  return true;
81
124
  }
82
125
 
@@ -86,7 +129,15 @@
86
129
  }
87
130
 
88
131
  function onSend(body: string) {
89
- thread = [...thread, { id: `n${thread.length}`, author: "Ada Lovelace", body, createdAt: new Date().toISOString() }];
132
+ thread = [
133
+ ...thread,
134
+ {
135
+ id: `n${thread.length}`,
136
+ author: "Ada Lovelace",
137
+ body,
138
+ createdAt: new Date().toISOString(),
139
+ },
140
+ ];
90
141
  }
91
142
  </script>
92
143
 
@@ -112,7 +163,10 @@
112
163
  </button>
113
164
  </div>
114
165
 
115
- <div class="mx-auto w-full overflow-hidden rounded-xl border border-border bg-background" style:max-width={narrow ? "390px" : "none"}>
166
+ <div
167
+ class="mx-auto w-full overflow-hidden rounded-xl border border-border bg-background"
168
+ style:max-width={narrow ? "390px" : "none"}
169
+ >
116
170
  <TaskDetail
117
171
  {title}
118
172
  onTitleChange={(next) => {
@@ -139,15 +193,21 @@
139
193
  {/snippet}
140
194
  {#snippet properties()}
141
195
  <TaskProperty label="Status">
142
- <TaskChip aria-label="Status: {statusLabel}"><StatusDot {statuses} {status} size={14} animate={false} />{statusLabel}</TaskChip>
196
+ <TaskChip aria-label="Status: {statusLabel}"
197
+ ><StatusDot {statuses} {status} size={14} animate={false} />{statusLabel}</TaskChip
198
+ >
143
199
  </TaskProperty>
144
200
  <TaskProperty label="Priority">
145
- <TaskChip><Flag weight="fill" class="text-destructive" aria-hidden="true" />High</TaskChip>
201
+ <TaskChip><Flag weight="fill" class="text-destructive" aria-hidden="true" />High</TaskChip
202
+ >
146
203
  </TaskProperty>
147
204
  <TaskProperty label="Assignee">
148
205
  {#if assignee}
149
206
  <TaskChip>
150
- <span class="grid size-4 place-items-center rounded-full bg-muted text-[0px]" aria-hidden="true"><User /></span>
207
+ <span
208
+ class="grid size-4 place-items-center rounded-full bg-muted text-[0px]"
209
+ aria-hidden="true"><User /></span
210
+ >
151
211
  {assignee}
152
212
  </TaskChip>
153
213
  {:else}
@@ -1,54 +1,54 @@
1
1
  /** One entry in a task's thread. The host resolves the author's name. */
2
2
  export type TaskComment = {
3
- id: string;
4
- author: string;
5
- body: string;
6
- /** ISO timestamp. */
7
- createdAt: string;
8
- /** An agent wrote it: the thread draws the agent avatar and an "AI" label. */
9
- agent?: boolean;
10
- /** Set when the body changed after posting. */
11
- edited?: boolean;
3
+ id: string;
4
+ author: string;
5
+ body: string;
6
+ /** ISO timestamp. */
7
+ createdAt: string;
8
+ /** An agent wrote it: the thread draws the agent avatar and an "AI" label. */
9
+ agent?: boolean;
10
+ /** Set when the body changed after posting. */
11
+ edited?: boolean;
12
12
  };
13
13
 
14
14
  export type TaskDetailLabels = {
15
- markComplete: string;
16
- markIncomplete: string;
17
- editTitle: string;
18
- description: string;
19
- addDescription: string;
20
- editDescription: string;
21
- save: string;
22
- saving: string;
23
- cancel: string;
24
- comments: string;
25
- commentPlaceholder: string;
26
- commentSend: string;
27
- commentEdit: string;
28
- commentDelete: string;
29
- commentEdited: string;
30
- commentsEmpty: string;
31
- ai: string;
32
- properties: string;
15
+ markComplete: string;
16
+ markIncomplete: string;
17
+ editTitle: string;
18
+ description: string;
19
+ addDescription: string;
20
+ editDescription: string;
21
+ save: string;
22
+ saving: string;
23
+ cancel: string;
24
+ comments: string;
25
+ commentPlaceholder: string;
26
+ commentSend: string;
27
+ commentEdit: string;
28
+ commentDelete: string;
29
+ commentEdited: string;
30
+ commentsEmpty: string;
31
+ ai: string;
32
+ properties: string;
33
33
  };
34
34
 
35
35
  export const DEFAULT_TASK_DETAIL_LABELS: TaskDetailLabels = {
36
- markComplete: "Mark complete",
37
- markIncomplete: "Mark incomplete",
38
- editTitle: "Edit title",
39
- description: "Description",
40
- addDescription: "Add a description",
41
- editDescription: "Edit description",
42
- save: "Save",
43
- saving: "Saving",
44
- cancel: "Cancel",
45
- comments: "Activity",
46
- commentPlaceholder: "Leave a comment",
47
- commentSend: "Comment",
48
- commentEdit: "Edit comment",
49
- commentDelete: "Delete comment",
50
- commentEdited: "edited",
51
- commentsEmpty: "No comments yet",
52
- ai: "AI",
53
- properties: "Properties",
36
+ markComplete: "Mark complete",
37
+ markIncomplete: "Mark incomplete",
38
+ editTitle: "Edit title",
39
+ description: "Description",
40
+ addDescription: "Add a description",
41
+ editDescription: "Edit description",
42
+ save: "Save",
43
+ saving: "Saving",
44
+ cancel: "Cancel",
45
+ comments: "Activity",
46
+ commentPlaceholder: "Leave a comment",
47
+ commentSend: "Comment",
48
+ commentEdit: "Edit comment",
49
+ commentDelete: "Delete comment",
50
+ commentEdited: "edited",
51
+ commentsEmpty: "No comments yet",
52
+ ai: "AI",
53
+ properties: "Properties",
54
54
  };