@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
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
// =========================
|
|
3
|
-
// IMPORTS
|
|
4
|
-
// =========================
|
|
5
|
-
import type { Snippet } from "svelte";
|
|
6
|
-
import { cn } from "../../lib/utils.js";
|
|
7
|
-
import type { PhosphorIcon } from "../../lib/icon-types.js";
|
|
2
|
+
// =========================
|
|
3
|
+
// IMPORTS
|
|
4
|
+
// =========================
|
|
5
|
+
import type { Snippet } from "svelte";
|
|
6
|
+
import { cn } from "../../lib/utils.js";
|
|
7
|
+
import type { PhosphorIcon } from "../../lib/icon-types.js";
|
|
8
8
|
|
|
9
|
-
// =========================
|
|
10
|
-
// TYPES
|
|
11
|
-
// =========================
|
|
12
|
-
interface Props {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
9
|
+
// =========================
|
|
10
|
+
// TYPES
|
|
11
|
+
// =========================
|
|
12
|
+
interface Props {
|
|
13
|
+
// Not list-page's `EmptyState`: that one takes exactly one action, and a
|
|
14
|
+
// dashboard can be empty for reasons (nothing connected, nothing synced)
|
|
15
|
+
// that need two buttons.
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
17
|
+
// The dashed edge marks truly empty, not loading.
|
|
18
|
+
icon?: PhosphorIcon;
|
|
19
|
+
title: string;
|
|
20
|
+
description?: string;
|
|
21
|
+
/** One or two buttons. Omit where there is nothing the reader can do. */
|
|
22
|
+
actions?: Snippet;
|
|
23
|
+
class?: string;
|
|
24
|
+
}
|
|
25
25
|
|
|
26
|
-
// =========================
|
|
27
|
-
// PROPS
|
|
28
|
-
// =========================
|
|
29
|
-
let { icon: Icon, title, description, actions, class: className }: Props = $props();
|
|
26
|
+
// =========================
|
|
27
|
+
// PROPS
|
|
28
|
+
// =========================
|
|
29
|
+
let { icon: Icon, title, description, actions, class: className }: Props = $props();
|
|
30
30
|
</script>
|
|
31
31
|
|
|
32
32
|
<!-- =========================== -->
|
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
// =========================
|
|
3
|
-
// IMPORTS
|
|
4
|
-
// =========================
|
|
5
|
-
import { ArrowRight } from "phosphor-svelte";
|
|
6
|
-
import type { Snippet } from "svelte";
|
|
7
|
-
import { cn } from "../../lib/utils.js";
|
|
2
|
+
// =========================
|
|
3
|
+
// IMPORTS
|
|
4
|
+
// =========================
|
|
5
|
+
import { ArrowRight } from "phosphor-svelte";
|
|
6
|
+
import type { Snippet } from "svelte";
|
|
7
|
+
import { cn } from "../../lib/utils.js";
|
|
8
8
|
|
|
9
|
-
// =========================
|
|
10
|
-
// TYPES
|
|
11
|
-
// =========================
|
|
12
|
-
interface Props {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
9
|
+
// =========================
|
|
10
|
+
// TYPES
|
|
11
|
+
// =========================
|
|
12
|
+
interface Props {
|
|
13
|
+
title: string;
|
|
14
|
+
/** One line on the right: a window, a provenance, a count. Never a sentence. */
|
|
15
|
+
note?: string;
|
|
16
|
+
/** The page that owns this area, when one page does. */
|
|
17
|
+
href?: string;
|
|
18
|
+
/** The link's wording. Translated at the call site. */
|
|
19
|
+
openLabel?: string;
|
|
20
|
+
children: Snippet;
|
|
21
|
+
class?: string;
|
|
22
|
+
}
|
|
23
23
|
|
|
24
|
-
// =========================
|
|
25
|
-
// PROPS
|
|
26
|
-
// =========================
|
|
27
|
-
let { title, note, href, openLabel = "Open", children, class: className }: Props = $props();
|
|
24
|
+
// =========================
|
|
25
|
+
// PROPS
|
|
26
|
+
// =========================
|
|
27
|
+
let { title, note, href, openLabel = "Open", children, class: className }: Props = $props();
|
|
28
28
|
</script>
|
|
29
29
|
|
|
30
30
|
<!-- =========================== -->
|
|
@@ -1,56 +1,56 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
// =========================
|
|
3
|
-
// IMPORTS
|
|
4
|
-
// =========================
|
|
5
|
-
import type { Snippet } from "svelte";
|
|
6
|
-
import { cn } from "../../lib/utils.js";
|
|
7
|
-
import { panelHeaderClass, panelShellClass } from "../../lib/panel.js";
|
|
8
|
-
import { SectionLabel } from "../../components/
|
|
9
|
-
import type { PhosphorIcon } from "../../lib/icon-types.js";
|
|
2
|
+
// =========================
|
|
3
|
+
// IMPORTS
|
|
4
|
+
// =========================
|
|
5
|
+
import type { Snippet } from "svelte";
|
|
6
|
+
import { cn } from "../../lib/utils.js";
|
|
7
|
+
import { panelHeaderClass, panelShellClass } from "../../lib/panel.js";
|
|
8
|
+
import { SectionLabel } from "../../components/section-header/index.js";
|
|
9
|
+
import type { PhosphorIcon } from "../../lib/icon-types.js";
|
|
10
10
|
|
|
11
|
-
// =========================
|
|
12
|
-
// TYPES
|
|
13
|
-
// =========================
|
|
14
|
-
interface Props {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
11
|
+
// =========================
|
|
12
|
+
// TYPES
|
|
13
|
+
// =========================
|
|
14
|
+
interface Props {
|
|
15
|
+
/** What this section of the dashboard is. Drawn as the app's one panel label. */
|
|
16
|
+
label: string;
|
|
17
|
+
labelIcon?: PhosphorIcon;
|
|
18
|
+
/**
|
|
19
|
+
* A row count, total or freshness stamp. It's a prop, not an action,
|
|
20
|
+
* because hand-placed hints ended up at three type sizes on one screen.
|
|
21
|
+
*/
|
|
22
|
+
hint?: string;
|
|
23
|
+
/** Controls that act on this panel. Pinned right, after the hint. */
|
|
24
|
+
actions?: Snippet;
|
|
25
|
+
/** A line under the label, for the scope a number was measured over. */
|
|
26
|
+
sublabel?: string;
|
|
27
|
+
/** Off for a body that supplies its own padding: a table, a full-bleed list. */
|
|
28
|
+
pad?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* The body scrolls sideways rather than squeezing. For a wide table, which is
|
|
31
|
+
* every table on a dashboard once the window is narrower than its columns.
|
|
32
|
+
*/
|
|
33
|
+
scroll?: boolean;
|
|
34
|
+
children: Snippet;
|
|
35
|
+
class?: string;
|
|
36
|
+
bodyClass?: string;
|
|
37
|
+
}
|
|
38
38
|
|
|
39
|
-
// =========================
|
|
40
|
-
// PROPS
|
|
41
|
-
// =========================
|
|
42
|
-
let {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}: Props = $props();
|
|
39
|
+
// =========================
|
|
40
|
+
// PROPS
|
|
41
|
+
// =========================
|
|
42
|
+
let {
|
|
43
|
+
label,
|
|
44
|
+
labelIcon,
|
|
45
|
+
hint,
|
|
46
|
+
actions,
|
|
47
|
+
sublabel,
|
|
48
|
+
pad = true,
|
|
49
|
+
scroll = false,
|
|
50
|
+
children,
|
|
51
|
+
class: className,
|
|
52
|
+
bodyClass,
|
|
53
|
+
}: Props = $props();
|
|
54
54
|
</script>
|
|
55
55
|
|
|
56
56
|
<!-- =========================== -->
|
|
@@ -1,68 +1,68 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
/*
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
/*
|
|
3
|
+
* A column head that sorts the table under it. Sort buttons above a table
|
|
4
|
+
* never say which column they rank, and read as filter tabs.
|
|
5
|
+
*/
|
|
6
6
|
|
|
7
|
-
// Every sortable head shows its caret, at 40%, solid on the active column.
|
|
8
|
-
// Hover-only makes people hunt, and it shifts the label under the pointer.
|
|
7
|
+
// Every sortable head shows its caret, at 40%, solid on the active column.
|
|
8
|
+
// Hover-only makes people hunt, and it shifts the label under the pointer.
|
|
9
9
|
|
|
10
|
-
// No padding of its own: it comes from the skin classes, so heads and cells
|
|
11
|
-
// stay in line when a dense table tightens both.
|
|
10
|
+
// No padding of its own: it comes from the skin classes, so heads and cells
|
|
11
|
+
// stay in line when a dense table tightens both.
|
|
12
12
|
|
|
13
|
-
// =========================
|
|
14
|
-
// IMPORTS
|
|
15
|
-
// =========================
|
|
16
|
-
import type { Snippet } from "svelte";
|
|
17
|
-
import { CaretDown, CaretUp } from "phosphor-svelte";
|
|
18
|
-
import { cn } from "../../lib/utils.js";
|
|
19
|
-
import { dataThClass, dataThNumClass } from "./data-table.js";
|
|
13
|
+
// =========================
|
|
14
|
+
// IMPORTS
|
|
15
|
+
// =========================
|
|
16
|
+
import type { Snippet } from "svelte";
|
|
17
|
+
import { CaretDown, CaretUp } from "phosphor-svelte";
|
|
18
|
+
import { cn } from "../../lib/utils.js";
|
|
19
|
+
import { dataThClass, dataThNumClass } from "./data-table.js";
|
|
20
20
|
|
|
21
|
-
// =========================
|
|
22
|
-
// TYPES
|
|
23
|
-
// =========================
|
|
24
|
-
interface Props {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
21
|
+
// =========================
|
|
22
|
+
// TYPES
|
|
23
|
+
// =========================
|
|
24
|
+
interface Props {
|
|
25
|
+
/** True when the table is currently ranked by this column. */
|
|
26
|
+
active: boolean;
|
|
27
|
+
/** Which way the active column runs. Ignored while inactive. */
|
|
28
|
+
descending: boolean;
|
|
29
|
+
/** Called on click and on Enter/Space. Toggling direction is the caller's. */
|
|
30
|
+
onSort: () => void;
|
|
31
|
+
/** Numbers right-align to their digits, so their caret leads the label. */
|
|
32
|
+
numeric?: boolean;
|
|
33
|
+
/** The long form of an abbreviated head, as the browser tooltip. */
|
|
34
|
+
title?: string;
|
|
35
|
+
class?: string;
|
|
36
|
+
children: Snippet;
|
|
37
|
+
}
|
|
38
38
|
|
|
39
|
-
// =========================
|
|
40
|
-
// PROPS
|
|
41
|
-
// =========================
|
|
42
|
-
let {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}: Props = $props();
|
|
39
|
+
// =========================
|
|
40
|
+
// PROPS
|
|
41
|
+
// =========================
|
|
42
|
+
let {
|
|
43
|
+
active,
|
|
44
|
+
descending,
|
|
45
|
+
onSort,
|
|
46
|
+
numeric = false,
|
|
47
|
+
title,
|
|
48
|
+
class: className,
|
|
49
|
+
children,
|
|
50
|
+
}: Props = $props();
|
|
51
51
|
|
|
52
|
-
// =========================
|
|
53
|
-
// DERIVED
|
|
54
|
-
// =========================
|
|
55
|
-
const ariaSort = $derived(active ? (descending ? "descending" : "ascending") : "none");
|
|
52
|
+
// =========================
|
|
53
|
+
// DERIVED
|
|
54
|
+
// =========================
|
|
55
|
+
const ariaSort = $derived(active ? (descending ? "descending" : "ascending") : "none");
|
|
56
56
|
|
|
57
|
-
// =========================
|
|
58
|
-
// FUNCTIONS
|
|
59
|
-
// =========================
|
|
60
|
-
function handleKeydown(event: KeyboardEvent) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
57
|
+
// =========================
|
|
58
|
+
// FUNCTIONS
|
|
59
|
+
// =========================
|
|
60
|
+
function handleKeydown(event: KeyboardEvent) {
|
|
61
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
62
|
+
event.preventDefault();
|
|
63
|
+
onSort();
|
|
64
|
+
}
|
|
64
65
|
}
|
|
65
|
-
}
|
|
66
66
|
</script>
|
|
67
67
|
|
|
68
68
|
<!-- =========================== -->
|
|
@@ -1,159 +1,159 @@
|
|
|
1
1
|
<script lang="ts" module>
|
|
2
|
-
import type { Snippet } from "svelte";
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
3
|
|
|
4
|
-
/** Narrow screens drop the columns that only add detail. */
|
|
5
|
-
export type DataColumnBreakpoint = "sm" | "md" | "lg";
|
|
4
|
+
/** Narrow screens drop the columns that only add detail. */
|
|
5
|
+
export type DataColumnBreakpoint = "sm" | "md" | "lg";
|
|
6
6
|
|
|
7
|
-
/** One column after the lead. Give it `value`, `rating` or a `cell` snippet. */
|
|
8
|
-
export type DataColumn<T> = {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
};
|
|
7
|
+
/** One column after the lead. Give it `value`, `rating` or a `cell` snippet. */
|
|
8
|
+
export type DataColumn<T> = {
|
|
9
|
+
key: string;
|
|
10
|
+
label: string;
|
|
11
|
+
/** The long form of the head, as its tooltip. */
|
|
12
|
+
hint?: string;
|
|
13
|
+
/** A Tailwind width class. Fixed widths are what keep the lead column wide. */
|
|
14
|
+
width: string;
|
|
15
|
+
/** Figures run to the end, so digits line up. Text, pills and bars start. */
|
|
16
|
+
align?: "start" | "end";
|
|
17
|
+
/** Makes the head rank the table. Higher is better; a new column starts descending. */
|
|
18
|
+
sort?: (row: T) => number;
|
|
19
|
+
/** Null draws the table's empty label, muted. */
|
|
20
|
+
value?: (row: T) => string | null;
|
|
21
|
+
rating?: (row: T) => { grade: string; hint?: string } | null;
|
|
22
|
+
cell?: Snippet<[T]>;
|
|
23
|
+
/** 0 to 1, a share-of-max track drawn before the value. */
|
|
24
|
+
bar?: (row: T) => number;
|
|
25
|
+
/** Cell tooltip. */
|
|
26
|
+
title?: (row: T) => string | undefined;
|
|
27
|
+
muted?: boolean | ((row: T) => boolean);
|
|
28
|
+
/** A loss, an overrun: the value turns the destructive colour. */
|
|
29
|
+
negative?: (row: T) => boolean;
|
|
30
|
+
/** The column the eye lands on first. */
|
|
31
|
+
strong?: boolean;
|
|
32
|
+
/** A hairline before this column, opening a group. */
|
|
33
|
+
rule?: boolean;
|
|
34
|
+
/** Hidden under this breakpoint. */
|
|
35
|
+
hideBelow?: DataColumnBreakpoint;
|
|
36
|
+
};
|
|
37
37
|
</script>
|
|
38
38
|
|
|
39
39
|
<script lang="ts" generics="T">
|
|
40
|
-
/*
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
import { cn } from "../../lib/utils.js";
|
|
45
|
-
import DataSortHead from "./data-sort-head.svelte";
|
|
46
|
-
import RatingChip from "./rating-chip.svelte";
|
|
47
|
-
import { Pagination, paginateRows, totalPages } from "../../components/data-table/index.js";
|
|
48
|
-
import {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
} from "./data-table.js";
|
|
40
|
+
/*
|
|
41
|
+
* The one data table: wide lead cell, fixed figure columns, sortable heads,
|
|
42
|
+
* optional pager. A row opens by `rowHref` or `onRowClick`, stretched over the row from the lead.
|
|
43
|
+
*/
|
|
44
|
+
import { cn } from "../../lib/utils.js";
|
|
45
|
+
import DataSortHead from "./data-sort-head.svelte";
|
|
46
|
+
import RatingChip from "./rating-chip.svelte";
|
|
47
|
+
import { Pagination, paginateRows, totalPages } from "../../components/data-table/index.js";
|
|
48
|
+
import {
|
|
49
|
+
dataTableClass,
|
|
50
|
+
dataTdClass,
|
|
51
|
+
dataTdNumClass,
|
|
52
|
+
dataThClass,
|
|
53
|
+
dataThNumClass,
|
|
54
|
+
dataTheadClass,
|
|
55
|
+
dataTrClass,
|
|
56
|
+
} from "./data-table.js";
|
|
57
57
|
|
|
58
|
-
interface Props {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
58
|
+
interface Props {
|
|
59
|
+
rows: T[];
|
|
60
|
+
columns: DataColumn<T>[];
|
|
61
|
+
rowKey: (row: T) => string;
|
|
62
|
+
leadLabel: string;
|
|
63
|
+
lead: Snippet<[T]>;
|
|
64
|
+
/** Drawn where a value or rating is null. */
|
|
65
|
+
emptyLabel: string;
|
|
66
|
+
/** A Tailwind width class. Omit and the lead takes whatever the figures leave. */
|
|
67
|
+
leadWidth?: string;
|
|
68
|
+
/** A Tailwind min-width class, past which the panel scrolls sideways. */
|
|
69
|
+
minWidth?: string;
|
|
70
|
+
/** Omit for every row on one page. */
|
|
71
|
+
pageSize?: number;
|
|
72
|
+
sortKey?: string | null;
|
|
73
|
+
descending?: boolean;
|
|
74
|
+
page?: number;
|
|
75
|
+
/** The row opens a page. The lead becomes the link. */
|
|
76
|
+
rowHref?: (row: T) => string;
|
|
77
|
+
/** The row opens in place: a panel, a detail view. The lead becomes the button. */
|
|
78
|
+
onRowClick?: (row: T) => void;
|
|
79
|
+
/** Placeholder rows while the data is on its way. */
|
|
80
|
+
loading?: boolean;
|
|
81
|
+
/** Drawn in place of the body when there are no rows. */
|
|
82
|
+
empty?: Snippet;
|
|
83
|
+
}
|
|
84
84
|
|
|
85
|
-
let {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}: Props = $props();
|
|
85
|
+
let {
|
|
86
|
+
rows,
|
|
87
|
+
columns,
|
|
88
|
+
rowKey,
|
|
89
|
+
leadLabel,
|
|
90
|
+
lead,
|
|
91
|
+
emptyLabel,
|
|
92
|
+
leadWidth,
|
|
93
|
+
minWidth = "min-w-[48rem]",
|
|
94
|
+
pageSize,
|
|
95
|
+
sortKey = $bindable(null),
|
|
96
|
+
descending = $bindable(true),
|
|
97
|
+
page = $bindable(1),
|
|
98
|
+
rowHref,
|
|
99
|
+
onRowClick,
|
|
100
|
+
loading = false,
|
|
101
|
+
empty,
|
|
102
|
+
}: Props = $props();
|
|
103
103
|
|
|
104
|
-
const pad = "px-3";
|
|
105
|
-
const LOADING_ROWS = 5;
|
|
104
|
+
const pad = "px-3";
|
|
105
|
+
const LOADING_ROWS = 5;
|
|
106
106
|
|
|
107
|
-
// Literal classes, so Tailwind sees each one.
|
|
108
|
-
const HIDE_BELOW: Record<DataColumnBreakpoint, string> = {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
};
|
|
107
|
+
// Literal classes, so Tailwind sees each one.
|
|
108
|
+
const HIDE_BELOW: Record<DataColumnBreakpoint, string> = {
|
|
109
|
+
sm: "hidden sm:table-cell",
|
|
110
|
+
md: "hidden md:table-cell",
|
|
111
|
+
lg: "hidden lg:table-cell",
|
|
112
|
+
};
|
|
113
113
|
|
|
114
|
-
// The ::after covers the whole row, so any cell opens it and the lead stays the one tab stop.
|
|
115
|
-
const stretch =
|
|
116
|
-
|
|
114
|
+
// The ::after covers the whole row, so any cell opens it and the lead stays the one tab stop.
|
|
115
|
+
const stretch =
|
|
116
|
+
"text-left outline-none after:absolute after:inset-0 after:content-[''] focus-visible:after:ring-2 focus-visible:after:ring-inset focus-visible:after:ring-ring";
|
|
117
117
|
|
|
118
|
-
const sorted = $derived.by(() => {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
});
|
|
118
|
+
const sorted = $derived.by(() => {
|
|
119
|
+
const by = columns.find((column) => column.key === sortKey)?.sort;
|
|
120
|
+
if (!by) return rows;
|
|
121
|
+
const direction = descending ? -1 : 1;
|
|
122
|
+
return [...rows].sort((left, right) => (by(left) - by(right)) * direction);
|
|
123
|
+
});
|
|
124
124
|
|
|
125
|
-
const visible = $derived(pageSize ? paginateRows(sorted, page, pageSize) : sorted);
|
|
126
|
-
const opens = $derived(Boolean(rowHref || onRowClick));
|
|
125
|
+
const visible = $derived(pageSize ? paginateRows(sorted, page, pageSize) : sorted);
|
|
126
|
+
const opens = $derived(Boolean(rowHref || onRowClick));
|
|
127
127
|
|
|
128
|
-
// Fewer rows than the page you stand on would draw an empty table.
|
|
129
|
-
$effect(() => {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
});
|
|
128
|
+
// Fewer rows than the page you stand on would draw an empty table.
|
|
129
|
+
$effect(() => {
|
|
130
|
+
if (!pageSize) return;
|
|
131
|
+
const last = totalPages(sorted.length, pageSize);
|
|
132
|
+
if (page > last) page = last;
|
|
133
|
+
});
|
|
134
134
|
|
|
135
|
-
function rankBy(key: string) {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
135
|
+
function rankBy(key: string) {
|
|
136
|
+
page = 1;
|
|
137
|
+
if (sortKey === key) {
|
|
138
|
+
descending = !descending;
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
sortKey = key;
|
|
142
|
+
descending = true;
|
|
140
143
|
}
|
|
141
|
-
sortKey = key;
|
|
142
|
-
descending = true;
|
|
143
|
-
}
|
|
144
144
|
|
|
145
|
-
function isMuted(column: DataColumn<T>, row: T) {
|
|
146
|
-
|
|
147
|
-
}
|
|
145
|
+
function isMuted(column: DataColumn<T>, row: T) {
|
|
146
|
+
return typeof column.muted === "function" ? column.muted(row) : Boolean(column.muted);
|
|
147
|
+
}
|
|
148
148
|
|
|
149
|
-
function columnClass(column: DataColumn<T>) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
149
|
+
function columnClass(column: DataColumn<T>) {
|
|
150
|
+
return cn(
|
|
151
|
+
pad,
|
|
152
|
+
column.align === "start" && "text-left",
|
|
153
|
+
column.rule && "border-l border-border",
|
|
154
|
+
column.hideBelow && HIDE_BELOW[column.hideBelow],
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
157
|
</script>
|
|
158
158
|
|
|
159
159
|
<table class={cn(dataTableClass, minWidth, "table-fixed")}>
|