@heyramzi/ui 2.0.1 → 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 +48 -24
- 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/README.md +9 -12
- 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 +8 -4
- 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/index.ts +1 -0
- package/src/components/section-header/section-header.svelte +1 -1
- package/src/components/section-header/section-header.test.ts +7 -1
- package/src/components/section-header/section-label.svelte +39 -0
- 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/index.ts +2 -0
- package/src/components/{list-page → toolbar}/toolbar-search.svelte +25 -25
- package/src/components/toolbar/toolbar.svelte +13 -9
- 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 +27 -0
- package/src/inbox/inbox.test.ts +214 -0
- package/src/inbox/index.ts +31 -0
- package/src/inbox/logic.ts +169 -0
- package/src/inbox/thread-inbox.svelte +439 -0
- package/src/inbox/types.ts +161 -0
- 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 +105 -0
- 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/README.md +5 -0
- package/src/panel/index.ts +2 -0
- package/src/panel/side-panel.svelte +194 -0
- package/src/record/README.md +3 -0
- package/src/record/demo-data.ts +352 -0
- package/src/record/field-section.svelte +57 -0
- package/src/record/fields.ts +194 -0
- package/src/record/format.ts +94 -0
- package/src/{tasks/record → record}/index.ts +49 -35
- package/src/{tasks/record → record}/info-list.svelte +145 -114
- package/src/record/kinds.ts +42 -0
- package/src/record/logic.ts +326 -0
- package/src/record/next-up.svelte +81 -0
- package/src/{tasks/record → record}/project-list.svelte +56 -50
- package/src/{tasks/record → record}/record-demo.svelte +130 -110
- package/src/{tasks/record → record}/record-header.svelte +37 -28
- package/src/{tasks/record → record}/record-shell.svelte +54 -54
- package/src/record/record-stats.svelte +48 -0
- package/src/record/record-timeline.svelte +251 -0
- package/src/record/record.test.ts +471 -0
- package/src/{tasks/record → record}/steps-rail.svelte +225 -216
- package/src/record/types.ts +299 -0
- package/src/record/where-we-are.svelte +125 -0
- 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/README.md +18 -0
- package/src/status/define-statuses.ts +25 -0
- package/src/status/index.ts +11 -0
- package/src/{tasks → status}/status-badge.svelte +3 -1
- package/src/{tasks → status}/status-dot.svelte +1 -3
- package/src/{tasks → status}/status-icon.svelte +1 -1
- package/src/status/status-types.ts +40 -0
- package/src/tasks/README.md +1 -1
- package/src/tasks/board-order.ts +2 -4
- package/src/tasks/demo.svelte +192 -34
- package/src/tasks/detail/detail-demo.svelte +75 -15
- 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 +4 -2
- package/src/tasks/gantt/logic.test.ts +110 -20
- package/src/tasks/gantt/logic.ts +42 -6
- package/src/tasks/inbox/inbox-card.svelte +15 -7
- 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 +24 -24
- 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 +52 -53
- package/src/tasks/kanban-board.svelte +16 -12
- package/src/tasks/kanban-types.ts +2 -3
- package/src/tasks/presets/sales.ts +7 -7
- 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/README.md +31 -0
- package/src/thread/index.ts +12 -0
- package/src/thread/logic.ts +61 -0
- package/src/thread/thread.svelte +432 -0
- package/src/thread/thread.test.ts +73 -0
- package/src/thread/types.ts +93 -0
- 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/components/list-page/section-label.svelte +0 -39
- package/src/tasks/define-statuses.ts +0 -32
- package/src/tasks/inbox/inbox.svelte +0 -203
- package/src/tasks/record/demo-data.ts +0 -286
- package/src/tasks/record/field-section.svelte +0 -53
- package/src/tasks/record/fields.ts +0 -142
- package/src/tasks/record/format.ts +0 -87
- package/src/tasks/record/kinds.ts +0 -42
- package/src/tasks/record/logic.ts +0 -324
- package/src/tasks/record/next-up.svelte +0 -70
- package/src/tasks/record/record-stats.svelte +0 -48
- package/src/tasks/record/record-timeline.svelte +0 -231
- package/src/tasks/record/record.test.ts +0 -350
- package/src/tasks/record/types.ts +0 -280
- package/src/tasks/record/where-we-are.svelte +0 -121
- package/src/tasks/side-panel.svelte +0 -193
- package/src/tasks/status-types.ts +0 -40
- /package/src/components/{list-page → toolbar}/toolbar-trigger.ts +0 -0
- /package/src/{tasks → panel}/side-panel-types.ts +0 -0
- /package/src/{tasks/record → record}/gutter.ts +0 -0
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { tick, type Snippet } from "svelte";
|
|
3
|
+
import { ArrowSquareOut, BellSlash, Circle, Envelope, EnvelopeOpen } from "phosphor-svelte";
|
|
4
|
+
import { AgentAvatar } from "../agents/index.js";
|
|
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";
|
|
17
|
+
import { Button } from "../shadcn/button/index.js";
|
|
18
|
+
import { Kbd, KbdGroup } from "../shadcn/kbd/index.js";
|
|
19
|
+
import { cn } from "../lib/utils.js";
|
|
20
|
+
import { TONE_CLASS } from "../lib/tone.js";
|
|
21
|
+
import InboxCard from "../tasks/inbox/inbox-card.svelte";
|
|
22
|
+
import type { InboxItem, InboxVerdict } from "../tasks/inbox/inbox-types.js";
|
|
23
|
+
import {
|
|
24
|
+
NO_FILTER,
|
|
25
|
+
actorNames,
|
|
26
|
+
entryLine,
|
|
27
|
+
filterThreads,
|
|
28
|
+
inboxKeyOf,
|
|
29
|
+
resolveInboxLabels,
|
|
30
|
+
snoozeChoices,
|
|
31
|
+
subjectTypes,
|
|
32
|
+
threadsOf,
|
|
33
|
+
} from "./logic.js";
|
|
34
|
+
import {
|
|
35
|
+
ALL,
|
|
36
|
+
type InboxActor,
|
|
37
|
+
type InboxEntry,
|
|
38
|
+
type InboxFilter,
|
|
39
|
+
type InboxLabels,
|
|
40
|
+
type InboxSnooze,
|
|
41
|
+
type InboxSubject,
|
|
42
|
+
type InboxThread,
|
|
43
|
+
} from "./types.js";
|
|
44
|
+
|
|
45
|
+
interface Props {
|
|
46
|
+
entries: InboxEntry[];
|
|
47
|
+
/** The key of the open thread. Without a match the first thread opens. */
|
|
48
|
+
selected?: string;
|
|
49
|
+
/** Threads with unread entries come first. */
|
|
50
|
+
unreadFirst?: boolean;
|
|
51
|
+
labels?: Partial<InboxLabels>;
|
|
52
|
+
/** Display names for subject types, such as `{ task: "Tasks" }`. A missing type shows as written. */
|
|
53
|
+
typeLabels?: Record<string, string>;
|
|
54
|
+
/** Replaces the default avatar for a person or an agent, drawn in a 24px slot. */
|
|
55
|
+
avatar?: Snippet<[InboxActor]>;
|
|
56
|
+
/** A badge for the subject's status, drawn by the host with its own status map. */
|
|
57
|
+
status?: Snippet<[InboxSubject]>;
|
|
58
|
+
/** Replaces a pinned proposal's summary lines. */
|
|
59
|
+
renderProposal?: Snippet<[InboxItem]>;
|
|
60
|
+
/** How a timestamp reads. Defaults to a short date and time. */
|
|
61
|
+
when?: (at: string) => string;
|
|
62
|
+
onSelect?: (thread: InboxThread) => void;
|
|
63
|
+
/** `read` is true when the thread had unread entries, so the host marks them all read. */
|
|
64
|
+
onRead?: (thread: InboxThread, read: boolean) => void;
|
|
65
|
+
onSnooze?: (request: InboxSnooze) => void;
|
|
66
|
+
onDecide?: (verdict: InboxVerdict, thread: InboxThread) => void;
|
|
67
|
+
class?: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
let {
|
|
71
|
+
entries,
|
|
72
|
+
selected = $bindable(),
|
|
73
|
+
unreadFirst = false,
|
|
74
|
+
labels: labelOverrides,
|
|
75
|
+
typeLabels = {},
|
|
76
|
+
avatar,
|
|
77
|
+
status,
|
|
78
|
+
renderProposal,
|
|
79
|
+
when = (at) => {
|
|
80
|
+
const date = new Date(at);
|
|
81
|
+
return Number.isNaN(date.getTime())
|
|
82
|
+
? ""
|
|
83
|
+
: date.toLocaleString(undefined, {
|
|
84
|
+
month: "short",
|
|
85
|
+
day: "numeric",
|
|
86
|
+
hour: "numeric",
|
|
87
|
+
minute: "2-digit",
|
|
88
|
+
});
|
|
89
|
+
},
|
|
90
|
+
onSelect,
|
|
91
|
+
onRead,
|
|
92
|
+
onSnooze,
|
|
93
|
+
onDecide,
|
|
94
|
+
class: className,
|
|
95
|
+
}: Props = $props();
|
|
96
|
+
|
|
97
|
+
const NEEDS_YOU = "needs-you";
|
|
98
|
+
|
|
99
|
+
let labels = $derived(resolveInboxLabels(labelOverrides));
|
|
100
|
+
let filter = $state<InboxFilter>({ ...NO_FILTER });
|
|
101
|
+
let snoozing = $state(false);
|
|
102
|
+
let pane = $state<"rail" | "detail">("rail");
|
|
103
|
+
let root = $state<HTMLDivElement>();
|
|
104
|
+
let cards = $state<Record<string, ReturnType<typeof InboxCard> | null>>({});
|
|
105
|
+
|
|
106
|
+
let all = $derived(threadsOf(entries, { unreadFirst }));
|
|
107
|
+
let visible = $derived(filterThreads(all, filter));
|
|
108
|
+
let types = $derived(subjectTypes(all));
|
|
109
|
+
let people = $derived(actorNames(all));
|
|
110
|
+
let current = $derived(visible.find((thread) => thread.key === selected) ?? visible[0]);
|
|
111
|
+
let needsYouCount = $derived(all.filter((thread) => thread.pending.length > 0).length);
|
|
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
|
+
]);
|
|
118
|
+
let pinned = $derived(current?.pending[0]);
|
|
119
|
+
let timeline = $derived(
|
|
120
|
+
current?.entries.filter((entry) => !current.pending.includes(entry)) ?? [],
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
function open(thread: InboxThread): void {
|
|
124
|
+
selected = thread.key;
|
|
125
|
+
snoozing = false;
|
|
126
|
+
onSelect?.(thread);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async function move(step: number): Promise<void> {
|
|
130
|
+
if (!visible.length) return;
|
|
131
|
+
const from = current ? visible.indexOf(current) : -1;
|
|
132
|
+
open(visible[Math.max(0, Math.min(visible.length - 1, from + step))]);
|
|
133
|
+
await tick();
|
|
134
|
+
root?.querySelector<HTMLElement>('.md-rail [aria-current="page"]')?.focus();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function toggleRead(): void {
|
|
138
|
+
if (current) onRead?.(current, current.unread > 0);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function snooze(until: Date): void {
|
|
142
|
+
if (current) onSnooze?.({ thread: current, until });
|
|
143
|
+
snoozing = false;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function onkeydown(event: KeyboardEvent): void {
|
|
147
|
+
if (snoozing && !event.defaultPrevented && !event.metaKey && !event.ctrlKey && !event.altKey) {
|
|
148
|
+
const choice = snoozeChoices(new Date())[Number(event.key) - 1];
|
|
149
|
+
if (choice) {
|
|
150
|
+
event.preventDefault();
|
|
151
|
+
snooze(choice.until);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
if (event.key === "Escape") {
|
|
155
|
+
snoozing = false;
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
const key = inboxKeyOf(event);
|
|
160
|
+
if (!key) return;
|
|
161
|
+
const card = pinned ? cards[pinned.id] : null;
|
|
162
|
+
const actions = {
|
|
163
|
+
next: () => move(1),
|
|
164
|
+
previous: () => move(-1),
|
|
165
|
+
toggleRead,
|
|
166
|
+
snooze: () => (snoozing = !snoozing),
|
|
167
|
+
approve: () => card?.approve(),
|
|
168
|
+
decline: () => card?.decline(),
|
|
169
|
+
steer: () => card?.steer(),
|
|
170
|
+
edit: () => card?.edit(),
|
|
171
|
+
};
|
|
172
|
+
event.preventDefault();
|
|
173
|
+
actions[key]();
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function snoozeLabel(id: string): string {
|
|
177
|
+
return id === "later"
|
|
178
|
+
? labels.snoozeLater
|
|
179
|
+
: id === "tomorrow"
|
|
180
|
+
? labels.snoozeTomorrow
|
|
181
|
+
: labels.snoozeNextWeek;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function initial(name: string): string {
|
|
185
|
+
return name.trim().charAt(0).toLocaleUpperCase() || "?";
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function lastEntry(thread: InboxThread): InboxEntry {
|
|
189
|
+
return thread.entries[thread.entries.length - 1];
|
|
190
|
+
}
|
|
191
|
+
</script>
|
|
192
|
+
|
|
193
|
+
{#snippet face(actor: InboxActor)}
|
|
194
|
+
<span class="relative size-6 shrink-0">
|
|
195
|
+
{#if avatar}
|
|
196
|
+
{@render avatar(actor)}
|
|
197
|
+
{:else if actor.kind === "agent"}
|
|
198
|
+
<AgentAvatar name={actor.name} size={24} paused interactive={false} />
|
|
199
|
+
{:else if actor.avatar}
|
|
200
|
+
<img src={actor.avatar} alt="" class="size-6 rounded-full object-cover" />
|
|
201
|
+
{:else}
|
|
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
|
+
>
|
|
206
|
+
{initial(actor.name)}
|
|
207
|
+
</span>
|
|
208
|
+
{/if}
|
|
209
|
+
</span>
|
|
210
|
+
{/snippet}
|
|
211
|
+
|
|
212
|
+
{#snippet subjectStatus()}
|
|
213
|
+
{#if current}{@render status?.(current.subject)}{/if}
|
|
214
|
+
{/snippet}
|
|
215
|
+
|
|
216
|
+
<!-- WHY the key handler sits on the region: the shortcuts work wherever focus is inside the inbox and nowhere else on the page. -->
|
|
217
|
+
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
|
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}
|
|
250
|
+
>
|
|
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}
|
|
262
|
+
{/if}
|
|
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}
|
|
329
|
+
|
|
330
|
+
{#snippet detail()}
|
|
331
|
+
{#if current}
|
|
332
|
+
<DetailHeader
|
|
333
|
+
title={current.subject.title}
|
|
334
|
+
meta={[current.subject.ref]}
|
|
335
|
+
badge={status ? subjectStatus : undefined}
|
|
336
|
+
>
|
|
337
|
+
{#snippet actions()}
|
|
338
|
+
<Button size="sm" variant="ghost" onclick={toggleRead} aria-keyshortcuts="u">
|
|
339
|
+
{#if current.unread > 0}
|
|
340
|
+
<EnvelopeOpen aria-hidden="true" />{labels.markRead}
|
|
341
|
+
{:else}
|
|
342
|
+
<Envelope aria-hidden="true" />{labels.markUnread}
|
|
343
|
+
{/if}
|
|
344
|
+
</Button>
|
|
345
|
+
<Button
|
|
346
|
+
size="sm"
|
|
347
|
+
variant="ghost"
|
|
348
|
+
onclick={() => (snoozing = !snoozing)}
|
|
349
|
+
aria-expanded={snoozing}
|
|
350
|
+
aria-keyshortcuts="h"
|
|
351
|
+
>
|
|
352
|
+
<BellSlash aria-hidden="true" />{labels.snooze}
|
|
353
|
+
</Button>
|
|
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>
|
|
361
|
+
|
|
362
|
+
{#if snoozing}
|
|
363
|
+
<div class="flex flex-wrap gap-2" role="group" aria-label={labels.snooze}>
|
|
364
|
+
{#each snoozeChoices(new Date()) as choice, index (choice.id)}
|
|
365
|
+
<Button size="sm" variant="outline" onclick={() => snooze(choice.until)}>
|
|
366
|
+
<Kbd>{index + 1}</Kbd>{snoozeLabel(choice.id)}
|
|
367
|
+
</Button>
|
|
368
|
+
{/each}
|
|
369
|
+
</div>
|
|
370
|
+
{/if}
|
|
371
|
+
|
|
372
|
+
{#each current.pending as entry (entry.id)}
|
|
373
|
+
<InboxCard
|
|
374
|
+
bind:this={cards[entry.id]}
|
|
375
|
+
item={entry.proposal!}
|
|
376
|
+
selected={entry === pinned}
|
|
377
|
+
onverdict={(verdict) => onDecide?.(verdict, current)}
|
|
378
|
+
{renderProposal}
|
|
379
|
+
/>
|
|
380
|
+
{/each}
|
|
381
|
+
|
|
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}
|
|
421
|
+
{:else}
|
|
422
|
+
<RailEmpty title={labels.selectThread} />
|
|
423
|
+
{/if}
|
|
424
|
+
{/snippet}
|
|
425
|
+
</MasterDetail>
|
|
426
|
+
|
|
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
|
+
>
|
|
433
|
+
<span class="inline-flex items-center gap-1.5"><Kbd>u</Kbd> {labels.hintRead}</span>
|
|
434
|
+
<span class="inline-flex items-center gap-1.5"><Kbd>h</Kbd> {labels.hintSnooze}</span>
|
|
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
|
+
>
|
|
438
|
+
</footer>
|
|
439
|
+
</div>
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import type { InboxItem } from "../tasks/inbox/inbox-types.js";
|
|
2
|
+
|
|
3
|
+
export type InboxActorKind = "user" | "agent";
|
|
4
|
+
|
|
5
|
+
export type InboxActor = {
|
|
6
|
+
kind: InboxActorKind;
|
|
7
|
+
name: string;
|
|
8
|
+
/** Image URL for a person. The host's own portrait goes through the `avatar` snippet. */
|
|
9
|
+
avatar?: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export type InboxEntryKind =
|
|
13
|
+
| "comment"
|
|
14
|
+
| "status"
|
|
15
|
+
| "assigned"
|
|
16
|
+
| "mention"
|
|
17
|
+
| "agent_response"
|
|
18
|
+
| "proposal";
|
|
19
|
+
|
|
20
|
+
/** What the thread is about: one task, project or doc. Entries with the same type and id share a thread. */
|
|
21
|
+
export type InboxSubject = {
|
|
22
|
+
/** "task", "project", "doc" or whatever the host calls it. */
|
|
23
|
+
type: string;
|
|
24
|
+
id: string;
|
|
25
|
+
/** The short reference, such as "TSK-7". */
|
|
26
|
+
ref?: string;
|
|
27
|
+
title: string;
|
|
28
|
+
/** A status id the host draws itself, for a badge in the thread header. */
|
|
29
|
+
status?: string;
|
|
30
|
+
href?: string;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type InboxEntry = {
|
|
34
|
+
id: string;
|
|
35
|
+
kind: InboxEntryKind;
|
|
36
|
+
/** An entry with no subject id belongs to no thread and is dropped. */
|
|
37
|
+
subject?: InboxSubject;
|
|
38
|
+
actor: InboxActor;
|
|
39
|
+
/** ISO timestamp. A malformed one sorts last. */
|
|
40
|
+
at: string;
|
|
41
|
+
read?: boolean;
|
|
42
|
+
/** Text of a comment, a mention or an agent response. */
|
|
43
|
+
body?: string;
|
|
44
|
+
/** A `status` entry: where the subject moved. */
|
|
45
|
+
status?: { from?: string; to: string };
|
|
46
|
+
/** An `assigned` entry: who got the work. */
|
|
47
|
+
assignee?: string;
|
|
48
|
+
/** A `proposal` entry: the agent's ask, drawn as an InboxCard while it waits. */
|
|
49
|
+
proposal?: InboxItem;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export type InboxThread = {
|
|
53
|
+
/** `type:id`, unique across subjects. */
|
|
54
|
+
key: string;
|
|
55
|
+
subject: InboxSubject;
|
|
56
|
+
/** Oldest first. */
|
|
57
|
+
entries: InboxEntry[];
|
|
58
|
+
unread: number;
|
|
59
|
+
/** The newest valid timestamp, as written. The raw first one when none parses. */
|
|
60
|
+
latestAt: string;
|
|
61
|
+
/** Proposals still waiting for a verdict, newest first. */
|
|
62
|
+
pending: InboxEntry[];
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export type InboxFilter = {
|
|
66
|
+
/** A subject type, or "all". */
|
|
67
|
+
type: string;
|
|
68
|
+
/** An actor name, or "all". */
|
|
69
|
+
who: string;
|
|
70
|
+
/** Only threads holding a pending proposal. */
|
|
71
|
+
needsYou: boolean;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export const ALL = "all";
|
|
75
|
+
|
|
76
|
+
export type InboxKey =
|
|
77
|
+
| "next"
|
|
78
|
+
| "previous"
|
|
79
|
+
| "toggleRead"
|
|
80
|
+
| "snooze"
|
|
81
|
+
| "approve"
|
|
82
|
+
| "decline"
|
|
83
|
+
| "steer"
|
|
84
|
+
| "edit";
|
|
85
|
+
|
|
86
|
+
export type InboxSnooze = { thread: InboxThread; until: Date };
|
|
87
|
+
|
|
88
|
+
export type InboxLabels = {
|
|
89
|
+
title: string;
|
|
90
|
+
all: string;
|
|
91
|
+
anyone: string;
|
|
92
|
+
needsYou: string;
|
|
93
|
+
empty: string;
|
|
94
|
+
emptyNeedsYou: string;
|
|
95
|
+
emptyFiltered: string;
|
|
96
|
+
clearFilters: string;
|
|
97
|
+
unread: string;
|
|
98
|
+
markRead: string;
|
|
99
|
+
markUnread: string;
|
|
100
|
+
snooze: string;
|
|
101
|
+
snoozeLater: string;
|
|
102
|
+
snoozeTomorrow: string;
|
|
103
|
+
snoozeNextWeek: string;
|
|
104
|
+
selectThread: string;
|
|
105
|
+
filterType: string;
|
|
106
|
+
filterWho: string;
|
|
107
|
+
filter: string;
|
|
108
|
+
kind: string;
|
|
109
|
+
from: string;
|
|
110
|
+
open: string;
|
|
111
|
+
agent: string;
|
|
112
|
+
statusMoved: string;
|
|
113
|
+
statusSet: string;
|
|
114
|
+
assigned: string;
|
|
115
|
+
mentioned: string;
|
|
116
|
+
commented: string;
|
|
117
|
+
responded: string;
|
|
118
|
+
proposed: string;
|
|
119
|
+
/** Keyboard hint words. */
|
|
120
|
+
hintMove: string;
|
|
121
|
+
hintRead: string;
|
|
122
|
+
hintSnooze: string;
|
|
123
|
+
hintAct: string;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export const DEFAULT_INBOX_LABELS: InboxLabels = {
|
|
127
|
+
title: "Inbox",
|
|
128
|
+
all: "All",
|
|
129
|
+
anyone: "Anyone",
|
|
130
|
+
needsYou: "Needs you",
|
|
131
|
+
empty: "Nothing here",
|
|
132
|
+
emptyNeedsYou: "Nothing is waiting on you",
|
|
133
|
+
emptyFiltered: "No thread matches these filters",
|
|
134
|
+
clearFilters: "Clear filters",
|
|
135
|
+
unread: "unread",
|
|
136
|
+
markRead: "Mark read",
|
|
137
|
+
markUnread: "Mark unread",
|
|
138
|
+
snooze: "Snooze",
|
|
139
|
+
snoozeLater: "Later today",
|
|
140
|
+
snoozeTomorrow: "Tomorrow",
|
|
141
|
+
snoozeNextWeek: "Next week",
|
|
142
|
+
selectThread: "Select a thread",
|
|
143
|
+
filterType: "Filter by type",
|
|
144
|
+
filterWho: "Filter by person or agent",
|
|
145
|
+
filter: "Filter",
|
|
146
|
+
kind: "Type",
|
|
147
|
+
from: "From",
|
|
148
|
+
open: "Open",
|
|
149
|
+
agent: "AI",
|
|
150
|
+
statusMoved: "moved this from {from} to {to}",
|
|
151
|
+
statusSet: "set this to {to}",
|
|
152
|
+
assigned: "assigned this to {assignee}",
|
|
153
|
+
mentioned: "mentioned you",
|
|
154
|
+
commented: "commented",
|
|
155
|
+
responded: "replied",
|
|
156
|
+
proposed: "asks for your call",
|
|
157
|
+
hintMove: "move",
|
|
158
|
+
hintRead: "read",
|
|
159
|
+
hintSnooze: "snooze",
|
|
160
|
+
hintAct: "approve, decline, steer, edit",
|
|
161
|
+
};
|
|
@@ -14,10 +14,8 @@ const DEFAULT_DURATION = 400;
|
|
|
14
14
|
const STYLE_ID = "heyramzi-reveal-theme";
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
* Run `apply` inside a circular wipe
|
|
18
|
-
*
|
|
19
|
-
* browser has no view transitions, the user prefers reduced motion, or `skip`
|
|
20
|
-
* is set. It adds the `::view-transition-*(root)` reset itself.
|
|
17
|
+
* Run `apply` inside a circular wipe from the clicked element or a point, falling back to
|
|
18
|
+
* plain `apply()` without view transitions, under reduced motion, or with `skip`.
|
|
21
19
|
*/
|
|
22
20
|
export function revealTheme(
|
|
23
21
|
origin: RevealOrigin,
|
package/src/lib/tone.ts
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
export type Tone = "neutral" | "accent" | "info" | "success" | "warning" | "destructive";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* The severity scale
|
|
5
|
-
*
|
|
6
|
-
* accent tone reads `--tone-accent` and falls back to `--color-primary`, for a
|
|
7
|
-
* host whose primary is a neutral and whose accent is a brand color.
|
|
4
|
+
* The severity scale as chip classes and dot colors. Accent reads `--tone-accent` before
|
|
5
|
+
* `--color-primary`, for a host whose primary is a neutral.
|
|
8
6
|
*/
|
|
9
7
|
|
|
10
8
|
export const TONE_CLASS: Record<Tone, string> = {
|
package/src/lib/utils.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// The class merge and prop types every shadcn primitive
|
|
2
|
-
//
|
|
1
|
+
// The class merge and prop types every shadcn primitive uses, kept here, not in a shared utils
|
|
2
|
+
// package, so this public package installs with nothing private behind it.
|
|
3
3
|
import { type ClassValue, clsx } from "clsx";
|
|
4
4
|
import { twMerge } from "tailwind-merge";
|
|
5
5
|
|