@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
@@ -1,121 +0,0 @@
1
- <script lang="ts">
2
- // =========================
3
- // IMPORTS
4
- // =========================
5
- import { NavigationArrow } from "phosphor-svelte";
6
- import { cn } from "../../lib/utils.js";
7
- import { Button } from "../../shadcn/button/index.js";
8
- import StatusBadge from "../status-badge.svelte";
9
- import type { Tone } from "../../lib/tone.js";
10
- import { gutterClass } from "./gutter.js";
11
- import { formatAge } from "./format.js";
12
- import { resolveLabels, type RecordLabels } from "./types.js";
13
-
14
- // =========================
15
- // PROPS
16
- // =========================
17
- interface Props {
18
- /** The status note. Nothing draws without it. */
19
- note?: string | null;
20
- /** ISO timestamp of the note. */
21
- at?: string | null;
22
- actor?: string | null;
23
- health?: { label: string; tone: Tone } | null;
24
- /** Client mode: the project this note belongs to. */
25
- project?: { name: string; href?: string | null } | null;
26
- labels?: Partial<RecordLabels>;
27
- locale?: string;
28
- now?: Date | number;
29
- class?: string;
30
- }
31
- let { note, at, actor, health, project, labels, locale, now, class: className }: Props = $props();
32
-
33
- // =========================
34
- // STATE
35
- // =========================
36
- let expanded = $state(false);
37
- let clamped = $state(false);
38
- let text = $state<HTMLElement | null>(null);
39
-
40
- // =========================
41
- // DERIVED
42
- // =========================
43
- let t = $derived(resolveLabels(labels));
44
- let age = $derived(at ? formatAge(at, now, locale) : null);
45
- let hasMeta = $derived(Boolean(health || actor || age));
46
-
47
- // =========================
48
- // EFFECTS
49
- // =========================
50
- // WHY measure instead of guessing from length: the clamp is two lines, so the
51
- // same note fits at 1280px and overflows at 390px. "More" shows only when text is cut.
52
- $effect(() => {
53
- if (!text) return;
54
- const el = text;
55
- const measure = () => {
56
- if (!expanded) clamped = el.scrollHeight > el.clientHeight + 1;
57
- };
58
- measure();
59
- const observer = new ResizeObserver(measure);
60
- observer.observe(el);
61
- return () => observer.disconnect();
62
- });
63
- </script>
64
-
65
- <!-- =========================== -->
66
- <!-- MARKUP -->
67
- <!-- =========================== -->
68
- {#if note}
69
- <section
70
- aria-label={t.whereWeAre}
71
- class={cn("flex items-start gap-2.5 border-b border-border bg-muted/40 py-2.5", gutterClass, className)}
72
- >
73
- <NavigationArrow
74
- class="mt-0.5 size-3.5 shrink-0 text-[color:var(--tone-accent,var(--color-primary))]"
75
- weight="fill"
76
- aria-hidden="true"
77
- />
78
- <div class="min-w-0 flex-1">
79
- <!-- No `title` attribute: a native tooltip would repeat the whole note
80
- over the steps list. "More" opens it in place. -->
81
- <p
82
- bind:this={text}
83
- class={cn("text-sm leading-snug text-muted-foreground", !expanded && "line-clamp-2")}
84
- >
85
- <span class="font-medium text-foreground">{t.whereWeAre}</span>
86
- {#if project}
87
- {#if project.href}
88
- <a
89
- href={project.href}
90
- class="font-medium text-foreground underline-offset-2 hover:underline"
91
- >{project.name}</a
92
- >
93
- {:else}
94
- <span class="font-medium text-foreground">{project.name}</span>
95
- {/if}
96
- {/if}
97
- <span class="whitespace-pre-line">{note}</span>
98
- </p>
99
- {#if hasMeta}
100
- <p class="mt-1 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-muted-foreground">
101
- {#if health}
102
- <StatusBadge tone={health.tone} dot capitalize={false}>{health.label}</StatusBadge>
103
- {/if}
104
- {#if actor}<span>{t.by(actor)}</span>{/if}
105
- {#if age}<span class="tabular-nums">{age}</span>{/if}
106
- </p>
107
- {/if}
108
- </div>
109
- {#if clamped || expanded}
110
- <Button
111
- variant="ghost"
112
- size="sm"
113
- class="-mr-2 shrink-0 text-muted-foreground"
114
- aria-expanded={expanded}
115
- onclick={() => (expanded = !expanded)}
116
- >
117
- {expanded ? t.less : t.more}
118
- </Button>
119
- {/if}
120
- </section>
121
- {/if}
@@ -1,193 +0,0 @@
1
- <script lang="ts" module>
2
- import type { PanelStat, SidePanelWidth } from "./side-panel-types.js";
3
- export type { PanelStat, SidePanelWidth };
4
- </script>
5
-
6
- <script lang="ts">
7
- // =========================
8
- // IMPORTS
9
- // =========================
10
- import type { Snippet } from "svelte";
11
- import * as Sheet from "../shadcn/sheet/index.js";
12
- import { OpenIn, type OpenInTool } from "../components/open-in/index.js";
13
- import { CopyButton } from "../components/copy/index.js";
14
- import type { Tone } from "../lib/tone.js";
15
- import { cn } from "../lib/utils.js";
16
- import StatusBadge from "./status-badge.svelte";
17
-
18
- // =========================
19
- // PROPS
20
- // =========================
21
- interface Props {
22
- open: boolean;
23
- /** Names the dialog for screen readers and heads the panel. */
24
- title: string;
25
- /** Merged onto the title. A short path is set `font-mono`, a subject is not. */
26
- titleClass?: string;
27
- /** The facts the record is filed under, read out under the title. */
28
- description?: string;
29
- /** Status chips, left of the action row. */
30
- badges?: { label: string; tone: Tone }[];
31
- /** Doors out to another tool. `text` replaces the tool's name on the button. */
32
- openIn?: { tool: OpenInTool; href: string; label: string; text?: string }[];
33
- /** A prompt for an AI about this record, copied on click. */
34
- handoff?: { value: () => string | Promise<string>; label: string; copiedLabel: string };
35
- /** The record's numbers, as a strip under the badges. Same place in every panel. */
36
- stats?: PanelStat[];
37
- /** Anything else the record can do, drawn last in the action row. */
38
- actions?: Snippet;
39
- /** Pinned actions. The body scrolls above it; the caller aligns the row. */
40
- footer?: Snippet;
41
- children: Snippet;
42
- width?: SidePanelWidth;
43
- /** The body brings its own header: the title is read out but not drawn, and
44
- the body is neither padded nor scrolled by the panel. */
45
- bare?: boolean;
46
- /** Fires once when the panel closes, from the close button, Escape or the overlay. */
47
- onClose?: () => void;
48
- };
49
- let {
50
- open = $bindable(),
51
- title,
52
- titleClass,
53
- description,
54
- badges = [],
55
- openIn = [],
56
- handoff,
57
- stats = [],
58
- actions,
59
- footer,
60
- children,
61
- width = "sm",
62
- bare = false,
63
- onClose,
64
- }: Props = $props();
65
-
66
- // =========================
67
- // STATE
68
- // =========================
69
- let panel = $state<HTMLElement | null>(null);
70
-
71
- // =========================
72
- // DERIVED
73
- // =========================
74
- let hasRow = $derived(badges.length > 0 || openIn.length > 0 || Boolean(handoff || actions));
75
- const STAT_TONE = {
76
- default: "",
77
- muted: "text-muted-foreground",
78
- good: "text-success",
79
- bad: "text-destructive",
80
- } as const;
81
- const WIDTH: Record<SidePanelWidth, string> = {
82
- sm: "sm:max-w-sm",
83
- md: "sm:max-w-md",
84
- lg: "sm:max-w-xl",
85
- xl: "sm:max-w-2xl",
86
- "2xl": "sm:max-w-3xl",
87
- };
88
-
89
- // =========================
90
- // HANDLERS
91
- // =========================
92
- // WHY focus goes to the panel unless a text field comes first: the dialog otherwise
93
- // opens on its first control, which draws a ring on a record nobody has touched.
94
- // A form that opens on its field keeps the default, since that is where you type.
95
- const FIRST_CONTROL =
96
- 'a[href], button:not([disabled]), input:not([type="hidden"]):not([disabled]), textarea:not([disabled]), select:not([disabled])';
97
- function onOpenAutoFocus(event: Event) {
98
- if (!panel || panel.querySelector(FIRST_CONTROL)?.matches("input, textarea, select")) return;
99
- event.preventDefault();
100
- panel.focus();
101
- }
102
- </script>
103
-
104
- <!-- =========================== -->
105
- <!-- MARKUP -->
106
- <!-- =========================== -->
107
- <Sheet.Root
108
- bind:open
109
- onOpenChange={(next) => {
110
- if (!next) onClose?.();
111
- }}
112
- >
113
- <Sheet.Content
114
- side="right"
115
- bind:ref={panel}
116
- tabindex={-1}
117
- class={cn("flex w-full flex-col gap-0 p-0", WIDTH[width], bare && "overflow-hidden")}
118
- {onOpenAutoFocus}
119
- >
120
- {#if bare}
121
- <Sheet.Header class="sr-only">
122
- <Sheet.Title>{title}</Sheet.Title>
123
- </Sheet.Header>
124
- {@render children()}
125
- {:else}
126
- <Sheet.Header class="gap-1 border-b border-border">
127
- <!-- WHY the right padding: the close button sits over this corner and
128
- a long title runs straight under it. -->
129
- <Sheet.Title class={cn("pr-9 text-base leading-snug", titleClass)}>{title}</Sheet.Title>
130
- {#if description}
131
- <Sheet.Description>{description}</Sheet.Description>
132
- {/if}
133
- {#if hasRow}
134
- <div class="flex items-center justify-between gap-3 pt-1.5">
135
- <div class="flex min-w-0 flex-wrap items-center gap-2">
136
- {#each badges as badge (`${badge.tone}:${badge.label}`)}
137
- <StatusBadge tone={badge.tone}>{badge.label}</StatusBadge>
138
- {/each}
139
- </div>
140
- <div class="flex shrink-0 items-center gap-1">
141
- {#each openIn as door (door.href)}
142
- <OpenIn
143
- tool={door.tool}
144
- href={door.href}
145
- title={door.label}
146
- label={door.text}
147
- variant="button"
148
- size="sm"
149
- />
150
- {/each}
151
- {#if handoff}
152
- <CopyButton
153
- agent
154
- value={handoff.value}
155
- label={handoff.label}
156
- copiedLabel={handoff.copiedLabel}
157
- />
158
- {/if}
159
- {@render actions?.()}
160
- </div>
161
- </div>
162
- {/if}
163
- {#if stats.length > 0}
164
- <dl class="flex flex-wrap gap-x-6 gap-y-3 pt-3">
165
- {#each stats as stat (stat.label)}
166
- <div class="min-w-0">
167
- <dt class="text-xs text-muted-foreground">{stat.label}</dt>
168
- <dd class={cn("text-sm font-medium tabular-nums", STAT_TONE[stat.tone ?? "default"])}>
169
- {stat.value}
170
- {#if stat.sub}
171
- <span class="text-xs font-normal text-muted-foreground">{stat.sub}</span>
172
- {/if}
173
- </dd>
174
- </div>
175
- {/each}
176
- </dl>
177
- {/if}
178
- </Sheet.Header>
179
-
180
- <!-- WHY the body pads and spaces its sections itself: a panel that lets the
181
- caller choose drifts, one with a grey band and one with a white page. -->
182
- <div class="flex min-h-0 flex-1 flex-col gap-4 overflow-y-auto p-4">
183
- {@render children()}
184
- </div>
185
-
186
- {#if footer}
187
- <Sheet.Footer class="mt-0 flex-row items-center justify-end border-t border-border">
188
- {@render footer()}
189
- </Sheet.Footer>
190
- {/if}
191
- {/if}
192
- </Sheet.Content>
193
- </Sheet.Root>
@@ -1,40 +0,0 @@
1
- import type { Component } from "svelte";
2
- import type { Tone } from "../lib/tone.js";
3
-
4
- /**
5
- * The shape the dot can take. `progress` needs a `progress` value between 0 and 1.
6
- * `dashed` is an open ring cut into dashes, for an aggregate such as "All".
7
- */
8
- export type StatusDotVariant = "open" | "dashed" | "progress" | "filled" | "completed" | "lost";
9
-
10
- export type StatusDef = {
11
- label: string;
12
- tone?: Tone;
13
- /** Any Svelte component, for example a Phosphor icon. Renders inside StatusIcon. */
14
- icon?: Component;
15
- variant?: StatusDotVariant;
16
- /** 0 to 1. Only used by the `progress` variant. */
17
- progress?: number;
18
- /** Optional CSS color. Overrides the tone color for the dot and icon. */
19
- color?: string;
20
- description?: string;
21
- };
22
-
23
- export type StatusMap = Record<string, StatusDef>;
24
-
25
- export type StatusId<M extends StatusMap> = keyof M & string;
26
-
27
- /** What the components accept. `defineStatuses` returns this plus a typed `ids`. */
28
- export type Statuses = {
29
- /** The raw map. Kept loose so a registry with specific keys is assignable here. */
30
- map: StatusMap;
31
- ids: string[];
32
- has(id: string): boolean;
33
- get(id: string): StatusDef | undefined;
34
- label(id: string): string;
35
- tone(id: string): Tone;
36
- icon(id: string): Component | undefined;
37
- variant(id: string): StatusDotVariant;
38
- progress(id: string): number | undefined;
39
- color(id: string): string | undefined;
40
- };
File without changes
File without changes