@happyvertical/smrt-svelte 0.55.6 → 0.55.8
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/AGENTS.md +9 -31
- package/README.md +195 -5
- package/agents/browser-ai.md +47 -0
- package/agents/command-palette.md +85 -0
- package/agents/import-export.md +62 -0
- package/agents/overview-surfaces.md +255 -0
- package/agents/screens.md +57 -0
- package/agents/workspace.md +202 -5
- package/dist/browser-ai/adapters/stt/dictation-source.d.ts.map +1 -1
- package/dist/browser-ai/adapters/stt/dictation-source.js +8 -2
- package/dist/browser-ai/adapters/stt/factory.d.ts +6 -3
- package/dist/browser-ai/adapters/stt/factory.d.ts.map +1 -1
- package/dist/browser-ai/adapters/stt/factory.js +19 -9
- package/dist/browser-ai/adapters/stt/index.d.ts +3 -1
- package/dist/browser-ai/adapters/stt/index.d.ts.map +1 -1
- package/dist/browser-ai/adapters/stt/index.js +3 -1
- package/dist/browser-ai/adapters/stt/local-speech-model.d.ts +111 -0
- package/dist/browser-ai/adapters/stt/local-speech-model.d.ts.map +1 -0
- package/dist/browser-ai/adapters/stt/local-speech-model.js +377 -0
- package/dist/browser-ai/adapters/stt/local-speech.d.ts +82 -0
- package/dist/browser-ai/adapters/stt/local-speech.d.ts.map +1 -0
- package/dist/browser-ai/adapters/stt/local-speech.js +317 -0
- package/dist/browser-ai/adapters/stt/local-speech.worker.d.ts +2 -0
- package/dist/browser-ai/adapters/stt/local-speech.worker.d.ts.map +1 -0
- package/dist/browser-ai/adapters/stt/local-speech.worker.js +32 -0
- package/dist/browser-ai/adapters/stt/transformers-env.d.ts +8 -0
- package/dist/browser-ai/adapters/stt/transformers-env.d.ts.map +1 -0
- package/dist/browser-ai/adapters/stt/transformers-env.js +17 -0
- package/dist/browser-ai/adapters/stt/types.d.ts +54 -9
- package/dist/browser-ai/adapters/stt/types.d.ts.map +1 -1
- package/dist/browser-ai/adapters/tts/browser-synthesis.d.ts +5 -0
- package/dist/browser-ai/adapters/tts/browser-synthesis.d.ts.map +1 -1
- package/dist/browser-ai/adapters/tts/browser-synthesis.js +83 -55
- package/dist/browser-ai/capabilities/speech-probe.d.ts +29 -0
- package/dist/browser-ai/capabilities/speech-probe.d.ts.map +1 -0
- package/dist/browser-ai/capabilities/speech-probe.js +19 -0
- package/dist/browser-ai/core/errors.d.ts +9 -0
- package/dist/browser-ai/core/errors.d.ts.map +1 -1
- package/dist/browser-ai/core/errors.js +12 -0
- package/dist/browser-ai/index.d.ts +1 -0
- package/dist/browser-ai/index.d.ts.map +1 -1
- package/dist/browser-ai/index.js +1 -0
- package/dist/components/app/AppShell.svelte +587 -33
- package/dist/components/app/AppShell.svelte.d.ts +75 -4
- package/dist/components/app/AppShell.svelte.d.ts.map +1 -1
- package/dist/components/app/DockToggles.svelte +0 -1
- package/dist/components/app/dock-toggle.d.ts +7 -1
- package/dist/components/app/dock-toggle.d.ts.map +1 -1
- package/dist/components/app/index.d.ts +2 -1
- package/dist/components/app/index.d.ts.map +1 -1
- package/dist/components/app/slot-item.d.ts +21 -0
- package/dist/components/app/slot-item.d.ts.map +1 -0
- package/dist/components/app/slot-item.js +1 -0
- package/dist/components/command-palette/CommandPalette.svelte +75 -0
- package/dist/components/command-palette/CommandPalette.svelte.d.ts +22 -0
- package/dist/components/command-palette/CommandPalette.svelte.d.ts.map +1 -0
- package/dist/components/command-palette/CommandPaletteDialog.svelte +406 -0
- package/dist/components/command-palette/CommandPaletteDialog.svelte.d.ts +18 -0
- package/dist/components/command-palette/CommandPaletteDialog.svelte.d.ts.map +1 -0
- package/dist/components/command-palette/CommandPaletteTrigger.svelte +91 -0
- package/dist/components/command-palette/CommandPaletteTrigger.svelte.d.ts +17 -0
- package/dist/components/command-palette/CommandPaletteTrigger.svelte.d.ts.map +1 -0
- package/dist/components/command-palette/context.d.ts +18 -0
- package/dist/components/command-palette/context.d.ts.map +1 -0
- package/dist/components/command-palette/context.js +38 -0
- package/dist/components/command-palette/controller.svelte.d.ts +70 -0
- package/dist/components/command-palette/controller.svelte.d.ts.map +1 -0
- package/dist/components/command-palette/controller.svelte.js +379 -0
- package/dist/components/command-palette/hotkeys.d.ts +30 -0
- package/dist/components/command-palette/hotkeys.d.ts.map +1 -0
- package/dist/components/command-palette/hotkeys.js +161 -0
- package/dist/components/command-palette/index.d.ts +19 -0
- package/dist/components/command-palette/index.d.ts.map +1 -0
- package/dist/components/command-palette/index.js +17 -0
- package/dist/components/command-palette/match.d.ts +38 -0
- package/dist/components/command-palette/match.d.ts.map +1 -0
- package/dist/components/command-palette/match.js +172 -0
- package/dist/components/command-palette/providers.d.ts +159 -0
- package/dist/components/command-palette/providers.d.ts.map +1 -0
- package/dist/components/command-palette/providers.js +345 -0
- package/dist/components/command-palette/rank.d.ts +20 -0
- package/dist/components/command-palette/rank.d.ts.map +1 -0
- package/dist/components/command-palette/rank.js +74 -0
- package/dist/components/command-palette/types.d.ts +119 -0
- package/dist/components/command-palette/types.d.ts.map +1 -0
- package/dist/components/command-palette/types.js +10 -0
- package/dist/components/command-palette/use-provider.svelte.d.ts +14 -0
- package/dist/components/command-palette/use-provider.svelte.d.ts.map +1 -0
- package/dist/components/command-palette/use-provider.svelte.js +23 -0
- package/dist/components/forms/AddressInput.svelte +2 -15
- package/dist/components/forms/AddressInput.svelte.d.ts.map +1 -1
- package/dist/components/forms/DateRangeInput.svelte +2 -15
- package/dist/components/forms/DateRangeInput.svelte.d.ts.map +1 -1
- package/dist/components/forms/DateTimeInput.svelte +8 -15
- package/dist/components/forms/DateTimeInput.svelte.d.ts.map +1 -1
- package/dist/components/forms/MeasurementInput.svelte +2 -15
- package/dist/components/forms/MeasurementInput.svelte.d.ts.map +1 -1
- package/dist/components/forms/MoneyInput.svelte +8 -25
- package/dist/components/forms/MoneyInput.svelte.d.ts.map +1 -1
- package/dist/components/forms/NumberInput.svelte +7 -15
- package/dist/components/forms/NumberInput.svelte.d.ts.map +1 -1
- package/dist/components/forms/PhoneInput.svelte +7 -15
- package/dist/components/forms/PhoneInput.svelte.d.ts.map +1 -1
- package/dist/components/forms/SelectInput.svelte +34 -40
- package/dist/components/forms/SelectInput.svelte.d.ts.map +1 -1
- package/dist/components/forms/TextInput.svelte +20 -37
- package/dist/components/forms/TextInput.svelte.d.ts.map +1 -1
- package/dist/components/forms/TextareaInput.svelte +19 -35
- package/dist/components/forms/TextareaInput.svelte.d.ts.map +1 -1
- package/dist/components/import-export/ImportExport.svelte +678 -0
- package/dist/components/import-export/ImportExport.svelte.d.ts +5 -0
- package/dist/components/import-export/ImportExport.svelte.d.ts.map +1 -0
- package/dist/components/import-export/collection-adapter.d.ts +35 -0
- package/dist/components/import-export/collection-adapter.d.ts.map +1 -0
- package/dist/components/import-export/collection-adapter.js +42 -0
- package/dist/components/import-export/csv.d.ts +60 -0
- package/dist/components/import-export/csv.d.ts.map +1 -0
- package/dist/components/import-export/csv.js +192 -0
- package/dist/components/import-export/download.d.ts +4 -0
- package/dist/components/import-export/download.d.ts.map +1 -0
- package/dist/components/import-export/download.js +17 -0
- package/dist/components/import-export/export.d.ts +25 -0
- package/dist/components/import-export/export.d.ts.map +1 -0
- package/dist/components/import-export/export.js +68 -0
- package/dist/components/import-export/fields.d.ts +48 -0
- package/dist/components/import-export/fields.d.ts.map +1 -0
- package/dist/components/import-export/fields.js +103 -0
- package/dist/components/import-export/index.d.ts +12 -0
- package/dist/components/import-export/index.d.ts.map +1 -0
- package/dist/components/import-export/index.js +9 -0
- package/dist/components/import-export/mapping.d.ts +12 -0
- package/dist/components/import-export/mapping.d.ts.map +1 -0
- package/dist/components/import-export/mapping.js +38 -0
- package/dist/components/import-export/props.d.ts +34 -0
- package/dist/components/import-export/props.d.ts.map +1 -0
- package/dist/components/import-export/props.js +1 -0
- package/dist/components/import-export/report.d.ts +13 -0
- package/dist/components/import-export/report.d.ts.map +1 -0
- package/dist/components/import-export/report.js +50 -0
- package/dist/components/import-export/runner.d.ts +17 -0
- package/dist/components/import-export/runner.d.ts.map +1 -0
- package/dist/components/import-export/runner.js +39 -0
- package/dist/components/import-export/types.d.ts +100 -0
- package/dist/components/import-export/types.d.ts.map +1 -0
- package/dist/components/import-export/types.js +6 -0
- package/dist/components/import-export/validate.d.ts +39 -0
- package/dist/components/import-export/validate.d.ts.map +1 -0
- package/dist/components/import-export/validate.js +268 -0
- package/dist/components/overview/OverviewGrid.svelte +579 -0
- package/dist/components/overview/OverviewGrid.svelte.d.ts +5 -0
- package/dist/components/overview/OverviewGrid.svelte.d.ts.map +1 -0
- package/dist/components/overview/WidgetOptionsForm.svelte +193 -0
- package/dist/components/overview/WidgetOptionsForm.svelte.d.ts +5 -0
- package/dist/components/overview/WidgetOptionsForm.svelte.d.ts.map +1 -0
- package/dist/components/overview/controller.svelte.d.ts +92 -0
- package/dist/components/overview/controller.svelte.d.ts.map +1 -0
- package/dist/components/overview/controller.svelte.js +336 -0
- package/dist/components/overview/format.d.ts +13 -0
- package/dist/components/overview/format.d.ts.map +1 -0
- package/dist/components/overview/format.js +45 -0
- package/dist/components/overview/grid-types.d.ts +52 -0
- package/dist/components/overview/grid-types.d.ts.map +1 -0
- package/dist/components/overview/grid-types.js +1 -0
- package/dist/components/overview/index.d.ts +24 -0
- package/dist/components/overview/index.d.ts.map +1 -0
- package/dist/components/overview/index.js +22 -0
- package/dist/components/overview/load.d.ts +30 -0
- package/dist/components/overview/load.d.ts.map +1 -0
- package/dist/components/overview/load.js +92 -0
- package/dist/components/overview/markdown.d.ts +53 -0
- package/dist/components/overview/markdown.d.ts.map +1 -0
- package/dist/components/overview/markdown.js +203 -0
- package/dist/components/overview/model.d.ts +100 -0
- package/dist/components/overview/model.d.ts.map +1 -0
- package/dist/components/overview/model.js +460 -0
- package/dist/components/overview/recipe-widgets.d.ts +77 -0
- package/dist/components/overview/recipe-widgets.d.ts.map +1 -0
- package/dist/components/overview/recipe-widgets.js +151 -0
- package/dist/components/overview/registry.d.ts +45 -0
- package/dist/components/overview/registry.d.ts.map +1 -0
- package/dist/components/overview/registry.js +112 -0
- package/dist/components/overview/resize.d.ts +25 -0
- package/dist/components/overview/resize.d.ts.map +1 -0
- package/dist/components/overview/resize.js +41 -0
- package/dist/components/overview/schema.d.ts +34 -0
- package/dist/components/overview/schema.d.ts.map +1 -0
- package/dist/components/overview/schema.js +180 -0
- package/dist/components/overview/server.d.ts +14 -0
- package/dist/components/overview/server.d.ts.map +1 -0
- package/dist/components/overview/server.js +13 -0
- package/dist/components/overview/types.d.ts +235 -0
- package/dist/components/overview/types.d.ts.map +1 -0
- package/dist/components/overview/types.js +17 -0
- package/dist/components/overview/widgets/ChartWidget.svelte +111 -0
- package/dist/components/overview/widgets/ChartWidget.svelte.d.ts +6 -0
- package/dist/components/overview/widgets/ChartWidget.svelte.d.ts.map +1 -0
- package/dist/components/overview/widgets/MetricWidget.svelte +86 -0
- package/dist/components/overview/widgets/MetricWidget.svelte.d.ts +6 -0
- package/dist/components/overview/widgets/MetricWidget.svelte.d.ts.map +1 -0
- package/dist/components/overview/widgets/NoteWidget.svelte +61 -0
- package/dist/components/overview/widgets/NoteWidget.svelte.d.ts +5 -0
- package/dist/components/overview/widgets/NoteWidget.svelte.d.ts.map +1 -0
- package/dist/components/overview/widgets/RecordListWidget.svelte +91 -0
- package/dist/components/overview/widgets/RecordListWidget.svelte.d.ts +6 -0
- package/dist/components/overview/widgets/RecordListWidget.svelte.d.ts.map +1 -0
- package/dist/components/overview/widgets/ShortcutsWidget.svelte +80 -0
- package/dist/components/overview/widgets/ShortcutsWidget.svelte.d.ts +6 -0
- package/dist/components/overview/widgets/ShortcutsWidget.svelte.d.ts.map +1 -0
- package/dist/components/overview/widgets/core.d.ts +44 -0
- package/dist/components/overview/widgets/core.d.ts.map +1 -0
- package/dist/components/overview/widgets/core.js +222 -0
- package/dist/components/overview/widgets/data.d.ts +76 -0
- package/dist/components/overview/widgets/data.d.ts.map +1 -0
- package/dist/components/overview/widgets/data.js +40 -0
- package/dist/components/screens/DetailScreen.svelte +220 -0
- package/dist/components/screens/DetailScreen.svelte.d.ts +5 -0
- package/dist/components/screens/DetailScreen.svelte.d.ts.map +1 -0
- package/dist/components/screens/EditForm.svelte +313 -0
- package/dist/components/screens/EditForm.svelte.d.ts +5 -0
- package/dist/components/screens/EditForm.svelte.d.ts.map +1 -0
- package/dist/components/screens/ListScreen.svelte +191 -0
- package/dist/components/screens/ListScreen.svelte.d.ts +5 -0
- package/dist/components/screens/ListScreen.svelte.d.ts.map +1 -0
- package/dist/components/screens/RecipeScreens.svelte +237 -0
- package/dist/components/screens/RecipeScreens.svelte.d.ts +5 -0
- package/dist/components/screens/RecipeScreens.svelte.d.ts.map +1 -0
- package/dist/components/screens/fields.d.ts +54 -0
- package/dist/components/screens/fields.d.ts.map +1 -0
- package/dist/components/screens/fields.js +229 -0
- package/dist/components/screens/index.d.ts +8 -0
- package/dist/components/screens/index.d.ts.map +1 -0
- package/dist/components/screens/index.js +6 -0
- package/dist/components/screens/types.d.ts +215 -0
- package/dist/components/screens/types.d.ts.map +1 -0
- package/dist/components/screens/types.js +1 -0
- package/dist/components/screens/values.d.ts +62 -0
- package/dist/components/screens/values.d.ts.map +1 -0
- package/dist/components/screens/values.js +289 -0
- package/dist/components/sortable/Sortable.svelte +6 -33
- package/dist/components/sortable/Sortable.svelte.d.ts.map +1 -1
- package/dist/components/sortable/announce.d.ts +5 -0
- package/dist/components/sortable/announce.d.ts.map +1 -0
- package/dist/components/sortable/announce.js +33 -0
- package/dist/components/sortable/controller.svelte.d.ts +10 -0
- package/dist/components/sortable/controller.svelte.d.ts.map +1 -1
- package/dist/components/sortable/controller.svelte.js +29 -7
- package/dist/components/workspace/admin-shell/AdminShell.svelte +424 -58
- package/dist/components/workspace/admin-shell/AdminShell.svelte.d.ts +27 -2
- package/dist/components/workspace/admin-shell/AdminShell.svelte.d.ts.map +1 -1
- package/dist/components/workspace/admin-shell/ShellBrand.svelte +86 -0
- package/dist/components/workspace/admin-shell/ShellBrand.svelte.d.ts +18 -0
- package/dist/components/workspace/admin-shell/ShellBrand.svelte.d.ts.map +1 -0
- package/dist/components/workspace/admin-shell/ShellIconButton.svelte +77 -0
- package/dist/components/workspace/admin-shell/ShellIconButton.svelte.d.ts +26 -0
- package/dist/components/workspace/admin-shell/ShellIconButton.svelte.d.ts.map +1 -0
- package/dist/components/workspace/admin-shell/ShellLayoutEditor.svelte +88 -16
- package/dist/components/workspace/admin-shell/ShellLayoutEditor.svelte.d.ts.map +1 -1
- package/dist/components/workspace/admin-shell/ShellNavEditor.svelte +531 -0
- package/dist/components/workspace/admin-shell/ShellNavEditor.svelte.d.ts +26 -0
- package/dist/components/workspace/admin-shell/ShellNavEditor.svelte.d.ts.map +1 -0
- package/dist/components/workspace/admin-shell/ShellSectionIcon.svelte +57 -0
- package/dist/components/workspace/admin-shell/ShellSectionIcon.svelte.d.ts +22 -0
- package/dist/components/workspace/admin-shell/ShellSectionIcon.svelte.d.ts.map +1 -0
- package/dist/components/workspace/admin-shell/ShellSectionMenu.svelte +290 -0
- package/dist/components/workspace/admin-shell/ShellSectionMenu.svelte.d.ts +32 -0
- package/dist/components/workspace/admin-shell/ShellSectionMenu.svelte.d.ts.map +1 -0
- package/dist/components/workspace/admin-shell/TenantNav.svelte +67 -2
- package/dist/components/workspace/admin-shell/TenantNav.svelte.d.ts +8 -0
- package/dist/components/workspace/admin-shell/TenantNav.svelte.d.ts.map +1 -1
- package/dist/components/workspace/admin-shell/layout-controller.svelte.d.ts +67 -0
- package/dist/components/workspace/admin-shell/layout-controller.svelte.d.ts.map +1 -1
- package/dist/components/workspace/admin-shell/layout-controller.svelte.js +129 -1
- package/dist/components/workspace/admin-shell/layout.d.ts +122 -0
- package/dist/components/workspace/admin-shell/layout.d.ts.map +1 -1
- package/dist/components/workspace/admin-shell/layout.js +410 -10
- package/dist/components/workspace/admin-shell/settings.js +4 -4
- package/dist/components/workspace/admin-shell/shell-icons.d.ts +45 -0
- package/dist/components/workspace/admin-shell/shell-icons.d.ts.map +1 -0
- package/dist/components/workspace/admin-shell/shell-icons.js +66 -0
- package/dist/components/workspace/admin-shell/slot-labels.d.ts +33 -0
- package/dist/components/workspace/admin-shell/slot-labels.d.ts.map +1 -0
- package/dist/components/workspace/admin-shell/slot-labels.js +33 -0
- package/dist/components/workspace/admin-shell/slots.d.ts +50 -0
- package/dist/components/workspace/admin-shell/slots.d.ts.map +1 -0
- package/dist/components/workspace/admin-shell/slots.js +77 -0
- package/dist/components/workspace/admin-shell/state.svelte.d.ts +35 -0
- package/dist/components/workspace/admin-shell/state.svelte.d.ts.map +1 -1
- package/dist/components/workspace/admin-shell/state.svelte.js +111 -0
- package/dist/components/workspace/admin-shell/types.d.ts +101 -1
- package/dist/components/workspace/admin-shell/types.d.ts.map +1 -1
- package/dist/components/workspace/index.d.ts +9 -2
- package/dist/components/workspace/index.d.ts.map +1 -1
- package/dist/components/workspace/index.js +6 -0
- package/dist/components/workspace/manifest-nav.d.ts +20 -0
- package/dist/components/workspace/manifest-nav.d.ts.map +1 -1
- package/dist/components/workspace/manifest-nav.js +42 -13
- package/dist/i18n/server.d.ts +6 -0
- package/dist/i18n/server.d.ts.map +1 -1
- package/dist/i18n/server.js +6 -0
- package/dist/i18n/strings.import-export.d.ts +88 -0
- package/dist/i18n/strings.import-export.d.ts.map +1 -0
- package/dist/i18n/strings.import-export.js +88 -0
- package/dist/i18n/strings.overview.d.ts +100 -0
- package/dist/i18n/strings.overview.d.ts.map +1 -0
- package/dist/i18n/strings.overview.js +107 -0
- package/dist/i18n/strings.palette.d.ts +18 -0
- package/dist/i18n/strings.palette.d.ts.map +1 -0
- package/dist/i18n/strings.palette.js +18 -0
- package/dist/i18n/strings.screens.d.ts +31 -0
- package/dist/i18n/strings.screens.d.ts.map +1 -0
- package/dist/i18n/strings.screens.js +31 -0
- package/dist/i18n/strings.workspace.d.ts +49 -0
- package/dist/i18n/strings.workspace.d.ts.map +1 -1
- package/dist/i18n/strings.workspace.js +49 -0
- package/package.json +59 -19
- package/dist/browser-ai/adapters/stt/whisper-wasm.d.ts +0 -51
- package/dist/browser-ai/adapters/stt/whisper-wasm.d.ts.map +0 -1
- package/dist/browser-ai/adapters/stt/whisper-wasm.js +0 -380
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import type { Component } from 'svelte';
|
|
2
|
+
/**
|
|
3
|
+
* Types of the customizable overview surface (#3727): the declarative overview
|
|
4
|
+
* data model, the widget contract, and the page-load contract, plus their
|
|
5
|
+
* limits. Shared by the Svelte-free `./overview/server` entry and the
|
|
6
|
+
* component barrel.
|
|
7
|
+
*/
|
|
8
|
+
/** Narrowest and widest a widget can be, in grid columns. */
|
|
9
|
+
export declare const OVERVIEW_MIN_SPAN = 1;
|
|
10
|
+
export declare const OVERVIEW_MAX_SPAN = 4;
|
|
11
|
+
/** Default cap on widgets in one overview. */
|
|
12
|
+
export declare const OVERVIEW_DEFAULT_MAX_WIDGETS = 24;
|
|
13
|
+
/** Widget ids: short, URL-safe, stable. */
|
|
14
|
+
export declare const OVERVIEW_ID_PATTERN: RegExp;
|
|
15
|
+
/** Overview (page) ids may be dotted or scoped, e.g. `events.home`. */
|
|
16
|
+
export declare const OVERVIEW_PAGE_ID_PATTERN: RegExp;
|
|
17
|
+
/** Widget type ids: lowercase kebab, so they are safe in selectors and keys. */
|
|
18
|
+
export declare const WIDGET_TYPE_PATTERN: RegExp;
|
|
19
|
+
/** An option value is a JSON primitive: options are flat data, never code. */
|
|
20
|
+
export type OverviewOptionValue = string | number | boolean | null;
|
|
21
|
+
export type OverviewOptions = Record<string, OverviewOptionValue>;
|
|
22
|
+
/**
|
|
23
|
+
* One widget on an overview. `version` is the widget type's option-schema
|
|
24
|
+
* version the options were written against (absent means 1).
|
|
25
|
+
*/
|
|
26
|
+
export interface OverviewWidget {
|
|
27
|
+
id: string;
|
|
28
|
+
type: string;
|
|
29
|
+
/** Column span, 1 to 4. */
|
|
30
|
+
span: number;
|
|
31
|
+
options: OverviewOptions;
|
|
32
|
+
version?: number;
|
|
33
|
+
}
|
|
34
|
+
/** The resolved, declarative overview: an ordered list of widgets. */
|
|
35
|
+
export interface OverviewDocument {
|
|
36
|
+
widgets: OverviewWidget[];
|
|
37
|
+
}
|
|
38
|
+
/** A change to a widget that exists in the base document. */
|
|
39
|
+
export interface OverviewWidgetPatch {
|
|
40
|
+
span?: number;
|
|
41
|
+
options?: OverviewOptions;
|
|
42
|
+
version?: number;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The sparse, JSON-serializable delta a host stores (tenant default or user
|
|
46
|
+
* override) on top of the page's default document. Unknown ids are ignored
|
|
47
|
+
* on read, so a default that ships later still appears.
|
|
48
|
+
*/
|
|
49
|
+
export interface OverviewOverride {
|
|
50
|
+
version: 1;
|
|
51
|
+
/** Widget ids in display order; unlisted widgets keep their slots. */
|
|
52
|
+
order?: string[];
|
|
53
|
+
/** Ids of base widgets the user removed. */
|
|
54
|
+
removed?: string[];
|
|
55
|
+
/** Widgets the user added (ids never collide with the base). */
|
|
56
|
+
added?: OverviewWidget[];
|
|
57
|
+
/** Span and option changes to base widgets, by id. */
|
|
58
|
+
changed?: Record<string, OverviewWidgetPatch>;
|
|
59
|
+
}
|
|
60
|
+
/** What a page declares: which widgets may appear and the default layout. */
|
|
61
|
+
export interface OverviewDefinition {
|
|
62
|
+
/** Stable id of this overview (e.g. `events.home`). */
|
|
63
|
+
id: string;
|
|
64
|
+
/** Widget types allowed here. Omit to allow every registered type. */
|
|
65
|
+
allowed?: readonly string[];
|
|
66
|
+
/**
|
|
67
|
+
* Models the overview may read. When set, a `model` option outside the list
|
|
68
|
+
* is invalid. Confines data sources on top of the loader's own authorization.
|
|
69
|
+
*/
|
|
70
|
+
models?: readonly string[];
|
|
71
|
+
/** The default arrangement. */
|
|
72
|
+
defaults: readonly OverviewWidget[];
|
|
73
|
+
/** Cap on widgets (default {@link OVERVIEW_DEFAULT_MAX_WIDGETS}). */
|
|
74
|
+
maxWidgets?: number;
|
|
75
|
+
}
|
|
76
|
+
export type OverviewIssueCode = 'malformed' | 'duplicate_id' | 'unknown_type' | 'type_not_allowed' | 'too_many' | 'invalid_span' | 'invalid_options' | 'future_version' | 'migration_failed';
|
|
77
|
+
/** A widget (or override entry) that was dropped or rejected, and why. */
|
|
78
|
+
export interface OverviewIssue {
|
|
79
|
+
widgetId: string | null;
|
|
80
|
+
type: string | null;
|
|
81
|
+
code: OverviewIssueCode;
|
|
82
|
+
/** Developer-facing detail; not localized. */
|
|
83
|
+
message: string;
|
|
84
|
+
/** Option-level problems when `code` is `invalid_options`. */
|
|
85
|
+
options?: WidgetOptionIssue[];
|
|
86
|
+
}
|
|
87
|
+
export type WidgetOptionType = 'text' | 'markdown' | 'identifier' | 'model' | 'integer' | 'number' | 'boolean' | 'enum';
|
|
88
|
+
export interface WidgetOptionChoice {
|
|
89
|
+
value: string;
|
|
90
|
+
/** Label text or an i18n key. */
|
|
91
|
+
label: string;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* One option of a widget. The shape mirrors the generated screens' field
|
|
95
|
+
* (`name`/`label`/`help`/`required`) so the option editor reads like any other
|
|
96
|
+
* generated form.
|
|
97
|
+
*/
|
|
98
|
+
export interface WidgetOptionField {
|
|
99
|
+
key: string;
|
|
100
|
+
type: WidgetOptionType;
|
|
101
|
+
/** Label text or an i18n key. */
|
|
102
|
+
label: string;
|
|
103
|
+
/** Help text or an i18n key. */
|
|
104
|
+
help?: string;
|
|
105
|
+
required?: boolean;
|
|
106
|
+
default?: OverviewOptionValue;
|
|
107
|
+
/** `integer` and `number` bounds. */
|
|
108
|
+
min?: number;
|
|
109
|
+
max?: number;
|
|
110
|
+
/** `text`, `markdown`: maximum length (defaults 200 and 10000). */
|
|
111
|
+
maxLength?: number;
|
|
112
|
+
/** `enum`: the closed set of values. */
|
|
113
|
+
choices?: readonly WidgetOptionChoice[];
|
|
114
|
+
}
|
|
115
|
+
export type WidgetOptionIssueCode = 'required' | 'invalid_type' | 'too_long' | 'out_of_range' | 'not_in_choices' | 'invalid_format' | 'not_allowed' | 'unknown_option';
|
|
116
|
+
export interface WidgetOptionIssue {
|
|
117
|
+
key: string;
|
|
118
|
+
code: WidgetOptionIssueCode;
|
|
119
|
+
}
|
|
120
|
+
export type WidgetOptionsResult = {
|
|
121
|
+
ok: true;
|
|
122
|
+
options: OverviewOptions;
|
|
123
|
+
} | {
|
|
124
|
+
ok: false;
|
|
125
|
+
issues: WidgetOptionIssue[];
|
|
126
|
+
};
|
|
127
|
+
/** Extra confinement applied while validating options. */
|
|
128
|
+
export interface WidgetOptionsContext {
|
|
129
|
+
/** Models a `model` option may name; omit for no list. */
|
|
130
|
+
models?: readonly string[];
|
|
131
|
+
}
|
|
132
|
+
/** Where a widget's data stands in the grid. */
|
|
133
|
+
export type WidgetStatus = 'ready' | 'loading' | 'error';
|
|
134
|
+
/**
|
|
135
|
+
* Props every widget component receives. The grid mounts a component only
|
|
136
|
+
* when its data is ready (it draws loading and error states itself), so
|
|
137
|
+
* `data` is whatever the widget's `load` returned, or `undefined` for a
|
|
138
|
+
* widget without a loader. Treat `data` as untrusted shape: check it.
|
|
139
|
+
*/
|
|
140
|
+
export interface WidgetComponentProps<Data = unknown> {
|
|
141
|
+
id: string;
|
|
142
|
+
options: OverviewOptions;
|
|
143
|
+
data: Data | undefined;
|
|
144
|
+
span: number;
|
|
145
|
+
/** Heading shown by the frame (the `title` option, else the type title). */
|
|
146
|
+
title: string;
|
|
147
|
+
/** BCP-47 locale for number formatting. */
|
|
148
|
+
locale: string;
|
|
149
|
+
/** The host's renderer for icon names that are not built in. */
|
|
150
|
+
iconComponent?: Component<{
|
|
151
|
+
name: string;
|
|
152
|
+
size?: number;
|
|
153
|
+
}>;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Context a widget `load` runs with. The host builds it inside the page's
|
|
157
|
+
* server load from the request principal: the user's permissions, the
|
|
158
|
+
* tenant-scoped collections, the locale. Index keys carry host capabilities
|
|
159
|
+
* (for example a permission-checked `db` or `fetch`).
|
|
160
|
+
*/
|
|
161
|
+
export interface WidgetLoadContext {
|
|
162
|
+
/** The overview being loaded. */
|
|
163
|
+
overviewId: string;
|
|
164
|
+
/** Aborts when the load times out or the request ends. */
|
|
165
|
+
signal?: AbortSignal;
|
|
166
|
+
locale?: string;
|
|
167
|
+
[capability: string]: unknown;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Server loader of one widget. Receives validated options only, and the
|
|
171
|
+
* request's context. Must return JSON-serializable data and must authorize
|
|
172
|
+
* through `ctx` (never trust the option values for access).
|
|
173
|
+
*/
|
|
174
|
+
export type WidgetLoad<Data = unknown, Ctx extends WidgetLoadContext = WidgetLoadContext> = (options: OverviewOptions, ctx: Ctx) => Data | Promise<Data>;
|
|
175
|
+
/** Upgrades stored options from an older schema version to the current one. */
|
|
176
|
+
export type WidgetMigrate = (options: Record<string, unknown>, fromVersion: number) => Record<string, unknown> | null;
|
|
177
|
+
/** A module (or component) a lazy widget resolves to. */
|
|
178
|
+
export type WidgetComponentModule<Data> = Component<WidgetComponentProps<Data>> | {
|
|
179
|
+
default: Component<WidgetComponentProps<Data>>;
|
|
180
|
+
};
|
|
181
|
+
/** What `registerWidget` takes. */
|
|
182
|
+
export interface WidgetDefinition<Data = unknown> {
|
|
183
|
+
/** Lowercase kebab id, e.g. `metric`. */
|
|
184
|
+
type: string;
|
|
185
|
+
/** Title text or an i18n key. */
|
|
186
|
+
title: string;
|
|
187
|
+
/** Short description or an i18n key (shown in the add list). */
|
|
188
|
+
description?: string;
|
|
189
|
+
/** Shell icon name drawn in the add list. */
|
|
190
|
+
icon?: string;
|
|
191
|
+
/** Option-schema version, a positive integer (default 1). */
|
|
192
|
+
version?: number;
|
|
193
|
+
/** The widget's options, as fields. */
|
|
194
|
+
options: readonly WidgetOptionField[];
|
|
195
|
+
/** Renders the widget. */
|
|
196
|
+
component?: Component<WidgetComponentProps<Data>>;
|
|
197
|
+
/**
|
|
198
|
+
* Resolves the component lazily (dynamic import by export ref). A page
|
|
199
|
+
* resolves these before rendering with `resolveWidgetComponents`.
|
|
200
|
+
*/
|
|
201
|
+
loadComponent?: () => Promise<WidgetComponentModule<Data>>;
|
|
202
|
+
/** Server loader; absent for widgets that render from options alone. */
|
|
203
|
+
load?: WidgetLoad<Data>;
|
|
204
|
+
/** Overview ids this widget may appear in; omit for any. */
|
|
205
|
+
allowedIn?: readonly string[];
|
|
206
|
+
/** Upgrades options stored at an older version. */
|
|
207
|
+
migrate?: WidgetMigrate;
|
|
208
|
+
/** Span a new widget starts with (default 1). */
|
|
209
|
+
defaultSpan?: number;
|
|
210
|
+
minSpan?: number;
|
|
211
|
+
maxSpan?: number;
|
|
212
|
+
}
|
|
213
|
+
/** A registered definition with every default filled in. */
|
|
214
|
+
export interface RegisteredWidget<Data = unknown> extends Omit<WidgetDefinition<Data>, 'version' | 'defaultSpan'> {
|
|
215
|
+
version: number;
|
|
216
|
+
defaultSpan: number;
|
|
217
|
+
minSpan: number;
|
|
218
|
+
maxSpan: number;
|
|
219
|
+
}
|
|
220
|
+
export type LoadedWidgetErrorCode = 'load_failed' | 'timeout' | 'invalid_data';
|
|
221
|
+
/** A widget with its loaded data. JSON-serializable. */
|
|
222
|
+
export interface LoadedWidget extends OverviewWidget {
|
|
223
|
+
status: 'ready' | 'error';
|
|
224
|
+
data?: unknown;
|
|
225
|
+
error?: {
|
|
226
|
+
code: LoadedWidgetErrorCode;
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
/** What a page's server load returns for the client to render. */
|
|
230
|
+
export interface LoadedOverview {
|
|
231
|
+
overviewId: string;
|
|
232
|
+
widgets: LoadedWidget[];
|
|
233
|
+
issues: OverviewIssue[];
|
|
234
|
+
}
|
|
235
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/overview/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types of the customizable overview surface (#3727): the declarative overview
|
|
3
|
+
* data model, the widget contract, and the page-load contract, plus their
|
|
4
|
+
* limits. Shared by the Svelte-free `./overview/server` entry and the
|
|
5
|
+
* component barrel.
|
|
6
|
+
*/
|
|
7
|
+
/** Narrowest and widest a widget can be, in grid columns. */
|
|
8
|
+
export const OVERVIEW_MIN_SPAN = 1;
|
|
9
|
+
export const OVERVIEW_MAX_SPAN = 4;
|
|
10
|
+
/** Default cap on widgets in one overview. */
|
|
11
|
+
export const OVERVIEW_DEFAULT_MAX_WIDGETS = 24;
|
|
12
|
+
/** Widget ids: short, URL-safe, stable. */
|
|
13
|
+
export const OVERVIEW_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/;
|
|
14
|
+
/** Overview (page) ids may be dotted or scoped, e.g. `events.home`. */
|
|
15
|
+
export const OVERVIEW_PAGE_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_.:-]{0,95}$/;
|
|
16
|
+
/** Widget type ids: lowercase kebab, so they are safe in selectors and keys. */
|
|
17
|
+
export const WIDGET_TYPE_PATTERN = /^[a-z][a-z0-9-]{0,31}$/;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* Chart widget (#3727): bars or a line over labelled values, drawn from the
|
|
4
|
+
* loaded data. Every chart carries its numbers as text (bar values inline, a
|
|
5
|
+
* visually hidden table for the line) so it is readable without sight.
|
|
6
|
+
*/
|
|
7
|
+
import { useI18n } from '@happyvertical/smrt-ui/i18n';
|
|
8
|
+
import { M } from '../../../i18n/strings.overview.js';
|
|
9
|
+
import { formatWidgetValue } from '../format.js';
|
|
10
|
+
import type { WidgetComponentProps } from '../types.js';
|
|
11
|
+
import { type ChartWidgetData, isRecord } from './data.js';
|
|
12
|
+
|
|
13
|
+
let { options, data, title, locale }: WidgetComponentProps<ChartWidgetData> =
|
|
14
|
+
$props();
|
|
15
|
+
|
|
16
|
+
const { t } = useI18n();
|
|
17
|
+
const MAX_POINTS = 60;
|
|
18
|
+
|
|
19
|
+
const chart = $derived(isRecord(data) ? data : null);
|
|
20
|
+
const points = $derived.by(() => {
|
|
21
|
+
if (!chart || !Array.isArray(chart.points)) return [];
|
|
22
|
+
const out: { label: string; value: number }[] = [];
|
|
23
|
+
for (const point of chart.points.slice(0, MAX_POINTS)) {
|
|
24
|
+
if (
|
|
25
|
+
isRecord(point) &&
|
|
26
|
+
typeof point.label === 'string' &&
|
|
27
|
+
typeof point.value === 'number' &&
|
|
28
|
+
Number.isFinite(point.value)
|
|
29
|
+
) {
|
|
30
|
+
out.push({ label: point.label, value: point.value });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return out;
|
|
34
|
+
});
|
|
35
|
+
const style = $derived(options.style === 'line' ? 'line' : 'bar');
|
|
36
|
+
const fmt = (value: number): string =>
|
|
37
|
+
formatWidgetValue(value, {
|
|
38
|
+
format: chart?.format ?? 'integer',
|
|
39
|
+
currency: chart?.currency,
|
|
40
|
+
locale,
|
|
41
|
+
});
|
|
42
|
+
const max = $derived(Math.max(0, ...points.map((point) => point.value)));
|
|
43
|
+
const min = $derived(Math.min(0, ...points.map((point) => point.value)));
|
|
44
|
+
const span = $derived(max - min || 1);
|
|
45
|
+
const polyline = $derived(
|
|
46
|
+
points
|
|
47
|
+
.map((point, index) => {
|
|
48
|
+
const x = points.length === 1 ? 50 : (index / (points.length - 1)) * 100;
|
|
49
|
+
const y = 36 - ((point.value - min) / span) * 32;
|
|
50
|
+
return `${x.toFixed(2)},${y.toFixed(2)}`;
|
|
51
|
+
})
|
|
52
|
+
.join(' '),
|
|
53
|
+
);
|
|
54
|
+
const summary = $derived(
|
|
55
|
+
`${title}. ${t(M['ui.overview.chart.summary'], { count: points.length })}`,
|
|
56
|
+
);
|
|
57
|
+
</script>
|
|
58
|
+
|
|
59
|
+
{#if points.length === 0}
|
|
60
|
+
<p class="smrt-chart__empty">{t(M['ui.overview.no_data'])}</p>
|
|
61
|
+
{:else if style === 'line'}
|
|
62
|
+
<div class="smrt-chart">
|
|
63
|
+
<svg class="smrt-chart__line" viewBox="0 0 100 40" preserveAspectRatio="none" role="img" aria-label={summary}>
|
|
64
|
+
<polyline points={polyline} fill="none" stroke="currentColor" stroke-width="2" vector-effect="non-scaling-stroke" />
|
|
65
|
+
</svg>
|
|
66
|
+
<p class="smrt-chart__axis" aria-hidden="true">
|
|
67
|
+
<span>{points[0].label}</span>
|
|
68
|
+
<span>{points[points.length - 1].label}</span>
|
|
69
|
+
</p>
|
|
70
|
+
<table class="smrt-chart__table">
|
|
71
|
+
<caption>{t(M['ui.overview.chart.table'])}</caption>
|
|
72
|
+
<thead>
|
|
73
|
+
<tr>
|
|
74
|
+
<th scope="col">{t(M['ui.overview.chart.label_column'])}</th>
|
|
75
|
+
<th scope="col">{t(M['ui.overview.chart.value_column'])}</th>
|
|
76
|
+
</tr>
|
|
77
|
+
</thead>
|
|
78
|
+
<tbody>
|
|
79
|
+
{#each points as point, index (index)}
|
|
80
|
+
<tr><th scope="row">{point.label}</th><td>{fmt(point.value)}</td></tr>
|
|
81
|
+
{/each}
|
|
82
|
+
</tbody>
|
|
83
|
+
</table>
|
|
84
|
+
</div>
|
|
85
|
+
{:else}
|
|
86
|
+
<ul class="smrt-chart__bars" aria-label={summary}>
|
|
87
|
+
{#each points as point, index (index)}
|
|
88
|
+
<li class="smrt-chart__row">
|
|
89
|
+
<span class="smrt-chart__label">{point.label}</span>
|
|
90
|
+
<span class="smrt-chart__track" aria-hidden="true">
|
|
91
|
+
<span class="smrt-chart__bar" style:inline-size="{max > 0 ? (Math.max(0, point.value) / max) * 100 : 0}%"></span>
|
|
92
|
+
</span>
|
|
93
|
+
<span class="smrt-chart__value">{fmt(point.value)}</span>
|
|
94
|
+
</li>
|
|
95
|
+
{/each}
|
|
96
|
+
</ul>
|
|
97
|
+
{/if}
|
|
98
|
+
|
|
99
|
+
<style>
|
|
100
|
+
.smrt-chart { display: grid; gap: var(--smrt-spacing-1); color: var(--smrt-color-primary); }
|
|
101
|
+
.smrt-chart__line { inline-size: 100%; block-size: 7rem; overflow: visible; }
|
|
102
|
+
.smrt-chart__axis { display: flex; justify-content: space-between; margin: 0; color: var(--smrt-color-on-surface-variant); font-size: var(--smrt-typography-label-large-size, 0.75rem); }
|
|
103
|
+
.smrt-chart__bars { display: grid; gap: var(--smrt-spacing-2); margin: 0; padding: 0; list-style: none; }
|
|
104
|
+
.smrt-chart__row { display: grid; grid-template-columns: minmax(4rem, 30%) minmax(0, 1fr) auto; align-items: center; gap: var(--smrt-spacing-2); font-size: var(--smrt-typography-body-medium-size, 0.875rem); color: var(--smrt-color-on-surface); }
|
|
105
|
+
.smrt-chart__label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
106
|
+
.smrt-chart__track { display: block; block-size: 0.625rem; border-radius: var(--smrt-radius-full, 9999px); background: var(--smrt-color-surface-container-high); overflow: hidden; }
|
|
107
|
+
.smrt-chart__bar { display: block; block-size: 100%; border-radius: inherit; background: var(--smrt-color-primary); }
|
|
108
|
+
.smrt-chart__value { font-variant-numeric: tabular-nums; color: var(--smrt-color-on-surface-variant); }
|
|
109
|
+
.smrt-chart__empty { margin: 0; color: var(--smrt-color-on-surface-variant); }
|
|
110
|
+
.smrt-chart__table { position: absolute; inline-size: 1px; block-size: 1px; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
|
|
111
|
+
</style>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { WidgetComponentProps } from '../types.js';
|
|
2
|
+
import { type ChartWidgetData } from './data.js';
|
|
3
|
+
declare const ChartWidget: import("svelte").Component<WidgetComponentProps<ChartWidgetData>, {}, "">;
|
|
4
|
+
type ChartWidget = ReturnType<typeof ChartWidget>;
|
|
5
|
+
export default ChartWidget;
|
|
6
|
+
//# sourceMappingURL=ChartWidget.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChartWidget.svelte.d.ts","sourceRoot":"","sources":["../../../../src/components/overview/widgets/ChartWidget.svelte.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,KAAK,eAAe,EAAY,MAAM,WAAW,CAAC;AAoG3D,QAAA,MAAM,WAAW,2EAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* Metric widget (#3727): one number with an optional caption and change. It
|
|
4
|
+
* renders from the loaded data only; the loader decides what the number means.
|
|
5
|
+
*/
|
|
6
|
+
import { useI18n } from '@happyvertical/smrt-ui/i18n';
|
|
7
|
+
import { M } from '../../../i18n/strings.overview.js';
|
|
8
|
+
import { formatWidgetValue } from '../format.js';
|
|
9
|
+
import { safeHref } from '../markdown.js';
|
|
10
|
+
import type { WidgetComponentProps } from '../types.js';
|
|
11
|
+
import { isRecord, type MetricWidgetData } from './data.js';
|
|
12
|
+
|
|
13
|
+
let { data, locale }: WidgetComponentProps<MetricWidgetData> = $props();
|
|
14
|
+
|
|
15
|
+
const { t } = useI18n();
|
|
16
|
+
const metric = $derived(isRecord(data) ? data : null);
|
|
17
|
+
const valid = $derived(
|
|
18
|
+
metric !== null &&
|
|
19
|
+
typeof metric.value === 'number' &&
|
|
20
|
+
Number.isFinite(metric.value),
|
|
21
|
+
);
|
|
22
|
+
const text = $derived(
|
|
23
|
+
valid && metric
|
|
24
|
+
? formatWidgetValue(metric.value, {
|
|
25
|
+
format: metric.format,
|
|
26
|
+
currency: metric.currency,
|
|
27
|
+
locale,
|
|
28
|
+
})
|
|
29
|
+
: '',
|
|
30
|
+
);
|
|
31
|
+
const change = $derived(
|
|
32
|
+
metric && typeof metric.change === 'number' && Number.isFinite(metric.change)
|
|
33
|
+
? metric.change
|
|
34
|
+
: null,
|
|
35
|
+
);
|
|
36
|
+
const changeText = $derived(
|
|
37
|
+
change === null || change === 0
|
|
38
|
+
? ''
|
|
39
|
+
: t(
|
|
40
|
+
M[
|
|
41
|
+
change > 0
|
|
42
|
+
? 'ui.overview.metric.change_up'
|
|
43
|
+
: 'ui.overview.metric.change_down'
|
|
44
|
+
],
|
|
45
|
+
{
|
|
46
|
+
value: formatWidgetValue(Math.abs(change) / 100, {
|
|
47
|
+
format: 'percent',
|
|
48
|
+
locale,
|
|
49
|
+
}),
|
|
50
|
+
},
|
|
51
|
+
),
|
|
52
|
+
);
|
|
53
|
+
const href = $derived(
|
|
54
|
+
metric && typeof metric.href === 'string' ? safeHref(metric.href) : null,
|
|
55
|
+
);
|
|
56
|
+
</script>
|
|
57
|
+
|
|
58
|
+
{#if valid && metric}
|
|
59
|
+
<div class="smrt-metric">
|
|
60
|
+
{#if href}
|
|
61
|
+
<a class="smrt-metric__value" {href}>{text}</a>
|
|
62
|
+
{:else}
|
|
63
|
+
<p class="smrt-metric__value">{text}</p>
|
|
64
|
+
{/if}
|
|
65
|
+
{#if typeof metric.label === 'string' && metric.label}
|
|
66
|
+
<p class="smrt-metric__label">{metric.label}</p>
|
|
67
|
+
{/if}
|
|
68
|
+
{#if changeText}
|
|
69
|
+
<p class="smrt-metric__change" data-direction={(change ?? 0) > 0 ? 'up' : 'down'}>
|
|
70
|
+
<span aria-hidden="true">{(change ?? 0) > 0 ? '▲' : '▼'}</span>
|
|
71
|
+
{changeText}
|
|
72
|
+
</p>
|
|
73
|
+
{/if}
|
|
74
|
+
</div>
|
|
75
|
+
{:else}
|
|
76
|
+
<p class="smrt-metric__label">{t(M['ui.overview.no_data'])}</p>
|
|
77
|
+
{/if}
|
|
78
|
+
|
|
79
|
+
<style>
|
|
80
|
+
.smrt-metric { display: grid; gap: var(--smrt-spacing-1); }
|
|
81
|
+
.smrt-metric__value { margin: 0; color: var(--smrt-color-on-surface); font-size: var(--smrt-typography-display-small-size, 2rem); font-weight: var(--smrt-typography-weight-medium, 500); line-height: 1.1; text-decoration: none; font-variant-numeric: tabular-nums; }
|
|
82
|
+
a.smrt-metric__value:hover { text-decoration: underline; }
|
|
83
|
+
a.smrt-metric__value:focus-visible { outline: 2px solid var(--smrt-color-primary); outline-offset: 2px; border-radius: var(--smrt-radius-small, 0.25rem); }
|
|
84
|
+
.smrt-metric__label { margin: 0; color: var(--smrt-color-on-surface-variant); font-size: var(--smrt-typography-body-medium-size, 0.875rem); }
|
|
85
|
+
.smrt-metric__change { margin: 0; color: var(--smrt-color-on-surface-variant); font-size: var(--smrt-typography-label-large-size, 0.875rem); }
|
|
86
|
+
</style>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { WidgetComponentProps } from '../types.js';
|
|
2
|
+
import { type MetricWidgetData } from './data.js';
|
|
3
|
+
declare const MetricWidget: import("svelte").Component<WidgetComponentProps<MetricWidgetData>, {}, "">;
|
|
4
|
+
type MetricWidget = ReturnType<typeof MetricWidget>;
|
|
5
|
+
export default MetricWidget;
|
|
6
|
+
//# sourceMappingURL=MetricWidget.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MetricWidget.svelte.d.ts","sourceRoot":"","sources":["../../../../src/components/overview/widgets/MetricWidget.svelte.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAY,KAAK,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAiF5D,QAAA,MAAM,YAAY,4EAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* Note widget (#3727): sanitized Markdown from the `body` option. It renders
|
|
4
|
+
* a parsed node tree as Svelte elements, never `{@html}`, so stored text
|
|
5
|
+
* cannot inject markup or an unsafe link.
|
|
6
|
+
*/
|
|
7
|
+
import { useI18n } from '@happyvertical/smrt-ui/i18n';
|
|
8
|
+
import { M } from '../../../i18n/strings.overview.js';
|
|
9
|
+
import { type InlineNode, parseMarkdown } from '../markdown.js';
|
|
10
|
+
import type { WidgetComponentProps } from '../types.js';
|
|
11
|
+
|
|
12
|
+
let { options }: WidgetComponentProps = $props();
|
|
13
|
+
|
|
14
|
+
const { t } = useI18n();
|
|
15
|
+
const blocks = $derived(
|
|
16
|
+
parseMarkdown(typeof options.body === 'string' ? options.body : ''),
|
|
17
|
+
);
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
{#snippet inline(nodes: InlineNode[])}
|
|
21
|
+
{#each nodes as node, index (index)}
|
|
22
|
+
{#if node.type === 'text'}{node.text}{:else if node.type === 'code'}<code>{node.text}</code>{:else if node.type === 'strong'}<strong>{@render inline(node.children)}</strong>{:else if node.type === 'em'}<em>{@render inline(node.children)}</em>{:else if node.type === 'link'}<a href={node.href} rel="noopener noreferrer">{@render inline(node.children)}</a>{/if}
|
|
23
|
+
{/each}
|
|
24
|
+
{/snippet}
|
|
25
|
+
|
|
26
|
+
{#if blocks.length === 0}
|
|
27
|
+
<p class="smrt-note__empty">{t(M['ui.overview.no_data'])}</p>
|
|
28
|
+
{:else}
|
|
29
|
+
<div class="smrt-note">
|
|
30
|
+
{#each blocks as block, index (index)}
|
|
31
|
+
{#if block.type === 'heading'}
|
|
32
|
+
<p class="smrt-note__heading" data-level={block.level}><strong>{@render inline(block.children)}</strong></p>
|
|
33
|
+
{:else if block.type === 'paragraph'}
|
|
34
|
+
<p>{@render inline(block.children)}</p>
|
|
35
|
+
{:else if block.type === 'quote'}
|
|
36
|
+
<blockquote>{@render inline(block.children)}</blockquote>
|
|
37
|
+
{:else if block.type === 'list'}
|
|
38
|
+
{#if block.ordered}
|
|
39
|
+
<ol>{#each block.items as item, i (i)}<li>{@render inline(item)}</li>{/each}</ol>
|
|
40
|
+
{:else}
|
|
41
|
+
<ul>{#each block.items as item, i (i)}<li>{@render inline(item)}</li>{/each}</ul>
|
|
42
|
+
{/if}
|
|
43
|
+
{:else if block.type === 'code'}
|
|
44
|
+
<pre><code>{block.text}</code></pre>
|
|
45
|
+
{/if}
|
|
46
|
+
{/each}
|
|
47
|
+
</div>
|
|
48
|
+
{/if}
|
|
49
|
+
|
|
50
|
+
<style>
|
|
51
|
+
.smrt-note { display: grid; gap: var(--smrt-spacing-2); color: var(--smrt-color-on-surface); font-size: var(--smrt-typography-body-medium-size, 0.875rem); overflow-wrap: anywhere; }
|
|
52
|
+
.smrt-note p, .smrt-note ul, .smrt-note ol, .smrt-note blockquote, .smrt-note pre { margin: 0; }
|
|
53
|
+
.smrt-note ul, .smrt-note ol { padding-inline-start: var(--smrt-spacing-5, 1.25rem); }
|
|
54
|
+
.smrt-note blockquote { padding-inline-start: var(--smrt-spacing-3); border-inline-start: 3px solid var(--smrt-color-outline-variant); color: var(--smrt-color-on-surface-variant); }
|
|
55
|
+
.smrt-note pre { overflow-x: auto; padding: var(--smrt-spacing-2); border-radius: var(--smrt-radius-small, 0.25rem); background: var(--smrt-color-surface-container); }
|
|
56
|
+
.smrt-note code { font-family: var(--smrt-font-family-mono, ui-monospace, monospace); }
|
|
57
|
+
.smrt-note a { color: var(--smrt-color-primary); }
|
|
58
|
+
.smrt-note__heading[data-level='1'] { font-size: var(--smrt-typography-title-large-size, 1.25rem); }
|
|
59
|
+
.smrt-note__heading[data-level='2'] { font-size: var(--smrt-typography-title-medium-size, 1.125rem); }
|
|
60
|
+
.smrt-note__empty { margin: 0; color: var(--smrt-color-on-surface-variant); }
|
|
61
|
+
</style>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { WidgetComponentProps } from '../types.js';
|
|
2
|
+
declare const NoteWidget: import("svelte").Component<WidgetComponentProps<unknown>, {}, "">;
|
|
3
|
+
type NoteWidget = ReturnType<typeof NoteWidget>;
|
|
4
|
+
export default NoteWidget;
|
|
5
|
+
//# sourceMappingURL=NoteWidget.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NoteWidget.svelte.d.ts","sourceRoot":"","sources":["../../../../src/components/overview/widgets/NoteWidget.svelte.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAmDxD,QAAA,MAAM,UAAU,mEAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* Record list widget (#3727): the rows a loader chose, each optionally a
|
|
4
|
+
* link. The loader owns which field is the title and which records the viewer
|
|
5
|
+
* may see; the widget only draws what it is given.
|
|
6
|
+
*/
|
|
7
|
+
import { useI18n } from '@happyvertical/smrt-ui/i18n';
|
|
8
|
+
import { M } from '../../../i18n/strings.overview.js';
|
|
9
|
+
import { safeHref } from '../markdown.js';
|
|
10
|
+
import type { WidgetComponentProps } from '../types.js';
|
|
11
|
+
import { isRecord, type RecordListWidgetData } from './data.js';
|
|
12
|
+
|
|
13
|
+
let { data, locale }: WidgetComponentProps<RecordListWidgetData> = $props();
|
|
14
|
+
|
|
15
|
+
const { t } = useI18n();
|
|
16
|
+
const MAX_ROWS = 50;
|
|
17
|
+
|
|
18
|
+
interface Row {
|
|
19
|
+
id: string;
|
|
20
|
+
title: string;
|
|
21
|
+
subtitle?: string;
|
|
22
|
+
meta?: string;
|
|
23
|
+
href: string | null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const rows = $derived.by((): Row[] => {
|
|
27
|
+
if (!isRecord(data) || !Array.isArray(data.rows)) return [];
|
|
28
|
+
const out: Row[] = [];
|
|
29
|
+
for (const row of data.rows.slice(0, MAX_ROWS)) {
|
|
30
|
+
if (!isRecord(row) || typeof row.title !== 'string') continue;
|
|
31
|
+
out.push({
|
|
32
|
+
id: typeof row.id === 'string' ? row.id : String(out.length),
|
|
33
|
+
title: row.title,
|
|
34
|
+
subtitle: typeof row.subtitle === 'string' ? row.subtitle : undefined,
|
|
35
|
+
meta: typeof row.meta === 'string' ? row.meta : undefined,
|
|
36
|
+
href: typeof row.href === 'string' ? safeHref(row.href) : null,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
return out;
|
|
40
|
+
});
|
|
41
|
+
const total = $derived(
|
|
42
|
+
isRecord(data) && typeof data.total === 'number' && data.total > rows.length
|
|
43
|
+
? data.total
|
|
44
|
+
: null,
|
|
45
|
+
);
|
|
46
|
+
const viewAll = $derived(
|
|
47
|
+
isRecord(data) && typeof data.href === 'string' ? safeHref(data.href) : null,
|
|
48
|
+
);
|
|
49
|
+
</script>
|
|
50
|
+
|
|
51
|
+
{#if rows.length === 0}
|
|
52
|
+
<p class="smrt-records__empty">{t(M['ui.overview.records.empty'])}</p>
|
|
53
|
+
{:else}
|
|
54
|
+
<ul class="smrt-records">
|
|
55
|
+
{#each rows as row (row.id)}
|
|
56
|
+
<li class="smrt-records__row">
|
|
57
|
+
<span class="smrt-records__main">
|
|
58
|
+
{#if row.href}
|
|
59
|
+
<a class="smrt-records__title" href={row.href}>{row.title}</a>
|
|
60
|
+
{:else}
|
|
61
|
+
<span class="smrt-records__title">{row.title}</span>
|
|
62
|
+
{/if}
|
|
63
|
+
{#if row.subtitle}<span class="smrt-records__sub">{row.subtitle}</span>{/if}
|
|
64
|
+
</span>
|
|
65
|
+
{#if row.meta}<span class="smrt-records__meta">{row.meta}</span>{/if}
|
|
66
|
+
</li>
|
|
67
|
+
{/each}
|
|
68
|
+
</ul>
|
|
69
|
+
{/if}
|
|
70
|
+
{#if total !== null || viewAll}
|
|
71
|
+
<p class="smrt-records__foot">
|
|
72
|
+
{#if total !== null}
|
|
73
|
+
<span>{t(M['ui.overview.records.total'], { count: new Intl.NumberFormat(locale).format(total) })}</span>
|
|
74
|
+
{/if}
|
|
75
|
+
{#if viewAll}<a href={viewAll}>{t(M['ui.overview.records.view_all'])}</a>{/if}
|
|
76
|
+
</p>
|
|
77
|
+
{/if}
|
|
78
|
+
|
|
79
|
+
<style>
|
|
80
|
+
.smrt-records { display: grid; margin: 0; padding: 0; list-style: none; }
|
|
81
|
+
.smrt-records__row { display: flex; align-items: baseline; justify-content: space-between; gap: var(--smrt-spacing-3); padding: var(--smrt-spacing-2) 0; border-block-end: 1px solid var(--smrt-color-outline-variant); }
|
|
82
|
+
.smrt-records__row:last-child { border-block-end: 0; }
|
|
83
|
+
.smrt-records__main { display: grid; min-inline-size: 0; }
|
|
84
|
+
.smrt-records__title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--smrt-color-on-surface); font-weight: var(--smrt-typography-weight-medium, 500); text-decoration: none; }
|
|
85
|
+
a.smrt-records__title:hover { text-decoration: underline; }
|
|
86
|
+
.smrt-records__sub, .smrt-records__meta { color: var(--smrt-color-on-surface-variant); font-size: var(--smrt-typography-body-medium-size, 0.875rem); }
|
|
87
|
+
.smrt-records__meta { flex: 0 0 auto; font-variant-numeric: tabular-nums; }
|
|
88
|
+
.smrt-records__foot { display: flex; justify-content: space-between; gap: var(--smrt-spacing-3); margin: var(--smrt-spacing-2) 0 0; color: var(--smrt-color-on-surface-variant); font-size: var(--smrt-typography-body-medium-size, 0.875rem); }
|
|
89
|
+
.smrt-records__foot a { color: var(--smrt-color-primary); }
|
|
90
|
+
.smrt-records__empty { margin: 0; color: var(--smrt-color-on-surface-variant); }
|
|
91
|
+
</style>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { WidgetComponentProps } from '../types.js';
|
|
2
|
+
import { type RecordListWidgetData } from './data.js';
|
|
3
|
+
declare const RecordListWidget: import("svelte").Component<WidgetComponentProps<RecordListWidgetData>, {}, "">;
|
|
4
|
+
type RecordListWidget = ReturnType<typeof RecordListWidget>;
|
|
5
|
+
export default RecordListWidget;
|
|
6
|
+
//# sourceMappingURL=RecordListWidget.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RecordListWidget.svelte.d.ts","sourceRoot":"","sources":["../../../../src/components/overview/widgets/RecordListWidget.svelte.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAY,KAAK,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAgFhE,QAAA,MAAM,gBAAgB,gFAAwC,CAAC;AAC/D,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC5D,eAAe,gBAAgB,CAAC"}
|