@runwisp/ui 0.12.0 → 0.14.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 (60) hide show
  1. package/package.json +40 -45
  2. package/src/astro/CTABand.astro +19 -12
  3. package/src/astro/Hero.astro +3 -3
  4. package/src/astro/SiteFooter.astro +4 -4
  5. package/src/astro/SiteHeader.astro +4 -4
  6. package/src/lib/assets/runwisp-logo.svg +1 -8
  7. package/src/lib/components/AccordionItem.svelte +4 -10
  8. package/src/lib/components/Alert.svelte +11 -11
  9. package/src/lib/components/Avatar.svelte +1 -1
  10. package/src/lib/components/Badge.svelte +13 -13
  11. package/src/lib/components/Breadcrumb.svelte +3 -3
  12. package/src/lib/components/Button.svelte +2 -2
  13. package/src/lib/components/Card.svelte +4 -4
  14. package/src/lib/components/Checkbox.svelte +12 -10
  15. package/src/lib/components/CodeBlock.svelte +7 -13
  16. package/src/lib/components/CronInput.svelte +12 -11
  17. package/src/lib/components/DataGrid.svelte +14 -11
  18. package/src/lib/components/Drawer.svelte +9 -6
  19. package/src/lib/components/Dropdown.svelte +10 -14
  20. package/src/lib/components/DurationInput.svelte +10 -14
  21. package/src/lib/components/EmptyState.svelte +1 -1
  22. package/src/lib/components/ErrorState.svelte +4 -4
  23. package/src/lib/components/FeatureCard.svelte +4 -4
  24. package/src/lib/components/FormField.svelte +11 -6
  25. package/src/lib/components/Heading.svelte +4 -1
  26. package/src/lib/components/Input.svelte +10 -12
  27. package/src/lib/components/Kbd.svelte +1 -1
  28. package/src/lib/components/Link.svelte +2 -3
  29. package/src/lib/components/LinkButton.svelte +2 -2
  30. package/src/lib/components/LogConsole.svelte +22 -21
  31. package/src/lib/components/Logo.svelte +3 -1
  32. package/src/lib/components/Modal.svelte +9 -8
  33. package/src/lib/components/PageContainer.svelte +1 -1
  34. package/src/lib/components/PageHeader.svelte +1 -1
  35. package/src/lib/components/Pagination.svelte +4 -4
  36. package/src/lib/components/Popover.svelte +5 -7
  37. package/src/lib/components/Progress.svelte +6 -4
  38. package/src/lib/components/Prose.svelte +4 -4
  39. package/src/lib/components/Radio.svelte +11 -10
  40. package/src/lib/components/RadioGroup.svelte +3 -5
  41. package/src/lib/components/Select.svelte +21 -31
  42. package/src/lib/components/Separator.svelte +4 -1
  43. package/src/lib/components/Skeleton.svelte +6 -6
  44. package/src/lib/components/StatusIndicator.svelte +7 -15
  45. package/src/lib/components/Table.svelte +1 -1
  46. package/src/lib/components/TableCell.svelte +1 -1
  47. package/src/lib/components/TableRow.svelte +1 -5
  48. package/src/lib/components/Tabs.svelte +10 -11
  49. package/src/lib/components/TaskCard.svelte +7 -4
  50. package/src/lib/components/Textarea.svelte +10 -11
  51. package/src/lib/components/ThemeToggle.svelte +1 -1
  52. package/src/lib/components/ToastContainer.svelte +3 -3
  53. package/src/lib/components/Toggle.svelte +2 -3
  54. package/src/lib/components/Tooltip.svelte +8 -9
  55. package/src/lib/components/button-styles.ts +17 -18
  56. package/src/lib/components/dashboard/RunDetailPanel.svelte +61 -49
  57. package/src/lib/components/dashboard/RunFilterPopover.svelte +17 -11
  58. package/src/lib/components/dashboard/RunsList.svelte +26 -21
  59. package/src/lib/theme-tokens.css +179 -114
  60. package/src/lib/theme.css +49 -35
@@ -82,7 +82,7 @@
82
82
  class="
83
83
  relative z-10 w-full {sizeClasses[size]}
84
84
  flex max-h-[90vh] flex-col
85
- rounded-2xl bg-surface-overlay shadow-xl
85
+ rounded-[4px] border border-outline bg-surface-overlay shadow-lg
86
86
  {className}
87
87
  "
88
88
  role="dialog"
@@ -91,16 +91,19 @@
91
91
  >
92
92
  <!-- Header -->
93
93
  {#if header}
94
- <div class="border-b border-outline-faint px-6 py-4">
94
+ <div class="border-b border-outline px-6 py-4">
95
95
  {@render header()}
96
96
  </div>
97
97
  {:else if title || closable}
98
98
  <div
99
- class="flex items-start justify-between gap-4 border-b border-outline-faint px-6 py-4"
99
+ class="flex items-start justify-between gap-4 border-b border-outline px-6 py-4"
100
100
  >
101
101
  <div>
102
102
  {#if title}
103
- <h2 id="modal-title" class="text-lg font-semibold text-on-surface">
103
+ <h2
104
+ id="modal-title"
105
+ class="font-mono text-lg font-semibold text-on-surface"
106
+ >
104
107
  {title}
105
108
  </h2>
106
109
  {/if}
@@ -111,7 +114,7 @@
111
114
  {#if closable}
112
115
  <button
113
116
  onclick={handleClose}
114
- class="-m-2 shrink-0 rounded-lg p-2 text-on-surface-faint transition-colors hover:bg-surface-sunken hover:text-on-surface-muted"
117
+ class="-m-2 shrink-0 rounded-[3px] p-2 text-on-surface-faint hover:bg-surface-sunken hover:text-on-surface-muted"
115
118
  aria-label="Close"
116
119
  >
117
120
  <X size={20} />
@@ -129,9 +132,7 @@
129
132
 
130
133
  <!-- Footer -->
131
134
  {#if footer}
132
- <div
133
- class="rounded-b-2xl border-t border-outline-faint bg-surface-sunken/50 px-6 py-4"
134
- >
135
+ <div class="rounded-b-[4px] border-t border-outline bg-surface-sunken px-6 py-4">
135
136
  {@render footer()}
136
137
  </div>
137
138
  {/if}
@@ -33,6 +33,6 @@
33
33
  };
34
34
  </script>
35
35
 
36
- <div class="animate-in fade-in duration-300 {variantClasses[variant]} {className}">
36
+ <div class="{variantClasses[variant]} {className}">
37
37
  {@render children()}
38
38
  </div>
@@ -16,7 +16,7 @@
16
16
 
17
17
  <div class="flex shrink-0 flex-wrap items-start justify-between gap-3 px-1 {className}">
18
18
  <div class="min-w-0">
19
- <h1 class="text-2xl font-bold tracking-tight text-on-surface">{title}</h1>
19
+ <h1 class="font-mono text-2xl font-bold tracking-tight text-on-surface">{title}</h1>
20
20
  {#if subtitle}
21
21
  <p class="mt-0.5 text-sm text-on-surface-muted">{subtitle}</p>
22
22
  {/if}
@@ -43,7 +43,7 @@
43
43
  </script>
44
44
 
45
45
  <div class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between {className}">
46
- <div class="flex items-center gap-4 text-sm text-on-surface-muted">
46
+ <div class="flex items-center gap-4 font-mono text-sm text-on-surface-muted">
47
47
  {#if totalItems === 0}
48
48
  <span>No results</span>
49
49
  {:else}
@@ -57,8 +57,8 @@
57
57
  value={pageSize}
58
58
  onchange={handlePageSizeChange}
59
59
  class="
60
- appearance-none rounded-lg border border-outline bg-surface-raised py-1 pr-7 pl-2 text-sm
61
- font-medium text-on-surface-muted shadow-sm focus:border-ring focus:ring-1 focus:ring-ring focus:outline-none
60
+ appearance-none rounded-[3px] border border-outline bg-surface-raised py-1 pr-7 pl-2 font-mono
61
+ text-sm text-on-surface-muted shadow-sm hover:border-outline-hover focus:border-ring focus:ring-1 focus:ring-ring focus:outline-none
62
62
  "
63
63
  >
64
64
  {#each pageSizeOptions as size (size)}
@@ -81,7 +81,7 @@
81
81
  disabled={safePage <= 1}
82
82
  onclick={() => goTo(safePage - 1)}>Prev</Button
83
83
  >
84
- <div class="min-w-[4rem] text-center text-xs text-on-surface-muted">
84
+ <div class="min-w-[4rem] text-center font-mono text-xs text-on-surface-muted">
85
85
  Page {safePage} of {totalPages}
86
86
  </div>
87
87
  <Button
@@ -6,8 +6,7 @@
6
6
  import type { Placement } from "@floating-ui/dom";
7
7
  import { onDestroy } from "svelte";
8
8
  import { computePosition, autoUpdate, flip, shift, offset } from "@floating-ui/dom";
9
- import { scale, fade } from "svelte/transition";
10
- import { quintOut } from "svelte/easing";
9
+ import { fade } from "svelte/transition";
11
10
  import { portal } from "../actions/portal.js";
12
11
 
13
12
  interface Props {
@@ -139,20 +138,19 @@
139
138
  <div
140
139
  use:portal
141
140
  transition:fade={{ duration: 120 }}
142
- class="fixed inset-0 z-[9998] bg-on-surface/40"
141
+ class="fixed inset-0 z-[9998] bg-backdrop"
143
142
  aria-hidden="true"
144
143
  ></div>
145
144
  {/if}
146
145
  <div
147
146
  use:portal
148
147
  bind:this={contentEl}
149
- transition:scale={{ duration: 150, start: 0.95, easing: quintOut }}
150
148
  class="
151
149
  z-[9999] max-h-[80vh] overflow-y-auto
152
- border border-outline bg-surface-overlay shadow-xl shadow-on-surface/5
150
+ border border-outline bg-surface-overlay shadow-lg
153
151
  {asSheet
154
- ? 'fixed inset-x-0 bottom-0 max-h-[85vh] rounded-t-2xl border-x-0 border-b-0 p-5'
155
- : 'rounded-xl p-4'}
152
+ ? 'fixed inset-x-0 bottom-0 max-h-[85vh] rounded-t-[4px] border-x-0 border-b-0 p-5'
153
+ : 'rounded-[4px] p-4'}
156
154
  "
157
155
  >
158
156
  {#if children}
@@ -45,19 +45,21 @@
45
45
  {#if showLabel || label}
46
46
  <div class="mb-1.5 flex items-center justify-between">
47
47
  {#if label}
48
- <span class="text-sm font-medium text-on-surface-muted">{label}</span>
48
+ <span class="font-mono text-sm text-on-surface-muted">{label}</span>
49
49
  {/if}
50
50
  {#if showLabel}
51
- <span class="text-sm text-on-surface-muted">{Math.round(percentage)}%</span>
51
+ <span class="font-mono text-sm text-on-surface-muted"
52
+ >{Math.round(percentage)}%</span
53
+ >
52
54
  {/if}
53
55
  </div>
54
56
  {/if}
55
57
 
56
- <div class="w-full {sizeClasses[size]} overflow-hidden rounded-full bg-outline">
58
+ <div class="w-full {sizeClasses[size]} overflow-hidden rounded-full bg-surface-sunken">
57
59
  <div
58
60
  class="{sizeClasses[size]} {variantClasses[
59
61
  variant
60
- ]} rounded-full transition-all duration-300"
62
+ ]} rounded-full transition-[width] duration-200"
61
63
  style="width: {percentage}%"
62
64
  role="progressbar"
63
65
  aria-valuenow={value}
@@ -28,10 +28,10 @@
28
28
  prose-headings:text-on-surface
29
29
  prose-p:text-on-surface-muted prose-a:text-primary prose-a:no-underline
30
30
  hover:prose-a:underline
31
- prose-blockquote:border-outline prose-blockquote:text-on-surface-muted prose-strong:text-on-surface prose-code:rounded prose-code:bg-surface-sunken
32
- prose-code:px-1 prose-code:py-0.5 prose-code:text-on-surface
33
- prose-pre:border prose-pre:border-outline
34
- prose-pre:bg-surface-sunken
31
+ prose-blockquote:border-outline prose-blockquote:text-on-surface-muted prose-strong:text-on-surface prose-code:rounded-[3px] prose-code:bg-surface-sunken
32
+ prose-code:px-1 prose-code:py-0.5 prose-code:font-mono prose-code:text-on-surface
33
+ prose-pre:rounded-[4px] prose-pre:border prose-pre:border-outline
34
+ prose-pre:bg-surface-sunken prose-pre:font-mono
35
35
  prose-li:text-on-surface-muted
36
36
  prose-th:text-on-surface
37
37
  prose-td:text-on-surface-muted
@@ -49,21 +49,20 @@
49
49
  checked={isChecked}
50
50
  onchange={() => (groupValue = value)}
51
51
  class="
52
- peer {sizeClasses[size].radio} duration-fast
52
+ peer {sizeClasses[size].radio}
53
53
  cursor-pointer appearance-none rounded-full
54
- border-2 border-outline-hover
55
- bg-surface-raised transition-colors
56
- checked:border-primary checked:bg-primary
57
- hover:border-on-surface-faint
54
+ border border-outline
55
+ bg-surface-raised checked:border-primary checked:bg-primary
56
+ hover:border-outline-hover
58
57
  checked:hover:border-primary-hover checked:hover:bg-primary-hover
59
- focus:ring-2 focus:ring-ring/20
60
- focus:ring-offset-0 focus:outline-none
61
- disabled:cursor-not-allowed disabled:hover:border-outline-hover
58
+ focus:ring-2 focus:ring-ring focus:ring-offset-2
59
+ focus:outline-none
60
+ disabled:cursor-not-allowed disabled:hover:border-outline
62
61
  disabled:checked:hover:bg-primary
63
62
  "
64
63
  />
65
64
  <div
66
- class="duration-fast pointer-events-none absolute rounded-full bg-on-primary opacity-0 transition-opacity peer-checked:opacity-100 {sizeClasses[
65
+ class="pointer-events-none absolute rounded-full bg-on-primary opacity-0 peer-checked:opacity-100 {sizeClasses[
67
66
  size
68
67
  ].dot}"
69
68
  ></div>
@@ -72,7 +71,9 @@
72
71
  {#if label || description}
73
72
  <div class="flex flex-col gap-0.5">
74
73
  {#if label}
75
- <span class="{sizeClasses[size].text} font-medium text-on-surface">{label}</span>
74
+ <span class="{sizeClasses[size].text} font-mono font-medium text-on-surface"
75
+ >{label}</span
76
+ >
76
77
  {/if}
77
78
  {#if description}
78
79
  <span class="text-sm text-on-surface-muted">{description}</span>
@@ -36,7 +36,7 @@
36
36
 
37
37
  <fieldset class="space-y-3 {className}" role="radiogroup" aria-label={label}>
38
38
  {#if label}
39
- <legend class="text-sm font-medium text-on-surface-muted">{label}</legend>
39
+ <legend class="font-mono text-xs font-medium text-on-surface-muted">{label}</legend>
40
40
  {/if}
41
41
 
42
42
  <div class={orientationClasses[orientation]}>
@@ -44,12 +44,10 @@
44
44
  </div>
45
45
 
46
46
  {#if error}
47
- <p
48
- class="animate-in slide-in-from-top-1 fade-in text-sm text-danger-soft-text duration-200"
49
- >
47
+ <p class="font-sans text-xs text-danger-soft-text">
50
48
  {error}
51
49
  </p>
52
50
  {:else if hint}
53
- <p class="text-sm text-on-surface-muted">{hint}</p>
51
+ <p class="font-sans text-xs text-on-surface-muted">{hint}</p>
54
52
  {/if}
55
53
  </fieldset>
@@ -18,7 +18,6 @@
18
18
  <script lang="ts">
19
19
  import { tick, onDestroy } from "svelte";
20
20
  import { ChevronDown, Check, Search } from "@lucide/svelte";
21
- import { fade } from "svelte/transition";
22
21
  import { computePosition, autoUpdate, flip, shift, offset } from "@floating-ui/dom";
23
22
  import { generateUlid } from "@runwisp/common";
24
23
 
@@ -231,18 +230,17 @@
231
230
  };
232
231
 
233
232
  const triggerBase = `
234
- relative w-full text-left cursor-pointer
235
- rounded-lg border bg-surface-raised
236
- transition-all duration-normal ease-out
237
- flex items-center justify-between
238
- focus:outline-none focus:ring-4 focus:ring-ring/10 focus:border-ring
233
+ relative w-full text-left cursor-pointer font-mono
234
+ rounded-[3px] border bg-surface-raised
235
+ flex items-center justify-between
236
+ focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:border-ring
239
237
  `;
240
238
 
241
239
  const borderClass = $derived(
242
240
  error
243
- ? "border-danger-300 ring-danger-500/20"
241
+ ? "border-danger-surface"
244
242
  : isOpen
245
- ? "border-ring ring-4 ring-ring/10"
243
+ ? "border-ring ring-2 ring-ring ring-offset-2"
246
244
  : "border-outline hover:border-outline-hover shadow-sm hover:shadow-md",
247
245
  );
248
246
  </script>
@@ -251,7 +249,7 @@
251
249
 
252
250
  <div class="relative w-full {className}">
253
251
  {#if label}
254
- <label for={id} class="mb-1.5 block text-sm font-medium text-on-surface-muted">
252
+ <label for={id} class="mb-1.5 block font-mono text-xs font-medium text-on-surface-muted">
255
253
  {label}
256
254
  </label>
257
255
  {/if}
@@ -292,10 +290,7 @@
292
290
  <div
293
291
  class="pointer-events-none absolute top-1/2 right-3 -translate-y-1/2 text-on-surface-faint"
294
292
  >
295
- <ChevronDown
296
- size={16}
297
- class="transition-transform duration-200 {isOpen ? 'rotate-180' : ''}"
298
- />
293
+ <ChevronDown size={16} class={isOpen ? "rotate-180" : ""} />
299
294
  </div>
300
295
  </button>
301
296
 
@@ -306,16 +301,10 @@
306
301
 
307
302
  <!-- Dropdown Menu -->
308
303
  {#if isOpen}
309
- <div
310
- use:portal
311
- bind:this={menuEl}
312
- transition:fade={{ duration: 100 }}
313
- class="z-[9999] min-w-[200px]"
314
- >
304
+ <div use:portal bind:this={menuEl} class="z-[9999] min-w-[200px]">
315
305
  <div
316
306
  class="
317
- overflow-hidden rounded-xl border border-outline bg-surface-overlay shadow-xl
318
- ring-1 shadow-on-surface/5 ring-black/5
307
+ overflow-hidden rounded-[4px] border border-outline bg-surface-overlay shadow-md
319
308
  "
320
309
  >
321
310
  {#if searchable}
@@ -331,8 +320,8 @@
331
320
  onkeydown={handleKeydown}
332
321
  placeholder="Search..."
333
322
  class="
334
- w-full rounded-lg border border-outline bg-surface-raised py-1.5 pr-3 pl-8 text-xs
335
- text-on-surface placeholder:text-on-surface-faint focus:border-ring focus:ring-1
323
+ w-full rounded-[3px] border border-outline bg-surface-raised py-1.5 pr-3 pl-8 font-mono text-xs
324
+ text-on-surface placeholder:text-on-surface-faint focus:border-ring focus:ring-2
336
325
  focus:ring-ring focus:outline-none
337
326
  "
338
327
  />
@@ -341,7 +330,7 @@
341
330
  {/if}
342
331
 
343
332
  <div
344
- class="scrollbar-thin scrollbar-thumb-mist-200 scrollbar-track-transparent max-h-60 overflow-x-hidden overflow-y-auto p-1"
333
+ class="max-h-60 scrollbar-thin scrollbar-thumb-mist-200 scrollbar-track-transparent overflow-x-hidden overflow-y-auto p-1"
345
334
  >
346
335
  {#if flattenedVisibleOptions.length === 0}
347
336
  <div class="px-4 py-8 text-center text-sm text-on-surface-muted">
@@ -363,7 +352,7 @@
363
352
 
364
353
  {#each Object.entries(groupedOptions.groups) as [groupName, groupOptions] (groupName)}
365
354
  <div
366
- class="sticky top-0 z-10 mt-1 bg-surface-sunken/50 px-2 py-1.5 text-xs font-semibold tracking-wider text-on-surface-faint uppercase backdrop-blur-sm first:mt-0"
355
+ class="sticky top-0 z-10 mt-1 bg-surface-sunken/50 px-2 py-1.5 font-mono text-xs font-semibold tracking-wider text-on-surface-faint uppercase backdrop-blur-sm first:mt-0"
367
356
  >
368
357
  {groupName}
369
358
  </div>
@@ -385,11 +374,11 @@
385
374
  {/if}
386
375
 
387
376
  {#if error}
388
- <p class="animate-in slide-in-from-top-1 fade-in mt-1.5 text-sm text-danger-soft-text">
377
+ <p class="mt-1.5 font-sans text-xs text-danger-soft-text">
389
378
  {error}
390
379
  </p>
391
380
  {:else if hint}
392
- <p class="mt-1.5 text-xs text-on-surface-muted">
381
+ <p class="mt-1.5 font-sans text-xs text-on-surface-muted">
393
382
  {hint}
394
383
  </p>
395
384
  {/if}
@@ -416,8 +405,9 @@
416
405
  {onclick}
417
406
  onmouseenter={onsemiactive}
418
407
  class="
419
- flex w-full items-start gap-3 rounded-lg px-2.5 py-2 text-left transition-colors
420
- {active ? 'bg-surface-sunken' : 'hover:bg-surface-sunken/50'}
408
+ flex w-full items-start gap-3 rounded-[3px] px-2.5 py-2 text-left {active
409
+ ? 'bg-surface-sunken'
410
+ : 'hover:bg-surface-sunken/50'}
421
411
  {selected ? 'bg-primary-soft/50 font-medium text-on-surface' : 'text-on-surface-muted'}
422
412
  {option.disabled
423
413
  ? 'pointer-events-none cursor-not-allowed opacity-50'
@@ -433,14 +423,14 @@
433
423
 
434
424
  <div class="min-w-0 flex-1">
435
425
  <div class="flex items-center justify-between gap-2">
436
- <span class="block truncate text-sm font-medium">{option.label}</span>
426
+ <span class="block truncate font-mono text-sm font-medium">{option.label}</span>
437
427
  {#if selected}
438
428
  <Check size={14} class="shrink-0 text-primary" />
439
429
  {/if}
440
430
  </div>
441
431
  {#if option.description}
442
432
  <div
443
- class="mt-0.5 line-clamp-2 text-xs leading-normal text-wrap text-on-surface-muted"
433
+ class="mt-0.5 line-clamp-2 font-sans text-xs leading-normal text-wrap text-on-surface-muted"
444
434
  >
445
435
  {option.description}
446
436
  </div>
@@ -22,7 +22,10 @@
22
22
  {:else if label}
23
23
  <div role="separator" class="flex items-center gap-3 {className}">
24
24
  <div class="h-px flex-1 bg-outline"></div>
25
- <span class="text-xs font-medium text-on-surface-faint select-none">{label}</span>
25
+ <span
26
+ class="font-mono text-xs font-medium tracking-wider text-on-surface-faint uppercase select-none"
27
+ >{label}</span
28
+ >
26
29
  <div class="h-px flex-1 bg-outline"></div>
27
30
  </div>
28
31
  {:else}
@@ -30,7 +30,7 @@
30
30
 
31
31
  {#if shape === "circle"}
32
32
  <div
33
- class="animate-pulse rounded-full bg-outline {className}"
33
+ class="animate-pulse rounded-full bg-surface-sunken {className}"
34
34
  style="width: {width ?? '2.5rem'}; height: {height ?? width ?? '2.5rem'}"
35
35
  role="status"
36
36
  aria-label="Loading"
@@ -39,7 +39,7 @@
39
39
  </div>
40
40
  {:else if shape === "rect"}
41
41
  <div
42
- class="animate-pulse rounded-lg bg-outline {className}"
42
+ class="animate-pulse rounded-[4px] bg-surface-sunken {className}"
43
43
  style="width: {width ?? '100%'}; height: {height ?? '2rem'}"
44
44
  role="status"
45
45
  aria-label="Loading"
@@ -50,8 +50,8 @@
50
50
  <div class="animate-pulse space-y-6 p-6 {className}" role="status" aria-label="Loading content">
51
51
  {#if header}
52
52
  <div class="space-y-3">
53
- <div class="h-7 w-48 rounded-lg bg-outline"></div>
54
- <div class="h-4 w-72 rounded bg-outline-faint"></div>
53
+ <div class="h-7 w-48 rounded-[4px] bg-surface-sunken"></div>
54
+ <div class="h-4 w-72 rounded-[3px] bg-surface-sunken"></div>
55
55
  </div>
56
56
  {/if}
57
57
 
@@ -59,11 +59,11 @@
59
59
  {#each Array.from({ length: rows }, (_, i) => i) as i (i)}
60
60
  <div class="space-y-2">
61
61
  <div
62
- class="h-4 rounded bg-outline-faint"
62
+ class="h-4 rounded-[3px] bg-surface-sunken"
63
63
  style="width: {70 + ((i * 17) % 30)}%"
64
64
  ></div>
65
65
  <div
66
- class="h-4 rounded bg-surface-sunken"
66
+ class="h-4 rounded-[3px] bg-surface-sunken"
67
67
  style="width: {40 + ((i * 23) % 40)}%"
68
68
  ></div>
69
69
  </div>
@@ -5,13 +5,7 @@
5
5
  import { fade } from "svelte/transition";
6
6
 
7
7
  type Status =
8
- | "running"
9
- | "success"
10
- | "failed"
11
- | "pending"
12
- | "paused"
13
- | "scheduled"
14
- | "cancelled";
8
+ "running" | "success" | "failed" | "pending" | "paused" | "scheduled" | "cancelled";
15
9
  type Size = "sm" | "md" | "lg";
16
10
 
17
11
  interface Props {
@@ -36,24 +30,22 @@
36
30
  const STATUS_CONFIG: Record<Status, { label: string; classes: string; iconColor: string }> = {
37
31
  running: {
38
32
  label: "Running",
39
- classes: "bg-info-soft text-info-soft-text border-info-soft ring-1 ring-info-soft",
33
+ classes: "bg-info-soft text-info-soft-text border-info-soft-border",
40
34
  iconColor: "text-info-surface",
41
35
  },
42
36
  success: {
43
37
  label: "Success",
44
- classes:
45
- "bg-success-soft text-success-soft-text border-success-soft ring-1 ring-success-soft/50",
38
+ classes: "bg-success-soft text-success-soft-text border-success-soft-border",
46
39
  iconColor: "text-success-surface",
47
40
  },
48
41
  failed: {
49
42
  label: "Failed",
50
- classes:
51
- "bg-danger-soft text-danger-soft-text border-danger-soft ring-1 ring-danger-soft/50",
43
+ classes: "bg-danger-soft text-danger-soft-text border-danger-soft-border",
52
44
  iconColor: "text-danger-surface",
53
45
  },
54
46
  pending: {
55
47
  label: "Pending",
56
- classes: "bg-warning-soft text-warning-soft-text border-warning-soft",
48
+ classes: "bg-warning-soft text-warning-soft-text border-warning-soft-border",
57
49
  iconColor: "text-warning-surface",
58
50
  },
59
51
  paused: {
@@ -63,7 +55,7 @@
63
55
  },
64
56
  scheduled: {
65
57
  label: "Scheduled",
66
- classes: "bg-primary-soft text-primary-soft-text border-primary-soft",
58
+ classes: "bg-primary-soft text-primary-soft-text border-primary-soft-border",
67
59
  iconColor: "text-primary",
68
60
  },
69
61
  cancelled: {
@@ -85,7 +77,7 @@
85
77
  </script>
86
78
 
87
79
  <div
88
- class="duration-normal inline-flex items-center justify-center rounded-full border font-medium transition-all {config.classes} {sizeConfig.classes} {className}"
80
+ class="inline-flex items-center justify-center rounded-full border font-mono tracking-wide {config.classes} {sizeConfig.classes} {className}"
89
81
  role="status"
90
82
  in:fade={{ duration: 150 }}
91
83
  >
@@ -12,7 +12,7 @@
12
12
  let { children, class: className = "" }: Props = $props();
13
13
  </script>
14
14
 
15
- <div class="overflow-x-auto rounded-xl border border-outline {className}">
15
+ <div class="overflow-x-auto rounded-[4px] border border-outline {className}">
16
16
  <table class="w-full text-sm">
17
17
  {@render children()}
18
18
  </table>
@@ -27,7 +27,7 @@
27
27
  <svelte:element
28
28
  this={tag}
29
29
  class="px-4 py-3 {alignClasses[align]} {header
30
- ? 'text-xs font-medium tracking-wider text-on-surface-muted uppercase'
30
+ ? 'font-mono text-xs tracking-wide text-on-surface-faint uppercase'
31
31
  : 'text-on-surface'} {className}"
32
32
  >
33
33
  {@render children()}
@@ -13,10 +13,6 @@
13
13
  let { children, hoverable = false, class: className = "" }: Props = $props();
14
14
  </script>
15
15
 
16
- <tr
17
- class="border-b border-outline-faint {hoverable
18
- ? 'duration-fast transition-colors hover:bg-surface-sunken'
19
- : ''} {className}"
20
- >
16
+ <tr class="border-b border-outline {hoverable ? 'hover:bg-surface-sunken' : ''} {className}">
21
17
  {@render children()}
22
18
  </tr>
@@ -53,9 +53,8 @@
53
53
  const baseClasses = `
54
54
  ${fullWidth ? "flex-1" : ""}
55
55
  inline-flex items-center justify-center gap-2 px-4 py-2.5
56
- text-sm font-medium
57
- transition-colors duration-150
58
- disabled:cursor-not-allowed disabled:opacity-50
56
+ text-sm font-mono
57
+ disabled:cursor-not-allowed disabled:opacity-50
59
58
  `;
60
59
 
61
60
  const isActive = activeTab === tab.id;
@@ -63,16 +62,16 @@
63
62
  if (variant === "underline") {
64
63
  return `${baseClasses} -mb-px border-b-2 ${
65
64
  isActive
66
- ? "border-primary text-primary-soft-text"
67
- : "border-transparent text-on-surface-muted hover:border-outline-hover hover:text-on-surface"
65
+ ? "border-primary text-primary"
66
+ : "border-transparent text-on-surface-muted hover:border-outline-hover hover:text-primary"
68
67
  }`;
69
68
  }
70
69
 
71
70
  if (variant === "pills" || variant === "enclosed") {
72
- return `${baseClasses} rounded-lg ${
71
+ return `${baseClasses} rounded-[3px] ${
73
72
  isActive
74
- ? "bg-surface-raised text-on-surface shadow-sm"
75
- : "text-on-surface-muted hover:text-on-surface"
73
+ ? "bg-primary-soft text-primary-soft-text"
74
+ : "text-on-surface-muted hover:text-primary"
76
75
  }`;
77
76
  }
78
77
 
@@ -85,8 +84,8 @@
85
84
  <div
86
85
  class="
87
86
  {variant === 'underline' ? 'border-b border-outline' : ''}
88
- {variant === 'pills' ? 'rounded-xl bg-surface-sunken p-1' : ''}
89
- {variant === 'enclosed' ? 'rounded-xl border border-outline bg-surface-sunken p-1' : ''}
87
+ {variant === 'pills' ? 'rounded-[4px] bg-surface-sunken p-1' : ''}
88
+ {variant === 'enclosed' ? 'rounded-[4px] border border-outline bg-surface-sunken p-1' : ''}
90
89
  "
91
90
  role="tablist"
92
91
  >
@@ -120,7 +119,7 @@
120
119
  {#if tab.badge || tab.badge === 0}
121
120
  <span
122
121
  class="
123
- rounded-full px-1.5 py-0.5 text-xs font-medium
122
+ rounded-[3px] px-1.5 py-0.5 font-mono text-xs
124
123
  {activeTab === tab.id
125
124
  ? 'bg-primary-soft text-primary-soft-text'
126
125
  : 'bg-surface-sunken text-on-surface-muted'}
@@ -15,16 +15,19 @@
15
15
 
16
16
  let { accent = "wisp", onclick, children, class: className = "" }: Props = $props();
17
17
 
18
+ // Each accent maps to a left keyline in the matching semantic colour. The
19
+ // other three sides stay a neutral hairline (set per-side so the shorthand
20
+ // never overrides the accent left-colour), and hover lifts the surface.
18
21
  const accentClasses: Record<TaskCardAccent, string> = {
19
- danger: "hover:border-danger-soft-border",
20
- wisp: "hover:border-primary-soft-border",
21
- aurora: "hover:border-info-soft-border",
22
+ danger: "border-l-danger-surface",
23
+ wisp: "border-l-primary",
24
+ aurora: "border-l-info",
22
25
  };
23
26
  </script>
24
27
 
25
28
  <button
26
29
  type="button"
27
- class="group w-full rounded-lg border border-outline-faint bg-surface-raised p-3 text-left transition-all hover:shadow-sm {accentClasses[
30
+ class="group w-full rounded-[4px] border border-l-2 border-t-outline border-r-outline border-b-outline bg-surface-raised p-3 text-left hover:bg-surface-sunken {accentClasses[
28
31
  accent
29
32
  ]} {className}"
30
33
  {onclick}