@heyramzi/ui 2.11.0 → 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.
- package/dist/agents/helpers.js +38 -38
- package/dist/agents/page-state.js +49 -50
- package/dist/agents/vendor/color.js +146 -127
- package/dist/agents/vendor/draw.js +617 -508
- package/dist/agents/vendor/engine.js +698 -599
- package/dist/agents/vendor/mesh.js +653 -683
- package/dist/agents/vendor/plastic.js +3913 -3112
- package/dist/agents/vendor/presets.js +163 -164
- package/dist/agents/vendor/shapes.js +21 -20
- package/dist/agents/vendor/ticker.js +41 -42
- package/dist/agents/vendor/types.js +1 -0
- package/dist/agents/vendor/wear.js +1421 -1448
- package/dist/ai/confirmation/confirmation-context.svelte.js +6 -6
- package/dist/ai/confirmation/index.js +3 -1
- package/dist/ai/index.js +33 -0
- package/dist/ai/prompt-input/index.js +3 -1
- package/dist/ai/reasoning/index.js +3 -1
- package/dist/ai/reasoning/reasoning-context.svelte.js +6 -6
- package/dist/ai/suggestion/index.js +3 -1
- package/dist/ai/typing-dots/index.js +3 -1
- package/dist/animations/text-swap.js +24 -24
- package/dist/brand/index.js +54 -48
- package/dist/canvas/card/resize.js +5 -3
- package/dist/canvas/edges/edge-path.js +255 -242
- package/dist/canvas/editor/context-menu.js +39 -36
- package/dist/canvas/editor/dispatch.svelte.js +154 -151
- package/dist/canvas/editor/editor-context.js +7 -2
- package/dist/canvas/editor/editor-mode.js +1 -0
- package/dist/canvas/editor/frame.js +73 -76
- package/dist/canvas/editor/hand-context.js +5 -2
- package/dist/canvas/editor/history-core.js +163 -191
- package/dist/canvas/editor/keymap.js +95 -169
- package/dist/canvas/editor/layout-actions.js +143 -144
- package/dist/canvas/editor/lock.js +52 -51
- package/dist/canvas/editor/rebase.js +217 -240
- package/dist/canvas/editor/style.js +132 -137
- package/dist/canvas/editor/text-field-context.js +7 -2
- package/dist/canvas/editor/z-order.js +65 -70
- package/dist/canvas/headless/alignment.js +22 -16
- package/dist/canvas/headless/break-apart-find.js +286 -279
- package/dist/canvas/headless/break-apart-pieces.js +62 -58
- package/dist/canvas/headless/break-apart-plan.js +299 -325
- package/dist/canvas/headless/break-apart-style.js +75 -70
- package/dist/canvas/headless/break-apart.js +188 -181
- package/dist/canvas/headless/canvas-cleanup.js +78 -58
- package/dist/canvas/headless/edge-anchors.js +115 -116
- package/dist/canvas/headless/edge-memo.js +24 -22
- package/dist/canvas/headless/edge-serialization.js +17 -27
- package/dist/canvas/headless/figure-geometry.js +232 -264
- package/dist/canvas/headless/fit-viewport.js +84 -67
- package/dist/canvas/headless/grid.js +88 -86
- package/dist/canvas/headless/icon-node.js +44 -36
- package/dist/canvas/headless/index.js +1 -0
- package/dist/canvas/headless/linkify.js +17 -19
- package/dist/canvas/headless/pen-marks.js +101 -95
- package/dist/canvas/headless/sketch.js +231 -209
- package/dist/canvas/headless/snap-guides.js +99 -83
- package/dist/canvas/headless/svg-figure.js +133 -117
- package/dist/canvas/headless/table-layout.js +146 -107
- package/dist/canvas/index.js +2 -0
- package/dist/canvas/lod/lod-mode.svelte.js +20 -18
- package/dist/canvas/lod/render-all.svelte.js +36 -39
- package/dist/canvas/ops/arrange.js +78 -71
- package/dist/canvas/ops/ops.js +260 -255
- package/dist/canvas/pen/colors.js +37 -35
- package/dist/canvas/pen/eraser.js +28 -27
- package/dist/canvas/pen/geometry.js +120 -130
- package/dist/canvas/pen/index.js +1 -0
- package/dist/canvas/pen/ops.js +11 -11
- package/dist/canvas/pen/pen-session.js +150 -159
- package/dist/canvas/pen/plugin.js +107 -104
- package/dist/canvas/pen/shapes.js +73 -68
- package/dist/canvas/pen/stroke-path.js +32 -30
- package/dist/canvas/pen/types.js +21 -21
- package/dist/canvas/pen/ui.js +10 -8
- package/dist/canvas/plugin.js +46 -46
- package/dist/canvas/screen/glyphs.js +12 -11
- package/dist/canvas/screen/labels.js +22 -22
- package/dist/canvas/screen/parts.js +98 -111
- package/dist/canvas/screen/plugin.js +47 -56
- package/dist/canvas/screen/types.js +30 -35
- package/dist/canvas/screen/ui.js +7 -7
- package/dist/canvas/test-utils.js +14 -14
- package/dist/canvas/types.js +1 -0
- package/dist/canvas/ui/forward-wheel.js +24 -25
- package/dist/canvas/ui/icons.js +64 -131
- package/dist/canvas/ui/place-panel.js +58 -49
- package/dist/canvas/ui/shortcut-tip.js +14 -12
- package/dist/canvas/ui/tools.js +300 -385
- package/dist/charts/dashboard/chart.js +4 -0
- package/dist/charts/dashboard/data-table.js +11 -0
- package/dist/charts/dashboard/windows.js +8 -3
- package/dist/charts/edge-fade.js +10 -5
- package/dist/charts/hover-band.js +16 -11
- package/dist/charts/index.js +0 -1
- package/dist/charts/motion.js +11 -7
- package/dist/charts/primitives/chart-utils.js +12 -12
- package/dist/components/copy/clipboard.js +32 -32
- package/dist/components/copy/copied.svelte.js +31 -23
- package/dist/components/data-table/data-table.js +39 -39
- package/dist/components/docs/index.js +4 -0
- package/dist/components/docs/scroll-spy.svelte.js +73 -68
- package/dist/components/list-page/filter-section.js +4 -1
- package/dist/components/list-page/index.js +2 -0
- package/dist/components/list-page/list-table.js +7 -2
- package/dist/components/list-page/queue-rail.js +14 -0
- package/dist/components/list-page/section-host.js +4 -2
- package/dist/components/list-page/step.js +4 -3
- package/dist/components/list-page/types.js +1 -0
- package/dist/components/picker/trigger.js +48 -30
- package/dist/components/picker/types.js +1 -0
- package/dist/components/segmented/collapse.js +38 -27
- package/dist/components/segmented/index.js +8 -0
- package/dist/components/segmented/segmented.js +67 -42
- package/dist/components/star-rating-input/index.js +3 -1
- package/dist/components/table-view/types.js +1 -0
- package/dist/components/tags-input/tags.js +81 -69
- package/dist/components/theme/index.js +4 -0
- package/dist/components/toolbar/index.js +4 -0
- package/dist/components/toolbar/toolbar-trigger.js +14 -1
- package/dist/editor/anchors.js +17 -13
- package/dist/editor/block-id.js +52 -51
- package/dist/editor/block-ops.js +108 -80
- package/dist/editor/doc-blocks.js +155 -166
- package/dist/editor/extensions.js +139 -180
- package/dist/editor/index.js +4 -0
- package/dist/editor/markdown-test-helpers.js +4 -2
- package/dist/editor/markdown.js +420 -408
- package/dist/editor/serializer.js +204 -200
- package/dist/editor/slash-items.js +89 -101
- package/dist/editor/youtube-url.js +25 -20
- package/dist/effects/animated-beam/path-calculator.svelte.js +43 -38
- package/dist/effects/animated-beam/types.js +1 -0
- package/dist/effects/border-beam/css.js +92 -78
- package/dist/effects/border-beam/presets.js +1705 -1720
- package/dist/effects/border-beam/register-properties.js +43 -33
- package/dist/effects/border-beam/types.js +1 -0
- package/dist/effects/image-comparison/compare.js +3 -2
- package/dist/effects/image-reveal/types.js +1 -0
- package/dist/effects/magnetic/magnetic.js +58 -52
- package/dist/effects/reveal/observe.js +50 -40
- package/dist/effects/reveal/types.js +1 -0
- package/dist/effects/shader-gradient/color.js +36 -29
- package/dist/effects/shader-gradient/renderer.js +384 -295
- package/dist/effects/shader-gradient/shaders.js +31 -0
- package/dist/effects/shader-gradient/types.js +1 -0
- package/dist/icons/apple-symbol-exports.js +99 -124
- package/dist/icons/sf-symbols.js +357 -461
- package/dist/icons/trades.js +43 -28
- package/dist/inbox/index.js +1 -0
- package/dist/inbox/logic.js +126 -122
- package/dist/inbox/types.js +43 -43
- package/dist/lib/arrive.js +19 -12
- package/dist/lib/icon-types.js +1 -0
- package/dist/lib/initials.js +16 -10
- package/dist/lib/layout.js +5 -0
- package/dist/lib/panel.js +13 -0
- package/dist/lib/result.js +22 -22
- package/dist/lib/sliding-pill.js +59 -44
- package/dist/lib/theme-transition.js +43 -43
- package/dist/lib/tone.js +31 -24
- package/dist/lib/utils.js +3 -1
- package/dist/onboarding/define-tours.js +24 -23
- package/dist/onboarding/onboarding.svelte.js +16 -12
- package/dist/onboarding/pick.js +10 -6
- package/dist/onboarding/stores.js +40 -41
- package/dist/onboarding/wait.js +24 -23
- package/dist/panel/side-panel-types.js +1 -0
- package/dist/record/demo-data.js +459 -486
- package/dist/record/fields.js +129 -131
- package/dist/record/format.js +70 -82
- package/dist/record/gutter.js +1 -0
- package/dist/record/kinds.js +95 -105
- package/dist/record/logic.js +238 -219
- package/dist/record/types.js +49 -48
- package/dist/shadcn/accordion/index.js +3 -1
- package/dist/shadcn/alert/index.js +3 -1
- package/dist/shadcn/alert-dialog/index.js +3 -1
- package/dist/shadcn/attachment/index.js +3 -1
- package/dist/shadcn/avatar/index.js +3 -1
- package/dist/shadcn/breadcrumb/index.js +3 -1
- package/dist/shadcn/bubble/index.js +3 -1
- package/dist/shadcn/button/index.js +3 -1
- package/dist/shadcn/calendar/index.js +3 -1
- package/dist/shadcn/card/index.js +3 -1
- package/dist/shadcn/checkbox/index.js +3 -1
- package/dist/shadcn/code-block/index.js +3 -1
- package/dist/shadcn/collapsible/index.js +3 -1
- package/dist/shadcn/command/index.js +4 -1
- package/dist/shadcn/context-menu/index.js +3 -1
- package/dist/shadcn/dialog/index.js +3 -1
- package/dist/shadcn/dropdown-menu/menu-item.js +40 -20
- package/dist/shadcn/empty/index.js +3 -1
- package/dist/shadcn/field/index.js +3 -1
- package/dist/shadcn/hooks/highlighter.js +77 -75
- package/dist/shadcn/hooks/is-mobile.svelte.js +3 -3
- package/dist/shadcn/hooks/use-highlighted-code.svelte.js +62 -62
- package/dist/shadcn/input/index.js +3 -1
- package/dist/shadcn/kbd/index.js +3 -1
- package/dist/shadcn/label/index.js +3 -1
- package/dist/shadcn/marker/index.js +3 -1
- package/dist/shadcn/message/index.js +3 -1
- package/dist/shadcn/message-scroller/index.js +3 -1
- package/dist/shadcn/popover/index.js +3 -1
- package/dist/shadcn/progress/index.js +3 -1
- package/dist/shadcn/progress/tone.js +8 -7
- package/dist/shadcn/radio-group/index.js +3 -1
- package/dist/shadcn/scroll-area/index.js +3 -1
- package/dist/shadcn/select/index.js +3 -1
- package/dist/shadcn/separator/index.js +3 -1
- package/dist/shadcn/sheet/index.js +3 -1
- package/dist/shadcn/sidebar/context.svelte.js +42 -28
- package/dist/shadcn/sidebar/index.js +3 -1
- package/dist/shadcn/skeleton/index.js +3 -1
- package/dist/shadcn/slider/index.js +3 -1
- package/dist/shadcn/switch/index.js +3 -1
- package/dist/shadcn/table/index.js +3 -1
- package/dist/shadcn/tabs/index.js +3 -1
- package/dist/shadcn/textarea/index.js +3 -1
- package/dist/shadcn/toggle/index.js +3 -1
- package/dist/shadcn/toggle-group/index.js +3 -1
- package/dist/shadcn/tooltip/context.js +7 -2
- package/dist/shadcn/tooltip/index.js +3 -1
- package/dist/shadcn/trace/index.js +3 -1
- package/dist/slides/bridges.js +65 -59
- package/dist/slides/deck-controller.svelte.js +210 -207
- package/dist/slides/export/capture.js +66 -71
- package/dist/slides/export/ffmpeg.js +76 -72
- package/dist/slides/export/index.js +3 -0
- package/dist/slides/export/launch.js +9 -6
- package/dist/slides/export/pdf.js +60 -54
- package/dist/slides/export/types.js +1 -0
- package/dist/slides/labels.js +24 -24
- package/dist/slides/layout.js +39 -41
- package/dist/slides/model.js +9 -7
- package/dist/slides/navigation.js +78 -73
- package/dist/slides/types.js +2 -2
- package/dist/status/define-statuses.js +18 -14
- package/dist/status/status-types.js +1 -0
- package/dist/test-setup.js +24 -20
- package/dist/thread/logic.js +73 -77
- package/dist/thread/types.js +21 -21
- package/dist/work/board-order.js +94 -90
- package/dist/work/dates.js +16 -9
- package/dist/work/detail/detail-types.js +18 -18
- package/dist/work/docs/edited.js +32 -29
- package/dist/work/docs/index.js +4 -0
- package/dist/work/docs/labels.js +34 -34
- package/dist/work/docs/menu.js +113 -106
- package/dist/work/docs/outline.js +39 -29
- package/dist/work/gantt/logic.js +211 -235
- package/dist/work/inbox/inbox-logic.js +71 -75
- package/dist/work/inbox/inbox-statuses.js +75 -72
- package/dist/work/inbox/inbox-types.js +1 -0
- package/dist/work/kanban-drag.js +27 -22
- package/dist/work/kanban-types.js +1 -0
- package/dist/work/presets/sales.js +36 -32
- package/dist/work/reorder.js +9 -8
- package/dist/work/task-types.js +1 -0
- package/dist/work/time/duration.js +51 -46
- package/dist/work/time/time-types.js +23 -23
- package/dist/work/use-kanban-dnd.svelte.js +126 -125
- package/package.json +3 -1
- package/src/components/list-page/master-detail.svelte +3 -1
- package/src/components/list-page/rail-row.svelte +4 -4
- package/src/components/tags-input/tags-input.svelte +2 -0
- package/src/editor/markdown.ts +30 -35
package/dist/work/gantt/logic.js
CHANGED
|
@@ -1,260 +1,236 @@
|
|
|
1
1
|
import { dayNumber, isoFromDay, weekday } from "../dates.js";
|
|
2
|
-
const DAY_MS =
|
|
2
|
+
const DAY_MS = 864e5;
|
|
3
3
|
export function dayX(layout, day) {
|
|
4
|
-
|
|
4
|
+
return (day - layout.first) * layout.dayWidth;
|
|
5
5
|
}
|
|
6
|
+
/** The task's own dates. A lone date stands for a one-day task. */
|
|
6
7
|
export function spanOf(item, { getStart, getEnd }) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
const first = getStart(item) || getEnd(item);
|
|
9
|
+
const last = getEnd(item) || getStart(item);
|
|
10
|
+
if (!first || !last) return null;
|
|
11
|
+
const start = dayNumber(first);
|
|
12
|
+
return {
|
|
13
|
+
start,
|
|
14
|
+
end: Math.max(start, dayNumber(last))
|
|
15
|
+
};
|
|
15
16
|
}
|
|
17
|
+
/** A bar's span, with the live drag applied. Resizes never cross the other edge. */
|
|
16
18
|
export function liveSpan(span, drag, id) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
19
|
+
if (!span || drag?.id !== id || drag.dx === 0) return span;
|
|
20
|
+
if (drag.mode === "move") return {
|
|
21
|
+
start: span.start + drag.dx,
|
|
22
|
+
end: span.end + drag.dx
|
|
23
|
+
};
|
|
24
|
+
if (drag.mode === "start") return {
|
|
25
|
+
start: Math.min(span.start + drag.dx, span.end),
|
|
26
|
+
end: span.end
|
|
27
|
+
};
|
|
28
|
+
return {
|
|
29
|
+
start: span.start,
|
|
30
|
+
end: Math.max(span.end + drag.dx, span.start)
|
|
31
|
+
};
|
|
30
32
|
}
|
|
31
33
|
function join(a, b) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
return !a ? b : !b ? a : {
|
|
35
|
+
start: Math.min(a.start, b.start),
|
|
36
|
+
end: Math.max(a.end, b.end)
|
|
37
|
+
};
|
|
36
38
|
}
|
|
39
|
+
/** The days shown: the tasks' span, padded, starting on a Monday, unless `from` and `to` say otherwise. */
|
|
37
40
|
export function rangeOf(items, source, todayDay, from, to) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
41
|
+
let lo = todayDay;
|
|
42
|
+
let hi = todayDay;
|
|
43
|
+
for (const item of items) {
|
|
44
|
+
const span = spanOf(item, source);
|
|
45
|
+
if (!span) continue;
|
|
46
|
+
lo = Math.min(lo, span.start);
|
|
47
|
+
hi = Math.max(hi, span.end);
|
|
48
|
+
}
|
|
49
|
+
let first = from ? dayNumber(from) : lo - 7;
|
|
50
|
+
// Day 0 was a Thursday. Step back to the Monday on or before `first`.
|
|
51
|
+
if (!from) first -= (weekday(first) + 6) % 7;
|
|
52
|
+
const last = to ? dayNumber(to) : hi + 21;
|
|
53
|
+
return {
|
|
54
|
+
first,
|
|
55
|
+
last: Math.max(last, first)
|
|
56
|
+
};
|
|
53
57
|
}
|
|
54
58
|
export function buildDays(first, count) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
};
|
|
67
|
-
});
|
|
59
|
+
return Array.from({ length: count }, (_, i) => {
|
|
60
|
+
const day = first + i;
|
|
61
|
+
const wd = weekday(day);
|
|
62
|
+
return {
|
|
63
|
+
day,
|
|
64
|
+
i,
|
|
65
|
+
date: Number(isoFromDay(day).slice(8, 10)),
|
|
66
|
+
wd,
|
|
67
|
+
weekend: wd === 0 || wd === 6
|
|
68
|
+
};
|
|
69
|
+
});
|
|
68
70
|
}
|
|
69
71
|
export function buildMonths(days, format) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
72
|
+
const out = [];
|
|
73
|
+
for (const d of days) {
|
|
74
|
+
const key = isoFromDay(d.day).slice(0, 7);
|
|
75
|
+
const last = out.at(-1);
|
|
76
|
+
if (last?.key === key) last.length++;
|
|
77
|
+
else out.push({
|
|
78
|
+
key,
|
|
79
|
+
label: format.format(new Date(d.day * DAY_MS)),
|
|
80
|
+
i: d.i,
|
|
81
|
+
length: 1
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return out;
|
|
83
85
|
}
|
|
86
|
+
/** Rows in draw order. Groups come first, then their tasks, a parent before its children. */
|
|
84
87
|
export function buildRows(items, source) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
return out;
|
|
88
|
+
const { getId, getParent, groups, getGroup, folded, drag } = source;
|
|
89
|
+
const out = [];
|
|
90
|
+
let order = 0;
|
|
91
|
+
const live = (item, id) => liveSpan(spanOf(item, source), drag, id);
|
|
92
|
+
// Depth first, so a parent's row comes before its children. A parent's span is known
|
|
93
|
+
// only after its children are, so the row is pushed first and filled in after.
|
|
94
|
+
const emit = (members) => {
|
|
95
|
+
if (!getParent) {
|
|
96
|
+
for (const item of members) {
|
|
97
|
+
const id = getId(item);
|
|
98
|
+
const own = live(item, id);
|
|
99
|
+
out.push({
|
|
100
|
+
kind: "task",
|
|
101
|
+
item,
|
|
102
|
+
id,
|
|
103
|
+
order: order++,
|
|
104
|
+
depth: 0,
|
|
105
|
+
hasChildren: false,
|
|
106
|
+
open: true,
|
|
107
|
+
own,
|
|
108
|
+
span: own
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const ids = new Set(members.map((item) => getId(item)));
|
|
114
|
+
const kids = new Map();
|
|
115
|
+
for (const item of members) {
|
|
116
|
+
const parent = getParent(item);
|
|
117
|
+
const key = parent && ids.has(parent) ? parent : null;
|
|
118
|
+
kids.set(key, [...kids.get(key) ?? [], item]);
|
|
119
|
+
}
|
|
120
|
+
const walk = (item, depth, visible) => {
|
|
121
|
+
const id = getId(item);
|
|
122
|
+
const children = kids.get(id) ?? [];
|
|
123
|
+
const open = !folded.has(id);
|
|
124
|
+
const own = live(item, id);
|
|
125
|
+
const row = {
|
|
126
|
+
kind: "task",
|
|
127
|
+
item,
|
|
128
|
+
id,
|
|
129
|
+
order: 0,
|
|
130
|
+
depth,
|
|
131
|
+
hasChildren: children.length > 0,
|
|
132
|
+
open,
|
|
133
|
+
own,
|
|
134
|
+
span: own
|
|
135
|
+
};
|
|
136
|
+
if (visible) {
|
|
137
|
+
row.order = order++;
|
|
138
|
+
out.push(row);
|
|
139
|
+
}
|
|
140
|
+
let below = null;
|
|
141
|
+
for (const child of children) below = join(below, walk(child, depth + 1, visible && open));
|
|
142
|
+
if (!own) row.span = below;
|
|
143
|
+
return join(own, below);
|
|
144
|
+
};
|
|
145
|
+
for (const item of kids.get(null) ?? []) walk(item, 0, true);
|
|
146
|
+
};
|
|
147
|
+
if (!groups || !getGroup) {
|
|
148
|
+
emit(items);
|
|
149
|
+
return out;
|
|
150
|
+
}
|
|
151
|
+
for (const group of groups) {
|
|
152
|
+
const members = items.filter((item) => getGroup(item) === group.id);
|
|
153
|
+
let span = null;
|
|
154
|
+
for (const item of members) span = join(span, live(item, getId(item)));
|
|
155
|
+
out.push({
|
|
156
|
+
kind: "group",
|
|
157
|
+
group,
|
|
158
|
+
count: members.length,
|
|
159
|
+
span
|
|
160
|
+
});
|
|
161
|
+
emit(members);
|
|
162
|
+
}
|
|
163
|
+
return out;
|
|
162
164
|
}
|
|
165
|
+
/** A right-angled path through `points`, each corner rounded by up to `radius`. */
|
|
163
166
|
export function roundedPath(points, radius) {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
167
|
+
let d = `M${points[0][0]},${points[0][1]}`;
|
|
168
|
+
for (let i = 1; i < points.length - 1; i++) {
|
|
169
|
+
const [px, py] = points[i - 1];
|
|
170
|
+
const [cx, cy] = points[i];
|
|
171
|
+
const [nx, ny] = points[i + 1];
|
|
172
|
+
const r = Math.min(radius, Math.hypot(cx - px, cy - py) / 2, Math.hypot(nx - cx, ny - cy) / 2);
|
|
173
|
+
const inX = cx - Math.sign(cx - px) * r;
|
|
174
|
+
const inY = cy - Math.sign(cy - py) * r;
|
|
175
|
+
const outX = cx + Math.sign(nx - cx) * r;
|
|
176
|
+
const outY = cy + Math.sign(ny - cy) * r;
|
|
177
|
+
d += ` L${inX},${inY} Q${cx},${cy} ${outX},${outY}`;
|
|
178
|
+
}
|
|
179
|
+
const [lx, ly] = points[points.length - 1];
|
|
180
|
+
return `${d} L${lx},${ly}`;
|
|
178
181
|
}
|
|
182
|
+
/** Each arrow runs from the end of the task waited on to the start of the one waiting. */
|
|
179
183
|
export function buildArrows(rows, layout, getDependsOn) {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
y1
|
|
225
|
-
],
|
|
226
|
-
[
|
|
227
|
-
x1 + 10,
|
|
228
|
-
y1 + (y2 > y1 ? rowHeight / 2 : -rowHeight / 2)
|
|
229
|
-
],
|
|
230
|
-
[
|
|
231
|
-
x2 - 12,
|
|
232
|
-
y1 + (y2 > y1 ? rowHeight / 2 : -rowHeight / 2)
|
|
233
|
-
],
|
|
234
|
-
[
|
|
235
|
-
x2 - 12,
|
|
236
|
-
y2
|
|
237
|
-
],
|
|
238
|
-
[
|
|
239
|
-
x2,
|
|
240
|
-
y2
|
|
241
|
-
]
|
|
242
|
-
];
|
|
243
|
-
out.push({
|
|
244
|
-
key: `${dep}->${row.id}`,
|
|
245
|
-
d: roundedPath(points, 6),
|
|
246
|
-
head: `M${x2 - 5},${y2 - 3.5} L${x2},${y2} L${x2 - 5},${y2 + 3.5}`,
|
|
247
|
-
from: dep,
|
|
248
|
-
to: row.id
|
|
249
|
-
});
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
return out;
|
|
184
|
+
const { rowHeight, inset } = layout;
|
|
185
|
+
const at = new Map();
|
|
186
|
+
rows.forEach((row, index) => {
|
|
187
|
+
if (row.kind === "task" && row.span) at.set(row.id, {
|
|
188
|
+
row: index,
|
|
189
|
+
span: row.span
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
const out = [];
|
|
193
|
+
for (const row of rows) {
|
|
194
|
+
if (row.kind !== "task") continue;
|
|
195
|
+
const target = at.get(row.id);
|
|
196
|
+
if (!target) continue;
|
|
197
|
+
for (const dep of getDependsOn(row.item) ?? []) {
|
|
198
|
+
const source = at.get(dep);
|
|
199
|
+
if (!source) continue;
|
|
200
|
+
const x1 = dayX(layout, source.span.end + 1) - inset;
|
|
201
|
+
const y1 = source.row * rowHeight + rowHeight / 2;
|
|
202
|
+
const x2 = dayX(layout, target.span.start) + inset;
|
|
203
|
+
const y2 = target.row * rowHeight + rowHeight / 2;
|
|
204
|
+
// Room between the bars: one bend in the gap. No room: out, round the row gap, and back in.
|
|
205
|
+
const points = x2 - x1 >= 24 ? [
|
|
206
|
+
[x1, y1],
|
|
207
|
+
[x1 + 12, y1],
|
|
208
|
+
[x1 + 12, y2],
|
|
209
|
+
[x2, y2]
|
|
210
|
+
] : [
|
|
211
|
+
[x1, y1],
|
|
212
|
+
[x1 + 10, y1],
|
|
213
|
+
[x1 + 10, y1 + (y2 > y1 ? rowHeight / 2 : -rowHeight / 2)],
|
|
214
|
+
[x2 - 12, y1 + (y2 > y1 ? rowHeight / 2 : -rowHeight / 2)],
|
|
215
|
+
[x2 - 12, y2],
|
|
216
|
+
[x2, y2]
|
|
217
|
+
];
|
|
218
|
+
out.push({
|
|
219
|
+
key: `${dep}->${row.id}`,
|
|
220
|
+
d: roundedPath(points, 6),
|
|
221
|
+
head: `M${x2 - 5},${y2 - 3.5} L${x2},${y2} L${x2 - 5},${y2 + 3.5}`,
|
|
222
|
+
from: dep,
|
|
223
|
+
to: row.id
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return out;
|
|
253
228
|
}
|
|
229
|
+
/** The pixel width of a span's bar, never under 8px. */
|
|
254
230
|
export function barWidth(span, layout) {
|
|
255
|
-
|
|
231
|
+
return Math.max((span.end - span.start + 1) * layout.dayWidth - layout.inset * 2, 8);
|
|
256
232
|
}
|
|
257
233
|
export function rangeLabel(span, format) {
|
|
258
|
-
|
|
259
|
-
|
|
234
|
+
const length = span.end - span.start + 1;
|
|
235
|
+
return `${format.format(new Date(span.start * DAY_MS))} to ${format.format(new Date(span.end * DAY_MS))}, ${length} ${length === 1 ? "day" : "days"}`;
|
|
260
236
|
}
|
|
@@ -1,94 +1,90 @@
|
|
|
1
|
+
/** The draft to open on: the agent's pick, else the first. */
|
|
1
2
|
export function startDraft(drafts, recommended) {
|
|
2
|
-
|
|
3
|
+
return drafts.find((draft) => draft.templateId === recommended) ?? drafts[0];
|
|
3
4
|
}
|
|
5
|
+
/** A person can act on an item only while it waits for them. */
|
|
4
6
|
export function isOpen(item) {
|
|
5
|
-
|
|
7
|
+
return item.tier === "ask" && item.state === "proposed";
|
|
6
8
|
}
|
|
7
9
|
export function canUndo(item) {
|
|
8
|
-
|
|
10
|
+
return item.tier === "auto" && item.state === "done";
|
|
9
11
|
}
|
|
12
|
+
/** Lowercase, one space between words, no trailing ellipsis: what two copies of a line share. */
|
|
10
13
|
function plain(text) {
|
|
11
|
-
|
|
14
|
+
return text.replace(/(…|\.{3})\s*$/, "").replace(/\s+/g, " ").trim().toLowerCase();
|
|
12
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Each fact once: a line that repeats the title or the command, even clipped, is dropped, and
|
|
18
|
+
* one that starts with the title keeps only the rest.
|
|
19
|
+
*/
|
|
13
20
|
export function cardFacts(item) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
return {
|
|
35
|
-
lines,
|
|
36
|
-
command
|
|
37
|
-
};
|
|
21
|
+
const { command, summary, detail } = item.proposal;
|
|
22
|
+
const shown = [plain(item.title)];
|
|
23
|
+
if (command) shown.push(plain(`${command.tool}: ${command.text}`), plain(command.text));
|
|
24
|
+
const lines = [];
|
|
25
|
+
for (const raw of [summary, detail]) {
|
|
26
|
+
let line = raw?.trim() ?? "";
|
|
27
|
+
const title = item.title.trim();
|
|
28
|
+
if (line.toLowerCase().startsWith(title.toLowerCase()) && line.length > title.length) {
|
|
29
|
+
line = line.slice(title.length).replace(/^[\s:.,;-]+/, "");
|
|
30
|
+
}
|
|
31
|
+
const key = plain(line);
|
|
32
|
+
if (!key || shown.some((seen) => seen.includes(key) || key.includes(seen))) continue;
|
|
33
|
+
shown.push(key);
|
|
34
|
+
lines.push(line);
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
lines,
|
|
38
|
+
command
|
|
39
|
+
};
|
|
38
40
|
}
|
|
41
|
+
/** The reasoning of a trace when no line of the card already says it. */
|
|
39
42
|
export function freshReasoning(item, facts) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
43
|
+
const reasoning = item.trace.reasoning.trim();
|
|
44
|
+
const key = plain(reasoning);
|
|
45
|
+
if (!key) return "";
|
|
46
|
+
const said = [
|
|
47
|
+
item.title,
|
|
48
|
+
item.proposal.summary,
|
|
49
|
+
item.proposal.detail ?? "",
|
|
50
|
+
...facts.lines
|
|
51
|
+
].map(plain).filter(Boolean);
|
|
52
|
+
return said.some((line) => line.includes(key) || key.includes(line)) ? "" : reasoning;
|
|
50
53
|
}
|
|
51
54
|
const ISO = /^\d{4}-\d{2}-\d{2}T/;
|
|
52
55
|
const UNITS = [
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
[
|
|
58
|
-
86_400,
|
|
59
|
-
"day"
|
|
60
|
-
],
|
|
61
|
-
[
|
|
62
|
-
3_600,
|
|
63
|
-
"hour"
|
|
64
|
-
],
|
|
65
|
-
[
|
|
66
|
-
60,
|
|
67
|
-
"minute"
|
|
68
|
-
]
|
|
56
|
+
[604800, "week"],
|
|
57
|
+
[86400, "day"],
|
|
58
|
+
[3600, "hour"],
|
|
59
|
+
[60, "minute"]
|
|
69
60
|
];
|
|
61
|
+
/**
|
|
62
|
+
* A time as a person says it: "3 hr. ago", "Oct 12". A host-formatted string stays as written,
|
|
63
|
+
* and a raw ISO string never reaches the screen.
|
|
64
|
+
*/
|
|
70
65
|
export function whenOf(at, now = Date.now(), locale = "en-GB") {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
66
|
+
if (!ISO.test(at)) return at;
|
|
67
|
+
const time = Date.parse(at);
|
|
68
|
+
if (Number.isNaN(time)) return "";
|
|
69
|
+
const seconds = Math.round((time - now) / 1e3);
|
|
70
|
+
const age = Math.abs(seconds);
|
|
71
|
+
if (age >= 4 * 604800) {
|
|
72
|
+
return new Intl.DateTimeFormat(locale, {
|
|
73
|
+
month: "short",
|
|
74
|
+
day: "numeric"
|
|
75
|
+
}).format(time);
|
|
76
|
+
}
|
|
77
|
+
const rtf = new Intl.RelativeTimeFormat(locale, {
|
|
78
|
+
numeric: "auto",
|
|
79
|
+
style: "short"
|
|
80
|
+
});
|
|
81
|
+
for (const [size, unit] of UNITS) {
|
|
82
|
+
if (age >= size) return rtf.format(Math.round(seconds / size), unit);
|
|
83
|
+
}
|
|
84
|
+
return rtf.format(0, "second");
|
|
90
85
|
}
|
|
86
|
+
/** True when a key press belongs to a text field and so isn't a shortcut. */
|
|
91
87
|
export function isTyping(target) {
|
|
92
|
-
|
|
93
|
-
|
|
88
|
+
if (!(target instanceof HTMLElement)) return false;
|
|
89
|
+
return target.isContentEditable || /^(INPUT|TEXTAREA|SELECT)$/.test(target.tagName);
|
|
94
90
|
}
|