@heyramzi/ui 2.11.1 → 2.11.2

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 (266) hide show
  1. package/dist/agents/helpers.js +38 -38
  2. package/dist/agents/page-state.js +49 -50
  3. package/dist/agents/vendor/color.js +146 -127
  4. package/dist/agents/vendor/draw.js +617 -508
  5. package/dist/agents/vendor/engine.js +698 -599
  6. package/dist/agents/vendor/mesh.js +653 -683
  7. package/dist/agents/vendor/plastic.js +3913 -3112
  8. package/dist/agents/vendor/presets.js +163 -164
  9. package/dist/agents/vendor/shapes.js +21 -20
  10. package/dist/agents/vendor/ticker.js +41 -42
  11. package/dist/agents/vendor/types.js +1 -0
  12. package/dist/agents/vendor/wear.js +1421 -1448
  13. package/dist/ai/confirmation/confirmation-context.svelte.js +6 -6
  14. package/dist/ai/confirmation/index.js +3 -1
  15. package/dist/ai/index.js +33 -0
  16. package/dist/ai/prompt-input/index.js +3 -1
  17. package/dist/ai/reasoning/index.js +3 -1
  18. package/dist/ai/reasoning/reasoning-context.svelte.js +6 -6
  19. package/dist/ai/suggestion/index.js +3 -1
  20. package/dist/ai/typing-dots/index.js +3 -1
  21. package/dist/animations/text-swap.js +24 -24
  22. package/dist/brand/index.js +54 -48
  23. package/dist/canvas/card/resize.js +5 -3
  24. package/dist/canvas/edges/edge-path.js +255 -242
  25. package/dist/canvas/editor/context-menu.js +39 -36
  26. package/dist/canvas/editor/dispatch.svelte.js +154 -151
  27. package/dist/canvas/editor/editor-context.js +7 -2
  28. package/dist/canvas/editor/editor-mode.js +1 -0
  29. package/dist/canvas/editor/frame.js +73 -76
  30. package/dist/canvas/editor/hand-context.js +5 -2
  31. package/dist/canvas/editor/history-core.js +163 -191
  32. package/dist/canvas/editor/keymap.js +95 -169
  33. package/dist/canvas/editor/layout-actions.js +143 -144
  34. package/dist/canvas/editor/lock.js +52 -51
  35. package/dist/canvas/editor/rebase.js +217 -240
  36. package/dist/canvas/editor/style.js +132 -137
  37. package/dist/canvas/editor/text-field-context.js +7 -2
  38. package/dist/canvas/editor/z-order.js +65 -70
  39. package/dist/canvas/headless/alignment.js +22 -16
  40. package/dist/canvas/headless/break-apart-find.js +286 -279
  41. package/dist/canvas/headless/break-apart-pieces.js +62 -58
  42. package/dist/canvas/headless/break-apart-plan.js +299 -325
  43. package/dist/canvas/headless/break-apart-style.js +75 -70
  44. package/dist/canvas/headless/break-apart.js +188 -181
  45. package/dist/canvas/headless/canvas-cleanup.js +78 -58
  46. package/dist/canvas/headless/edge-anchors.js +115 -116
  47. package/dist/canvas/headless/edge-memo.js +24 -22
  48. package/dist/canvas/headless/edge-serialization.js +17 -27
  49. package/dist/canvas/headless/figure-geometry.js +232 -264
  50. package/dist/canvas/headless/fit-viewport.js +84 -67
  51. package/dist/canvas/headless/grid.js +88 -86
  52. package/dist/canvas/headless/icon-node.js +44 -36
  53. package/dist/canvas/headless/index.js +1 -0
  54. package/dist/canvas/headless/linkify.js +17 -19
  55. package/dist/canvas/headless/pen-marks.js +101 -95
  56. package/dist/canvas/headless/sketch.js +231 -209
  57. package/dist/canvas/headless/snap-guides.js +99 -83
  58. package/dist/canvas/headless/svg-figure.js +133 -117
  59. package/dist/canvas/headless/table-layout.js +146 -107
  60. package/dist/canvas/index.js +2 -0
  61. package/dist/canvas/lod/lod-mode.svelte.js +20 -18
  62. package/dist/canvas/lod/render-all.svelte.js +36 -39
  63. package/dist/canvas/ops/arrange.js +78 -71
  64. package/dist/canvas/ops/ops.js +260 -255
  65. package/dist/canvas/pen/colors.js +37 -35
  66. package/dist/canvas/pen/eraser.js +28 -27
  67. package/dist/canvas/pen/geometry.js +120 -130
  68. package/dist/canvas/pen/index.js +1 -0
  69. package/dist/canvas/pen/ops.js +11 -11
  70. package/dist/canvas/pen/pen-session.js +150 -159
  71. package/dist/canvas/pen/plugin.js +107 -104
  72. package/dist/canvas/pen/shapes.js +73 -68
  73. package/dist/canvas/pen/stroke-path.js +32 -30
  74. package/dist/canvas/pen/types.js +21 -21
  75. package/dist/canvas/pen/ui.js +10 -8
  76. package/dist/canvas/plugin.js +46 -46
  77. package/dist/canvas/screen/glyphs.js +12 -11
  78. package/dist/canvas/screen/labels.js +22 -22
  79. package/dist/canvas/screen/parts.js +98 -111
  80. package/dist/canvas/screen/plugin.js +47 -56
  81. package/dist/canvas/screen/types.js +30 -35
  82. package/dist/canvas/screen/ui.js +7 -7
  83. package/dist/canvas/test-utils.js +14 -14
  84. package/dist/canvas/types.js +1 -0
  85. package/dist/canvas/ui/forward-wheel.js +24 -25
  86. package/dist/canvas/ui/icons.js +64 -131
  87. package/dist/canvas/ui/place-panel.js +58 -49
  88. package/dist/canvas/ui/shortcut-tip.js +14 -12
  89. package/dist/canvas/ui/tools.js +300 -385
  90. package/dist/charts/dashboard/chart.js +4 -0
  91. package/dist/charts/dashboard/data-table.js +11 -0
  92. package/dist/charts/dashboard/windows.js +8 -3
  93. package/dist/charts/edge-fade.js +10 -5
  94. package/dist/charts/hover-band.js +16 -11
  95. package/dist/charts/index.js +0 -1
  96. package/dist/charts/motion.js +11 -7
  97. package/dist/charts/primitives/chart-utils.js +12 -12
  98. package/dist/components/copy/clipboard.js +32 -32
  99. package/dist/components/copy/copied.svelte.js +31 -23
  100. package/dist/components/data-table/data-table.js +39 -39
  101. package/dist/components/docs/index.js +4 -0
  102. package/dist/components/docs/scroll-spy.svelte.js +73 -68
  103. package/dist/components/list-page/filter-section.js +4 -1
  104. package/dist/components/list-page/index.js +2 -0
  105. package/dist/components/list-page/list-table.js +7 -2
  106. package/dist/components/list-page/queue-rail.js +14 -0
  107. package/dist/components/list-page/section-host.js +4 -2
  108. package/dist/components/list-page/step.js +4 -3
  109. package/dist/components/list-page/types.js +1 -0
  110. package/dist/components/picker/trigger.js +48 -30
  111. package/dist/components/picker/types.js +1 -0
  112. package/dist/components/segmented/collapse.js +38 -27
  113. package/dist/components/segmented/index.js +8 -0
  114. package/dist/components/segmented/segmented.js +67 -42
  115. package/dist/components/star-rating-input/index.js +3 -1
  116. package/dist/components/table-view/types.js +1 -0
  117. package/dist/components/tags-input/tags.js +81 -69
  118. package/dist/components/theme/index.js +4 -0
  119. package/dist/components/toolbar/index.js +4 -0
  120. package/dist/components/toolbar/toolbar-trigger.js +14 -1
  121. package/dist/editor/anchors.js +17 -13
  122. package/dist/editor/block-id.js +52 -51
  123. package/dist/editor/block-ops.js +108 -80
  124. package/dist/editor/doc-blocks.js +155 -166
  125. package/dist/editor/extensions.js +139 -180
  126. package/dist/editor/index.js +4 -0
  127. package/dist/editor/markdown-test-helpers.js +4 -2
  128. package/dist/editor/markdown.js +420 -408
  129. package/dist/editor/serializer.js +204 -200
  130. package/dist/editor/slash-items.js +89 -101
  131. package/dist/editor/youtube-url.js +25 -20
  132. package/dist/effects/animated-beam/path-calculator.svelte.js +43 -38
  133. package/dist/effects/animated-beam/types.js +1 -0
  134. package/dist/effects/border-beam/css.js +92 -78
  135. package/dist/effects/border-beam/presets.js +1705 -1720
  136. package/dist/effects/border-beam/register-properties.js +43 -33
  137. package/dist/effects/border-beam/types.js +1 -0
  138. package/dist/effects/image-comparison/compare.js +3 -2
  139. package/dist/effects/image-reveal/types.js +1 -0
  140. package/dist/effects/magnetic/magnetic.js +58 -52
  141. package/dist/effects/reveal/observe.js +50 -40
  142. package/dist/effects/reveal/types.js +1 -0
  143. package/dist/effects/shader-gradient/color.js +36 -29
  144. package/dist/effects/shader-gradient/renderer.js +384 -295
  145. package/dist/effects/shader-gradient/shaders.js +31 -0
  146. package/dist/effects/shader-gradient/types.js +1 -0
  147. package/dist/icons/apple-symbol-exports.js +99 -124
  148. package/dist/icons/sf-symbols.js +357 -461
  149. package/dist/icons/trades.js +43 -28
  150. package/dist/inbox/index.js +1 -0
  151. package/dist/inbox/logic.js +126 -122
  152. package/dist/inbox/types.js +43 -43
  153. package/dist/lib/arrive.js +19 -12
  154. package/dist/lib/icon-types.js +1 -0
  155. package/dist/lib/initials.js +16 -10
  156. package/dist/lib/layout.js +5 -0
  157. package/dist/lib/panel.js +13 -0
  158. package/dist/lib/result.js +22 -22
  159. package/dist/lib/sliding-pill.js +59 -44
  160. package/dist/lib/theme-transition.js +43 -43
  161. package/dist/lib/tone.js +31 -24
  162. package/dist/lib/utils.js +3 -1
  163. package/dist/onboarding/define-tours.js +24 -23
  164. package/dist/onboarding/onboarding.svelte.js +16 -12
  165. package/dist/onboarding/pick.js +10 -6
  166. package/dist/onboarding/stores.js +40 -41
  167. package/dist/onboarding/wait.js +24 -23
  168. package/dist/panel/side-panel-types.js +1 -0
  169. package/dist/record/demo-data.js +459 -486
  170. package/dist/record/fields.js +129 -131
  171. package/dist/record/format.js +70 -82
  172. package/dist/record/gutter.js +1 -0
  173. package/dist/record/kinds.js +95 -105
  174. package/dist/record/logic.js +238 -219
  175. package/dist/record/types.js +49 -48
  176. package/dist/shadcn/accordion/index.js +3 -1
  177. package/dist/shadcn/alert/index.js +3 -1
  178. package/dist/shadcn/alert-dialog/index.js +3 -1
  179. package/dist/shadcn/attachment/index.js +3 -1
  180. package/dist/shadcn/avatar/index.js +3 -1
  181. package/dist/shadcn/breadcrumb/index.js +3 -1
  182. package/dist/shadcn/bubble/index.js +3 -1
  183. package/dist/shadcn/button/index.js +3 -1
  184. package/dist/shadcn/calendar/index.js +3 -1
  185. package/dist/shadcn/card/index.js +3 -1
  186. package/dist/shadcn/checkbox/index.js +3 -1
  187. package/dist/shadcn/code-block/index.js +3 -1
  188. package/dist/shadcn/collapsible/index.js +3 -1
  189. package/dist/shadcn/command/index.js +4 -1
  190. package/dist/shadcn/context-menu/index.js +3 -1
  191. package/dist/shadcn/dialog/index.js +3 -1
  192. package/dist/shadcn/dropdown-menu/menu-item.js +40 -20
  193. package/dist/shadcn/empty/index.js +3 -1
  194. package/dist/shadcn/field/index.js +3 -1
  195. package/dist/shadcn/hooks/highlighter.js +77 -75
  196. package/dist/shadcn/hooks/is-mobile.svelte.js +3 -3
  197. package/dist/shadcn/hooks/use-highlighted-code.svelte.js +62 -62
  198. package/dist/shadcn/input/index.js +3 -1
  199. package/dist/shadcn/kbd/index.js +3 -1
  200. package/dist/shadcn/label/index.js +3 -1
  201. package/dist/shadcn/marker/index.js +3 -1
  202. package/dist/shadcn/message/index.js +3 -1
  203. package/dist/shadcn/message-scroller/index.js +3 -1
  204. package/dist/shadcn/popover/index.js +3 -1
  205. package/dist/shadcn/progress/index.js +3 -1
  206. package/dist/shadcn/progress/tone.js +8 -7
  207. package/dist/shadcn/radio-group/index.js +3 -1
  208. package/dist/shadcn/scroll-area/index.js +3 -1
  209. package/dist/shadcn/select/index.js +3 -1
  210. package/dist/shadcn/separator/index.js +3 -1
  211. package/dist/shadcn/sheet/index.js +3 -1
  212. package/dist/shadcn/sidebar/context.svelte.js +42 -28
  213. package/dist/shadcn/sidebar/index.js +3 -1
  214. package/dist/shadcn/skeleton/index.js +3 -1
  215. package/dist/shadcn/slider/index.js +3 -1
  216. package/dist/shadcn/switch/index.js +3 -1
  217. package/dist/shadcn/table/index.js +3 -1
  218. package/dist/shadcn/tabs/index.js +3 -1
  219. package/dist/shadcn/textarea/index.js +3 -1
  220. package/dist/shadcn/toggle/index.js +3 -1
  221. package/dist/shadcn/toggle-group/index.js +3 -1
  222. package/dist/shadcn/tooltip/context.js +7 -2
  223. package/dist/shadcn/tooltip/index.js +3 -1
  224. package/dist/shadcn/trace/index.js +3 -1
  225. package/dist/slides/bridges.js +65 -59
  226. package/dist/slides/deck-controller.svelte.js +210 -207
  227. package/dist/slides/export/capture.js +66 -71
  228. package/dist/slides/export/ffmpeg.js +76 -72
  229. package/dist/slides/export/index.js +3 -0
  230. package/dist/slides/export/launch.js +9 -6
  231. package/dist/slides/export/pdf.js +60 -54
  232. package/dist/slides/export/types.js +1 -0
  233. package/dist/slides/labels.js +24 -24
  234. package/dist/slides/layout.js +39 -41
  235. package/dist/slides/model.js +9 -7
  236. package/dist/slides/navigation.js +78 -73
  237. package/dist/slides/types.js +2 -2
  238. package/dist/status/define-statuses.js +18 -14
  239. package/dist/status/status-types.js +1 -0
  240. package/dist/test-setup.js +24 -20
  241. package/dist/thread/logic.js +73 -77
  242. package/dist/thread/types.js +21 -21
  243. package/dist/work/board-order.js +94 -90
  244. package/dist/work/dates.js +16 -9
  245. package/dist/work/detail/detail-types.js +18 -18
  246. package/dist/work/docs/edited.js +32 -29
  247. package/dist/work/docs/index.js +4 -0
  248. package/dist/work/docs/labels.js +34 -34
  249. package/dist/work/docs/menu.js +113 -106
  250. package/dist/work/docs/outline.js +39 -29
  251. package/dist/work/gantt/logic.js +211 -235
  252. package/dist/work/inbox/inbox-logic.js +71 -75
  253. package/dist/work/inbox/inbox-statuses.js +75 -72
  254. package/dist/work/inbox/inbox-types.js +1 -0
  255. package/dist/work/kanban-drag.js +27 -22
  256. package/dist/work/kanban-types.js +1 -0
  257. package/dist/work/presets/sales.js +36 -32
  258. package/dist/work/reorder.js +9 -8
  259. package/dist/work/task-types.js +1 -0
  260. package/dist/work/time/duration.js +51 -46
  261. package/dist/work/time/time-types.js +23 -23
  262. package/dist/work/use-kanban-dnd.svelte.js +126 -125
  263. package/package.json +3 -1
  264. package/src/components/list-page/master-detail.svelte +3 -1
  265. package/src/components/list-page/rail-row.svelte +4 -4
  266. package/src/editor/markdown.ts +30 -35
@@ -1,86 +1,89 @@
1
1
  import { defineStatuses } from "../../status/define-statuses.js";
2
2
  import { ClipboardText, EnvelopeSimple, Hash, Phone } from "phosphor-svelte";
3
+ /** The lifecycle of an item. The dot and the badge both read this one map. */
3
4
  export const inboxStates = defineStatuses({
4
- proposed: {
5
- label: "Needs you",
6
- tone: "warning",
7
- variant: "open"
8
- },
9
- working: {
10
- label: "Agent working",
11
- tone: "accent",
12
- variant: "progress",
13
- progress: 0.6
14
- },
15
- approved: {
16
- label: "Approved",
17
- tone: "success",
18
- variant: "completed"
19
- },
20
- declined: {
21
- label: "Declined",
22
- tone: "neutral",
23
- variant: "lost"
24
- },
25
- done: {
26
- label: "Done by agent",
27
- tone: "success",
28
- variant: "completed"
29
- },
30
- undone: {
31
- label: "Undone",
32
- tone: "neutral",
33
- variant: "lost"
34
- }
5
+ proposed: {
6
+ label: "Needs you",
7
+ tone: "warning",
8
+ variant: "open"
9
+ },
10
+ working: {
11
+ label: "Agent working",
12
+ tone: "accent",
13
+ variant: "progress",
14
+ progress: .6
15
+ },
16
+ approved: {
17
+ label: "Approved",
18
+ tone: "success",
19
+ variant: "completed"
20
+ },
21
+ declined: {
22
+ label: "Declined",
23
+ tone: "neutral",
24
+ variant: "lost"
25
+ },
26
+ done: {
27
+ label: "Done by agent",
28
+ tone: "success",
29
+ variant: "completed"
30
+ },
31
+ undone: {
32
+ label: "Undone",
33
+ tone: "neutral",
34
+ variant: "lost"
35
+ }
35
36
  });
37
+ /** What the agent made of the touchpoint. */
36
38
  export const inboxKinds = defineStatuses({
37
- information: {
38
- label: "Information",
39
- tone: "info",
40
- variant: "filled"
41
- },
42
- action: {
43
- label: "Action",
44
- tone: "accent",
45
- variant: "filled"
46
- },
47
- decision: {
48
- label: "Decision",
49
- tone: "warning",
50
- variant: "filled"
51
- }
39
+ information: {
40
+ label: "Information",
41
+ tone: "info",
42
+ variant: "filled"
43
+ },
44
+ action: {
45
+ label: "Action",
46
+ tone: "accent",
47
+ variant: "filled"
48
+ },
49
+ decision: {
50
+ label: "Decision",
51
+ tone: "warning",
52
+ variant: "filled"
53
+ }
52
54
  });
55
+ /** How sure the agent is, bucketed. The dot's fill carries the exact score. */
53
56
  export const inboxConfidence = defineStatuses({
54
- high: {
55
- label: "Confident",
56
- tone: "success",
57
- variant: "progress"
58
- },
59
- medium: {
60
- label: "Unsure",
61
- tone: "warning",
62
- variant: "progress"
63
- },
64
- low: {
65
- label: "Guessing",
66
- tone: "destructive",
67
- variant: "progress"
68
- }
57
+ high: {
58
+ label: "Confident",
59
+ tone: "success",
60
+ variant: "progress"
61
+ },
62
+ medium: {
63
+ label: "Unsure",
64
+ tone: "warning",
65
+ variant: "progress"
66
+ },
67
+ low: {
68
+ label: "Guessing",
69
+ tone: "destructive",
70
+ variant: "progress"
71
+ }
69
72
  });
70
73
  export function confidenceLevel(score) {
71
- if (score >= 0.8) return "high";
72
- if (score >= 0.5) return "medium";
73
- return "low";
74
+ if (score >= .8) return "high";
75
+ if (score >= .5) return "medium";
76
+ return "low";
74
77
  }
75
78
  export const SOURCE_ICON = {
76
- call: Phone,
77
- email: EnvelopeSimple,
78
- slack: Hash,
79
- form: ClipboardText
79
+ call: Phone,
80
+ email: EnvelopeSimple,
81
+ slack: Hash,
82
+ form: ClipboardText
80
83
  };
81
84
  export const SOURCE_LABEL = {
82
- call: "Call",
83
- email: "Email",
84
- slack: "Slack",
85
- form: "Form"
85
+ call: "Call",
86
+ email: "Email",
87
+ slack: "Slack",
88
+ form: "Form"
86
89
  };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,25 +1,30 @@
1
1
  const FRAME_PAD = 16;
2
+ /**
3
+ * Native drag shows a flat, faded snapshot. This hands the browser a tilted
4
+ * copy with a lifted shadow instead. Call it from `ondragstart`.
5
+ */
2
6
  export function liftDragImage(e, tilt = -3) {
3
- const source = e.currentTarget;
4
- if (!source || !e.dataTransfer) return;
5
- const rect = source.getBoundingClientRect();
6
- const frame = document.createElement("div");
7
- Object.assign(frame.style, {
8
- position: "fixed",
9
- top: "-10000px",
10
- left: "-10000px",
11
- padding: `${FRAME_PAD}px`,
12
- pointerEvents: "none"
13
- });
14
- const ghost = source.cloneNode(true);
15
- Object.assign(ghost.style, {
16
- width: `${rect.width}px`,
17
- opacity: "1",
18
- rotate: `${tilt}deg`,
19
- filter: "drop-shadow(0 2px 4px rgb(35 35 35 / 0.08)) drop-shadow(0 10px 18px rgb(35 35 35 / 0.14))"
20
- });
21
- frame.appendChild(ghost);
22
- document.body.appendChild(frame);
23
- e.dataTransfer.setDragImage(frame, e.clientX - rect.left + FRAME_PAD, e.clientY - rect.top + FRAME_PAD);
24
- setTimeout(()=>frame.remove());
7
+ const source = e.currentTarget;
8
+ if (!source || !e.dataTransfer) return;
9
+ const rect = source.getBoundingClientRect();
10
+ // The padded frame leaves room for the tilt and shadow, or the snapshot crops them.
11
+ const frame = document.createElement("div");
12
+ Object.assign(frame.style, {
13
+ position: "fixed",
14
+ top: "-10000px",
15
+ left: "-10000px",
16
+ padding: `${FRAME_PAD}px`,
17
+ pointerEvents: "none"
18
+ });
19
+ const ghost = source.cloneNode(true);
20
+ Object.assign(ghost.style, {
21
+ width: `${rect.width}px`,
22
+ opacity: "1",
23
+ rotate: `${tilt}deg`,
24
+ filter: "drop-shadow(0 2px 4px rgb(35 35 35 / 0.08)) drop-shadow(0 10px 18px rgb(35 35 35 / 0.14))"
25
+ });
26
+ frame.appendChild(ghost);
27
+ document.body.appendChild(frame);
28
+ e.dataTransfer.setDragImage(frame, e.clientX - rect.left + FRAME_PAD, e.clientY - rect.top + FRAME_PAD);
29
+ setTimeout(() => frame.remove());
25
30
  }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,35 +1,39 @@
1
1
  import { defineStatuses } from "../../status/define-statuses.js";
2
+ /**
3
+ * An example status map for a sales pipeline. Names are neutral on purpose:
4
+ * swap the keys and labels for your own domain.
5
+ */
2
6
  export const salesStatuses = defineStatuses({
3
- new: {
4
- label: "New",
5
- tone: "accent",
6
- variant: "open"
7
- },
8
- contacted: {
9
- label: "Contacted",
10
- tone: "info",
11
- variant: "open"
12
- },
13
- proposal: {
14
- label: "Proposal",
15
- tone: "accent",
16
- variant: "progress",
17
- progress: 0.25
18
- },
19
- negotiation: {
20
- label: "Negotiation",
21
- tone: "warning",
22
- variant: "progress",
23
- progress: 0.75
24
- },
25
- won: {
26
- label: "Won",
27
- tone: "success",
28
- variant: "completed"
29
- },
30
- lost: {
31
- label: "Lost",
32
- tone: "destructive",
33
- variant: "lost"
34
- }
7
+ new: {
8
+ label: "New",
9
+ tone: "accent",
10
+ variant: "open"
11
+ },
12
+ contacted: {
13
+ label: "Contacted",
14
+ tone: "info",
15
+ variant: "open"
16
+ },
17
+ proposal: {
18
+ label: "Proposal",
19
+ tone: "accent",
20
+ variant: "progress",
21
+ progress: .25
22
+ },
23
+ negotiation: {
24
+ label: "Negotiation",
25
+ tone: "warning",
26
+ variant: "progress",
27
+ progress: .75
28
+ },
29
+ won: {
30
+ label: "Won",
31
+ tone: "success",
32
+ variant: "completed"
33
+ },
34
+ lost: {
35
+ label: "Lost",
36
+ tone: "destructive",
37
+ variant: "lost"
38
+ }
35
39
  });
@@ -1,10 +1,11 @@
1
+ /** Move `activeId` to `overId`'s index. Returns a copy; unknown ids pass through. */
1
2
  export function reorderByIds(items, activeId, overId) {
2
- const activeIndex = items.findIndex((item)=>item.id === activeId);
3
- const overIndex = items.findIndex((item)=>item.id === overId);
4
- if (activeIndex === -1 || overIndex === -1 || activeIndex === overIndex) {
5
- return items.slice();
6
- }
7
- const next = items.slice();
8
- next.splice(overIndex, 0, ...next.splice(activeIndex, 1));
9
- return next;
3
+ const activeIndex = items.findIndex((item) => item.id === activeId);
4
+ const overIndex = items.findIndex((item) => item.id === overId);
5
+ if (activeIndex === -1 || overIndex === -1 || activeIndex === overIndex) {
6
+ return items.slice();
7
+ }
8
+ const next = items.slice();
9
+ next.splice(overIndex, 0, ...next.splice(activeIndex, 1));
10
+ return next;
10
11
  }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,60 +1,65 @@
1
+ /** "90", "45m", "1h", "1.5h", "1h30", "1h 30m" and "1:30" to whole minutes. Null when it isn't a duration. */
1
2
  export function parseMinutes(text) {
2
- const value = text.trim().toLowerCase();
3
- if (!value) return null;
4
- if (/^\d+$/.test(value)) return Number(value);
5
- const clock = /^(\d+):([0-5]?\d)$/.exec(value);
6
- if (clock) return Number(clock[1]) * 60 + Number(clock[2]);
7
- const decimalHours = /^(\d+(?:[.,]\d+)?)\s*h$/.exec(value);
8
- if (decimalHours?.[1]) return Math.round(Number(decimalHours[1].replace(",", ".")) * 60);
9
- const parts = /^(?:(\d+)\s*h)?\s*(?:(\d+)\s*m?)?$/.exec(value);
10
- if (!parts || !parts[1] && !parts[2]) return null;
11
- return Number(parts[1] ?? 0) * 60 + Number(parts[2] ?? 0);
3
+ const value = text.trim().toLowerCase();
4
+ if (!value) return null;
5
+ if (/^\d+$/.test(value)) return Number(value);
6
+ const clock = /^(\d+):([0-5]?\d)$/.exec(value);
7
+ if (clock) return Number(clock[1]) * 60 + Number(clock[2]);
8
+ const decimalHours = /^(\d+(?:[.,]\d+)?)\s*h$/.exec(value);
9
+ if (decimalHours?.[1]) return Math.round(Number(decimalHours[1].replace(",", ".")) * 60);
10
+ const parts = /^(?:(\d+)\s*h)?\s*(?:(\d+)\s*m?)?$/.exec(value);
11
+ if (!parts || !parts[1] && !parts[2]) return null;
12
+ return Number(parts[1] ?? 0) * 60 + Number(parts[2] ?? 0);
12
13
  }
14
+ /** 150 to "2h 30m". */
13
15
  export function formatMinutes(minutes) {
14
- const whole = Math.max(0, Math.round(Number.isFinite(minutes) ? minutes : 0));
15
- const hours = Math.floor(whole / 60);
16
- const rest = whole % 60;
17
- if (hours === 0) return `${rest}m`;
18
- return rest === 0 ? `${hours}h` : `${hours}h ${rest}m`;
16
+ const whole = Math.max(0, Math.round(Number.isFinite(minutes) ? minutes : 0));
17
+ const hours = Math.floor(whole / 60);
18
+ const rest = whole % 60;
19
+ if (hours === 0) return `${rest}m`;
20
+ return rest === 0 ? `${hours}h` : `${hours}h ${rest}m`;
19
21
  }
22
+ /** Milliseconds to the timer readout, "1:05:09". */
20
23
  export function formatClock(ms) {
21
- const total = Math.max(0, Math.floor(ms / 1000));
22
- return {
23
- hours: String(Math.floor(total / 3600)),
24
- minutes: String(Math.floor(total % 3600 / 60)).padStart(2, "0"),
25
- seconds: String(total % 60).padStart(2, "0")
26
- };
24
+ const total = Math.max(0, Math.floor(ms / 1e3));
25
+ return {
26
+ hours: String(Math.floor(total / 3600)),
27
+ minutes: String(Math.floor(total % 3600 / 60)).padStart(2, "0"),
28
+ seconds: String(total % 60).padStart(2, "0")
29
+ };
27
30
  }
31
+ /** The reader's own calendar day as `YYYY-MM-DD`. */
28
32
  export function localDay(date = new Date()) {
29
- const month = String(date.getMonth() + 1).padStart(2, "0");
30
- const day = String(date.getDate()).padStart(2, "0");
31
- return `${date.getFullYear()}-${month}-${day}`;
33
+ const month = String(date.getMonth() + 1).padStart(2, "0");
34
+ const day = String(date.getDate()).padStart(2, "0");
35
+ return `${date.getFullYear()}-${month}-${day}`;
32
36
  }
37
+ /** "Today", "Yesterday", then "Mon, Oct 12", in the given locale. */
33
38
  export function dayLabel(day, locale) {
34
- const date = new Date(`${day}T12:00:00`);
35
- const now = new Date();
36
- now.setHours(12, 0, 0, 0);
37
- const gap = Math.round((date.getTime() - now.getTime()) / 86_400_000);
38
- if (gap === 0 || gap === -1) {
39
- const word = new Intl.RelativeTimeFormat(locale, {
40
- numeric: "auto"
41
- }).format(gap, "day");
42
- return word.charAt(0).toLocaleUpperCase(locale) + word.slice(1);
43
- }
44
- return date.toLocaleDateString(locale, {
45
- weekday: "short",
46
- month: "short",
47
- day: "numeric"
48
- });
39
+ const date = new Date(`${day}T12:00:00`);
40
+ const now = new Date();
41
+ now.setHours(12, 0, 0, 0);
42
+ const gap = Math.round((date.getTime() - now.getTime()) / 864e5);
43
+ if (gap === 0 || gap === -1) {
44
+ const word = new Intl.RelativeTimeFormat(locale, { numeric: "auto" }).format(gap, "day");
45
+ return word.charAt(0).toLocaleUpperCase(locale) + word.slice(1);
46
+ }
47
+ return date.toLocaleDateString(locale, {
48
+ weekday: "short",
49
+ month: "short",
50
+ day: "numeric"
51
+ });
49
52
  }
53
+ /** The tone of a budget: quiet until 90%, warning to 100%, destructive past it. */
50
54
  export function budgetTone(logged, estimate) {
51
- if (!estimate || estimate <= 0) return "neutral";
52
- const ratio = logged / estimate;
53
- if (ratio > 1) return "destructive";
54
- return ratio >= 0.9 ? "warning" : "neutral";
55
+ if (!estimate || estimate <= 0) return "neutral";
56
+ const ratio = logged / estimate;
57
+ if (ratio > 1) return "destructive";
58
+ return ratio >= .9 ? "warning" : "neutral";
55
59
  }
60
+ /** A stable color for a person, from their name or id. */
56
61
  export function personColor(key) {
57
- let hash = 0;
58
- for (const char of key)hash = (hash * 31 + char.charCodeAt(0)) % 360;
59
- return `oklch(0.72 0.12 ${hash})`;
62
+ let hash = 0;
63
+ for (const char of key) hash = (hash * 31 + char.charCodeAt(0)) % 360;
64
+ return `oklch(0.72 0.12 ${hash})`;
60
65
  }
@@ -1,25 +1,25 @@
1
1
  export const DEFAULT_TIME_LABELS = {
2
- title: "Time",
3
- timer: "Timer",
4
- start: "Start timer",
5
- stop: "Stop timer",
6
- running: "Running",
7
- since: (time)=>`Since ${time}`,
8
- started: "Timer started",
9
- runningFor: (duration)=>`Timer running, ${duration}`,
10
- stopped: (duration)=>`Timer stopped, ${duration} to log`,
11
- elapsed: "Elapsed time",
12
- logged: "Logged",
13
- duration: "Time spent",
14
- durationPlaceholder: "1h30",
15
- date: "Date worked",
16
- note: "Note",
17
- notePlaceholder: "What was done",
18
- log: "Log",
19
- saving: "Saving",
20
- invalid: "Try 45m, 1h30 or 1.5h",
21
- empty: "Log your first hour",
22
- remaining: (left, estimate)=>`${left} left of ${estimate}`,
23
- over: (over, estimate)=>`${over} over ${estimate}`,
24
- deleteEntry: (duration)=>`Delete ${duration} entry`
2
+ title: "Time",
3
+ timer: "Timer",
4
+ start: "Start timer",
5
+ stop: "Stop timer",
6
+ running: "Running",
7
+ since: (time) => `Since ${time}`,
8
+ started: "Timer started",
9
+ runningFor: (duration) => `Timer running, ${duration}`,
10
+ stopped: (duration) => `Timer stopped, ${duration} to log`,
11
+ elapsed: "Elapsed time",
12
+ logged: "Logged",
13
+ duration: "Time spent",
14
+ durationPlaceholder: "1h30",
15
+ date: "Date worked",
16
+ note: "Note",
17
+ notePlaceholder: "What was done",
18
+ log: "Log",
19
+ saving: "Saving",
20
+ invalid: "Try 45m, 1h30 or 1.5h",
21
+ empty: "Log your first hour",
22
+ remaining: (left, estimate) => `${left} left of ${estimate}`,
23
+ over: (over, estimate) => `${over} over ${estimate}`,
24
+ deleteEntry: (duration) => `Delete ${duration} entry`
25
25
  };