@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
@@ -12,43 +12,57 @@ export { default as InfoList } from "./info-list.svelte";
12
12
  export { DEFAULT_RECORD_FILTERS, DEFAULT_RECORD_KINDS } from "./kinds.js";
13
13
  export { DEFAULT_RECORD_LABELS, resolveLabels } from "./types.js";
14
14
  export {
15
- activeProjects,
16
- dayRelation,
17
- eventsForFilter,
18
- filterCounts,
19
- foldGroups,
20
- groupEventsByDay,
21
- groupSteps,
22
- latestWhereWeAre,
23
- localDay,
24
- mergeClientEvents,
25
- nextAcrossProjects,
26
- nudgeStep,
27
- reorderIds,
28
- rollupProjects,
29
- stepMarkers,
30
- stepProgress,
15
+ activeProjects,
16
+ dayRelation,
17
+ eventsForFilter,
18
+ filterCounts,
19
+ foldGroups,
20
+ groupEventsByDay,
21
+ groupSteps,
22
+ latestWhereWeAre,
23
+ localDay,
24
+ mergeClientEvents,
25
+ nextAcrossProjects,
26
+ nudgeStep,
27
+ reorderIds,
28
+ rollupProjects,
29
+ stepMarkers,
30
+ stepProgress,
31
31
  } from "./logic.js";
32
- export { fieldRow, groupFields, isFieldVisible, parseSaved, pickableOptions } from "./fields.js";
32
+ export {
33
+ fieldRow,
34
+ groupFields,
35
+ isFieldVisible,
36
+ parseSaved,
37
+ pickableOptions,
38
+ } from "./fields.js";
33
39
  export { formatAge, formatDay, formatMoney, formatRange } from "./format.js";
34
- export type { ClientRollup, DayGroup, LatestStatus, MoneyTotals, ProjectEvents } from "./logic.js";
40
+ export type {
41
+ ClientRollup,
42
+ DayGroup,
43
+ LatestStatus,
44
+ MoneyTotals,
45
+ ProjectEvents,
46
+ } from "./logic.js";
35
47
  export type { FieldValues } from "./fields.js";
36
48
  export type {
37
- FieldDef,
38
- FieldOption,
39
- FieldSectionDef,
40
- FieldType,
41
- FieldValue,
42
- InfoRow,
43
- RecordEvent,
44
- RecordFilterDef,
45
- RecordKindDef,
46
- RecordLabels,
47
- RecordNext,
48
- RecordSummary,
49
- StageCategory,
50
- StageDef,
51
- StepDef,
52
- StepGroupDef,
53
- StepMarker,
49
+ FieldDef,
50
+ FieldOption,
51
+ FieldSectionDef,
52
+ TagsConfig,
53
+ FieldType,
54
+ FieldTypes,
55
+ FieldValue,
56
+ InfoRow,
57
+ RecordEvent,
58
+ RecordFilterDef,
59
+ RecordKindDef,
60
+ RecordLabels,
61
+ RecordNext,
62
+ RecordSummary,
63
+ StageCategory,
64
+ StageDef,
65
+ StepDef,
66
+ StepGroupDef,
67
+ StepMarker,
54
68
  } from "./types.js";
@@ -1,127 +1,135 @@
1
1
  <script lang="ts">
2
- // =========================
3
- // IMPORTS
4
- // =========================
5
- import { Check, CaretUpDown } from "phosphor-svelte";
6
- import { cn } from "../../lib/utils.js";
7
- import { Button } from "../../shadcn/button/index.js";
8
- import { Input } from "../../shadcn/input/index.js";
9
- import { Textarea } from "../../shadcn/textarea/index.js";
10
- import { Spinner } from "../../shadcn/spinner/index.js";
11
- import * as Select from "../../shadcn/select/index.js";
12
- import * as Popover from "../../shadcn/popover/index.js";
13
- import * as Command from "../../shadcn/command/index.js";
14
- import StatusBadge from "../status-badge.svelte";
15
- import { resolveLabels, type InfoRow, type RecordLabels } from "./types.js";
2
+ // =========================
3
+ // IMPORTS
4
+ // =========================
5
+ import { Check, CaretUpDown } from "phosphor-svelte";
6
+ import { cn } from "../lib/utils.js";
7
+ import { Button } from "../shadcn/button/index.js";
8
+ import { Input } from "../shadcn/input/index.js";
9
+ import { Textarea } from "../shadcn/textarea/index.js";
10
+ import { Spinner } from "../shadcn/spinner/index.js";
11
+ import * as Select from "../shadcn/select/index.js";
12
+ import * as Popover from "../shadcn/popover/index.js";
13
+ import * as Command from "../shadcn/command/index.js";
14
+ import { TagsInput } from "../components/tags-input/index.js";
15
+ import StatusBadge from "../status/status-badge.svelte";
16
+ import { resolveLabels, type InfoRow, type RecordLabels } from "./types.js";
16
17
 
17
- // =========================
18
- // PROPS
19
- // =========================
20
- interface Props {
21
- rows: InfoRow[];
22
- /** A heading over the list. Left out, nothing is drawn. */
23
- title?: string | null;
24
- labels?: Partial<RecordLabels>;
25
- class?: string;
26
- }
27
- let { rows, title = null, labels, class: className }: Props = $props();
28
-
29
- // =========================
30
- // STATE
31
- // =========================
32
- let editing = $state<string | null>(null);
33
- let draft = $state("");
34
- let saving = $state<string | null>(null);
35
- let failed = $state<{ key: string; text: string } | null>(null);
36
- let pickerOpen = $state<string | null>(null);
18
+ // =========================
19
+ // PROPS
20
+ // =========================
21
+ interface Props {
22
+ rows: InfoRow[];
23
+ /** A heading over the list. Left out, nothing is drawn. */
24
+ title?: string | null;
25
+ labels?: Partial<RecordLabels>;
26
+ class?: string;
27
+ }
28
+ let { rows, title = null, labels, class: className }: Props = $props();
37
29
 
38
- // =========================
39
- // DERIVED
40
- // =========================
41
- let t = $derived(resolveLabels(labels));
42
- // A read-only row with nothing in it is noise. An editable one stays, as the way to fill it.
43
- let shown = $derived(
44
- rows.filter(
45
- (r) => r.divider || r.onSave || (r.value != null && r.value !== "") || (r.chips?.length ?? 0) > 0,
46
- ),
47
- );
48
- // Past this many options a plain list is slower than typing.
49
- const SEARCH_AT = 7;
30
+ // =========================
31
+ // STATE
32
+ // =========================
33
+ let editing = $state<string | null>(null);
34
+ let draft = $state("");
35
+ let saving = $state<string | null>(null);
36
+ let failed = $state<{ key: string; text: string } | null>(null);
37
+ let pickerOpen = $state<string | null>(null);
50
38
 
51
- // =========================
52
- // FUNCTIONS
53
- // =========================
54
- const keyOf = (row: InfoRow) => row.id ?? row.label;
39
+ // =========================
40
+ // DERIVED
41
+ // =========================
42
+ let t = $derived(resolveLabels(labels));
43
+ // A read-only row with nothing in it is noise. An editable one stays, as the way to fill it.
44
+ let shown = $derived(
45
+ rows.filter(
46
+ (r) =>
47
+ r.divider || r.onSave || (r.value != null && r.value !== "") || (r.chips?.length ?? 0) > 0,
48
+ ),
49
+ );
50
+ // Past this many options a plain list is slower than typing.
51
+ const SEARCH_AT = 7;
55
52
 
56
- function isEmpty(row: InfoRow): boolean {
57
- return (row.value == null || row.value === "") && (row.chips?.length ?? 0) === 0;
58
- }
53
+ // =========================
54
+ // FUNCTIONS
55
+ // =========================
56
+ const keyOf = (row: InfoRow) => row.id ?? row.label;
59
57
 
60
- function inputType(row: InfoRow): string {
61
- return row.input === "date" || row.input === "number" || row.input === "url" || row.input === "email"
62
- ? row.input
63
- : "text";
64
- }
58
+ function isEmpty(row: InfoRow): boolean {
59
+ return (row.value == null || row.value === "") && (row.chips?.length ?? 0) === 0;
60
+ }
65
61
 
66
- function begin(row: InfoRow) {
67
- editing = keyOf(row);
68
- failed = null;
69
- const from = row.editValue ?? row.value ?? "";
70
- draft = Array.isArray(from) ? from.join(", ") : String(from);
71
- }
62
+ function inputType(row: InfoRow): string {
63
+ return row.input === "date" ||
64
+ row.input === "number" ||
65
+ row.input === "url" ||
66
+ row.input === "email"
67
+ ? row.input
68
+ : "text";
69
+ }
72
70
 
73
- function stop() {
74
- editing = null;
75
- failed = null;
76
- draft = "";
77
- }
71
+ function begin(row: InfoRow) {
72
+ editing = keyOf(row);
73
+ failed = null;
74
+ const from = row.editValue ?? row.value ?? "";
75
+ draft = Array.isArray(from) ? from.join(", ") : String(from);
76
+ }
78
77
 
79
- async function commit(row: InfoRow, value: string | string[], close = true) {
80
- if (!row.onSave) return;
81
- const key = keyOf(row);
82
- const next = Array.isArray(value) ? value : value.trim();
83
- if (row.required && (Array.isArray(next) ? next.length === 0 : next === "")) {
84
- failed = { key, text: t.required };
85
- return;
78
+ function stop() {
79
+ editing = null;
80
+ failed = null;
81
+ draft = "";
86
82
  }
87
- saving = key;
88
- failed = null;
89
- try {
90
- await row.onSave(next);
91
- if (close) stop();
92
- } catch {
93
- failed = { key, text: t.saveFailed };
94
- } finally {
95
- saving = null;
83
+
84
+ async function commit(row: InfoRow, value: string | string[], close = true) {
85
+ if (!row.onSave) return;
86
+ const key = keyOf(row);
87
+ const next = Array.isArray(value) ? value : value.trim();
88
+ if (row.required && (Array.isArray(next) ? next.length === 0 : next === "")) {
89
+ failed = { key, text: t.required };
90
+ return;
91
+ }
92
+ saving = key;
93
+ failed = null;
94
+ try {
95
+ await row.onSave(next);
96
+ if (close) stop();
97
+ } catch {
98
+ failed = { key, text: t.saveFailed };
99
+ } finally {
100
+ saving = null;
101
+ }
96
102
  }
97
- }
98
103
 
99
- function pick(row: InfoRow, value: string) {
100
- pickerOpen = null;
101
- const current = typeof row.editValue === "string" ? row.editValue : null;
102
- if (value !== current) void commit(row, value, false);
103
- }
104
+ function pick(row: InfoRow, value: string) {
105
+ pickerOpen = null;
106
+ const current = typeof row.editValue === "string" ? row.editValue : null;
107
+ if (value !== current) void commit(row, value, false);
108
+ }
104
109
 
105
- function toggle(row: InfoRow, value: string) {
106
- const current = Array.isArray(row.editValue) ? row.editValue : [];
107
- const next = current.includes(value) ? current.filter((v) => v !== value) : [...current, value];
108
- void commit(row, next, false);
109
- }
110
+ function toggle(row: InfoRow, value: string) {
111
+ const current = Array.isArray(row.editValue) ? row.editValue : [];
112
+ const next = current.includes(value) ? current.filter((v) => v !== value) : [...current, value];
113
+ void commit(row, next, false);
114
+ }
110
115
 
111
- // Enter saves a line. A long text keeps Enter for the line break and saves on Cmd or Ctrl.
112
- function onKey(event: KeyboardEvent, row: InfoRow) {
113
- if (event.key === "Escape") {
114
- event.preventDefault();
115
- stop();
116
- } else if (event.key === "Enter" && (row.input !== "longtext" || event.metaKey || event.ctrlKey)) {
117
- event.preventDefault();
118
- void commit(row, draft);
116
+ // Enter saves a line. A long text keeps Enter for the line break and saves on Cmd or Ctrl.
117
+ function onKey(event: KeyboardEvent, row: InfoRow) {
118
+ if (event.key === "Escape") {
119
+ event.preventDefault();
120
+ stop();
121
+ } else if (
122
+ event.key === "Enter" &&
123
+ (row.input !== "longtext" || event.metaKey || event.ctrlKey)
124
+ ) {
125
+ event.preventDefault();
126
+ void commit(row, draft);
127
+ }
119
128
  }
120
- }
121
129
 
122
- // The ghost button that opens an editor reads as text until hovered, so a read
123
- // of the record isn't a page of controls.
124
- const OPENER = "-ml-1.5 max-w-full px-1.5 text-sm font-medium";
130
+ // The ghost button that opens an editor reads as text until hovered, so a read
131
+ // of the record isn't a page of controls.
132
+ const OPENER = "-ml-1.5 max-w-full px-1.5 text-sm font-medium";
125
133
  </script>
126
134
 
127
135
  <!-- =========================== -->
@@ -137,8 +145,9 @@ const OPENER = "-ml-1.5 max-w-full px-1.5 text-sm font-medium";
137
145
  {:else if row.tone && row.value}
138
146
  <StatusBadge tone={row.tone} capitalize={false}>{row.value}</StatusBadge>
139
147
  {:else if row.href && row.value}
140
- <a href={row.href} class="min-w-0 truncate text-sm font-medium underline-offset-2 hover:underline"
141
- >{row.value}</a
148
+ <a
149
+ href={row.href}
150
+ class="min-w-0 truncate text-sm font-medium underline-offset-2 hover:underline">{row.value}</a
142
151
  >
143
152
  {:else if row.value}
144
153
  <span
@@ -191,7 +200,10 @@ const OPENER = "-ml-1.5 max-w-full px-1.5 text-sm font-medium";
191
200
  onSelect={() => (multi ? toggle(row, option.value) : pick(row, option.value))}
192
201
  >
193
202
  <Check
194
- class={cn("size-3.5", current.includes(option.value) ? "opacity-100" : "opacity-0")}
203
+ class={cn(
204
+ "size-3.5",
205
+ current.includes(option.value) ? "opacity-100" : "opacity-0",
206
+ )}
195
207
  />
196
208
  {option.label}
197
209
  </Command.Item>
@@ -208,7 +220,9 @@ const OPENER = "-ml-1.5 max-w-full px-1.5 text-sm font-medium";
208
220
  {#if title}
209
221
  <h2 class="text-xs font-medium tracking-wide text-muted-foreground uppercase">{title}</h2>
210
222
  {/if}
211
- <dl class="grid grid-cols-[minmax(5rem,max-content)_minmax(0,1fr)] items-start gap-x-4 gap-y-2.5">
223
+ <dl
224
+ class="grid grid-cols-[minmax(5rem,max-content)_minmax(0,1fr)] items-start gap-x-4 gap-y-2.5"
225
+ >
212
226
  {#each shown as row, index (row.divider ? `divider-${index}` : keyOf(row))}
213
227
  {#if row.divider}
214
228
  <div class="col-span-2 -my-0.5 border-t border-border/50"></div>
@@ -227,9 +241,24 @@ const OPENER = "-ml-1.5 max-w-full px-1.5 text-sm font-medium";
227
241
  {/if}
228
242
  {row.label}
229
243
  </dt>
230
- <dd class={cn("flex min-h-7 min-w-0 flex-col justify-center gap-1", long && "col-span-2 -mt-1")}>
244
+ <dd
245
+ class={cn(
246
+ "flex min-h-7 min-w-0 flex-col justify-center gap-1",
247
+ long && "col-span-2 -mt-1",
248
+ )}
249
+ >
231
250
  {#if !row.onSave}
232
251
  {@render display(row)}
252
+ {:else if row.input === "tags" && row.tags}
253
+ <TagsInput
254
+ value={Array.isArray(row.editValue) ? row.editValue : []}
255
+ options={row.tags.options}
256
+ allowCreate={row.tags.allowCreate}
257
+ max={row.tags.max}
258
+ label={t.edit(row.label)}
259
+ labels={{ add: t.add(row.label), none: t.noMatch }}
260
+ onchange={(next) => commit(row, next, false)}
261
+ />
233
262
  {:else if row.input === "multi" && row.options}
234
263
  {@render list(row, key, true)}
235
264
  {:else if row.input === "select" && row.options && row.options.length > SEARCH_AT}
@@ -255,7 +284,9 @@ const OPENER = "-ml-1.5 max-w-full px-1.5 text-sm font-medium";
255
284
  </Select.Trigger>
256
285
  <Select.Content>
257
286
  {#each row.options as option (option.value)}
258
- <Select.Item value={option.value} label={option.label}>{option.label}</Select.Item>
287
+ <Select.Item value={option.value} label={option.label}
288
+ >{option.label}</Select.Item
289
+ >
259
290
  {/each}
260
291
  </Select.Content>
261
292
  </Select.Root>
@@ -0,0 +1,42 @@
1
+ import {
2
+ CheckCircle,
3
+ ClipboardText,
4
+ CurrencyCircleDollar,
5
+ EnvelopeSimple,
6
+ File,
7
+ Flag,
8
+ Gavel,
9
+ NavigationArrow,
10
+ NotePencil,
11
+ Phone,
12
+ Receipt,
13
+ Signpost,
14
+ UsersThree,
15
+ } from "phosphor-svelte";
16
+ import type { RecordFilterDef, RecordKindDef } from "./types.js";
17
+
18
+ /** The kit's event kinds, drawn in plain English. A module adds its own beside them. */
19
+ export const DEFAULT_RECORD_KINDS: RecordKindDef[] = [
20
+ { key: "call", label: "Call", icon: Phone },
21
+ { key: "meeting", label: "Meeting", icon: UsersThree },
22
+ { key: "email", label: "Email", icon: EnvelopeSimple },
23
+ { key: "form", label: "Form", icon: ClipboardText },
24
+ { key: "note", label: "Note", icon: NotePencil },
25
+ { key: "status", label: "Where we are", icon: NavigationArrow },
26
+ { key: "stage", label: "Stage", icon: Signpost },
27
+ { key: "task.done", label: "Task done", icon: CheckCircle, tone: "success" },
28
+ { key: "milestone.done", label: "Step done", icon: Flag, tone: "success" },
29
+ { key: "invoice.sent", label: "Invoice", icon: Receipt },
30
+ { key: "payment", label: "Payment", icon: CurrencyCircleDollar, tone: "success" },
31
+ { key: "decision", label: "Decision", icon: Gavel },
32
+ { key: "file", label: "File", icon: File },
33
+ ];
34
+
35
+ /** The chips over the timeline. Kinds a record has none of are not drawn. */
36
+ export const DEFAULT_RECORD_FILTERS: RecordFilterDef[] = [
37
+ { key: "calls", label: "Calls", kinds: ["call", "meeting"] },
38
+ { key: "notes", label: "Notes", kinds: ["note"] },
39
+ { key: "money", label: "Money", kinds: ["invoice.sent", "payment"] },
40
+ { key: "stage", label: "Stage", kinds: ["stage"] },
41
+ { key: "status", label: "Status", kinds: ["status"] },
42
+ ];