@tollerud/ui 3.1.0 → 4.0.1

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 (46) hide show
  1. package/AGENTS.md +20 -4
  2. package/CHANGELOG.md +122 -0
  3. package/COMPONENTS.md +13 -1
  4. package/GETTING_STARTED.md +0 -58
  5. package/README.md +31 -59
  6. package/SKILL.md +6 -4
  7. package/components.json +1 -1
  8. package/dist/bento-dashboard.js +1 -1
  9. package/dist/button.d.ts +2 -2
  10. package/dist/button.js +1 -1
  11. package/dist/checkbox.js +1 -1
  12. package/dist/{chunk-ADE22JSR.js → chunk-BQWF5MP7.js} +7 -7
  13. package/dist/chunk-BQWF5MP7.js.map +1 -0
  14. package/dist/{chunk-IUPVQWO5.js → chunk-FPFLOYIJ.js} +5 -5
  15. package/dist/chunk-FPFLOYIJ.js.map +1 -0
  16. package/dist/{chunk-6SKTH45H.js → chunk-J2Z4ZFVX.js} +29 -18
  17. package/dist/chunk-J2Z4ZFVX.js.map +1 -0
  18. package/dist/{chunk-YPP7QHYT.js → chunk-K4ALNUZI.js} +4 -4
  19. package/dist/{chunk-YPP7QHYT.js.map → chunk-K4ALNUZI.js.map} +1 -1
  20. package/dist/{chunk-ONMTHBZ4.js → chunk-LGVXEWNB.js} +10 -10
  21. package/dist/chunk-LGVXEWNB.js.map +1 -0
  22. package/dist/{chunk-OVSIOZHJ.js → chunk-SNNMZ444.js} +3 -3
  23. package/dist/{chunk-OVSIOZHJ.js.map → chunk-SNNMZ444.js.map} +1 -1
  24. package/dist/{chunk-T3TQPOVM.js → chunk-TLEKK53J.js} +5 -8
  25. package/dist/chunk-TLEKK53J.js.map +1 -0
  26. package/dist/cta-band.js +1 -1
  27. package/dist/data-table.js +3 -3
  28. package/dist/index.js +7 -7
  29. package/dist/pricing-card.js +2 -2
  30. package/dist/radio-group.d.ts +6 -0
  31. package/dist/radio-group.js +1 -1
  32. package/globals-layers.css +27 -1
  33. package/package.json +16 -20
  34. package/registry.json +14 -9
  35. package/tokens.css +29 -5
  36. package/dist/chunk-6SKTH45H.js.map +0 -1
  37. package/dist/chunk-ADE22JSR.js.map +0 -1
  38. package/dist/chunk-IUPVQWO5.js.map +0 -1
  39. package/dist/chunk-ONMTHBZ4.js.map +0 -1
  40. package/dist/chunk-T3TQPOVM.js.map +0 -1
  41. package/globals-v4.css +0 -2
  42. /package/{tollerud-avatar-full.png → brand/tollerud-avatar-full.png} +0 -0
  43. /package/{tollerud-avatar-full.svg → brand/tollerud-avatar-full.svg} +0 -0
  44. /package/{tollerud-avatar.png → brand/tollerud-avatar.png} +0 -0
  45. /package/{tollerud-avatar.svg → brand/tollerud-avatar.svg} +0 -0
  46. /package/{tollerud-logo.svg → brand/tollerud-logo.svg} +0 -0
@@ -141,6 +141,7 @@
141
141
  rgba(232, 213, 0, 0.8),
142
142
  rgba(255, 184, 0, 0.4)
143
143
  );
144
+ --tollerud-shimmer-highlight: #FFFDE6;
144
145
 
145
146
  /* ═══ Transition ═══ */
146
147
  --transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
@@ -193,6 +194,13 @@
193
194
  transition-duration: 0.01ms !important;
194
195
  scroll-behavior: auto !important;
195
196
  }
197
+ .tollerud-display-shimmer {
198
+ animation: none !important;
199
+ background: none;
200
+ -webkit-background-clip: initial;
201
+ background-clip: initial;
202
+ color: var(--primary);
203
+ }
196
204
  }
197
205
  }
198
206
 
@@ -236,7 +244,7 @@
236
244
  box-shadow: var(--shadow-glow, 0 0 15px rgba(255,255,0,0.3));
237
245
  }
238
246
  .tollerud-btn--secondary {
239
- background: transparent;
247
+ background: var(--surface-raised);
240
248
  color: var(--foreground);
241
249
  border-color: var(--border);
242
250
  }
@@ -597,6 +605,24 @@
597
605
  line-height: 1.1;
598
606
  }
599
607
 
608
+ /* Animated yellow sweep clipped to text — pair with .tollerud-display on dark surfaces */
609
+ .tollerud-display-shimmer {
610
+ background: linear-gradient(
611
+ 100deg,
612
+ var(--tollerud-yellow) 32%,
613
+ var(--tollerud-shimmer-highlight) 50%,
614
+ var(--tollerud-yellow) 68%
615
+ );
616
+ background-size: 220% 100%;
617
+ -webkit-background-clip: text;
618
+ background-clip: text;
619
+ color: transparent;
620
+ animation: tollerud-display-shimmer 5s linear infinite;
621
+ }
622
+ @keyframes tollerud-display-shimmer {
623
+ to { background-position: -220% 0; }
624
+ }
625
+
600
626
  /* ═══ Status Indicator ═══ */
601
627
  .tollerud-status {
602
628
  display: inline-flex;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tollerud/ui",
3
- "version": "3.1.0",
3
+ "version": "4.0.1",
4
4
  "description": "Tollerud User Interface — dark, monochrome + yellow accent. Noir aesthetic meets modern utility.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -8,14 +8,15 @@
8
8
  "type": "git",
9
9
  "url": "git+https://github.com/Tollerud/ui.git"
10
10
  },
11
- "homepage": "https://tollerud.github.io/design-system/",
11
+ "homepage": "https://design.tollerud.dev/",
12
12
  "bugs": {
13
13
  "url": "https://github.com/Tollerud/ui/issues"
14
14
  },
15
15
  "license": "MIT",
16
16
  "author": "Mathias Tollerud <mathias.tollerud@gmail.com>",
17
+ "packageManager": "npm@11.16.0",
17
18
  "engines": {
18
- "node": ">=18"
19
+ "node": ">=20"
19
20
  },
20
21
  "sideEffects": [
21
22
  "*.css"
@@ -32,16 +33,15 @@
32
33
  },
33
34
  "./globals.css": "./globals.css",
34
35
  "./globals-v3.css": "./globals-v3.css",
35
- "./globals-v4.css": "./globals-v4.css",
36
36
  "./globals-layers.css": "./globals-layers.css",
37
37
  "./tailwind.css": "./tailwind.css",
38
38
  "./tokens.css": "./tokens.css",
39
39
  "./preset": "./tollerud-preset.js",
40
- "./tollerud-logo.svg": "./tollerud-logo.svg",
41
- "./tollerud-avatar.svg": "./tollerud-avatar.svg",
42
- "./tollerud-avatar.png": "./tollerud-avatar.png",
43
- "./tollerud-avatar-full.svg": "./tollerud-avatar-full.svg",
44
- "./tollerud-avatar-full.png": "./tollerud-avatar-full.png",
40
+ "./brand/tollerud-logo.svg": "./brand/tollerud-logo.svg",
41
+ "./brand/tollerud-avatar.svg": "./brand/tollerud-avatar.svg",
42
+ "./brand/tollerud-avatar.png": "./brand/tollerud-avatar.png",
43
+ "./brand/tollerud-avatar-full.svg": "./brand/tollerud-avatar-full.svg",
44
+ "./brand/tollerud-avatar-full.png": "./brand/tollerud-avatar-full.png",
45
45
  "./registry.json": "./registry.json",
46
46
  "./*": {
47
47
  "import": {
@@ -54,7 +54,6 @@
54
54
  "dist",
55
55
  "globals.css",
56
56
  "globals-v3.css",
57
- "globals-v4.css",
58
57
  "globals-layers.css",
59
58
  "tailwind.css",
60
59
  "tokens.css",
@@ -64,11 +63,7 @@
64
63
  "GETTING_STARTED.md",
65
64
  "COMPONENTS.md",
66
65
  "CHANGELOG.md",
67
- "tollerud-logo.svg",
68
- "tollerud-avatar.svg",
69
- "tollerud-avatar.png",
70
- "tollerud-avatar-full.svg",
71
- "tollerud-avatar-full.png",
66
+ "brand",
72
67
  "AGENTS.md",
73
68
  "SKILL.md"
74
69
  ],
@@ -83,19 +78,20 @@
83
78
  "test:subpath": "node scripts/verify-subpath-exports.mjs",
84
79
  "test:drift": "node scripts/verify-registry-drift.mjs",
85
80
  "test:consumer": "node scripts/test-consumer.mjs",
81
+ "sync:footer": "node scripts/sync-footer-package.mjs",
82
+ "verify:footer-sync": "node scripts/verify-footer-sync.mjs",
86
83
  "test:package": "node scripts/test-package.mjs",
87
84
  "test:size": "node scripts/test-size.mjs",
88
85
  "sync:registry": "node scripts/sync-registry-version.mjs",
89
86
  "changelog:draft": "node scripts/changelog-draft.mjs",
90
87
  "changeset": "changeset",
91
- "version:release": "changeset version && npm run sync:registry",
88
+ "version:release": "changeset version && npm run sync:registry && npm run sync:footer",
92
89
  "docs:props": "node scripts/generate-props.mjs",
93
90
  "test:props": "node scripts/verify-props-drift.mjs",
94
- "validate": "npm run typecheck && npm run lint && npm run test && npm run build && npm run test:subpath && npm run test:drift && npm run test:package && npm run test:size && npm run test:props && npm run build:docs && npm run test:consumer",
91
+ "validate": "npm run typecheck && npm run lint && npm run test && npm run build && npm run test:subpath && npm run test:drift && npm run test:package && npm run test:size && npm run test:props && npm run verify:footer-sync && npm run build:docs && npm run test:consumer",
95
92
  "prepublishOnly": "npm run sync:registry && npm run typecheck && npm run lint && npm run test && npm run build && npm run test:subpath && npm run test:drift && npm run test:package && npm run test:size && npm run test:props",
96
93
  "build:docs": "node scripts/build-docs.mjs",
97
- "preview:docs": "npx --yes serve _site -l 4173",
98
- "preview": "open preview.html"
94
+ "preview:docs": "npx --yes serve _site -l 4173"
99
95
  },
100
96
  "peerDependencies": {
101
97
  "@paper-design/shaders-react": "^0.0.76",
@@ -129,7 +125,7 @@
129
125
  "@radix-ui/react-dropdown-menu": "^2.1.17",
130
126
  "@radix-ui/react-progress": "^1.1.9",
131
127
  "@radix-ui/react-slot": "^1.2.5",
132
- "@radix-ui/react-tabs": "^1.1.13",
128
+ "@radix-ui/react-tabs": "^1.1.14",
133
129
  "@radix-ui/react-tooltip": "^1.2.9",
134
130
  "@eslint/js": "^9.39.4",
135
131
  "@playwright/test": "^1.60.0",
package/registry.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
- "name": "tollerud-noir",
3
- "version": "3.1.0",
4
- "description": "Tollerud Design System \u2014 dark, cinematic, keyboard-first infrastructure UI",
2
+ "name": "Tollerud User Interface",
3
+ "version": "4.0.1",
4
+ "description": "Dark, monochrome React components with a single yellow accent — built for dashboards, tools, and homelab UIs.",
5
5
  "components": {
6
6
  "button": {
7
7
  "name": "Button",
8
- "description": "Primary action button with terminal, ghost, and variant styles",
8
+ "description": "Five variants and three sizes — primary, secondary, ghost, destructive, and terminal. Supports asChild, icons, and loading state",
9
9
  "files": [
10
10
  "components/Button.tsx"
11
11
  ],
@@ -213,7 +213,7 @@
213
213
  },
214
214
  "incident-card": {
215
215
  "name": "IncidentCard",
216
- "description": "Severity-graded incident/alert card (critical \u2192 info)",
216
+ "description": "Severity-graded incident/alert card (critical info)",
217
217
  "files": [
218
218
  "components/IncidentCard.tsx"
219
219
  ],
@@ -455,7 +455,7 @@
455
455
  },
456
456
  "bento-dashboard": {
457
457
  "name": "BentoDashboard",
458
- "description": "Composable bento-grid dashboard layout for hosts, metrics, services, and incidents",
458
+ "description": "Homelab mission-control bento grid host cards, metrics, services, and recent incidents",
459
459
  "files": [
460
460
  "components/BentoDashboard.tsx"
461
461
  ],
@@ -463,7 +463,12 @@
463
463
  "clsx",
464
464
  "tailwind-merge"
465
465
  ],
466
- "registryDependencies": [],
466
+ "registryDependencies": [
467
+ "host-card",
468
+ "stat-card",
469
+ "service-health-card",
470
+ "incident-card"
471
+ ],
467
472
  "type": "components:ui"
468
473
  },
469
474
  "breadcrumb": {
@@ -890,7 +895,7 @@
890
895
  },
891
896
  "hero-block": {
892
897
  "name": "HeroBlock",
893
- "description": "Landing hero on noir glow background with optional shader intensity",
898
+ "description": "Landing hero with noir glow background. Pass intense for live WebGL shader; optional media slot for two-column layout",
894
899
  "files": [
895
900
  "components/HeroBlock.tsx"
896
901
  ],
@@ -921,7 +926,7 @@
921
926
  },
922
927
  "cta-band": {
923
928
  "name": "CTABand",
924
- "description": "Closing call-to-action band with optional yellow accent bar",
929
+ "description": "Centered closing call-to-action with title, description, action row, and optional yellow accent bar",
925
930
  "files": [
926
931
  "components/CTABand.tsx"
927
932
  ],
package/tokens.css CHANGED
@@ -42,6 +42,7 @@
42
42
  --tollerud-border: #333333;
43
43
  --tollerud-border-subtle: #252525;
44
44
  --tollerud-border-accent: #FFFF00;
45
+ --tollerud-shimmer-highlight: #FFFDE6;
45
46
 
46
47
  /* ── States ── */
47
48
  --tollerud-success: #22C55E;
@@ -222,13 +223,13 @@ code, pre {
222
223
  }
223
224
 
224
225
  .tollerud-btn--secondary {
225
- background: transparent;
226
- color: var(--tollerud-text-primary);
227
- border-color: var(--tollerud-border);
226
+ background: var(--surface-raised, var(--tollerud-surface-raised));
227
+ color: var(--foreground, var(--tollerud-text-primary));
228
+ border-color: var(--border, var(--tollerud-border));
228
229
  }
229
230
  .tollerud-btn--secondary:hover {
230
- border-color: var(--tollerud-text-secondary);
231
- background: var(--tollerud-surface-hover);
231
+ border-color: var(--text-secondary, var(--tollerud-text-secondary));
232
+ background: var(--surface-hover, var(--tollerud-surface-hover));
232
233
  }
233
234
 
234
235
  .tollerud-btn--ghost {
@@ -351,6 +352,13 @@ code, pre {
351
352
  @media (prefers-reduced-motion: reduce) {
352
353
  .tollerud-noir-glow-bg,
353
354
  .tollerud-noir-noise { animation: none !important; }
355
+ .tollerud-display-shimmer {
356
+ animation: none !important;
357
+ background: none;
358
+ -webkit-background-clip: initial;
359
+ background-clip: initial;
360
+ color: var(--tollerud-yellow);
361
+ }
354
362
  }
355
363
 
356
364
  /* ── Background Grid ── */
@@ -452,6 +460,22 @@ code, pre {
452
460
  line-height: 0.95;
453
461
  color: white;
454
462
  }
463
+ .tollerud-display-shimmer {
464
+ background: linear-gradient(
465
+ 100deg,
466
+ var(--tollerud-yellow) 32%,
467
+ var(--tollerud-shimmer-highlight) 50%,
468
+ var(--tollerud-yellow) 68%
469
+ );
470
+ background-size: 220% 100%;
471
+ -webkit-background-clip: text;
472
+ background-clip: text;
473
+ color: transparent;
474
+ animation: tollerud-display-shimmer 5s linear infinite;
475
+ }
476
+ @keyframes tollerud-display-shimmer {
477
+ to { background-position: -220% 0; }
478
+ }
455
479
 
456
480
  /* ── Kbd (Keyboard Shortcut Chip) ── */
457
481
  .tollerud-kbd { display: inline-flex; align-items: center; gap: 2px; }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../components/RadioGroup.tsx"],"names":[],"mappings":";;;;AAcA,IAAM,UAAA,GAAa,UAAA;AAAA,EACjB,CAAC,EAAE,KAAA,EAAO,OAAO,QAAA,EAAU,SAAA,IAAa,GAAA,KAAQ;AAC9C,IAAA,4BACG,UAAA,EAAA,EAAS,GAAA,EAAU,WAAW,EAAA,CAAG,qBAAA,EAAuB,SAAS,CAAA,EAC/D,QAAA,EAAA;AAAA,MAAA,KAAA,oBACC,GAAA,CAAC,QAAA,EAAA,EAAO,SAAA,EAAU,mDAAA,EACf,QAAA,EAAA,KAAA,EACH,CAAA;AAAA,sBAEF,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,qBAAA,EAAuB,QAAA,EAAS,CAAA;AAAA,MAC9C,KAAA,oBACC,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,sCAAsC,QAAA,EAAA,KAAA,EAAM;AAAA,KAAA,EAE7D,CAAA;AAAA,EAEJ;AACF;AACA,UAAA,CAAW,WAAA,GAAc,YAAA;AAMzB,IAAM,KAAA,GAAQ,UAAA;AAAA,EACZ,CAAC,EAAE,SAAA,EAAW,KAAA,EAAO,IAAI,MAAA,EAAQ,GAAG,KAAA,EAAM,EAAG,GAAA,KAAQ;AACnD,IAAA,MAAM,SAAS,KAAA,EAAM;AACrB,IAAA,MAAM,KAAK,MAAA,IAAU,MAAA;AAErB,IAAA,uBACE,IAAA;AAAA,MAAC,OAAA;AAAA,MAAA;AAAA,QACC,OAAA,EAAS,EAAA;AAAA,QACT,SAAA,EAAW,EAAA;AAAA,UACT,iEAAA;AAAA,UACA,oCAAA;AAAA,UACA,MAAM,QAAA,IAAY,gCAAA;AAAA,UAClB;AAAA,SACF;AAAA,QAEA,QAAA,EAAA;AAAA,0BAAA,IAAA,CAAC,MAAA,EAAA,EAAK,WAAU,2CAAA,EACd,QAAA,EAAA;AAAA,4BAAA,GAAA;AAAA,cAAC,OAAA;AAAA,cAAA;AAAA,gBACC,GAAA;AAAA,gBACA,EAAA;AAAA,gBACA,IAAA,EAAK,OAAA;AAAA,gBACL,SAAA,EAAU,cAAA;AAAA,gBACT,GAAG;AAAA;AAAA,aACN;AAAA,4BAEA,GAAA;AAAA,cAAC,MAAA;AAAA,cAAA;AAAA,gBACC,SAAA,EAAW,EAAA;AAAA,kBACT,6DAAA;AAAA,kBACA,mDAAA;AAAA,kBACA,yEAAA;AAAA,kBACA,qCAAA;AAAA,kBACA,4CAAA;AAAA,kBACA;AAAA,iBACF;AAAA,gBAGA,QAAA,kBAAA,GAAA;AAAA,kBAAC,MAAA;AAAA,kBAAA;AAAA,oBACC,SAAA,EAAW,EAAA;AAAA,sBACT,6EAAA;AAAA,sBACA,KAAA,CAAM,UAAU,aAAA,GAAgB;AAAA;AAClC;AAAA;AACF;AAAA;AACF,WAAA,EACF,CAAA;AAAA,UACC,KAAA,oBAAS,GAAA,CAAC,MAAA,EAAA,EAAM,QAAA,EAAA,KAAA,EAAM;AAAA;AAAA;AAAA,KACzB;AAAA,EAEJ;AACF;AACA,KAAA,CAAM,WAAA,GAAc,OAAA","file":"chunk-6SKTH45H.js","sourcesContent":["'use client'\n\nimport { type InputHTMLAttributes, forwardRef, useId } from 'react'\nimport { cn } from '@/lib/utils'\n\nexport interface RadioGroupProps {\n /** Group label */\n label?: string\n /** Error message */\n error?: string\n children?: React.ReactNode\n className?: string\n}\n\nconst RadioGroup = forwardRef<HTMLFieldSetElement, RadioGroupProps>(\n ({ label, error, children, className }, ref) => {\n return (\n <fieldset ref={ref} className={cn('flex flex-col gap-1', className)}>\n {label && (\n <legend className=\"text-xs font-medium text-tollerud-text-muted mb-1\">\n {label}\n </legend>\n )}\n <div className=\"flex flex-col gap-2\">{children}</div>\n {error && (\n <p className=\"text-xs text-tollerud-error mt-0.5\">{error}</p>\n )}\n </fieldset>\n )\n }\n)\nRadioGroup.displayName = 'RadioGroup'\n\nexport interface RadioProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'type'> {\n label?: string\n}\n\nconst Radio = forwardRef<HTMLInputElement, RadioProps>(\n ({ className, label, id: idProp, ...props }, ref) => {\n const autoId = useId()\n const id = idProp ?? autoId\n\n return (\n <label\n htmlFor={id}\n className={cn(\n 'inline-flex items-center gap-2 cursor-pointer select-none group',\n 'text-sm text-tollerud-text-primary',\n props.disabled && 'opacity-50 pointer-events-none',\n className\n )}\n >\n <span className=\"relative flex items-center justify-center\">\n <input\n ref={ref}\n id={id}\n type=\"radio\"\n className=\"peer sr-only\"\n {...props}\n />\n {/* Custom radio circle */}\n <span\n className={cn(\n 'h-4 w-4 rounded-full border transition-all duration-[150ms]',\n 'bg-tollerud-surface-raised border-tollerud-border',\n 'peer-focus-visible:outline-2 peer-focus-visible:outline-tollerud-yellow',\n 'peer-checked:border-tollerud-yellow',\n 'group-hover:border-tollerud-text-secondary',\n 'flex items-center justify-center'\n )}\n >\n {/* Inner dot */}\n <span\n className={cn(\n 'h-2 w-2 rounded-full bg-tollerud-yellow transition-opacity duration-[150ms]',\n props.checked ? 'opacity-100' : 'opacity-0'\n )}\n />\n </span>\n </span>\n {label && <span>{label}</span>}\n </label>\n )\n }\n)\nRadio.displayName = 'Radio'\n\nexport { RadioGroup, Radio }"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../components/Button.tsx"],"names":[],"mappings":";;;;;AAIA,IAAM,QAAA,GAAW;AAAA,EACf,OAAA,EAAS,mHAAA;AAAA,EACT,SAAA,EAAW,uIAAA;AAAA,EACX,KAAA,EAAO,iIAAA;AAAA,EACP,WAAA,EAAa,gGAAA;AAAA,EACb,QAAA,EAAU;AACZ,CAAA;AAGA,IAAM,aAAA,GAAgB;AAAA,EACpB,OAAA,EAAS,uBAAA;AAAA,EACT,SAAA,EAAW,EAAA;AAAA,EACX,KAAA,EAAO,EAAA;AAAA,EACP,WAAA,EAAa,EAAA;AAAA,EACb,QAAA,EAAU;AACZ,CAAA;AAEA,IAAM,KAAA,GAAQ;AAAA,EACZ,EAAA,EAAI,mBAAA;AAAA,EACJ,EAAA,EAAI,qBAAA;AAAA,EACJ,EAAA,EAAI;AACN,CAAA;AAOO,SAAS,cAAA,CAAe,EAAE,OAAA,GAAU,WAAA,EAAa,OAAO,IAAA,EAAM,SAAA,EAAU,GAAiD,EAAC,EAAG;AAClI,EAAA,OAAO,EAAA;AAAA,IACL,+MAAA;AAAA,IACA,uBAAA;AAAA,IACA,kDAAA;AAAA,IACA,SAAS,OAAO,CAAA;AAAA,IAChB,cAAc,OAAO,CAAA;AAAA,IACrB,MAAM,IAAI,CAAA;AAAA,IACV;AAAA,GACF;AACF;AAOA,IAAM,MAAA,GAAS,UAAA;AAAA,EACb,CAAC,EAAE,SAAA,EAAW,OAAA,GAAU,WAAA,EAAa,IAAA,GAAO,IAAA,EAAM,OAAA,GAAU,KAAA,EAAO,GAAG,KAAA,EAAM,EAAG,GAAA,KAAQ;AACrF,IAAA,MAAM,IAAA,GAAO,UAAU,IAAA,GAAO,QAAA;AAC9B,IAAA,uBACE,GAAA;AAAA,MAAC,IAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,WAAW,cAAA,CAAe,EAAE,OAAA,EAAS,IAAA,EAAM,WAAW,CAAA;AAAA,QACrD,GAAG;AAAA;AAAA,KACN;AAAA,EAEJ;AACF;AACA,MAAA,CAAO,WAAA,GAAc,QAAA","file":"chunk-ADE22JSR.js","sourcesContent":["import { type ButtonHTMLAttributes, forwardRef } from 'react'\nimport { Slot } from '@radix-ui/react-slot'\nimport { cn } from '@/lib/utils'\n\nconst variants = {\n primary: 'bg-tollerud-yellow text-tollerud-black border-tollerud-yellow hover:bg-tollerud-yellow hover:shadow-tollerud-glow',\n secondary: 'bg-transparent text-tollerud-text-primary border-tollerud-border hover:border-tollerud-text-secondary hover:bg-tollerud-surface-hover',\n ghost: 'bg-transparent text-tollerud-text-secondary border-transparent hover:text-tollerud-text-primary hover:bg-tollerud-surface-hover',\n destructive: 'bg-tollerud-error text-white border-tollerud-error hover:shadow-[0_0_12px_rgba(239,68,68,0.3)]',\n terminal: 'font-mono text-tollerud-yellow border-[rgba(255,255,0,0.25)] bg-transparent hover:border-tollerud-yellow hover:shadow-tollerud-glow hover:bg-[rgba(255,255,0,0.05)]',\n} as const\n\n/** Layer classes from globals-layers.css — ❯ prefix, hover glow, magnetic glow in docs */\nconst variantLayers = {\n primary: 'tollerud-btn--primary',\n secondary: '',\n ghost: '',\n destructive: '',\n terminal: 'tollerud-btn--terminal',\n} as const\n\nconst sizes = {\n sm: 'px-3 py-1 text-sm',\n md: 'px-4 py-2 text-base',\n lg: 'px-6 py-3 text-lg',\n} as const\n\nexport interface ButtonVariantProps {\n variant?: keyof typeof variants\n size?: keyof typeof sizes\n}\n\nexport function buttonVariants({ variant = 'secondary', size = 'md', className }: ButtonVariantProps & { className?: string } = {}) {\n return cn(\n 'tollerud-btn inline-flex items-center justify-center gap-2 font-semibold rounded transition-all duration-[150ms] focus-visible:outline-2 focus-visible:outline-tollerud-yellow focus-visible:outline-offset-2',\n 'border cursor-pointer',\n 'disabled:opacity-50 disabled:pointer-events-none',\n variants[variant],\n variantLayers[variant],\n sizes[size],\n className\n )\n}\n\nexport interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement>, ButtonVariantProps {\n /** Render as the single child element (e.g. a `<Link>`) instead of a `<button>`, merging props and styles onto it. */\n asChild?: boolean\n}\n\nconst Button = forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant = 'secondary', size = 'md', asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : 'button'\n return (\n <Comp\n ref={ref}\n className={buttonVariants({ variant, size, className })}\n {...props}\n />\n )\n }\n)\nButton.displayName = 'Button'\n\nexport { Button }\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../components/CTABand.tsx"],"names":[],"mappings":";;;;AAUA,IAAM,OAAA,GAAU,UAAA;AAAA,EACd,CAAC,EAAE,SAAA,EAAW,KAAA,EAAO,WAAA,EAAa,OAAA,EAAS,SAAA,GAAY,IAAA,EAAM,GAAG,KAAA,EAAM,EAAG,GAAA,KAAQ;AAC/E,IAAA,uBACE,IAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,SAAA,EAAW,EAAA;AAAA,UACT,mGAAA;AAAA,UACA;AAAA,SACF;AAAA,QACC,GAAG,KAAA;AAAA,QAEJ,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,yDAAA,EAA2D,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,UAC9E,WAAA,oBACC,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,uEACV,QAAA,EAAA,WAAA,EACH,CAAA;AAAA,UAED,OAAA,oBACC,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,8DAA8D,QAAA,EAAA,OAAA,EAAQ,CAAA;AAAA,UAEtF,SAAA,oBACC,GAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,qFAAA,EAAsF;AAAA;AAAA;AAAA,KAExG;AAAA,EAEJ;AACF;AACA,OAAA,CAAQ,WAAA,GAAc,SAAA","file":"chunk-IUPVQWO5.js","sourcesContent":["import { type HTMLAttributes, forwardRef } from 'react'\nimport { cn } from '@/lib/utils'\n\nexport interface CTABandProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {\n title: React.ReactNode\n description?: React.ReactNode\n actions?: React.ReactNode\n accentBar?: boolean\n}\n\nconst CTABand = forwardRef<HTMLDivElement, CTABandProps>(\n ({ className, title, description, actions, accentBar = true, ...props }, ref) => {\n return (\n <div\n ref={ref}\n className={cn(\n 'tollerud-card rounded-xl border border-tollerud-border bg-tollerud-surface px-8 py-11 text-center',\n className\n )}\n {...props}\n >\n <h2 className=\"tollerud-display text-[30px] text-tollerud-text-primary\">{title}</h2>\n {description && (\n <p className=\"mx-auto mt-3 max-w-[440px] text-[15px] text-tollerud-text-secondary\">\n {description}\n </p>\n )}\n {actions && (\n <div className=\"mt-[22px] flex flex-wrap items-center justify-center gap-3\">{actions}</div>\n )}\n {accentBar && (\n <hr className=\"tollerud-accent-bar tollerud-accent-bar--inline mx-auto mt-8 max-w-[320px] border-0\" />\n )}\n </div>\n )\n }\n)\nCTABand.displayName = 'CTABand'\n\nexport { CTABand }\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../components/BentoDashboard.tsx"],"names":[],"mappings":"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","file":"chunk-ONMTHBZ4.js","sourcesContent":["'use client'\n\nimport { type ReactNode } from 'react'\nimport { cn } from '@/lib/utils'\nimport { HostCard, type HostCardProps } from './HostCard'\nimport { StatCard, type StatCardProps } from './StatCard'\nimport { ServiceHealthCard, type ServiceHealthCardProps } from './ServiceHealthCard'\nimport { IncidentCard } from './IncidentCard'\nimport type { IncidentSeverity } from './IncidentCard'\nimport type { BackupJob } from './BackupStatusPanel'\n\n/* ──────────────────── Bento Grid Dashboard Template ──────────────────── */\n\nexport interface BentoDashboardProps {\n title: string\n hosts?: HostCardProps[]\n metrics?: StatCardProps[]\n services?: ServiceHealthCardProps[]\n incidents?: { title: string; severity: IncidentSeverity; timestamp: string; service: string; description?: string; acknowledged?: boolean }[]\n backupJobs?: BackupJob[]\n className?: string\n /** Render the incident list footer */\n renderIncidentFooter?: () => ReactNode\n}\n\nexport function BentoDashboard({\n title,\n hosts = [],\n metrics = [],\n services = [],\n incidents = [],\n className,\n}: BentoDashboardProps) {\n return (\n <div className={cn('space-y-4', className)}>\n {/* Title bar */}\n <div className=\"flex items-center justify-between\">\n <div>\n <h2 className=\"text-lg font-semibold text-tollerud-text-primary\">{title}</h2>\n <p className=\"text-xs text-tollerud-text-muted\">\n {hosts.length} hosts · {services.length} services\n {incidents.length > 0 && ` · ${incidents.length} active incident${incidents.length > 1 ? 's' : ''}`}\n </p>\n </div>\n </div>\n\n {/* Row 1: Host cards — bento asymmetric */}\n {hosts.length > 0 && (\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-3\">\n <div className=\"md:col-span-2 lg:col-span-1\">\n <HostCard {...hosts[0]} />\n </div>\n <div className=\"grid grid-cols-1 gap-3 md:col-span-2 lg:col-span-1\">\n {hosts.slice(1).map((h, i) => (\n <HostCard key={h.hostname ?? i} {...h} />\n ))}\n </div>\n </div>\n )}\n\n {/* Row 2: Metrics + Services — side by side */}\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-3\">\n {metrics.length > 0 && (\n <div className=\"lg:col-span-2\">\n <SectionLabel>Metrics</SectionLabel>\n <div className=\"grid grid-cols-2 sm:grid-cols-4 gap-2\">\n {metrics.map((m, i) => (\n <StatCard key={m.label ?? i} {...m} />\n ))}\n </div>\n </div>\n )}\n\n {services.length > 0 && (\n <div>\n <SectionLabel>Services</SectionLabel>\n <div className=\"space-y-2\">\n {services.slice(0, 4).map((s, i) => (\n <ServiceHealthCard key={s.service ?? i} {...s} />\n ))}\n </div>\n </div>\n )}\n </div>\n\n {/* Row 3: Incidents — full width */}\n {incidents.length > 0 && (\n <div>\n <SectionLabel>Recent Incidents</SectionLabel>\n <div className=\"space-y-1.5\">\n {incidents.slice(0, 4).map((inc, i) => (\n <IncidentCard key={inc.title + i} {...inc} />\n ))}\n </div>\n </div>\n )}\n </div>\n )\n}\n\nfunction SectionLabel({ children }: { children: ReactNode }) {\n return (\n <p className=\"text-xs font-semibold text-tollerud-text-muted uppercase tracking-wider mb-2\">{children}</p>\n )\n}\n\nexport default BentoDashboard\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../components/Checkbox.tsx"],"names":[],"mappings":";;;;AASA,IAAM,QAAA,GAAW,UAAA;AAAA,EACf,CAAC,EAAE,SAAA,EAAW,KAAA,EAAO,EAAA,EAAI,QAAQ,OAAA,EAAS,GAAG,KAAA,EAAM,EAAG,GAAA,KAAQ;AAC5D,IAAA,MAAM,SAAS,KAAA,EAAM;AACrB,IAAA,MAAM,KAAK,MAAA,IAAU,MAAA;AAErB,IAAA,uBACE,IAAA;AAAA,MAAC,OAAA;AAAA,MAAA;AAAA,QACC,OAAA,EAAS,EAAA;AAAA,QACT,SAAA,EAAW,EAAA;AAAA,UACT,iEAAA;AAAA,UACA,oCAAA;AAAA,UACA,MAAM,QAAA,IAAY,gCAAA;AAAA,UAClB;AAAA,SACF;AAAA,QAEA,QAAA,EAAA;AAAA,0BAAA,IAAA,CAAC,MAAA,EAAA,EAAK,WAAU,2CAAA,EACd,QAAA,EAAA;AAAA,4BAAA,GAAA;AAAA,cAAC,OAAA;AAAA,cAAA;AAAA,gBACC,GAAA;AAAA,gBACA,EAAA;AAAA,gBACA,IAAA,EAAK,UAAA;AAAA,gBACL,OAAA;AAAA,gBACA,SAAA,EAAU,cAAA;AAAA,gBACT,GAAG;AAAA;AAAA,aACN;AAAA,4BAEA,GAAA;AAAA,cAAC,MAAA;AAAA,cAAA;AAAA,gBACC,SAAA,EAAW,EAAA;AAAA,kBACT,wDAAA;AAAA,kBACA,kCAAA;AAAA,kBACA,mDAAA;AAAA,kBACA,yEAAA;AAAA,kBACA,qEAAA;AAAA,kBACA;AAAA,iBACF;AAAA,gBAGA,QAAA,kBAAA,GAAA;AAAA,kBAAC,KAAA;AAAA,kBAAA;AAAA,oBACC,SAAA,EAAW,EAAA;AAAA,sBACT,sEAAA;AAAA,sBACA,UAAU,aAAA,GAAgB;AAAA,qBAC5B;AAAA,oBACA,OAAA,EAAQ,WAAA;AAAA,oBACR,IAAA,EAAK,MAAA;AAAA,oBACL,aAAA,EAAY,MAAA;AAAA,oBAEZ,QAAA,kBAAA,GAAA;AAAA,sBAAC,MAAA;AAAA,sBAAA;AAAA,wBACC,CAAA,EAAE,sBAAA;AAAA,wBACF,MAAA,EAAO,cAAA;AAAA,wBACP,WAAA,EAAa,CAAA;AAAA,wBACb,aAAA,EAAc,OAAA;AAAA,wBACd,cAAA,EAAe;AAAA;AAAA;AACjB;AAAA;AACF;AAAA;AACF,WAAA,EACF,CAAA;AAAA,UACC,KAAA,oBAAS,GAAA,CAAC,MAAA,EAAA,EAAM,QAAA,EAAA,KAAA,EAAM;AAAA;AAAA;AAAA,KACzB;AAAA,EAEJ;AACF;AACA,QAAA,CAAS,WAAA,GAAc,UAAA","file":"chunk-T3TQPOVM.js","sourcesContent":["'use client'\n\nimport { type InputHTMLAttributes, forwardRef, useId } from 'react'\nimport { cn } from '@/lib/utils'\n\nexport interface CheckboxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'type'> {\n label?: string\n}\n\nconst Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(\n ({ className, label, id: idProp, checked, ...props }, ref) => {\n const autoId = useId()\n const id = idProp ?? autoId\n\n return (\n <label\n htmlFor={id}\n className={cn(\n 'inline-flex items-center gap-2 cursor-pointer select-none group',\n 'text-sm text-tollerud-text-primary',\n props.disabled && 'opacity-50 pointer-events-none',\n className\n )}\n >\n <span className=\"relative flex items-center justify-center\">\n <input\n ref={ref}\n id={id}\n type=\"checkbox\"\n checked={checked}\n className=\"peer sr-only\"\n {...props}\n />\n {/* Custom box */}\n <span\n className={cn(\n 'h-4 w-4 rounded border transition-all duration-[150ms]',\n 'flex items-center justify-center',\n 'bg-tollerud-surface-raised border-tollerud-border',\n 'peer-focus-visible:outline-2 peer-focus-visible:outline-tollerud-yellow',\n 'peer-checked:bg-tollerud-yellow peer-checked:border-tollerud-yellow',\n 'group-hover:border-tollerud-text-secondary'\n )}\n >\n {/* Checkmark SVG — visible when checked */}\n <svg\n className={cn(\n 'h-3 w-3 text-tollerud-noir-black transition-opacity duration-[150ms]',\n checked ? 'opacity-100' : 'opacity-0'\n )}\n viewBox=\"0 0 12 12\"\n fill=\"none\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M2.5 6l2.5 2.5 4.5-5\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </span>\n </span>\n {label && <span>{label}</span>}\n </label>\n )\n }\n)\nCheckbox.displayName = 'Checkbox'\n\nexport { Checkbox }"]}
package/globals-v4.css DELETED
@@ -1,2 +0,0 @@
1
- /* @tollerud/ui/globals-v4.css — alias for globals.css (Tailwind v4). Prefer globals.css. */
2
- @import "./globals.css";
File without changes