@momoi-labs/kiso 0.1.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.
Files changed (73) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +63 -0
  3. package/kiso/AGENTS.md +50 -0
  4. package/kiso/README.md +62 -0
  5. package/kiso/docs/accessibility.md +87 -0
  6. package/kiso/docs/brand.md +95 -0
  7. package/kiso/docs/components/README.md +58 -0
  8. package/kiso/docs/components/alert.md +158 -0
  9. package/kiso/docs/components/badge.md +135 -0
  10. package/kiso/docs/components/breadcrumb.md +66 -0
  11. package/kiso/docs/components/button.md +168 -0
  12. package/kiso/docs/components/card.md +154 -0
  13. package/kiso/docs/components/checkbox.md +91 -0
  14. package/kiso/docs/components/command-palette.md +165 -0
  15. package/kiso/docs/components/drawer.md +79 -0
  16. package/kiso/docs/components/dropdown-menu.md +178 -0
  17. package/kiso/docs/components/empty-state.md +142 -0
  18. package/kiso/docs/components/form-field.md +115 -0
  19. package/kiso/docs/components/header.md +79 -0
  20. package/kiso/docs/components/helper-text.md +86 -0
  21. package/kiso/docs/components/icon-button.md +161 -0
  22. package/kiso/docs/components/input.md +99 -0
  23. package/kiso/docs/components/label.md +88 -0
  24. package/kiso/docs/components/link.md +152 -0
  25. package/kiso/docs/components/modal-dialog.md +82 -0
  26. package/kiso/docs/components/navigation.md +68 -0
  27. package/kiso/docs/components/page-header.md +70 -0
  28. package/kiso/docs/components/pagination.md +129 -0
  29. package/kiso/docs/components/popover.md +74 -0
  30. package/kiso/docs/components/search.md +147 -0
  31. package/kiso/docs/components/select.md +105 -0
  32. package/kiso/docs/components/sidebar.md +74 -0
  33. package/kiso/docs/components/skeleton.md +140 -0
  34. package/kiso/docs/components/spinner.md +125 -0
  35. package/kiso/docs/components/switch.md +92 -0
  36. package/kiso/docs/components/table.md +255 -0
  37. package/kiso/docs/components/tabs.md +69 -0
  38. package/kiso/docs/components/textarea.md +91 -0
  39. package/kiso/docs/components/toast.md +80 -0
  40. package/kiso/docs/components/tooltip.md +162 -0
  41. package/kiso/docs/components/validation-message.md +96 -0
  42. package/kiso/docs/data-interfaces.md +309 -0
  43. package/kiso/docs/evolution.md +35 -0
  44. package/kiso/docs/patterns/README.md +40 -0
  45. package/kiso/docs/patterns/application-shell.md +106 -0
  46. package/kiso/docs/patterns/command-palette.md +142 -0
  47. package/kiso/docs/patterns/confirmations.md +158 -0
  48. package/kiso/docs/patterns/crud.md +139 -0
  49. package/kiso/docs/patterns/dashboard.md +102 -0
  50. package/kiso/docs/patterns/destructive-actions.md +137 -0
  51. package/kiso/docs/patterns/developer-oriented-interfaces.md +162 -0
  52. package/kiso/docs/patterns/empty-states.md +76 -0
  53. package/kiso/docs/patterns/errors.md +93 -0
  54. package/kiso/docs/patterns/filtering.md +147 -0
  55. package/kiso/docs/patterns/keyboard-shortcuts.md +155 -0
  56. package/kiso/docs/patterns/large-data-tables.md +182 -0
  57. package/kiso/docs/patterns/list-detail.md +118 -0
  58. package/kiso/docs/patterns/loading.md +80 -0
  59. package/kiso/docs/patterns/login-authentication.md +101 -0
  60. package/kiso/docs/patterns/onboarding.md +94 -0
  61. package/kiso/docs/patterns/pagination.md +121 -0
  62. package/kiso/docs/patterns/permission-denied.md +84 -0
  63. package/kiso/docs/patterns/search.md +150 -0
  64. package/kiso/docs/patterns/settings.md +100 -0
  65. package/kiso/docs/patterns/sorting.md +121 -0
  66. package/kiso/docs/principles.md +122 -0
  67. package/kiso/docs/tokens.md +95 -0
  68. package/kiso/docs/voice-and-tone.md +154 -0
  69. package/package.json +42 -0
  70. package/tokens/build/tokens.css +143 -0
  71. package/tokens/build/tokens.d.ts +160 -0
  72. package/tokens/build/tokens.json +88 -0
  73. package/tokens/build/tokens.scss +89 -0
@@ -0,0 +1,142 @@
1
+ # Command palette
2
+
3
+ Keyboard-driven global navigation and actions. This pattern composes the
4
+ [CommandPalette](../components/command-palette.md) component as the app-wide
5
+ "do or go anywhere" surface, invoked by a documented shortcut, filtering
6
+ commands and destinations as the person types.
7
+
8
+ User story #23.
9
+
10
+ ## Purpose
11
+
12
+ The command palette lets a person run frequent actions and jump to destinations
13
+ without hunting through menus: open a query editor, jump to a replica, switch
14
+ project, run a saved action. It is keyboard-first, invoked by a shortcut, and
15
+ filters a command list as the person types.
16
+
17
+ It is **not** list [Search](search.md) (which filters content in view) and not
18
+ a [DropdownMenu](../components/dropdown-menu.md) (which is contextual to one
19
+ trigger). The palette is global.
20
+
21
+ ## Component composition
22
+
23
+ | Region | Compose with | Role |
24
+ | --- | --- | --- |
25
+ | Overlay | [CommandPalette](../components/command-palette.md) dialog surface | Modal or non-modal elevated panel |
26
+ | Filter input | CommandPalette Input (autofocused) | Filters commands as the person types |
27
+ | Command list | CommandPalette List with Groups + Items | Actions and destinations, grouped |
28
+ | Empty | CommandPalette in-palette empty message | "No commands match 'xyz'" — not page-level EmptyState |
29
+ | Footer hints | optional keyboard legend | Reminds the person of `Enter`, `↑↓`, `Esc` |
30
+ | Explicit trigger | [Button](../components/button.md) or [IconButton](../components/icon-button.md) in [Header](../components/header.md) | Opens the same palette for non-keyboard users |
31
+
32
+ ## Flow
33
+
34
+ 1. Person presses `⌘K` (macOS) / `Ctrl+K` (Windows/Linux), or activates the
35
+ explicit trigger in the header.
36
+ 2. The palette opens; focus moves to the Input. The list shows all commands
37
+ (or a default group).
38
+ 3. Person types. The list filters as they type (search-as-you-type).
39
+ 4. Person navigates with `↑` / `↓` across groups; the highlighted item is the
40
+ active descendant.
41
+ 5. Person activates with `Enter` (or click). The command runs or navigation
42
+ occurs, and the palette closes.
43
+ 6. `Escape` closes without activating. Focus returns to the previously focused
44
+ element (or the trigger).
45
+
46
+ If the chosen command is a [destructive action](destructive-actions.md), the
47
+ palette closes and a [confirmation](confirmations.md) dialog opens — the palette
48
+ is acceleration, not a bypass for the gate.
49
+
50
+ ## States
51
+
52
+ | State | Behavior |
53
+ | --- | --- |
54
+ | closed | Palette not in tree (or inert). Shortcut and explicit trigger available. |
55
+ | open | Input focused; list visible; focus trapped within the palette (if modal). |
56
+ | filtering | List updates as the person types. Active descendant resets to the first match. |
57
+ | no matches | In-palette empty message: "No commands match 'xyz'". Not the page-level [EmptyState](../components/empty-state.md). |
58
+ | loading | Optional [Spinner](../components/spinner.md) in the list while command providers resolve. Input stays usable. `aria-busy` on the list. |
59
+ | error | Provider failure: short in-palette message or [Alert](../components/alert.md) pattern inside the panel. Do not fail silently to an empty list that looks like "no matches". |
60
+
61
+ ## Layout sketch
62
+
63
+ ```text
64
+ ┌──────────────────────────────────────────────┐
65
+ │ ⌘K Type a command or destination… │
66
+ ├──────────────────────────────────────────────┤
67
+ │ Navigation │
68
+ │ ▸ Queries │
69
+ │ Replicas │
70
+ │ Settings │
71
+ │ Replicas │
72
+ │ ▸ Open prod-eu │
73
+ │ Open staging │
74
+ │ Open analytics │
75
+ │ Actions │
76
+ │ ▸ New query │
77
+ │ Switch project │
78
+ │ Refresh all replicas │
79
+ ├──────────────────────────────────────────────┤
80
+ │ ↑↓ navigate ↵ run esc close │
81
+ └──────────────────────────────────────────────┘
82
+ ```
83
+
84
+ The palette is centered or top-anchored, elevated (`--color-elevated-surface`,
85
+ `--shadow-sm`, `--radius-lg`). The active (highlighted) item uses a quiet
86
+ `--color-surface` or `--color-primary` indicator — not a filled primary row.
87
+
88
+ ## Rules
89
+
90
+ - **Invocation:** default `⌘K` / `Ctrl+K`, documented in product chrome. Do
91
+ not bind list [Search](search.md) fields to this shortcut.
92
+ - **One app-level palette.** Do not ship separate palettes per page unless the
93
+ product truly scopes commands. Default is one palette with groups
94
+ (Navigation, Replicas, Actions, Settings).
95
+ - **Commands vs destinations.** Both live in the palette. Destinations navigate
96
+ (open a route); commands run an action (new query, switch project). Group
97
+ them so the person can scan.
98
+ - **Shortcut hints** in items are decorative unless they document real bindings.
99
+ If an item shows `⌘N`, that binding must work even when the palette is closed.
100
+ - **Destructive commands still confirm.** A "Delete replica" command closes the
101
+ palette and opens a [confirmation](confirmations.md) dialog — it does not
102
+ delete on `Enter` from the palette.
103
+ - **Discoverability:** the palette is acceleration, not the only path. Critical
104
+ actions still need a visible control somewhere (header, page action, row
105
+ menu). Do not hide a primary action only in the palette.
106
+ - **Explicit trigger:** provide a [Button](../components/button.md) or
107
+ [IconButton](../components/icon-button.md) in the
108
+ [Header](../components/header.md) ("Search commands…") that opens the same
109
+ palette, so non-keyboard users can reach it.
110
+ - Do not use the palette for form data entry. It is not a form.
111
+
112
+ ## Accessibility
113
+
114
+ - Prefer a modal dialog pattern (`role="dialog"`, `aria-modal="true"`) with
115
+ an accessible name ("Command palette").
116
+ - Input has a visible or programmatically associated label.
117
+ - List uses `role="listbox"` (or cmdk's list semantics) with items as options;
118
+ the active item is exposed via `aria-activedescendant` on the Input — do not
119
+ invent a broken tab-per-item list.
120
+ - Focus moves to the Input on open; on close, focus returns to the previously
121
+ focused element (or the trigger).
122
+ - `Escape` closes without running a command.
123
+ - Reduced motion: no gratuitous entrance animation beyond token durations.
124
+
125
+ ### Keyboard
126
+
127
+ | Key | Action |
128
+ | --- | --- |
129
+ | `⌘K` / `Ctrl+K` | Toggle open/close. |
130
+ | Printable keys | Filter commands (input focused). |
131
+ | `↑` / `↓` | Move highlight through items (and across groups). |
132
+ | `Enter` | Activate highlighted item. |
133
+ | `Escape` | Close without activating. |
134
+ | `Tab` | Stays within the palette (focus trap) while open; do not tab into the page behind a modal palette. |
135
+
136
+ ## Related patterns
137
+
138
+ - [Search](search.md) — filters content in view; the palette is global actions.
139
+ - [Keyboard shortcuts](keyboard-shortcuts.md) — the palette's `⌘K` is one
140
+ shortcut; this pattern covers the rest.
141
+ - [Destructive actions](destructive-actions.md) — palette commands that are
142
+ destructive still confirm.
@@ -0,0 +1,158 @@
1
+ # Confirmations
2
+
3
+ Explain risk and require explicit acknowledgment before a consequential action.
4
+ This pattern is the dialog spec for any confirmation — destructive or not —
5
+ covering copy structure, focus, and the acknowledgment model. Destructive
6
+ actions ([destructive-actions](destructive-actions.md)) always use this pattern;
7
+ not every confirmation is destructive.
8
+
9
+ User story #12.
10
+
11
+ ## Purpose
12
+
13
+ A confirmation interrupts the person before an action whose consequence is
14
+ non-obvious, delayed, or hard to reverse: disconnect a live connection, apply a
15
+ config change to production, revoke access, overwrite a resource. The
16
+ confirmation makes the consequence explicit and requires a deliberate choice.
17
+
18
+ It is not a courtesy "are you sure?" for routine actions. Over-confirming
19
+ trains the person to click through without reading; reserve confirmations for
20
+ genuine risk.
21
+
22
+ ## Component composition
23
+
24
+ | Region | Compose with | Role |
25
+ | --- | --- | --- |
26
+ | Dialog | [Modal / Dialog](../components/modal-dialog.md) | Blocks the page; focused task |
27
+ | Title | Dialog Title | Names the action in product language ("Disconnect 'staging-db'?") |
28
+ | Consequence | Dialog Description | What will happen, in plain language |
29
+ | Confirm action | [Button](../components/button.md) — variant matches stakes | Commits the action |
30
+ | Cancel action | [Button](../components/button.md) `default` or `ghost` | Closes without committing; always available |
31
+ | Acknowledgment (high-stakes) | [Checkbox](../components/checkbox.md) or type-to-confirm [Input](../components/input.md) | Required before confirm is enabled |
32
+ | Progress | [Spinner](../components/spinner.md) inside confirm Button | While the action is in flight |
33
+
34
+ ## Flow
35
+
36
+ 1. Person activates a trigger that opens the confirmation.
37
+ 2. [Modal / Dialog](../components/modal-dialog.md) opens with focus on the first
38
+ meaningful element (usually Cancel).
39
+ 3. The dialog states the action and its consequence. For high-stakes actions, an
40
+ acknowledgment step (checkbox or type-to-confirm) gates the confirm Button.
41
+ 4. Person confirms or cancels.
42
+ - **Cancel** / `Escape` / overlay click (when safe): dialog closes, focus
43
+ returns to trigger, nothing changes.
44
+ - **Confirm**: Button enters loading; action runs.
45
+ 5. On success, dialog closes and feedback follows ([Toast](../components/toast.md)
46
+ for brief confirmation, navigation if the context changed). On failure,
47
+ error [Alert](../components/alert.md) inside the dialog with recovery.
48
+
49
+ ## States
50
+
51
+ | State | Behavior |
52
+ | --- | --- |
53
+ | closed | Trigger available. |
54
+ | open | Page inert; focus trapped. Cancel available; confirm available or gated. |
55
+ | gated | High-stakes: confirm Button disabled until acknowledgment complete (checkbox checked, or typed name matches). |
56
+ | submitting | Confirm Button loading ([Spinner](../components/spinner.md), `aria-busy`). Cancel available unless uninterruptible. |
57
+ | error | Recoverable error as [Alert](../components/alert.md) inside dialog; dialog stays open. |
58
+ | success | Dialog closes; [Toast](../components/toast.md) or navigation. |
59
+
60
+ ## Copy structure
61
+
62
+ Confirmation copy follows [voice-and-tone](../voice-and-tone.md):
63
+
64
+ - **Title:** Name the action and the object. "Disconnect 'staging-db'?" — not
65
+ "Warning" or "Confirm".
66
+ - **Consequence:** What will happen, in one or two sentences. State the
67
+ irreversibility or side effect directly: "Active queries will be
68
+ terminated." Do not say "Are you absolutely sure?" — state the fact.
69
+ - **Match weight to stakes.** A low-stakes action (leave a draft unsaved) gets
70
+ a neutral dialog. A high-stakes action (drop database) gets type-to-confirm.
71
+ Do not wrap a low-stakes action in danger color, and do not under-state a
72
+ high-stakes one.
73
+
74
+ Anti-patterns (from voice-and-tone):
75
+ - "Are you absolutely sure?"
76
+ - "Oops! Are you sure you want to..."
77
+ - Danger color on a low-stakes confirmation.
78
+ - No consequence stated, only "Confirm / Cancel".
79
+
80
+ ## Layout sketch
81
+
82
+ ### Standard confirmation
83
+
84
+ ```text
85
+ ┌──────────────────────────────────────────┐
86
+ │ Disconnect "staging-db"? │
87
+ │ │
88
+ │ Active queries to this database will be │
89
+ │ terminated. The connection can be │
90
+ │ re-established later. │
91
+ │ │
92
+ │ [Cancel] [Disconnect] │
93
+ └──────────────────────────────────────────┘
94
+ ```
95
+
96
+ ### High-stakes (type-to-confirm)
97
+
98
+ ```text
99
+ ┌──────────────────────────────────────────┐
100
+ │ Drop database "production"? │
101
+ │ │
102
+ │ All tables, data, and replicas in this │
103
+ │ database will be permanently deleted. │
104
+ │ This cannot be undone. │
105
+ │ │
106
+ │ Type the database name to confirm: │
107
+ │ [production ] │
108
+ │ │
109
+ │ [Cancel] [Drop database] │
110
+ └──────────────────────────────────────────┘
111
+ ```
112
+
113
+ `Drop database` stays disabled until "production" is typed exactly. The
114
+ confirm Button is the only destructive-styled control.
115
+
116
+ ## Rules
117
+
118
+ - Confirm only when there is genuine consequence. Routine saves, toggles, and
119
+ navigation do not need confirmation; over-confirmation trains click-through.
120
+ - State the consequence, not a question. "Active queries will be terminated"
121
+ beats "Are you sure you want to disconnect?"
122
+ - The confirm Button's variant matches the stakes:
123
+ - Destructive (delete, drop, purge) → `destructive` variant.
124
+ - Consequential but not destructive (disconnect, revoke, apply to production)
125
+ → `default` variant, possibly with a warning tone in the copy.
126
+ - Low-stakes (discard draft) → `default`.
127
+ - Cancel is always available and is the safe default. Prefer focusing Cancel on
128
+ open.
129
+ - High-stakes actions use acknowledgment:
130
+ - **Checkbox:** "I understand this cannot be undone" — for actions where the
131
+ person must consciously accept irreversibility.
132
+ - **Type-to-confirm:** type the exact resource name — for the highest-stakes
133
+ actions (drop database, delete workspace). Reserve sparingly; overuse makes
134
+ it friction without safety.
135
+ - Do not use [Toast](../components/toast.md) as a confirmation. Toast is
136
+ transient and cannot require a decision. If a decision is needed, it is a
137
+ dialog.
138
+ - Do not auto-confirm after a timeout. The person must explicitly choose.
139
+
140
+ ## Accessibility
141
+
142
+ - Dialog: `role="dialog"`, `aria-modal="true"`, `aria-labelledby`,
143
+ `aria-describedby` (consequence).
144
+ - Focus to first meaningful element on open (usually Cancel). `Tab` /
145
+ `Shift+Tab` cycle inside; `Escape` closes when safe.
146
+ - Confirm Button accessible name includes the action: "Disconnect", "Drop
147
+ database" — not "Confirm".
148
+ - Gated confirm: the disabled Button has an accessible explanation ("Type the
149
+ database name to enable Drop database"). The acknowledgment
150
+ [Checkbox](../components/checkbox.md) or [Input](../components/input.md) has a
151
+ [Label](../components/label.md).
152
+ - On error, move focus to the error [Alert](../components/alert.md) so the
153
+ person lands on the recovery path.
154
+
155
+ ## Related patterns
156
+
157
+ - [Destructive actions](destructive-actions.md) — the specific gate for
158
+ irreversible actions; always uses this confirmation spec.
@@ -0,0 +1,139 @@
1
+ # CRUD
2
+
3
+ Create, read/update, and delete flows for a single entity type. Covers form
4
+ layout, validation, and the create / edit / delete states without inventing
5
+ one-off form kits.
6
+
7
+ User stories #9 and #10.
8
+
9
+ ## Purpose
10
+
11
+ Make every Momoi resource editable the same way: labeled fields, predictable
12
+ primary/secondary actions, field-level validation, and clear success or failure
13
+ feedback. This layout pattern places create/edit surfaces and delete entry
14
+ points; confirmation copy and acknowledgment for irreversible deletes are
15
+ specified separately and must still run before destruction.
16
+
17
+ ## Component composition
18
+
19
+ | Concern | Compose with | Role |
20
+ | --- | --- | --- |
21
+ | Page framing | [PageHeader](../components/page-header.md) | Title ("New connection", "Edit connection"); optional cancel secondary action |
22
+ | Fields | [FormField](../components/form-field.md) | Each field = [Label](../components/label.md) + control ([Input](../components/input.md), [Textarea](../components/textarea.md), [Select](../components/select.md), [Checkbox](../components/checkbox.md), …) + optional [HelperText](../components/helper-text.md) + [ValidationMessage](../components/validation-message.md) |
23
+ | Grouping | [Card](../components/card.md) or section headings | Related field groups (connection, credentials, advanced) |
24
+ | Primary actions | [Button](../components/button.md) | Save / Create (primary); Cancel (secondary/ghost) |
25
+ | Overlays | [Modal / Dialog](../components/modal-dialog.md) or [Drawer](../components/drawer.md) | Compact create/edit; Drawer preferred on small viewports for the same task |
26
+ | Inline errors | [ValidationMessage](../components/validation-message.md) on FormField | Field-level recovery; page [Alert](../components/alert.md) is for non-field failures |
27
+ | Form / load errors | [Alert](../components/alert.md) | Submit or load failures that are not field-local (what / why / now) |
28
+ | Success | [Toast](../components/toast.md) | Brief "Saved" / "Created"; do not rely on Toast alone for blocking failures |
29
+ | Delete entry | Button or [DropdownMenu](../components/dropdown-menu.md) item | Opens confirmation flow; danger styling on the destructive control |
30
+ | Read context | [Badge](../components/badge.md), [Tabs](../components/tabs.md) | Status and sections on edit/detail surfaces |
31
+ | Shell | [Application shell](application-shell.md) | Authenticated framing |
32
+
33
+ Tokens: form surfaces `--color-surface`, canvas `--color-background`, borders
34
+ `--color-border`, text `--color-foreground` / `--color-muted-foreground`,
35
+ invalid fields and ValidationMessage use `--color-danger`, focus
36
+ `--color-focus`, destructive Buttons use `--color-danger` per the Button
37
+ contract.
38
+
39
+ ## Flow
40
+
41
+ ### Create
42
+
43
+ 1. Person activates Create from PageHeader or EmptyState.
44
+ 2. Open full-page form, Modal, or Drawer with empty FormFields.
45
+ 3. Person submits; invalid fields show ValidationMessage and receive focus on
46
+ the first error.
47
+ 4. On success: Toast (optional), navigate to the new entity's detail or list
48
+ selection; close overlay if used.
49
+ 5. On failure: keep the form open; Alert for non-field errors; preserve input.
50
+
51
+ ### Edit
52
+
53
+ 1. Person opens Edit from list-detail actions or a detail PageHeader.
54
+ 2. Form loads current values; read-only identifiers stay visible but not
55
+ editable when the API forbids changes.
56
+ 3. Save enables when the form is dirty (product may also allow explicit Save
57
+ always — be consistent within a product).
58
+ 4. Validation and error handling match Create.
59
+ 5. Cancel discards unsaved changes (confirm only if dirty and loss is material).
60
+
61
+ ### Delete
62
+
63
+ 1. Person chooses Delete from entity actions.
64
+ 2. An explicit confirmation step runs before destruction (Modal/Dialog with
65
+ clear consequences); this layout requires that step, not its microcopy.
66
+ 3. On success: Toast or list refresh; navigate away from a deleted detail.
67
+ 4. On failure: Alert with recovery; entity remains.
68
+
69
+ Prefer Modal/Drawer for short create/edit. Use a full main-page form when the
70
+ field set is long, multi-section, or needs side-by-side reference content.
71
+
72
+ ## States
73
+
74
+ | State | Behavior |
75
+ | --- | --- |
76
+ | loading (edit) | Skeleton for known field layout inside the form surface; do not flash empty Inputs. |
77
+ | empty (create from empty collection) | EmptyState on the list offers Create; CRUD form is the next step — do not reinvent empty handling inside the form. |
78
+ | invalid | ValidationMessage per field; first invalid control focused; do not clear other fields. |
79
+ | submitting | Primary Button loading (Spinner in Button); prevent double submit; Cancel remains available when safe. |
80
+ | error (load) | Alert in the form region (what / why / now); offer retry; Cancel/back remains. |
81
+ | error (submit) | Field errors via ValidationMessage; server/business errors via Alert; form stays open with values preserved. |
82
+ | success | Toast or inline success only as confirmation; navigate or refresh per flow above. |
83
+
84
+ ## Layout sketch
85
+
86
+ Full-page create/edit:
87
+
88
+ ```text
89
+ ┌──────────────────────────────────────────────────────────────────────┐
90
+ │ PageHeader: Edit connection [Cancel] [Save] │
91
+ ├──────────────────────────────────────────────────────────────────────┤
92
+ │ Alert (only if submit/load error — what / why / now) │
93
+ │ │
94
+ │ Card: Connection │
95
+ │ FormField Name │
96
+ │ FormField Host │
97
+ │ FormField Port │
98
+ │ │
99
+ │ Card: Credentials │
100
+ │ FormField User │
101
+ │ FormField Password │
102
+ │ FormField SSL [Select] │
103
+ │ │
104
+ │ [Cancel] [Save] │
105
+ └──────────────────────────────────────────────────────────────────────┘
106
+ ```
107
+
108
+ Modal create (compact):
109
+
110
+ ```text
111
+ ┌─────────────────────────────────┐
112
+ │ New connection [✕] │
113
+ │ │
114
+ │ FormField Name │
115
+ │ FormField Host │
116
+ │ FormField Port │
117
+ │ │
118
+ │ [Cancel] [Create] │
119
+ └─────────────────────────────────┘
120
+ ```
121
+
122
+ ## When to use
123
+
124
+ - Any resource with create and/or edit forms.
125
+ - Delete entry points on list rows or detail headers.
126
+
127
+ ## When NOT to use
128
+
129
+ - Immediate boolean preferences without a Save affordance — prefer Switch
130
+ inside [Settings](settings.md).
131
+ - Bulk multi-entity editors — extend list-detail selection + confirmed bulk
132
+ actions instead of a single CRUD form.
133
+
134
+ ## Related patterns
135
+
136
+ - [List-detail](list-detail.md) — where Create and row actions usually live.
137
+ List EmptyState still follows the canonical rule: do not reinvent search,
138
+ filters, pagination, or empty state on the way into Create.
139
+ - [Settings](settings.md) — preference forms with explicit save sections.
@@ -0,0 +1,102 @@
1
+ # Dashboard
2
+
3
+ A scan-first overview of several related metrics or summaries on one page.
4
+ Widgets share density and hierarchy rules; the page is not a junk drawer of
5
+ unrelated Cards.
6
+
7
+ User story #30.
8
+
9
+ ## Purpose
10
+
11
+ Orient the person quickly: what needs attention, what is healthy, and where to
12
+ go next. Dashboards summarize; deep investigation happens in list-detail,
13
+ tables, or dedicated tool routes.
14
+
15
+ ## Component composition
16
+
17
+ | Region | Compose with | Role |
18
+ | --- | --- | --- |
19
+ | Page framing | [PageHeader](../components/page-header.md) | Dashboard title; optional time-range or environment [Select](../components/select.md); optional refresh [IconButton](../components/icon-button.md) / [Button](../components/button.md) |
20
+ | Widget unit | [Card](../components/card.md) | One concern per Card (metric cluster, short table, status list) |
21
+ | Status | [Badge](../components/badge.md) | Compact health/severity labels inside Cards |
22
+ | Dense lists | [Table / DataTable](../components/table.md) | Short "needs attention" tables — still compose Search/EmptyState/Pagination only when those behaviors are truly present |
23
+ | Alerts | [Alert](../components/alert.md) | Page-level degraded conditions that outrank widgets |
24
+ | Navigation out | [Link](../components/link.md) | "View all" from a widget into list-detail or a tool |
25
+ | Shell | [Application shell](application-shell.md) | Header + Sidebar + main |
26
+
27
+ **Canonical rule (when a widget is a list):** A list screen must not reinvent
28
+ search, filters, pagination, and empty state. A dashboard widget that embeds a
29
+ mini-list still uses EmptyState and Table composition — it does not invent a
30
+ third list pattern.
31
+
32
+ Tokens: page canvas `--color-background`, widgets `--color-surface` with
33
+ `--color-border`, titles `--color-foreground`, supporting
34
+ `--color-muted-foreground`, emphasis `--color-primary`, status via Badge
35
+ semantic colors, focus `--color-focus`. Prefer quiet surfaces and strong
36
+ hierarchy ([principles](../principles.md)).
37
+
38
+ Charts are out of scope for this epic; when charts exist later, they sit inside
39
+ Card like any other widget payload.
40
+
41
+ ## Flow
42
+
43
+ 1. Person opens Overview / Dashboard from Sidebar.
44
+ 2. PageHeader establishes scope (product area, optional range/environment).
45
+ 3. Widgets load independently when possible so one slow tile does not block the
46
+ whole page.
47
+ 4. Person scans Badges and summary numbers, then follows a Link into a deeper
48
+ list-detail or tool view.
49
+ 5. Refresh updates widget data without remounting the application shell.
50
+
51
+ Keep widget count deliberate. If a Card has no job beyond decoration, remove
52
+ it.
53
+
54
+ ## States
55
+
56
+ | State | Behavior |
57
+ | --- | --- |
58
+ | loading | Per-widget Skeleton that preserves Card size; PageHeader stays. Avoid a single full-page Spinner unless the dashboard has no known layout yet. |
59
+ | empty (no data in a widget) | EmptyState inside that Card only ("No failing checks") with optional Link; other widgets remain. |
60
+ | empty (product not configured) | One page-level [EmptyState](../components/empty-state.md) with a clear next action instead of a grid of hollow Cards. |
61
+ | error (one widget) | Alert or error content inside that Card with retry; siblings keep working. |
62
+ | error (page) | Alert under PageHeader (what / why / now); widgets may still show last-known content if labeled stale. |
63
+
64
+ ## Layout sketch
65
+
66
+ ```text
67
+ ┌──────────────────────────────────────────────────────────────────────┐
68
+ │ PageHeader: Overview [Environment▾] [Refresh] │
69
+ ├──────────────────────────────────────────────────────────────────────┤
70
+ │ Alert (optional page-level condition) │
71
+ │ │
72
+ │ ┌───────────────┐ ┌───────────────┐ ┌───────────────────────────────┐│
73
+ │ │ Card: Health │ │ Card: Lag │ │ Card: Connections ││
74
+ │ │ [Badge ok] │ │ 18 ms │ │ active 12 · idle 3 ││
75
+ │ │ 4 / 4 up │ │ p95 │ │ [View connections →] ││
76
+ │ └───────────────┘ └───────────────┘ └───────────────────────────────┘│
77
+ │ │
78
+ │ ┌──────────────────────────────────────────────────────────────────┐ │
79
+ │ │ Card: Needs attention │ │
80
+ │ │ Table: Name | Issue | Since │ │
81
+ │ │ … short rows … │ │
82
+ │ │ EmptyState if none │ │
83
+ │ └──────────────────────────────────────────────────────────────────┘ │
84
+ └──────────────────────────────────────────────────────────────────────┘
85
+ ```
86
+
87
+ ## When to use
88
+
89
+ - Product home / overview routes.
90
+ - Operator glance surfaces that link into deeper tools.
91
+
92
+ ## When NOT to use
93
+
94
+ - The primary working surface for one entity — use [List-detail](list-detail.md).
95
+ - Long configuration forms — use [Settings](settings.md) or [CRUD](crud.md).
96
+ - A single full-height operational table — use list-detail / DataTable, not a
97
+ one-widget "dashboard".
98
+
99
+ ## Related patterns
100
+
101
+ - [Application shell](application-shell.md)
102
+ - [List-detail](list-detail.md) — drill-down target for "View all"