@heyramzi/ui 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +7 -8
- package/scripts/sync-shadcn.mjs +3 -4
- package/src/agents/agent-avatar.svelte +604 -575
- package/src/agents/agent-cast.svelte +179 -183
- package/src/agents/demo.svelte +125 -113
- package/src/agents/helpers.ts +23 -17
- package/src/agents/index.ts +4 -4
- package/src/agents/page-state.ts +6 -6
- package/src/agents/types.ts +6 -6
- package/src/ai/ai-button/AiButton.svelte +4 -12
- package/src/ai/generation-progress/GenerationProgress.svelte +10 -3
- package/src/ai/prompt-input/PromptInputTextarea.svelte +1 -2
- package/src/ai/response/Response.css +2 -3
- package/src/animations/avatar-group-hover.css +2 -16
- package/src/animations/card-tilt.css +3 -6
- package/src/animations/digit-pop-in.css +2 -15
- package/src/animations/dropdown.css +4 -17
- package/src/animations/input-clear-dissolve.css +5 -18
- package/src/animations/input-shake.css +9 -41
- package/src/animations/learn-more-hover.css +17 -9
- package/src/animations/like-button.css +2 -4
- package/src/animations/page-side-by-side.css +2 -10
- package/src/animations/plus-menu-morph.css +2 -5
- package/src/animations/shimmer-text.css +5 -18
- package/src/animations/spinning-counter.css +2 -6
- package/src/animations/success-check.css +2 -15
- package/src/animations/thinking-states.css +2 -7
- package/src/brand/brand.test.ts +21 -5
- package/src/brand/index.ts +4 -10
- package/src/canvas/card/card-frame.svelte +43 -39
- package/src/canvas/card/resize-handles.svelte +89 -80
- package/src/canvas/chrome/chrome-zoom.svelte +101 -100
- package/src/canvas/chrome/lock-badge.svelte +8 -8
- package/src/canvas/chrome/side-handles.svelte +24 -19
- package/src/canvas/chrome/size-chip.svelte +30 -30
- package/src/canvas/chrome/snap-guides.svelte +20 -20
- package/src/canvas/components/icons/ToolIcon.svelte +8 -8
- package/src/canvas/components/shared/svg/PreviewSvg.svelte +19 -19
- package/src/canvas/components/shared/svg/ShapeOutline.svelte +71 -48
- package/src/canvas/components/shared/svg/StrokeNode.svelte +21 -27
- package/src/canvas/components/shared/svg/TextRule.svelte +25 -17
- package/src/canvas/edges/bend-handle.svelte +46 -46
- package/src/canvas/edges/edge-gradient.svelte +10 -10
- package/src/canvas/edges/gradient-edge.svelte +45 -29
- package/src/canvas/editor/lock.test.ts +6 -1
- package/src/canvas/editor/style.ts +7 -1
- package/src/canvas/headless/svg-figure.test.ts +5 -1
- package/src/canvas/lod/lod-switch.svelte +111 -106
- package/src/canvas/pen/PenField.svelte +87 -81
- package/src/canvas/pen/PenOverlay.svelte +127 -127
- package/src/canvas/pen/ShapeNode.svelte +31 -32
- package/src/canvas/pen/TextNode.svelte +54 -53
- package/src/canvas/pen/host-field.test.svelte +7 -7
- package/src/canvas/pen/shapes.ts +7 -1
- package/src/canvas/screen/GlyphIcon.svelte +22 -17
- package/src/canvas/screen/PartView.svelte +138 -72
- package/src/canvas/screen/ScreenBody.svelte +81 -60
- package/src/canvas/screen/ScreenCard.svelte +20 -20
- package/src/canvas/ui/CanvasToolbar.svelte +173 -85
- package/src/canvas/ui/FrameLayer.svelte +59 -59
- package/src/canvas/ui/PenLayer.svelte +39 -30
- package/src/canvas/ui/StylePanel.svelte +119 -102
- package/src/canvas/ui/canvas-grid.svelte +137 -129
- package/src/charts/animated-value.svelte +1 -1
- package/src/charts/area-chart.css +2 -5
- package/src/charts/area-chart.svelte +1 -1
- package/src/charts/bar-chart.css +2 -3
- package/src/charts/bar-chart.svelte +1 -1
- package/src/charts/charts.css +5 -17
- package/src/charts/crosshair.svelte +1 -1
- package/src/charts/dashboard/dashboard-empty.svelte +25 -25
- package/src/charts/dashboard/dashboard-section.svelte +24 -24
- package/src/charts/dashboard/data-panel.svelte +50 -50
- package/src/charts/dashboard/data-sort-head.svelte +56 -56
- package/src/charts/dashboard/data-table.svelte +138 -138
- package/src/charts/dashboard/panel-grid.svelte +30 -30
- package/src/charts/dashboard/period-filter.svelte +25 -25
- package/src/charts/dashboard/rating-chip.svelte +19 -19
- package/src/charts/dashboard/stat-band.svelte +32 -32
- package/src/charts/dashboard/stat-tile.svelte +106 -99
- package/src/charts/donut-chart.svelte +1 -1
- package/src/charts/edge-fade.svelte +1 -1
- package/src/charts/figure.svelte +1 -1
- package/src/charts/gauge-chart.css +4 -7
- package/src/charts/gauge-chart.svelte +1 -1
- package/src/charts/hover-focus.svelte +1 -1
- package/src/charts/legend.css +1 -3
- package/src/charts/legend.svelte +1 -1
- package/src/charts/line-chart.svelte +1 -1
- package/src/charts/number-chart.css +6 -9
- package/src/charts/number-chart.svelte +1 -1
- package/src/charts/reference-line.svelte +19 -19
- package/src/charts/reveal.svelte +1 -1
- package/src/charts/ring-chart.css +2 -4
- package/src/charts/ring-chart.svelte +1 -1
- package/src/charts/sparkline.svelte +5 -2
- package/src/charts/stat-card.svelte +1 -1
- package/src/charts/time-series-chart.css +2 -5
- package/src/charts/trend-pill.css +2 -4
- package/src/charts/trend-pill.svelte +1 -1
- package/src/components/copy/copy-button.svelte +93 -98
- package/src/components/copy/copy-button.test.ts +10 -2
- package/src/components/data-table/infinite-scroll.svelte +42 -42
- package/src/components/data-table/pagination.svelte +34 -22
- package/src/components/data-table/row-arrow.svelte +19 -16
- package/src/components/data-table/row-context-menu.svelte +52 -52
- package/src/components/data-table/sortable-head.svelte +25 -25
- package/src/components/data-table/table-skeleton.svelte +41 -36
- package/src/components/docs/doc-page.svelte +18 -9
- package/src/components/docs/on-this-page.svelte +16 -3
- package/src/components/docs/scroll-spy.svelte.ts +2 -3
- package/src/components/field-row/field-row.svelte +10 -8
- package/src/components/hold-to-confirm/hold-to-confirm.svelte +5 -1
- package/src/components/icon/icon.svelte +14 -14
- package/src/components/language-flag/language-flag.svelte +3 -1
- package/src/components/list-page/detail-empty.svelte +34 -34
- package/src/components/list-page/detail-header.svelte +55 -47
- package/src/components/list-page/detail-panel.svelte +51 -59
- package/src/components/list-page/detail-row.svelte +19 -19
- package/src/components/list-page/detail-stack.svelte +21 -21
- package/src/components/list-page/empty-state.svelte +30 -30
- package/src/components/list-page/filter-item.svelte +20 -20
- package/src/components/list-page/filter-popover.svelte +60 -55
- package/src/components/list-page/grouped-list.svelte +4 -2
- package/src/components/list-page/index.ts +5 -1
- package/src/components/list-page/list-page-shell.svelte +2 -5
- package/src/components/list-page/master-detail.svelte +87 -88
- package/src/components/list-page/notice-bar.svelte +38 -38
- package/src/components/list-page/prev-next.svelte +63 -63
- package/src/components/list-page/rail-body.svelte +18 -18
- package/src/components/list-page/rail-empty.svelte +23 -30
- package/src/components/list-page/rail-head.svelte +24 -24
- package/src/components/list-page/rail-row.svelte +77 -73
- package/src/components/list-page/section-host.ts +2 -3
- package/src/components/locale-switch/locale-switch.svelte +41 -41
- package/src/components/mark/mark.svelte +34 -38
- package/src/components/open-in/index.ts +1 -5
- package/src/components/open-in/open-in.svelte +40 -40
- package/src/components/picker/mark-picker.svelte +49 -49
- package/src/components/picker/picker.svelte +5 -3
- package/src/components/section-header/section-header.test.ts +7 -1
- package/src/components/section-header/section-label.svelte +20 -20
- package/src/components/segmented/animated-tabs.svelte +31 -2
- package/src/components/segmented/collapse.test.ts +2 -1
- package/src/components/segmented/index.ts +2 -0
- package/src/components/segmented/segment.svelte +52 -49
- package/src/components/segmented/segmented-filter.svelte +79 -80
- package/src/components/segmented/segmented-nav.svelte +34 -40
- package/src/components/segmented/segmented-overflow.svelte +53 -50
- package/src/components/segmented/segmented-track.svelte +62 -46
- package/src/components/segmented/segmented.ts +2 -3
- package/src/components/star-rating-input/star-rating-input.svelte +103 -103
- package/src/components/svg/svg.svelte +4 -4
- package/src/components/table-view/table-view.svelte +17 -2
- package/src/components/table-view/table-view.test.ts +7 -1
- package/src/components/table-view/types.ts +11 -11
- package/src/components/tags-input/index.ts +13 -0
- package/src/components/tags-input/tags-input.svelte +305 -0
- package/src/components/tags-input/tags.test.ts +64 -0
- package/src/components/tags-input/tags.ts +142 -0
- package/src/components/theme/index.ts +2 -4
- package/src/components/theme/theme-provider.svelte +1 -3
- package/src/components/toolbar/toolbar-search.svelte +25 -25
- package/src/components/toolbar/toolbar.svelte +11 -7
- package/src/components/toolbar/toolbar.test.ts +10 -1
- package/src/design/index.css +21 -78
- package/src/design/polish.css +26 -35
- package/src/editor/editor-toolbar.svelte +104 -99
- package/src/editor/editor.svelte +296 -266
- package/src/editor/image-toolbar.svelte +20 -22
- package/src/editor/index.ts +1 -4
- package/src/editor/inline-editor.svelte +280 -238
- package/src/editor/markdown.ts +15 -15
- package/src/editor/renderer.svelte +71 -71
- package/src/editor/slash-menu.svelte +24 -27
- package/src/effects/animated-beam/diagrams/BeamSvg.svelte +1 -1
- package/src/effects/image-comparison/ImageComparison.svelte +11 -1
- package/src/effects/interactive-hover-button/InteractiveHoverButton.svelte +59 -46
- package/src/effects/magic-card/MagicCard.css +14 -7
- package/src/effects/marquee/Marquee.svelte +3 -5
- package/src/effects/reveal/observe.ts +0 -3
- package/src/effects/spotlight/Spotlight.svelte +1 -1
- package/src/effects/theme-toggle/ThemeToggle.css +25 -22
- package/src/effects/theme-toggle/ThemeToggle.svelte +6 -7
- package/src/gallery.test.ts +14 -4
- package/src/inbox/README.md +1 -3
- package/src/inbox/inbox.test.ts +181 -138
- package/src/inbox/index.ts +20 -20
- package/src/inbox/logic.ts +114 -111
- package/src/inbox/thread-inbox.svelte +227 -151
- package/src/inbox/types.ts +130 -108
- package/src/lib/theme-transition.ts +2 -4
- package/src/lib/tone.ts +2 -4
- package/src/lib/utils.ts +2 -2
- package/src/modules.test.ts +79 -69
- package/src/onboarding/define-tours.test.ts +55 -40
- package/src/onboarding/define-tours.ts +23 -23
- package/src/onboarding/demo.svelte +24 -5
- package/src/onboarding/index.ts +1 -8
- package/src/onboarding/onboarding-provider.svelte +19 -7
- package/src/onboarding/onboarding.svelte.ts +16 -16
- package/src/onboarding/pick.test.ts +61 -52
- package/src/onboarding/pick.ts +16 -13
- package/src/onboarding/stores.test.ts +80 -80
- package/src/onboarding/stores.ts +41 -39
- package/src/onboarding/tour-card.svelte +30 -5
- package/src/onboarding/tour-runner.svelte +12 -3
- package/src/onboarding/types.ts +20 -12
- package/src/onboarding/wait.ts +22 -22
- package/src/panel/side-panel.svelte +94 -93
- package/src/record/demo-data.ts +291 -225
- package/src/record/field-section.svelte +38 -34
- package/src/record/fields.ts +148 -96
- package/src/record/format.ts +63 -56
- package/src/record/index.ts +49 -35
- package/src/record/info-list.svelte +145 -114
- package/src/record/kinds.ts +31 -31
- package/src/record/logic.ts +216 -214
- package/src/record/next-up.svelte +45 -34
- package/src/record/project-list.svelte +56 -50
- package/src/record/record-demo.svelte +130 -110
- package/src/record/record-header.svelte +37 -28
- package/src/record/record-shell.svelte +54 -54
- package/src/record/record-stats.svelte +25 -25
- package/src/record/record-timeline.svelte +134 -114
- package/src/record/record.test.ts +430 -309
- package/src/record/steps-rail.svelte +225 -216
- package/src/record/types.ts +234 -215
- package/src/record/where-we-are.svelte +62 -58
- package/src/shadcn/button/button.svelte +1 -1
- package/src/shadcn/card/card-title.svelte +1 -5
- package/src/shadcn/hooks/use-highlighted-code.svelte.ts +2 -13
- package/src/shadcn/sheet/sheet-content.svelte +2 -4
- package/src/shadcn/table/table-cell.svelte +2 -3
- package/src/shadcn/utilities.css +3 -8
- package/src/slides/Controls.svelte +150 -124
- package/src/slides/Deck.svelte +243 -238
- package/src/slides/Fragment.svelte +64 -57
- package/src/slides/Overview.svelte +106 -101
- package/src/slides/Presenter.svelte +300 -266
- package/src/slides/Slide.svelte +185 -170
- package/src/slides/SlideList.svelte +16 -12
- package/src/slides/ambient.d.ts +1 -1
- package/src/slides/bridges.ts +42 -23
- package/src/slides/deck-controller.svelte.ts +47 -35
- package/src/slides/demo-slides.svelte +330 -306
- package/src/slides/demo.svelte +164 -160
- package/src/slides/export/capture.ts +20 -16
- package/src/slides/export/ffmpeg.ts +43 -38
- package/src/slides/export/index.ts +5 -5
- package/src/slides/export/launch.ts +3 -1
- package/src/slides/export/pdf.ts +30 -27
- package/src/slides/export/types.ts +10 -8
- package/src/slides/index.ts +11 -11
- package/src/slides/labels.ts +22 -19
- package/src/slides/layout.ts +9 -2
- package/src/slides/model.ts +4 -4
- package/src/slides/navigation.ts +43 -31
- package/src/slides/theme.css +5 -7
- package/src/slides/types.ts +9 -10
- package/src/status/define-statuses.ts +17 -24
- package/src/status/index.ts +5 -5
- package/src/status/status-badge.svelte +3 -1
- package/src/status/status-dot.svelte +1 -3
- package/src/status/status-icon.svelte +1 -1
- package/src/status/status-types.ts +21 -21
- package/src/tasks/board-order.ts +2 -4
- package/src/tasks/demo.svelte +189 -31
- package/src/tasks/detail/detail-demo.svelte +73 -13
- package/src/tasks/detail/detail-types.ts +45 -45
- package/src/tasks/detail/task-detail.svelte +40 -10
- package/src/tasks/detail/task-property.svelte +8 -2
- package/src/tasks/detail/task-thread.svelte +53 -12
- package/src/tasks/gantt/gantt-bar.svelte +17 -6
- package/src/tasks/gantt/gantt-grid.svelte +40 -9
- package/src/tasks/gantt/gantt-group-row.svelte +8 -2
- package/src/tasks/gantt/gantt-header.svelte +9 -3
- package/src/tasks/gantt/gantt-task-row.svelte +26 -6
- package/src/tasks/gantt/gantt.css +2 -1
- package/src/tasks/gantt/gantt.test.ts +3 -1
- package/src/tasks/gantt/logic.test.ts +110 -20
- package/src/tasks/gantt/logic.ts +42 -6
- package/src/tasks/inbox/inbox-card.svelte +13 -5
- package/src/tasks/inbox/inbox-draft.svelte +1 -1
- package/src/tasks/inbox/inbox-logic.ts +6 -40
- package/src/tasks/inbox/inbox-statuses.ts +23 -23
- package/src/tasks/inbox/inbox-trace.svelte +9 -3
- package/src/tasks/inbox/inbox-types.ts +54 -58
- package/src/tasks/inbox/index.ts +22 -21
- package/src/tasks/index.ts +49 -52
- package/src/tasks/kanban-board.svelte +16 -12
- package/src/tasks/kanban-types.ts +2 -3
- package/src/tasks/presets/sales.ts +6 -6
- package/src/tasks/task-gantt.svelte +28 -8
- package/src/tasks/task-list.svelte +41 -17
- package/src/tasks/time/duration.ts +40 -40
- package/src/tasks/time/time-chip.svelte +9 -2
- package/src/tasks/time/time-dot.svelte +1 -1
- package/src/tasks/time/time-ring.svelte +11 -3
- package/src/tasks/time/time-tracker.svelte +57 -15
- package/src/tasks/time/time-types.ts +57 -57
- package/src/tasks/use-kanban-dnd.svelte.ts +2 -3
- package/src/thread/index.ts +7 -7
- package/src/thread/logic.ts +36 -33
- package/src/thread/thread.svelte +82 -16
- package/src/thread/thread.test.ts +58 -47
- package/src/thread/types.ts +68 -68
- package/src/tokens/craft.css +17 -53
- package/src/tokens/index.css +3 -13
- package/src/tokens/palette.css +13 -11
- package/src/tokens/primitives.css +10 -23
- package/src/tasks/inbox/inbox.svelte +0 -203
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { tick, type Snippet } from "svelte";
|
|
3
|
-
import {
|
|
3
|
+
import { ArrowSquareOut, BellSlash, Circle, Envelope, EnvelopeOpen } from "phosphor-svelte";
|
|
4
4
|
import { AgentAvatar } from "../agents/index.js";
|
|
5
|
-
import
|
|
5
|
+
import DetailHeader from "../components/list-page/detail-header.svelte";
|
|
6
|
+
import DetailPanel from "../components/list-page/detail-panel.svelte";
|
|
7
|
+
import FilterItem from "../components/list-page/filter-item.svelte";
|
|
8
|
+
import FilterPopover from "../components/list-page/filter-popover.svelte";
|
|
9
|
+
import MasterDetail from "../components/list-page/master-detail.svelte";
|
|
10
|
+
import RailBody from "../components/list-page/rail-body.svelte";
|
|
11
|
+
import RailEmpty from "../components/list-page/rail-empty.svelte";
|
|
12
|
+
import RailHead from "../components/list-page/rail-head.svelte";
|
|
13
|
+
import RailRow from "../components/list-page/rail-row.svelte";
|
|
14
|
+
import { filterSectionClass } from "../components/list-page/filter-section.js";
|
|
15
|
+
import { queueRailClass, queueRailWidth } from "../components/list-page/queue-rail.js";
|
|
16
|
+
import SegmentedFilter from "../components/segmented/segmented-filter.svelte";
|
|
6
17
|
import { Button } from "../shadcn/button/index.js";
|
|
7
|
-
import * as Empty from "../shadcn/empty/index.js";
|
|
8
18
|
import { Kbd, KbdGroup } from "../shadcn/kbd/index.js";
|
|
9
|
-
import { ToggleGroup, ToggleGroupItem } from "../shadcn/toggle-group/index.js";
|
|
10
19
|
import { cn } from "../lib/utils.js";
|
|
11
20
|
import { TONE_CLASS } from "../lib/tone.js";
|
|
12
21
|
import InboxCard from "../tasks/inbox/inbox-card.svelte";
|
|
@@ -71,7 +80,12 @@
|
|
|
71
80
|
const date = new Date(at);
|
|
72
81
|
return Number.isNaN(date.getTime())
|
|
73
82
|
? ""
|
|
74
|
-
: date.toLocaleString(undefined, {
|
|
83
|
+
: date.toLocaleString(undefined, {
|
|
84
|
+
month: "short",
|
|
85
|
+
day: "numeric",
|
|
86
|
+
hour: "numeric",
|
|
87
|
+
minute: "2-digit",
|
|
88
|
+
});
|
|
75
89
|
},
|
|
76
90
|
onSelect,
|
|
77
91
|
onRead,
|
|
@@ -80,10 +94,13 @@
|
|
|
80
94
|
class: className,
|
|
81
95
|
}: Props = $props();
|
|
82
96
|
|
|
97
|
+
const NEEDS_YOU = "needs-you";
|
|
98
|
+
|
|
83
99
|
let labels = $derived(resolveInboxLabels(labelOverrides));
|
|
84
100
|
let filter = $state<InboxFilter>({ ...NO_FILTER });
|
|
85
101
|
let snoozing = $state(false);
|
|
86
|
-
let
|
|
102
|
+
let pane = $state<"rail" | "detail">("rail");
|
|
103
|
+
let root = $state<HTMLDivElement>();
|
|
87
104
|
let cards = $state<Record<string, ReturnType<typeof InboxCard> | null>>({});
|
|
88
105
|
|
|
89
106
|
let all = $derived(threadsOf(entries, { unreadFirst }));
|
|
@@ -93,24 +110,28 @@
|
|
|
93
110
|
let current = $derived(visible.find((thread) => thread.key === selected) ?? visible[0]);
|
|
94
111
|
let needsYouCount = $derived(all.filter((thread) => thread.pending.length > 0).length);
|
|
95
112
|
let filtered = $derived(filter.type !== ALL || filter.who !== ALL || filter.needsYou);
|
|
113
|
+
let narrowed = $derived(Number(filter.type !== ALL) + Number(filter.who !== ALL));
|
|
114
|
+
let views = $derived([
|
|
115
|
+
{ value: ALL, label: labels.all, count: all.length },
|
|
116
|
+
{ value: NEEDS_YOU, label: labels.needsYou, count: needsYouCount },
|
|
117
|
+
]);
|
|
96
118
|
let pinned = $derived(current?.pending[0]);
|
|
97
|
-
let timeline = $derived(
|
|
119
|
+
let timeline = $derived(
|
|
120
|
+
current?.entries.filter((entry) => !current.pending.includes(entry)) ?? [],
|
|
121
|
+
);
|
|
98
122
|
|
|
99
123
|
function open(thread: InboxThread): void {
|
|
100
124
|
selected = thread.key;
|
|
101
125
|
snoozing = false;
|
|
102
|
-
detailOpen = true;
|
|
103
126
|
onSelect?.(thread);
|
|
104
127
|
}
|
|
105
128
|
|
|
106
129
|
async function move(step: number): Promise<void> {
|
|
107
130
|
if (!visible.length) return;
|
|
108
131
|
const from = current ? visible.indexOf(current) : -1;
|
|
109
|
-
|
|
110
|
-
open(next);
|
|
111
|
-
detailOpen = false;
|
|
132
|
+
open(visible[Math.max(0, Math.min(visible.length - 1, from + step))]);
|
|
112
133
|
await tick();
|
|
113
|
-
|
|
134
|
+
root?.querySelector<HTMLElement>('.md-rail [aria-current="page"]')?.focus();
|
|
114
135
|
}
|
|
115
136
|
|
|
116
137
|
function toggleRead(): void {
|
|
@@ -152,12 +173,12 @@
|
|
|
152
173
|
actions[key]();
|
|
153
174
|
}
|
|
154
175
|
|
|
155
|
-
function setType(next: string | undefined): void {
|
|
156
|
-
filter = { ...filter, type: next || ALL };
|
|
157
|
-
}
|
|
158
|
-
|
|
159
176
|
function snoozeLabel(id: string): string {
|
|
160
|
-
return id === "later"
|
|
177
|
+
return id === "later"
|
|
178
|
+
? labels.snoozeLater
|
|
179
|
+
: id === "tomorrow"
|
|
180
|
+
? labels.snoozeTomorrow
|
|
181
|
+
: labels.snoozeNextWeek;
|
|
161
182
|
}
|
|
162
183
|
|
|
163
184
|
function initial(name: string): string {
|
|
@@ -178,121 +199,142 @@
|
|
|
178
199
|
{:else if actor.avatar}
|
|
179
200
|
<img src={actor.avatar} alt="" class="size-6 rounded-full object-cover" />
|
|
180
201
|
{:else}
|
|
181
|
-
<span
|
|
202
|
+
<span
|
|
203
|
+
class="grid size-6 place-items-center rounded-full bg-muted text-xs font-medium text-muted-foreground"
|
|
204
|
+
aria-hidden="true"
|
|
205
|
+
>
|
|
182
206
|
{initial(actor.name)}
|
|
183
207
|
</span>
|
|
184
208
|
{/if}
|
|
185
209
|
</span>
|
|
186
210
|
{/snippet}
|
|
187
211
|
|
|
212
|
+
{#snippet subjectStatus()}
|
|
213
|
+
{#if current}{@render status?.(current.subject)}{/if}
|
|
214
|
+
{/snippet}
|
|
215
|
+
|
|
188
216
|
<!-- WHY the key handler sits on the region: the shortcuts work wherever focus is inside the inbox and nowhere else on the page. -->
|
|
189
217
|
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
|
190
|
-
<div
|
|
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
|
-
{#each visible as thread (thread.key)}
|
|
223
|
-
{@const last = lastEntry(thread)}
|
|
224
|
-
<li>
|
|
225
|
-
<button
|
|
226
|
-
type="button"
|
|
227
|
-
data-thread-key={thread.key}
|
|
228
|
-
aria-current={current?.key === thread.key}
|
|
229
|
-
onclick={() => open(thread)}
|
|
230
|
-
class={cn(
|
|
231
|
-
"flex w-full flex-col gap-1 rounded-lg border border-transparent p-2.5 text-start outline-none focus-visible:ring-3 focus-visible:ring-ring/50",
|
|
232
|
-
current?.key === thread.key ? "border-border bg-muted" : "hover:bg-muted/50",
|
|
233
|
-
)}
|
|
218
|
+
<div
|
|
219
|
+
role="region"
|
|
220
|
+
aria-label={labels.title}
|
|
221
|
+
bind:this={root}
|
|
222
|
+
class={cn("flex h-full min-h-0 flex-col gap-3", className)}
|
|
223
|
+
{onkeydown}
|
|
224
|
+
>
|
|
225
|
+
<MasterDetail
|
|
226
|
+
bind:pane
|
|
227
|
+
railWidth={queueRailWidth}
|
|
228
|
+
railClass={queueRailClass}
|
|
229
|
+
detailClass="flex flex-col gap-4 overflow-y-auto"
|
|
230
|
+
pad={false}
|
|
231
|
+
backLabel={labels.title}
|
|
232
|
+
class="min-h-0 flex-1"
|
|
233
|
+
>
|
|
234
|
+
{#snippet rail()}
|
|
235
|
+
<RailHead>
|
|
236
|
+
<div class="flex items-center gap-2">
|
|
237
|
+
<SegmentedFilter
|
|
238
|
+
options={views}
|
|
239
|
+
value={filter.needsYou ? NEEDS_YOU : ALL}
|
|
240
|
+
onValueChange={(view) => (filter = { ...filter, needsYou: view === NEEDS_YOU })}
|
|
241
|
+
ariaLabel={labels.title}
|
|
242
|
+
class="min-w-0 flex-1"
|
|
243
|
+
/>
|
|
244
|
+
<FilterPopover
|
|
245
|
+
label={labels.filter}
|
|
246
|
+
count={narrowed}
|
|
247
|
+
align="end"
|
|
248
|
+
onClear={() => (filter = { ...NO_FILTER, needsYou: filter.needsYou })}
|
|
249
|
+
clearLabel={labels.clearFilters}
|
|
234
250
|
>
|
|
235
|
-
|
|
236
|
-
{
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
<span class="truncate">{last.actor.name} {entryLine(last, labels)}</span>
|
|
247
|
-
{#if thread.pending.length > 0}
|
|
248
|
-
<span class={cn("ms-auto inline-flex h-5 shrink-0 items-center rounded-sm border px-1.5 font-medium", TONE_CLASS.warning)}>
|
|
249
|
-
{labels.needsYou}
|
|
250
|
-
</span>
|
|
251
|
-
{:else if thread.unread > 0}
|
|
252
|
-
<Badge variant="outline" class="ms-auto tabular-nums" aria-label="{thread.unread} {labels.unread}">{thread.unread}</Badge>
|
|
253
|
-
{/if}
|
|
254
|
-
</span>
|
|
255
|
-
</button>
|
|
256
|
-
</li>
|
|
257
|
-
{:else}
|
|
258
|
-
<li class="h-full">
|
|
259
|
-
<Empty.Root class="h-full">
|
|
260
|
-
<Empty.Header>
|
|
261
|
-
<Empty.Title>
|
|
262
|
-
{filtered ? (filter.needsYou ? labels.emptyNeedsYou : labels.emptyFiltered) : labels.empty}
|
|
263
|
-
</Empty.Title>
|
|
264
|
-
</Empty.Header>
|
|
265
|
-
{#if filtered}
|
|
266
|
-
<Empty.Content>
|
|
267
|
-
<Button size="sm" variant="outline" onclick={() => (filter = { ...NO_FILTER })}>{labels.clearFilters}</Button>
|
|
268
|
-
</Empty.Content>
|
|
251
|
+
{#if types.length > 1}
|
|
252
|
+
<p class={filterSectionClass()}>{labels.kind}</p>
|
|
253
|
+
{#each [ALL, ...types] as type (type)}
|
|
254
|
+
<FilterItem
|
|
255
|
+
variant="radio"
|
|
256
|
+
checked={filter.type === type}
|
|
257
|
+
onclick={() => (filter = { ...filter, type })}
|
|
258
|
+
>
|
|
259
|
+
{type === ALL ? labels.all : (typeLabels[type] ?? type)}
|
|
260
|
+
</FilterItem>
|
|
261
|
+
{/each}
|
|
269
262
|
{/if}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
263
|
+
<p class={filterSectionClass()}>{labels.from}</p>
|
|
264
|
+
{#each [ALL, ...people] as who (who)}
|
|
265
|
+
<FilterItem
|
|
266
|
+
variant="radio"
|
|
267
|
+
checked={filter.who === who}
|
|
268
|
+
onclick={() => (filter = { ...filter, who })}
|
|
269
|
+
>
|
|
270
|
+
{who === ALL ? labels.anyone : who}
|
|
271
|
+
</FilterItem>
|
|
272
|
+
{/each}
|
|
273
|
+
</FilterPopover>
|
|
274
|
+
</div>
|
|
275
|
+
</RailHead>
|
|
276
|
+
<RailBody>
|
|
277
|
+
<ol aria-label={labels.title}>
|
|
278
|
+
{#each visible as thread (thread.key)}
|
|
279
|
+
{@const last = lastEntry(thread)}
|
|
280
|
+
<li>
|
|
281
|
+
<RailRow
|
|
282
|
+
title={thread.subject.title}
|
|
283
|
+
titleLines={2}
|
|
284
|
+
selected={current?.key === thread.key}
|
|
285
|
+
onclick={() => open(thread)}
|
|
286
|
+
preview="{last.actor.name} {entryLine(last, labels)}"
|
|
287
|
+
meta={[thread.subject.ref, when(thread.latestAt)]}
|
|
288
|
+
metaTruncate="last"
|
|
289
|
+
>
|
|
290
|
+
{#snippet trailing()}
|
|
291
|
+
{#if thread.pending.length > 0}
|
|
292
|
+
<span
|
|
293
|
+
class={cn(
|
|
294
|
+
"inline-flex h-5 items-center rounded-sm border px-1.5 font-medium",
|
|
295
|
+
TONE_CLASS.warning,
|
|
296
|
+
)}
|
|
297
|
+
>
|
|
298
|
+
{labels.needsYou}
|
|
299
|
+
</span>
|
|
300
|
+
{:else if thread.unread > 0}
|
|
301
|
+
<Circle
|
|
302
|
+
weight="fill"
|
|
303
|
+
class="size-2 text-primary"
|
|
304
|
+
aria-label="{thread.unread} {labels.unread}"
|
|
305
|
+
/>
|
|
306
|
+
{/if}
|
|
307
|
+
{/snippet}
|
|
308
|
+
</RailRow>
|
|
309
|
+
</li>
|
|
310
|
+
{:else}
|
|
311
|
+
<li class="flex h-full flex-col items-center">
|
|
312
|
+
<RailEmpty
|
|
313
|
+
title={filtered
|
|
314
|
+
? filter.needsYou
|
|
315
|
+
? labels.emptyNeedsYou
|
|
316
|
+
: labels.emptyFiltered
|
|
317
|
+
: labels.empty}
|
|
318
|
+
/>
|
|
319
|
+
{#if filtered}
|
|
320
|
+
<Button size="sm" variant="outline" onclick={() => (filter = { ...NO_FILTER })}
|
|
321
|
+
>{labels.clearFilters}</Button
|
|
322
|
+
>
|
|
323
|
+
{/if}
|
|
324
|
+
</li>
|
|
325
|
+
{/each}
|
|
326
|
+
</ol>
|
|
327
|
+
</RailBody>
|
|
328
|
+
{/snippet}
|
|
274
329
|
|
|
275
|
-
|
|
276
|
-
class={cn("min-h-0 flex-col gap-4 overflow-y-auto rounded-xl border border-border p-4", detailOpen ? "flex" : "max-md:hidden md:flex")}
|
|
277
|
-
aria-label={current?.subject.title ?? labels.selectThread}
|
|
278
|
-
>
|
|
330
|
+
{#snippet detail()}
|
|
279
331
|
{#if current}
|
|
280
|
-
<
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
{/if}
|
|
287
|
-
<h2 class="min-w-0 truncate text-sm font-medium">
|
|
288
|
-
{#if current.subject.href}
|
|
289
|
-
<a href={current.subject.href} class="hover:underline">{current.subject.title}</a>
|
|
290
|
-
{:else}
|
|
291
|
-
{current.subject.title}
|
|
292
|
-
{/if}
|
|
293
|
-
</h2>
|
|
294
|
-
{@render status?.(current.subject)}
|
|
295
|
-
<span class="ms-auto flex items-center gap-1">
|
|
332
|
+
<DetailHeader
|
|
333
|
+
title={current.subject.title}
|
|
334
|
+
meta={[current.subject.ref]}
|
|
335
|
+
badge={status ? subjectStatus : undefined}
|
|
336
|
+
>
|
|
337
|
+
{#snippet actions()}
|
|
296
338
|
<Button size="sm" variant="ghost" onclick={toggleRead} aria-keyshortcuts="u">
|
|
297
339
|
{#if current.unread > 0}
|
|
298
340
|
<EnvelopeOpen aria-hidden="true" />{labels.markRead}
|
|
@@ -300,11 +342,22 @@
|
|
|
300
342
|
<Envelope aria-hidden="true" />{labels.markUnread}
|
|
301
343
|
{/if}
|
|
302
344
|
</Button>
|
|
303
|
-
<Button
|
|
345
|
+
<Button
|
|
346
|
+
size="sm"
|
|
347
|
+
variant="ghost"
|
|
348
|
+
onclick={() => (snoozing = !snoozing)}
|
|
349
|
+
aria-expanded={snoozing}
|
|
350
|
+
aria-keyshortcuts="h"
|
|
351
|
+
>
|
|
304
352
|
<BellSlash aria-hidden="true" />{labels.snooze}
|
|
305
353
|
</Button>
|
|
306
|
-
|
|
307
|
-
|
|
354
|
+
{#if current.subject.href}
|
|
355
|
+
<Button size="sm" variant="ghost" href={current.subject.href}>
|
|
356
|
+
<ArrowSquareOut aria-hidden="true" />{labels.open}
|
|
357
|
+
</Button>
|
|
358
|
+
{/if}
|
|
359
|
+
{/snippet}
|
|
360
|
+
</DetailHeader>
|
|
308
361
|
|
|
309
362
|
{#if snoozing}
|
|
310
363
|
<div class="flex flex-wrap gap-2" role="group" aria-label={labels.snooze}>
|
|
@@ -326,38 +379,61 @@
|
|
|
326
379
|
/>
|
|
327
380
|
{/each}
|
|
328
381
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
<
|
|
332
|
-
{
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
<
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
{
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
382
|
+
{#if timeline.length > 0}
|
|
383
|
+
<DetailPanel>
|
|
384
|
+
<ol class="flex flex-col gap-4">
|
|
385
|
+
{#each timeline as entry (entry.id)}
|
|
386
|
+
<li class={cn("flex gap-3", !entry.read && "font-medium")}>
|
|
387
|
+
{@render face(entry.actor)}
|
|
388
|
+
<div class="min-w-0 flex-1">
|
|
389
|
+
<div class="flex flex-wrap items-center gap-x-2 text-[13px]">
|
|
390
|
+
<span class="truncate font-medium">{entry.actor.name}</span>
|
|
391
|
+
{#if entry.actor.kind === "agent"}
|
|
392
|
+
<span
|
|
393
|
+
class={cn(
|
|
394
|
+
"inline-flex h-5 items-center rounded-sm border px-1.5 text-xs font-medium",
|
|
395
|
+
TONE_CLASS.accent,
|
|
396
|
+
)}
|
|
397
|
+
>
|
|
398
|
+
{labels.agent}
|
|
399
|
+
</span>
|
|
400
|
+
{/if}
|
|
401
|
+
<span class="font-normal text-muted-foreground"
|
|
402
|
+
>{entryLine(entry, labels)}</span
|
|
403
|
+
>
|
|
404
|
+
<span class="ms-auto text-xs font-normal text-muted-foreground tabular-nums"
|
|
405
|
+
>{when(entry.at)}</span
|
|
406
|
+
>
|
|
407
|
+
</div>
|
|
408
|
+
{#if entry.body}
|
|
409
|
+
<p
|
|
410
|
+
class="mt-1 text-sm leading-relaxed font-normal whitespace-pre-wrap text-pretty"
|
|
411
|
+
>
|
|
412
|
+
{entry.body}
|
|
413
|
+
</p>
|
|
414
|
+
{/if}
|
|
415
|
+
</div>
|
|
416
|
+
</li>
|
|
417
|
+
{/each}
|
|
418
|
+
</ol>
|
|
419
|
+
</DetailPanel>
|
|
420
|
+
{/if}
|
|
351
421
|
{:else}
|
|
352
|
-
<
|
|
422
|
+
<RailEmpty title={labels.selectThread} />
|
|
353
423
|
{/if}
|
|
354
|
-
|
|
355
|
-
</
|
|
424
|
+
{/snippet}
|
|
425
|
+
</MasterDetail>
|
|
356
426
|
|
|
357
|
-
<footer
|
|
358
|
-
|
|
427
|
+
<footer
|
|
428
|
+
class="flex flex-wrap items-center gap-x-4 gap-y-1 text-xs text-muted-foreground max-sm:hidden"
|
|
429
|
+
>
|
|
430
|
+
<span class="inline-flex items-center gap-1.5"
|
|
431
|
+
><KbdGroup><Kbd>j</Kbd><Kbd>k</Kbd></KbdGroup> {labels.hintMove}</span
|
|
432
|
+
>
|
|
359
433
|
<span class="inline-flex items-center gap-1.5"><Kbd>u</Kbd> {labels.hintRead}</span>
|
|
360
434
|
<span class="inline-flex items-center gap-1.5"><Kbd>h</Kbd> {labels.hintSnooze}</span>
|
|
361
|
-
<span class="inline-flex items-center gap-1.5"
|
|
435
|
+
<span class="inline-flex items-center gap-1.5"
|
|
436
|
+
><KbdGroup><Kbd>a</Kbd><Kbd>d</Kbd><Kbd>s</Kbd><Kbd>e</Kbd></KbdGroup> {labels.hintAct}</span
|
|
437
|
+
>
|
|
362
438
|
</footer>
|
|
363
439
|
</div>
|