@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/record/logic.js
CHANGED
|
@@ -1,255 +1,274 @@
|
|
|
1
|
+
// =========================
|
|
2
|
+
// EVENTS
|
|
3
|
+
// =========================
|
|
4
|
+
/** The calendar day of a timestamp as `YYYY-MM-DD`, in the given zone or the viewer's own. */
|
|
1
5
|
export function localDay(iso, timeZone) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
return new Intl.DateTimeFormat("en-CA", {
|
|
7
|
+
year: "numeric",
|
|
8
|
+
month: "2-digit",
|
|
9
|
+
day: "2-digit",
|
|
10
|
+
timeZone
|
|
11
|
+
}).format(new Date(iso));
|
|
8
12
|
}
|
|
13
|
+
/** Newest day first, newest event first inside a day. */
|
|
9
14
|
export function groupEventsByDay(events, timeZone) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
]
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
return groups;
|
|
15
|
+
const sorted = [...events].sort((a, b) => new Date(b.occurredAt).getTime() - new Date(a.occurredAt).getTime());
|
|
16
|
+
const groups = [];
|
|
17
|
+
for (const event of sorted) {
|
|
18
|
+
const day = localDay(event.occurredAt, timeZone);
|
|
19
|
+
const last = groups[groups.length - 1];
|
|
20
|
+
if (last && last.day === day) last.events.push(event);
|
|
21
|
+
else groups.push({
|
|
22
|
+
day,
|
|
23
|
+
events: [event]
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
return groups;
|
|
26
27
|
}
|
|
28
|
+
/** `today`, `yesterday` or `date`, by calendar distance from `today`. */
|
|
27
29
|
export function dayRelation(day, today) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
if (day === today) return "today";
|
|
31
|
+
const gap = (Date.parse(`${today}T00:00:00Z`) - Date.parse(`${day}T00:00:00Z`)) / 864e5;
|
|
32
|
+
return gap === 1 ? "yesterday" : "date";
|
|
31
33
|
}
|
|
34
|
+
/** The events one filter chip shows. An unknown or empty key shows everything. */
|
|
32
35
|
export function eventsForFilter(events, filterKey, filters) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const kinds = new Set(filter.kinds);
|
|
38
|
-
return events.filter((e)=>kinds.has(e.kind));
|
|
36
|
+
const filter = filters.find((f) => f.key === filterKey);
|
|
37
|
+
if (!filter) return [...events];
|
|
38
|
+
const kinds = new Set(filter.kinds);
|
|
39
|
+
return events.filter((e) => kinds.has(e.kind));
|
|
39
40
|
}
|
|
41
|
+
/** Per-chip counts. Chips with no events are the host's to hide. */
|
|
40
42
|
export function filterCounts(events, filters) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
const counts = {};
|
|
44
|
+
for (const filter of filters) {
|
|
45
|
+
const kinds = new Set(filter.kinds);
|
|
46
|
+
counts[filter.key] = events.filter((e) => kinds.has(e.kind)).length;
|
|
47
|
+
}
|
|
48
|
+
return counts;
|
|
47
49
|
}
|
|
50
|
+
/** Keep the newest `limit` events and count the rest, cutting a day group where the limit falls. */
|
|
48
51
|
export function foldGroups(groups, limit) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
52
|
+
const kept = [];
|
|
53
|
+
let used = 0;
|
|
54
|
+
let total = 0;
|
|
55
|
+
for (const group of groups) total += group.events.length;
|
|
56
|
+
for (const group of groups) {
|
|
57
|
+
if (used >= limit) break;
|
|
58
|
+
const room = limit - used;
|
|
59
|
+
const events = group.events.slice(0, room);
|
|
60
|
+
kept.push({
|
|
61
|
+
day: group.day,
|
|
62
|
+
events
|
|
63
|
+
});
|
|
64
|
+
used += events.length;
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
groups: kept,
|
|
68
|
+
hidden: total - used
|
|
69
|
+
};
|
|
67
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* One client's timeline, newest first, with project events tagged. An id seen twice keeps the
|
|
73
|
+
* first, so a source passed in both lists draws once.
|
|
74
|
+
*/
|
|
68
75
|
export function mergeClientEvents(clientEvents, projects) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
76
|
+
const seen = new Set();
|
|
77
|
+
const merged = [];
|
|
78
|
+
const add = (event) => {
|
|
79
|
+
if (seen.has(event.id)) return;
|
|
80
|
+
seen.add(event.id);
|
|
81
|
+
merged.push(event);
|
|
82
|
+
};
|
|
83
|
+
for (const project of projects) {
|
|
84
|
+
for (const event of project.events) {
|
|
85
|
+
add({
|
|
86
|
+
...event,
|
|
87
|
+
projectId: project.id,
|
|
88
|
+
projectName: project.name,
|
|
89
|
+
projectHref: project.href ?? null
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
for (const event of clientEvents) add({
|
|
94
|
+
...event,
|
|
95
|
+
projectId: null,
|
|
96
|
+
projectName: null,
|
|
97
|
+
projectHref: null
|
|
98
|
+
});
|
|
99
|
+
return merged.sort((a, b) => new Date(b.occurredAt).getTime() - new Date(a.occurredAt).getTime());
|
|
93
100
|
}
|
|
101
|
+
// =========================
|
|
102
|
+
// PROJECTS
|
|
103
|
+
// =========================
|
|
94
104
|
const ACTIVE = new Set([
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
105
|
+
"open",
|
|
106
|
+
"proposal",
|
|
107
|
+
"ongoing"
|
|
98
108
|
]);
|
|
109
|
+
/** Projects still in play: not closed, and in a stage that isn't won-and-done or lost. */
|
|
99
110
|
export function activeProjects(projects, stages) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
const c = category.get(p.stageKey);
|
|
107
|
-
return c === undefined || ACTIVE.has(c);
|
|
108
|
-
});
|
|
111
|
+
const category = new Map(stages.map((s) => [s.key, s.category]));
|
|
112
|
+
return projects.filter((p) => {
|
|
113
|
+
if (p.closed) return false;
|
|
114
|
+
const c = category.get(p.stageKey);
|
|
115
|
+
return c === undefined || ACTIVE.has(c);
|
|
116
|
+
});
|
|
109
117
|
}
|
|
118
|
+
/** The earliest dated next across active projects, undated ones after, ties by list order. */
|
|
110
119
|
export function nextAcrossProjects(projects, stages) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
120
|
+
let best = null;
|
|
121
|
+
for (const project of activeProjects(projects, stages)) {
|
|
122
|
+
const next = project.next;
|
|
123
|
+
if (!next) continue;
|
|
124
|
+
const candidate = {
|
|
125
|
+
...next,
|
|
126
|
+
projectId: project.id,
|
|
127
|
+
projectName: project.name
|
|
128
|
+
};
|
|
129
|
+
if (!best) {
|
|
130
|
+
best = candidate;
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
if (!best.date && candidate.date) best = candidate;
|
|
134
|
+
else if (best.date && candidate.date && candidate.date < best.date) best = candidate;
|
|
135
|
+
}
|
|
136
|
+
return best;
|
|
128
137
|
}
|
|
138
|
+
/** The newest "where we are" across projects, tagged with its project. */
|
|
129
139
|
export function latestWhereWeAre(projects) {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
140
|
+
let best = null;
|
|
141
|
+
for (const project of projects) {
|
|
142
|
+
const status = project.whereWeAre;
|
|
143
|
+
if (!status || !status.text) continue;
|
|
144
|
+
const at = status.at ? new Date(status.at).getTime() : 0;
|
|
145
|
+
const bestAt = best?.at ? new Date(best.at).getTime() : -1;
|
|
146
|
+
if (!best || at > bestAt) best = {
|
|
147
|
+
...status,
|
|
148
|
+
projectId: project.id,
|
|
149
|
+
projectName: project.name
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
return best;
|
|
143
153
|
}
|
|
154
|
+
/**
|
|
155
|
+
* The client's pipeline, won and paid totals, kept per currency because a sum across two
|
|
156
|
+
* currencies is a lie.
|
|
157
|
+
*/
|
|
144
158
|
export function rollupProjects(projects, stages, fallbackCurrency = "EUR") {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
totals,
|
|
169
|
-
lastCallAt
|
|
170
|
-
};
|
|
159
|
+
const category = new Map(stages.map((s) => [s.key, s.category]));
|
|
160
|
+
const totals = {};
|
|
161
|
+
let lastCallAt = null;
|
|
162
|
+
for (const project of projects) {
|
|
163
|
+
const currency = project.currency ?? fallbackCurrency;
|
|
164
|
+
const bucket = totals[currency] ??= {
|
|
165
|
+
pipeline: 0,
|
|
166
|
+
won: 0,
|
|
167
|
+
paid: 0
|
|
168
|
+
};
|
|
169
|
+
const c = category.get(project.stageKey);
|
|
170
|
+
const value = project.value ?? 0;
|
|
171
|
+
if (c === "open" || c === "proposal") bucket.pipeline += value;
|
|
172
|
+
if (c === "ongoing" || c === "completed") bucket.won += value;
|
|
173
|
+
bucket.paid += project.paid ?? 0;
|
|
174
|
+
if (project.lastCallAt && (!lastCallAt || project.lastCallAt > lastCallAt)) lastCallAt = project.lastCallAt;
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
count: projects.length,
|
|
178
|
+
activeCount: activeProjects(projects, stages).length,
|
|
179
|
+
totals,
|
|
180
|
+
lastCallAt
|
|
181
|
+
};
|
|
171
182
|
}
|
|
183
|
+
// =========================
|
|
184
|
+
// STEPS
|
|
185
|
+
// =========================
|
|
186
|
+
/** A step is visible unless hidden. */
|
|
172
187
|
export function visibleSteps(steps) {
|
|
173
|
-
|
|
188
|
+
return steps.filter((s) => !s.hidden);
|
|
174
189
|
}
|
|
175
190
|
export function stepProgress(steps) {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
191
|
+
const visible = visibleSteps(steps);
|
|
192
|
+
return {
|
|
193
|
+
done: visible.filter((s) => s.done).length,
|
|
194
|
+
total: visible.length
|
|
195
|
+
};
|
|
181
196
|
}
|
|
197
|
+
/**
|
|
198
|
+
* One marker per step. Only an open step before the current one, or past its own date, is
|
|
199
|
+
* late. `today` is an ISO date.
|
|
200
|
+
*/
|
|
182
201
|
export function stepMarkers(steps, today) {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
+
const visible = visibleSteps(steps);
|
|
203
|
+
const currentId = visible.find((s) => !s.done)?.id ?? null;
|
|
204
|
+
const markers = new Map();
|
|
205
|
+
let beforeCurrent = currentId !== null;
|
|
206
|
+
for (const step of visible) {
|
|
207
|
+
if (step.done) {
|
|
208
|
+
markers.set(step.id, "complete");
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
if (step.id === currentId) {
|
|
212
|
+
markers.set(step.id, "current");
|
|
213
|
+
beforeCurrent = false;
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
const due = (step.end ?? step.start)?.slice(0, 10);
|
|
217
|
+
const overdue = due !== undefined && due < today;
|
|
218
|
+
markers.set(step.id, beforeCurrent || overdue ? "late" : "pending");
|
|
219
|
+
}
|
|
220
|
+
return markers;
|
|
202
221
|
}
|
|
222
|
+
/**
|
|
223
|
+
* Buckets by declared group order, not consecutive runs, so a reordered rail still draws one
|
|
224
|
+
* header per group. Ungrouped steps go last.
|
|
225
|
+
*/
|
|
203
226
|
export function groupSteps(steps, groups = []) {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
227
|
+
const known = new Set(groups.map((g) => g.key));
|
|
228
|
+
const buckets = groups.map((g) => ({
|
|
229
|
+
key: g.key,
|
|
230
|
+
label: g.label,
|
|
231
|
+
steps: []
|
|
232
|
+
}));
|
|
233
|
+
const loose = {
|
|
234
|
+
key: "",
|
|
235
|
+
label: null,
|
|
236
|
+
steps: []
|
|
237
|
+
};
|
|
238
|
+
for (const step of steps) {
|
|
239
|
+
const bucket = buckets.find((b) => b.key === step.group);
|
|
240
|
+
(step.group && known.has(step.group) && bucket ? bucket : loose).steps.push(step);
|
|
241
|
+
}
|
|
242
|
+
const result = buckets.filter((b) => b.steps.length > 0);
|
|
243
|
+
if (loose.steps.length > 0) result.push(loose);
|
|
244
|
+
return result;
|
|
222
245
|
}
|
|
246
|
+
/** Move `movedId` next to `targetId` inside the id list. Same list back when nothing moves. */
|
|
223
247
|
export function reorderIds(ids, movedId, targetId, before) {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
...ids
|
|
233
|
-
];
|
|
234
|
-
next.splice(from, 1);
|
|
235
|
-
const at = next.indexOf(targetId);
|
|
236
|
-
next.splice(before ? at : at + 1, 0, movedId);
|
|
237
|
-
return next;
|
|
248
|
+
if (movedId === targetId) return [...ids];
|
|
249
|
+
const from = ids.indexOf(movedId);
|
|
250
|
+
if (from < 0 || !ids.includes(targetId)) return [...ids];
|
|
251
|
+
const next = [...ids];
|
|
252
|
+
next.splice(from, 1);
|
|
253
|
+
const at = next.indexOf(targetId);
|
|
254
|
+
next.splice(before ? at : at + 1, 0, movedId);
|
|
255
|
+
return next;
|
|
238
256
|
}
|
|
257
|
+
/** Swap a step with its neighbour in its own group. Same list back at an edge. */
|
|
239
258
|
export function nudgeStep(steps, id, direction) {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
259
|
+
const ids = steps.map((s) => s.id);
|
|
260
|
+
const step = steps.find((s) => s.id === id);
|
|
261
|
+
if (!step) return ids;
|
|
262
|
+
const mates = steps.filter((s) => s.group === step.group && !s.hidden);
|
|
263
|
+
const at = mates.findIndex((s) => s.id === id);
|
|
264
|
+
const neighbour = mates[at + direction];
|
|
265
|
+
if (!neighbour) return ids;
|
|
266
|
+
const a = ids.indexOf(id);
|
|
267
|
+
const b = ids.indexOf(neighbour.id);
|
|
268
|
+
const first = ids[a];
|
|
269
|
+
const second = ids[b];
|
|
270
|
+
if (first === undefined || second === undefined) return ids;
|
|
271
|
+
ids[a] = second;
|
|
272
|
+
ids[b] = first;
|
|
273
|
+
return ids;
|
|
255
274
|
}
|
package/dist/record/types.js
CHANGED
|
@@ -1,52 +1,53 @@
|
|
|
1
1
|
export const DEFAULT_RECORD_LABELS = {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
2
|
+
whereWeAre: "Where we are",
|
|
3
|
+
more: "More",
|
|
4
|
+
less: "Less",
|
|
5
|
+
next: "Next",
|
|
6
|
+
late: "Late",
|
|
7
|
+
steps: "Steps",
|
|
8
|
+
stepsCount: (done, total) => `${done}/${total}`,
|
|
9
|
+
editSteps: "Choose visible steps",
|
|
10
|
+
rename: "Rename",
|
|
11
|
+
resetName: "Reset name",
|
|
12
|
+
hide: "Hide",
|
|
13
|
+
show: "Show",
|
|
14
|
+
moveUp: "Move up",
|
|
15
|
+
moveDown: "Move down",
|
|
16
|
+
shownCount: (shown, total) => `${shown} of ${total} shown`,
|
|
17
|
+
openSteps: "Open steps",
|
|
18
|
+
activity: "Activity",
|
|
19
|
+
all: "All",
|
|
20
|
+
noEvents: "Nothing logged yet",
|
|
21
|
+
older: (count) => `Show ${count} older`,
|
|
22
|
+
today: "Today",
|
|
23
|
+
yesterday: "Yesterday",
|
|
24
|
+
by: (name) => `by ${name}`,
|
|
25
|
+
projects: "Projects",
|
|
26
|
+
projectCount: (count) => count === 1 ? "1 project" : `${count} projects`,
|
|
27
|
+
noProjects: "No projects",
|
|
28
|
+
details: "Details",
|
|
29
|
+
edit: (field) => `Edit ${field}`,
|
|
30
|
+
add: (field) => `Add ${field.toLowerCase()}`,
|
|
31
|
+
save: "Save",
|
|
32
|
+
cancel: "Cancel",
|
|
33
|
+
search: "Search",
|
|
34
|
+
noMatch: "No match",
|
|
35
|
+
pipeline: "Pipeline",
|
|
36
|
+
won: "Won",
|
|
37
|
+
paid: "Paid",
|
|
38
|
+
lastCall: "Last call",
|
|
39
|
+
lastTouch: "Last touch",
|
|
40
|
+
noCall: "None yet",
|
|
41
|
+
open: "Open",
|
|
42
|
+
edited: "edited",
|
|
43
|
+
noSteps: "No steps yet",
|
|
44
|
+
saveFailed: "Couldn't save",
|
|
45
|
+
required: "Required"
|
|
46
46
|
};
|
|
47
|
+
/** Merge a partial label set over the defaults. */
|
|
47
48
|
export function resolveLabels(labels) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
return labels ? {
|
|
50
|
+
...DEFAULT_RECORD_LABELS,
|
|
51
|
+
...labels
|
|
52
|
+
} : DEFAULT_RECORD_LABELS;
|
|
52
53
|
}
|
|
@@ -2,4 +2,6 @@ import Root from "../../../src/shadcn/accordion/accordion.svelte";
|
|
|
2
2
|
import Content from "../../../src/shadcn/accordion/accordion-content.svelte";
|
|
3
3
|
import Item from "../../../src/shadcn/accordion/accordion-item.svelte";
|
|
4
4
|
import Trigger from "../../../src/shadcn/accordion/accordion-trigger.svelte";
|
|
5
|
-
export { Content, Content as AccordionContent, Item, Item as AccordionItem, Root,
|
|
5
|
+
export { Content, Content as AccordionContent, Item, Item as AccordionItem, Root,
|
|
6
|
+
//
|
|
7
|
+
Root as Accordion, Trigger, Trigger as AccordionTrigger };
|
|
@@ -2,4 +2,6 @@ import Root from "../../../src/shadcn/alert/alert.svelte";
|
|
|
2
2
|
import Description from "../../../src/shadcn/alert/alert-description.svelte";
|
|
3
3
|
import Title from "../../../src/shadcn/alert/alert-title.svelte";
|
|
4
4
|
export { alertVariants } from "../../../src/shadcn/alert/alert.svelte";
|
|
5
|
-
export { Root, Description, Title,
|
|
5
|
+
export { Root, Description, Title,
|
|
6
|
+
//
|
|
7
|
+
Root as Alert, Description as AlertDescription, Title as AlertTitle };
|
|
@@ -9,4 +9,6 @@ import Header from "../../../src/shadcn/alert-dialog/alert-dialog-header.svelte"
|
|
|
9
9
|
import Overlay from "../../../src/shadcn/alert-dialog/alert-dialog-overlay.svelte";
|
|
10
10
|
import Content from "../../../src/shadcn/alert-dialog/alert-dialog-content.svelte";
|
|
11
11
|
import Description from "../../../src/shadcn/alert-dialog/alert-dialog-description.svelte";
|
|
12
|
-
export { Root, Title, Action, Cancel, Portal, Footer, Header, Trigger, Overlay, Content, Description,
|
|
12
|
+
export { Root, Title, Action, Cancel, Portal, Footer, Header, Trigger, Overlay, Content, Description,
|
|
13
|
+
//
|
|
14
|
+
Root as AlertDialog, Title as AlertDialogTitle, Action as AlertDialogAction, Cancel as AlertDialogCancel, Portal as AlertDialogPortal, Footer as AlertDialogFooter, Header as AlertDialogHeader, Trigger as AlertDialogTrigger, Overlay as AlertDialogOverlay, Content as AlertDialogContent, Description as AlertDialogDescription };
|
|
@@ -7,4 +7,6 @@ import Media from "../../../src/shadcn/attachment/attachment-media.svelte";
|
|
|
7
7
|
import Title from "../../../src/shadcn/attachment/attachment-title.svelte";
|
|
8
8
|
import Trigger from "../../../src/shadcn/attachment/attachment-trigger.svelte";
|
|
9
9
|
import Root, { attachmentVariants } from "../../../src/shadcn/attachment/attachment.svelte";
|
|
10
|
-
export { Root, Group, Media, Content, Title, Description, Actions, Action, Trigger, attachmentVariants,
|
|
10
|
+
export { Root, Group, Media, Content, Title, Description, Actions, Action, Trigger, attachmentVariants,
|
|
11
|
+
//
|
|
12
|
+
Root as Attachment, Group as AttachmentGroup, Media as AttachmentMedia, Content as AttachmentContent, Title as AttachmentTitle, Description as AttachmentDescription, Actions as AttachmentActions, Action as AttachmentAction, Trigger as AttachmentTrigger };
|
|
@@ -4,4 +4,6 @@ import Fallback from "../../../src/shadcn/avatar/avatar-fallback.svelte";
|
|
|
4
4
|
import Badge from "../../../src/shadcn/avatar/avatar-badge.svelte";
|
|
5
5
|
import Group from "../../../src/shadcn/avatar/avatar-group.svelte";
|
|
6
6
|
import GroupCount from "../../../src/shadcn/avatar/avatar-group-count.svelte";
|
|
7
|
-
export { Root, Image, Fallback, Badge, Group, GroupCount,
|
|
7
|
+
export { Root, Image, Fallback, Badge, Group, GroupCount,
|
|
8
|
+
//
|
|
9
|
+
Root as Avatar, Image as AvatarImage, Fallback as AvatarFallback, Badge as AvatarBadge, Group as AvatarGroup, GroupCount as AvatarGroupCount };
|
|
@@ -5,4 +5,6 @@ import Separator from "../../../src/shadcn/breadcrumb/breadcrumb-separator.svelt
|
|
|
5
5
|
import Link from "../../../src/shadcn/breadcrumb/breadcrumb-link.svelte";
|
|
6
6
|
import List from "../../../src/shadcn/breadcrumb/breadcrumb-list.svelte";
|
|
7
7
|
import Page from "../../../src/shadcn/breadcrumb/breadcrumb-page.svelte";
|
|
8
|
-
export { Root, Ellipsis, Item, Separator, Link, List, Page,
|
|
8
|
+
export { Root, Ellipsis, Item, Separator, Link, List, Page,
|
|
9
|
+
//
|
|
10
|
+
Root as Breadcrumb, Ellipsis as BreadcrumbEllipsis, Item as BreadcrumbItem, Separator as BreadcrumbSeparator, Link as BreadcrumbLink, List as BreadcrumbList, Page as BreadcrumbPage };
|