@heyramzi/ui 1.54.2 → 2.0.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/COMPONENTS.md +3 -2
- package/README.md +34 -9
- package/package.json +198 -6
- package/src/ai/generation-progress/GenerationProgress.svelte +12 -12
- package/src/ambient.d.ts +8 -0
- package/src/brand/brand.test.ts +67 -0
- package/src/brand/index.ts +137 -0
- package/src/canvas/README.md +236 -0
- package/src/canvas/card/card-frame.svelte +61 -0
- package/src/canvas/card/card.css +39 -0
- package/src/canvas/card/resize-handles.svelte +119 -0
- package/src/canvas/card/resize.ts +33 -0
- package/src/canvas/chrome/chrome-zoom.svelte +120 -0
- package/src/canvas/chrome/chrome.css +231 -0
- package/src/canvas/chrome/lock-badge.svelte +18 -0
- package/src/canvas/chrome/side-handles.svelte +30 -0
- package/src/canvas/chrome/size-chip.svelte +45 -0
- package/src/canvas/chrome/snap-guides.svelte +69 -0
- package/src/canvas/components/icons/ToolIcon.svelte +30 -0
- package/src/canvas/components/shared/svg/PreviewSvg.svelte +67 -0
- package/src/canvas/components/shared/svg/ShapeOutline.svelte +76 -0
- package/src/canvas/components/shared/svg/StrokeNode.svelte +69 -0
- package/src/canvas/components/shared/svg/TextRule.svelte +37 -0
- package/src/canvas/edges/bend-handle.svelte +76 -0
- package/src/canvas/edges/edge-gradient.svelte +30 -0
- package/src/canvas/edges/edge-path.test.ts +58 -0
- package/src/canvas/edges/edge-path.ts +293 -0
- package/src/canvas/edges/gradient-edge.svelte +43 -0
- package/src/canvas/editor/context-menu.test.ts +65 -0
- package/src/canvas/editor/context-menu.ts +48 -0
- package/src/canvas/editor/dispatch.svelte.test.ts +243 -0
- package/src/canvas/editor/dispatch.svelte.ts +205 -0
- package/src/canvas/editor/editor-context.ts +62 -0
- package/src/canvas/editor/editor-mode.ts +67 -0
- package/src/canvas/editor/frame.ts +98 -0
- package/src/canvas/editor/hand-context.ts +15 -0
- package/src/canvas/editor/history-core.test.ts +239 -0
- package/src/canvas/editor/history-core.ts +247 -0
- package/src/canvas/editor/keymap.test.ts +161 -0
- package/src/canvas/editor/keymap.ts +151 -0
- package/src/canvas/editor/layout-actions.test.ts +156 -0
- package/src/canvas/editor/layout-actions.ts +219 -0
- package/src/canvas/editor/lock.test.ts +68 -0
- package/src/canvas/editor/lock.ts +87 -0
- package/src/canvas/editor/rebase.test.ts +208 -0
- package/src/canvas/editor/rebase.ts +272 -0
- package/src/canvas/editor/style.ts +184 -0
- package/src/canvas/editor/text-field-context.ts +41 -0
- package/src/canvas/editor/z-order.test.ts +75 -0
- package/src/canvas/editor/z-order.ts +87 -0
- package/src/canvas/headless/alignment.test.ts +59 -0
- package/src/canvas/headless/alignment.ts +23 -0
- package/src/canvas/headless/break-apart-find.ts +418 -0
- package/src/canvas/headless/break-apart-pieces.ts +104 -0
- package/src/canvas/headless/break-apart-plan.ts +439 -0
- package/src/canvas/headless/break-apart-style.ts +106 -0
- package/src/canvas/headless/break-apart.ts +244 -0
- package/src/canvas/headless/canvas-cleanup.test.ts +181 -0
- package/src/canvas/headless/canvas-cleanup.ts +102 -0
- package/src/canvas/headless/edge-anchors.test.ts +70 -0
- package/src/canvas/headless/edge-anchors.ts +143 -0
- package/src/canvas/headless/edge-memo.test.ts +58 -0
- package/src/canvas/headless/edge-memo.ts +32 -0
- package/src/canvas/headless/edge-serialization.test.ts +55 -0
- package/src/canvas/headless/edge-serialization.ts +32 -0
- package/src/canvas/headless/figure-geometry.ts +293 -0
- package/src/canvas/headless/fit-viewport.test.ts +85 -0
- package/src/canvas/headless/fit-viewport.ts +137 -0
- package/src/canvas/headless/grid.test.ts +34 -0
- package/src/canvas/headless/grid.ts +94 -0
- package/src/canvas/headless/icon-node.test.ts +23 -0
- package/src/canvas/headless/icon-node.ts +66 -0
- package/src/canvas/headless/index.ts +9 -0
- package/src/canvas/headless/linkify.test.ts +23 -0
- package/src/canvas/headless/linkify.ts +25 -0
- package/src/canvas/headless/pen-marks.ts +133 -0
- package/src/canvas/headless/sketch.test.ts +99 -0
- package/src/canvas/headless/sketch.ts +302 -0
- package/src/canvas/headless/snap-guides.test.ts +61 -0
- package/src/canvas/headless/snap-guides.ts +146 -0
- package/src/canvas/headless/svg-figure.test.ts +49 -0
- package/src/canvas/headless/svg-figure.ts +176 -0
- package/src/canvas/headless/table-layout.test.ts +158 -0
- package/src/canvas/headless/table-layout.ts +309 -0
- package/src/canvas/index.ts +35 -0
- package/src/canvas/lod/lod-mode.svelte.ts +30 -0
- package/src/canvas/lod/lod-switch.svelte +140 -0
- package/src/canvas/lod/render-all.svelte.ts +52 -0
- package/src/canvas/ops/arrange.ts +108 -0
- package/src/canvas/ops/ops.test.ts +98 -0
- package/src/canvas/ops/ops.ts +347 -0
- package/src/canvas/pen/PenField.svelte +128 -0
- package/src/canvas/pen/PenField.test.ts +87 -0
- package/src/canvas/pen/PenOverlay.svelte +172 -0
- package/src/canvas/pen/ShapeNode.svelte +64 -0
- package/src/canvas/pen/TextNode.svelte +97 -0
- package/src/canvas/pen/colors.ts +28 -0
- package/src/canvas/pen/eraser.ts +46 -0
- package/src/canvas/pen/geometry.ts +148 -0
- package/src/canvas/pen/host-field.test.svelte +13 -0
- package/src/canvas/pen/index.ts +40 -0
- package/src/canvas/pen/ops.ts +16 -0
- package/src/canvas/pen/pen-session.ts +177 -0
- package/src/canvas/pen/pen.css +149 -0
- package/src/canvas/pen/plugin.ts +139 -0
- package/src/canvas/pen/shapes.ts +104 -0
- package/src/canvas/pen/stroke-path.ts +54 -0
- package/src/canvas/pen/types.ts +96 -0
- package/src/canvas/pen/ui.ts +26 -0
- package/src/canvas/plugin.test.ts +45 -0
- package/src/canvas/plugin.ts +159 -0
- package/src/canvas/screen/GlyphIcon.svelte +25 -0
- package/src/canvas/screen/PartView.svelte +176 -0
- package/src/canvas/screen/ScreenBody.svelte +142 -0
- package/src/canvas/screen/ScreenCard.svelte +32 -0
- package/src/canvas/screen/glyphs/button.svg +1 -0
- package/src/canvas/screen/glyphs/close.svg +1 -0
- package/src/canvas/screen/glyphs/down.svg +1 -0
- package/src/canvas/screen/glyphs/header.svg +1 -0
- package/src/canvas/screen/glyphs/hills.svg +1 -0
- package/src/canvas/screen/glyphs/image.svg +1 -0
- package/src/canvas/screen/glyphs/input.svg +1 -0
- package/src/canvas/screen/glyphs/list.svg +1 -0
- package/src/canvas/screen/glyphs/modal.svg +1 -0
- package/src/canvas/screen/glyphs/plus.svg +1 -0
- package/src/canvas/screen/glyphs/up.svg +1 -0
- package/src/canvas/screen/glyphs.ts +40 -0
- package/src/canvas/screen/labels.ts +41 -0
- package/src/canvas/screen/parts.ts +164 -0
- package/src/canvas/screen/plugin.ts +67 -0
- package/src/canvas/screen/screen.css +593 -0
- package/src/canvas/screen/types.ts +47 -0
- package/src/canvas/screen/ui.ts +13 -0
- package/src/canvas/test-utils.ts +18 -0
- package/src/canvas/types.ts +53 -0
- package/src/canvas/ui/CanvasToolbar.svelte +169 -0
- package/src/canvas/ui/FrameLayer.svelte +116 -0
- package/src/canvas/ui/PenLayer.svelte +39 -0
- package/src/canvas/ui/StylePanel.svelte +268 -0
- package/src/canvas/ui/canvas-grid.svelte +156 -0
- package/src/canvas/ui/canvas-ui.css +350 -0
- package/src/canvas/ui/forward-wheel.ts +29 -0
- package/src/canvas/ui/icons.ts +124 -0
- package/src/canvas/ui/place-panel.ts +80 -0
- package/src/canvas/ui/shortcut-tip.test.ts +16 -0
- package/src/canvas/ui/shortcut-tip.ts +17 -0
- package/src/canvas/ui/tools.ts +146 -0
- package/src/charts/README.md +104 -0
- package/src/charts/ambient.d.ts +4 -0
- package/src/charts/animated-value.css +7 -0
- package/src/charts/animated-value.svelte +110 -0
- package/src/charts/area-chart.css +29 -0
- package/src/charts/area-chart.svelte +204 -0
- package/src/charts/bar-chart.css +119 -0
- package/src/charts/bar-chart.svelte +275 -0
- package/src/charts/charts.css +201 -0
- package/src/charts/crosshair.svelte +35 -0
- package/src/charts/dashboard/chart.ts +5 -0
- package/src/charts/dashboard/dashboard-empty.svelte +55 -0
- package/src/charts/dashboard/dashboard-section.svelte +58 -0
- package/src/charts/dashboard/data-panel.svelte +81 -0
- package/src/charts/dashboard/data-sort-head.svelte +102 -0
- package/src/charts/dashboard/data-table.svelte +278 -0
- package/src/charts/dashboard/data-table.ts +26 -0
- package/src/charts/dashboard/index.ts +25 -0
- package/src/charts/dashboard/panel-grid.svelte +43 -0
- package/src/charts/dashboard/period-filter.svelte +53 -0
- package/src/charts/dashboard/rating-chip.svelte +35 -0
- package/src/charts/dashboard/stat-band.svelte +47 -0
- package/src/charts/dashboard/stat-tile.svelte +176 -0
- package/src/charts/dashboard/windows.ts +8 -0
- package/src/charts/donut-chart.css +56 -0
- package/src/charts/donut-chart.svelte +158 -0
- package/src/charts/edge-fade.svelte +43 -0
- package/src/charts/edge-fade.ts +16 -0
- package/src/charts/figure.css +100 -0
- package/src/charts/figure.svelte +122 -0
- package/src/charts/gauge-chart.css +94 -0
- package/src/charts/gauge-chart.svelte +302 -0
- package/src/charts/hover-band.test.ts +30 -0
- package/src/charts/hover-band.ts +21 -0
- package/src/charts/hover-focus.svelte +85 -0
- package/src/charts/index.ts +31 -0
- package/src/charts/legend.css +136 -0
- package/src/charts/legend.svelte +112 -0
- package/src/charts/line-chart.css +26 -0
- package/src/charts/line-chart.svelte +256 -0
- package/src/charts/motion.ts +19 -0
- package/src/charts/number-chart.css +179 -0
- package/src/charts/number-chart.svelte +187 -0
- package/src/charts/primitives/chart-container.svelte +57 -0
- package/src/charts/primitives/chart-style.svelte +36 -0
- package/src/charts/primitives/chart-tooltip.svelte +161 -0
- package/src/charts/primitives/chart-utils.ts +54 -0
- package/src/charts/primitives/index.ts +11 -0
- package/src/charts/reference-line.css +18 -0
- package/src/charts/reference-line.svelte +31 -0
- package/src/charts/reveal.svelte +61 -0
- package/src/charts/ring-chart.css +104 -0
- package/src/charts/ring-chart.svelte +166 -0
- package/src/charts/sparkline.css +45 -0
- package/src/charts/sparkline.svelte +141 -0
- package/src/charts/stat-card.css +105 -0
- package/src/charts/stat-card.svelte +267 -0
- package/src/charts/time-series-chart.css +28 -0
- package/src/charts/time-series-chart.svelte +179 -0
- package/src/charts/trend-pill.css +38 -0
- package/src/charts/trend-pill.svelte +48 -0
- package/src/components/copy/copy-button.svelte +1 -1
- package/src/components/docs/doc-page.svelte +1 -1
- package/src/components/docs/on-this-page.svelte +2 -2
- package/src/components/list-page/empty-state.svelte +1 -1
- package/src/components/list-page/filter-popover.svelte +1 -1
- package/src/components/list-page/section-label.svelte +1 -1
- package/src/components/segmented/segment.svelte +4 -4
- package/src/components/theme/theme-provider.svelte +6 -4
- package/src/components/toolbar/index.ts +5 -0
- package/src/components/toolbar/toolbar.svelte +168 -0
- package/src/components/toolbar/toolbar.test.ts +66 -0
- package/src/editor/README.md +58 -0
- package/src/editor/ambient.d.ts +1 -0
- package/src/editor/block-id.ts +77 -0
- package/src/editor/block-ops.test.ts +237 -0
- package/src/editor/block-ops.ts +157 -0
- package/src/editor/content.css +418 -0
- package/src/editor/editor-toolbar.svelte +303 -0
- package/src/editor/editor.svelte +462 -0
- package/src/editor/extensions.ts +145 -0
- package/src/editor/image-toolbar.svelte +123 -0
- package/src/editor/index.ts +17 -0
- package/src/editor/inline-editor.svelte +261 -0
- package/src/editor/markdown-escaping.test.ts +158 -0
- package/src/editor/markdown-marks.test.ts +89 -0
- package/src/editor/markdown-test-helpers.ts +13 -0
- package/src/editor/markdown-youtube.test.ts +93 -0
- package/src/editor/markdown.test.ts +250 -0
- package/src/editor/markdown.ts +511 -0
- package/src/editor/renderer.svelte +92 -0
- package/src/editor/serializer.test.ts +133 -0
- package/src/editor/serializer.ts +370 -0
- package/src/editor/slash-items.ts +115 -0
- package/src/editor/slash-menu.svelte +159 -0
- package/src/editor/youtube-url.ts +35 -0
- package/src/effects/interactive-hover-button/InteractiveHoverButton.svelte +13 -13
- package/src/lib/result.ts +19 -0
- package/src/onboarding/README.md +120 -0
- package/src/onboarding/define-tours.test.ts +50 -0
- package/src/onboarding/define-tours.ts +31 -0
- package/src/onboarding/demo.svelte +86 -0
- package/src/onboarding/index.ts +12 -0
- package/src/onboarding/onboarding-provider.svelte +120 -0
- package/src/onboarding/onboarding.svelte.ts +24 -0
- package/src/onboarding/pick.test.ts +79 -0
- package/src/onboarding/pick.ts +36 -0
- package/src/onboarding/stores.test.ts +103 -0
- package/src/onboarding/stores.ts +58 -0
- package/src/onboarding/tour-card.svelte +70 -0
- package/src/onboarding/tour-runner.svelte +197 -0
- package/src/onboarding/types.ts +34 -0
- package/src/onboarding/wait.ts +29 -0
- package/src/shadcn/command/command-input.svelte +1 -1
- package/src/slides/Controls.svelte +138 -0
- package/src/slides/Deck.svelte +271 -0
- package/src/slides/Fragment.svelte +71 -0
- package/src/slides/Overview.svelte +113 -0
- package/src/slides/Presenter.svelte +292 -0
- package/src/slides/README.md +89 -0
- package/src/slides/Slide.svelte +179 -0
- package/src/slides/SlideList.svelte +19 -0
- package/src/slides/ambient.d.ts +1 -0
- package/src/slides/bridges.ts +69 -0
- package/src/slides/deck-controller.svelte.ts +292 -0
- package/src/slides/demo-slides.svelte +358 -0
- package/src/slides/demo.svelte +176 -0
- package/src/slides/export/capture.ts +113 -0
- package/src/slides/export/ffmpeg.ts +120 -0
- package/src/slides/export/index.ts +9 -0
- package/src/slides/export/launch.ts +10 -0
- package/src/slides/export/pdf.ts +152 -0
- package/src/slides/export/types.ts +48 -0
- package/src/slides/index.ts +19 -0
- package/src/slides/labels.ts +48 -0
- package/src/slides/layout.ts +51 -0
- package/src/slides/model.ts +47 -0
- package/src/slides/navigation.ts +100 -0
- package/src/slides/theme.css +205 -0
- package/src/slides/types.ts +86 -0
- package/src/tasks/README.md +312 -0
- package/src/tasks/ambient.d.ts +3 -0
- package/src/tasks/board-order.ts +137 -0
- package/src/tasks/dates.ts +31 -0
- package/src/tasks/define-statuses.ts +32 -0
- package/src/tasks/demo.svelte +389 -0
- package/src/tasks/detail/detail-demo.svelte +186 -0
- package/src/tasks/detail/detail-types.ts +54 -0
- package/src/tasks/detail/task-chip.svelte +28 -0
- package/src/tasks/detail/task-detail.svelte +315 -0
- package/src/tasks/detail/task-property.svelte +17 -0
- package/src/tasks/detail/task-thread.svelte +258 -0
- package/src/tasks/gantt/gantt-bar.svelte +243 -0
- package/src/tasks/gantt/gantt-grid.svelte +94 -0
- package/src/tasks/gantt/gantt-group-row.svelte +55 -0
- package/src/tasks/gantt/gantt-header.svelte +71 -0
- package/src/tasks/gantt/gantt-task-row.svelte +186 -0
- package/src/tasks/gantt/gantt.css +22 -0
- package/src/tasks/gantt/gantt.test.ts +77 -0
- package/src/tasks/gantt/logic.test.ts +163 -0
- package/src/tasks/gantt/logic.ts +248 -0
- package/src/tasks/inbox/inbox-card.svelte +283 -0
- package/src/tasks/inbox/inbox-draft.svelte +84 -0
- package/src/tasks/inbox/inbox-logic.ts +55 -0
- package/src/tasks/inbox/inbox-statuses.ts +48 -0
- package/src/tasks/inbox/inbox-trace.svelte +45 -0
- package/src/tasks/inbox/inbox-types.ts +108 -0
- package/src/tasks/inbox/inbox.svelte +203 -0
- package/src/tasks/inbox/index.ts +23 -0
- package/src/tasks/index.ts +85 -0
- package/src/tasks/kanban-board.svelte +561 -0
- package/src/tasks/kanban-column.svelte +117 -0
- package/src/tasks/kanban-drag.ts +38 -0
- package/src/tasks/kanban-types.ts +65 -0
- package/src/tasks/presets/sales.ts +16 -0
- package/src/tasks/record/demo-data.ts +286 -0
- package/src/tasks/record/field-section.svelte +53 -0
- package/src/tasks/record/fields.ts +142 -0
- package/src/tasks/record/format.ts +87 -0
- package/src/tasks/record/gutter.ts +2 -0
- package/src/tasks/record/index.ts +54 -0
- package/src/tasks/record/info-list.svelte +316 -0
- package/src/tasks/record/kinds.ts +42 -0
- package/src/tasks/record/logic.ts +324 -0
- package/src/tasks/record/next-up.svelte +70 -0
- package/src/tasks/record/project-list.svelte +133 -0
- package/src/tasks/record/record-demo.svelte +324 -0
- package/src/tasks/record/record-header.svelte +70 -0
- package/src/tasks/record/record-shell.svelte +138 -0
- package/src/tasks/record/record-stats.svelte +48 -0
- package/src/tasks/record/record-timeline.svelte +231 -0
- package/src/tasks/record/record.test.ts +350 -0
- package/src/tasks/record/steps-rail.svelte +474 -0
- package/src/tasks/record/types.ts +280 -0
- package/src/tasks/record/where-we-are.svelte +121 -0
- package/src/tasks/reorder.ts +19 -0
- package/src/tasks/side-panel-types.ts +16 -0
- package/src/tasks/side-panel.svelte +193 -0
- package/src/tasks/status-badge.svelte +63 -0
- package/src/tasks/status-dot.svelte +228 -0
- package/src/tasks/status-icon.svelte +30 -0
- package/src/tasks/status-types.ts +40 -0
- package/src/tasks/task-gantt.svelte +230 -0
- package/src/tasks/task-list.svelte +470 -0
- package/src/tasks/task-types.ts +33 -0
- package/src/tasks/time/duration.ts +69 -0
- package/src/tasks/time/time-chip.svelte +62 -0
- package/src/tasks/time/time-dot.svelte +58 -0
- package/src/tasks/time/time-ring.svelte +74 -0
- package/src/tasks/time/time-tracker.svelte +565 -0
- package/src/tasks/time/time-types.ts +74 -0
- package/src/tasks/use-kanban-dnd.svelte.ts +173 -0
- package/src/tokens/base.css +5 -5
- package/src/tokens/palette.css +115 -120
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/* Global theming for layerchart-rendered chrome shared by every chart in this
|
|
2
|
+
package (tooltip surface, header, rows). Ships with `@heyramzi/ui/charts`, so
|
|
3
|
+
any consumer that defines the shadcn token set gets a legible tooltip in both
|
|
4
|
+
themes for free.
|
|
5
|
+
|
|
6
|
+
WHY: layerchart's built-in `default` tooltip paints itself with
|
|
7
|
+
`light-dark(var(--color-surface-100, white), var(--color-surface-300, black))`
|
|
8
|
+
and a `backdrop-filter` blur. Apps that don't define `--color-surface-*` (and
|
|
9
|
+
don't set `color-scheme`) fall back to a translucent white card, which is
|
|
10
|
+
unreadable on a dark page. These rules repaint it with `--popover` /
|
|
11
|
+
`--border` / `--muted-foreground`, which already flip per theme. The selectors
|
|
12
|
+
stay unlayered so they beat layerchart's `@layer component` defaults
|
|
13
|
+
regardless of specificity. */
|
|
14
|
+
|
|
15
|
+
.lc-tooltip-container[data-variant="default"] {
|
|
16
|
+
color: var(--popover-foreground, var(--foreground));
|
|
17
|
+
background-color: var(--popover, #fff);
|
|
18
|
+
border: 1px solid var(--border, transparent);
|
|
19
|
+
border-radius: 0.5rem;
|
|
20
|
+
padding: 0.625rem 0.75rem;
|
|
21
|
+
min-width: 8.75rem;
|
|
22
|
+
backdrop-filter: none;
|
|
23
|
+
box-shadow:
|
|
24
|
+
0 1px 2px -1px oklch(0 0 0 / 0.2),
|
|
25
|
+
0 10px 28px -10px oklch(0 0 0 / 0.32);
|
|
26
|
+
/* WHY: opacity only; the container's transform is inline positioning, so
|
|
27
|
+
animating transform here would fight it and make the tooltip jump. */
|
|
28
|
+
transform-origin: top left;
|
|
29
|
+
animation: hr-tooltip-in var(--duration-fast, 250ms) var(--ease-smooth-out) both;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* WHY `scale` and `translate`, not `transform`: the container's inline transform is
|
|
33
|
+
its position, and the individual properties compose with it instead of fighting. */
|
|
34
|
+
@keyframes hr-tooltip-in {
|
|
35
|
+
from {
|
|
36
|
+
opacity: 0;
|
|
37
|
+
scale: var(--scale-large, 0.96);
|
|
38
|
+
translate: calc(var(--distance-small, 6px) * -1) 0;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@media (prefers-reduced-motion: reduce) {
|
|
43
|
+
.lc-tooltip-container[data-variant="default"] {
|
|
44
|
+
animation: none;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/* bklit-ui's panel: a small title with no rule under it, and a dot on every row. */
|
|
49
|
+
.lc-tooltip-header {
|
|
50
|
+
color: var(--popover-foreground, var(--foreground));
|
|
51
|
+
font-size: 0.75rem;
|
|
52
|
+
font-weight: 500;
|
|
53
|
+
border-bottom: none;
|
|
54
|
+
margin-bottom: 0.5rem;
|
|
55
|
+
padding-bottom: 0;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.lc-tooltip-list {
|
|
59
|
+
gap: 0.375rem 1rem;
|
|
60
|
+
font-size: 0.8125rem;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.lc-tooltip-item-color {
|
|
64
|
+
width: 0.625rem;
|
|
65
|
+
height: 0.625rem;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.lc-tooltip-item-label,
|
|
69
|
+
.lc-tooltip-container .label {
|
|
70
|
+
color: var(--muted-foreground);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.lc-tooltip-item-value,
|
|
74
|
+
.lc-tooltip-container .value {
|
|
75
|
+
color: var(--popover-foreground, var(--foreground));
|
|
76
|
+
font-weight: 500;
|
|
77
|
+
font-variant-numeric: tabular-nums;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/* Shared chart tokens, held at zero specificity by `:where()`. The reveal pair
|
|
81
|
+
is the entrance every chart shares; motion.ts mirrors its duration. */
|
|
82
|
+
:where(
|
|
83
|
+
.hr-area-chart,
|
|
84
|
+
.hr-bar-chart,
|
|
85
|
+
.hr-line-chart,
|
|
86
|
+
.hr-sparkline,
|
|
87
|
+
.hr-number-chart,
|
|
88
|
+
.hr-stat-card,
|
|
89
|
+
.hr-legend,
|
|
90
|
+
.hr-ts-chart,
|
|
91
|
+
.hr-donut-chart,
|
|
92
|
+
.hr-ring,
|
|
93
|
+
.hr-gauge
|
|
94
|
+
) {
|
|
95
|
+
--chart-label: var(--muted-foreground, oklch(0.5 0.01 286));
|
|
96
|
+
--chart-grid: color-mix(in srgb, var(--border, oklch(0.5 0.01 286)) 65%, transparent);
|
|
97
|
+
--chart-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
|
|
98
|
+
--chart-motion-fast: 150ms;
|
|
99
|
+
--chart-motion: 250ms;
|
|
100
|
+
--chart-motion-slow: 800ms;
|
|
101
|
+
--chart-motion-reveal: 1100ms;
|
|
102
|
+
--chart-ease-reveal: cubic-bezier(0.85, 0, 0.15, 1);
|
|
103
|
+
--chart-stagger: 30ms;
|
|
104
|
+
--chart-crosshair: color-mix(
|
|
105
|
+
in srgb,
|
|
106
|
+
var(--muted-foreground, oklch(0.5 0.01 286)) 60%,
|
|
107
|
+
transparent
|
|
108
|
+
);
|
|
109
|
+
--chart-card-shadow: 0 1px 2px 0 oklch(0 0 0 / 0.04), 0 1px 3px 0 oklch(0 0 0 / 0.06);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/* Shared layerchart chrome: axis labels, grid rules, and hover highlights were
|
|
113
|
+
duplicated identically across every chart's scoped <style>. Centralize them
|
|
114
|
+
here, scoped to the chart roots, so the look is defined once. `:where()` keeps
|
|
115
|
+
specificity at 0 so a component can still override locally if it must. */
|
|
116
|
+
:where(
|
|
117
|
+
.hr-area-chart,
|
|
118
|
+
.hr-bar-chart,
|
|
119
|
+
.hr-line-chart,
|
|
120
|
+
.hr-scatter-chart,
|
|
121
|
+
.hr-live-line-chart,
|
|
122
|
+
.hr-sparkline,
|
|
123
|
+
.hr-stat-card,
|
|
124
|
+
.hr-donut-chart
|
|
125
|
+
)
|
|
126
|
+
.lc-axis-tick-label {
|
|
127
|
+
fill: var(--chart-label);
|
|
128
|
+
font-size: 11px;
|
|
129
|
+
}
|
|
130
|
+
:where(
|
|
131
|
+
.hr-area-chart,
|
|
132
|
+
.hr-bar-chart,
|
|
133
|
+
.hr-line-chart,
|
|
134
|
+
.hr-scatter-chart,
|
|
135
|
+
.hr-live-line-chart,
|
|
136
|
+
.hr-sparkline,
|
|
137
|
+
.hr-stat-card,
|
|
138
|
+
.hr-donut-chart
|
|
139
|
+
)
|
|
140
|
+
.lc-axis-tick {
|
|
141
|
+
stroke: transparent;
|
|
142
|
+
}
|
|
143
|
+
:where(
|
|
144
|
+
.hr-area-chart,
|
|
145
|
+
.hr-bar-chart,
|
|
146
|
+
.hr-line-chart,
|
|
147
|
+
.hr-scatter-chart,
|
|
148
|
+
.hr-live-line-chart,
|
|
149
|
+
.hr-sparkline,
|
|
150
|
+
.hr-stat-card,
|
|
151
|
+
.hr-donut-chart
|
|
152
|
+
)
|
|
153
|
+
:is(.lc-grid-x-rule, .lc-grid-y-rule) {
|
|
154
|
+
stroke: var(--chart-grid);
|
|
155
|
+
stroke-dasharray: 4 4;
|
|
156
|
+
}
|
|
157
|
+
:where(
|
|
158
|
+
.hr-area-chart,
|
|
159
|
+
.hr-bar-chart,
|
|
160
|
+
.hr-line-chart,
|
|
161
|
+
.hr-scatter-chart,
|
|
162
|
+
.hr-live-line-chart,
|
|
163
|
+
.hr-sparkline,
|
|
164
|
+
.hr-stat-card,
|
|
165
|
+
.hr-donut-chart
|
|
166
|
+
)
|
|
167
|
+
.lc-highlight-point {
|
|
168
|
+
stroke: var(--background, white);
|
|
169
|
+
stroke-width: 2;
|
|
170
|
+
}
|
|
171
|
+
:where(
|
|
172
|
+
.hr-area-chart,
|
|
173
|
+
.hr-bar-chart,
|
|
174
|
+
.hr-line-chart,
|
|
175
|
+
.hr-scatter-chart,
|
|
176
|
+
.hr-live-line-chart,
|
|
177
|
+
.hr-sparkline,
|
|
178
|
+
.hr-stat-card,
|
|
179
|
+
.hr-donut-chart
|
|
180
|
+
)
|
|
181
|
+
.lc-highlight-line {
|
|
182
|
+
stroke: var(--chart-grid);
|
|
183
|
+
stroke-width: 1;
|
|
184
|
+
stroke-dasharray: none;
|
|
185
|
+
}
|
|
186
|
+
/* bklit-ui's hover: the series drops to 0.3 and hover-focus.svelte redraws the
|
|
187
|
+
stretch around the point at full strength. */
|
|
188
|
+
.hr-hover-dim {
|
|
189
|
+
transition: opacity 400ms ease-in-out;
|
|
190
|
+
}
|
|
191
|
+
.hr-hover-dim.hr-hover-dimmed {
|
|
192
|
+
opacity: 0.3;
|
|
193
|
+
}
|
|
194
|
+
@media (prefers-reduced-motion: reduce) {
|
|
195
|
+
.hr-hover-dim {
|
|
196
|
+
transition: none;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
.hr-crosshair-stop {
|
|
200
|
+
stop-color: var(--chart-crosshair);
|
|
201
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
// =========================
|
|
3
|
+
// IMPORTS
|
|
4
|
+
// =========================
|
|
5
|
+
import { getChartContext } from "layerchart";
|
|
6
|
+
|
|
7
|
+
// =========================
|
|
8
|
+
// TYPES
|
|
9
|
+
// =========================
|
|
10
|
+
interface Props {
|
|
11
|
+
/** Gradient id. Paint the highlight line with `stroke: url(#id)`. */
|
|
12
|
+
id: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// =========================
|
|
16
|
+
// PROPS
|
|
17
|
+
// =========================
|
|
18
|
+
let { id }: Props = $props();
|
|
19
|
+
|
|
20
|
+
const ctx = getChartContext();
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<!-- =========================== -->
|
|
24
|
+
<!-- CROSSHAIR -->
|
|
25
|
+
<!-- =========================== -->
|
|
26
|
+
<!-- WHY userSpaceOnUse: a vertical line has a zero-width bounding box, so an
|
|
27
|
+
objectBoundingBox gradient on it paints nothing. -->
|
|
28
|
+
<defs>
|
|
29
|
+
<linearGradient {id} gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="0" y2={ctx.height}>
|
|
30
|
+
<stop offset="0" class="hr-crosshair-stop" stop-opacity="0" />
|
|
31
|
+
<stop offset="0.12" class="hr-crosshair-stop" />
|
|
32
|
+
<stop offset="0.88" class="hr-crosshair-stop" />
|
|
33
|
+
<stop offset="1" class="hr-crosshair-stop" stop-opacity="0" />
|
|
34
|
+
</linearGradient>
|
|
35
|
+
</defs>
|
|
@@ -0,0 +1,55 @@
|
|
|
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";
|
|
8
|
+
|
|
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
|
+
|
|
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
|
+
|
|
26
|
+
// =========================
|
|
27
|
+
// PROPS
|
|
28
|
+
// =========================
|
|
29
|
+
let { icon: Icon, title, description, actions, class: className }: Props = $props();
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<!-- =========================== -->
|
|
33
|
+
<!-- MARKUP -->
|
|
34
|
+
<!-- =========================== -->
|
|
35
|
+
<div
|
|
36
|
+
class={cn(
|
|
37
|
+
"rounded-xl border-2 border-dashed border-border bg-transparent p-10 text-center",
|
|
38
|
+
className,
|
|
39
|
+
)}
|
|
40
|
+
>
|
|
41
|
+
<div class="mx-auto flex max-w-md flex-col items-center gap-4">
|
|
42
|
+
{#if Icon}
|
|
43
|
+
<Icon class="size-10 text-muted-foreground" aria-hidden="true" />
|
|
44
|
+
{/if}
|
|
45
|
+
<div class="space-y-1.5">
|
|
46
|
+
<h2 class="font-heading text-lg font-semibold">{title}</h2>
|
|
47
|
+
{#if description}
|
|
48
|
+
<p class="text-sm text-muted-foreground">{description}</p>
|
|
49
|
+
{/if}
|
|
50
|
+
</div>
|
|
51
|
+
{#if actions}
|
|
52
|
+
<div class="flex flex-wrap justify-center gap-2">{@render actions()}</div>
|
|
53
|
+
{/if}
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
@@ -0,0 +1,58 @@
|
|
|
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";
|
|
8
|
+
|
|
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
|
+
|
|
24
|
+
// =========================
|
|
25
|
+
// PROPS
|
|
26
|
+
// =========================
|
|
27
|
+
let { title, note, href, openLabel = "Open", children, class: className }: Props = $props();
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<!-- =========================== -->
|
|
31
|
+
<!-- MARKUP -->
|
|
32
|
+
<!-- =========================== -->
|
|
33
|
+
<!-- An area of a dashboard, named, then its numbers. No box of its own: its
|
|
34
|
+
cards are the containers, and a card in a card is never right. -->
|
|
35
|
+
<section class={cn("flex flex-col gap-4", className)}>
|
|
36
|
+
<div class="flex flex-wrap items-baseline justify-between gap-x-4 gap-y-1">
|
|
37
|
+
<h2 class="text-base font-semibold tracking-tight">{title}</h2>
|
|
38
|
+
<div class="flex items-baseline gap-3">
|
|
39
|
+
{#if note}
|
|
40
|
+
<p class="text-xs text-muted-foreground">{note}</p>
|
|
41
|
+
{/if}
|
|
42
|
+
{#if href}
|
|
43
|
+
<a
|
|
44
|
+
{href}
|
|
45
|
+
class="group inline-flex items-center gap-1 rounded-md text-xs font-medium text-muted-foreground transition-colors duration-[var(--duration-quick)] hover:text-foreground focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:outline-none"
|
|
46
|
+
>
|
|
47
|
+
{openLabel}
|
|
48
|
+
<ArrowRight
|
|
49
|
+
size={12}
|
|
50
|
+
class="shrink-0 transition-transform duration-[var(--duration-quick)] ease-out group-hover:translate-x-0.5"
|
|
51
|
+
/>
|
|
52
|
+
</a>
|
|
53
|
+
{/if}
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
{@render children()}
|
|
58
|
+
</section>
|
|
@@ -0,0 +1,81 @@
|
|
|
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/list-page/index.js";
|
|
9
|
+
import type { PhosphorIcon } from "../../lib/icon-types.js";
|
|
10
|
+
|
|
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
|
+
|
|
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
|
+
</script>
|
|
55
|
+
|
|
56
|
+
<!-- =========================== -->
|
|
57
|
+
<!-- MARKUP -->
|
|
58
|
+
<!-- =========================== -->
|
|
59
|
+
<section class={cn(panelShellClass, className)}>
|
|
60
|
+
<div class={panelHeaderClass}>
|
|
61
|
+
<div class="flex min-w-0 flex-col gap-0.5">
|
|
62
|
+
<SectionLabel icon={labelIcon}>{label}</SectionLabel>
|
|
63
|
+
{#if sublabel}
|
|
64
|
+
<span class="truncate text-xs text-muted-foreground">{sublabel}</span>
|
|
65
|
+
{/if}
|
|
66
|
+
</div>
|
|
67
|
+
{#if hint || actions}
|
|
68
|
+
<div class="flex min-w-0 shrink-0 items-center gap-3">
|
|
69
|
+
{#if hint}
|
|
70
|
+
<span class="text-xs tabular-nums text-muted-foreground">{hint}</span>
|
|
71
|
+
{/if}
|
|
72
|
+
{#if actions}
|
|
73
|
+
{@render actions()}
|
|
74
|
+
{/if}
|
|
75
|
+
</div>
|
|
76
|
+
{/if}
|
|
77
|
+
</div>
|
|
78
|
+
<div class={cn(pad && "p-4", scroll && "overflow-x-auto", bodyClass)}>
|
|
79
|
+
{@render children()}
|
|
80
|
+
</div>
|
|
81
|
+
</section>
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
<script lang="ts">
|
|
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
|
+
|
|
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
|
+
|
|
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
|
+
|
|
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
|
+
|
|
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
|
+
|
|
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
|
+
|
|
52
|
+
// =========================
|
|
53
|
+
// DERIVED
|
|
54
|
+
// =========================
|
|
55
|
+
const ariaSort = $derived(active ? (descending ? "descending" : "ascending") : "none");
|
|
56
|
+
|
|
57
|
+
// =========================
|
|
58
|
+
// FUNCTIONS
|
|
59
|
+
// =========================
|
|
60
|
+
function handleKeydown(event: KeyboardEvent) {
|
|
61
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
62
|
+
event.preventDefault();
|
|
63
|
+
onSort();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
</script>
|
|
67
|
+
|
|
68
|
+
<!-- =========================== -->
|
|
69
|
+
<!-- MARKUP -->
|
|
70
|
+
<!-- =========================== -->
|
|
71
|
+
<th
|
|
72
|
+
scope="col"
|
|
73
|
+
{title}
|
|
74
|
+
tabindex="0"
|
|
75
|
+
aria-sort={ariaSort}
|
|
76
|
+
onclick={onSort}
|
|
77
|
+
onkeydown={handleKeydown}
|
|
78
|
+
class={cn(
|
|
79
|
+
numeric ? dataThNumClass : dataThClass,
|
|
80
|
+
"cursor-pointer select-none transition-colors hover:text-foreground",
|
|
81
|
+
active && "text-foreground",
|
|
82
|
+
className,
|
|
83
|
+
)}
|
|
84
|
+
>
|
|
85
|
+
<span class="inline-flex items-center gap-0.5 whitespace-nowrap">
|
|
86
|
+
{#if numeric}
|
|
87
|
+
{@render caret()}{@render children()}
|
|
88
|
+
{:else}
|
|
89
|
+
{@render children()}{@render caret()}
|
|
90
|
+
{/if}
|
|
91
|
+
</span>
|
|
92
|
+
</th>
|
|
93
|
+
|
|
94
|
+
{#snippet caret()}
|
|
95
|
+
{#if active && !descending}
|
|
96
|
+
<CaretUp class="size-3 shrink-0" weight="bold" />
|
|
97
|
+
{:else if active}
|
|
98
|
+
<CaretDown class="size-3 shrink-0" weight="bold" />
|
|
99
|
+
{:else}
|
|
100
|
+
<CaretDown class="size-3 shrink-0 text-muted-foreground/40" />
|
|
101
|
+
{/if}
|
|
102
|
+
{/snippet}
|