@runwisp/ui 0.13.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +39 -47
- package/src/astro/CTABand.astro +19 -12
- package/src/astro/Hero.astro +3 -3
- package/src/astro/SiteFooter.astro +4 -4
- package/src/astro/SiteHeader.astro +4 -4
- package/src/lib/actions/portal.ts +0 -3
- package/src/lib/assets/runwisp-logo.svg +1 -8
- package/src/lib/components/AccordionItem.svelte +4 -10
- package/src/lib/components/Alert.svelte +11 -11
- package/src/lib/components/Avatar.svelte +1 -1
- package/src/lib/components/Badge.svelte +13 -13
- package/src/lib/components/Breadcrumb.svelte +3 -3
- package/src/lib/components/Button.svelte +2 -2
- package/src/lib/components/Card.svelte +4 -4
- package/src/lib/components/Checkbox.svelte +12 -10
- package/src/lib/components/CodeBlock.svelte +7 -13
- package/src/lib/components/CronInput.svelte +12 -15
- package/src/lib/components/DataGrid.svelte +14 -13
- package/src/lib/components/Drawer.svelte +9 -9
- package/src/lib/components/Dropdown.svelte +12 -20
- package/src/lib/components/DurationInput.svelte +10 -14
- package/src/lib/components/EmptyState.svelte +1 -1
- package/src/lib/components/ErrorState.svelte +4 -4
- package/src/lib/components/FeatureCard.svelte +4 -4
- package/src/lib/components/FormField.svelte +4 -6
- package/src/lib/components/Heading.svelte +4 -1
- package/src/lib/components/Input.svelte +10 -12
- package/src/lib/components/Kbd.svelte +1 -1
- package/src/lib/components/Link.svelte +2 -3
- package/src/lib/components/LinkButton.svelte +2 -2
- package/src/lib/components/LogConsole.svelte +22 -21
- package/src/lib/components/Logo.svelte +3 -1
- package/src/lib/components/Modal.svelte +9 -11
- package/src/lib/components/PageContainer.svelte +1 -1
- package/src/lib/components/PageHeader.svelte +1 -1
- package/src/lib/components/Pagination.svelte +4 -4
- package/src/lib/components/Popover.svelte +5 -7
- package/src/lib/components/Progress.svelte +6 -4
- package/src/lib/components/Prose.svelte +4 -4
- package/src/lib/components/Radio.svelte +11 -10
- package/src/lib/components/RadioGroup.svelte +3 -5
- package/src/lib/components/Select.svelte +23 -36
- package/src/lib/components/Separator.svelte +4 -1
- package/src/lib/components/Skeleton.svelte +6 -6
- package/src/lib/components/StatusIndicator.svelte +7 -18
- package/src/lib/components/Table.svelte +1 -1
- package/src/lib/components/TableCell.svelte +1 -1
- package/src/lib/components/TableRow.svelte +1 -5
- package/src/lib/components/Tabs.svelte +10 -13
- package/src/lib/components/TaskCard.svelte +7 -4
- package/src/lib/components/Textarea.svelte +10 -11
- package/src/lib/components/ThemeToggle.svelte +1 -1
- package/src/lib/components/ToastContainer.svelte +3 -8
- package/src/lib/components/Toggle.svelte +2 -3
- package/src/lib/components/Tooltip.svelte +12 -10
- package/src/lib/components/button-styles.ts +17 -18
- package/src/lib/components/dashboard/RunDetailPanel.svelte +160 -249
- package/src/lib/components/dashboard/RunFilterPopover.svelte +31 -25
- package/src/lib/components/dashboard/RunsList.svelte +55 -50
- package/src/lib/components/dashboard/run-filters.test.ts +31 -33
- package/src/lib/components/dashboard/run-filters.ts +33 -33
- package/src/lib/components/dashboard/run-helpers.test.ts +42 -17
- package/src/lib/components/dashboard/run-helpers.ts +53 -17
- package/src/lib/components/dashboard/status-config.ts +9 -8
- package/src/lib/theme-tokens.css +179 -114
- package/src/lib/theme.css +49 -35
- package/src/lib/utils/error.ts +0 -3
- package/src/lib/utils/format.test.ts +2 -6
- package/src/lib/utils/format.ts +28 -3
package/src/lib/theme-tokens.css
CHANGED
|
@@ -17,8 +17,26 @@
|
|
|
17
17
|
* - apps/ui toggles the `.dark` class on <html>.
|
|
18
18
|
* - Starlight (apps/docs) writes data-theme="dark" on the documentElement.
|
|
19
19
|
* The union selector covers both. Light mode is the default.
|
|
20
|
+
*
|
|
21
|
+
* Webfonts are @imported here (not in theme.css) so every consumer that reads
|
|
22
|
+
* these tokens also gets the faces they name — apps/docs imports this file
|
|
23
|
+
* alone. Both families ship in the binary; nothing is fetched from a CDN.
|
|
20
24
|
*/
|
|
21
25
|
|
|
26
|
+
@import "@fontsource/tasa-orbiter/400.css";
|
|
27
|
+
@import "@fontsource/tasa-orbiter/500.css";
|
|
28
|
+
@import "@fontsource/tasa-orbiter/600.css";
|
|
29
|
+
@import "@fontsource/tasa-orbiter/700.css";
|
|
30
|
+
@import "@fontsource-variable/geist-mono/index.css";
|
|
31
|
+
|
|
32
|
+
:root {
|
|
33
|
+
/* Typography — body sans for prose, mono for all chrome and identifiers.
|
|
34
|
+
* Geist Mono is variable (100–900), so heading weight 800 is a real cut. */
|
|
35
|
+
--rw-font-sans: "TASA Orbiter", system-ui, -apple-system, sans-serif;
|
|
36
|
+
--rw-font-mono:
|
|
37
|
+
"Geist Mono Variable", "Geist Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
38
|
+
}
|
|
39
|
+
|
|
22
40
|
:root {
|
|
23
41
|
/* Primary — Wisp Teal (brand = #0E7C86, the artifact's deep teal). Deeper
|
|
24
42
|
* and less cyan than Aurora (running/info) so the two stay distinct. */
|
|
@@ -46,20 +64,21 @@
|
|
|
46
64
|
--rw-color-aurora-800: oklch(0.35 0.07 192);
|
|
47
65
|
--rw-color-aurora-900: oklch(0.28 0.055 192);
|
|
48
66
|
|
|
49
|
-
/* Mist —
|
|
50
|
-
* #
|
|
51
|
-
*
|
|
52
|
-
|
|
53
|
-
--rw-color-mist-
|
|
54
|
-
--rw-color-mist-
|
|
55
|
-
--rw-color-mist-
|
|
56
|
-
--rw-color-mist-
|
|
57
|
-
--rw-color-mist-
|
|
58
|
-
--rw-color-mist-
|
|
59
|
-
--rw-color-mist-
|
|
60
|
-
--rw-color-mist-
|
|
61
|
-
--rw-color-mist-
|
|
62
|
-
--rw-color-mist-
|
|
67
|
+
/* Mist — teal-gray neutrals (the runbook's #F3F6F6 / #E0E7E7 /
|
|
68
|
+
* #14262A / #0C1719 family). No purple tint; hue ~195-205, low chroma,
|
|
69
|
+
* so bg-mist-* utilities agree with the new teal-black surfaces. The light
|
|
70
|
+
* end stays near-neutral to match the desaturated canvas. */
|
|
71
|
+
--rw-color-mist-50: oklch(0.972 0.003 200); /* ≈ #F3F6F6 */
|
|
72
|
+
--rw-color-mist-100: oklch(0.945 0.004 200); /* ≈ #E9EEEE */
|
|
73
|
+
--rw-color-mist-200: oklch(0.925 0.005 200); /* ≈ #E0E7E7 */
|
|
74
|
+
--rw-color-mist-300: oklch(0.83 0.016 198);
|
|
75
|
+
--rw-color-mist-400: oklch(0.676 0.02 200);
|
|
76
|
+
--rw-color-mist-500: oklch(0.6 0.022 200);
|
|
77
|
+
--rw-color-mist-600: oklch(0.531 0.024 202);
|
|
78
|
+
--rw-color-mist-700: oklch(0.42 0.024 203);
|
|
79
|
+
--rw-color-mist-800: oklch(0.32 0.024 204);
|
|
80
|
+
--rw-color-mist-900: oklch(0.266 0.025 204); /* ≈ #16292B */
|
|
81
|
+
--rw-color-mist-950: oklch(0.195 0.016 208); /* ≈ #0C1719 */
|
|
63
82
|
|
|
64
83
|
/* Success — Field Green (success status = #1F9D57, a true grass green) */
|
|
65
84
|
--rw-color-success-50: oklch(0.97 0.02 150);
|
|
@@ -112,8 +131,11 @@
|
|
|
112
131
|
--rw-ansi-bright-cyan: var(--rw-color-aurora-300);
|
|
113
132
|
--rw-ansi-bright-white: var(--rw-color-mist-50);
|
|
114
133
|
|
|
115
|
-
/*
|
|
116
|
-
*
|
|
134
|
+
/* Fixed-dark sibling palettes — the `--rw-con-*` log console (a "black box"
|
|
135
|
+
* device) and the `--rw-term-*`/`--rw-syn-*` website terminal surfaces both
|
|
136
|
+
* keep their own dark palette in BOTH themes; they never flip light/dark. */
|
|
137
|
+
|
|
138
|
+
/* Console device surface — the log console instrument.
|
|
117
139
|
* Exact values from the approved execution-detail design. */
|
|
118
140
|
--rw-con-bg: #0e141b; /* body / gutter backing */
|
|
119
141
|
--rw-con-panel: #11181f; /* toolbar + footer chrome */
|
|
@@ -121,62 +143,97 @@
|
|
|
121
143
|
--rw-con-dim: #6c7d8c; /* footer + muted readouts */
|
|
122
144
|
--rw-con-gutter: #3c4a58; /* line numbers + sentinel rule */
|
|
123
145
|
|
|
124
|
-
/*
|
|
146
|
+
/* Terminal surface — always dark in both themes (website --term-* set) */
|
|
147
|
+
--rw-term: #0a1116;
|
|
148
|
+
--rw-term-2: #0d151b;
|
|
149
|
+
--rw-term-line: #1d2932;
|
|
150
|
+
--rw-term-line-2: #2a3a45;
|
|
151
|
+
--rw-term-text: #dbe6ec;
|
|
152
|
+
--rw-term-muted: #7d919c;
|
|
153
|
+
--rw-term-faint: #566873;
|
|
154
|
+
--rw-term-teal: #2fd4dd;
|
|
155
|
+
--rw-term-ok: #3fc26b;
|
|
156
|
+
--rw-term-warn: #e0a52e;
|
|
157
|
+
--rw-term-bad: #f15a4d;
|
|
158
|
+
/* Syntax highlighting */
|
|
159
|
+
--rw-syn-comment: #5b6b75;
|
|
160
|
+
--rw-syn-kw: #79c7ff;
|
|
161
|
+
--rw-syn-str: #7fd6a0;
|
|
162
|
+
--rw-syn-num: #e0a52e;
|
|
163
|
+
--rw-syn-punc: #9aa7b0;
|
|
164
|
+
--rw-syn-fn: #2fd4dd;
|
|
165
|
+
|
|
166
|
+
/* Elevation — light-mode drop shadows; flipped to `none` in dark so the
|
|
167
|
+
* UI reads as borders-only there. */
|
|
168
|
+
--rw-shadow-xs: 0 1px 2px rgba(16, 41, 43, 0.04);
|
|
169
|
+
--rw-shadow-sm: 0 1px 2px rgba(16, 41, 43, 0.04), 0 12px 28px -20px rgba(16, 41, 43, 0.22);
|
|
170
|
+
--rw-shadow-md: 0 1px 2px rgba(16, 41, 43, 0.06), 0 22px 44px -26px rgba(16, 41, 43, 0.4);
|
|
171
|
+
--rw-shadow-lg: 0 1px 2px rgba(16, 41, 43, 0.06), 0 30px 60px -28px rgba(16, 41, 43, 0.45);
|
|
172
|
+
--rw-shadow-xl: 0 1px 2px rgba(16, 41, 43, 0.06), 0 40px 80px -30px rgba(16, 41, 43, 0.5);
|
|
173
|
+
|
|
174
|
+
/* Light-mode semantic tokens (default) — runbook palette (exact hex).
|
|
175
|
+
*
|
|
176
|
+
* The canvas carries only a whisper of the brand teal. The website can
|
|
177
|
+
* afford a minty `--ground` because dark panes and terminals cover most
|
|
178
|
+
* of it; in a dashboard the canvas is most of the pixels, and a saturated
|
|
179
|
+
* mint under white panels reads washed-out. Structure comes from the
|
|
180
|
+
* hairline outlines, not from tinting the page. */
|
|
125
181
|
/* Surfaces */
|
|
126
|
-
--rw-surface:
|
|
127
|
-
--rw-surface-raised:
|
|
128
|
-
--rw-surface-
|
|
129
|
-
--rw-surface-
|
|
182
|
+
--rw-surface: #f3f6f6;
|
|
183
|
+
--rw-surface-raised: #ffffff;
|
|
184
|
+
--rw-surface-sunken: #e9eeee;
|
|
185
|
+
--rw-surface-overlay: #ffffff;
|
|
130
186
|
/* On-surface text */
|
|
131
|
-
--rw-on-surface:
|
|
132
|
-
--rw-on-surface-muted:
|
|
133
|
-
--rw-on-surface-faint:
|
|
187
|
+
--rw-on-surface: #14262a;
|
|
188
|
+
--rw-on-surface-muted: #5a6d70;
|
|
189
|
+
--rw-on-surface-faint: #869798;
|
|
134
190
|
/* Borders / outlines */
|
|
135
|
-
--rw-outline:
|
|
136
|
-
--rw-outline-hover:
|
|
137
|
-
--rw-outline-faint:
|
|
138
|
-
--rw-ring:
|
|
139
|
-
--rw-backdrop:
|
|
191
|
+
--rw-outline: #e0e7e7;
|
|
192
|
+
--rw-outline-hover: #c8d2d2;
|
|
193
|
+
--rw-outline-faint: #edf1f1;
|
|
194
|
+
--rw-ring: #15a0a8;
|
|
195
|
+
--rw-backdrop: rgba(243, 246, 246, 0.78);
|
|
140
196
|
/* Primary */
|
|
141
|
-
--rw-primary:
|
|
142
|
-
--rw-primary-hover:
|
|
143
|
-
--rw-primary-active:
|
|
144
|
-
--rw-on-primary:
|
|
145
|
-
--rw-primary-soft:
|
|
146
|
-
--rw-primary-soft-text:
|
|
147
|
-
|
|
148
|
-
--rw-danger: var(--rw-color-danger-600);
|
|
149
|
-
--rw-danger-hover: var(--rw-color-danger-700);
|
|
150
|
-
--rw-danger-active: var(--rw-color-danger-800);
|
|
151
|
-
--rw-on-danger: white;
|
|
152
|
-
--rw-danger-soft: var(--rw-color-danger-50);
|
|
153
|
-
--rw-danger-soft-text: var(--rw-color-danger-700);
|
|
197
|
+
--rw-primary: #15a0a8;
|
|
198
|
+
--rw-primary-hover: #0e7c86;
|
|
199
|
+
--rw-primary-active: #0a6068;
|
|
200
|
+
--rw-on-primary: #ffffff;
|
|
201
|
+
--rw-primary-soft: rgba(21, 160, 168, 0.1);
|
|
202
|
+
--rw-primary-soft-text: #15a0a8;
|
|
203
|
+
--rw-primary-soft-border: rgba(21, 160, 168, 0.25);
|
|
154
204
|
/* Success */
|
|
155
|
-
--rw-success:
|
|
156
|
-
--rw-success-hover:
|
|
157
|
-
--rw-
|
|
158
|
-
--rw-success
|
|
159
|
-
--rw-success-soft
|
|
205
|
+
--rw-success: #1e8a4a;
|
|
206
|
+
--rw-success-hover: #1a753e;
|
|
207
|
+
--rw-success-active: #156033;
|
|
208
|
+
--rw-on-success: #ffffff;
|
|
209
|
+
--rw-success-soft: rgba(30, 138, 74, 0.1);
|
|
210
|
+
--rw-success-soft-text: #1e8a4a;
|
|
211
|
+
--rw-success-soft-border: rgba(30, 138, 74, 0.25);
|
|
212
|
+
/* Danger */
|
|
213
|
+
--rw-danger: #d6453d;
|
|
214
|
+
--rw-danger-hover: #b8352b;
|
|
215
|
+
--rw-danger-active: #9a2a22;
|
|
216
|
+
--rw-on-danger: #ffffff;
|
|
217
|
+
--rw-danger-soft: rgba(214, 69, 61, 0.1);
|
|
218
|
+
--rw-danger-soft-text: #d6453d;
|
|
219
|
+
--rw-danger-soft-border: rgba(214, 69, 61, 0.25);
|
|
160
220
|
/* Warning */
|
|
161
|
-
--rw-warning:
|
|
162
|
-
--rw-warning-hover:
|
|
163
|
-
--rw-
|
|
164
|
-
--rw-warning
|
|
165
|
-
--rw-warning-soft
|
|
166
|
-
|
|
167
|
-
--rw-
|
|
168
|
-
|
|
169
|
-
--rw-
|
|
170
|
-
--rw-info-
|
|
171
|
-
--rw-info
|
|
172
|
-
|
|
173
|
-
--rw-
|
|
174
|
-
--rw-
|
|
175
|
-
--rw-success-soft-border: var(--rw-color-success-200);
|
|
176
|
-
--rw-warning-soft-border: var(--rw-color-warning-200);
|
|
177
|
-
--rw-info-soft-border: var(--rw-color-aurora-200);
|
|
221
|
+
--rw-warning: #c4781a;
|
|
222
|
+
--rw-warning-hover: #a36414;
|
|
223
|
+
--rw-warning-active: #82500f;
|
|
224
|
+
--rw-on-warning: #ffffff;
|
|
225
|
+
--rw-warning-soft: rgba(196, 120, 26, 0.1);
|
|
226
|
+
--rw-warning-soft-text: #c4781a;
|
|
227
|
+
--rw-warning-soft-border: rgba(196, 120, 26, 0.25);
|
|
228
|
+
/* Info — matches primary teal */
|
|
229
|
+
--rw-info: #15a0a8;
|
|
230
|
+
--rw-info-hover: #0e7c86;
|
|
231
|
+
--rw-on-info: #ffffff;
|
|
232
|
+
--rw-info-soft: rgba(21, 160, 168, 0.1);
|
|
233
|
+
--rw-info-soft-text: #15a0a8;
|
|
234
|
+
--rw-info-soft-border: rgba(21, 160, 168, 0.25);
|
|
178
235
|
/* Glass */
|
|
179
|
-
--rw-glass:
|
|
236
|
+
--rw-glass: rgba(255, 255, 255, 0.78);
|
|
180
237
|
--rw-glass-blur: blur(12px);
|
|
181
238
|
}
|
|
182
239
|
|
|
@@ -184,58 +241,66 @@
|
|
|
184
241
|
* attribute for Starlight. Both selectors apply the same token set. */
|
|
185
242
|
:root.dark,
|
|
186
243
|
:root[data-theme="dark"] {
|
|
187
|
-
|
|
188
|
-
--rw-surface
|
|
189
|
-
--rw-surface-
|
|
190
|
-
--rw-surface-sunken:
|
|
191
|
-
--rw-
|
|
192
|
-
|
|
193
|
-
--rw-on-surface
|
|
194
|
-
--rw-
|
|
195
|
-
--rw-
|
|
196
|
-
|
|
197
|
-
--rw-
|
|
198
|
-
--rw-
|
|
199
|
-
|
|
200
|
-
--rw-
|
|
201
|
-
--rw-
|
|
202
|
-
|
|
203
|
-
--rw-
|
|
204
|
-
--rw-primary-
|
|
205
|
-
--rw-primary-
|
|
206
|
-
|
|
207
|
-
--rw-
|
|
208
|
-
--rw-
|
|
209
|
-
--rw-
|
|
210
|
-
--rw-on-danger: white;
|
|
211
|
-
--rw-danger-soft: oklch(0.2 0.04 355);
|
|
212
|
-
--rw-danger-soft-text: var(--rw-color-danger-300);
|
|
244
|
+
/* Surfaces */
|
|
245
|
+
--rw-surface: #0c1719;
|
|
246
|
+
--rw-surface-raised: #122226;
|
|
247
|
+
--rw-surface-sunken: #080f11;
|
|
248
|
+
--rw-surface-overlay: rgba(8, 15, 17, 0.86);
|
|
249
|
+
/* On-surface text */
|
|
250
|
+
--rw-on-surface: #e8eff4;
|
|
251
|
+
--rw-on-surface-muted: #94a6b1;
|
|
252
|
+
--rw-on-surface-faint: #5f7079;
|
|
253
|
+
/* Borders / outlines */
|
|
254
|
+
--rw-outline: #1d2932;
|
|
255
|
+
--rw-outline-hover: #2a3a45;
|
|
256
|
+
--rw-outline-faint: #1d2932;
|
|
257
|
+
--rw-ring: #2fd4dd;
|
|
258
|
+
--rw-backdrop: rgba(4, 10, 12, 0.7);
|
|
259
|
+
/* Primary — bright teal in dark, matches info */
|
|
260
|
+
--rw-primary: #2fd4dd;
|
|
261
|
+
--rw-primary-hover: #5fe3ea;
|
|
262
|
+
--rw-primary-active: #5fe3ea;
|
|
263
|
+
--rw-on-primary: #04181a;
|
|
264
|
+
--rw-primary-soft: rgba(21, 160, 168, 0.14);
|
|
265
|
+
--rw-primary-soft-text: #2fd4dd;
|
|
266
|
+
--rw-primary-soft-border: rgba(47, 212, 221, 0.28);
|
|
213
267
|
/* Success */
|
|
214
|
-
--rw-success:
|
|
215
|
-
--rw-success-hover:
|
|
216
|
-
--rw-on-success:
|
|
217
|
-
--rw-success-soft:
|
|
218
|
-
--rw-success-soft-text:
|
|
268
|
+
--rw-success: #3fc26b;
|
|
269
|
+
--rw-success-hover: #5fd487;
|
|
270
|
+
--rw-on-success: #04181a;
|
|
271
|
+
--rw-success-soft: rgba(63, 194, 107, 0.14);
|
|
272
|
+
--rw-success-soft-text: #3fc26b;
|
|
273
|
+
--rw-success-soft-border: rgba(63, 194, 107, 0.28);
|
|
274
|
+
/* Danger */
|
|
275
|
+
--rw-danger: #f15a4d;
|
|
276
|
+
--rw-danger-hover: #ff7568;
|
|
277
|
+
--rw-danger-active: #ff8a7e;
|
|
278
|
+
--rw-on-danger: #04181a;
|
|
279
|
+
--rw-danger-soft: rgba(241, 90, 77, 0.14);
|
|
280
|
+
--rw-danger-soft-text: #f15a4d;
|
|
281
|
+
--rw-danger-soft-border: rgba(241, 90, 77, 0.28);
|
|
219
282
|
/* Warning */
|
|
220
|
-
--rw-warning:
|
|
221
|
-
--rw-warning-hover:
|
|
222
|
-
--rw-on-warning:
|
|
223
|
-
--rw-warning-soft:
|
|
224
|
-
--rw-warning-soft-text:
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
--rw-info
|
|
228
|
-
--rw-
|
|
229
|
-
--rw-info
|
|
230
|
-
--rw-info-soft
|
|
231
|
-
|
|
232
|
-
--rw-
|
|
233
|
-
--rw-danger-soft-border: oklch(0.32 0.06 355);
|
|
234
|
-
--rw-success-soft-border: oklch(0.32 0.06 165);
|
|
235
|
-
--rw-warning-soft-border: oklch(0.32 0.06 85);
|
|
236
|
-
--rw-info-soft-border: oklch(0.32 0.06 180);
|
|
283
|
+
--rw-warning: #e0a52e;
|
|
284
|
+
--rw-warning-hover: #ecb845;
|
|
285
|
+
--rw-on-warning: #04181a;
|
|
286
|
+
--rw-warning-soft: rgba(224, 165, 46, 0.14);
|
|
287
|
+
--rw-warning-soft-text: #e0a52e;
|
|
288
|
+
--rw-warning-soft-border: rgba(224, 165, 46, 0.28);
|
|
289
|
+
/* Info — bright teal in dark */
|
|
290
|
+
--rw-info: #2fd4dd;
|
|
291
|
+
--rw-info-hover: #5fe3ea;
|
|
292
|
+
--rw-on-info: #04181a;
|
|
293
|
+
--rw-info-soft: rgba(47, 212, 221, 0.14);
|
|
294
|
+
--rw-info-soft-text: #2fd4dd;
|
|
295
|
+
--rw-info-soft-border: rgba(47, 212, 221, 0.28);
|
|
237
296
|
/* Glass */
|
|
238
|
-
--rw-glass:
|
|
297
|
+
--rw-glass: rgba(8, 15, 17, 0.9);
|
|
298
|
+
/* Elevation — borders-only in dark, no drop shadow */
|
|
299
|
+
--rw-shadow-xs: none;
|
|
300
|
+
--rw-shadow-sm: none;
|
|
301
|
+
--rw-shadow-md: none;
|
|
302
|
+
--rw-shadow-lg: none;
|
|
303
|
+
--rw-shadow-xl: none;
|
|
239
304
|
}
|
|
240
305
|
|
|
241
306
|
/* Platform polish — focus ring, text selection, scrollbar. Lifted from
|
package/src/lib/theme.css
CHANGED
|
@@ -14,10 +14,6 @@
|
|
|
14
14
|
|
|
15
15
|
@import "tailwindcss";
|
|
16
16
|
@import "./theme-tokens.css";
|
|
17
|
-
@import "@fontsource/tasa-orbiter/400.css";
|
|
18
|
-
@import "@fontsource/tasa-orbiter/500.css";
|
|
19
|
-
@import "@fontsource/tasa-orbiter/600.css";
|
|
20
|
-
@import "@fontsource/tasa-orbiter/700.css";
|
|
21
17
|
|
|
22
18
|
@plugin "@tailwindcss/forms";
|
|
23
19
|
@plugin "@tailwindcss/typography";
|
|
@@ -87,9 +83,10 @@
|
|
|
87
83
|
--color-warning-600: var(--rw-color-warning-600);
|
|
88
84
|
--color-warning-700: var(--rw-color-warning-700);
|
|
89
85
|
|
|
90
|
-
/* Typography
|
|
91
|
-
|
|
92
|
-
--font-
|
|
86
|
+
/* Typography — stacks and @font-face live in theme-tokens.css so the
|
|
87
|
+
* non-Tailwind consumers (apps/docs) share one definition. */
|
|
88
|
+
--font-sans: var(--rw-font-sans);
|
|
89
|
+
--font-mono: var(--rw-font-mono);
|
|
93
90
|
|
|
94
91
|
/* Font sizes */
|
|
95
92
|
--text-2xs: 0.625rem;
|
|
@@ -125,31 +122,24 @@
|
|
|
125
122
|
--spacing-20: 5rem;
|
|
126
123
|
--spacing-24: 6rem;
|
|
127
124
|
|
|
128
|
-
/* Border radius
|
|
125
|
+
/* Border radius — runbook scale (small radii are signature). lg/xl/2xl/3xl
|
|
126
|
+
* remain for legacy call sites but should not be used going forward. */
|
|
129
127
|
--radius-none: 0;
|
|
130
|
-
--radius-sm: 0.
|
|
131
|
-
--radius-md: 0.
|
|
128
|
+
--radius-sm: 0.1875rem; /* 3px — controls */
|
|
129
|
+
--radius-md: 0.25rem; /* 4px — panels / cards */
|
|
132
130
|
--radius-lg: 0.5rem;
|
|
133
131
|
--radius-xl: 0.75rem;
|
|
134
132
|
--radius-2xl: 1rem;
|
|
135
133
|
--radius-3xl: 1.5rem;
|
|
136
134
|
--radius-full: 9999px;
|
|
137
135
|
|
|
138
|
-
/* Shadows —
|
|
139
|
-
|
|
140
|
-
--shadow-
|
|
141
|
-
|
|
142
|
-
--shadow-md:
|
|
143
|
-
|
|
144
|
-
--shadow-
|
|
145
|
-
0 10px 15px -3px oklch(0.18 0.02 280 / 0.08), 0 4px 6px -4px oklch(0.18 0.02 280 / 0.08);
|
|
146
|
-
--shadow-xl:
|
|
147
|
-
0 20px 25px -5px oklch(0.18 0.02 280 / 0.1), 0 8px 10px -6px oklch(0.18 0.02 280 / 0.1);
|
|
148
|
-
|
|
149
|
-
/* Glow effects for wisp theme */
|
|
150
|
-
--shadow-glow-sm: 0 0 10px oklch(0.58 0.18 270 / 0.15);
|
|
151
|
-
--shadow-glow-md: 0 0 20px oklch(0.58 0.18 270 / 0.2);
|
|
152
|
-
--shadow-glow-lg: 0 0 30px oklch(0.58 0.18 270 / 0.25);
|
|
136
|
+
/* Shadows — mapped to the flip tokens in theme-tokens.css so every
|
|
137
|
+
* shadow-* utility resolves to `none` in dark (borders-only look). */
|
|
138
|
+
--shadow-xs: var(--rw-shadow-xs);
|
|
139
|
+
--shadow-sm: var(--rw-shadow-sm);
|
|
140
|
+
--shadow-md: var(--rw-shadow-md);
|
|
141
|
+
--shadow-lg: var(--rw-shadow-lg);
|
|
142
|
+
--shadow-xl: var(--rw-shadow-xl);
|
|
153
143
|
}
|
|
154
144
|
|
|
155
145
|
/* Semantic Design Tokens — Tailwind utility aliases.
|
|
@@ -212,14 +202,30 @@
|
|
|
212
202
|
--color-warning-soft-border: var(--rw-warning-soft-border);
|
|
213
203
|
--color-info-soft-border: var(--rw-info-soft-border);
|
|
214
204
|
|
|
215
|
-
/*
|
|
216
|
-
--
|
|
217
|
-
--
|
|
218
|
-
--
|
|
205
|
+
/* Terminal surface — fixed dark in both themes */
|
|
206
|
+
--color-term: var(--rw-term);
|
|
207
|
+
--color-term-2: var(--rw-term-2);
|
|
208
|
+
--color-term-line: var(--rw-term-line);
|
|
209
|
+
--color-term-line-2: var(--rw-term-line-2);
|
|
210
|
+
--color-term-text: var(--rw-term-text);
|
|
211
|
+
--color-term-muted: var(--rw-term-muted);
|
|
212
|
+
--color-term-faint: var(--rw-term-faint);
|
|
213
|
+
--color-term-teal: var(--rw-term-teal);
|
|
214
|
+
--color-term-ok: var(--rw-term-ok);
|
|
215
|
+
--color-term-warn: var(--rw-term-warn);
|
|
216
|
+
--color-term-bad: var(--rw-term-bad);
|
|
217
|
+
/* Syntax highlighting */
|
|
218
|
+
--color-syn-comment: var(--rw-syn-comment);
|
|
219
|
+
--color-syn-kw: var(--rw-syn-kw);
|
|
220
|
+
--color-syn-str: var(--rw-syn-str);
|
|
221
|
+
--color-syn-num: var(--rw-syn-num);
|
|
222
|
+
--color-syn-punc: var(--rw-syn-punc);
|
|
223
|
+
--color-syn-fn: var(--rw-syn-fn);
|
|
219
224
|
|
|
220
|
-
/*
|
|
221
|
-
|
|
222
|
-
|
|
225
|
+
/* Motion. Deliberately minimal: hover, focus and state changes are
|
|
226
|
+
* instant, so there is no scale of durations to pick from. The few things
|
|
227
|
+
* that still move — a drawer sliding, a toggle knob, an accordion's
|
|
228
|
+
* height, a progress bar's width — set their own timing inline. */
|
|
223
229
|
--ease-out: cubic-bezier(0, 0, 0.2, 1);
|
|
224
230
|
}
|
|
225
231
|
|
|
@@ -245,6 +251,17 @@ body {
|
|
|
245
251
|
color: var(--rw-on-surface);
|
|
246
252
|
}
|
|
247
253
|
|
|
254
|
+
/* Headings are mono chrome — the runbook voice. Components should not fight this. */
|
|
255
|
+
h1,
|
|
256
|
+
h2,
|
|
257
|
+
h3 {
|
|
258
|
+
font-family: var(--font-mono);
|
|
259
|
+
font-weight: 800;
|
|
260
|
+
line-height: 1.1;
|
|
261
|
+
letter-spacing: -0.02em;
|
|
262
|
+
text-wrap: balance;
|
|
263
|
+
}
|
|
264
|
+
|
|
248
265
|
/* Utility classes for the design system */
|
|
249
266
|
.rw-text-gradient {
|
|
250
267
|
background: linear-gradient(135deg, var(--rw-color-wisp-600), var(--rw-color-aurora-500));
|
|
@@ -278,9 +295,6 @@ body {
|
|
|
278
295
|
}
|
|
279
296
|
}
|
|
280
297
|
|
|
281
|
-
.btn-scale {
|
|
282
|
-
transition: all 0.15s ease-in-out;
|
|
283
|
-
}
|
|
284
298
|
.btn-scale:active {
|
|
285
299
|
transform: scale(0.97);
|
|
286
300
|
}
|
package/src/lib/utils/error.ts
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: PoppyCake, s.r.o.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* Extracts a human-readable message from an unknown caught value.
|
|
6
|
-
*/
|
|
7
4
|
export function extractErrorMessage(
|
|
8
5
|
err: unknown,
|
|
9
6
|
fallback = "An unexpected error occurred",
|
|
@@ -124,12 +124,8 @@ describe("formatRelativeTimeWithAbsolute", () => {
|
|
|
124
124
|
describe("formatRelativeTime", () => {
|
|
125
125
|
it("advances as the supplied now advances", () => {
|
|
126
126
|
const date = new Date("2024-01-01T12:00:00Z");
|
|
127
|
-
expect(formatRelativeTime(date, new Date("2024-01-01T14:00:00Z"))).toBe(
|
|
128
|
-
|
|
129
|
-
);
|
|
130
|
-
expect(formatRelativeTime(date, new Date("2024-01-01T15:00:00Z"))).toBe(
|
|
131
|
-
"about 3 hours ago",
|
|
132
|
-
);
|
|
127
|
+
expect(formatRelativeTime(date, new Date("2024-01-01T14:00:00Z"))).toBe("2 hours ago");
|
|
128
|
+
expect(formatRelativeTime(date, new Date("2024-01-01T15:00:00Z"))).toBe("3 hours ago");
|
|
133
129
|
});
|
|
134
130
|
});
|
|
135
131
|
|
package/src/lib/utils/format.ts
CHANGED
|
@@ -1,7 +1,32 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: PoppyCake, s.r.o.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
// Signed magnitude thresholds for Intl.RelativeTimeFormat, largest-first
|
|
5
|
+
// division. Mirrors the buckets date-fns' formatDistance used to pick.
|
|
6
|
+
const RELATIVE_DIVISIONS: [amount: number, unit: Intl.RelativeTimeFormatUnit][] = [
|
|
7
|
+
[60, "seconds"],
|
|
8
|
+
[60, "minutes"],
|
|
9
|
+
[24, "hours"],
|
|
10
|
+
[7, "days"],
|
|
11
|
+
[4.34524, "weeks"],
|
|
12
|
+
[12, "months"],
|
|
13
|
+
[Number.POSITIVE_INFINITY, "years"],
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
// formatDistance renders a signed date delta as "N units ago" / "in N units"
|
|
17
|
+
// using the platform Intl formatter. Negative delta (date before base) reads as
|
|
18
|
+
// past, positive as future.
|
|
19
|
+
function formatDistance(date: Date, base: Date): string {
|
|
20
|
+
const rtf = new Intl.RelativeTimeFormat(undefined, { numeric: "always" });
|
|
21
|
+
let delta = (date.getTime() - base.getTime()) / 1000;
|
|
22
|
+
for (const [amount, unit] of RELATIVE_DIVISIONS) {
|
|
23
|
+
if (Math.abs(delta) < amount) {
|
|
24
|
+
return rtf.format(Math.round(delta), unit);
|
|
25
|
+
}
|
|
26
|
+
delta /= amount;
|
|
27
|
+
}
|
|
28
|
+
return rtf.format(Math.round(delta), "years");
|
|
29
|
+
}
|
|
5
30
|
|
|
6
31
|
export function formatBytes(bytes: number): string {
|
|
7
32
|
const units: [string, ...string[]] = ["B", "KB", "MB", "GB", "TB", "PB"];
|
|
@@ -17,7 +42,7 @@ export function formatBytes(bytes: number): string {
|
|
|
17
42
|
}
|
|
18
43
|
|
|
19
44
|
export function formatRelativeTime(dateStr: string | Date, now: Date = new Date()): string {
|
|
20
|
-
return formatDistance(new Date(dateStr), now
|
|
45
|
+
return formatDistance(new Date(dateStr), now);
|
|
21
46
|
}
|
|
22
47
|
|
|
23
48
|
export function formatRelativeTimeWithAbsolute(
|
|
@@ -25,7 +50,7 @@ export function formatRelativeTimeWithAbsolute(
|
|
|
25
50
|
now: Date = new Date(),
|
|
26
51
|
): string {
|
|
27
52
|
const date = new Date(dateStr);
|
|
28
|
-
const relative = formatDistance(date, now
|
|
53
|
+
const relative = formatDistance(date, now);
|
|
29
54
|
const diffMs = Math.abs(now.getTime() - date.getTime());
|
|
30
55
|
const diffDays = diffMs / (1000 * 60 * 60 * 24);
|
|
31
56
|
|