@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
package/src/tasks/demo.svelte
CHANGED
|
@@ -50,14 +50,91 @@
|
|
|
50
50
|
const on = (days: number) => addDays(today, days);
|
|
51
51
|
|
|
52
52
|
let tasks = $state<Task[]>([
|
|
53
|
-
{
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
53
|
+
{
|
|
54
|
+
id: "t1",
|
|
55
|
+
status: "done",
|
|
56
|
+
title: "Set up analytics",
|
|
57
|
+
assignee: "Bo",
|
|
58
|
+
priority: "low",
|
|
59
|
+
boardOrder: "a0",
|
|
60
|
+
start: on(-12),
|
|
61
|
+
end: on(-8),
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
id: "t2",
|
|
65
|
+
status: "done",
|
|
66
|
+
title: "Interview five customers",
|
|
67
|
+
assignee: "Cleo",
|
|
68
|
+
priority: "medium",
|
|
69
|
+
boardOrder: "a1",
|
|
70
|
+
start: on(-10),
|
|
71
|
+
end: on(-4),
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
id: "t3",
|
|
75
|
+
status: "review",
|
|
76
|
+
title: "Write the pricing page",
|
|
77
|
+
assignee: "Ada",
|
|
78
|
+
priority: "high",
|
|
79
|
+
boardOrder: "a0",
|
|
80
|
+
start: on(-5),
|
|
81
|
+
end: on(1),
|
|
82
|
+
dependsOn: ["t2"],
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
id: "t4",
|
|
86
|
+
status: "doing",
|
|
87
|
+
title: "Build the onboarding flow",
|
|
88
|
+
assignee: "Dana",
|
|
89
|
+
priority: "high",
|
|
90
|
+
boardOrder: "a0",
|
|
91
|
+
start: on(-3),
|
|
92
|
+
end: on(5),
|
|
93
|
+
dependsOn: ["t1"],
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
id: "t5",
|
|
97
|
+
status: "doing",
|
|
98
|
+
title: "Draft the launch email",
|
|
99
|
+
assignee: "Bo",
|
|
100
|
+
priority: "medium",
|
|
101
|
+
boardOrder: "a1",
|
|
102
|
+
start: on(0),
|
|
103
|
+
end: on(3),
|
|
104
|
+
dependsOn: ["t3"],
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
id: "t6",
|
|
108
|
+
status: "todo",
|
|
109
|
+
title: "Record the demo video",
|
|
110
|
+
assignee: "Cleo",
|
|
111
|
+
priority: "medium",
|
|
112
|
+
boardOrder: "a0",
|
|
113
|
+
start: on(4),
|
|
114
|
+
end: on(8),
|
|
115
|
+
dependsOn: ["t4"],
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
id: "t7",
|
|
119
|
+
status: "todo",
|
|
120
|
+
title: "Pick a shipping date",
|
|
121
|
+
assignee: "Ada",
|
|
122
|
+
priority: "low",
|
|
123
|
+
boardOrder: "a1",
|
|
124
|
+
start: on(6),
|
|
125
|
+
end: on(6),
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
id: "t8",
|
|
129
|
+
status: "todo",
|
|
130
|
+
title: "Launch on Product Hunt",
|
|
131
|
+
assignee: "Dana",
|
|
132
|
+
priority: "high",
|
|
133
|
+
boardOrder: "a2",
|
|
134
|
+
start: on(10),
|
|
135
|
+
end: on(11),
|
|
136
|
+
dependsOn: ["t5", "t6"],
|
|
137
|
+
},
|
|
61
138
|
]);
|
|
62
139
|
|
|
63
140
|
const views = [
|
|
@@ -76,7 +153,11 @@
|
|
|
76
153
|
|
|
77
154
|
const sortKeys = [
|
|
78
155
|
{ id: "title", label: "Title", compare: (a: Task, b: Task) => a.title.localeCompare(b.title) },
|
|
79
|
-
{
|
|
156
|
+
{
|
|
157
|
+
id: "assignee",
|
|
158
|
+
label: "Assignee",
|
|
159
|
+
compare: (a: Task, b: Task) => a.assignee.localeCompare(b.assignee),
|
|
160
|
+
},
|
|
80
161
|
{ id: "due", label: "Due date", compare: (a: Task, b: Task) => a.end.localeCompare(b.end) },
|
|
81
162
|
];
|
|
82
163
|
|
|
@@ -93,7 +174,11 @@
|
|
|
93
174
|
Dana: "oklch(0.72 0.13 20)",
|
|
94
175
|
};
|
|
95
176
|
|
|
96
|
-
const dueFormat = new Intl.DateTimeFormat("en-US", {
|
|
177
|
+
const dueFormat = new Intl.DateTimeFormat("en-US", {
|
|
178
|
+
month: "short",
|
|
179
|
+
day: "numeric",
|
|
180
|
+
timeZone: "UTC",
|
|
181
|
+
});
|
|
97
182
|
|
|
98
183
|
function due(task: Task): { label: string; late: boolean } {
|
|
99
184
|
const late = task.status !== "done" && dayNumber(task.end) < dayNumber(today);
|
|
@@ -113,7 +198,14 @@
|
|
|
113
198
|
}
|
|
114
199
|
|
|
115
200
|
// ---- time tracking, an option the host turns on
|
|
116
|
-
type Entry = {
|
|
201
|
+
type Entry = {
|
|
202
|
+
id: string;
|
|
203
|
+
taskId: string;
|
|
204
|
+
person: string;
|
|
205
|
+
day: string;
|
|
206
|
+
minutes: number;
|
|
207
|
+
note?: string;
|
|
208
|
+
};
|
|
117
209
|
|
|
118
210
|
const estimates: Record<string, number> = { t3: 360, t4: 480, t5: 180, t6: 240 };
|
|
119
211
|
|
|
@@ -121,9 +213,30 @@
|
|
|
121
213
|
let timeTaskId = $state("t4");
|
|
122
214
|
let nextEntry = 100;
|
|
123
215
|
let entries = $state<Entry[]>([
|
|
124
|
-
{
|
|
125
|
-
|
|
126
|
-
|
|
216
|
+
{
|
|
217
|
+
id: "e1",
|
|
218
|
+
taskId: "t4",
|
|
219
|
+
person: "Dana",
|
|
220
|
+
day: on(-3),
|
|
221
|
+
minutes: 150,
|
|
222
|
+
note: "Signup and email step",
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
id: "e2",
|
|
226
|
+
taskId: "t4",
|
|
227
|
+
person: "Ada",
|
|
228
|
+
day: on(-2),
|
|
229
|
+
minutes: 95,
|
|
230
|
+
note: "Copy for the welcome screen",
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
id: "e3",
|
|
234
|
+
taskId: "t4",
|
|
235
|
+
person: "Dana",
|
|
236
|
+
day: on(-2),
|
|
237
|
+
minutes: 125,
|
|
238
|
+
note: "Progress bar and empty states",
|
|
239
|
+
},
|
|
127
240
|
{ id: "e4", taskId: "t4", person: "Dana", day: on(-1), minutes: 80 },
|
|
128
241
|
{ id: "e5", taskId: "t3", person: "Ada", day: on(-5), minutes: 210, note: "First draft" },
|
|
129
242
|
{ id: "e6", taskId: "t3", person: "Bo", day: on(-3), minutes: 95, note: "Pricing table" },
|
|
@@ -158,7 +271,8 @@
|
|
|
158
271
|
timer = null;
|
|
159
272
|
}
|
|
160
273
|
|
|
161
|
-
const listGrid =
|
|
274
|
+
const listGrid =
|
|
275
|
+
"grid grid-cols-[minmax(0,1fr)_7rem_5.5rem_4.5rem] items-center gap-3 max-sm:grid-cols-[minmax(0,1fr)_4.5rem]";
|
|
162
276
|
</script>
|
|
163
277
|
|
|
164
278
|
{#snippet avatar(name: string)}
|
|
@@ -176,12 +290,23 @@
|
|
|
176
290
|
<div class="flex flex-wrap items-center gap-2">
|
|
177
291
|
<SegmentedFilter options={views} bind:value={view} ariaLabel="Task view" block={false} />
|
|
178
292
|
<div class="ml-auto flex items-center gap-3">
|
|
179
|
-
<label
|
|
180
|
-
|
|
293
|
+
<label
|
|
294
|
+
class="flex cursor-pointer items-center gap-1.5 text-xs font-medium text-muted-foreground"
|
|
295
|
+
>
|
|
296
|
+
<input
|
|
297
|
+
type="checkbox"
|
|
298
|
+
bind:checked={tracking}
|
|
299
|
+
class="size-3.5 accent-[var(--tone-accent,var(--color-primary))]"
|
|
300
|
+
/>
|
|
181
301
|
Time tracking
|
|
182
302
|
</label>
|
|
183
303
|
{#if view === "gantt"}
|
|
184
|
-
<SegmentedFilter
|
|
304
|
+
<SegmentedFilter
|
|
305
|
+
options={scales}
|
|
306
|
+
bind:value={scale}
|
|
307
|
+
ariaLabel="Timeline scale"
|
|
308
|
+
block={false}
|
|
309
|
+
/>
|
|
185
310
|
{:else}
|
|
186
311
|
<label for="tasks-sort" class="text-xs font-medium text-muted-foreground">Sort</label>
|
|
187
312
|
<select
|
|
@@ -213,15 +338,27 @@
|
|
|
213
338
|
>
|
|
214
339
|
{#snippet renderCard(task)}
|
|
215
340
|
{@const d = due(task)}
|
|
216
|
-
<article
|
|
341
|
+
<article
|
|
342
|
+
class="rounded-xl border border-border bg-card p-2.5 text-card-foreground shadow-sm"
|
|
343
|
+
>
|
|
217
344
|
<p class="text-sm leading-snug">{task.title}</p>
|
|
218
345
|
<div class="mt-2.5 flex items-center gap-2 text-xs">
|
|
219
346
|
{@render avatar(task.assignee)}
|
|
220
|
-
<span class={d.late ? "font-medium text-destructive" : "text-muted-foreground"}
|
|
347
|
+
<span class={d.late ? "font-medium text-destructive" : "text-muted-foreground"}
|
|
348
|
+
>{d.label}</span
|
|
349
|
+
>
|
|
221
350
|
{#if tracking}
|
|
222
|
-
<TimeChip
|
|
351
|
+
<TimeChip
|
|
352
|
+
minutes={minutesByTask[task.id] ?? 0}
|
|
353
|
+
estimate={estimates[task.id]}
|
|
354
|
+
running={timer?.taskId === task.id}
|
|
355
|
+
/>
|
|
223
356
|
{/if}
|
|
224
|
-
<span
|
|
357
|
+
<span
|
|
358
|
+
class="ml-auto rounded-full px-1.5 py-0.5 font-medium capitalize {priorityClass[
|
|
359
|
+
task.priority
|
|
360
|
+
]}"
|
|
361
|
+
>
|
|
225
362
|
{task.priority}
|
|
226
363
|
</span>
|
|
227
364
|
</div>
|
|
@@ -252,13 +389,21 @@
|
|
|
252
389
|
<div class="{listGrid} h-10 px-2 text-sm">
|
|
253
390
|
<span class="flex min-w-0 items-center gap-2.5">
|
|
254
391
|
{#key task.status}
|
|
255
|
-
<StatusDot
|
|
392
|
+
<StatusDot {statuses} status={task.status} />
|
|
256
393
|
{/key}
|
|
257
|
-
<span
|
|
394
|
+
<span
|
|
395
|
+
class="truncate"
|
|
396
|
+
class:text-muted-foreground={task.status === "done"}
|
|
397
|
+
class:line-through={task.status === "done"}
|
|
398
|
+
>
|
|
258
399
|
{task.title}
|
|
259
400
|
</span>
|
|
260
401
|
{#if tracking}
|
|
261
|
-
<TimeChip
|
|
402
|
+
<TimeChip
|
|
403
|
+
minutes={minutesByTask[task.id] ?? 0}
|
|
404
|
+
estimate={estimates[task.id]}
|
|
405
|
+
running={timer?.taskId === task.id}
|
|
406
|
+
/>
|
|
262
407
|
{/if}
|
|
263
408
|
</span>
|
|
264
409
|
<span class="flex min-w-0 items-center gap-2 text-muted-foreground max-sm:hidden">
|
|
@@ -266,11 +411,19 @@
|
|
|
266
411
|
<span class="truncate">{task.assignee}</span>
|
|
267
412
|
</span>
|
|
268
413
|
<span class="max-sm:hidden">
|
|
269
|
-
<span
|
|
414
|
+
<span
|
|
415
|
+
class="rounded-full px-1.5 py-0.5 text-xs font-medium capitalize {priorityClass[
|
|
416
|
+
task.priority
|
|
417
|
+
]}"
|
|
418
|
+
>
|
|
270
419
|
{task.priority}
|
|
271
420
|
</span>
|
|
272
421
|
</span>
|
|
273
|
-
<span
|
|
422
|
+
<span
|
|
423
|
+
class="text-right text-xs tabular-nums {d.late
|
|
424
|
+
? 'font-medium text-destructive'
|
|
425
|
+
: 'text-muted-foreground'}"
|
|
426
|
+
>
|
|
274
427
|
{d.label}
|
|
275
428
|
</span>
|
|
276
429
|
</div>
|
|
@@ -293,7 +446,7 @@
|
|
|
293
446
|
{onChange}
|
|
294
447
|
>
|
|
295
448
|
{#snippet renderLabel(task)}
|
|
296
|
-
<StatusDot
|
|
449
|
+
<StatusDot {statuses} status={task.status} />
|
|
297
450
|
<span class="min-w-0 flex-1 truncate">{task.title}</span>
|
|
298
451
|
{@render avatar(task.assignee)}
|
|
299
452
|
{/snippet}
|
|
@@ -316,7 +469,9 @@
|
|
|
316
469
|
{#if tracking}
|
|
317
470
|
<section class="flex flex-col gap-3 border-t border-border pt-4">
|
|
318
471
|
<div class="flex items-center justify-between gap-3">
|
|
319
|
-
<h3 class="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
|
|
472
|
+
<h3 class="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
|
|
473
|
+
Task time
|
|
474
|
+
</h3>
|
|
320
475
|
<select
|
|
321
476
|
bind:value={timeTaskId}
|
|
322
477
|
aria-label="Task"
|
|
@@ -350,7 +505,9 @@
|
|
|
350
505
|
{/if}
|
|
351
506
|
|
|
352
507
|
<section class="flex flex-col gap-2 border-t border-border pt-4">
|
|
353
|
-
<h3 class="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
|
|
508
|
+
<h3 class="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
|
|
509
|
+
Status badges
|
|
510
|
+
</h3>
|
|
354
511
|
<div class="flex flex-wrap items-center gap-2">
|
|
355
512
|
{#each salesStatuses.ids as id (id)}
|
|
356
513
|
<StatusBadge statuses={salesStatuses} status={id} />
|
|
@@ -370,7 +527,8 @@
|
|
|
370
527
|
<style>
|
|
371
528
|
/* Switching views: the new one rises in with a touch of blur, the old one is gone at once. */
|
|
372
529
|
.tasks-view {
|
|
373
|
-
animation: tasks-view-in var(--duration-fast, 250ms)
|
|
530
|
+
animation: tasks-view-in var(--duration-fast, 250ms)
|
|
531
|
+
var(--ease-smooth-out, cubic-bezier(0.22, 1, 0.36, 1)) backwards;
|
|
374
532
|
}
|
|
375
533
|
|
|
376
534
|
@keyframes tasks-view-in {
|
|
@@ -9,7 +9,15 @@
|
|
|
9
9
|
import type { TaskComment } from "./detail-types.js";
|
|
10
10
|
import type { TimeLogInput, TimeStopInfo } from "../time/time-types.js";
|
|
11
11
|
|
|
12
|
-
type Scenario =
|
|
12
|
+
type Scenario =
|
|
13
|
+
| "default"
|
|
14
|
+
| "long"
|
|
15
|
+
| "emptyDescription"
|
|
16
|
+
| "unassigned"
|
|
17
|
+
| "running"
|
|
18
|
+
| "busy"
|
|
19
|
+
| "closed"
|
|
20
|
+
| "loading";
|
|
13
21
|
|
|
14
22
|
const statuses = defineStatuses({
|
|
15
23
|
todo: { label: "To do", tone: "neutral", variant: "open" },
|
|
@@ -34,15 +42,35 @@
|
|
|
34
42
|
const stamp = (agoHours: number) => new Date(now - agoHours * hour).toISOString();
|
|
35
43
|
|
|
36
44
|
const seed: TaskComment[] = [
|
|
37
|
-
{
|
|
38
|
-
|
|
39
|
-
|
|
45
|
+
{
|
|
46
|
+
id: "c1",
|
|
47
|
+
author: "Ada Lovelace",
|
|
48
|
+
body: "Calls with Yoan: the format that sold the template was simple. A board on why, then the system, then the demo.",
|
|
49
|
+
createdAt: stamp(30),
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: "c2",
|
|
53
|
+
author: "Planner",
|
|
54
|
+
agent: true,
|
|
55
|
+
body: "Reused that shape for the outline. Three sections, the demo last, one call to action at the end.",
|
|
56
|
+
createdAt: stamp(26),
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: "c3",
|
|
60
|
+
author: "Bo Chen",
|
|
61
|
+
body: "Looks right. I'll record Thursday.",
|
|
62
|
+
createdAt: stamp(5),
|
|
63
|
+
edited: true,
|
|
64
|
+
},
|
|
40
65
|
];
|
|
41
66
|
const crowd: TaskComment[] = Array.from({ length: 24 }, (_, i) => ({
|
|
42
67
|
id: `b${i}`,
|
|
43
|
-
author: i % 4 === 1 ? "Planner" : people[i % people.length] ?? "Ada Lovelace",
|
|
68
|
+
author: i % 4 === 1 ? "Planner" : (people[i % people.length] ?? "Ada Lovelace"),
|
|
44
69
|
agent: i % 4 === 1,
|
|
45
|
-
body:
|
|
70
|
+
body:
|
|
71
|
+
i % 5 === 0
|
|
72
|
+
? "Pushed the second cut. The intro runs 40 seconds, so I trimmed the first example and kept the one with numbers."
|
|
73
|
+
: "Noted, moving on to the next step.",
|
|
46
74
|
createdAt: stamp(60 - i * 2),
|
|
47
75
|
}));
|
|
48
76
|
|
|
@@ -59,7 +87,13 @@
|
|
|
59
87
|
let done = $state(false);
|
|
60
88
|
let timer = $state<{ startedAt: number } | null>(null);
|
|
61
89
|
let entries = $state([
|
|
62
|
-
{
|
|
90
|
+
{
|
|
91
|
+
id: "e1",
|
|
92
|
+
minutes: 90,
|
|
93
|
+
day: new Date(now - 24 * hour).toISOString().slice(0, 10),
|
|
94
|
+
person: "Ada Lovelace",
|
|
95
|
+
note: "Outline",
|
|
96
|
+
},
|
|
63
97
|
]);
|
|
64
98
|
|
|
65
99
|
$effect(() => {
|
|
@@ -76,7 +110,16 @@
|
|
|
76
110
|
let statusLabel = $derived(statuses.label(status));
|
|
77
111
|
|
|
78
112
|
function onLog(input: TimeLogInput) {
|
|
79
|
-
entries = [
|
|
113
|
+
entries = [
|
|
114
|
+
{
|
|
115
|
+
id: `e${entries.length + 1}`,
|
|
116
|
+
minutes: input.minutes,
|
|
117
|
+
day: input.day,
|
|
118
|
+
person: "Ada Lovelace",
|
|
119
|
+
note: input.note ?? "",
|
|
120
|
+
},
|
|
121
|
+
...entries,
|
|
122
|
+
];
|
|
80
123
|
return true;
|
|
81
124
|
}
|
|
82
125
|
|
|
@@ -86,7 +129,15 @@
|
|
|
86
129
|
}
|
|
87
130
|
|
|
88
131
|
function onSend(body: string) {
|
|
89
|
-
thread = [
|
|
132
|
+
thread = [
|
|
133
|
+
...thread,
|
|
134
|
+
{
|
|
135
|
+
id: `n${thread.length}`,
|
|
136
|
+
author: "Ada Lovelace",
|
|
137
|
+
body,
|
|
138
|
+
createdAt: new Date().toISOString(),
|
|
139
|
+
},
|
|
140
|
+
];
|
|
90
141
|
}
|
|
91
142
|
</script>
|
|
92
143
|
|
|
@@ -112,7 +163,10 @@
|
|
|
112
163
|
</button>
|
|
113
164
|
</div>
|
|
114
165
|
|
|
115
|
-
<div
|
|
166
|
+
<div
|
|
167
|
+
class="mx-auto w-full overflow-hidden rounded-xl border border-border bg-background"
|
|
168
|
+
style:max-width={narrow ? "390px" : "none"}
|
|
169
|
+
>
|
|
116
170
|
<TaskDetail
|
|
117
171
|
{title}
|
|
118
172
|
onTitleChange={(next) => {
|
|
@@ -139,15 +193,21 @@
|
|
|
139
193
|
{/snippet}
|
|
140
194
|
{#snippet properties()}
|
|
141
195
|
<TaskProperty label="Status">
|
|
142
|
-
<TaskChip aria-label="Status: {statusLabel}"
|
|
196
|
+
<TaskChip aria-label="Status: {statusLabel}"
|
|
197
|
+
><StatusDot {statuses} {status} size={14} animate={false} />{statusLabel}</TaskChip
|
|
198
|
+
>
|
|
143
199
|
</TaskProperty>
|
|
144
200
|
<TaskProperty label="Priority">
|
|
145
|
-
<TaskChip><Flag weight="fill" class="text-destructive" aria-hidden="true" />High</TaskChip
|
|
201
|
+
<TaskChip><Flag weight="fill" class="text-destructive" aria-hidden="true" />High</TaskChip
|
|
202
|
+
>
|
|
146
203
|
</TaskProperty>
|
|
147
204
|
<TaskProperty label="Assignee">
|
|
148
205
|
{#if assignee}
|
|
149
206
|
<TaskChip>
|
|
150
|
-
<span
|
|
207
|
+
<span
|
|
208
|
+
class="grid size-4 place-items-center rounded-full bg-muted text-[0px]"
|
|
209
|
+
aria-hidden="true"><User /></span
|
|
210
|
+
>
|
|
151
211
|
{assignee}
|
|
152
212
|
</TaskChip>
|
|
153
213
|
{:else}
|
|
@@ -1,54 +1,54 @@
|
|
|
1
1
|
/** One entry in a task's thread. The host resolves the author's name. */
|
|
2
2
|
export type TaskComment = {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
3
|
+
id: string;
|
|
4
|
+
author: string;
|
|
5
|
+
body: string;
|
|
6
|
+
/** ISO timestamp. */
|
|
7
|
+
createdAt: string;
|
|
8
|
+
/** An agent wrote it: the thread draws the agent avatar and an "AI" label. */
|
|
9
|
+
agent?: boolean;
|
|
10
|
+
/** Set when the body changed after posting. */
|
|
11
|
+
edited?: boolean;
|
|
12
12
|
};
|
|
13
13
|
|
|
14
14
|
export type TaskDetailLabels = {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
15
|
+
markComplete: string;
|
|
16
|
+
markIncomplete: string;
|
|
17
|
+
editTitle: string;
|
|
18
|
+
description: string;
|
|
19
|
+
addDescription: string;
|
|
20
|
+
editDescription: string;
|
|
21
|
+
save: string;
|
|
22
|
+
saving: string;
|
|
23
|
+
cancel: string;
|
|
24
|
+
comments: string;
|
|
25
|
+
commentPlaceholder: string;
|
|
26
|
+
commentSend: string;
|
|
27
|
+
commentEdit: string;
|
|
28
|
+
commentDelete: string;
|
|
29
|
+
commentEdited: string;
|
|
30
|
+
commentsEmpty: string;
|
|
31
|
+
ai: string;
|
|
32
|
+
properties: string;
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
export const DEFAULT_TASK_DETAIL_LABELS: TaskDetailLabels = {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
36
|
+
markComplete: "Mark complete",
|
|
37
|
+
markIncomplete: "Mark incomplete",
|
|
38
|
+
editTitle: "Edit title",
|
|
39
|
+
description: "Description",
|
|
40
|
+
addDescription: "Add a description",
|
|
41
|
+
editDescription: "Edit description",
|
|
42
|
+
save: "Save",
|
|
43
|
+
saving: "Saving",
|
|
44
|
+
cancel: "Cancel",
|
|
45
|
+
comments: "Activity",
|
|
46
|
+
commentPlaceholder: "Leave a comment",
|
|
47
|
+
commentSend: "Comment",
|
|
48
|
+
commentEdit: "Edit comment",
|
|
49
|
+
commentDelete: "Delete comment",
|
|
50
|
+
commentEdited: "edited",
|
|
51
|
+
commentsEmpty: "No comments yet",
|
|
52
|
+
ai: "AI",
|
|
53
|
+
properties: "Properties",
|
|
54
54
|
};
|
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
import type { Snippet } from "svelte";
|
|
3
3
|
import { Circle, CheckCircle, PencilSimple } from "phosphor-svelte";
|
|
4
4
|
import { cn } from "../../lib/utils.js";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
DEFAULT_TASK_DETAIL_LABELS,
|
|
7
|
+
type TaskComment,
|
|
8
|
+
type TaskDetailLabels,
|
|
9
|
+
} from "./detail-types.js";
|
|
6
10
|
import TaskThread from "./task-thread.svelte";
|
|
7
11
|
|
|
8
12
|
interface Props {
|
|
@@ -119,7 +123,10 @@
|
|
|
119
123
|
onclick={onToggleDone}
|
|
120
124
|
disabled={!onToggleDone}
|
|
121
125
|
aria-label={done ? labels.markIncomplete : labels.markComplete}
|
|
122
|
-
class={cn(
|
|
126
|
+
class={cn(
|
|
127
|
+
"tk-icon mt-px",
|
|
128
|
+
done ? "text-success" : "text-muted-foreground/60 hover:text-foreground",
|
|
129
|
+
)}
|
|
123
130
|
>
|
|
124
131
|
{#if done}
|
|
125
132
|
<CheckCircle class="size-5" weight="fill" aria-hidden="true" />
|
|
@@ -139,7 +146,9 @@
|
|
|
139
146
|
class="-mx-2 -my-1 min-w-0 flex-1 resize-none rounded-md border border-input bg-transparent px-2 py-1 text-2xl leading-tight font-semibold tracking-tight outline-none focus-visible:ring-3 focus-visible:ring-ring/50"
|
|
140
147
|
></textarea>
|
|
141
148
|
{:else}
|
|
142
|
-
<h1
|
|
149
|
+
<h1
|
|
150
|
+
class="min-w-0 flex-1 text-2xl leading-tight font-semibold tracking-tight text-balance break-words"
|
|
151
|
+
>
|
|
143
152
|
<button
|
|
144
153
|
type="button"
|
|
145
154
|
onclick={startTitle}
|
|
@@ -153,14 +162,19 @@
|
|
|
153
162
|
>
|
|
154
163
|
{title}
|
|
155
164
|
{#if onTitleChange}
|
|
156
|
-
<PencilSimple
|
|
165
|
+
<PencilSimple
|
|
166
|
+
class="ms-1.5 inline size-3.5 align-middle text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100"
|
|
167
|
+
aria-hidden="true"
|
|
168
|
+
/>
|
|
157
169
|
{/if}
|
|
158
170
|
</button>
|
|
159
171
|
</h1>
|
|
160
172
|
{/if}
|
|
161
173
|
</div>
|
|
162
174
|
{#if meta}
|
|
163
|
-
<div
|
|
175
|
+
<div
|
|
176
|
+
class="mt-2 flex min-h-5 flex-wrap items-center gap-x-3 gap-y-1 ps-9 text-xs text-muted-foreground"
|
|
177
|
+
>
|
|
164
178
|
{@render meta()}
|
|
165
179
|
</div>
|
|
166
180
|
{/if}
|
|
@@ -171,10 +185,14 @@
|
|
|
171
185
|
class="px-4 pt-3 @3xl:col-start-2 @3xl:row-span-2 @3xl:row-start-1 @3xl:border-s @3xl:border-border @3xl:px-5 @3xl:pt-6"
|
|
172
186
|
aria-label={labels.properties}
|
|
173
187
|
>
|
|
174
|
-
<div
|
|
188
|
+
<div
|
|
189
|
+
class="flex flex-wrap items-center gap-1 @3xl:sticky @3xl:top-0 @3xl:flex-col @3xl:items-stretch @3xl:gap-0.5"
|
|
190
|
+
>
|
|
175
191
|
{@render properties?.()}
|
|
176
192
|
{#if railFooter}
|
|
177
|
-
<div class="mt-2 hidden w-full border-t border-border/60 pt-3 @3xl:block">
|
|
193
|
+
<div class="mt-2 hidden w-full border-t border-border/60 pt-3 @3xl:block">
|
|
194
|
+
{@render railFooter()}
|
|
195
|
+
</div>
|
|
178
196
|
{/if}
|
|
179
197
|
</div>
|
|
180
198
|
</aside>
|
|
@@ -185,7 +203,12 @@
|
|
|
185
203
|
<div class="flex h-7 items-center justify-between">
|
|
186
204
|
<h2 class="text-xs font-medium text-muted-foreground">{labels.description}</h2>
|
|
187
205
|
{#if !editingDescription && description && onDescriptionChange}
|
|
188
|
-
<button
|
|
206
|
+
<button
|
|
207
|
+
type="button"
|
|
208
|
+
class="tk-icon"
|
|
209
|
+
onclick={startDescription}
|
|
210
|
+
aria-label={labels.editDescription}
|
|
211
|
+
>
|
|
189
212
|
<PencilSimple class="size-3.5" aria-hidden="true" />
|
|
190
213
|
</button>
|
|
191
214
|
{/if}
|
|
@@ -200,8 +223,15 @@
|
|
|
200
223
|
class="w-full resize-y rounded-md border border-input bg-transparent px-3 py-2 text-sm leading-relaxed outline-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50"
|
|
201
224
|
></textarea>
|
|
202
225
|
<div class="mt-1 flex justify-end gap-1.5">
|
|
203
|
-
<button type="button" class="tk-button" onclick={() => (editingDescription = false)}
|
|
204
|
-
|
|
226
|
+
<button type="button" class="tk-button" onclick={() => (editingDescription = false)}
|
|
227
|
+
>{labels.cancel}</button
|
|
228
|
+
>
|
|
229
|
+
<button
|
|
230
|
+
type="button"
|
|
231
|
+
class="tk-button tk-primary"
|
|
232
|
+
onclick={saveDescription}
|
|
233
|
+
disabled={savingDescription}
|
|
234
|
+
>
|
|
205
235
|
{savingDescription ? labels.saving : labels.save}
|
|
206
236
|
</button>
|
|
207
237
|
</div>
|