@heyramzi/ui 2.20.0 → 2.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/charts/dashboard/data-table.js +1 -2
- package/dist/components/list-page/filter-section.js +1 -1
- package/dist/components/list-page/list-table.js +5 -6
- package/dist/components/list-page/queue-rail.js +2 -1
- package/dist/components/picker/trigger.js +3 -3
- package/dist/components/segmented/segmented.js +5 -5
- package/dist/components/work-parts/looks.js +1 -1
- package/dist/shadcn/dialog/index.js +3 -2
- package/dist/shadcn/dropdown-menu/menu-item.js +1 -1
- package/dist/shadcn/sheet/index.js +3 -2
- package/dist/shadcn/skeleton/index.js +3 -2
- package/dist/status/index.js +1 -0
- package/dist/work/kanban-drag.js +13 -7
- package/package.json +1 -1
- package/src/ai/confirmation/ConfirmationTitle.svelte +1 -4
- package/src/ai/loading-state/PixelLoader.svelte +1 -1
- package/src/animations/dropdown.css +19 -10
- package/src/animations/modal.css +7 -2
- package/src/charts/charts.css +3 -5
- package/src/charts/dashboard/dashboard-section.svelte +1 -1
- package/src/charts/dashboard/data-table.ts +1 -2
- package/src/charts/dashboard/stat-tile.svelte +1 -1
- package/src/charts/number-chart.css +8 -7
- package/src/charts/pop-value.svelte +68 -0
- package/src/charts/primitives/chart-tooltip.svelte +1 -1
- package/src/charts/reference-line.css +1 -1
- package/src/charts/stat-card.css +4 -4
- package/src/components/copy/copy-button.svelte +11 -10
- package/src/components/data-table/row-arrow.svelte +1 -1
- package/src/components/data-table/row-context-menu.svelte +1 -1
- package/src/components/data-table/sortable-head.svelte +2 -2
- package/src/components/data-table/table-skeleton.svelte +5 -5
- package/src/components/docs/doc-page.svelte +1 -3
- package/src/components/docs/on-this-page.svelte +4 -4
- package/src/components/field-row/field-row.svelte +1 -1
- package/src/components/list-page/detail-empty.svelte +3 -8
- package/src/components/list-page/detail-header.svelte +1 -1
- package/src/components/list-page/detail-row.svelte +2 -1
- package/src/components/list-page/empty-state.svelte +15 -7
- package/src/components/list-page/filter-item.svelte +2 -2
- package/src/components/list-page/filter-popover.svelte +1 -1
- package/src/components/list-page/filter-section.ts +1 -4
- package/src/components/list-page/grouped-list.svelte +37 -8
- package/src/components/list-page/list-page-shell.svelte +1 -1
- package/src/components/list-page/list-table.ts +6 -6
- package/src/components/list-page/master-detail.svelte +1 -1
- package/src/components/list-page/queue-rail.ts +2 -2
- package/src/components/list-page/rail-empty.svelte +1 -1
- package/src/components/list-page/rail-row.svelte +5 -5
- package/src/components/open-in/open-in.svelte +2 -1
- package/src/components/picker/trigger.ts +6 -5
- package/src/components/section-card/section-card.svelte +1 -1
- package/src/components/section-header/section-header.svelte +4 -2
- package/src/components/section-header/section-label.svelte +2 -2
- package/src/components/segmented/animated-tabs.svelte +1 -1
- package/src/components/segmented/section-runs.svelte +1 -1
- package/src/components/segmented/segment.svelte +4 -6
- package/src/components/segmented/segmented-track.svelte +18 -52
- package/src/components/segmented/segmented.ts +5 -5
- package/src/components/table-view/table-view.svelte +43 -24
- package/src/components/tags-input/tags-input.svelte +17 -31
- package/src/components/work-parts/looks.ts +1 -1
- package/src/editor/content.css +3 -3
- package/src/editor/editor.svelte +1 -1
- package/src/inbox/thread-inbox.svelte +2 -9
- package/src/panel/side-panel.svelte +9 -4
- package/src/record/info-list.svelte +7 -8
- package/src/record/project-list.svelte +1 -1
- package/src/record/record-demo.svelte +2 -4
- package/src/record/record-shell.svelte +1 -1
- package/src/record/record-stats.svelte +9 -3
- package/src/record/steps-rail.svelte +7 -11
- package/src/shadcn/accordion/accordion-trigger.svelte +1 -1
- package/src/shadcn/alert-dialog/alert-dialog-content.svelte +5 -1
- package/src/shadcn/alert-dialog/alert-dialog-footer.svelte +12 -2
- package/src/shadcn/alert-dialog/alert-dialog-header.svelte +1 -1
- package/src/shadcn/alert-dialog/alert-dialog-title.svelte +1 -1
- package/src/shadcn/badge/badge.svelte +3 -1
- package/src/shadcn/bubble/bubble-content.svelte +1 -1
- package/src/shadcn/bubble/bubble.svelte +1 -1
- package/src/shadcn/button/button.svelte +11 -5
- package/src/shadcn/calendar/calendar-month-select.svelte +1 -1
- package/src/shadcn/calendar/calendar-year-select.svelte +1 -1
- package/src/shadcn/calendar/calendar.svelte +1 -1
- package/src/shadcn/card/card.svelte +2 -1
- package/src/shadcn/checkbox/checkbox.svelte +1 -1
- package/src/shadcn/code-block/code-block-actions.svelte +1 -1
- package/src/shadcn/command/command-dialog.svelte +2 -2
- package/src/shadcn/command/command-group.svelte +1 -1
- package/src/shadcn/command/command-input.svelte +1 -1
- package/src/shadcn/command/command-item.svelte +1 -1
- package/src/shadcn/dialog/dialog-body.svelte +22 -0
- package/src/shadcn/dialog/dialog-content.svelte +19 -4
- package/src/shadcn/dialog/dialog-footer.svelte +19 -1
- package/src/shadcn/dialog/dialog-header.svelte +6 -1
- package/src/shadcn/dialog/dialog-title.svelte +2 -1
- package/src/shadcn/dialog/index.ts +3 -0
- package/src/shadcn/dropdown-menu/dropdown-menu-content.svelte +5 -1
- package/src/shadcn/dropdown-menu/dropdown-menu-sub-content.svelte +1 -1
- package/src/shadcn/dropdown-menu/menu-item.ts +1 -1
- package/src/shadcn/field/field-separator.svelte +1 -1
- package/src/shadcn/hover-card/hover-card-content.svelte +1 -1
- package/src/shadcn/input/input.svelte +2 -2
- package/src/shadcn/input-otp/input-otp-slot.svelte +1 -1
- package/src/shadcn/message-scroller/message-scroller-button.svelte +1 -1
- package/src/shadcn/popover/popover-content.svelte +1 -1
- package/src/shadcn/radio-group/radio-group-item.svelte +1 -1
- package/src/shadcn/scroll-area/scroll-area.svelte +1 -1
- package/src/shadcn/select/select-content.svelte +6 -2
- package/src/shadcn/select/select-item.svelte +1 -1
- package/src/shadcn/select/select-trigger.svelte +1 -1
- package/src/shadcn/sheet/index.ts +3 -0
- package/src/shadcn/sheet/sheet-body.svelte +22 -0
- package/src/shadcn/sheet/sheet-content.svelte +27 -5
- package/src/shadcn/sheet/sheet-footer.svelte +14 -2
- package/src/shadcn/sheet/sheet-header.svelte +1 -1
- package/src/shadcn/sheet/sheet-title.svelte +1 -1
- package/src/shadcn/sheet/sheet.css +11 -5
- package/src/shadcn/sidebar/sidebar-group-action.svelte +1 -1
- package/src/shadcn/sidebar/sidebar-group-label.svelte +1 -1
- package/src/shadcn/sidebar/sidebar-inset.svelte +1 -1
- package/src/shadcn/sidebar/sidebar-menu-action.svelte +1 -1
- package/src/shadcn/sidebar/sidebar-menu-button.svelte +2 -2
- package/src/shadcn/sidebar/sidebar-menu-sub-button.svelte +1 -1
- package/src/shadcn/sidebar/sidebar-menu.svelte +1 -1
- package/src/shadcn/sidebar/sidebar.svelte +1 -1
- package/src/shadcn/skeleton/index.ts +3 -0
- package/src/shadcn/skeleton/skeleton-delay.svelte +63 -0
- package/src/shadcn/skeleton/skeleton-delay.svelte.test.ts +57 -0
- package/src/shadcn/skeleton/skeleton.svelte +5 -1
- package/src/shadcn/slider/slider.svelte +1 -1
- package/src/shadcn/switch/switch.svelte +2 -2
- package/src/shadcn/table/table-row.svelte +1 -1
- package/src/shadcn/tabs/tabs-list.svelte +1 -1
- package/src/shadcn/tabs/tabs-trigger.svelte +2 -1
- package/src/shadcn/textarea/textarea.svelte +1 -1
- package/src/shadcn/toggle/toggle.svelte +2 -2
- package/src/shadcn/toggle-group/toggle-group.svelte +1 -1
- package/src/shadcn/tooltip/tooltip-content.svelte +1 -1
- package/src/shadcn/trace/trace-collapsible-trigger.svelte +1 -1
- package/src/shadcn/trace/trace.svelte +1 -1
- package/src/status/README.md +1 -1
- package/src/status/index.ts +1 -0
- package/src/status/status-badge.svelte +21 -7
- package/src/status/status-dot.svelte +6 -11
- package/src/status/status-pill.svelte +50 -0
- package/src/thread/thread.svelte +54 -136
- package/src/tokens/craft.css +55 -36
- package/src/tokens/palette.css +16 -9
- package/src/work/demo.svelte +48 -42
- package/src/work/detail/detail-demo.svelte +33 -24
- package/src/work/detail/task-chip.svelte +4 -4
- package/src/work/detail/task-detail.svelte +41 -108
- package/src/work/detail/task-property.svelte +7 -13
- package/src/work/detail/task-thread.svelte +48 -119
- package/src/work/docs/doc-editor-page.svelte +5 -4
- package/src/work/docs/doc-menu.svelte +9 -4
- package/src/work/docs/docs-demo.svelte +4 -4
- package/src/work/docs/edited-chip.svelte +11 -4
- package/src/work/gantt/gantt-bar.svelte +18 -14
- package/src/work/gantt/gantt-grid.svelte +7 -7
- package/src/work/gantt/gantt-group-row.svelte +7 -10
- package/src/work/gantt/gantt-header.svelte +3 -1
- package/src/work/gantt/gantt-task-row.svelte +19 -9
- package/src/work/gantt/gantt.css +4 -5
- package/src/work/inbox/inbox-card.svelte +32 -10
- package/src/work/inbox/inbox-draft.svelte +2 -2
- package/src/work/kanban-column.svelte +7 -15
- package/src/work/kanban-drag.ts +13 -8
- package/src/work/task-gantt.svelte +2 -1
- package/src/work/task-list.svelte +54 -53
- package/src/work/time/time-chip.svelte +16 -19
- package/src/work/time/time-dot.svelte +2 -1
- package/src/work/time/time-ring.svelte +2 -3
- package/src/work/time/time-tracker.svelte +72 -166
package/src/tokens/palette.css
CHANGED
|
@@ -31,11 +31,13 @@
|
|
|
31
31
|
|
|
32
32
|
/* Dark surfaces. Light pendants are surface-light, line-light and paper. */
|
|
33
33
|
--brand-ink: oklch(0.145 0 0); /* Page background */
|
|
34
|
-
--brand-surface: oklch(0.
|
|
34
|
+
--brand-surface: oklch(0.2 0 0); /* Cards, panels: 0.055 over the page, the light step */
|
|
35
35
|
--brand-line: oklch(0.29 0 0); /* Borders, dividers */
|
|
36
36
|
--brand-raised: oklch(0.24 0 0); /* Hover surfaces, inputs, between surface and line */
|
|
37
37
|
--brand-paper: oklch(0.97 0 0); /* Text on dark, light backgrounds */
|
|
38
|
-
|
|
38
|
+
/* Two levels, grey canvas and white card: the 0.055 step dark uses, and muted text keeps 6.3:1. */
|
|
39
|
+
--brand-canvas-light: oklch(0.945 0 0); /* The page, the sidebar under it */
|
|
40
|
+
--brand-surface-light: oklch(1 0 0); /* Cards, popovers, the shell panel on a light page */
|
|
39
41
|
--brand-line-light: oklch(0.91 0 0); /* Borders on a light page */
|
|
40
42
|
|
|
41
43
|
/* The key button. Each theme has its own pair, since a hue lifted for dark needs dark text. */
|
|
@@ -111,12 +113,12 @@
|
|
|
111
113
|
--black: oklch(0 0 0);
|
|
112
114
|
|
|
113
115
|
/* === Sidebar Colors === */
|
|
114
|
-
/*
|
|
115
|
-
--sidebar:
|
|
116
|
+
/* The sidebar sits on the canvas, not on a third grey, and the active item is a card on it. */
|
|
117
|
+
--sidebar: var(--brand-canvas-light);
|
|
116
118
|
--sidebar-foreground: oklch(0.45 0 0);
|
|
117
119
|
--sidebar-primary: oklch(0.15 0 0);
|
|
118
120
|
--sidebar-primary-foreground: oklch(0.98 0 0);
|
|
119
|
-
--sidebar-accent:
|
|
121
|
+
--sidebar-accent: var(--brand-surface-light);
|
|
120
122
|
--sidebar-accent-foreground: oklch(0.15 0 0);
|
|
121
123
|
--sidebar-border: oklch(0.91 0 0);
|
|
122
124
|
--sidebar-ring: var(--brand);
|
|
@@ -146,6 +148,7 @@
|
|
|
146
148
|
--color-line: var(--brand-line);
|
|
147
149
|
--color-raised: var(--brand-raised);
|
|
148
150
|
--color-paper: var(--brand-paper);
|
|
151
|
+
--color-canvas-light: var(--brand-canvas-light);
|
|
149
152
|
--color-surface-light: var(--brand-surface-light);
|
|
150
153
|
--color-line-light: var(--brand-line-light);
|
|
151
154
|
|
|
@@ -216,7 +219,7 @@
|
|
|
216
219
|
);
|
|
217
220
|
|
|
218
221
|
/* Light theme color system: the light surfaces and lines of the brand roles */
|
|
219
|
-
--color-background: var(--
|
|
222
|
+
--color-background: var(--brand-canvas-light);
|
|
220
223
|
--color-foreground: var(--gray-900);
|
|
221
224
|
--color-foreground-muted: var(--gray-700);
|
|
222
225
|
|
|
@@ -342,14 +345,18 @@
|
|
|
342
345
|
--color-destructive-foreground: var(--brand-paper);
|
|
343
346
|
|
|
344
347
|
--color-border: var(--brand-line);
|
|
345
|
-
|
|
348
|
+
/* WHY not raised: raised equals muted, so an input's edge vanished on the card. Mixed from the
|
|
349
|
+
brand's own paper and surface so a brand that moves them keeps the step. Neutral defaults:
|
|
350
|
+
L 0.547, 3.7:1 on the card (L 0.2), 4.0:1 on the canvas (L 0.145), past the 3:1 for an edge.
|
|
351
|
+
Fills read it at /30 (L 0.30), a step over the card. */
|
|
352
|
+
--color-input: color-mix(in oklab, var(--brand-paper) 45%, var(--brand-surface));
|
|
346
353
|
--color-ring: var(--brand-on-dark);
|
|
347
354
|
|
|
348
355
|
/* The brand colour lifts for contrast on the dark page. */
|
|
349
356
|
--color-brand: var(--brand-on-dark);
|
|
350
357
|
|
|
351
|
-
/* Dark sidebar */
|
|
352
|
-
--sidebar: var(--brand-
|
|
358
|
+
/* Dark sidebar: on the page, like light, so the cards are the only raised level */
|
|
359
|
+
--sidebar: var(--brand-ink);
|
|
353
360
|
--sidebar-foreground: var(--brand-paper);
|
|
354
361
|
--sidebar-primary: var(--brand-on-dark);
|
|
355
362
|
--sidebar-primary-foreground: oklch(1 0 0);
|
package/src/work/demo.svelte
CHANGED
|
@@ -3,7 +3,19 @@
|
|
|
3
3
|
import TaskList from "./task-list.svelte";
|
|
4
4
|
import TaskGantt from "./task-gantt.svelte";
|
|
5
5
|
import { SegmentedFilter } from "../components/segmented/index.js";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
CalendarBlank,
|
|
8
|
+
CellSignalFull,
|
|
9
|
+
CellSignalLow,
|
|
10
|
+
CellSignalMedium,
|
|
11
|
+
ChartBarHorizontal,
|
|
12
|
+
Kanban,
|
|
13
|
+
ListBullets,
|
|
14
|
+
} from "phosphor-svelte";
|
|
15
|
+
import StatusPill from "../status/status-pill.svelte";
|
|
16
|
+
import { Card } from "../shadcn/card/index.js";
|
|
17
|
+
import WorkCard from "../components/work-parts/work-card.svelte";
|
|
18
|
+
import type { Tone } from "../lib/tone.js";
|
|
7
19
|
import StatusBadge from "../status/status-badge.svelte";
|
|
8
20
|
import StatusDot from "../status/status-dot.svelte";
|
|
9
21
|
import { defineStatuses } from "../status/define-statuses.js";
|
|
@@ -161,11 +173,12 @@
|
|
|
161
173
|
{ id: "due", label: "Due date", compare: (a: Task, b: Task) => a.end.localeCompare(b.end) },
|
|
162
174
|
];
|
|
163
175
|
|
|
164
|
-
const
|
|
165
|
-
low: "
|
|
166
|
-
medium: "
|
|
167
|
-
high: "
|
|
176
|
+
const priorityTone: Record<Priority, Tone> = {
|
|
177
|
+
low: "neutral",
|
|
178
|
+
medium: "warning",
|
|
179
|
+
high: "destructive",
|
|
168
180
|
};
|
|
181
|
+
const priorityIcon = { low: CellSignalLow, medium: CellSignalMedium, high: CellSignalFull };
|
|
169
182
|
|
|
170
183
|
const people: Record<string, string> = {
|
|
171
184
|
Ada: "oklch(0.72 0.12 280)",
|
|
@@ -275,6 +288,14 @@
|
|
|
275
288
|
"grid grid-cols-[minmax(0,1fr)_7rem_5.5rem_4.5rem] items-center gap-3 max-sm:grid-cols-[minmax(0,1fr)_4.5rem]";
|
|
276
289
|
</script>
|
|
277
290
|
|
|
291
|
+
{#snippet priority(level: Priority)}
|
|
292
|
+
{@const Icon = priorityIcon[level]}
|
|
293
|
+
<StatusPill tone={priorityTone[level]} class="capitalize">
|
|
294
|
+
{#snippet icon()}<Icon weight="bold" aria-hidden="true" />{/snippet}
|
|
295
|
+
{level}
|
|
296
|
+
</StatusPill>
|
|
297
|
+
{/snippet}
|
|
298
|
+
|
|
278
299
|
{#snippet avatar(name: string)}
|
|
279
300
|
<span
|
|
280
301
|
class="grid size-5 shrink-0 place-items-center rounded-full text-[10px] font-semibold text-white"
|
|
@@ -285,7 +306,7 @@
|
|
|
285
306
|
</span>
|
|
286
307
|
{/snippet}
|
|
287
308
|
|
|
288
|
-
<
|
|
309
|
+
<Card class="gap-6 p-4">
|
|
289
310
|
<div class="flex h-[600px] flex-col gap-3">
|
|
290
311
|
<div class="flex flex-wrap items-center gap-2">
|
|
291
312
|
<SegmentedFilter options={views} bind:value={view} ariaLabel="Task view" block={false} />
|
|
@@ -312,7 +333,7 @@
|
|
|
312
333
|
<select
|
|
313
334
|
id="tasks-sort"
|
|
314
335
|
bind:value={sortKey}
|
|
315
|
-
class="h-8 rounded-md border border-border bg-
|
|
336
|
+
class="h-8 rounded-md border border-border bg-card px-2 text-xs text-foreground"
|
|
316
337
|
>
|
|
317
338
|
<option value="manual">Manual</option>
|
|
318
339
|
{#each sortKeys as key (key.id)}
|
|
@@ -338,15 +359,15 @@
|
|
|
338
359
|
>
|
|
339
360
|
{#snippet renderCard(task)}
|
|
340
361
|
{@const d = due(task)}
|
|
341
|
-
<
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
{@render avatar(task.assignee)}
|
|
347
|
-
<span class={d.late ? "font-medium text-destructive" : "text-muted-foreground"}
|
|
348
|
-
>{d.label}</span
|
|
362
|
+
<WorkCard>
|
|
363
|
+
{task.title}
|
|
364
|
+
{#snippet meta()}
|
|
365
|
+
<span
|
|
366
|
+
class="flex items-center gap-1 {d.late ? 'font-medium text-destructive' : ''}"
|
|
349
367
|
>
|
|
368
|
+
<CalendarBlank class="size-3.5" aria-hidden="true" />
|
|
369
|
+
{d.label}
|
|
370
|
+
</span>
|
|
350
371
|
{#if tracking}
|
|
351
372
|
<TimeChip
|
|
352
373
|
minutes={minutesByTask[task.id] ?? 0}
|
|
@@ -354,15 +375,12 @@
|
|
|
354
375
|
running={timer?.taskId === task.id}
|
|
355
376
|
/>
|
|
356
377
|
{/if}
|
|
357
|
-
<span
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
]}"
|
|
361
|
-
>
|
|
362
|
-
{task.priority}
|
|
378
|
+
<span class="ms-auto flex items-center gap-1.5">
|
|
379
|
+
{@render priority(task.priority)}
|
|
380
|
+
{@render avatar(task.assignee)}
|
|
363
381
|
</span>
|
|
364
|
-
|
|
365
|
-
</
|
|
382
|
+
{/snippet}
|
|
383
|
+
</WorkCard>
|
|
366
384
|
{/snippet}
|
|
367
385
|
</KanbanBoard>
|
|
368
386
|
{:else if view === "list"}
|
|
@@ -386,7 +404,7 @@
|
|
|
386
404
|
{/snippet}
|
|
387
405
|
{#snippet renderRow(task)}
|
|
388
406
|
{@const d = due(task)}
|
|
389
|
-
<div class="{listGrid}
|
|
407
|
+
<div class="{listGrid} px-2 text-sm">
|
|
390
408
|
<span class="flex min-w-0 items-center gap-2.5">
|
|
391
409
|
{#key task.status}
|
|
392
410
|
<StatusDot {statuses} status={task.status} />
|
|
@@ -410,15 +428,7 @@
|
|
|
410
428
|
{@render avatar(task.assignee)}
|
|
411
429
|
<span class="truncate">{task.assignee}</span>
|
|
412
430
|
</span>
|
|
413
|
-
<span class="max-sm:hidden">
|
|
414
|
-
<span
|
|
415
|
-
class="rounded-full px-1.5 py-0.5 text-xs font-medium capitalize {priorityClass[
|
|
416
|
-
task.priority
|
|
417
|
-
]}"
|
|
418
|
-
>
|
|
419
|
-
{task.priority}
|
|
420
|
-
</span>
|
|
421
|
-
</span>
|
|
431
|
+
<span class="max-sm:hidden">{@render priority(task.priority)}</span>
|
|
422
432
|
<span
|
|
423
433
|
class="text-right text-xs tabular-nums {d.late
|
|
424
434
|
? 'font-medium text-destructive'
|
|
@@ -469,13 +479,11 @@
|
|
|
469
479
|
{#if tracking}
|
|
470
480
|
<section class="flex flex-col gap-3 border-t border-border pt-4">
|
|
471
481
|
<div class="flex items-center justify-between gap-3">
|
|
472
|
-
<h3 class="text-xs font-semibold
|
|
473
|
-
Task time
|
|
474
|
-
</h3>
|
|
482
|
+
<h3 class="text-xs font-semibold text-muted-foreground">Task time</h3>
|
|
475
483
|
<select
|
|
476
484
|
bind:value={timeTaskId}
|
|
477
485
|
aria-label="Task"
|
|
478
|
-
class="h-8 max-w-[60%] rounded-md border border-border bg-
|
|
486
|
+
class="h-8 max-w-[60%] rounded-md border border-border bg-card px-2 text-xs text-foreground"
|
|
479
487
|
>
|
|
480
488
|
{#each tasks as task (task.id)}
|
|
481
489
|
<option value={task.id}>{task.title}</option>
|
|
@@ -483,7 +491,7 @@
|
|
|
483
491
|
</select>
|
|
484
492
|
</div>
|
|
485
493
|
<TimeTracker
|
|
486
|
-
class="
|
|
494
|
+
class="w-full max-w-xl"
|
|
487
495
|
entries={timeEntries}
|
|
488
496
|
getId={(entry) => entry.id}
|
|
489
497
|
getMinutes={(entry) => entry.minutes}
|
|
@@ -505,9 +513,7 @@
|
|
|
505
513
|
{/if}
|
|
506
514
|
|
|
507
515
|
<section class="flex flex-col gap-2 border-t border-border pt-4">
|
|
508
|
-
<h3 class="text-xs font-semibold
|
|
509
|
-
Status badges
|
|
510
|
-
</h3>
|
|
516
|
+
<h3 class="text-xs font-semibold text-muted-foreground">Status badges</h3>
|
|
511
517
|
<div class="flex flex-wrap items-center gap-2">
|
|
512
518
|
{#each salesStatuses.ids as id (id)}
|
|
513
519
|
<StatusBadge statuses={salesStatuses} status={id} />
|
|
@@ -522,7 +528,7 @@
|
|
|
522
528
|
{/each}
|
|
523
529
|
</ul>
|
|
524
530
|
</section>
|
|
525
|
-
</
|
|
531
|
+
</Card>
|
|
526
532
|
|
|
527
533
|
<style>
|
|
528
534
|
/* Switching views: the new one rises in with a touch of blur, the old one is gone at once. */
|
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
CalendarBlank,
|
|
4
|
+
CircleDashed,
|
|
5
|
+
CircleHalf,
|
|
6
|
+
Flag,
|
|
7
|
+
Folder,
|
|
8
|
+
Timer,
|
|
9
|
+
User,
|
|
10
|
+
UserCircle,
|
|
11
|
+
} from "phosphor-svelte";
|
|
12
|
+
import { Button } from "../../shadcn/button/index.js";
|
|
13
|
+
import { Card } from "../../shadcn/card/index.js";
|
|
14
|
+
import * as Avatar from "../../shadcn/avatar/index.js";
|
|
3
15
|
import TaskDetail from "./task-detail.svelte";
|
|
4
16
|
import TaskProperty from "./task-property.svelte";
|
|
5
17
|
import TaskChip from "./task-chip.svelte";
|
|
@@ -144,29 +156,27 @@
|
|
|
144
156
|
<div class="flex flex-col gap-3">
|
|
145
157
|
<div class="flex flex-wrap items-center gap-1.5" role="group" aria-label="Scenario">
|
|
146
158
|
{#each scenarios as item (item.id)}
|
|
147
|
-
<
|
|
148
|
-
|
|
159
|
+
<Button
|
|
160
|
+
size="sm"
|
|
161
|
+
variant={scenario === item.id ? "default" : "outline"}
|
|
149
162
|
aria-pressed={scenario === item.id}
|
|
150
163
|
onclick={() => (scenario = item.id)}
|
|
151
|
-
class="h-7 rounded-md border border-border px-2.5 text-[13px] font-medium transition-colors hover:bg-muted aria-pressed:bg-foreground aria-pressed:text-background"
|
|
152
164
|
>
|
|
153
165
|
{item.label}
|
|
154
|
-
</
|
|
166
|
+
</Button>
|
|
155
167
|
{/each}
|
|
156
|
-
<
|
|
157
|
-
|
|
168
|
+
<Button
|
|
169
|
+
size="sm"
|
|
170
|
+
variant={narrow ? "default" : "outline"}
|
|
171
|
+
class="ms-auto"
|
|
158
172
|
aria-pressed={narrow}
|
|
159
173
|
onclick={() => (narrow = !narrow)}
|
|
160
|
-
class="ms-auto h-7 rounded-md border border-border px-2.5 text-[13px] font-medium transition-colors hover:bg-muted aria-pressed:bg-foreground aria-pressed:text-background"
|
|
161
174
|
>
|
|
162
175
|
390 wide
|
|
163
|
-
</
|
|
176
|
+
</Button>
|
|
164
177
|
</div>
|
|
165
178
|
|
|
166
|
-
<
|
|
167
|
-
class="mx-auto w-full overflow-hidden rounded-xl border border-border bg-background"
|
|
168
|
-
style:max-width={narrow ? "390px" : "none"}
|
|
169
|
-
>
|
|
179
|
+
<Card class="mx-auto w-full gap-0 py-0" style="max-width: {narrow ? '390px' : 'none'}">
|
|
170
180
|
<TaskDetail
|
|
171
181
|
{title}
|
|
172
182
|
onTitleChange={(next) => {
|
|
@@ -192,35 +202,34 @@
|
|
|
192
202
|
<span class="tabular-nums">Created Sep 9, 2026</span>
|
|
193
203
|
{/snippet}
|
|
194
204
|
{#snippet properties()}
|
|
195
|
-
<TaskProperty label="Status">
|
|
205
|
+
<TaskProperty label="Status" icon={CircleHalf}>
|
|
196
206
|
<TaskChip aria-label="Status: {statusLabel}"
|
|
197
207
|
><StatusDot {statuses} {status} size={14} animate={false} />{statusLabel}</TaskChip
|
|
198
208
|
>
|
|
199
209
|
</TaskProperty>
|
|
200
|
-
<TaskProperty label="Priority">
|
|
210
|
+
<TaskProperty label="Priority" icon={Flag}>
|
|
201
211
|
<TaskChip><Flag weight="fill" class="text-destructive" aria-hidden="true" />High</TaskChip
|
|
202
212
|
>
|
|
203
213
|
</TaskProperty>
|
|
204
|
-
<TaskProperty label="Assignee">
|
|
214
|
+
<TaskProperty label="Assignee" icon={UserCircle}>
|
|
205
215
|
{#if assignee}
|
|
206
216
|
<TaskChip>
|
|
207
|
-
<
|
|
208
|
-
class="
|
|
209
|
-
|
|
210
|
-
>
|
|
217
|
+
<Avatar.Root class="size-4" aria-hidden="true">
|
|
218
|
+
<Avatar.Fallback><User class="size-3" /></Avatar.Fallback>
|
|
219
|
+
</Avatar.Root>
|
|
211
220
|
{assignee}
|
|
212
221
|
</TaskChip>
|
|
213
222
|
{:else}
|
|
214
223
|
<TaskChip empty><CircleDashed aria-hidden="true" />Assign</TaskChip>
|
|
215
224
|
{/if}
|
|
216
225
|
</TaskProperty>
|
|
217
|
-
<TaskProperty label="Due date">
|
|
226
|
+
<TaskProperty label="Due date" icon={CalendarBlank}>
|
|
218
227
|
<TaskChip><CalendarBlank aria-hidden="true" />Oct 9, 2026</TaskChip>
|
|
219
228
|
</TaskProperty>
|
|
220
|
-
<TaskProperty label="Project">
|
|
229
|
+
<TaskProperty label="Project" icon={Folder}>
|
|
221
230
|
<TaskChip><Folder aria-hidden="true" />Agency OS</TaskChip>
|
|
222
231
|
</TaskProperty>
|
|
223
|
-
<TaskProperty label="Time">
|
|
232
|
+
<TaskProperty label="Time" icon={Timer}>
|
|
224
233
|
<TimeTracker
|
|
225
234
|
{entries}
|
|
226
235
|
running={timer}
|
|
@@ -242,5 +251,5 @@
|
|
|
242
251
|
</TaskProperty>
|
|
243
252
|
{/snippet}
|
|
244
253
|
</TaskDetail>
|
|
245
|
-
</
|
|
254
|
+
</Card>
|
|
246
255
|
</div>
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import type { Snippet } from "svelte";
|
|
3
3
|
import type { HTMLButtonAttributes } from "svelte/elements";
|
|
4
4
|
import { cn } from "../../lib/utils.js";
|
|
5
|
+
import { buttonVariants } from "../../shadcn/button/index.js";
|
|
5
6
|
|
|
6
7
|
interface Props extends Omit<HTMLButtonAttributes, "children"> {
|
|
7
8
|
/** No value yet: the label is a prompt and recedes until hovered. */
|
|
@@ -12,13 +13,12 @@
|
|
|
12
13
|
let { empty = false, class: className, children, ...rest }: Props = $props();
|
|
13
14
|
</script>
|
|
14
15
|
|
|
15
|
-
<!-- The one box every property value sits in: 28px, 40 under a coarse pointer. -->
|
|
16
|
+
<!-- The one box every property value sits in: a quiet ghost Button, 28px, 40 under a coarse pointer. -->
|
|
16
17
|
<button
|
|
17
18
|
type="button"
|
|
18
19
|
class={cn(
|
|
19
|
-
|
|
20
|
-
"
|
|
21
|
-
"disabled:pointer-events-none disabled:opacity-50 [&_svg]:size-3.5 [&_svg]:shrink-0",
|
|
20
|
+
buttonVariants({ variant: "ghost", size: "sm" }),
|
|
21
|
+
"min-w-0 justify-start ps-1.5 pe-2.5 text-(length:--text-control) font-normal data-[state=open]:bg-muted",
|
|
22
22
|
empty && "text-muted-foreground hover:text-foreground",
|
|
23
23
|
className,
|
|
24
24
|
)}
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
import type { Snippet } from "svelte";
|
|
3
3
|
import { Circle, CheckCircle, PencilSimple } from "phosphor-svelte";
|
|
4
4
|
import { cn } from "../../lib/utils.js";
|
|
5
|
+
import { Button } from "../../shadcn/button/index.js";
|
|
6
|
+
import { Textarea } from "../../shadcn/textarea/index.js";
|
|
5
7
|
import {
|
|
6
8
|
DEFAULT_TASK_DETAIL_LABELS,
|
|
7
9
|
type TaskComment,
|
|
@@ -118,13 +120,15 @@
|
|
|
118
120
|
<header class="min-w-0 px-4 pt-6 @3xl:col-start-1 @3xl:px-8">
|
|
119
121
|
<div class="mx-auto w-full max-w-184">
|
|
120
122
|
<div class="flex items-start gap-2">
|
|
121
|
-
<
|
|
122
|
-
|
|
123
|
+
<Button
|
|
124
|
+
variant="ghost"
|
|
125
|
+
size="sm"
|
|
126
|
+
icon
|
|
123
127
|
onclick={onToggleDone}
|
|
124
128
|
disabled={!onToggleDone}
|
|
125
129
|
aria-label={done ? labels.markIncomplete : labels.markComplete}
|
|
126
130
|
class={cn(
|
|
127
|
-
"
|
|
131
|
+
"mt-px disabled:opacity-100",
|
|
128
132
|
done ? "text-success" : "text-muted-foreground/60 hover:text-foreground",
|
|
129
133
|
)}
|
|
130
134
|
>
|
|
@@ -133,30 +137,30 @@
|
|
|
133
137
|
{:else}
|
|
134
138
|
<Circle class="size-5" aria-hidden="true" />
|
|
135
139
|
{/if}
|
|
136
|
-
</
|
|
140
|
+
</Button>
|
|
137
141
|
|
|
138
142
|
{#if editingTitle}
|
|
139
|
-
<
|
|
140
|
-
bind:
|
|
143
|
+
<Textarea
|
|
144
|
+
bind:ref={titleField}
|
|
141
145
|
bind:value={titleDraft}
|
|
142
146
|
onkeydown={onTitleKeydown}
|
|
143
147
|
onblur={commitTitle}
|
|
144
148
|
rows={2}
|
|
145
149
|
aria-label={labels.editTitle}
|
|
146
|
-
class="-mx-2 -my-1 min-w-0 flex-1 resize-none
|
|
147
|
-
|
|
150
|
+
class="-mx-2 -my-1 min-h-0 min-w-0 flex-1 resize-none px-2 py-1 text-2xl leading-tight font-semibold tracking-tight md:text-2xl"
|
|
151
|
+
/>
|
|
148
152
|
{:else}
|
|
149
153
|
<h1
|
|
150
154
|
class="min-w-0 flex-1 text-2xl leading-tight font-semibold tracking-tight text-balance break-words"
|
|
151
155
|
>
|
|
152
|
-
<
|
|
153
|
-
|
|
156
|
+
<Button
|
|
157
|
+
variant="text"
|
|
154
158
|
onclick={startTitle}
|
|
155
159
|
disabled={!onTitleChange}
|
|
156
160
|
aria-label={labels.editTitle}
|
|
157
161
|
class={cn(
|
|
158
|
-
"group -mx-2 -my-1
|
|
159
|
-
onTitleChange && "hover:bg-
|
|
162
|
+
"group -mx-2 -my-1 px-2 py-1 text-2xl leading-tight font-semibold tracking-tight disabled:opacity-100",
|
|
163
|
+
!onTitleChange && "hover:bg-transparent",
|
|
160
164
|
closed && "text-muted-foreground",
|
|
161
165
|
)}
|
|
162
166
|
>
|
|
@@ -167,7 +171,7 @@
|
|
|
167
171
|
aria-hidden="true"
|
|
168
172
|
/>
|
|
169
173
|
{/if}
|
|
170
|
-
</
|
|
174
|
+
</Button>
|
|
171
175
|
</h1>
|
|
172
176
|
{/if}
|
|
173
177
|
</div>
|
|
@@ -203,58 +207,56 @@
|
|
|
203
207
|
<div class="flex h-7 items-center justify-between">
|
|
204
208
|
<h2 class="text-xs font-medium text-muted-foreground">{labels.description}</h2>
|
|
205
209
|
{#if !editingDescription && description && onDescriptionChange}
|
|
206
|
-
<
|
|
207
|
-
|
|
208
|
-
|
|
210
|
+
<Button
|
|
211
|
+
variant="ghost"
|
|
212
|
+
size="sm"
|
|
213
|
+
icon
|
|
214
|
+
class="text-muted-foreground"
|
|
209
215
|
onclick={startDescription}
|
|
210
216
|
aria-label={labels.editDescription}
|
|
211
217
|
>
|
|
212
|
-
<PencilSimple
|
|
213
|
-
</
|
|
218
|
+
<PencilSimple aria-hidden="true" />
|
|
219
|
+
</Button>
|
|
214
220
|
{/if}
|
|
215
221
|
</div>
|
|
216
222
|
|
|
217
223
|
{#if editingDescription}
|
|
218
|
-
<
|
|
224
|
+
<Textarea
|
|
219
225
|
bind:value={descriptionDraft}
|
|
220
226
|
rows={8}
|
|
221
227
|
placeholder={labels.addDescription}
|
|
222
228
|
aria-label={labels.description}
|
|
223
|
-
class="
|
|
224
|
-
|
|
229
|
+
class="resize-y px-3 leading-relaxed"
|
|
230
|
+
/>
|
|
225
231
|
<div class="mt-1 flex justify-end gap-1.5">
|
|
226
|
-
<
|
|
227
|
-
>{labels.cancel}</
|
|
228
|
-
>
|
|
229
|
-
<button
|
|
230
|
-
type="button"
|
|
231
|
-
class="tk-button tk-primary"
|
|
232
|
-
onclick={saveDescription}
|
|
233
|
-
disabled={savingDescription}
|
|
232
|
+
<Button variant="ghost" size="sm" onclick={() => (editingDescription = false)}
|
|
233
|
+
>{labels.cancel}</Button
|
|
234
234
|
>
|
|
235
|
+
<Button size="sm" onclick={saveDescription} disabled={savingDescription}>
|
|
235
236
|
{savingDescription ? labels.saving : labels.save}
|
|
236
|
-
</
|
|
237
|
+
</Button>
|
|
237
238
|
</div>
|
|
238
239
|
{:else if description}
|
|
239
|
-
<
|
|
240
|
-
|
|
240
|
+
<Button
|
|
241
|
+
variant="text"
|
|
241
242
|
onclick={startDescription}
|
|
242
243
|
disabled={!onDescriptionChange}
|
|
243
244
|
class={cn(
|
|
244
|
-
"-mx-3 block w-[calc(100%+1.5rem)]
|
|
245
|
-
onDescriptionChange && "hover:bg-
|
|
245
|
+
"-mx-3 block w-[calc(100%+1.5rem)] px-3 py-1.5 leading-relaxed font-normal whitespace-pre-wrap text-pretty disabled:opacity-100",
|
|
246
|
+
!onDescriptionChange && "hover:bg-transparent",
|
|
246
247
|
)}
|
|
247
248
|
>
|
|
248
249
|
{description}
|
|
249
|
-
</
|
|
250
|
+
</Button>
|
|
250
251
|
{:else if onDescriptionChange}
|
|
251
|
-
<
|
|
252
|
-
|
|
252
|
+
<Button
|
|
253
|
+
variant="dashed"
|
|
254
|
+
size="sm"
|
|
253
255
|
onclick={startDescription}
|
|
254
|
-
class="
|
|
256
|
+
class="w-full justify-start text-(length:--text-control) font-normal"
|
|
255
257
|
>
|
|
256
258
|
{labels.addDescription}
|
|
257
|
-
</
|
|
259
|
+
</Button>
|
|
258
260
|
{/if}
|
|
259
261
|
</div>
|
|
260
262
|
|
|
@@ -274,72 +276,3 @@
|
|
|
274
276
|
</section>
|
|
275
277
|
</div>
|
|
276
278
|
</div>
|
|
277
|
-
|
|
278
|
-
<style>
|
|
279
|
-
.tk-icon {
|
|
280
|
-
display: grid;
|
|
281
|
-
place-items: center;
|
|
282
|
-
width: 1.75rem;
|
|
283
|
-
height: 1.75rem;
|
|
284
|
-
flex: none;
|
|
285
|
-
border-radius: var(--radius-md, 0.5rem);
|
|
286
|
-
outline: none;
|
|
287
|
-
transition:
|
|
288
|
-
background-color var(--duration-quick, 150ms) var(--ease-smooth-out, ease-out),
|
|
289
|
-
color var(--duration-quick, 150ms) var(--ease-smooth-out, ease-out);
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
@media (hover: hover) and (pointer: fine) {
|
|
293
|
-
.tk-icon:hover:not(:disabled) {
|
|
294
|
-
background: var(--color-muted);
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
.tk-icon:focus-visible,
|
|
299
|
-
.tk-button:focus-visible {
|
|
300
|
-
box-shadow: 0 0 0 3px color-mix(in oklab, var(--color-ring) 50%, transparent);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
.tk-button {
|
|
304
|
-
height: 1.75rem;
|
|
305
|
-
padding-inline: 0.75rem;
|
|
306
|
-
border-radius: var(--radius-md, 0.5rem);
|
|
307
|
-
font-size: 0.8125rem;
|
|
308
|
-
font-weight: 500;
|
|
309
|
-
outline: none;
|
|
310
|
-
transition: background-color var(--duration-quick, 150ms) var(--ease-smooth-out, ease-out);
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
@media (hover: hover) and (pointer: fine) {
|
|
314
|
-
.tk-button:hover:not(:disabled) {
|
|
315
|
-
background: var(--color-muted);
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
.tk-button:disabled {
|
|
320
|
-
opacity: 0.5;
|
|
321
|
-
pointer-events: none;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
.tk-primary {
|
|
325
|
-
background: var(--color-primary);
|
|
326
|
-
color: var(--color-primary-foreground);
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
@media (hover: hover) and (pointer: fine) {
|
|
330
|
-
.tk-primary:hover:not(:disabled) {
|
|
331
|
-
background: color-mix(in oklab, var(--color-primary) 90%, transparent);
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
@media (any-pointer: coarse) {
|
|
336
|
-
.tk-icon {
|
|
337
|
-
width: 2.5rem;
|
|
338
|
-
height: 2.5rem;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
.tk-button {
|
|
342
|
-
height: 2.5rem;
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
</style>
|
|
@@ -1,23 +1,17 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import type { Snippet } from "svelte";
|
|
2
|
+
import type { Component, Snippet } from "svelte";
|
|
3
|
+
import PropertyRow from "../../components/work-parts/property-row.svelte";
|
|
3
4
|
|
|
4
5
|
interface Props {
|
|
5
6
|
label: string;
|
|
7
|
+
/** A Phosphor icon before the label, shown when the rail is wide. */
|
|
8
|
+
icon?: Component<{ class?: string; "aria-hidden"?: boolean | "true" | "false" }>;
|
|
6
9
|
children: Snippet;
|
|
7
10
|
}
|
|
8
11
|
|
|
9
|
-
let { label, children }: Props = $props();
|
|
12
|
+
let { label, icon, children }: Props = $props();
|
|
10
13
|
</script>
|
|
11
14
|
|
|
12
|
-
<!-- A labelled row in the rail. In the narrow chip row the label hides and
|
|
15
|
+
<!-- A labelled row in the rail: icon, label, value. In the narrow chip row the label hides and
|
|
13
16
|
names the group for assistive tech. -->
|
|
14
|
-
<
|
|
15
|
-
class="flex min-h-7 items-center @3xl:grid @3xl:grid-cols-[6rem_minmax(0,1fr)]"
|
|
16
|
-
role="group"
|
|
17
|
-
aria-label={label}
|
|
18
|
-
>
|
|
19
|
-
<span class="hidden text-xs font-medium text-muted-foreground @3xl:block" aria-hidden="true"
|
|
20
|
-
>{label}</span
|
|
21
|
-
>
|
|
22
|
-
<div class="flex min-w-0 items-center">{@render children()}</div>
|
|
23
|
-
</div>
|
|
17
|
+
<PropertyRow {label} {icon} layout="responsive">{@render children()}</PropertyRow>
|