@tollerud/ui 3.1.0 → 3.1.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 (39) hide show
  1. package/AGENTS.md +3 -1
  2. package/CHANGELOG.md +32 -0
  3. package/COMPONENTS.md +13 -1
  4. package/README.md +1 -0
  5. package/SKILL.md +4 -2
  6. package/components.json +1 -1
  7. package/dist/bento-dashboard.js +1 -1
  8. package/dist/button.d.ts +2 -2
  9. package/dist/button.js +1 -1
  10. package/dist/checkbox.js +1 -1
  11. package/dist/{chunk-ADE22JSR.js → chunk-BQWF5MP7.js} +7 -7
  12. package/dist/chunk-BQWF5MP7.js.map +1 -0
  13. package/dist/{chunk-IUPVQWO5.js → chunk-FPFLOYIJ.js} +5 -5
  14. package/dist/chunk-FPFLOYIJ.js.map +1 -0
  15. package/dist/{chunk-6SKTH45H.js → chunk-J2Z4ZFVX.js} +29 -18
  16. package/dist/chunk-J2Z4ZFVX.js.map +1 -0
  17. package/dist/{chunk-YPP7QHYT.js → chunk-K4ALNUZI.js} +4 -4
  18. package/dist/{chunk-YPP7QHYT.js.map → chunk-K4ALNUZI.js.map} +1 -1
  19. package/dist/{chunk-ONMTHBZ4.js → chunk-LGVXEWNB.js} +10 -10
  20. package/dist/chunk-LGVXEWNB.js.map +1 -0
  21. package/dist/{chunk-OVSIOZHJ.js → chunk-SNNMZ444.js} +3 -3
  22. package/dist/{chunk-OVSIOZHJ.js.map → chunk-SNNMZ444.js.map} +1 -1
  23. package/dist/{chunk-T3TQPOVM.js → chunk-TLEKK53J.js} +5 -8
  24. package/dist/chunk-TLEKK53J.js.map +1 -0
  25. package/dist/cta-band.js +1 -1
  26. package/dist/data-table.js +3 -3
  27. package/dist/index.js +7 -7
  28. package/dist/pricing-card.js +2 -2
  29. package/dist/radio-group.d.ts +6 -0
  30. package/dist/radio-group.js +1 -1
  31. package/globals-layers.css +27 -1
  32. package/package.json +1 -1
  33. package/registry.json +14 -9
  34. package/tokens.css +29 -5
  35. package/dist/chunk-6SKTH45H.js.map +0 -1
  36. package/dist/chunk-ADE22JSR.js.map +0 -1
  37. package/dist/chunk-IUPVQWO5.js.map +0 -1
  38. package/dist/chunk-ONMTHBZ4.js.map +0 -1
  39. package/dist/chunk-T3TQPOVM.js.map +0 -1
package/AGENTS.md CHANGED
@@ -330,7 +330,9 @@ Monogram sizing: top bar/sidebar expanded → `h-5`, sidebar collapsed → `h-6`
330
330
 
331
331
  ```html
332
332
  <h1 class="tollerud-display text-[70px]">Dark. Monochrome.</h1>
333
- <h2 class="tollerud-display--secondary text-[40px]">Yellow where it counts</h2>
333
+ <h2 class="tollerud-display--secondary text-[40px]">
334
+ <span class="tollerud-display-shimmer">Yellow where it counts</span>
335
+ </h2>
334
336
  ```
335
337
 
336
338
  ### Container
package/CHANGELOG.md CHANGED
@@ -7,6 +7,38 @@
7
7
  • Never write bold mid-paragraph as a heading substitute — it merges into surrounding text
8
8
  -->
9
9
 
10
+ ## 3.1.1 — 2026-06-09 — Display shimmer, form indicators, and button fixes
11
+
12
+ Patch release: ships hero text shimmer for consumer apps, fixes secondary/checkbox/radio styling, and polishes docs layout components.
13
+
14
+ ### New utilities
15
+
16
+ - `.tollerud-display-shimmer` — animated yellow gradient clipped to text; respects `prefers-reduced-motion` (static `var(--primary)` fallback)
17
+
18
+ ### Fixes
19
+
20
+ - `Button` — secondary variant restores raised surface and border (theme-aware CSS vars); all variants apply layer classes again
21
+ - `Checkbox` — checkmark visible on `defaultChecked` and click via `peer-checked` on the custom indicator
22
+ - `RadioGroup` — wires `value`, `onChange`, and `name` to children; inner dot shows when selected
23
+ - `CTABand` — title and description centered in the band
24
+ - `BentoDashboard` — section spacing and label alignment
25
+ - Docs `PageTOC` — restores `jumpToSection` import for in-page scroll
26
+
27
+ ### Registry
28
+
29
+ - Top-level `name` → `Tollerud User Interface`; updated description and component metadata for blocks
30
+
31
+ ### Docs
32
+
33
+ - Overview, Backgrounds, and Foundations Typography use `.tollerud-display-shimmer` (replaces docs-only `.ds-shimmer`)
34
+ - Light theme shimmer and secondary-button token overrides
35
+
36
+ ### Migration
37
+
38
+ Drop-in. Replace any copied `.ds-shimmer` with `.tollerud-display-shimmer` from `@tollerud/ui/globals.css`.
39
+
40
+ ---
41
+
10
42
  ## 3.1.0 — 2026-06-09 — Monogram component and docs fixes
11
43
 
12
44
  Restores component styling in the docs site, ships the monogram as an npm component, and renames brand avatar assets.
package/COMPONENTS.md CHANGED
@@ -786,10 +786,22 @@ The config-driven table. Pass `rows` + a `columns` spec and opt into search, a f
786
786
 
787
787
  ```html
788
788
  <h1 class="tollerud-display text-[70px]">Dark. Monochrome.</h1>
789
- <h2 class="tollerud-display--secondary text-[40px]">Yellow where it counts</h2>
789
+ <h2 class="tollerud-display--secondary text-[40px]">
790
+ <span class="tollerud-display-shimmer">Yellow where it counts</span>
791
+ </h2>
790
792
  <h3 class="tollerud-display--tertiary text-[28px]">Subtle hierarchy</h3>
791
793
  ```
792
794
 
795
+ ## Display shimmer
796
+
797
+ Animated yellow gradient clipped to text — for hero accent lines and key metrics on **dark surfaces**. Respects `prefers-reduced-motion` (falls back to static `var(--primary)` / `var(--tollerud-yellow)`).
798
+
799
+ ```html
800
+ <span class="tollerud-display-shimmer">Yellow where it counts.</span>
801
+ ```
802
+
803
+ Pair with `.tollerud-display` on the parent heading. Not for body copy or light backgrounds (yellow fails contrast on white).
804
+
793
805
  ## Container
794
806
 
795
807
  ```jsx
package/README.md CHANGED
@@ -288,4 +288,5 @@ New additions inspired by [Graphify Labs](https://graphifylabs.ai/):
288
288
  | Accent Bar | `.tollerud-accent-bar` | `bg-tollerud-gradient-bar h-[1px]` | Gradient divider bar |
289
289
  | Gradient Text | `.tollerud-gradient-text` | `bg-tollerud-gradient-soft bg-clip-text text-transparent` | Yellow → amber gradient text |
290
290
  | Display Heading | `.tollerud-display` | `tracking-tightest leading-[0.95] font-semibold text-white` | Tight, impactful display heads |
291
+ | Display Shimmer | `.tollerud-display-shimmer` | — | Animated yellow gradient sweep clipped to hero accent text (dark surfaces) |
291
292
  | Section Container | `.tollerud-section` | `max-w-[1100px] mx-auto px-6` | Content width constraint |
package/SKILL.md CHANGED
@@ -20,7 +20,7 @@ npm install @tollerud/ui clsx tailwind-merge tailwindcss@4 \
20
20
  npm install @paper-design/shaders-react
21
21
  ```
22
22
 
23
- As of **v3.1.0**, `Monogram` ships as an inline SVG component (`color`: `yellow` | `black` | `white`). As of **v3.0.0**, the package is **ESM-only** (no CJS `require` entry). As of **v2.0.0**, Radix, Lucide, Framer Motion, and Sonner are **required peers** (not bundled).
23
+ As of **v3.1.1**, `.tollerud-display-shimmer` ships in `globals.css` for animated hero accent text. As of **v3.1.0**, `Monogram` ships as an inline SVG component (`color`: `yellow` | `black` | `white`). As of **v3.0.0**, the package is **ESM-only** (no CJS `require` entry). As of **v2.0.0**, Radix, Lucide, Framer Motion, and Sonner are **required peers** (not bundled).
24
24
 
25
25
  Apply the Tailwind preset when you need extra utilities from `tollerud-preset.js` — `globals.css` already includes tokens and component layers for v4:
26
26
 
@@ -469,7 +469,9 @@ Monogram sizing: top bar/sidebar expanded → `h-5`, collapsed → `h-6`, footer
469
469
  <nav class="tollerud-glass fixed top-0 inset-x-0 z-50 h-14 flex items-center px-6">…</nav>
470
470
  <section class="tollerud-grid-bg">…</section>
471
471
  <h1 class="tollerud-display text-[70px]">Dark. Monochrome.</h1>
472
- <h2 class="tollerud-display--secondary text-[40px]">Yellow where it counts</h2>
472
+ <h2 class="tollerud-display--secondary text-[40px]">
473
+ <span class="tollerud-display-shimmer">Yellow where it counts</span>
474
+ </h2>
473
475
  <div data-density="compact">…dense tables / forms…</div>
474
476
  ```
475
477
 
package/components.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://ui.shadcn.com/schema.json",
3
- "name": "tollerud-noir",
3
+ "name": "Tollerud User Interface",
4
4
  "style": "default",
5
5
  "rsc": true,
6
6
  "tsx": true,
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- export { BentoDashboard } from './chunk-ONMTHBZ4.js';
2
+ export { BentoDashboard } from './chunk-LGVXEWNB.js';
3
3
  import './chunk-LUM2YJBH.js';
4
4
  import './chunk-7EP2T3OW.js';
5
5
  import './chunk-DOUDJU4P.js';
package/dist/button.d.ts CHANGED
@@ -3,8 +3,8 @@ import { ButtonHTMLAttributes } from 'react';
3
3
 
4
4
  declare const variants: {
5
5
  readonly primary: "bg-tollerud-yellow text-tollerud-black border-tollerud-yellow hover:bg-tollerud-yellow hover:shadow-tollerud-glow";
6
- readonly secondary: "bg-transparent text-tollerud-text-primary border-tollerud-border hover:border-tollerud-text-secondary hover:bg-tollerud-surface-hover";
7
- readonly ghost: "bg-transparent text-tollerud-text-secondary border-transparent hover:text-tollerud-text-primary hover:bg-tollerud-surface-hover";
6
+ readonly secondary: "text-tollerud-text-primary [background:var(--surface-raised,var(--tollerud-surface-raised))] [border-color:var(--border,var(--tollerud-border))] hover:[border-color:var(--text-secondary,var(--tollerud-text-secondary))] hover:[background:var(--surface-hover,var(--tollerud-surface-hover))]";
7
+ readonly ghost: "text-tollerud-text-secondary border-transparent hover:text-tollerud-text-primary hover:bg-tollerud-surface-hover";
8
8
  readonly destructive: "bg-tollerud-error text-white border-tollerud-error hover:shadow-[0_0_12px_rgba(239,68,68,0.3)]";
9
9
  readonly 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)]";
10
10
  };
package/dist/button.js CHANGED
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- export { Button, buttonVariants } from './chunk-ADE22JSR.js';
2
+ export { Button, buttonVariants } from './chunk-BQWF5MP7.js';
3
3
  import './chunk-WSQNPRGN.js';
4
4
  //# sourceMappingURL=button.js.map
5
5
  //# sourceMappingURL=button.js.map
package/dist/checkbox.js CHANGED
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- export { Checkbox } from './chunk-T3TQPOVM.js';
2
+ export { Checkbox } from './chunk-TLEKK53J.js';
3
3
  import './chunk-WSQNPRGN.js';
4
4
  //# sourceMappingURL=checkbox.js.map
5
5
  //# sourceMappingURL=checkbox.js.map
@@ -6,16 +6,16 @@ import { jsx } from 'react/jsx-runtime';
6
6
 
7
7
  var variants = {
8
8
  primary: "bg-tollerud-yellow text-tollerud-black border-tollerud-yellow hover:bg-tollerud-yellow hover:shadow-tollerud-glow",
9
- secondary: "bg-transparent text-tollerud-text-primary border-tollerud-border hover:border-tollerud-text-secondary hover:bg-tollerud-surface-hover",
10
- ghost: "bg-transparent text-tollerud-text-secondary border-transparent hover:text-tollerud-text-primary hover:bg-tollerud-surface-hover",
9
+ secondary: "text-tollerud-text-primary [background:var(--surface-raised,var(--tollerud-surface-raised))] [border-color:var(--border,var(--tollerud-border))] hover:[border-color:var(--text-secondary,var(--tollerud-text-secondary))] hover:[background:var(--surface-hover,var(--tollerud-surface-hover))]",
10
+ ghost: "text-tollerud-text-secondary border-transparent hover:text-tollerud-text-primary hover:bg-tollerud-surface-hover",
11
11
  destructive: "bg-tollerud-error text-white border-tollerud-error hover:shadow-[0_0_12px_rgba(239,68,68,0.3)]",
12
12
  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)]"
13
13
  };
14
14
  var variantLayers = {
15
15
  primary: "tollerud-btn--primary",
16
- secondary: "",
17
- ghost: "",
18
- destructive: "",
16
+ secondary: "tollerud-btn--secondary",
17
+ ghost: "tollerud-btn--ghost",
18
+ destructive: "tollerud-btn--destructive",
19
19
  terminal: "tollerud-btn--terminal"
20
20
  };
21
21
  var sizes = {
@@ -50,5 +50,5 @@ var Button = forwardRef(
50
50
  Button.displayName = "Button";
51
51
 
52
52
  export { Button, buttonVariants };
53
- //# sourceMappingURL=chunk-ADE22JSR.js.map
54
- //# sourceMappingURL=chunk-ADE22JSR.js.map
53
+ //# sourceMappingURL=chunk-BQWF5MP7.js.map
54
+ //# sourceMappingURL=chunk-BQWF5MP7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../components/Button.tsx"],"names":[],"mappings":";;;;;AAIA,IAAM,QAAA,GAAW;AAAA,EACf,OAAA,EAAS,mHAAA;AAAA,EACT,SAAA,EACE,kSAAA;AAAA,EACF,KAAA,EAAO,kHAAA;AAAA,EACP,WAAA,EAAa,gGAAA;AAAA,EACb,QAAA,EAAU;AACZ,CAAA;AAGA,IAAM,aAAA,GAAgB;AAAA,EACpB,OAAA,EAAS,uBAAA;AAAA,EACT,SAAA,EAAW,yBAAA;AAAA,EACX,KAAA,EAAO,qBAAA;AAAA,EACP,WAAA,EAAa,2BAAA;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-BQWF5MP7.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:\n 'text-tollerud-text-primary [background:var(--surface-raised,var(--tollerud-surface-raised))] [border-color:var(--border,var(--tollerud-border))] hover:[border-color:var(--text-secondary,var(--tollerud-text-secondary))] hover:[background:var(--surface-hover,var(--tollerud-surface-hover))]',\n ghost: '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: 'tollerud-btn--secondary',\n ghost: 'tollerud-btn--ghost',\n destructive: 'tollerud-btn--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"]}
@@ -10,13 +10,13 @@ var CTABand = forwardRef(
10
10
  {
11
11
  ref,
12
12
  className: cn(
13
- "tollerud-card rounded-xl border border-tollerud-border bg-tollerud-surface px-8 py-11 text-center",
13
+ "tollerud-card w-full rounded-xl border border-tollerud-border bg-tollerud-surface px-8 py-11 text-center",
14
14
  className
15
15
  ),
16
16
  ...props,
17
17
  children: [
18
- /* @__PURE__ */ jsx("h2", { className: "tollerud-display text-[30px] text-tollerud-text-primary", children: title }),
19
- description && /* @__PURE__ */ jsx("p", { className: "mx-auto mt-3 max-w-[440px] text-[15px] text-tollerud-text-secondary", children: description }),
18
+ /* @__PURE__ */ jsx("h2", { className: "tollerud-display mx-auto max-w-[640px] text-center text-[30px] text-tollerud-text-primary", children: title }),
19
+ description && /* @__PURE__ */ jsx("p", { className: "mx-auto mt-3 max-w-[440px] text-center text-[15px] text-tollerud-text-secondary", children: description }),
20
20
  actions && /* @__PURE__ */ jsx("div", { className: "mt-[22px] flex flex-wrap items-center justify-center gap-3", children: actions }),
21
21
  accentBar && /* @__PURE__ */ jsx("hr", { className: "tollerud-accent-bar tollerud-accent-bar--inline mx-auto mt-8 max-w-[320px] border-0" })
22
22
  ]
@@ -27,5 +27,5 @@ var CTABand = forwardRef(
27
27
  CTABand.displayName = "CTABand";
28
28
 
29
29
  export { CTABand };
30
- //# sourceMappingURL=chunk-IUPVQWO5.js.map
31
- //# sourceMappingURL=chunk-IUPVQWO5.js.map
30
+ //# sourceMappingURL=chunk-FPFLOYIJ.js.map
31
+ //# sourceMappingURL=chunk-FPFLOYIJ.js.map
@@ -0,0 +1 @@
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,0GAAA;AAAA,UACA;AAAA,SACF;AAAA,QACC,GAAG,KAAA;AAAA,QAEJ,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,2FAAA,EACX,QAAA,EAAA,KAAA,EACH,CAAA;AAAA,UACC,WAAA,oBACC,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,mFACV,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-FPFLOYIJ.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 w-full 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 mx-auto max-w-[640px] text-center text-[30px] text-tollerud-text-primary\">\n {title}\n </h2>\n {description && (\n <p className=\"mx-auto mt-3 max-w-[440px] text-center 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,20 +1,38 @@
1
1
  'use client';
2
2
  import { cn } from './chunk-WSQNPRGN.js';
3
- import { forwardRef, useId } from 'react';
3
+ import { forwardRef, useId, Children, isValidElement, cloneElement } from 'react';
4
4
  import { jsxs, jsx } from 'react/jsx-runtime';
5
5
 
6
6
  var RadioGroup = forwardRef(
7
- ({ label, error, children, className }, ref) => {
7
+ ({ label, error, value, onChange, name: nameProp, children, className }, ref) => {
8
+ const autoName = useId();
9
+ const name = nameProp ?? autoName;
10
+ const wired = Children.map(children, (child) => {
11
+ if (!isValidElement(child)) return child;
12
+ const radio = child;
13
+ const optionValue = radio.props.value;
14
+ if (optionValue === void 0) return child;
15
+ const option = String(optionValue);
16
+ const checked = value !== void 0 ? value === option : radio.props.checked;
17
+ return cloneElement(radio, {
18
+ name,
19
+ ...checked !== void 0 ? { checked } : {},
20
+ onChange: (e) => {
21
+ radio.props.onChange?.(e);
22
+ if (e.target.checked) onChange?.(option);
23
+ }
24
+ });
25
+ });
8
26
  return /* @__PURE__ */ jsxs("fieldset", { ref, className: cn("flex flex-col gap-1", className), children: [
9
27
  label && /* @__PURE__ */ jsx("legend", { className: "text-xs font-medium text-tollerud-text-muted mb-1", children: label }),
10
- /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children }),
28
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: wired }),
11
29
  error && /* @__PURE__ */ jsx("p", { className: "text-xs text-tollerud-error mt-0.5", children: error })
12
30
  ] });
13
31
  }
14
32
  );
15
33
  RadioGroup.displayName = "RadioGroup";
16
34
  var Radio = forwardRef(
17
- ({ className, label, id: idProp, ...props }, ref) => {
35
+ ({ className, label, id: idProp, checked, ...props }, ref) => {
18
36
  const autoId = useId();
19
37
  const id = idProp ?? autoId;
20
38
  return /* @__PURE__ */ jsxs(
@@ -35,6 +53,7 @@ var Radio = forwardRef(
35
53
  ref,
36
54
  id,
37
55
  type: "radio",
56
+ ...checked !== void 0 ? { checked } : {},
38
57
  className: "peer sr-only",
39
58
  ...props
40
59
  }
@@ -43,22 +62,14 @@ var Radio = forwardRef(
43
62
  "span",
44
63
  {
45
64
  className: cn(
46
- "h-4 w-4 rounded-full border transition-all duration-[150ms]",
65
+ "flex h-4 w-4 items-center justify-center rounded-full border transition-all duration-[150ms]",
47
66
  "bg-tollerud-surface-raised border-tollerud-border",
48
67
  "peer-focus-visible:outline-2 peer-focus-visible:outline-tollerud-yellow",
49
68
  "peer-checked:border-tollerud-yellow",
50
- "group-hover:border-tollerud-text-secondary",
51
- "flex items-center justify-center"
69
+ "peer-checked:[&>span]:opacity-100",
70
+ "group-hover:border-tollerud-text-secondary"
52
71
  ),
53
- children: /* @__PURE__ */ jsx(
54
- "span",
55
- {
56
- className: cn(
57
- "h-2 w-2 rounded-full bg-tollerud-yellow transition-opacity duration-[150ms]",
58
- props.checked ? "opacity-100" : "opacity-0"
59
- )
60
- }
61
- )
72
+ children: /* @__PURE__ */ jsx("span", { className: "pointer-events-none h-2 w-2 rounded-full bg-tollerud-yellow opacity-0 transition-opacity duration-[150ms]" })
62
73
  }
63
74
  )
64
75
  ] }),
@@ -71,5 +82,5 @@ var Radio = forwardRef(
71
82
  Radio.displayName = "Radio";
72
83
 
73
84
  export { Radio, RadioGroup };
74
- //# sourceMappingURL=chunk-6SKTH45H.js.map
75
- //# sourceMappingURL=chunk-6SKTH45H.js.map
85
+ //# sourceMappingURL=chunk-J2Z4ZFVX.js.map
86
+ //# sourceMappingURL=chunk-J2Z4ZFVX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../components/RadioGroup.tsx"],"names":[],"mappings":"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","file":"chunk-J2Z4ZFVX.js","sourcesContent":["'use client'\n\nimport {\n Children,\n cloneElement,\n isValidElement,\n type InputHTMLAttributes,\n type ReactElement,\n forwardRef,\n useId,\n} from 'react'\nimport { cn } from '@/lib/utils'\n\nexport interface RadioGroupProps {\n /** Group label */\n label?: string\n /** Error message */\n error?: string\n /** Controlled selected value */\n value?: string\n /** Called with the selected option value */\n onChange?: (value: string) => void\n /** Shared name for native radio grouping (auto-generated if omitted) */\n name?: string\n children?: React.ReactNode\n className?: string\n}\n\nconst RadioGroup = forwardRef<HTMLFieldSetElement, RadioGroupProps>(\n ({ label, error, value, onChange, name: nameProp, children, className }, ref) => {\n const autoName = useId()\n const name = nameProp ?? autoName\n\n const wired = Children.map(children, (child) => {\n if (!isValidElement(child)) return child\n const radio = child as ReactElement<RadioProps>\n const optionValue = radio.props.value\n if (optionValue === undefined) return child\n\n const option = String(optionValue)\n const checked = value !== undefined ? value === option : radio.props.checked\n\n return cloneElement(radio, {\n name,\n ...(checked !== undefined ? { checked } : {}),\n onChange: (e) => {\n radio.props.onChange?.(e)\n if (e.target.checked) onChange?.(option)\n },\n })\n })\n\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\">{wired}</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, 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=\"radio\"\n {...(checked !== undefined ? { checked } : {})}\n className=\"peer sr-only\"\n {...props}\n />\n {/* Custom radio circle */}\n <span\n className={cn(\n 'flex h-4 w-4 items-center justify-center 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 'peer-checked:[&>span]:opacity-100',\n 'group-hover:border-tollerud-text-secondary'\n )}\n >\n {/* Inner dot — visible when checked (via peer on sibling input) */}\n <span className=\"pointer-events-none h-2 w-2 rounded-full bg-tollerud-yellow opacity-0 transition-opacity duration-[150ms]\" />\n </span>\n </span>\n {label && <span>{label}</span>}\n </label>\n )\n }\n)\nRadio.displayName = 'Radio'\n\nexport { RadioGroup, Radio }"]}
@@ -3,9 +3,9 @@ import { Skeleton } from './chunk-AQT3FZRQ.js';
3
3
  import { Segmented } from './chunk-NSMU66ZX.js';
4
4
  import { Pagination } from './chunk-RJTDQOT2.js';
5
5
  import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuSeparator, DropdownMenuLabel, DropdownMenuItem } from './chunk-435JHF7G.js';
6
- import { Checkbox } from './chunk-T3TQPOVM.js';
6
+ import { Checkbox } from './chunk-TLEKK53J.js';
7
7
  import { Badge } from './chunk-QEHTPQHL.js';
8
- import { Button } from './chunk-ADE22JSR.js';
8
+ import { Button } from './chunk-BQWF5MP7.js';
9
9
  import { cn } from './chunk-WSQNPRGN.js';
10
10
  import { forwardRef, useMemo, useState } from 'react';
11
11
  import { Search, X, MoreHorizontal, ChevronDown } from 'lucide-react';
@@ -389,5 +389,5 @@ var DataTable = forwardRef((props, ref) => /* @__PURE__ */ jsx(DataTableInner, {
389
389
  DataTable.displayName = "DataTable";
390
390
 
391
391
  export { DataTable };
392
- //# sourceMappingURL=chunk-YPP7QHYT.js.map
393
- //# sourceMappingURL=chunk-YPP7QHYT.js.map
392
+ //# sourceMappingURL=chunk-K4ALNUZI.js.map
393
+ //# sourceMappingURL=chunk-K4ALNUZI.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../components/DataTable.tsx"],"names":[],"mappings":"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","file":"chunk-YPP7QHYT.js","sourcesContent":["'use client'\n\nimport { useState, useMemo, forwardRef, type ReactNode } from 'react'\nimport { ChevronDown, MoreHorizontal, Search, X } from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport { Badge } from './Badge'\nimport { Button } from './Button'\nimport { Checkbox } from './Checkbox'\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from './DropdownMenu'\nimport { Pagination } from './Pagination'\nimport { Segmented } from './Segmented'\nimport { Skeleton } from './Skeleton'\n\n/* ──────────────────── Sortable & Filterable Data Table ──────────────────── */\n\nexport interface Column<T> {\n key: string\n label: string\n sortable?: boolean\n filterable?: boolean\n align?: 'left' | 'center' | 'right'\n width?: string\n render?: (value: unknown, row: T) => ReactNode\n}\n\nexport interface DataTableFilter {\n key: string\n options?: string[]\n allLabel?: string\n}\n\nexport interface DataTableBulkAction {\n label: string\n variant?: 'primary' | 'secondary' | 'ghost' | 'destructive' | 'terminal'\n icon?: ReactNode\n onRun: (selectedIds: (string | number)[], clearSelection: () => void) => void\n}\n\nexport interface DataTableRowMenuItem {\n label: string\n onSelect?: () => void\n icon?: ReactNode\n sep?: boolean\n heading?: boolean\n}\n\nexport interface DataTableProps<T extends Record<string, unknown>> {\n columns: Column<T>[]\n /** Row data — use `data` or `rows` (alias). */\n data?: T[]\n rows?: T[]\n /** Row key extractor — defaults to `row.id` or `row.key` */\n rowKey?: keyof T | ((row: T) => string | number)\n onRowClick?: (row: T) => void\n className?: string\n emptyMessage?: string\n /** Global search across `searchKeys` (or all column keys). */\n searchable?: boolean\n searchKeys?: (keyof T | string)[]\n searchPlaceholder?: string\n /** Segmented filter on a single column value. */\n filter?: DataTableFilter\n selectable?: boolean\n pageSize?: number\n bulkActions?: DataTableBulkAction[]\n rowMenu?: (row: T) => DataTableRowMenuItem[]\n toolbarRight?: ReactNode\n emptyState?: ReactNode\n loading?: boolean\n skeletonRows?: number\n}\n\ninterface DataTableInnerProps<T extends Record<string, unknown>> extends DataTableProps<T> {\n forwardedRef?: React.Ref<HTMLDivElement>\n}\n\nfunction DataTableInner<T extends Record<string, unknown>>({\n columns,\n data,\n rows,\n rowKey,\n onRowClick,\n className,\n emptyMessage = 'No data',\n searchable = false,\n searchKeys,\n searchPlaceholder = 'Search…',\n filter,\n selectable = false,\n pageSize,\n bulkActions = [],\n rowMenu,\n toolbarRight,\n emptyState,\n loading = false,\n skeletonRows = 5,\n forwardedRef,\n}: DataTableInnerProps<T>) {\n const tableData = useMemo(() => rows ?? data ?? [], [rows, data])\n\n const isRich =\n searchable ||\n filter ||\n selectable ||\n pageSize !== undefined ||\n !!rowMenu ||\n !!toolbarRight ||\n bulkActions.length > 0 ||\n !!emptyState ||\n loading\n\n const [sortKey, setSortKey] = useState<string | null>(null)\n const [sortDir, setSortDir] = useState<'asc' | 'desc'>('asc')\n const [filters, setFilters] = useState<Record<string, string>>({})\n const [query, setQuery] = useState('')\n const [filterValue, setFilterValue] = useState('all')\n const [selected, setSelected] = useState<(string | number)[]>([])\n const [page, setPage] = useState(1)\n\n const getRowKey = (row: T, i: number): string | number => {\n if (typeof rowKey === 'function') return rowKey(row)\n if (rowKey) return row[rowKey] as string | number\n return (row.id ?? row.key ?? i) as string | number\n }\n\n const toggleSort = (key: string) => {\n if (sortKey === key) {\n setSortDir((d) => (d === 'asc' ? 'desc' : 'asc'))\n } else {\n setSortKey(key)\n setSortDir('asc')\n }\n }\n\n const updateFilter = (key: string, value: string) => {\n setFilters((prev) => {\n const next = { ...prev }\n if (value.trim() === '') {\n delete next[key]\n } else {\n next[key] = value\n }\n return next\n })\n }\n\n const searchKeysResolved = searchKeys ?? columns.map((c) => c.key)\n const filterOptions = filter\n ? (filter.options ?? Array.from(new Set(tableData.map((r) => String(r[filter.key] ?? '')))))\n : []\n\n const filtered = useMemo(() => {\n let result = tableData\n\n if (isRich && filter && filterValue !== 'all') {\n result = result.filter((row) => String(row[filter.key] ?? '') === filterValue)\n }\n\n if (isRich && searchable && query.trim()) {\n const q = query.trim().toLowerCase()\n result = result.filter((row) =>\n searchKeysResolved.some((key) => String(row[key as keyof T] ?? '').toLowerCase().includes(q))\n )\n }\n\n if (!isRich) {\n const activeFilters = Object.entries(filters).filter(([, v]) => v.trim() !== '')\n if (activeFilters.length > 0) {\n result = result.filter((row) =>\n activeFilters.every(([key, filterVal]) => {\n const cellValue = String(row[key] ?? '').toLowerCase()\n return cellValue.includes(filterVal.toLowerCase())\n })\n )\n }\n }\n\n return result\n }, [tableData, filters, isRich, filter, filterValue, searchable, query, searchKeysResolved])\n\n const sorted = useMemo(() => {\n if (!sortKey) return filtered\n const col = columns.find((c) => c.key === sortKey)\n if (!col?.sortable) return filtered\n\n return [...filtered].sort((a, b) => {\n const aVal = a[sortKey]\n const bVal = b[sortKey]\n\n if (typeof aVal === 'number' && typeof bVal === 'number') {\n return sortDir === 'asc' ? aVal - bVal : bVal - aVal\n }\n\n const aStr = String(aVal ?? '')\n const bStr = String(bVal ?? '')\n const cmp = aStr.localeCompare(bStr, 'nb', { numeric: true })\n return sortDir === 'asc' ? cmp : -cmp\n })\n }, [filtered, sortKey, sortDir, columns])\n\n const pageCount = pageSize ? Math.max(1, Math.ceil(sorted.length / pageSize)) : 1\n const currentPage = Math.min(page, pageCount)\n const pageRows = pageSize\n ? sorted.slice((currentPage - 1) * pageSize, currentPage * pageSize)\n : sorted\n\n const clearSelection = () => setSelected([])\n const allOnPageSelected =\n pageRows.length > 0 && pageRows.every((row) => selected.includes(getRowKey(row, 0)))\n\n const toggleAllOnPage = () => {\n const pageIds = pageRows.map((row, i) => getRowKey(row, i))\n if (allOnPageSelected) {\n setSelected((prev) => prev.filter((id) => !pageIds.includes(id)))\n } else {\n setSelected((prev) => Array.from(new Set([...prev, ...pageIds])))\n }\n }\n\n const toggleRow = (id: string | number) => {\n setSelected((prev) => (prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id]))\n }\n\n const hasActiveFilters = Object.values(filters).some((v) => v.trim() !== '')\n const filterableColumns = columns.filter((c) => c.filterable)\n const colSpan = columns.length + (selectable ? 1 : 0) + (rowMenu ? 1 : 0)\n\n const sortIndicator = (key: string) => {\n const active = sortKey === key\n return (\n <ChevronDown\n size={12}\n className={cn(\n 'shrink-0 transition-transform duration-150',\n active ? 'text-tollerud-yellow opacity-100' : 'opacity-25',\n active && sortDir === 'desc' && 'rotate-180'\n )}\n aria-hidden\n />\n )\n }\n\n const headerCell = (col: Column<T>) => (\n <th\n key={col.key}\n className={cn(\n 'px-3 py-2.5 text-left text-xs font-semibold text-tollerud-text-muted uppercase tracking-wider',\n col.sortable && 'cursor-pointer select-none hover:text-tollerud-text-primary transition-colors',\n col.align === 'right' && 'text-right',\n col.align === 'center' && 'text-center',\n )}\n style={col.width ? { width: col.width } : undefined}\n onClick={() => col.sortable && toggleSort(col.key)}\n >\n <span\n className={cn(\n 'inline-flex items-center gap-1',\n col.align === 'right' && 'justify-end w-full',\n col.align === 'center' && 'justify-center w-full',\n )}\n >\n {col.label}\n {col.sortable && (isRich ? sortIndicator(col.key) : (\n <>\n {sortKey === col.key && (\n <span className=\"text-tollerud-accent\">{sortDir === 'asc' ? '↑' : '↓'}</span>\n )}\n {sortKey !== col.key && <span className=\"text-tollerud-text-muted/30\">↕</span>}\n </>\n ))}\n {!isRich && col.filterable && (\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={cn('opacity-40', filters[col.key] && 'opacity-100 text-tollerud-yellow')}\n aria-hidden\n >\n <path d=\"M4 4h16v2.172a2 2 0 0 1-.586 1.414L15 12v7l-6 2v-8.5L4.52 7.53A2 2 0 0 1 4 6.16V4z\" />\n </svg>\n )}\n </span>\n </th>\n )\n\n const tableBody = () => {\n if (loading) {\n return (\n <tbody>\n {Array.from({ length: skeletonRows }).map((_, i) => (\n <tr key={i} className=\"border-b border-tollerud-border/20\">\n {selectable && (\n <td className=\"px-3 py-2.5 w-10\">\n <Skeleton className=\"h-4 w-4 rounded\" />\n </td>\n )}\n {columns.map((col, j) => (\n <td key={col.key} className={cn('px-3 py-2.5', col.align === 'right' && 'text-right')}>\n <Skeleton className={cn('h-3', j === 0 ? 'w-[70%]' : 'w-[55%]')} />\n </td>\n ))}\n {rowMenu && (\n <td className=\"px-3 py-2.5 w-11\">\n <Skeleton className=\"h-4 w-4 rounded\" />\n </td>\n )}\n </tr>\n ))}\n </tbody>\n )\n }\n\n if (sorted.length === 0) {\n if (isRich && emptyState) {\n return null\n }\n return (\n <tbody>\n <tr>\n <td colSpan={colSpan} className=\"px-3 py-8 text-center text-sm text-tollerud-text-muted\">\n {hasActiveFilters || query || filterValue !== 'all' ? 'No matching rows' : emptyMessage}\n </td>\n </tr>\n </tbody>\n )\n }\n\n return (\n <tbody>\n {pageRows.map((row, i) => {\n const id = getRowKey(row, i)\n const isSelected = selected.includes(id)\n return (\n <tr\n key={id}\n className={cn(\n 'border-b border-tollerud-border/20 transition-colors',\n onRowClick && 'cursor-pointer hover:bg-tollerud-surface-raised/50',\n isSelected && 'bg-tollerud-yellow/[0.05]',\n )}\n onClick={() => onRowClick?.(row)}\n >\n {selectable && (\n <td className=\"px-3 py-2.5 w-10\" onClick={(e) => e.stopPropagation()}>\n <Checkbox checked={isSelected} onChange={() => toggleRow(id)} aria-label={`Select row ${id}`} />\n </td>\n )}\n {columns.map((col) => {\n const value = row[col.key]\n return (\n <td\n key={col.key}\n className={cn(\n 'px-3 py-2.5 text-tollerud-text-secondary',\n col.align === 'right' && 'text-right',\n col.align === 'center' && 'text-center',\n !col.render && 'font-mono text-xs',\n )}\n >\n {col.render ? col.render(value, row) : String(value ?? '—')}\n </td>\n )\n })}\n {rowMenu && (\n <td className=\"px-2 py-2 w-11\" onClick={(e) => e.stopPropagation()}>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n className=\"inline-flex h-7 w-7 items-center justify-center rounded-md text-tollerud-text-muted hover:text-tollerud-text-primary hover:bg-tollerud-surface-raised transition-colors tollerud-focus-ring\"\n aria-label=\"Row actions\"\n >\n <MoreHorizontal size={15} />\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n {rowMenu(row).map((item, index) => {\n if (item.sep) return <DropdownMenuSeparator key={index} />\n if (item.heading) return <DropdownMenuLabel key={index}>{item.label}</DropdownMenuLabel>\n return (\n <DropdownMenuItem key={index} onSelect={() => item.onSelect?.()}>\n {item.icon ? <span className=\"mr-2 inline-flex\">{item.icon}</span> : null}\n {item.label}\n </DropdownMenuItem>\n )\n })}\n </DropdownMenuContent>\n </DropdownMenu>\n </td>\n )}\n </tr>\n )\n })}\n {isRich &&\n pageSize &&\n pageRows.length < pageSize &&\n Array.from({ length: pageSize - pageRows.length }).map((_, i) => (\n <tr key={`spacer-${i}`} aria-hidden className=\"h-[49px]\">\n <td colSpan={colSpan} />\n </tr>\n ))}\n </tbody>\n )\n }\n\n const table = (\n <table className=\"w-full min-w-[640px] text-sm\">\n <thead>\n <tr className=\"border-b border-tollerud-border/30 bg-tollerud-noir-900\">\n {selectable && (\n <th className=\"px-3 py-2.5 w-10\">\n <Checkbox\n checked={allOnPageSelected}\n onChange={toggleAllOnPage}\n aria-label=\"Select all rows on page\"\n />\n </th>\n )}\n {columns.map((col) => headerCell(col))}\n {rowMenu && <th className=\"w-11\" />}\n </tr>\n {!isRich && filterableColumns.length > 0 && (\n <tr className=\"border-b border-tollerud-border/20\">\n {columns.map((col) => (\n <th\n key={`filter-${col.key}`}\n className={cn('px-1.5 py-1', col.align === 'right' && 'text-right', col.align === 'center' && 'text-center')}\n >\n {col.filterable ? (\n <input\n type=\"text\"\n placeholder={`Filter ${col.label.toLowerCase()}…`}\n value={filters[col.key] ?? ''}\n onChange={(e) => updateFilter(col.key, e.target.value)}\n className={cn(\n 'w-full px-2 py-1 text-xs rounded border transition-colors outline-none',\n 'bg-tollerud-noir-900/50 border-tollerud-border/20 text-tollerud-text-primary placeholder:text-tollerud-text-muted/40',\n 'focus:border-tollerud-yellow/40 focus:ring-1 focus:ring-tollerud-yellow/20',\n )}\n />\n ) : null}\n </th>\n ))}\n </tr>\n )}\n </thead>\n {tableBody()}\n </table>\n )\n\n if (!isRich) {\n return (\n <div ref={forwardedRef} className={cn('overflow-x-auto rounded-lg border border-tollerud-border/30', className)}>\n {table}\n </div>\n )\n }\n\n const showEmpty = !loading && sorted.length === 0\n\n return (\n <div\n ref={forwardedRef}\n className={cn(\n 'overflow-hidden rounded-lg border border-tollerud-border/30 bg-tollerud-noir-900',\n className,\n )}\n >\n {(searchable || filter || toolbarRight) && (\n <div className=\"flex flex-wrap items-center justify-between gap-3 border-b border-tollerud-border/30 px-4 py-3.5\">\n <div className=\"flex flex-wrap items-center gap-2.5\">\n {searchable && (\n <div className=\"flex h-9 w-[230px] max-w-full items-center gap-2 rounded-lg border border-tollerud-border/30 bg-tollerud-noir-950 px-3\">\n <Search size={15} className=\"shrink-0 text-tollerud-text-muted\" aria-hidden />\n <input\n value={query}\n onChange={(e) => {\n setQuery(e.target.value)\n setPage(1)\n }}\n placeholder={searchPlaceholder}\n className=\"min-w-0 flex-1 border-none bg-transparent text-sm text-tollerud-text-primary outline-none placeholder:text-tollerud-text-muted\"\n />\n {query && (\n <button\n type=\"button\"\n onClick={() => setQuery('')}\n className=\"text-tollerud-text-muted hover:text-tollerud-text-primary\"\n aria-label=\"Clear search\"\n >\n <X size={13} />\n </button>\n )}\n </div>\n )}\n {filter && (\n <Segmented\n size=\"sm\"\n value={filterValue}\n onChange={(value) => {\n setFilterValue(value)\n setPage(1)\n }}\n options={[\n { value: 'all', label: filter.allLabel ?? 'All' },\n ...filterOptions.map((opt) => ({ value: opt, label: opt })),\n ]}\n />\n )}\n </div>\n {toolbarRight}\n </div>\n )}\n\n {selectable && selected.length > 0 && (\n <div className=\"flex flex-wrap items-center justify-between gap-3 border-b border-tollerud-border/30 bg-tollerud-yellow/[0.07] px-4 py-2.5\">\n <span className=\"flex items-center gap-2 text-sm text-tollerud-text-primary\">\n <Badge variant=\"accent\">{selected.length}</Badge>\n selected\n </span>\n <div className=\"flex flex-wrap items-center gap-2\">\n {bulkActions.map((action, index) => (\n <Button\n key={index}\n variant={action.variant ?? 'ghost'}\n size=\"sm\"\n onClick={() => action.onRun(selected, clearSelection)}\n >\n {action.icon}\n {action.label}\n </Button>\n ))}\n </div>\n </div>\n )}\n\n {showEmpty ? (\n <div className=\"p-2\">{emptyState ?? <div className=\"py-12 text-center text-sm text-tollerud-text-muted\">No results.</div>}</div>\n ) : (\n <div className=\"overflow-x-auto\">{table}</div>\n )}\n\n {!loading && sorted.length > 0 && (\n <div className=\"flex flex-wrap items-center justify-between gap-3 border-t border-tollerud-border/30 px-4 py-3\">\n <span className=\"text-xs text-tollerud-text-muted\">\n {pageSize\n ? `Showing ${(currentPage - 1) * pageSize + 1}–${(currentPage - 1) * pageSize + pageRows.length} of ${sorted.length}`\n : `${sorted.length} row${sorted.length === 1 ? '' : 's'}`}\n </span>\n {pageSize && pageCount > 1 && (\n <Pagination page={currentPage} pageCount={pageCount} onChange={setPage} siblingCount={1} />\n )}\n </div>\n )}\n </div>\n )\n}\n\nconst DataTable = forwardRef(<T extends Record<string, unknown>>(\n props: DataTableProps<T>,\n ref: React.Ref<HTMLDivElement>\n) => <DataTableInner {...props} forwardedRef={ref} />)\n\nDataTable.displayName = 'DataTable'\n\nexport { DataTable }\n"]}
1
+ {"version":3,"sources":["../components/DataTable.tsx"],"names":[],"mappings":"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","file":"chunk-K4ALNUZI.js","sourcesContent":["'use client'\n\nimport { useState, useMemo, forwardRef, type ReactNode } from 'react'\nimport { ChevronDown, MoreHorizontal, Search, X } from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport { Badge } from './Badge'\nimport { Button } from './Button'\nimport { Checkbox } from './Checkbox'\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from './DropdownMenu'\nimport { Pagination } from './Pagination'\nimport { Segmented } from './Segmented'\nimport { Skeleton } from './Skeleton'\n\n/* ──────────────────── Sortable & Filterable Data Table ──────────────────── */\n\nexport interface Column<T> {\n key: string\n label: string\n sortable?: boolean\n filterable?: boolean\n align?: 'left' | 'center' | 'right'\n width?: string\n render?: (value: unknown, row: T) => ReactNode\n}\n\nexport interface DataTableFilter {\n key: string\n options?: string[]\n allLabel?: string\n}\n\nexport interface DataTableBulkAction {\n label: string\n variant?: 'primary' | 'secondary' | 'ghost' | 'destructive' | 'terminal'\n icon?: ReactNode\n onRun: (selectedIds: (string | number)[], clearSelection: () => void) => void\n}\n\nexport interface DataTableRowMenuItem {\n label: string\n onSelect?: () => void\n icon?: ReactNode\n sep?: boolean\n heading?: boolean\n}\n\nexport interface DataTableProps<T extends Record<string, unknown>> {\n columns: Column<T>[]\n /** Row data — use `data` or `rows` (alias). */\n data?: T[]\n rows?: T[]\n /** Row key extractor — defaults to `row.id` or `row.key` */\n rowKey?: keyof T | ((row: T) => string | number)\n onRowClick?: (row: T) => void\n className?: string\n emptyMessage?: string\n /** Global search across `searchKeys` (or all column keys). */\n searchable?: boolean\n searchKeys?: (keyof T | string)[]\n searchPlaceholder?: string\n /** Segmented filter on a single column value. */\n filter?: DataTableFilter\n selectable?: boolean\n pageSize?: number\n bulkActions?: DataTableBulkAction[]\n rowMenu?: (row: T) => DataTableRowMenuItem[]\n toolbarRight?: ReactNode\n emptyState?: ReactNode\n loading?: boolean\n skeletonRows?: number\n}\n\ninterface DataTableInnerProps<T extends Record<string, unknown>> extends DataTableProps<T> {\n forwardedRef?: React.Ref<HTMLDivElement>\n}\n\nfunction DataTableInner<T extends Record<string, unknown>>({\n columns,\n data,\n rows,\n rowKey,\n onRowClick,\n className,\n emptyMessage = 'No data',\n searchable = false,\n searchKeys,\n searchPlaceholder = 'Search…',\n filter,\n selectable = false,\n pageSize,\n bulkActions = [],\n rowMenu,\n toolbarRight,\n emptyState,\n loading = false,\n skeletonRows = 5,\n forwardedRef,\n}: DataTableInnerProps<T>) {\n const tableData = useMemo(() => rows ?? data ?? [], [rows, data])\n\n const isRich =\n searchable ||\n filter ||\n selectable ||\n pageSize !== undefined ||\n !!rowMenu ||\n !!toolbarRight ||\n bulkActions.length > 0 ||\n !!emptyState ||\n loading\n\n const [sortKey, setSortKey] = useState<string | null>(null)\n const [sortDir, setSortDir] = useState<'asc' | 'desc'>('asc')\n const [filters, setFilters] = useState<Record<string, string>>({})\n const [query, setQuery] = useState('')\n const [filterValue, setFilterValue] = useState('all')\n const [selected, setSelected] = useState<(string | number)[]>([])\n const [page, setPage] = useState(1)\n\n const getRowKey = (row: T, i: number): string | number => {\n if (typeof rowKey === 'function') return rowKey(row)\n if (rowKey) return row[rowKey] as string | number\n return (row.id ?? row.key ?? i) as string | number\n }\n\n const toggleSort = (key: string) => {\n if (sortKey === key) {\n setSortDir((d) => (d === 'asc' ? 'desc' : 'asc'))\n } else {\n setSortKey(key)\n setSortDir('asc')\n }\n }\n\n const updateFilter = (key: string, value: string) => {\n setFilters((prev) => {\n const next = { ...prev }\n if (value.trim() === '') {\n delete next[key]\n } else {\n next[key] = value\n }\n return next\n })\n }\n\n const searchKeysResolved = searchKeys ?? columns.map((c) => c.key)\n const filterOptions = filter\n ? (filter.options ?? Array.from(new Set(tableData.map((r) => String(r[filter.key] ?? '')))))\n : []\n\n const filtered = useMemo(() => {\n let result = tableData\n\n if (isRich && filter && filterValue !== 'all') {\n result = result.filter((row) => String(row[filter.key] ?? '') === filterValue)\n }\n\n if (isRich && searchable && query.trim()) {\n const q = query.trim().toLowerCase()\n result = result.filter((row) =>\n searchKeysResolved.some((key) => String(row[key as keyof T] ?? '').toLowerCase().includes(q))\n )\n }\n\n if (!isRich) {\n const activeFilters = Object.entries(filters).filter(([, v]) => v.trim() !== '')\n if (activeFilters.length > 0) {\n result = result.filter((row) =>\n activeFilters.every(([key, filterVal]) => {\n const cellValue = String(row[key] ?? '').toLowerCase()\n return cellValue.includes(filterVal.toLowerCase())\n })\n )\n }\n }\n\n return result\n }, [tableData, filters, isRich, filter, filterValue, searchable, query, searchKeysResolved])\n\n const sorted = useMemo(() => {\n if (!sortKey) return filtered\n const col = columns.find((c) => c.key === sortKey)\n if (!col?.sortable) return filtered\n\n return [...filtered].sort((a, b) => {\n const aVal = a[sortKey]\n const bVal = b[sortKey]\n\n if (typeof aVal === 'number' && typeof bVal === 'number') {\n return sortDir === 'asc' ? aVal - bVal : bVal - aVal\n }\n\n const aStr = String(aVal ?? '')\n const bStr = String(bVal ?? '')\n const cmp = aStr.localeCompare(bStr, 'nb', { numeric: true })\n return sortDir === 'asc' ? cmp : -cmp\n })\n }, [filtered, sortKey, sortDir, columns])\n\n const pageCount = pageSize ? Math.max(1, Math.ceil(sorted.length / pageSize)) : 1\n const currentPage = Math.min(page, pageCount)\n const pageRows = pageSize\n ? sorted.slice((currentPage - 1) * pageSize, currentPage * pageSize)\n : sorted\n\n const clearSelection = () => setSelected([])\n const allOnPageSelected =\n pageRows.length > 0 && pageRows.every((row) => selected.includes(getRowKey(row, 0)))\n\n const toggleAllOnPage = () => {\n const pageIds = pageRows.map((row, i) => getRowKey(row, i))\n if (allOnPageSelected) {\n setSelected((prev) => prev.filter((id) => !pageIds.includes(id)))\n } else {\n setSelected((prev) => Array.from(new Set([...prev, ...pageIds])))\n }\n }\n\n const toggleRow = (id: string | number) => {\n setSelected((prev) => (prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id]))\n }\n\n const hasActiveFilters = Object.values(filters).some((v) => v.trim() !== '')\n const filterableColumns = columns.filter((c) => c.filterable)\n const colSpan = columns.length + (selectable ? 1 : 0) + (rowMenu ? 1 : 0)\n\n const sortIndicator = (key: string) => {\n const active = sortKey === key\n return (\n <ChevronDown\n size={12}\n className={cn(\n 'shrink-0 transition-transform duration-150',\n active ? 'text-tollerud-yellow opacity-100' : 'opacity-25',\n active && sortDir === 'desc' && 'rotate-180'\n )}\n aria-hidden\n />\n )\n }\n\n const headerCell = (col: Column<T>) => (\n <th\n key={col.key}\n className={cn(\n 'px-3 py-2.5 text-left text-xs font-semibold text-tollerud-text-muted uppercase tracking-wider',\n col.sortable && 'cursor-pointer select-none hover:text-tollerud-text-primary transition-colors',\n col.align === 'right' && 'text-right',\n col.align === 'center' && 'text-center',\n )}\n style={col.width ? { width: col.width } : undefined}\n onClick={() => col.sortable && toggleSort(col.key)}\n >\n <span\n className={cn(\n 'inline-flex items-center gap-1',\n col.align === 'right' && 'justify-end w-full',\n col.align === 'center' && 'justify-center w-full',\n )}\n >\n {col.label}\n {col.sortable && (isRich ? sortIndicator(col.key) : (\n <>\n {sortKey === col.key && (\n <span className=\"text-tollerud-accent\">{sortDir === 'asc' ? '↑' : '↓'}</span>\n )}\n {sortKey !== col.key && <span className=\"text-tollerud-text-muted/30\">↕</span>}\n </>\n ))}\n {!isRich && col.filterable && (\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={cn('opacity-40', filters[col.key] && 'opacity-100 text-tollerud-yellow')}\n aria-hidden\n >\n <path d=\"M4 4h16v2.172a2 2 0 0 1-.586 1.414L15 12v7l-6 2v-8.5L4.52 7.53A2 2 0 0 1 4 6.16V4z\" />\n </svg>\n )}\n </span>\n </th>\n )\n\n const tableBody = () => {\n if (loading) {\n return (\n <tbody>\n {Array.from({ length: skeletonRows }).map((_, i) => (\n <tr key={i} className=\"border-b border-tollerud-border/20\">\n {selectable && (\n <td className=\"px-3 py-2.5 w-10\">\n <Skeleton className=\"h-4 w-4 rounded\" />\n </td>\n )}\n {columns.map((col, j) => (\n <td key={col.key} className={cn('px-3 py-2.5', col.align === 'right' && 'text-right')}>\n <Skeleton className={cn('h-3', j === 0 ? 'w-[70%]' : 'w-[55%]')} />\n </td>\n ))}\n {rowMenu && (\n <td className=\"px-3 py-2.5 w-11\">\n <Skeleton className=\"h-4 w-4 rounded\" />\n </td>\n )}\n </tr>\n ))}\n </tbody>\n )\n }\n\n if (sorted.length === 0) {\n if (isRich && emptyState) {\n return null\n }\n return (\n <tbody>\n <tr>\n <td colSpan={colSpan} className=\"px-3 py-8 text-center text-sm text-tollerud-text-muted\">\n {hasActiveFilters || query || filterValue !== 'all' ? 'No matching rows' : emptyMessage}\n </td>\n </tr>\n </tbody>\n )\n }\n\n return (\n <tbody>\n {pageRows.map((row, i) => {\n const id = getRowKey(row, i)\n const isSelected = selected.includes(id)\n return (\n <tr\n key={id}\n className={cn(\n 'border-b border-tollerud-border/20 transition-colors',\n onRowClick && 'cursor-pointer hover:bg-tollerud-surface-raised/50',\n isSelected && 'bg-tollerud-yellow/[0.05]',\n )}\n onClick={() => onRowClick?.(row)}\n >\n {selectable && (\n <td className=\"px-3 py-2.5 w-10\" onClick={(e) => e.stopPropagation()}>\n <Checkbox checked={isSelected} onChange={() => toggleRow(id)} aria-label={`Select row ${id}`} />\n </td>\n )}\n {columns.map((col) => {\n const value = row[col.key]\n return (\n <td\n key={col.key}\n className={cn(\n 'px-3 py-2.5 text-tollerud-text-secondary',\n col.align === 'right' && 'text-right',\n col.align === 'center' && 'text-center',\n !col.render && 'font-mono text-xs',\n )}\n >\n {col.render ? col.render(value, row) : String(value ?? '—')}\n </td>\n )\n })}\n {rowMenu && (\n <td className=\"px-2 py-2 w-11\" onClick={(e) => e.stopPropagation()}>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n className=\"inline-flex h-7 w-7 items-center justify-center rounded-md text-tollerud-text-muted hover:text-tollerud-text-primary hover:bg-tollerud-surface-raised transition-colors tollerud-focus-ring\"\n aria-label=\"Row actions\"\n >\n <MoreHorizontal size={15} />\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n {rowMenu(row).map((item, index) => {\n if (item.sep) return <DropdownMenuSeparator key={index} />\n if (item.heading) return <DropdownMenuLabel key={index}>{item.label}</DropdownMenuLabel>\n return (\n <DropdownMenuItem key={index} onSelect={() => item.onSelect?.()}>\n {item.icon ? <span className=\"mr-2 inline-flex\">{item.icon}</span> : null}\n {item.label}\n </DropdownMenuItem>\n )\n })}\n </DropdownMenuContent>\n </DropdownMenu>\n </td>\n )}\n </tr>\n )\n })}\n {isRich &&\n pageSize &&\n pageRows.length < pageSize &&\n Array.from({ length: pageSize - pageRows.length }).map((_, i) => (\n <tr key={`spacer-${i}`} aria-hidden className=\"h-[49px]\">\n <td colSpan={colSpan} />\n </tr>\n ))}\n </tbody>\n )\n }\n\n const table = (\n <table className=\"w-full min-w-[640px] text-sm\">\n <thead>\n <tr className=\"border-b border-tollerud-border/30 bg-tollerud-noir-900\">\n {selectable && (\n <th className=\"px-3 py-2.5 w-10\">\n <Checkbox\n checked={allOnPageSelected}\n onChange={toggleAllOnPage}\n aria-label=\"Select all rows on page\"\n />\n </th>\n )}\n {columns.map((col) => headerCell(col))}\n {rowMenu && <th className=\"w-11\" />}\n </tr>\n {!isRich && filterableColumns.length > 0 && (\n <tr className=\"border-b border-tollerud-border/20\">\n {columns.map((col) => (\n <th\n key={`filter-${col.key}`}\n className={cn('px-1.5 py-1', col.align === 'right' && 'text-right', col.align === 'center' && 'text-center')}\n >\n {col.filterable ? (\n <input\n type=\"text\"\n placeholder={`Filter ${col.label.toLowerCase()}…`}\n value={filters[col.key] ?? ''}\n onChange={(e) => updateFilter(col.key, e.target.value)}\n className={cn(\n 'w-full px-2 py-1 text-xs rounded border transition-colors outline-none',\n 'bg-tollerud-noir-900/50 border-tollerud-border/20 text-tollerud-text-primary placeholder:text-tollerud-text-muted/40',\n 'focus:border-tollerud-yellow/40 focus:ring-1 focus:ring-tollerud-yellow/20',\n )}\n />\n ) : null}\n </th>\n ))}\n </tr>\n )}\n </thead>\n {tableBody()}\n </table>\n )\n\n if (!isRich) {\n return (\n <div ref={forwardedRef} className={cn('overflow-x-auto rounded-lg border border-tollerud-border/30', className)}>\n {table}\n </div>\n )\n }\n\n const showEmpty = !loading && sorted.length === 0\n\n return (\n <div\n ref={forwardedRef}\n className={cn(\n 'overflow-hidden rounded-lg border border-tollerud-border/30 bg-tollerud-noir-900',\n className,\n )}\n >\n {(searchable || filter || toolbarRight) && (\n <div className=\"flex flex-wrap items-center justify-between gap-3 border-b border-tollerud-border/30 px-4 py-3.5\">\n <div className=\"flex flex-wrap items-center gap-2.5\">\n {searchable && (\n <div className=\"flex h-9 w-[230px] max-w-full items-center gap-2 rounded-lg border border-tollerud-border/30 bg-tollerud-noir-950 px-3\">\n <Search size={15} className=\"shrink-0 text-tollerud-text-muted\" aria-hidden />\n <input\n value={query}\n onChange={(e) => {\n setQuery(e.target.value)\n setPage(1)\n }}\n placeholder={searchPlaceholder}\n className=\"min-w-0 flex-1 border-none bg-transparent text-sm text-tollerud-text-primary outline-none placeholder:text-tollerud-text-muted\"\n />\n {query && (\n <button\n type=\"button\"\n onClick={() => setQuery('')}\n className=\"text-tollerud-text-muted hover:text-tollerud-text-primary\"\n aria-label=\"Clear search\"\n >\n <X size={13} />\n </button>\n )}\n </div>\n )}\n {filter && (\n <Segmented\n size=\"sm\"\n value={filterValue}\n onChange={(value) => {\n setFilterValue(value)\n setPage(1)\n }}\n options={[\n { value: 'all', label: filter.allLabel ?? 'All' },\n ...filterOptions.map((opt) => ({ value: opt, label: opt })),\n ]}\n />\n )}\n </div>\n {toolbarRight}\n </div>\n )}\n\n {selectable && selected.length > 0 && (\n <div className=\"flex flex-wrap items-center justify-between gap-3 border-b border-tollerud-border/30 bg-tollerud-yellow/[0.07] px-4 py-2.5\">\n <span className=\"flex items-center gap-2 text-sm text-tollerud-text-primary\">\n <Badge variant=\"accent\">{selected.length}</Badge>\n selected\n </span>\n <div className=\"flex flex-wrap items-center gap-2\">\n {bulkActions.map((action, index) => (\n <Button\n key={index}\n variant={action.variant ?? 'ghost'}\n size=\"sm\"\n onClick={() => action.onRun(selected, clearSelection)}\n >\n {action.icon}\n {action.label}\n </Button>\n ))}\n </div>\n </div>\n )}\n\n {showEmpty ? (\n <div className=\"p-2\">{emptyState ?? <div className=\"py-12 text-center text-sm text-tollerud-text-muted\">No results.</div>}</div>\n ) : (\n <div className=\"overflow-x-auto\">{table}</div>\n )}\n\n {!loading && sorted.length > 0 && (\n <div className=\"flex flex-wrap items-center justify-between gap-3 border-t border-tollerud-border/30 px-4 py-3\">\n <span className=\"text-xs text-tollerud-text-muted\">\n {pageSize\n ? `Showing ${(currentPage - 1) * pageSize + 1}–${(currentPage - 1) * pageSize + pageRows.length} of ${sorted.length}`\n : `${sorted.length} row${sorted.length === 1 ? '' : 's'}`}\n </span>\n {pageSize && pageCount > 1 && (\n <Pagination page={currentPage} pageCount={pageCount} onChange={setPage} siblingCount={1} />\n )}\n </div>\n )}\n </div>\n )\n}\n\nconst DataTable = forwardRef(<T extends Record<string, unknown>>(\n props: DataTableProps<T>,\n ref: React.Ref<HTMLDivElement>\n) => <DataTableInner {...props} forwardedRef={ref} />)\n\nDataTable.displayName = 'DataTable'\n\nexport { DataTable }\n"]}
@@ -14,7 +14,7 @@ function BentoDashboard({
14
14
  incidents = [],
15
15
  className
16
16
  }) {
17
- return /* @__PURE__ */ jsxs("div", { className: cn("space-y-4", className), children: [
17
+ return /* @__PURE__ */ jsxs("div", { className: cn("w-full space-y-6", className), children: [
18
18
  /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsxs("div", { children: [
19
19
  /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-tollerud-text-primary", children: title }),
20
20
  /* @__PURE__ */ jsxs("p", { className: "text-xs text-tollerud-text-muted", children: [
@@ -29,26 +29,26 @@ function BentoDashboard({
29
29
  /* @__PURE__ */ jsx("div", { className: "md:col-span-2 lg:col-span-1", children: /* @__PURE__ */ jsx(HostCard, { ...hosts[0] }) }),
30
30
  /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-3 md:col-span-2 lg:col-span-1", children: hosts.slice(1).map((h, i) => /* @__PURE__ */ jsx(HostCard, { ...h }, h.hostname ?? i)) })
31
31
  ] }),
32
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-3 gap-3", children: [
33
- metrics.length > 0 && /* @__PURE__ */ jsxs("div", { className: "lg:col-span-2", children: [
32
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 items-start gap-4 lg:grid-cols-3 lg:gap-3", children: [
33
+ metrics.length > 0 && /* @__PURE__ */ jsxs("div", { className: "min-w-0 lg:col-span-2", children: [
34
34
  /* @__PURE__ */ jsx(SectionLabel, { children: "Metrics" }),
35
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 sm:grid-cols-4 gap-2", children: metrics.map((m, i) => /* @__PURE__ */ jsx(StatCard, { ...m }, m.label ?? i)) })
35
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-3 sm:grid-cols-4", children: metrics.map((m, i) => /* @__PURE__ */ jsx(StatCard, { ...m }, m.label ?? i)) })
36
36
  ] }),
37
- services.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
37
+ services.length > 0 && /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
38
38
  /* @__PURE__ */ jsx(SectionLabel, { children: "Services" }),
39
39
  /* @__PURE__ */ jsx("div", { className: "space-y-2", children: services.slice(0, 4).map((s, i) => /* @__PURE__ */ jsx(ServiceHealthCard, { ...s }, s.service ?? i)) })
40
40
  ] })
41
41
  ] }),
42
- incidents.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
42
+ incidents.length > 0 && /* @__PURE__ */ jsxs("div", { className: "min-w-0 pt-1", children: [
43
43
  /* @__PURE__ */ jsx(SectionLabel, { children: "Recent Incidents" }),
44
- /* @__PURE__ */ jsx("div", { className: "space-y-1.5", children: incidents.slice(0, 4).map((inc, i) => /* @__PURE__ */ jsx(IncidentCard, { ...inc }, inc.title + i)) })
44
+ /* @__PURE__ */ jsx("div", { className: "space-y-2", children: incidents.slice(0, 4).map((inc, i) => /* @__PURE__ */ jsx(IncidentCard, { ...inc }, inc.title + i)) })
45
45
  ] })
46
46
  ] });
47
47
  }
48
48
  function SectionLabel({ children }) {
49
- return /* @__PURE__ */ jsx("p", { className: "text-xs font-semibold text-tollerud-text-muted uppercase tracking-wider mb-2", children });
49
+ return /* @__PURE__ */ jsx("p", { className: "mb-3 text-xs font-semibold uppercase tracking-wider text-tollerud-text-muted", children });
50
50
  }
51
51
 
52
52
  export { BentoDashboard };
53
- //# sourceMappingURL=chunk-ONMTHBZ4.js.map
54
- //# sourceMappingURL=chunk-ONMTHBZ4.js.map
53
+ //# sourceMappingURL=chunk-LGVXEWNB.js.map
54
+ //# sourceMappingURL=chunk-LGVXEWNB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../components/BentoDashboard.tsx"],"names":[],"mappings":"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","file":"chunk-LGVXEWNB.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('w-full space-y-6', 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 items-start gap-4 lg:grid-cols-3 lg:gap-3\">\n {metrics.length > 0 && (\n <div className=\"min-w-0 lg:col-span-2\">\n <SectionLabel>Metrics</SectionLabel>\n <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-4\">\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 className=\"min-w-0\">\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 className=\"min-w-0 pt-1\">\n <SectionLabel>Recent Incidents</SectionLabel>\n <div className=\"space-y-2\">\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=\"mb-3 text-xs font-semibold uppercase tracking-wider text-tollerud-text-muted\">{children}</p>\n )\n}\n\nexport default BentoDashboard\n"]}
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- import { Button } from './chunk-ADE22JSR.js';
2
+ import { Button } from './chunk-BQWF5MP7.js';
3
3
  import { cn } from './chunk-WSQNPRGN.js';
4
4
  import { forwardRef } from 'react';
5
5
  import { Check } from 'lucide-react';
@@ -52,5 +52,5 @@ var PricingCard = forwardRef(
52
52
  PricingCard.displayName = "PricingCard";
53
53
 
54
54
  export { PricingCard };
55
- //# sourceMappingURL=chunk-OVSIOZHJ.js.map
56
- //# sourceMappingURL=chunk-OVSIOZHJ.js.map
55
+ //# sourceMappingURL=chunk-SNNMZ444.js.map
56
+ //# sourceMappingURL=chunk-SNNMZ444.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../components/PricingCard.tsx"],"names":[],"mappings":";;;;;;AAoBA,IAAM,WAAA,GAAc,UAAA;AAAA,EAClB,CACE;AAAA,IACE,SAAA;AAAA,IACA,IAAA;AAAA,IACA,KAAA;AAAA,IACA,MAAA;AAAA,IACA,WAAA;AAAA,IACA,WAAW,EAAC;AAAA,IACZ,QAAA,GAAW,aAAA;AAAA,IACX,UAAA;AAAA,IACA,QAAA;AAAA,IACA,KAAA;AAAA,IACA,GAAG;AAAA,KAEL,GAAA,KACG;AACH,IAAA,uBACE,IAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,SAAA,EAAW,EAAA;AAAA,UACT,2CAAA;AAAA,UACA,WACI,0FAAA,GACA,4CAAA;AAAA,UACJ;AAAA,SACF;AAAA,QACC,GAAG,KAAA;AAAA,QAEJ,QAAA,EAAA;AAAA,0BAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,qBAAA,EACZ,QAAA,EAAA;AAAA,YAAA,KAAA,oBACC,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,0HAAA,EACb,QAAA,EAAA,KAAA,EACH,CAAA;AAAA,4BAEF,GAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,kDAAA,EAAoD,QAAA,EAAA,IAAA,EAAK,CAAA;AAAA,YACtE,WAAA,oBAAe,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,oCAAoC,QAAA,EAAA,WAAA,EAAY;AAAA,WAAA,EAC/E,CAAA;AAAA,0BAEA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,2BAAA,EACb,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,kEAAA,EAAoE,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,YACzF,MAAA,oBAAU,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,oCAAoC,QAAA,EAAA,MAAA,EAAO;AAAA,WAAA,EACxE,CAAA;AAAA,UAEC,QAAA,CAAS,MAAA,GAAS,CAAA,oBACjB,GAAA,CAAC,QAAG,SAAA,EAAU,uBAAA,EACX,QAAA,EAAA,QAAA,CAAS,GAAA,CAAI,CAAC,OAAA,EAAS,CAAA,qBACtB,IAAA,CAAC,IAAA,EAAA,EAAW,WAAU,+DAAA,EACpB,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,KAAA,EAAA,EAAM,IAAA,EAAM,EAAA,EAAI,SAAA,EAAU,sCAAA,EAAuC,CAAA;AAAA,4BAClE,GAAA,CAAC,UAAM,QAAA,EAAA,OAAA,EAAQ;AAAA,WAAA,EAAA,EAFR,CAGT,CACD,CAAA,EACH,CAAA;AAAA,0BAGF,GAAA,CAAC,MAAA,EAAA,EAAO,OAAA,EAAS,QAAA,GAAW,SAAA,GAAY,aAAa,OAAA,EAAS,UAAA,EAAY,SAAA,EAAU,gBAAA,EACjF,QAAA,EAAA,QAAA,EACH;AAAA;AAAA;AAAA,KACF;AAAA,EAEJ;AACF;AACA,WAAA,CAAY,WAAA,GAAc,aAAA","file":"chunk-OVSIOZHJ.js","sourcesContent":["import { type HTMLAttributes, forwardRef } from 'react'\nimport { Check } from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport { Button } from './Button'\n\nexport interface PricingCardProps extends HTMLAttributes<HTMLDivElement> {\n name: React.ReactNode\n price: React.ReactNode\n /** Rendered after the price, e.g. \"/month\" */\n period?: React.ReactNode\n description?: React.ReactNode\n features?: React.ReactNode[]\n ctaLabel?: React.ReactNode\n onCtaClick?: () => void\n /** Visually highlights this plan as the recommended/featured option */\n featured?: boolean\n /** Small label shown above the price when featured, e.g. \"Most popular\" */\n badge?: React.ReactNode\n}\n\nconst PricingCard = forwardRef<HTMLDivElement, PricingCardProps>(\n (\n {\n className,\n name,\n price,\n period,\n description,\n features = [],\n ctaLabel = 'Get started',\n onCtaClick,\n featured,\n badge,\n ...props\n },\n ref\n ) => {\n return (\n <div\n ref={ref}\n className={cn(\n 'flex flex-col gap-5 rounded-xl border p-6',\n featured\n ? 'border-tollerud-yellow bg-tollerud-yellow/[0.04] shadow-[0_0_0_1px_rgba(255,255,0,0.15)]'\n : 'border-tollerud-border bg-tollerud-surface',\n className\n )}\n {...props}\n >\n <div className=\"flex flex-col gap-1\">\n {badge && (\n <span className=\"inline-flex w-fit items-center rounded-full bg-tollerud-yellow/15 px-2.5 py-0.5 text-xs font-medium text-tollerud-yellow\">\n {badge}\n </span>\n )}\n <h3 className=\"text-base font-medium text-tollerud-text-primary\">{name}</h3>\n {description && <p className=\"text-sm text-tollerud-text-muted\">{description}</p>}\n </div>\n\n <div className=\"flex items-baseline gap-1\">\n <span className=\"text-3xl font-semibold tracking-tight text-tollerud-text-primary\">{price}</span>\n {period && <span className=\"text-sm text-tollerud-text-muted\">{period}</span>}\n </div>\n\n {features.length > 0 && (\n <ul className=\"flex flex-col gap-2.5\">\n {features.map((feature, i) => (\n <li key={i} className=\"flex items-start gap-2.5 text-sm text-tollerud-text-secondary\">\n <Check size={16} className=\"mt-0.5 shrink-0 text-tollerud-yellow\" />\n <span>{feature}</span>\n </li>\n ))}\n </ul>\n )}\n\n <Button variant={featured ? 'primary' : 'secondary'} onClick={onCtaClick} className=\"mt-auto w-full\">\n {ctaLabel}\n </Button>\n </div>\n )\n }\n)\nPricingCard.displayName = 'PricingCard'\n\nexport { PricingCard }\n"]}
1
+ {"version":3,"sources":["../components/PricingCard.tsx"],"names":[],"mappings":";;;;;;AAoBA,IAAM,WAAA,GAAc,UAAA;AAAA,EAClB,CACE;AAAA,IACE,SAAA;AAAA,IACA,IAAA;AAAA,IACA,KAAA;AAAA,IACA,MAAA;AAAA,IACA,WAAA;AAAA,IACA,WAAW,EAAC;AAAA,IACZ,QAAA,GAAW,aAAA;AAAA,IACX,UAAA;AAAA,IACA,QAAA;AAAA,IACA,KAAA;AAAA,IACA,GAAG;AAAA,KAEL,GAAA,KACG;AACH,IAAA,uBACE,IAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,SAAA,EAAW,EAAA;AAAA,UACT,2CAAA;AAAA,UACA,WACI,0FAAA,GACA,4CAAA;AAAA,UACJ;AAAA,SACF;AAAA,QACC,GAAG,KAAA;AAAA,QAEJ,QAAA,EAAA;AAAA,0BAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,qBAAA,EACZ,QAAA,EAAA;AAAA,YAAA,KAAA,oBACC,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,0HAAA,EACb,QAAA,EAAA,KAAA,EACH,CAAA;AAAA,4BAEF,GAAA,CAAC,IAAA,EAAA,EAAG,SAAA,EAAU,kDAAA,EAAoD,QAAA,EAAA,IAAA,EAAK,CAAA;AAAA,YACtE,WAAA,oBAAe,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,oCAAoC,QAAA,EAAA,WAAA,EAAY;AAAA,WAAA,EAC/E,CAAA;AAAA,0BAEA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,2BAAA,EACb,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,kEAAA,EAAoE,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,YACzF,MAAA,oBAAU,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,oCAAoC,QAAA,EAAA,MAAA,EAAO;AAAA,WAAA,EACxE,CAAA;AAAA,UAEC,QAAA,CAAS,MAAA,GAAS,CAAA,oBACjB,GAAA,CAAC,QAAG,SAAA,EAAU,uBAAA,EACX,QAAA,EAAA,QAAA,CAAS,GAAA,CAAI,CAAC,OAAA,EAAS,CAAA,qBACtB,IAAA,CAAC,IAAA,EAAA,EAAW,WAAU,+DAAA,EACpB,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,KAAA,EAAA,EAAM,IAAA,EAAM,EAAA,EAAI,SAAA,EAAU,sCAAA,EAAuC,CAAA;AAAA,4BAClE,GAAA,CAAC,UAAM,QAAA,EAAA,OAAA,EAAQ;AAAA,WAAA,EAAA,EAFR,CAGT,CACD,CAAA,EACH,CAAA;AAAA,0BAGF,GAAA,CAAC,MAAA,EAAA,EAAO,OAAA,EAAS,QAAA,GAAW,SAAA,GAAY,aAAa,OAAA,EAAS,UAAA,EAAY,SAAA,EAAU,gBAAA,EACjF,QAAA,EAAA,QAAA,EACH;AAAA;AAAA;AAAA,KACF;AAAA,EAEJ;AACF;AACA,WAAA,CAAY,WAAA,GAAc,aAAA","file":"chunk-SNNMZ444.js","sourcesContent":["import { type HTMLAttributes, forwardRef } from 'react'\nimport { Check } from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport { Button } from './Button'\n\nexport interface PricingCardProps extends HTMLAttributes<HTMLDivElement> {\n name: React.ReactNode\n price: React.ReactNode\n /** Rendered after the price, e.g. \"/month\" */\n period?: React.ReactNode\n description?: React.ReactNode\n features?: React.ReactNode[]\n ctaLabel?: React.ReactNode\n onCtaClick?: () => void\n /** Visually highlights this plan as the recommended/featured option */\n featured?: boolean\n /** Small label shown above the price when featured, e.g. \"Most popular\" */\n badge?: React.ReactNode\n}\n\nconst PricingCard = forwardRef<HTMLDivElement, PricingCardProps>(\n (\n {\n className,\n name,\n price,\n period,\n description,\n features = [],\n ctaLabel = 'Get started',\n onCtaClick,\n featured,\n badge,\n ...props\n },\n ref\n ) => {\n return (\n <div\n ref={ref}\n className={cn(\n 'flex flex-col gap-5 rounded-xl border p-6',\n featured\n ? 'border-tollerud-yellow bg-tollerud-yellow/[0.04] shadow-[0_0_0_1px_rgba(255,255,0,0.15)]'\n : 'border-tollerud-border bg-tollerud-surface',\n className\n )}\n {...props}\n >\n <div className=\"flex flex-col gap-1\">\n {badge && (\n <span className=\"inline-flex w-fit items-center rounded-full bg-tollerud-yellow/15 px-2.5 py-0.5 text-xs font-medium text-tollerud-yellow\">\n {badge}\n </span>\n )}\n <h3 className=\"text-base font-medium text-tollerud-text-primary\">{name}</h3>\n {description && <p className=\"text-sm text-tollerud-text-muted\">{description}</p>}\n </div>\n\n <div className=\"flex items-baseline gap-1\">\n <span className=\"text-3xl font-semibold tracking-tight text-tollerud-text-primary\">{price}</span>\n {period && <span className=\"text-sm text-tollerud-text-muted\">{period}</span>}\n </div>\n\n {features.length > 0 && (\n <ul className=\"flex flex-col gap-2.5\">\n {features.map((feature, i) => (\n <li key={i} className=\"flex items-start gap-2.5 text-sm text-tollerud-text-secondary\">\n <Check size={16} className=\"mt-0.5 shrink-0 text-tollerud-yellow\" />\n <span>{feature}</span>\n </li>\n ))}\n </ul>\n )}\n\n <Button variant={featured ? 'primary' : 'secondary'} onClick={onCtaClick} className=\"mt-auto w-full\">\n {ctaLabel}\n </Button>\n </div>\n )\n }\n)\nPricingCard.displayName = 'PricingCard'\n\nexport { PricingCard }\n"]}
@@ -4,7 +4,7 @@ import { forwardRef, useId } from 'react';
4
4
  import { jsxs, jsx } from 'react/jsx-runtime';
5
5
 
6
6
  var Checkbox = forwardRef(
7
- ({ className, label, id: idProp, checked, ...props }, ref) => {
7
+ ({ className, label, id: idProp, ...props }, ref) => {
8
8
  const autoId = useId();
9
9
  const id = idProp ?? autoId;
10
10
  return /* @__PURE__ */ jsxs(
@@ -25,7 +25,6 @@ var Checkbox = forwardRef(
25
25
  ref,
26
26
  id,
27
27
  type: "checkbox",
28
- checked,
29
28
  className: "peer sr-only",
30
29
  ...props
31
30
  }
@@ -39,15 +38,13 @@ var Checkbox = forwardRef(
39
38
  "bg-tollerud-surface-raised border-tollerud-border",
40
39
  "peer-focus-visible:outline-2 peer-focus-visible:outline-tollerud-yellow",
41
40
  "peer-checked:bg-tollerud-yellow peer-checked:border-tollerud-yellow",
41
+ "peer-checked:[&_svg]:opacity-100",
42
42
  "group-hover:border-tollerud-text-secondary"
43
43
  ),
44
44
  children: /* @__PURE__ */ jsx(
45
45
  "svg",
46
46
  {
47
- className: cn(
48
- "h-3 w-3 text-tollerud-noir-black transition-opacity duration-[150ms]",
49
- checked ? "opacity-100" : "opacity-0"
50
- ),
47
+ className: "pointer-events-none h-3 w-3 text-tollerud-black opacity-0 transition-opacity duration-[150ms]",
51
48
  viewBox: "0 0 12 12",
52
49
  fill: "none",
53
50
  "aria-hidden": "true",
@@ -75,5 +72,5 @@ var Checkbox = forwardRef(
75
72
  Checkbox.displayName = "Checkbox";
76
73
 
77
74
  export { Checkbox };
78
- //# sourceMappingURL=chunk-T3TQPOVM.js.map
79
- //# sourceMappingURL=chunk-T3TQPOVM.js.map
75
+ //# sourceMappingURL=chunk-TLEKK53J.js.map
76
+ //# sourceMappingURL=chunk-TLEKK53J.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../components/Checkbox.tsx"],"names":[],"mappings":";;;;AASA,IAAM,QAAA,GAAW,UAAA;AAAA,EACf,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,UAAA;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,wDAAA;AAAA,kBACA,kCAAA;AAAA,kBACA,mDAAA;AAAA,kBACA,yEAAA;AAAA,kBACA,qEAAA;AAAA,kBACA,kCAAA;AAAA,kBACA;AAAA,iBACF;AAAA,gBAGA,QAAA,kBAAA,GAAA;AAAA,kBAAC,KAAA;AAAA,kBAAA;AAAA,oBACC,SAAA,EAAU,+FAAA;AAAA,oBACV,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-TLEKK53J.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, ...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 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 'peer-checked:[&_svg]:opacity-100',\n 'group-hover:border-tollerud-text-secondary'\n )}\n >\n {/* Checkmark SVG — visible when checked (via peer on sibling input) */}\n <svg\n className=\"pointer-events-none h-3 w-3 text-tollerud-black opacity-0 transition-opacity duration-[150ms]\"\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/dist/cta-band.js CHANGED
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- export { CTABand } from './chunk-IUPVQWO5.js';
2
+ export { CTABand } from './chunk-FPFLOYIJ.js';
3
3
  import './chunk-WSQNPRGN.js';
4
4
  //# sourceMappingURL=cta-band.js.map
5
5
  //# sourceMappingURL=cta-band.js.map
@@ -1,12 +1,12 @@
1
1
  'use client';
2
- export { DataTable } from './chunk-YPP7QHYT.js';
2
+ export { DataTable } from './chunk-K4ALNUZI.js';
3
3
  import './chunk-AQT3FZRQ.js';
4
4
  import './chunk-NSMU66ZX.js';
5
5
  import './chunk-RJTDQOT2.js';
6
6
  import './chunk-435JHF7G.js';
7
- import './chunk-T3TQPOVM.js';
7
+ import './chunk-TLEKK53J.js';
8
8
  import './chunk-QEHTPQHL.js';
9
- import './chunk-ADE22JSR.js';
9
+ import './chunk-BQWF5MP7.js';
10
10
  import './chunk-WSQNPRGN.js';
11
11
  //# sourceMappingURL=data-table.js.map
12
12
  //# sourceMappingURL=data-table.js.map
package/dist/index.js CHANGED
@@ -9,9 +9,9 @@ export { Sparkline } from './chunk-EVHZFYWX.js';
9
9
  export { Stepper } from './chunk-2QWKOCWF.js';
10
10
  export { Switch } from './chunk-YTU7BRDW.js';
11
11
  export { Tabs, TabsContent, TabsList, TabsTrigger } from './chunk-T56TTOI6.js';
12
- export { PricingCard } from './chunk-OVSIOZHJ.js';
12
+ export { PricingCard } from './chunk-SNNMZ444.js';
13
13
  export { Progress } from './chunk-5GWHUJ5D.js';
14
- export { Radio, RadioGroup } from './chunk-6SKTH45H.js';
14
+ export { Radio, RadioGroup } from './chunk-J2Z4ZFVX.js';
15
15
  export { RollbackPlan } from './chunk-WDANALHD.js';
16
16
  export { Select } from './chunk-GTM2DE4C.js';
17
17
  export { Sheet, SheetClose, SheetContent, SheetDescription, SheetHeader, SheetTitle, SheetTrigger } from './chunk-ILADNTUB.js';
@@ -39,25 +39,25 @@ export { CodeBlock } from './chunk-DRCMGIQ6.js';
39
39
  export { Combobox } from './chunk-H3ZVGTJM.js';
40
40
  export { CommandMenu } from './chunk-RQ3RXKAZ.js';
41
41
  export { Container } from './chunk-DNJI65VQ.js';
42
- export { DataTable } from './chunk-YPP7QHYT.js';
42
+ export { DataTable } from './chunk-K4ALNUZI.js';
43
43
  export { Skeleton } from './chunk-AQT3FZRQ.js';
44
44
  export { Segmented } from './chunk-NSMU66ZX.js';
45
45
  export { Pagination } from './chunk-RJTDQOT2.js';
46
46
  export { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from './chunk-435JHF7G.js';
47
- export { Checkbox } from './chunk-T3TQPOVM.js';
47
+ export { Checkbox } from './chunk-TLEKK53J.js';
48
48
  export { DatePicker } from './chunk-Q54CVE3W.js';
49
49
  export { Avatar, AvatarGroup } from './chunk-VFS3V3VY.js';
50
50
  export { BackupStatusPanel } from './chunk-JRFSUVSO.js';
51
51
  export { Badge } from './chunk-QEHTPQHL.js';
52
52
  export { BarChart } from './chunk-4PA2ACNF.js';
53
- export { BentoDashboard } from './chunk-ONMTHBZ4.js';
53
+ export { BentoDashboard } from './chunk-LGVXEWNB.js';
54
54
  export { StatCard } from './chunk-LUM2YJBH.js';
55
55
  export { ServiceHealthCard } from './chunk-7EP2T3OW.js';
56
56
  export { HostCard } from './chunk-DOUDJU4P.js';
57
57
  export { StatusDot } from './chunk-NHPISZWS.js';
58
58
  export { Breadcrumb } from './chunk-7J5QXUQN.js';
59
- export { Button, buttonVariants } from './chunk-ADE22JSR.js';
60
- export { CTABand } from './chunk-IUPVQWO5.js';
59
+ export { Button, buttonVariants } from './chunk-BQWF5MP7.js';
60
+ export { CTABand } from './chunk-FPFLOYIJ.js';
61
61
  export { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from './chunk-YYWODLER.js';
62
62
  export { ActionDiff } from './chunk-3XTZPDNV.js';
63
63
  export { ActionRow } from './chunk-OGVSZ7NV.js';
@@ -1,6 +1,6 @@
1
1
  'use client';
2
- export { PricingCard } from './chunk-OVSIOZHJ.js';
3
- import './chunk-ADE22JSR.js';
2
+ export { PricingCard } from './chunk-SNNMZ444.js';
3
+ import './chunk-BQWF5MP7.js';
4
4
  import './chunk-WSQNPRGN.js';
5
5
  //# sourceMappingURL=pricing-card.js.map
6
6
  //# sourceMappingURL=pricing-card.js.map
@@ -6,6 +6,12 @@ interface RadioGroupProps {
6
6
  label?: string;
7
7
  /** Error message */
8
8
  error?: string;
9
+ /** Controlled selected value */
10
+ value?: string;
11
+ /** Called with the selected option value */
12
+ onChange?: (value: string) => void;
13
+ /** Shared name for native radio grouping (auto-generated if omitted) */
14
+ name?: string;
9
15
  children?: React.ReactNode;
10
16
  className?: string;
11
17
  }
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- export { Radio, RadioGroup } from './chunk-6SKTH45H.js';
2
+ export { Radio, RadioGroup } from './chunk-J2Z4ZFVX.js';
3
3
  import './chunk-WSQNPRGN.js';
4
4
  //# sourceMappingURL=radio-group.js.map
5
5
  //# sourceMappingURL=radio-group.js.map
@@ -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": "3.1.1",
4
4
  "description": "Tollerud User Interface — dark, monochrome + yellow accent. Noir aesthetic meets modern utility.",
5
5
  "private": false,
6
6
  "type": "module",
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": "3.1.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 }"]}