@heyramzi/ui 2.1.0 → 2.3.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 (317) hide show
  1. package/COMPONENTS.md +1 -1
  2. package/package.json +7 -8
  3. package/scripts/sync-shadcn.mjs +3 -4
  4. package/src/agents/agent-avatar.svelte +604 -575
  5. package/src/agents/agent-cast.svelte +179 -183
  6. package/src/agents/demo.svelte +125 -113
  7. package/src/agents/helpers.ts +23 -17
  8. package/src/agents/index.ts +4 -4
  9. package/src/agents/page-state.ts +6 -6
  10. package/src/agents/types.ts +6 -6
  11. package/src/ai/ai-button/AiButton.svelte +4 -12
  12. package/src/ai/generation-progress/GenerationProgress.svelte +10 -3
  13. package/src/ai/prompt-input/PromptInputTextarea.svelte +1 -2
  14. package/src/ai/response/Response.css +2 -3
  15. package/src/animations/avatar-group-hover.css +2 -16
  16. package/src/animations/card-tilt.css +3 -6
  17. package/src/animations/digit-pop-in.css +2 -15
  18. package/src/animations/dropdown.css +4 -17
  19. package/src/animations/input-clear-dissolve.css +5 -18
  20. package/src/animations/input-shake.css +9 -41
  21. package/src/animations/learn-more-hover.css +17 -9
  22. package/src/animations/like-button.css +2 -4
  23. package/src/animations/page-side-by-side.css +2 -10
  24. package/src/animations/plus-menu-morph.css +2 -5
  25. package/src/animations/shimmer-text.css +5 -18
  26. package/src/animations/spinning-counter.css +2 -6
  27. package/src/animations/success-check.css +2 -15
  28. package/src/animations/thinking-states.css +2 -7
  29. package/src/brand/brand.test.ts +21 -5
  30. package/src/brand/index.ts +4 -10
  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/canvas-cleanup.test.ts +1 -1
  49. package/src/canvas/headless/svg-figure.test.ts +5 -1
  50. package/src/canvas/lod/lod-switch.svelte +111 -106
  51. package/src/canvas/ops/ops.ts +1 -1
  52. package/src/canvas/pen/PenField.svelte +87 -81
  53. package/src/canvas/pen/PenOverlay.svelte +127 -127
  54. package/src/canvas/pen/ShapeNode.svelte +31 -32
  55. package/src/canvas/pen/TextNode.svelte +54 -53
  56. package/src/canvas/pen/host-field.test.svelte +7 -7
  57. package/src/canvas/pen/shapes.ts +7 -1
  58. package/src/canvas/screen/GlyphIcon.svelte +22 -17
  59. package/src/canvas/screen/PartView.svelte +138 -72
  60. package/src/canvas/screen/ScreenBody.svelte +81 -60
  61. package/src/canvas/screen/ScreenCard.svelte +20 -20
  62. package/src/canvas/ui/CanvasToolbar.svelte +173 -85
  63. package/src/canvas/ui/FrameLayer.svelte +59 -59
  64. package/src/canvas/ui/PenLayer.svelte +39 -30
  65. package/src/canvas/ui/StylePanel.svelte +119 -102
  66. package/src/canvas/ui/canvas-grid.svelte +137 -129
  67. package/src/charts/animated-value.svelte +1 -1
  68. package/src/charts/area-chart.css +2 -5
  69. package/src/charts/area-chart.svelte +1 -1
  70. package/src/charts/bar-chart.css +2 -3
  71. package/src/charts/bar-chart.svelte +1 -1
  72. package/src/charts/charts.css +5 -17
  73. package/src/charts/crosshair.svelte +1 -1
  74. package/src/charts/dashboard/dashboard-empty.svelte +25 -25
  75. package/src/charts/dashboard/dashboard-section.svelte +24 -24
  76. package/src/charts/dashboard/data-panel.svelte +50 -50
  77. package/src/charts/dashboard/data-sort-head.svelte +56 -56
  78. package/src/charts/dashboard/data-table.svelte +138 -138
  79. package/src/charts/dashboard/panel-grid.svelte +30 -30
  80. package/src/charts/dashboard/period-filter.svelte +25 -25
  81. package/src/charts/dashboard/rating-chip.svelte +19 -19
  82. package/src/charts/dashboard/stat-band.svelte +32 -32
  83. package/src/charts/dashboard/stat-tile.svelte +106 -99
  84. package/src/charts/donut-chart.svelte +1 -1
  85. package/src/charts/edge-fade.svelte +1 -1
  86. package/src/charts/figure.svelte +1 -1
  87. package/src/charts/gauge-chart.css +4 -7
  88. package/src/charts/gauge-chart.svelte +1 -1
  89. package/src/charts/hover-focus.svelte +1 -1
  90. package/src/charts/legend.css +1 -3
  91. package/src/charts/legend.svelte +1 -1
  92. package/src/charts/line-chart.svelte +1 -1
  93. package/src/charts/number-chart.css +6 -9
  94. package/src/charts/number-chart.svelte +1 -1
  95. package/src/charts/reference-line.svelte +19 -19
  96. package/src/charts/reveal.svelte +1 -1
  97. package/src/charts/ring-chart.css +2 -4
  98. package/src/charts/ring-chart.svelte +1 -1
  99. package/src/charts/sparkline.svelte +5 -2
  100. package/src/charts/stat-card.svelte +1 -1
  101. package/src/charts/time-series-chart.css +2 -5
  102. package/src/charts/trend-pill.css +2 -4
  103. package/src/charts/trend-pill.svelte +1 -1
  104. package/src/components/copy/copy-button.svelte +93 -98
  105. package/src/components/copy/copy-button.test.ts +10 -2
  106. package/src/components/data-table/infinite-scroll.svelte +42 -42
  107. package/src/components/data-table/pagination.svelte +34 -22
  108. package/src/components/data-table/row-arrow.svelte +19 -16
  109. package/src/components/data-table/row-context-menu.svelte +52 -52
  110. package/src/components/data-table/sortable-head.svelte +25 -25
  111. package/src/components/data-table/table-skeleton.svelte +41 -36
  112. package/src/components/docs/doc-page.svelte +18 -9
  113. package/src/components/docs/on-this-page.svelte +16 -3
  114. package/src/components/docs/scroll-spy.svelte.ts +2 -3
  115. package/src/components/field-row/field-row.svelte +10 -8
  116. package/src/components/hold-to-confirm/hold-to-confirm.svelte +5 -1
  117. package/src/components/icon/icon.svelte +14 -14
  118. package/src/components/language-flag/language-flag.svelte +3 -1
  119. package/src/components/list-page/detail-empty.svelte +34 -34
  120. package/src/components/list-page/detail-header.svelte +55 -47
  121. package/src/components/list-page/detail-panel.svelte +51 -59
  122. package/src/components/list-page/detail-row.svelte +19 -19
  123. package/src/components/list-page/detail-stack.svelte +21 -21
  124. package/src/components/list-page/empty-state.svelte +30 -30
  125. package/src/components/list-page/filter-item.svelte +20 -20
  126. package/src/components/list-page/filter-popover.svelte +60 -55
  127. package/src/components/list-page/grouped-list.svelte +4 -2
  128. package/src/components/list-page/index.ts +5 -1
  129. package/src/components/list-page/list-page-shell.svelte +2 -5
  130. package/src/components/list-page/master-detail.svelte +87 -88
  131. package/src/components/list-page/notice-bar.svelte +38 -38
  132. package/src/components/list-page/prev-next.svelte +63 -63
  133. package/src/components/list-page/rail-body.svelte +18 -18
  134. package/src/components/list-page/rail-empty.svelte +23 -30
  135. package/src/components/list-page/rail-head.svelte +24 -24
  136. package/src/components/list-page/rail-row.svelte +77 -73
  137. package/src/components/list-page/section-host.ts +2 -3
  138. package/src/components/locale-switch/locale-switch.svelte +41 -41
  139. package/src/components/mark/mark.svelte +34 -38
  140. package/src/components/open-in/index.ts +1 -5
  141. package/src/components/open-in/open-in.svelte +40 -40
  142. package/src/components/picker/mark-picker.svelte +49 -49
  143. package/src/components/picker/picker.svelte +5 -3
  144. package/src/components/section-header/section-header.test.ts +7 -1
  145. package/src/components/section-header/section-label.svelte +20 -20
  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/index.ts +1 -1
  158. package/src/components/table-view/table-view.svelte +352 -13
  159. package/src/components/table-view/table-view.test.ts +108 -1
  160. package/src/components/table-view/types.ts +22 -11
  161. package/src/components/tags-input/index.ts +13 -0
  162. package/src/components/tags-input/tags-input.svelte +305 -0
  163. package/src/components/tags-input/tags.test.ts +64 -0
  164. package/src/components/tags-input/tags.ts +142 -0
  165. package/src/components/theme/index.ts +2 -4
  166. package/src/components/theme/theme-provider.svelte +1 -3
  167. package/src/components/toolbar/toolbar-search.svelte +25 -25
  168. package/src/components/toolbar/toolbar.svelte +11 -7
  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/icons/trades.ts +1 -1
  191. package/src/inbox/README.md +1 -3
  192. package/src/inbox/inbox.test.ts +181 -138
  193. package/src/inbox/index.ts +20 -20
  194. package/src/inbox/logic.ts +114 -111
  195. package/src/inbox/thread-inbox.svelte +227 -151
  196. package/src/inbox/types.ts +130 -108
  197. package/src/lib/theme-transition.ts +2 -4
  198. package/src/lib/tone.ts +2 -4
  199. package/src/lib/utils.ts +2 -2
  200. package/src/modules.test.ts +79 -69
  201. package/src/onboarding/define-tours.test.ts +55 -40
  202. package/src/onboarding/define-tours.ts +23 -23
  203. package/src/onboarding/demo.svelte +24 -5
  204. package/src/onboarding/index.ts +1 -8
  205. package/src/onboarding/onboarding-provider.svelte +19 -7
  206. package/src/onboarding/onboarding.svelte.ts +16 -16
  207. package/src/onboarding/pick.test.ts +61 -52
  208. package/src/onboarding/pick.ts +16 -13
  209. package/src/onboarding/stores.test.ts +80 -80
  210. package/src/onboarding/stores.ts +41 -39
  211. package/src/onboarding/tour-card.svelte +30 -5
  212. package/src/onboarding/tour-runner.svelte +12 -3
  213. package/src/onboarding/types.ts +20 -12
  214. package/src/onboarding/wait.ts +22 -22
  215. package/src/panel/side-panel.svelte +94 -93
  216. package/src/record/demo-data.ts +291 -225
  217. package/src/record/field-section.svelte +38 -34
  218. package/src/record/fields.ts +148 -96
  219. package/src/record/format.ts +63 -56
  220. package/src/record/index.ts +49 -35
  221. package/src/record/info-list.svelte +145 -114
  222. package/src/record/kinds.ts +31 -31
  223. package/src/record/logic.ts +216 -214
  224. package/src/record/next-up.svelte +45 -34
  225. package/src/record/project-list.svelte +56 -50
  226. package/src/record/record-demo.svelte +130 -110
  227. package/src/record/record-header.svelte +37 -28
  228. package/src/record/record-shell.svelte +54 -54
  229. package/src/record/record-stats.svelte +25 -25
  230. package/src/record/record-timeline.svelte +134 -114
  231. package/src/record/record.test.ts +430 -309
  232. package/src/record/steps-rail.svelte +225 -216
  233. package/src/record/types.ts +234 -215
  234. package/src/record/where-we-are.svelte +62 -58
  235. package/src/shadcn/button/button.svelte +1 -1
  236. package/src/shadcn/card/card-title.svelte +1 -5
  237. package/src/shadcn/hooks/use-highlighted-code.svelte.ts +2 -13
  238. package/src/shadcn/sheet/sheet-content.svelte +2 -4
  239. package/src/shadcn/table/table-cell.svelte +2 -3
  240. package/src/shadcn/utilities.css +3 -8
  241. package/src/slides/Controls.svelte +150 -124
  242. package/src/slides/Deck.svelte +243 -238
  243. package/src/slides/Fragment.svelte +64 -57
  244. package/src/slides/Overview.svelte +106 -101
  245. package/src/slides/Presenter.svelte +300 -266
  246. package/src/slides/Slide.svelte +185 -170
  247. package/src/slides/SlideList.svelte +16 -12
  248. package/src/slides/ambient.d.ts +1 -1
  249. package/src/slides/bridges.ts +42 -23
  250. package/src/slides/deck-controller.svelte.ts +47 -35
  251. package/src/slides/demo-slides.svelte +330 -306
  252. package/src/slides/demo.svelte +164 -160
  253. package/src/slides/export/capture.ts +20 -16
  254. package/src/slides/export/ffmpeg.ts +43 -38
  255. package/src/slides/export/index.ts +5 -5
  256. package/src/slides/export/launch.ts +3 -1
  257. package/src/slides/export/pdf.ts +30 -27
  258. package/src/slides/export/types.ts +10 -8
  259. package/src/slides/index.ts +11 -11
  260. package/src/slides/labels.ts +22 -19
  261. package/src/slides/layout.ts +9 -2
  262. package/src/slides/model.ts +4 -4
  263. package/src/slides/navigation.ts +43 -31
  264. package/src/slides/theme.css +5 -7
  265. package/src/slides/types.ts +9 -10
  266. package/src/status/define-statuses.ts +17 -24
  267. package/src/status/index.ts +5 -5
  268. package/src/status/status-badge.svelte +3 -1
  269. package/src/status/status-dot.svelte +1 -3
  270. package/src/status/status-icon.svelte +1 -1
  271. package/src/status/status-types.ts +21 -21
  272. package/src/tasks/board-order.ts +2 -4
  273. package/src/tasks/demo.svelte +189 -31
  274. package/src/tasks/detail/detail-demo.svelte +73 -13
  275. package/src/tasks/detail/detail-types.ts +45 -45
  276. package/src/tasks/detail/task-detail.svelte +40 -10
  277. package/src/tasks/detail/task-property.svelte +8 -2
  278. package/src/tasks/detail/task-thread.svelte +53 -12
  279. package/src/tasks/gantt/gantt-bar.svelte +17 -6
  280. package/src/tasks/gantt/gantt-grid.svelte +40 -9
  281. package/src/tasks/gantt/gantt-group-row.svelte +8 -2
  282. package/src/tasks/gantt/gantt-header.svelte +9 -3
  283. package/src/tasks/gantt/gantt-task-row.svelte +26 -6
  284. package/src/tasks/gantt/gantt.css +2 -1
  285. package/src/tasks/gantt/gantt.test.ts +3 -1
  286. package/src/tasks/gantt/logic.test.ts +110 -20
  287. package/src/tasks/gantt/logic.ts +42 -6
  288. package/src/tasks/inbox/inbox-card.svelte +13 -5
  289. package/src/tasks/inbox/inbox-draft.svelte +1 -1
  290. package/src/tasks/inbox/inbox-logic.ts +6 -40
  291. package/src/tasks/inbox/inbox-statuses.ts +23 -23
  292. package/src/tasks/inbox/inbox-trace.svelte +9 -3
  293. package/src/tasks/inbox/inbox-types.ts +54 -58
  294. package/src/tasks/inbox/index.ts +22 -21
  295. package/src/tasks/index.ts +49 -52
  296. package/src/tasks/kanban-board.svelte +16 -12
  297. package/src/tasks/kanban-types.ts +2 -3
  298. package/src/tasks/presets/sales.ts +6 -6
  299. package/src/tasks/task-gantt.svelte +28 -8
  300. package/src/tasks/task-list.svelte +41 -17
  301. package/src/tasks/time/duration.ts +40 -40
  302. package/src/tasks/time/time-chip.svelte +9 -2
  303. package/src/tasks/time/time-dot.svelte +1 -1
  304. package/src/tasks/time/time-ring.svelte +11 -3
  305. package/src/tasks/time/time-tracker.svelte +57 -15
  306. package/src/tasks/time/time-types.ts +57 -57
  307. package/src/tasks/use-kanban-dnd.svelte.ts +2 -3
  308. package/src/thread/index.ts +7 -7
  309. package/src/thread/logic.ts +36 -33
  310. package/src/thread/thread.svelte +82 -16
  311. package/src/thread/thread.test.ts +58 -47
  312. package/src/thread/types.ts +68 -68
  313. package/src/tokens/craft.css +17 -53
  314. package/src/tokens/index.css +3 -13
  315. package/src/tokens/palette.css +13 -11
  316. package/src/tokens/primitives.css +10 -23
  317. package/src/tasks/inbox/inbox.svelte +0 -203
@@ -1,53 +1,53 @@
1
1
  <script lang="ts">
2
- // =========================
3
- // IMPORTS
4
- // =========================
5
- import { cn } from "../lib/utils.js";
6
- import { Progress } from "../shadcn/progress/index.js";
7
- import { TONE_TEXT } from "../lib/tone.js";
8
- import StatusBadge from "../status/status-badge.svelte";
9
- import { todayIso } from "../tasks/dates.js";
10
- import { formatMoney, formatRange } from "./format.js";
11
- import {
12
- resolveLabels,
13
- type RecordLabels,
14
- type RecordSummary,
15
- type StageDef,
16
- } from "./types.js";
2
+ // =========================
3
+ // IMPORTS
4
+ // =========================
5
+ import { cn } from "../lib/utils.js";
6
+ import { Progress } from "../shadcn/progress/index.js";
7
+ import { TONE_TEXT } from "../lib/tone.js";
8
+ import StatusBadge from "../status/status-badge.svelte";
9
+ import { todayIso } from "../tasks/dates.js";
10
+ import { formatMoney, formatRange } from "./format.js";
11
+ import {
12
+ resolveLabels,
13
+ type RecordLabels,
14
+ type RecordSummary,
15
+ type StageDef,
16
+ } from "./types.js";
17
17
 
18
- // =========================
19
- // PROPS
20
- // =========================
21
- interface Props {
22
- projects: RecordSummary[];
23
- /** The agency's stages: each project draws its stage's label and tone. */
24
- stages: StageDef[];
25
- /** A project being looked at, marked in the list. */
26
- activeId?: string | null;
27
- /** Money shown when a project has none of its own. */
28
- currency?: string;
29
- labels?: Partial<RecordLabels>;
30
- locale?: string;
31
- /** ISO date. Decides "late". Defaults to the viewer's today. */
32
- today?: string;
33
- class?: string;
34
- }
35
- let {
36
- projects,
37
- stages,
38
- activeId = null,
39
- currency = "EUR",
40
- labels,
41
- locale,
42
- today = todayIso(),
43
- class: className,
44
- }: Props = $props();
18
+ // =========================
19
+ // PROPS
20
+ // =========================
21
+ interface Props {
22
+ projects: RecordSummary[];
23
+ /** The agency's stages: each project draws its stage's label and tone. */
24
+ stages: StageDef[];
25
+ /** A project being looked at, marked in the list. */
26
+ activeId?: string | null;
27
+ /** Money shown when a project has none of its own. */
28
+ currency?: string;
29
+ labels?: Partial<RecordLabels>;
30
+ locale?: string;
31
+ /** ISO date. Decides "late". Defaults to the viewer's today. */
32
+ today?: string;
33
+ class?: string;
34
+ }
35
+ let {
36
+ projects,
37
+ stages,
38
+ activeId = null,
39
+ currency = "EUR",
40
+ labels,
41
+ locale,
42
+ today = todayIso(),
43
+ class: className,
44
+ }: Props = $props();
45
45
 
46
- // =========================
47
- // DERIVED
48
- // =========================
49
- let t = $derived(resolveLabels(labels));
50
- let stageByKey = $derived(new Map(stages.map((s) => [s.key, s])));
46
+ // =========================
47
+ // DERIVED
48
+ // =========================
49
+ let t = $derived(resolveLabels(labels));
50
+ let stageByKey = $derived(new Map(stages.map((s) => [s.key, s])));
51
51
  </script>
52
52
 
53
53
  <!-- =========================== -->
@@ -67,7 +67,9 @@ let stageByKey = $derived(new Map(stages.map((s) => [s.key, s])));
67
67
  </span>
68
68
  <span class="flex flex-wrap items-center gap-x-2 gap-y-1">
69
69
  <StatusBadge tone={stage?.tone ?? "neutral"} dot capitalize={false}>
70
- {stage ? stage.label : project.stageKey}{project.stageDetail ? ` · ${project.stageDetail}` : ""}
70
+ {stage ? stage.label : project.stageKey}{project.stageDetail
71
+ ? ` · ${project.stageDetail}`
72
+ : ""}
71
73
  </StatusBadge>
72
74
  {#if project.whereWeAre?.health}
73
75
  <StatusBadge tone={project.whereWeAre.health.tone} capitalize={false}>
@@ -76,7 +78,9 @@ let stageByKey = $derived(new Map(stages.map((s) => [s.key, s])));
76
78
  {/if}
77
79
  </span>
78
80
  {#if project.whereWeAre?.text}
79
- <span class="line-clamp-2 text-xs leading-snug text-muted-foreground">{project.whereWeAre.text}</span>
81
+ <span class="line-clamp-2 text-xs leading-snug text-muted-foreground"
82
+ >{project.whereWeAre.text}</span
83
+ >
80
84
  {/if}
81
85
  {#if project.progress && project.progress.total > 0}
82
86
  <span class="flex items-center gap-2">
@@ -96,7 +100,9 @@ let stageByKey = $derived(new Map(stages.map((s) => [s.key, s])));
96
100
  <span class="flex flex-wrap items-baseline gap-x-2 text-xs text-muted-foreground">
97
101
  <span>{t.next}</span>
98
102
  {#if next.date}
99
- <span class={cn("tabular-nums", late && TONE_TEXT.warning)}>{formatRange(next.date, next.endDate, locale)}</span>
103
+ <span class={cn("tabular-nums", late && TONE_TEXT.warning)}
104
+ >{formatRange(next.date, next.endDate, locale)}</span
105
+ >
100
106
  {/if}
101
107
  <span class="min-w-0 truncate text-foreground">{next.label}</span>
102
108
  </span>
@@ -1,117 +1,130 @@
1
1
  <script lang="ts">
2
- // =========================
3
- // IMPORTS
4
- // =========================
5
- import { DotsThree, NotePencil } from "phosphor-svelte";
6
- import { SegmentedFilter } from "../components/segmented/index.js";
7
- import { Button } from "../shadcn/button/index.js";
8
- import { Input } from "../shadcn/input/index.js";
9
- import * as Tabs from "../shadcn/tabs/index.js";
10
- import RecordShell from "./record-shell.svelte";
11
- import RecordHeader from "./record-header.svelte";
12
- import WhereWeAre from "./where-we-are.svelte";
13
- import NextUp from "./next-up.svelte";
14
- import RecordStats from "./record-stats.svelte";
15
- import StepsRail from "./steps-rail.svelte";
16
- import RecordTimeline from "./record-timeline.svelte";
17
- import ProjectList from "./project-list.svelte";
18
- import FieldSection from "./field-section.svelte";
19
- import InfoList from "./info-list.svelte";
20
- import { formatAge, formatMoney, formatRange } from "./format.js";
21
- import {
22
- latestWhereWeAre,
23
- mergeClientEvents,
24
- nextAcrossProjects,
25
- rollupProjects,
26
- stepProgress,
27
- } from "./logic.js";
28
- import type { FieldValue, RecordEvent, StepDef } from "./types.js";
29
- import {
30
- DEMO_NOW,
31
- DEMO_TODAY,
32
- clientFields,
33
- clientOnlyEvents,
34
- clientProjects,
35
- clientSections,
36
- clientValues,
37
- projectFields,
38
- projectSections,
39
- stages,
40
- stepGroups,
41
- website,
42
- websiteEvents,
43
- websiteSteps,
44
- websiteValues,
45
- } from "./demo-data.js";
2
+ // =========================
3
+ // IMPORTS
4
+ // =========================
5
+ import { DotsThree, NotePencil } from "phosphor-svelte";
6
+ import { SegmentedFilter } from "../components/segmented/index.js";
7
+ import { Button } from "../shadcn/button/index.js";
8
+ import { Input } from "../shadcn/input/index.js";
9
+ import * as Tabs from "../shadcn/tabs/index.js";
10
+ import RecordShell from "./record-shell.svelte";
11
+ import RecordHeader from "./record-header.svelte";
12
+ import WhereWeAre from "./where-we-are.svelte";
13
+ import NextUp from "./next-up.svelte";
14
+ import RecordStats from "./record-stats.svelte";
15
+ import StepsRail from "./steps-rail.svelte";
16
+ import RecordTimeline from "./record-timeline.svelte";
17
+ import ProjectList from "./project-list.svelte";
18
+ import FieldSection from "./field-section.svelte";
19
+ import InfoList from "./info-list.svelte";
20
+ import { formatAge, formatMoney, formatRange } from "./format.js";
21
+ import {
22
+ latestWhereWeAre,
23
+ mergeClientEvents,
24
+ nextAcrossProjects,
25
+ rollupProjects,
26
+ stepProgress,
27
+ } from "./logic.js";
28
+ import type { FieldValue, RecordEvent, StepDef } from "./types.js";
29
+ import {
30
+ DEMO_NOW,
31
+ DEMO_TODAY,
32
+ clientFields,
33
+ clientOnlyEvents,
34
+ clientProjects,
35
+ clientSections,
36
+ clientValues,
37
+ projectFields,
38
+ projectSections,
39
+ stages,
40
+ stepGroups,
41
+ website,
42
+ websiteEvents,
43
+ websiteSteps,
44
+ websiteValues,
45
+ } from "./demo-data.js";
46
46
 
47
- // =========================
48
- // STATE
49
- // =========================
50
- type Fixture = "project" | "client";
51
- let fixture = $state<Fixture>("project");
52
- let narrow = $state(false);
53
- let tab = $state<"activity" | "notes">("activity");
54
- let filter = $state("all");
55
- let steps = $state<StepDef[]>(structuredClone(websiteSteps));
56
- let activeStep = $state<string | null>("s2");
57
- let projectValues = $state<Record<string, FieldValue | undefined>>({ ...websiteValues });
58
- let personValues = $state<Record<string, FieldValue | undefined>>({ ...clientValues });
59
- let extra = $state<RecordEvent[]>([]);
60
- let draftNote = $state("");
61
- let railOpen = $state(false);
47
+ // =========================
48
+ // STATE
49
+ // =========================
50
+ type Fixture = "project" | "client";
51
+ let fixture = $state<Fixture>("project");
52
+ let narrow = $state(false);
53
+ let tab = $state<"activity" | "notes">("activity");
54
+ let filter = $state("all");
55
+ let steps = $state<StepDef[]>(structuredClone(websiteSteps));
56
+ let activeStep = $state<string | null>("s2");
57
+ let projectValues = $state<Record<string, FieldValue | undefined>>({ ...websiteValues });
58
+ let personValues = $state<Record<string, FieldValue | undefined>>({ ...clientValues });
59
+ let extra = $state<RecordEvent[]>([]);
60
+ let draftNote = $state("");
61
+ let railOpen = $state(false);
62
62
 
63
- // =========================
64
- // DERIVED
65
- // =========================
66
- const locale = "en-GB";
67
- let projectEvents = $derived([...extra, ...websiteEvents]);
68
- let clientEvents = $derived(
69
- mergeClientEvents(
70
- clientOnlyEvents,
71
- clientProjects.map((p) => ({
72
- id: p.summary.id,
73
- name: p.summary.name,
74
- href: p.summary.href,
75
- events: p.events,
76
- })),
77
- ),
78
- );
79
- let summaries = $derived(clientProjects.map((p) => p.summary));
80
- let rollup = $derived(rollupProjects(summaries, stages));
81
- let latest = $derived(latestWhereWeAre(summaries));
82
- let next = $derived(nextAcrossProjects(summaries, stages));
83
- let progress = $derived(stepProgress(steps));
84
- let notes = $derived(projectEvents.filter((e) => e.kind === "note"));
85
- let stage = $derived(stages.find((s) => s.key === website.stageKey));
63
+ // =========================
64
+ // DERIVED
65
+ // =========================
66
+ const locale = "en-GB";
67
+ let projectEvents = $derived([...extra, ...websiteEvents]);
68
+ let clientEvents = $derived(
69
+ mergeClientEvents(
70
+ clientOnlyEvents,
71
+ clientProjects.map((p) => ({
72
+ id: p.summary.id,
73
+ name: p.summary.name,
74
+ href: p.summary.href,
75
+ events: p.events,
76
+ })),
77
+ ),
78
+ );
79
+ let summaries = $derived(clientProjects.map((p) => p.summary));
80
+ let rollup = $derived(rollupProjects(summaries, stages));
81
+ let latest = $derived(latestWhereWeAre(summaries));
82
+ let next = $derived(nextAcrossProjects(summaries, stages));
83
+ let progress = $derived(stepProgress(steps));
84
+ let notes = $derived(projectEvents.filter((e) => e.kind === "note"));
85
+ let stage = $derived(stages.find((s) => s.key === website.stageKey));
86
86
 
87
- let clientStats = $derived.by(() => {
88
- const eur = rollup.totals.EUR;
89
- return [
90
- { label: "Projects", value: String(rollup.count), sub: `${rollup.activeCount} active` },
91
- { label: "Pipeline", value: formatMoney(eur?.pipeline ?? 0, "EUR", locale, true) },
92
- { label: "Won", value: formatMoney(eur?.won ?? 0, "EUR", locale, true) },
93
- { label: "Paid", value: formatMoney(eur?.paid ?? 0, "EUR", locale, true), tone: "good" as const },
94
- { label: "Last call", value: rollup.lastCallAt ? formatAge(rollup.lastCallAt, DEMO_NOW, locale) : "None yet" },
95
- ];
96
- });
87
+ let clientStats = $derived.by(() => {
88
+ const eur = rollup.totals.EUR;
89
+ return [
90
+ { label: "Projects", value: String(rollup.count), sub: `${rollup.activeCount} active` },
91
+ { label: "Pipeline", value: formatMoney(eur?.pipeline ?? 0, "EUR", locale, true) },
92
+ { label: "Won", value: formatMoney(eur?.won ?? 0, "EUR", locale, true) },
93
+ {
94
+ label: "Paid",
95
+ value: formatMoney(eur?.paid ?? 0, "EUR", locale, true),
96
+ tone: "good" as const,
97
+ },
98
+ {
99
+ label: "Last call",
100
+ value: rollup.lastCallAt ? formatAge(rollup.lastCallAt, DEMO_NOW, locale) : "None yet",
101
+ },
102
+ ];
103
+ });
97
104
 
98
- // =========================
99
- // FUNCTIONS
100
- // =========================
101
- function addNote() {
102
- const title = draftNote.trim();
103
- if (!title) return;
104
- extra = [
105
- { id: `n${extra.length}`, kind: "note", occurredAt: DEMO_NOW.toISOString(), title, actor: "Ramzi" },
106
- ...extra,
107
- ];
108
- draftNote = "";
109
- }
105
+ // =========================
106
+ // FUNCTIONS
107
+ // =========================
108
+ function addNote() {
109
+ const title = draftNote.trim();
110
+ if (!title) return;
111
+ extra = [
112
+ {
113
+ id: `n${extra.length}`,
114
+ kind: "note",
115
+ occurredAt: DEMO_NOW.toISOString(),
116
+ title,
117
+ actor: "Ramzi",
118
+ },
119
+ ...extra,
120
+ ];
121
+ draftNote = "";
122
+ }
110
123
 
111
- // A real host would round-trip here. The pause lets the rail show its optimistic order.
112
- async function pause() {
113
- await new Promise((resolve) => setTimeout(resolve, 250));
114
- }
124
+ // A real host would round-trip here. The pause lets the rail show its optimistic order.
125
+ async function pause() {
126
+ await new Promise((resolve) => setTimeout(resolve, 250));
127
+ }
115
128
  </script>
116
129
 
117
130
  <!-- =========================== -->
@@ -125,7 +138,12 @@ async function pause() {
125
138
  addNote();
126
139
  }}
127
140
  >
128
- <Input bind:value={draftNote} placeholder="Write a note" aria-label="Write a note" class="flex-1" />
141
+ <Input
142
+ bind:value={draftNote}
143
+ placeholder="Write a note"
144
+ aria-label="Write a note"
145
+ class="flex-1"
146
+ />
129
147
  <Button type="submit" variant="outline" disabled={!draftNote.trim()}>
130
148
  <NotePencil data-icon="inline-start" />
131
149
  Add
@@ -188,7 +206,9 @@ async function pause() {
188
206
  ]}
189
207
  >
190
208
  {#snippet actions()}
191
- <Button variant="ghost" size="sm" icon aria-label="More actions"><DotsThree weight="bold" /></Button>
209
+ <Button variant="ghost" size="sm" icon aria-label="More actions"
210
+ ><DotsThree weight="bold" /></Button
211
+ >
192
212
  {/snippet}
193
213
  </RecordHeader>
194
214
  {/snippet}
@@ -1,33 +1,42 @@
1
1
  <script lang="ts">
2
- // =========================
3
- // IMPORTS
4
- // =========================
5
- import type { Snippet } from "svelte";
6
- import { CaretLeft } from "phosphor-svelte";
7
- import { cn } from "../lib/utils.js";
8
- import type { Tone } from "../lib/tone.js";
9
- import StatusBadge from "../status/status-badge.svelte";
10
- import { gutterClass } from "./gutter.js";
2
+ // =========================
3
+ // IMPORTS
4
+ // =========================
5
+ import type { Snippet } from "svelte";
6
+ import { CaretLeft } from "phosphor-svelte";
7
+ import { cn } from "../lib/utils.js";
8
+ import type { Tone } from "../lib/tone.js";
9
+ import StatusBadge from "../status/status-badge.svelte";
10
+ import { gutterClass } from "./gutter.js";
11
11
 
12
- // =========================
13
- // PROPS
14
- // =========================
15
- interface Props {
16
- title: string;
17
- /** A mark drawn before the title: a logo, an avatar. */
18
- logo?: Snippet;
19
- /** The stage, in the agency's own word and the tone of its category. */
20
- stage?: { label: string; tone: Tone; detail?: string | null } | null;
21
- /** What this record sits under, such as the client of a project. */
22
- parent?: { label: string; href: string } | null;
23
- /** Quiet facts after the stage: a value, dates. */
24
- facts?: string[];
25
- actions?: Snippet;
26
- /** Under the title row, for a stat strip. */
27
- children?: Snippet;
28
- class?: string;
29
- }
30
- let { title, logo, stage, parent, facts = [], actions, children, class: className }: Props = $props();
12
+ // =========================
13
+ // PROPS
14
+ // =========================
15
+ interface Props {
16
+ title: string;
17
+ /** A mark drawn before the title: a logo, an avatar. */
18
+ logo?: Snippet;
19
+ /** The stage, in the agency's own word and the tone of its category. */
20
+ stage?: { label: string; tone: Tone; detail?: string | null } | null;
21
+ /** What this record sits under, such as the client of a project. */
22
+ parent?: { label: string; href: string } | null;
23
+ /** Quiet facts after the stage: a value, dates. */
24
+ facts?: string[];
25
+ actions?: Snippet;
26
+ /** Under the title row, for a stat strip. */
27
+ children?: Snippet;
28
+ class?: string;
29
+ }
30
+ let {
31
+ title,
32
+ logo,
33
+ stage,
34
+ parent,
35
+ facts = [],
36
+ actions,
37
+ children,
38
+ class: className,
39
+ }: Props = $props();
31
40
  </script>
32
41
 
33
42
  <!-- =========================== -->
@@ -1,60 +1,60 @@
1
1
  <script lang="ts" generics="T extends string = string">
2
- // =========================
3
- // IMPORTS
4
- // =========================
5
- import type { Snippet } from "svelte";
6
- import { CaretRight } from "phosphor-svelte";
7
- import { cn } from "../lib/utils.js";
8
- import { AnimatedTabs, type TabDef } from "../components/segmented/index.js";
9
- import * as Sheet from "../shadcn/sheet/index.js";
10
- import { Progress } from "../shadcn/progress/index.js";
11
- import { gutterClass } from "./gutter.js";
12
- import { resolveLabels, type RecordLabels } from "./types.js";
2
+ // =========================
3
+ // IMPORTS
4
+ // =========================
5
+ import type { Snippet } from "svelte";
6
+ import { CaretRight } from "phosphor-svelte";
7
+ import { cn } from "../lib/utils.js";
8
+ import { AnimatedTabs, type TabDef } from "../components/segmented/index.js";
9
+ import * as Sheet from "../shadcn/sheet/index.js";
10
+ import { Progress } from "../shadcn/progress/index.js";
11
+ import { gutterClass } from "./gutter.js";
12
+ import { resolveLabels, type RecordLabels } from "./types.js";
13
13
 
14
- // =========================
15
- // PROPS
16
- // =========================
17
- interface Props {
18
- header: Snippet;
19
- /** Where we are, next up, stats: whatever sits between the header and the body. */
20
- banner?: Snippet;
21
- /** The tab row. Put each panel in a `Tabs.Content` from `@heyramzi/ui/shadcn/tabs`. */
22
- tabs?: readonly TabDef<T>[];
23
- tab?: T;
24
- tabsLabel?: string;
25
- /** The side rail. Docked at 48rem and wider, a sheet behind one row under that. */
26
- rail?: Snippet;
27
- /** The sheet's title, read out by screen readers. Defaults to the steps label. */
28
- railTitle?: string;
29
- /** Fills the narrow row's bar. Leave it out for a row with no progress. */
30
- railProgress?: { done: number; total: number } | null;
31
- railOpen?: boolean;
32
- children: Snippet;
33
- labels?: Partial<RecordLabels>;
34
- class?: string;
35
- }
36
- let {
37
- header,
38
- banner,
39
- tabs,
40
- tab = $bindable(),
41
- tabsLabel,
42
- rail,
43
- railTitle,
44
- railProgress = null,
45
- railOpen = $bindable(false),
46
- children,
47
- labels,
48
- class: className,
49
- }: Props = $props();
14
+ // =========================
15
+ // PROPS
16
+ // =========================
17
+ interface Props {
18
+ header: Snippet;
19
+ /** Where we are, next up, stats: whatever sits between the header and the body. */
20
+ banner?: Snippet;
21
+ /** The tab row. Put each panel in a `Tabs.Content` from `@heyramzi/ui/shadcn/tabs`. */
22
+ tabs?: readonly TabDef<T>[];
23
+ tab?: T;
24
+ tabsLabel?: string;
25
+ /** The side rail. Docked at 48rem and wider, a sheet behind one row under that. */
26
+ rail?: Snippet;
27
+ /** The sheet's title, read out by screen readers. Defaults to the steps label. */
28
+ railTitle?: string;
29
+ /** Fills the narrow row's bar. Leave it out for a row with no progress. */
30
+ railProgress?: { done: number; total: number } | null;
31
+ railOpen?: boolean;
32
+ children: Snippet;
33
+ labels?: Partial<RecordLabels>;
34
+ class?: string;
35
+ }
36
+ let {
37
+ header,
38
+ banner,
39
+ tabs,
40
+ tab = $bindable(),
41
+ tabsLabel,
42
+ rail,
43
+ railTitle,
44
+ railProgress = null,
45
+ railOpen = $bindable(false),
46
+ children,
47
+ labels,
48
+ class: className,
49
+ }: Props = $props();
50
50
 
51
- // =========================
52
- // DERIVED
53
- // =========================
54
- let t = $derived(resolveLabels(labels));
55
- let percent = $derived(
56
- railProgress && railProgress.total > 0 ? (railProgress.done / railProgress.total) * 100 : 0,
57
- );
51
+ // =========================
52
+ // DERIVED
53
+ // =========================
54
+ let t = $derived(resolveLabels(labels));
55
+ let percent = $derived(
56
+ railProgress && railProgress.total > 0 ? (railProgress.done / railProgress.total) * 100 : 0,
57
+ );
58
58
  </script>
59
59
 
60
60
  <!-- =========================== -->
@@ -1,31 +1,31 @@
1
1
  <script lang="ts">
2
- // =========================
3
- // IMPORTS
4
- // =========================
5
- import { cn } from "../lib/utils.js";
6
- import type { PanelStat } from "../panel/side-panel-types.js";
7
- import { gutterClass } from "./gutter.js";
2
+ // =========================
3
+ // IMPORTS
4
+ // =========================
5
+ import { cn } from "../lib/utils.js";
6
+ import type { PanelStat } from "../panel/side-panel-types.js";
7
+ import { gutterClass } from "./gutter.js";
8
8
 
9
- // =========================
10
- // PROPS
11
- // =========================
12
- interface Props {
13
- stats: PanelStat[];
14
- /** Sits flush with the record's gutter. Off inside a card. */
15
- gutter?: boolean;
16
- class?: string;
17
- }
18
- let { stats, gutter = true, class: className }: Props = $props();
9
+ // =========================
10
+ // PROPS
11
+ // =========================
12
+ interface Props {
13
+ stats: PanelStat[];
14
+ /** Sits flush with the record's gutter. Off inside a card. */
15
+ gutter?: boolean;
16
+ class?: string;
17
+ }
18
+ let { stats, gutter = true, class: className }: Props = $props();
19
19
 
20
- // =========================
21
- // DERIVED
22
- // =========================
23
- const TONE = {
24
- default: "",
25
- muted: "text-muted-foreground",
26
- good: "text-success",
27
- bad: "text-destructive",
28
- } as const;
20
+ // =========================
21
+ // DERIVED
22
+ // =========================
23
+ const TONE = {
24
+ default: "",
25
+ muted: "text-muted-foreground",
26
+ good: "text-success",
27
+ bad: "text-destructive",
28
+ } as const;
29
29
  </script>
30
30
 
31
31
  <!-- =========================== -->