@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
|
@@ -6,57 +6,68 @@ const ada = { kind: "user", name: "Ada" } as const;
|
|
|
6
6
|
const bot = { kind: "agent", name: "Scribe" } as const;
|
|
7
7
|
|
|
8
8
|
function comment(id: string, at: string, extra: Partial<ThreadComment> = {}): ThreadComment {
|
|
9
|
-
|
|
9
|
+
return { id, author: ada, body: id, createdAt: at, ...extra };
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
describe("buildThread", () => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
13
|
+
it("puts replies under their root in time order", () => {
|
|
14
|
+
const nodes = buildThread([
|
|
15
|
+
comment("r2", "2026-10-22T10:05:00Z", { parentId: "a" }),
|
|
16
|
+
comment("a", "2026-10-22T10:00:00Z"),
|
|
17
|
+
comment("b", "2026-10-22T10:02:00Z", { author: bot }),
|
|
18
|
+
comment("r1", "2026-10-22T10:03:00Z", { parentId: "a" }),
|
|
19
|
+
]);
|
|
20
|
+
expect(nodes.map((n) => n.comment.id)).toEqual(["a", "b"]);
|
|
21
|
+
expect(nodes[0].replies.map((r) => r.id)).toEqual(["r1", "r2"]);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("keeps a reply to a reply under the root", () => {
|
|
25
|
+
const nodes = buildThread([
|
|
26
|
+
comment("a", "2026-10-22T10:00:00Z"),
|
|
27
|
+
comment("r1", "2026-10-22T10:01:00Z", { parentId: "a" }),
|
|
28
|
+
comment("r2", "2026-10-22T10:02:00Z", { parentId: "r1" }),
|
|
29
|
+
]);
|
|
30
|
+
expect(nodes).toHaveLength(1);
|
|
31
|
+
expect(nodes[0].replies.map((r) => r.id)).toEqual(["r1", "r2"]);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("turns an orphan reply into a root and survives a parent loop", () => {
|
|
35
|
+
const nodes = buildThread([
|
|
36
|
+
comment("x", "2026-10-22T10:00:00Z", { parentId: "gone" }),
|
|
37
|
+
comment("p", "2026-10-22T10:01:00Z", { parentId: "q" }),
|
|
38
|
+
comment("q", "2026-10-22T10:02:00Z", { parentId: "p" }),
|
|
39
|
+
]);
|
|
40
|
+
expect(nodes.map((n) => n.comment.id)).toContain("x");
|
|
41
|
+
expect(nodes.flatMap((n) => [n.comment.id, ...n.replies.map((r) => r.id)]).sort()).toEqual([
|
|
42
|
+
"p",
|
|
43
|
+
"q",
|
|
44
|
+
"x",
|
|
45
|
+
]);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("sorts a malformed timestamp last", () => {
|
|
49
|
+
const nodes = buildThread([comment("bad", "soon"), comment("ok", "2026-10-22T10:00:00Z")]);
|
|
50
|
+
expect(nodes.map((n) => n.comment.id)).toEqual(["ok", "bad"]);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("counts resolved roots", () => {
|
|
54
|
+
const nodes = buildThread([
|
|
55
|
+
comment("a", "2026-10-22T10:00:00Z", { resolved: true }),
|
|
56
|
+
comment("b", "2026-10-22T10:01:00Z"),
|
|
57
|
+
]);
|
|
58
|
+
expect(resolvedCount(nodes)).toBe(1);
|
|
59
|
+
});
|
|
53
60
|
});
|
|
54
61
|
|
|
55
62
|
describe("labels", () => {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
63
|
+
it("lets a host write French over the English defaults", () => {
|
|
64
|
+
const fr = resolveThreadLabels({
|
|
65
|
+
title: "Activité",
|
|
66
|
+
send: "Commenter",
|
|
67
|
+
showResolved: "Afficher {count} résolus",
|
|
68
|
+
});
|
|
69
|
+
expect(fr.title).toBe("Activité");
|
|
70
|
+
expect(fr.cancel).toBe(DEFAULT_THREAD_LABELS.cancel);
|
|
71
|
+
expect(fillCount(fr.showResolved, 3)).toBe("Afficher 3 résolus");
|
|
72
|
+
});
|
|
62
73
|
});
|
package/src/thread/types.ts
CHANGED
|
@@ -1,93 +1,93 @@
|
|
|
1
1
|
export type ThreadAuthorKind = "user" | "agent";
|
|
2
2
|
|
|
3
3
|
export type ThreadAuthor = {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
kind: ThreadAuthorKind;
|
|
5
|
+
name: string;
|
|
6
|
+
/** Image URL for a person. The host's own portrait goes through the `avatar` snippet. */
|
|
7
|
+
avatar?: string;
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
/** Where on a canvas a comment is pinned: a node and an offset from it, or a point. */
|
|
11
11
|
export type ThreadAnchor = {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
nodeId?: string;
|
|
13
|
+
dx?: number;
|
|
14
|
+
dy?: number;
|
|
15
|
+
x?: number;
|
|
16
|
+
y?: number;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
/** One comment on any subject. The host resolves the author's name. */
|
|
20
20
|
export type ThreadComment = {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
21
|
+
id: string;
|
|
22
|
+
author: ThreadAuthor;
|
|
23
|
+
/** Plain text, shown as written. Also the fallback when `content` is missing. */
|
|
24
|
+
body: string;
|
|
25
|
+
/** Tiptap JSON. When set, the thread draws it through the editor's renderer instead of `body`. */
|
|
26
|
+
content?: Record<string, unknown>;
|
|
27
|
+
/** ISO timestamp. */
|
|
28
|
+
createdAt: string;
|
|
29
|
+
/** Set when the body changed after posting. */
|
|
30
|
+
edited?: boolean;
|
|
31
|
+
/** The comment this one answers. A reply to a reply sits under the same root. */
|
|
32
|
+
parentId?: string | null;
|
|
33
|
+
/** Only a root carries it: the whole conversation is resolved. */
|
|
34
|
+
resolved?: boolean;
|
|
35
|
+
anchor?: ThreadAnchor | null;
|
|
36
36
|
};
|
|
37
37
|
|
|
38
38
|
export type ThreadPost = {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
body: string;
|
|
40
|
+
parentId: string | null;
|
|
41
|
+
anchor?: ThreadAnchor | null;
|
|
42
42
|
};
|
|
43
43
|
|
|
44
44
|
/** A root comment with its replies in time order. */
|
|
45
45
|
export type ThreadNode = {
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
comment: ThreadComment;
|
|
47
|
+
replies: ThreadComment[];
|
|
48
48
|
};
|
|
49
49
|
|
|
50
50
|
export type ThreadLabels = {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
51
|
+
title: string;
|
|
52
|
+
empty: string;
|
|
53
|
+
placeholder: string;
|
|
54
|
+
replyPlaceholder: string;
|
|
55
|
+
send: string;
|
|
56
|
+
sending: string;
|
|
57
|
+
reply: string;
|
|
58
|
+
edit: string;
|
|
59
|
+
delete: string;
|
|
60
|
+
edited: string;
|
|
61
|
+
save: string;
|
|
62
|
+
cancel: string;
|
|
63
|
+
resolve: string;
|
|
64
|
+
unresolve: string;
|
|
65
|
+
resolved: string;
|
|
66
|
+
/** Shows `{count}` resolved conversations. */
|
|
67
|
+
showResolved: string;
|
|
68
|
+
hideResolved: string;
|
|
69
|
+
agent: string;
|
|
70
|
+
pinned: string;
|
|
71
71
|
};
|
|
72
72
|
|
|
73
73
|
export const DEFAULT_THREAD_LABELS: ThreadLabels = {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
74
|
+
title: "Activity",
|
|
75
|
+
empty: "No comments yet",
|
|
76
|
+
placeholder: "Leave a comment",
|
|
77
|
+
replyPlaceholder: "Reply",
|
|
78
|
+
send: "Comment",
|
|
79
|
+
sending: "Sending",
|
|
80
|
+
reply: "Reply",
|
|
81
|
+
edit: "Edit comment",
|
|
82
|
+
delete: "Delete comment",
|
|
83
|
+
edited: "edited",
|
|
84
|
+
save: "Save",
|
|
85
|
+
cancel: "Cancel",
|
|
86
|
+
resolve: "Resolve",
|
|
87
|
+
unresolve: "Reopen",
|
|
88
|
+
resolved: "Resolved",
|
|
89
|
+
showResolved: "Show {count} resolved",
|
|
90
|
+
hideResolved: "Hide resolved",
|
|
91
|
+
agent: "AI",
|
|
92
|
+
pinned: "Pinned",
|
|
93
93
|
};
|
package/src/tokens/craft.css
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
/* ── Radius, by role not by size ─────────────────────────────
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
home so `rounded-lg` on a button already resolves to the control radius and
|
|
5
|
-
no component has to learn a new class. */
|
|
2
|
+
These override Tailwind's own names, so `rounded-lg` on a button already
|
|
3
|
+
resolves to the control radius. */
|
|
6
4
|
@theme {
|
|
7
5
|
--radius-xs: 4px; /* tag, dot, inline code */
|
|
8
6
|
--radius-sm: 6px; /* chip, badge, small pill */
|
|
@@ -14,30 +12,9 @@
|
|
|
14
12
|
}
|
|
15
13
|
|
|
16
14
|
/* ── Elevation ───────────────────────────────────────────────
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
WHY the steps are shadow-only and the hairline is its own token: most boxes
|
|
20
|
-
in a kit already draw a border, and an elevation that bakes a `0 0 0 1px`
|
|
21
|
-
ring into every step gives those boxes two edges a pixel apart. Compose them
|
|
22
|
-
where a component drops its border:
|
|
23
|
-
|
|
24
|
-
box-shadow: var(--elev-hairline), var(--elev-card);
|
|
25
|
-
|
|
26
|
-
WHY each step is stacked rather than one blurred drop: a single shadow reads
|
|
27
|
-
as a sticker. Depth is several offsets falling off together, which is what
|
|
28
|
-
the eye reads as distance. They cost nothing extra because every stop is the
|
|
29
|
-
same colour at a different alpha.
|
|
30
|
-
|
|
31
|
-
WHY the blur radii are large and the alphas small: a 4px blur at 20% draws a
|
|
32
|
-
visible grey edge, which the eye reads as a second border. A 28px blur at 7%
|
|
33
|
-
is barely a colour anywhere and reads as height. Reach for more blur before
|
|
34
|
-
more alpha, every time.
|
|
35
|
-
|
|
36
|
-
`--elev-tint` is the one knob an app turns. Pure black greys a warm palette
|
|
37
|
-
out; the hue of the app's own darkest surface keeps the shadow in the
|
|
38
|
-
family. */
|
|
15
|
+
The steps carry no ring, since a bordered box would get two edges a pixel
|
|
16
|
+
apart; a borderless one adds `var(--elev-hairline)` in front. */
|
|
39
17
|
:root {
|
|
40
|
-
|
|
41
18
|
/* Resting on the page. A button, a chip, a row. */
|
|
42
19
|
--elev-btn:
|
|
43
20
|
0 1px 1px -0.5px color-mix(in oklab, var(--elev-tint) 7%, transparent),
|
|
@@ -61,9 +38,8 @@
|
|
|
61
38
|
0 12px 26px -8px color-mix(in oklab, var(--elev-tint) 12%, transparent),
|
|
62
39
|
0 40px 72px -20px color-mix(in oklab, var(--elev-tint) 20%, transparent);
|
|
63
40
|
|
|
64
|
-
/*
|
|
65
|
-
|
|
66
|
-
read as a physical key rather than a coloured rectangle. */
|
|
41
|
+
/* A hairline separates a surface from what's behind it; a rim is light on the
|
|
42
|
+
top edge, which makes a filled control read as a key. */
|
|
67
43
|
--elev-hairline: 0 0 0 1px var(--color-border, var(--border));
|
|
68
44
|
--elev-rim: inset 0 1px 0 color-mix(in oklab, white 16%, transparent);
|
|
69
45
|
|
|
@@ -71,10 +47,8 @@
|
|
|
71
47
|
--elev-field: inset 0 1px 2px color-mix(in oklab, var(--elev-tint) 7%, transparent);
|
|
72
48
|
}
|
|
73
49
|
|
|
74
|
-
/* A
|
|
75
|
-
hairline does the separating
|
|
76
|
-
dark the hairline is white at a low alpha, which is what reads as a lit edge
|
|
77
|
-
rather than as a drawn border. */
|
|
50
|
+
/* A shadow can't get darker than a dark page, so on dark the low-alpha white
|
|
51
|
+
hairline does the separating. */
|
|
78
52
|
.dark {
|
|
79
53
|
--elev-btn: 0 1px 2px color-mix(in oklab, black 30%, transparent);
|
|
80
54
|
--elev-card:
|
|
@@ -93,25 +67,19 @@
|
|
|
93
67
|
}
|
|
94
68
|
|
|
95
69
|
/* ── Focus ───────────────────────────────────────────────────
|
|
96
|
-
One
|
|
97
|
-
|
|
98
|
-
variable so a component spends one line on it and every control focuses the
|
|
99
|
-
same way. */
|
|
70
|
+
One variable, so every control focuses the same way: a solid accent edge,
|
|
71
|
+
then a soft halo. */
|
|
100
72
|
:root {
|
|
101
73
|
--ring-color: var(--color-ring, var(--ring));
|
|
102
74
|
--ring-halo: color-mix(in oklab, var(--ring-color) 16%, transparent);
|
|
103
|
-
/*
|
|
104
|
-
|
|
105
|
-
is why it is 16% over 4px and not 30% over 2px. */
|
|
75
|
+
/* The halo is 16% over 4px, not 30% over 2px, because a stronger band reads
|
|
76
|
+
as a second border instead of a glow. */
|
|
106
77
|
--ring-focus: 0 0 0 1px var(--ring-color), 0 0 0 5px var(--ring-halo);
|
|
107
78
|
}
|
|
108
79
|
|
|
109
80
|
/* ── Motion ──────────────────────────────────────────────────
|
|
110
|
-
The transitions-dev scale, verbatim, so a
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
The doctrine in one line: an open is an invitation and a close should get out
|
|
114
|
-
of the way, so every close is shorter than its open and no close bounces. */
|
|
81
|
+
The transitions-dev scale, verbatim, so a pasted snippet reads the same
|
|
82
|
+
names. Every close is shorter than its open, and no close bounces. */
|
|
115
83
|
:root {
|
|
116
84
|
--duration-stagger: 40ms;
|
|
117
85
|
--duration-micro: 80ms;
|
|
@@ -163,13 +131,9 @@
|
|
|
163
131
|
|
|
164
132
|
--ease-smooth-out: var(--ease-smooth-out);
|
|
165
133
|
|
|
166
|
-
/*
|
|
167
|
-
`duration
|
|
168
|
-
|
|
169
|
-
compiled to nothing and the element ended up at `transition-duration: 0s`:
|
|
170
|
-
no error, no warning, and a component that simply does not animate. The
|
|
171
|
-
comment at the top of this block had claimed `duration-fast` was a class
|
|
172
|
-
since the block was written. Found 31 Aug 2026 by probing a live page. */
|
|
134
|
+
/* Tailwind's `duration-*` reads `--transition-duration-*`, so without these
|
|
135
|
+
`duration-fast` silently compiles to nothing and the element doesn't animate
|
|
136
|
+
(31 Aug 2026). */
|
|
173
137
|
--transition-duration-micro: var(--duration-micro);
|
|
174
138
|
--transition-duration-quick: var(--duration-quick);
|
|
175
139
|
--transition-duration-fast: var(--duration-fast);
|
package/src/tokens/index.css
CHANGED
|
@@ -1,16 +1,6 @@
|
|
|
1
|
-
/* tokens.css
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* @import "tailwindcss";
|
|
6
|
-
* @import "@heyramzi/ui/tokens.css";
|
|
7
|
-
* @import "@heyramzi/ui/animations";
|
|
8
|
-
* @import "@heyramzi/ui/shadcn/utilities.css"; // only if you use Attachment or Message
|
|
9
|
-
*
|
|
10
|
-
* It carries three things: the color palette and semantic tokens, the craft
|
|
11
|
-
* layer (radius, elevation, focus and motion), and the small set of motion
|
|
12
|
-
* primitives the components share. Override any variable on :root to retheme.
|
|
13
|
-
* The parts load in this order because later blocks read earlier variables.
|
|
1
|
+
/* tokens.css: import once, right after `@import "tailwindcss"`. Override any
|
|
2
|
+
* variable on :root to retheme; the parts load in this order because later ones
|
|
3
|
+
* read earlier variables.
|
|
14
4
|
*/
|
|
15
5
|
|
|
16
6
|
@import "./palette.css";
|
package/src/tokens/palette.css
CHANGED
|
@@ -22,9 +22,8 @@
|
|
|
22
22
|
--gray-900: oklch(0.15 0 0); /* Near-black — headings, primary text */
|
|
23
23
|
|
|
24
24
|
/* === Brand roles ===
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
other token below reads from these, so nothing else in the package names a hue. */
|
|
25
|
+
Neutral defaults a brand replaces through `@heyramzi/ui/brand`; every token below reads
|
|
26
|
+
from these, so nothing else in the package names a hue. */
|
|
28
27
|
--brand: oklch(0.28 0 0); /* The signature colour: focus ring, links, active states, the mark */
|
|
29
28
|
--brand-on-dark: oklch(0.92 0 0); /* The same colour lifted for a dark page */
|
|
30
29
|
--brand-highlight: oklch(0.78 0 0); /* Warmth: badges, highlights, soft accents */
|
|
@@ -39,9 +38,9 @@
|
|
|
39
38
|
--brand-surface-light: oklch(0.99 0 0); /* Cards on a light page */
|
|
40
39
|
--brand-line-light: oklch(0.91 0 0); /* Borders on a light page */
|
|
41
40
|
|
|
42
|
-
/* === Tint scales
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
/* === Tint scales ===
|
|
42
|
+
Mixed from the three hues so `--brand` alone yields 100 to 800; 400 is the colour lifted
|
|
43
|
+
for dark, 600 the colour itself. */
|
|
45
44
|
--brand-100: color-mix(in oklab, var(--brand) 12%, white);
|
|
46
45
|
--brand-200: color-mix(in oklab, var(--brand) 28%, white);
|
|
47
46
|
--brand-400: var(--brand-on-dark);
|
|
@@ -117,8 +116,7 @@
|
|
|
117
116
|
--sidebar-ring: var(--brand);
|
|
118
117
|
|
|
119
118
|
/* === Shadow tint ===
|
|
120
|
-
|
|
121
|
-
so the shadow takes the darkest surface's hue. Radius, focus and motion live there. */
|
|
119
|
+
Pure black greys out warm surfaces, so the shadow takes the darkest surface's hue. */
|
|
122
120
|
--elev-tint: var(--brand-ink);
|
|
123
121
|
}
|
|
124
122
|
|
|
@@ -198,14 +196,18 @@
|
|
|
198
196
|
--color-cat-indigo: var(--cat-indigo);
|
|
199
197
|
--color-cat-purple: var(--cat-purple);
|
|
200
198
|
|
|
201
|
-
/* A hue as text
|
|
202
|
-
|
|
199
|
+
/* A hue as text on its own tint mixes 40% toward the foreground to clear AA in both themes,
|
|
200
|
+
where plain destructive text on that tint is 3.6:1. */
|
|
203
201
|
--color-cat-cyan-ink: color-mix(in oklab, var(--color-cat-cyan) 60%, var(--color-foreground));
|
|
204
202
|
--color-cat-teal-ink: color-mix(in oklab, var(--color-cat-teal) 60%, var(--color-foreground));
|
|
205
203
|
--color-cat-purple-ink: color-mix(in oklab, var(--color-cat-purple) 60%, var(--color-foreground));
|
|
206
204
|
--color-cat-amber-ink: color-mix(in oklab, var(--color-cat-amber) 60%, var(--color-foreground));
|
|
207
205
|
--color-success-ink: color-mix(in oklab, var(--color-success) 60%, var(--color-foreground));
|
|
208
|
-
--color-destructive-ink: color-mix(
|
|
206
|
+
--color-destructive-ink: color-mix(
|
|
207
|
+
in oklab,
|
|
208
|
+
var(--color-destructive) 60%,
|
|
209
|
+
var(--color-foreground)
|
|
210
|
+
);
|
|
209
211
|
|
|
210
212
|
/* Light theme color system: the light surfaces and lines of the brand roles */
|
|
211
213
|
--color-background: var(--gray-50);
|
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
/*
|
|
2
|
-
*
|
|
3
|
-
* bits-ui v2 writes `data-checked` / `data-open` and v1 wrote
|
|
4
|
-
* `data-state="checked"`, so each variant matches both and a component does not
|
|
5
|
-
* have to know which it is talking to. They live here rather than in a
|
|
6
|
-
* consumer's stylesheet because the classes that need them ship in this
|
|
7
|
-
* package: an app that defines only the palette would render a switch that
|
|
8
|
-
* never moves. */
|
|
1
|
+
/* Each variant matches both bits-ui v2's `data-checked` and v1's `data-state="checked"`, and
|
|
2
|
+
* ships here because an app that defines only the palette gets a switch that never moves. */
|
|
9
3
|
@custom-variant data-open {
|
|
10
4
|
&:where([data-state="open"]),
|
|
11
5
|
&:where([data-open]:not([data-open="false"])) {
|
|
@@ -80,9 +74,8 @@
|
|
|
80
74
|
background: color-mix(in oklab, var(--ring-color) 24%, transparent);
|
|
81
75
|
}
|
|
82
76
|
|
|
83
|
-
/* A default macOS overlay scrollbar paints a black bar on a dark panel
|
|
84
|
-
transparent
|
|
85
|
-
is over. The border is what insets the thumb without a second element. */
|
|
77
|
+
/* A default macOS overlay scrollbar paints a black bar on a dark panel, so the track stays
|
|
78
|
+
transparent and the thumb takes the line token. */
|
|
86
79
|
:where(html) {
|
|
87
80
|
scrollbar-color: var(--color-border, var(--border)) transparent;
|
|
88
81
|
}
|
|
@@ -111,16 +104,11 @@
|
|
|
111
104
|
}
|
|
112
105
|
|
|
113
106
|
@layer components {
|
|
114
|
-
/*
|
|
115
|
-
|
|
116
|
-
motion guard then lives in one place instead of in every component.
|
|
107
|
+
/* Classes, not tokens, so a component takes one name and the reduced-motion guard lives in
|
|
108
|
+
one place; the `t-` prefix matches the transitions-dev snippets. */
|
|
117
109
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
/* A control that reads as a key: it travels down a pixel under the finger.
|
|
122
|
-
The travel is what sells it, because a colour change alone reads as a hover
|
|
123
|
-
state, not as a press. */
|
|
110
|
+
/* A key-like control travels down a pixel under the finger, because a colour change alone
|
|
111
|
+
reads as a hover, not a press. */
|
|
124
112
|
.t-press {
|
|
125
113
|
transition:
|
|
126
114
|
background-color var(--duration-quick) var(--ease-smooth-out),
|
|
@@ -134,9 +122,8 @@
|
|
|
134
122
|
transform: translateY(1px);
|
|
135
123
|
}
|
|
136
124
|
|
|
137
|
-
/* A card
|
|
138
|
-
|
|
139
|
-
than as its border changing colour. */
|
|
125
|
+
/* A hover card rises a pixel and gains the next elevation step, so it reads as coming
|
|
126
|
+
forward, not as its border changing colour. */
|
|
140
127
|
.t-lift {
|
|
141
128
|
transition:
|
|
142
129
|
box-shadow var(--duration-fast) var(--ease-smooth-out),
|