@tollerud/ui 1.1.5 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +36 -13
- package/CHANGELOG.md +411 -0
- package/COMPONENTS.md +951 -0
- package/GETTING_STARTED.md +159 -0
- package/README.md +51 -43
- package/SKILL.md +59 -24
- package/components.json +18 -0
- package/dist/accordion.d.ts +20 -0
- package/dist/accordion.js +5 -0
- package/dist/accordion.js.map +1 -0
- package/dist/action-diff.d.ts +26 -0
- package/dist/action-diff.js +5 -0
- package/dist/action-diff.js.map +1 -0
- package/dist/action-row.d.ts +36 -0
- package/dist/action-row.js +6 -0
- package/dist/action-row.js.map +1 -0
- package/dist/alert-inbox.d.ts +23 -0
- package/dist/alert-inbox.js +6 -0
- package/dist/alert-inbox.js.map +1 -0
- package/dist/alert.d.ts +33 -0
- package/dist/alert.js +5 -0
- package/dist/alert.js.map +1 -0
- package/dist/approval-card.d.ts +27 -0
- package/dist/approval-card.js +5 -0
- package/dist/approval-card.js.map +1 -0
- package/dist/area-chart.d.ts +10 -0
- package/dist/area-chart.js +5 -0
- package/dist/area-chart.js.map +1 -0
- package/dist/avatar.d.ts +28 -0
- package/dist/avatar.js +5 -0
- package/dist/avatar.js.map +1 -0
- package/dist/backup-status-panel.d.ts +25 -0
- package/dist/backup-status-panel.js +6 -0
- package/dist/backup-status-panel.js.map +1 -0
- package/dist/badge.d.ts +17 -0
- package/dist/badge.js +5 -0
- package/dist/badge.js.map +1 -0
- package/dist/bar-chart.d.ts +15 -0
- package/dist/bar-chart.js +5 -0
- package/dist/bar-chart.js.map +1 -0
- package/dist/bento-dashboard.d.ts +30 -0
- package/dist/bento-dashboard.js +10 -0
- package/dist/bento-dashboard.js.map +1 -0
- package/dist/breadcrumb.d.ts +16 -0
- package/dist/breadcrumb.js +5 -0
- package/dist/breadcrumb.js.map +1 -0
- package/dist/button.d.ts +29 -0
- package/dist/button.js +5 -0
- package/dist/button.js.map +1 -0
- package/dist/card.d.ts +10 -0
- package/dist/card.js +5 -0
- package/dist/card.js.map +1 -0
- package/dist/checkbox.d.ts +9 -0
- package/dist/checkbox.js +5 -0
- package/dist/checkbox.js.map +1 -0
- package/dist/chunk-2QWKOCWF.js +79 -0
- package/dist/chunk-2QWKOCWF.js.map +1 -0
- package/dist/chunk-3LTW224O.js +53 -0
- package/dist/chunk-3LTW224O.js.map +1 -0
- package/dist/chunk-3XTZPDNV.js +94 -0
- package/dist/chunk-3XTZPDNV.js.map +1 -0
- package/dist/chunk-435JHF7G.js +65 -0
- package/dist/chunk-435JHF7G.js.map +1 -0
- package/dist/chunk-4PA2ACNF.js +52 -0
- package/dist/chunk-4PA2ACNF.js.map +1 -0
- package/dist/chunk-5GWHUJ5D.js +29 -0
- package/dist/chunk-5GWHUJ5D.js.map +1 -0
- package/dist/chunk-6FUKJD3W.js +123 -0
- package/dist/chunk-6FUKJD3W.js.map +1 -0
- package/dist/chunk-6IS2AYYG.js +106 -0
- package/dist/chunk-6IS2AYYG.js.map +1 -0
- package/dist/chunk-6PZKU6ZL.js +78 -0
- package/dist/chunk-6PZKU6ZL.js.map +1 -0
- package/dist/chunk-6SKTH45H.js +75 -0
- package/dist/chunk-6SKTH45H.js.map +1 -0
- package/dist/chunk-6UXW5YUC.js +77 -0
- package/dist/chunk-6UXW5YUC.js.map +1 -0
- package/dist/chunk-7EP2T3OW.js +52 -0
- package/dist/chunk-7EP2T3OW.js.map +1 -0
- package/dist/chunk-7J5QXUQN.js +38 -0
- package/dist/chunk-7J5QXUQN.js.map +1 -0
- package/dist/chunk-A6L5C3IJ.js +47 -0
- package/dist/chunk-A6L5C3IJ.js.map +1 -0
- package/dist/chunk-ADE22JSR.js +54 -0
- package/dist/chunk-ADE22JSR.js.map +1 -0
- package/dist/chunk-ANW6J6PV.js +42 -0
- package/dist/chunk-ANW6J6PV.js.map +1 -0
- package/dist/chunk-APFFKNPS.js +80 -0
- package/dist/chunk-APFFKNPS.js.map +1 -0
- package/dist/chunk-AQT3FZRQ.js +23 -0
- package/dist/chunk-AQT3FZRQ.js.map +1 -0
- package/dist/chunk-AZADSX4Z.js +85 -0
- package/dist/chunk-AZADSX4Z.js.map +1 -0
- package/dist/chunk-BPCH5LJ3.js +36 -0
- package/dist/chunk-BPCH5LJ3.js.map +1 -0
- package/dist/chunk-CDI7353B.js +40 -0
- package/dist/chunk-CDI7353B.js.map +1 -0
- package/dist/chunk-CKNWXYMA.js +53 -0
- package/dist/chunk-CKNWXYMA.js.map +1 -0
- package/dist/chunk-DNJI65VQ.js +22 -0
- package/dist/chunk-DNJI65VQ.js.map +1 -0
- package/dist/chunk-DOUDJU4P.js +63 -0
- package/dist/chunk-DOUDJU4P.js.map +1 -0
- package/dist/chunk-DRCMGIQ6.js +64 -0
- package/dist/chunk-DRCMGIQ6.js.map +1 -0
- package/dist/chunk-DZOBXK2S.js +28 -0
- package/dist/chunk-DZOBXK2S.js.map +1 -0
- package/dist/chunk-EN4OJCEF.js +54 -0
- package/dist/chunk-EN4OJCEF.js.map +1 -0
- package/dist/chunk-EVHZFYWX.js +33 -0
- package/dist/chunk-EVHZFYWX.js.map +1 -0
- package/dist/chunk-G2VKWNZA.js +53 -0
- package/dist/chunk-G2VKWNZA.js.map +1 -0
- package/dist/chunk-GTM2DE4C.js +156 -0
- package/dist/chunk-GTM2DE4C.js.map +1 -0
- package/dist/chunk-H3ZVGTJM.js +165 -0
- package/dist/chunk-H3ZVGTJM.js.map +1 -0
- package/dist/chunk-HWAWUEHC.js +28 -0
- package/dist/chunk-HWAWUEHC.js.map +1 -0
- package/dist/chunk-HWJVRTWO.js +36 -0
- package/dist/chunk-HWJVRTWO.js.map +1 -0
- package/dist/chunk-ILADNTUB.js +77 -0
- package/dist/chunk-ILADNTUB.js.map +1 -0
- package/dist/chunk-IUPVQWO5.js +31 -0
- package/dist/chunk-IUPVQWO5.js.map +1 -0
- package/dist/chunk-JFOW2DI5.js +43 -0
- package/dist/chunk-JFOW2DI5.js.map +1 -0
- package/dist/chunk-JRFSUVSO.js +66 -0
- package/dist/chunk-JRFSUVSO.js.map +1 -0
- package/dist/chunk-KI6OTVID.js +91 -0
- package/dist/chunk-KI6OTVID.js.map +1 -0
- package/dist/chunk-LUM2YJBH.js +73 -0
- package/dist/chunk-LUM2YJBH.js.map +1 -0
- package/dist/chunk-NHPISZWS.js +71 -0
- package/dist/chunk-NHPISZWS.js.map +1 -0
- package/dist/chunk-NOLWJJHT.js +52 -0
- package/dist/chunk-NOLWJJHT.js.map +1 -0
- package/dist/chunk-NPVINX3Q.js +20 -0
- package/dist/chunk-NPVINX3Q.js.map +1 -0
- package/dist/chunk-NSMU66ZX.js +47 -0
- package/dist/chunk-NSMU66ZX.js.map +1 -0
- package/dist/chunk-O5SWPHUQ.js +79 -0
- package/dist/chunk-O5SWPHUQ.js.map +1 -0
- package/dist/chunk-OGVSZ7NV.js +53 -0
- package/dist/chunk-OGVSZ7NV.js.map +1 -0
- package/dist/chunk-OLHMMFQ7.js +43 -0
- package/dist/chunk-OLHMMFQ7.js.map +1 -0
- package/dist/chunk-ONMTHBZ4.js +54 -0
- package/dist/chunk-ONMTHBZ4.js.map +1 -0
- package/dist/chunk-OVSIOZHJ.js +56 -0
- package/dist/chunk-OVSIOZHJ.js.map +1 -0
- package/dist/chunk-Q54CVE3W.js +154 -0
- package/dist/chunk-Q54CVE3W.js.map +1 -0
- package/dist/chunk-QEHTPQHL.js +35 -0
- package/dist/chunk-QEHTPQHL.js.map +1 -0
- package/dist/chunk-QEIEWGHA.js +62 -0
- package/dist/chunk-QEIEWGHA.js.map +1 -0
- package/dist/chunk-QQHBEACI.js +88 -0
- package/dist/chunk-QQHBEACI.js.map +1 -0
- package/dist/chunk-RJTDQOT2.js +73 -0
- package/dist/chunk-RJTDQOT2.js.map +1 -0
- package/dist/chunk-RQ3RXKAZ.js +203 -0
- package/dist/chunk-RQ3RXKAZ.js.map +1 -0
- package/dist/chunk-RZK2S2OO.js +126 -0
- package/dist/chunk-RZK2S2OO.js.map +1 -0
- package/dist/chunk-SAP7JSSO.js +106 -0
- package/dist/chunk-SAP7JSSO.js.map +1 -0
- package/dist/chunk-T3TQPOVM.js +79 -0
- package/dist/chunk-T3TQPOVM.js.map +1 -0
- package/dist/chunk-T3UQ7G4T.js +58 -0
- package/dist/chunk-T3UQ7G4T.js.map +1 -0
- package/dist/chunk-T56TTOI6.js +53 -0
- package/dist/chunk-T56TTOI6.js.map +1 -0
- package/dist/chunk-T7EFDE2L.js +36 -0
- package/dist/chunk-T7EFDE2L.js.map +1 -0
- package/dist/chunk-VFS3V3VY.js +91 -0
- package/dist/chunk-VFS3V3VY.js.map +1 -0
- package/dist/chunk-VOARBYVQ.js +44 -0
- package/dist/chunk-VOARBYVQ.js.map +1 -0
- package/dist/chunk-WDANALHD.js +95 -0
- package/dist/chunk-WDANALHD.js.map +1 -0
- package/dist/chunk-WSQNPRGN.js +12 -0
- package/dist/chunk-WSQNPRGN.js.map +1 -0
- package/dist/chunk-YPP7QHYT.js +393 -0
- package/dist/chunk-YPP7QHYT.js.map +1 -0
- package/dist/chunk-YTU7BRDW.js +72 -0
- package/dist/chunk-YTU7BRDW.js.map +1 -0
- package/dist/chunk-YYWODLER.js +111 -0
- package/dist/chunk-YYWODLER.js.map +1 -0
- package/dist/chunk-ZOXO3G3I.js +50 -0
- package/dist/chunk-ZOXO3G3I.js.map +1 -0
- package/dist/chunk-ZTFOR3AN.js +79 -0
- package/dist/chunk-ZTFOR3AN.js.map +1 -0
- package/dist/code-block.d.ts +14 -0
- package/dist/code-block.js +5 -0
- package/dist/code-block.js.map +1 -0
- package/dist/combobox.d.ts +26 -0
- package/dist/combobox.js +5 -0
- package/dist/combobox.js.map +1 -0
- package/dist/command-menu.d.ts +52 -0
- package/dist/command-menu.js +7 -0
- package/dist/command-menu.js.map +1 -0
- package/dist/container.d.ts +9 -0
- package/dist/container.js +5 -0
- package/dist/container.js.map +1 -0
- package/dist/cta-band.d.ts +12 -0
- package/dist/cta-band.js +5 -0
- package/dist/cta-band.js.map +1 -0
- package/dist/data-table.d.ts +58 -0
- package/dist/data-table.js +12 -0
- package/dist/data-table.js.map +1 -0
- package/dist/date-picker.d.ts +20 -0
- package/dist/date-picker.js +5 -0
- package/dist/date-picker.js.map +1 -0
- package/dist/dialog.d.ts +21 -0
- package/dist/dialog.js +5 -0
- package/dist/dialog.js.map +1 -0
- package/dist/divider.d.ts +12 -0
- package/dist/divider.js +5 -0
- package/dist/divider.js.map +1 -0
- package/dist/docker-stack-card.d.ts +21 -0
- package/dist/docker-stack-card.js +6 -0
- package/dist/docker-stack-card.js.map +1 -0
- package/dist/donut.d.ts +15 -0
- package/dist/donut.js +5 -0
- package/dist/donut.js.map +1 -0
- package/dist/dropdown-menu.d.ts +15 -0
- package/dist/dropdown-menu.js +5 -0
- package/dist/dropdown-menu.js.map +1 -0
- package/dist/empty.d.ts +12 -0
- package/dist/empty.js +5 -0
- package/dist/empty.js.map +1 -0
- package/dist/feature-card.d.ts +11 -0
- package/dist/feature-card.js +6 -0
- package/dist/feature-card.js.map +1 -0
- package/dist/file-upload.d.ts +20 -0
- package/dist/file-upload.js +5 -0
- package/dist/file-upload.js.map +1 -0
- package/dist/footer.d.ts +35 -0
- package/dist/footer.js +6 -0
- package/dist/footer.js.map +1 -0
- package/dist/form-row.d.ts +19 -0
- package/dist/form-row.js +5 -0
- package/dist/form-row.js.map +1 -0
- package/dist/glow-card.d.ts +14 -0
- package/dist/glow-card.js +5 -0
- package/dist/glow-card.js.map +1 -0
- package/dist/hero-block.d.ts +16 -0
- package/dist/hero-block.js +7 -0
- package/dist/hero-block.js.map +1 -0
- package/dist/host-card.d.ts +27 -0
- package/dist/host-card.js +6 -0
- package/dist/host-card.js.map +1 -0
- package/dist/incident-card.d.ts +23 -0
- package/dist/incident-card.js +5 -0
- package/dist/incident-card.js.map +1 -0
- package/dist/index.d.ts +77 -960
- package/dist/index.js +69 -3812
- package/dist/index.js.map +1 -1
- package/dist/input.d.ts +10 -0
- package/dist/input.js +5 -0
- package/dist/input.js.map +1 -0
- package/dist/kbd.d.ts +24 -0
- package/dist/kbd.js +5 -0
- package/dist/kbd.js.map +1 -0
- package/dist/log-viewer.d.ts +35 -0
- package/dist/log-viewer.js +5 -0
- package/dist/log-viewer.js.map +1 -0
- package/dist/meter.d.ts +23 -0
- package/dist/meter.js +5 -0
- package/dist/meter.js.map +1 -0
- package/dist/monogram.d.ts +20 -0
- package/dist/monogram.js +5 -0
- package/dist/monogram.js.map +1 -0
- package/dist/noir-glow-background.d.ts +56 -0
- package/dist/noir-glow-background.js +4 -0
- package/dist/noir-glow-background.js.map +1 -0
- package/dist/pagination.d.ts +16 -0
- package/dist/pagination.js +5 -0
- package/dist/pagination.js.map +1 -0
- package/dist/panel.d.ts +12 -0
- package/dist/panel.js +5 -0
- package/dist/panel.js.map +1 -0
- package/dist/password-input.d.ts +10 -0
- package/dist/password-input.js +5 -0
- package/dist/password-input.js.map +1 -0
- package/dist/pill.d.ts +17 -0
- package/dist/pill.js +5 -0
- package/dist/pill.js.map +1 -0
- package/dist/pricing-card.d.ts +20 -0
- package/dist/pricing-card.js +6 -0
- package/dist/pricing-card.js.map +1 -0
- package/dist/progress.d.ts +6 -0
- package/dist/progress.js +5 -0
- package/dist/progress.js.map +1 -0
- package/dist/radio-group.d.ts +18 -0
- package/dist/radio-group.js +5 -0
- package/dist/radio-group.js.map +1 -0
- package/dist/rollback-plan.d.ts +23 -0
- package/dist/rollback-plan.js +5 -0
- package/dist/rollback-plan.js.map +1 -0
- package/dist/segmented.d.ts +17 -0
- package/dist/segmented.js +5 -0
- package/dist/segmented.js.map +1 -0
- package/dist/select.d.ts +18 -0
- package/dist/select.js +5 -0
- package/dist/select.js.map +1 -0
- package/dist/service-health-card.d.ts +21 -0
- package/dist/service-health-card.js +6 -0
- package/dist/service-health-card.js.map +1 -0
- package/dist/sheet.d.ts +25 -0
- package/dist/sheet.js +5 -0
- package/dist/sheet.js.map +1 -0
- package/dist/skeleton.d.ts +13 -0
- package/dist/skeleton.js +5 -0
- package/dist/skeleton.js.map +1 -0
- package/dist/slider.d.ts +12 -0
- package/dist/slider.js +5 -0
- package/dist/slider.js.map +1 -0
- package/dist/sparkline.d.ts +16 -0
- package/dist/sparkline.js +5 -0
- package/dist/sparkline.js.map +1 -0
- package/dist/stat-card.d.ts +15 -0
- package/dist/stat-card.js +5 -0
- package/dist/stat-card.js.map +1 -0
- package/dist/status-dot.d.ts +13 -0
- package/dist/status-dot.js +5 -0
- package/dist/status-dot.js.map +1 -0
- package/dist/stepper.d.ts +16 -0
- package/dist/stepper.js +5 -0
- package/dist/stepper.js.map +1 -0
- package/dist/switch.d.ts +9 -0
- package/dist/switch.js +5 -0
- package/dist/switch.js.map +1 -0
- package/dist/tabs.d.ts +9 -0
- package/dist/tabs.js +5 -0
- package/dist/tabs.js.map +1 -0
- package/dist/tag-input.d.ts +20 -0
- package/dist/tag-input.js +5 -0
- package/dist/tag-input.js.map +1 -0
- package/dist/textarea.d.ts +10 -0
- package/dist/textarea.js +5 -0
- package/dist/textarea.js.map +1 -0
- package/dist/timeline.d.ts +30 -0
- package/dist/timeline.js +5 -0
- package/dist/timeline.js.map +1 -0
- package/dist/toaster.d.ts +10 -0
- package/dist/toaster.js +4 -0
- package/dist/toaster.js.map +1 -0
- package/dist/tooltip.d.ts +12 -0
- package/dist/tooltip.js +5 -0
- package/dist/tooltip.js.map +1 -0
- package/dist/utils.d.ts +5 -0
- package/dist/utils.js +4 -0
- package/dist/utils.js.map +1 -0
- package/globals-layers.css +1019 -0
- package/globals-v3.css +17 -0
- package/globals-v4.css +2 -0
- package/globals.css +12 -939
- package/package.json +85 -17
- package/registry.json +936 -0
- package/tailwind.css +9 -0
- package/tokens.css +20 -0
- package/tollerud-avatar-full.png +0 -0
- package/dist/index.cjs +0 -3938
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -960
- /package/{tia-full-figure.svg → tollerud-avatar-full.svg} +0 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { cn } from './chunk-WSQNPRGN.js';
|
|
3
|
+
import { forwardRef } from 'react';
|
|
4
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
var stepIcon = {
|
|
7
|
+
pending: "\u25CB",
|
|
8
|
+
running: "\u25C9",
|
|
9
|
+
success: "\u25CF",
|
|
10
|
+
failed: "\u2715",
|
|
11
|
+
skipped: "\u2014"
|
|
12
|
+
};
|
|
13
|
+
var stepStyles = {
|
|
14
|
+
pending: "text-tollerud-noir-400",
|
|
15
|
+
running: "text-tollerud-yellow animate-pulse",
|
|
16
|
+
success: "text-tollerud-success",
|
|
17
|
+
failed: "text-tollerud-error",
|
|
18
|
+
skipped: "text-tollerud-noir-500"
|
|
19
|
+
};
|
|
20
|
+
var RollbackPlan = forwardRef(
|
|
21
|
+
({ className, name, steps, executing, loading, ...props }, ref) => {
|
|
22
|
+
const statusSummary = {
|
|
23
|
+
pending: steps.filter((s) => s.status === "pending").length,
|
|
24
|
+
running: steps.filter((s) => s.status === "running").length,
|
|
25
|
+
success: steps.filter((s) => s.status === "success").length,
|
|
26
|
+
failed: steps.filter((s) => s.status === "failed").length,
|
|
27
|
+
skipped: steps.filter((s) => s.status === "skipped").length
|
|
28
|
+
};
|
|
29
|
+
return /* @__PURE__ */ jsxs(
|
|
30
|
+
"div",
|
|
31
|
+
{
|
|
32
|
+
ref,
|
|
33
|
+
className: cn(
|
|
34
|
+
"rounded-lg border border-tollerud-border bg-tollerud-surface-raised",
|
|
35
|
+
loading && "animate-pulse",
|
|
36
|
+
className
|
|
37
|
+
),
|
|
38
|
+
...props,
|
|
39
|
+
children: [
|
|
40
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b border-tollerud-border", children: [
|
|
41
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
42
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-tollerud-foreground", children: name }),
|
|
43
|
+
executing && /* @__PURE__ */ jsx("span", { className: "text-[11px] text-tollerud-yellow font-medium animate-pulse", children: "Executing\u2026" })
|
|
44
|
+
] }),
|
|
45
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-[11px] text-tollerud-text-muted", children: [
|
|
46
|
+
statusSummary.success > 0 && /* @__PURE__ */ jsxs("span", { className: "text-tollerud-success", children: [
|
|
47
|
+
statusSummary.success,
|
|
48
|
+
" done"
|
|
49
|
+
] }),
|
|
50
|
+
statusSummary.failed > 0 && /* @__PURE__ */ jsxs("span", { className: "text-tollerud-error", children: [
|
|
51
|
+
statusSummary.failed,
|
|
52
|
+
" failed"
|
|
53
|
+
] }),
|
|
54
|
+
statusSummary.running > 0 && /* @__PURE__ */ jsxs("span", { className: "text-tollerud-yellow", children: [
|
|
55
|
+
statusSummary.running,
|
|
56
|
+
" running"
|
|
57
|
+
] })
|
|
58
|
+
] })
|
|
59
|
+
] }),
|
|
60
|
+
/* @__PURE__ */ jsx("div", { className: "p-1", children: steps.map((step) => /* @__PURE__ */ jsxs(
|
|
61
|
+
"div",
|
|
62
|
+
{
|
|
63
|
+
className: cn(
|
|
64
|
+
"flex items-start gap-3 px-3 py-2 rounded-md",
|
|
65
|
+
"transition-colors duration-[150ms]",
|
|
66
|
+
step.status === "failed" && "bg-tollerud-error/5",
|
|
67
|
+
step.status === "running" && "bg-tollerud-yellow/5"
|
|
68
|
+
),
|
|
69
|
+
children: [
|
|
70
|
+
/* @__PURE__ */ jsx("span", { className: cn("font-mono text-sm mt-0.5 flex-shrink-0", stepStyles[step.status]), children: stepIcon[step.status] }),
|
|
71
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
72
|
+
/* @__PURE__ */ jsx("span", { className: cn(
|
|
73
|
+
"text-xs font-medium",
|
|
74
|
+
step.status === "success" ? "text-tollerud-success" : step.status === "failed" ? "text-tollerud-error" : step.status === "skipped" ? "text-tollerud-noir-500" : "text-tollerud-foreground"
|
|
75
|
+
), children: step.label }),
|
|
76
|
+
step.description && /* @__PURE__ */ jsx("p", { className: "text-[11px] text-tollerud-text-muted mt-0.5", children: step.description })
|
|
77
|
+
] }),
|
|
78
|
+
/* @__PURE__ */ jsx("span", { className: cn(
|
|
79
|
+
"text-[10px] uppercase font-semibold flex-shrink-0",
|
|
80
|
+
stepStyles[step.status]
|
|
81
|
+
), children: step.status })
|
|
82
|
+
]
|
|
83
|
+
},
|
|
84
|
+
step.id
|
|
85
|
+
)) })
|
|
86
|
+
]
|
|
87
|
+
}
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
);
|
|
91
|
+
RollbackPlan.displayName = "RollbackPlan";
|
|
92
|
+
|
|
93
|
+
export { RollbackPlan };
|
|
94
|
+
//# sourceMappingURL=chunk-WDANALHD.js.map
|
|
95
|
+
//# sourceMappingURL=chunk-WDANALHD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../components/RollbackPlan.tsx"],"names":[],"mappings":";;;;AAuBA,IAAM,QAAA,GAA+C;AAAA,EACnD,OAAA,EAAS,QAAA;AAAA,EACT,OAAA,EAAS,QAAA;AAAA,EACT,OAAA,EAAS,QAAA;AAAA,EACT,MAAA,EAAS,QAAA;AAAA,EACT,OAAA,EAAS;AACX,CAAA;AAEA,IAAM,UAAA,GAAiD;AAAA,EACrD,OAAA,EAAU,wBAAA;AAAA,EACV,OAAA,EAAU,oCAAA;AAAA,EACV,OAAA,EAAU,uBAAA;AAAA,EACV,MAAA,EAAU,qBAAA;AAAA,EACV,OAAA,EAAU;AACZ,CAAA;AAEA,IAAM,YAAA,GAAe,UAAA;AAAA,EACnB,CAAC,EAAE,SAAA,EAAW,IAAA,EAAM,KAAA,EAAO,WAAW,OAAA,EAAS,GAAG,KAAA,EAAM,EAAG,GAAA,KAAQ;AACjE,IAAA,MAAM,aAAA,GAAoD;AAAA,MACxD,OAAA,EAAS,MAAM,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,MAAA,KAAW,SAAS,CAAA,CAAE,MAAA;AAAA,MACrD,OAAA,EAAS,MAAM,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,MAAA,KAAW,SAAS,CAAA,CAAE,MAAA;AAAA,MACrD,OAAA,EAAS,MAAM,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,MAAA,KAAW,SAAS,CAAA,CAAE,MAAA;AAAA,MACrD,MAAA,EAAS,MAAM,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,MAAA,KAAW,QAAQ,CAAA,CAAE,MAAA;AAAA,MACpD,OAAA,EAAS,MAAM,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,MAAA,KAAW,SAAS,CAAA,CAAE;AAAA,KACvD;AAEA,IAAA,uBACE,IAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,SAAA,EAAW,EAAA;AAAA,UACT,qEAAA;AAAA,UACA,OAAA,IAAW,eAAA;AAAA,UACX;AAAA,SACF;AAAA,QACC,GAAG,KAAA;AAAA,QAGJ,QAAA,EAAA;AAAA,0BAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,6EAAA,EACb,QAAA,EAAA;AAAA,4BAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,yBAAA,EACb,QAAA,EAAA;AAAA,8BAAA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,gDAAA,EAAkD,QAAA,EAAA,IAAA,EAAK,CAAA;AAAA,cACtE,SAAA,oBACC,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,8DAA6D,QAAA,EAAA,iBAAA,EAAU;AAAA,aAAA,EAE3F,CAAA;AAAA,4BACA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,8DAAA,EACZ,QAAA,EAAA;AAAA,cAAA,aAAA,CAAc,OAAA,GAAU,CAAA,oBAAK,IAAA,CAAC,MAAA,EAAA,EAAK,WAAU,uBAAA,EAAyB,QAAA,EAAA;AAAA,gBAAA,aAAA,CAAc,OAAA;AAAA,gBAAQ;AAAA,eAAA,EAAK,CAAA;AAAA,cACjG,cAAc,MAAA,GAAS,CAAA,oBAAK,IAAA,CAAC,MAAA,EAAA,EAAK,WAAU,qBAAA,EAAuB,QAAA,EAAA;AAAA,gBAAA,aAAA,CAAc,MAAA;AAAA,gBAAO;AAAA,eAAA,EAAO,CAAA;AAAA,cAC/F,cAAc,OAAA,GAAU,CAAA,oBAAK,IAAA,CAAC,MAAA,EAAA,EAAK,WAAU,sBAAA,EAAwB,QAAA,EAAA;AAAA,gBAAA,aAAA,CAAc,OAAA;AAAA,gBAAQ;AAAA,eAAA,EAAQ;AAAA,aAAA,EACtG;AAAA,WAAA,EACF,CAAA;AAAA,8BAGC,KAAA,EAAA,EAAI,SAAA,EAAU,OACZ,QAAA,EAAA,KAAA,CAAM,GAAA,CAAI,CAAC,IAAA,qBACV,IAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cAEC,SAAA,EAAW,EAAA;AAAA,gBACT,6CAAA;AAAA,gBACA,oCAAA;AAAA,gBACA,IAAA,CAAK,WAAW,QAAA,IAAY,qBAAA;AAAA,gBAC5B,IAAA,CAAK,WAAW,SAAA,IAAa;AAAA,eAC/B;AAAA,cAEA,QAAA,EAAA;AAAA,gCAAA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAW,EAAA,CAAG,wCAAA,EAA0C,UAAA,CAAW,IAAA,CAAK,MAAM,CAAC,CAAA,EAClF,QAAA,EAAA,QAAA,CAAS,IAAA,CAAK,MAAM,CAAA,EACvB,CAAA;AAAA,gCACA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,gBAAA,EACb,QAAA,EAAA;AAAA,kCAAA,GAAA,CAAC,UAAK,SAAA,EAAW,EAAA;AAAA,oBACf,qBAAA;AAAA,oBACA,IAAA,CAAK,MAAA,KAAW,SAAA,GAAY,uBAAA,GAC5B,IAAA,CAAK,MAAA,KAAW,QAAA,GAAW,qBAAA,GAC3B,IAAA,CAAK,MAAA,KAAW,SAAA,GAAY,wBAAA,GAC5B;AAAA,mBACF,EACG,eAAK,KAAA,EACR,CAAA;AAAA,kBACC,KAAK,WAAA,oBACJ,GAAA,CAAC,OAAE,SAAA,EAAU,6CAAA,EAA+C,eAAK,WAAA,EAAY;AAAA,iBAAA,EAEjF,CAAA;AAAA,gCACA,GAAA,CAAC,UAAK,SAAA,EAAW,EAAA;AAAA,kBACf,mDAAA;AAAA,kBACA,UAAA,CAAW,KAAK,MAAM;AAAA,iBACxB,EACG,eAAK,MAAA,EACR;AAAA;AAAA,aAAA;AAAA,YA9BK,IAAA,CAAK;AAAA,WAgCb,CAAA,EACH;AAAA;AAAA;AAAA,KACF;AAAA,EAEJ;AACF;AACA,YAAA,CAAa,WAAA,GAAc,cAAA","file":"chunk-WDANALHD.js","sourcesContent":["import { type HTMLAttributes, forwardRef } from 'react'\nimport { cn } from '@/lib/utils'\n\nexport type RollbackStepStatus = 'pending' | 'running' | 'success' | 'failed' | 'skipped'\n\nexport interface RollbackStep {\n id: string\n label: string\n description?: string\n status: RollbackStepStatus\n}\n\nexport interface RollbackPlanProps extends HTMLAttributes<HTMLDivElement> {\n /** Name/identifier for the plan */\n name: string\n /** Rollback steps */\n steps: RollbackStep[]\n /** Whether the plan is executing */\n executing?: boolean\n /** Whether the plan is loading */\n loading?: boolean\n}\n\nconst stepIcon: Record<RollbackStepStatus, string> = {\n pending: '○',\n running: '◉',\n success: '●',\n failed: '✕',\n skipped: '—',\n}\n\nconst stepStyles: Record<RollbackStepStatus, string> = {\n pending: 'text-tollerud-noir-400',\n running: 'text-tollerud-yellow animate-pulse',\n success: 'text-tollerud-success',\n failed: 'text-tollerud-error',\n skipped: 'text-tollerud-noir-500',\n}\n\nconst RollbackPlan = forwardRef<HTMLDivElement, RollbackPlanProps>(\n ({ className, name, steps, executing, loading, ...props }, ref) => {\n const statusSummary: Record<RollbackStepStatus, number> = {\n pending: steps.filter((s) => s.status === 'pending').length,\n running: steps.filter((s) => s.status === 'running').length,\n success: steps.filter((s) => s.status === 'success').length,\n failed: steps.filter((s) => s.status === 'failed').length,\n skipped: steps.filter((s) => s.status === 'skipped').length,\n }\n\n return (\n <div\n ref={ref}\n className={cn(\n 'rounded-lg border border-tollerud-border bg-tollerud-surface-raised',\n loading && 'animate-pulse',\n className\n )}\n {...props}\n >\n {/* Header */}\n <div className=\"flex items-center justify-between px-4 py-3 border-b border-tollerud-border\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm font-semibold text-tollerud-foreground\">{name}</span>\n {executing && (\n <span className=\"text-[11px] text-tollerud-yellow font-medium animate-pulse\">Executing…</span>\n )}\n </div>\n <div className=\"flex items-center gap-2 text-[11px] text-tollerud-text-muted\">\n {statusSummary.success > 0 && <span className=\"text-tollerud-success\">{statusSummary.success} done</span>}\n {statusSummary.failed > 0 && <span className=\"text-tollerud-error\">{statusSummary.failed} failed</span>}\n {statusSummary.running > 0 && <span className=\"text-tollerud-yellow\">{statusSummary.running} running</span>}\n </div>\n </div>\n\n {/* Steps */}\n <div className=\"p-1\">\n {steps.map((step) => (\n <div\n key={step.id}\n className={cn(\n 'flex items-start gap-3 px-3 py-2 rounded-md',\n 'transition-colors duration-[150ms]',\n step.status === 'failed' && 'bg-tollerud-error/5',\n step.status === 'running' && 'bg-tollerud-yellow/5'\n )}\n >\n <span className={cn('font-mono text-sm mt-0.5 flex-shrink-0', stepStyles[step.status])}>\n {stepIcon[step.status]}\n </span>\n <div className=\"flex-1 min-w-0\">\n <span className={cn(\n 'text-xs font-medium',\n step.status === 'success' ? 'text-tollerud-success' :\n step.status === 'failed' ? 'text-tollerud-error' :\n step.status === 'skipped' ? 'text-tollerud-noir-500' :\n 'text-tollerud-foreground'\n )}>\n {step.label}\n </span>\n {step.description && (\n <p className=\"text-[11px] text-tollerud-text-muted mt-0.5\">{step.description}</p>\n )}\n </div>\n <span className={cn(\n 'text-[10px] uppercase font-semibold flex-shrink-0',\n stepStyles[step.status]\n )}>\n {step.status}\n </span>\n </div>\n ))}\n </div>\n </div>\n )\n }\n)\nRollbackPlan.displayName = 'RollbackPlan'\n\nexport { RollbackPlan }"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { clsx } from 'clsx';
|
|
3
|
+
import { twMerge } from 'tailwind-merge';
|
|
4
|
+
|
|
5
|
+
// lib/utils.ts
|
|
6
|
+
function cn(...inputs) {
|
|
7
|
+
return twMerge(clsx(inputs));
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export { cn };
|
|
11
|
+
//# sourceMappingURL=chunk-WSQNPRGN.js.map
|
|
12
|
+
//# sourceMappingURL=chunk-WSQNPRGN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../lib/utils.ts"],"names":[],"mappings":";;;;AAGO,SAAS,MAAM,MAAA,EAAsB;AAC1C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC7B","file":"chunk-WSQNPRGN.js","sourcesContent":["import { type ClassValue, clsx } from 'clsx'\nimport { twMerge } from 'tailwind-merge'\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n"]}
|
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { Skeleton } from './chunk-AQT3FZRQ.js';
|
|
3
|
+
import { Segmented } from './chunk-NSMU66ZX.js';
|
|
4
|
+
import { Pagination } from './chunk-RJTDQOT2.js';
|
|
5
|
+
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuSeparator, DropdownMenuLabel, DropdownMenuItem } from './chunk-435JHF7G.js';
|
|
6
|
+
import { Checkbox } from './chunk-T3TQPOVM.js';
|
|
7
|
+
import { Badge } from './chunk-QEHTPQHL.js';
|
|
8
|
+
import { Button } from './chunk-ADE22JSR.js';
|
|
9
|
+
import { cn } from './chunk-WSQNPRGN.js';
|
|
10
|
+
import { forwardRef, useMemo, useState } from 'react';
|
|
11
|
+
import { Search, X, MoreHorizontal, ChevronDown } from 'lucide-react';
|
|
12
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
13
|
+
|
|
14
|
+
function DataTableInner({
|
|
15
|
+
columns,
|
|
16
|
+
data,
|
|
17
|
+
rows,
|
|
18
|
+
rowKey,
|
|
19
|
+
onRowClick,
|
|
20
|
+
className,
|
|
21
|
+
emptyMessage = "No data",
|
|
22
|
+
searchable = false,
|
|
23
|
+
searchKeys,
|
|
24
|
+
searchPlaceholder = "Search\u2026",
|
|
25
|
+
filter,
|
|
26
|
+
selectable = false,
|
|
27
|
+
pageSize,
|
|
28
|
+
bulkActions = [],
|
|
29
|
+
rowMenu,
|
|
30
|
+
toolbarRight,
|
|
31
|
+
emptyState,
|
|
32
|
+
loading = false,
|
|
33
|
+
skeletonRows = 5,
|
|
34
|
+
forwardedRef
|
|
35
|
+
}) {
|
|
36
|
+
const tableData = useMemo(() => rows ?? data ?? [], [rows, data]);
|
|
37
|
+
const isRich = searchable || filter || selectable || pageSize !== void 0 || !!rowMenu || !!toolbarRight || bulkActions.length > 0 || !!emptyState || loading;
|
|
38
|
+
const [sortKey, setSortKey] = useState(null);
|
|
39
|
+
const [sortDir, setSortDir] = useState("asc");
|
|
40
|
+
const [filters, setFilters] = useState({});
|
|
41
|
+
const [query, setQuery] = useState("");
|
|
42
|
+
const [filterValue, setFilterValue] = useState("all");
|
|
43
|
+
const [selected, setSelected] = useState([]);
|
|
44
|
+
const [page, setPage] = useState(1);
|
|
45
|
+
const getRowKey = (row, i) => {
|
|
46
|
+
if (typeof rowKey === "function") return rowKey(row);
|
|
47
|
+
if (rowKey) return row[rowKey];
|
|
48
|
+
return row.id ?? row.key ?? i;
|
|
49
|
+
};
|
|
50
|
+
const toggleSort = (key) => {
|
|
51
|
+
if (sortKey === key) {
|
|
52
|
+
setSortDir((d) => d === "asc" ? "desc" : "asc");
|
|
53
|
+
} else {
|
|
54
|
+
setSortKey(key);
|
|
55
|
+
setSortDir("asc");
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const updateFilter = (key, value) => {
|
|
59
|
+
setFilters((prev) => {
|
|
60
|
+
const next = { ...prev };
|
|
61
|
+
if (value.trim() === "") {
|
|
62
|
+
delete next[key];
|
|
63
|
+
} else {
|
|
64
|
+
next[key] = value;
|
|
65
|
+
}
|
|
66
|
+
return next;
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
const searchKeysResolved = searchKeys ?? columns.map((c) => c.key);
|
|
70
|
+
const filterOptions = filter ? filter.options ?? Array.from(new Set(tableData.map((r) => String(r[filter.key] ?? "")))) : [];
|
|
71
|
+
const filtered = useMemo(() => {
|
|
72
|
+
let result = tableData;
|
|
73
|
+
if (isRich && filter && filterValue !== "all") {
|
|
74
|
+
result = result.filter((row) => String(row[filter.key] ?? "") === filterValue);
|
|
75
|
+
}
|
|
76
|
+
if (isRich && searchable && query.trim()) {
|
|
77
|
+
const q = query.trim().toLowerCase();
|
|
78
|
+
result = result.filter(
|
|
79
|
+
(row) => searchKeysResolved.some((key) => String(row[key] ?? "").toLowerCase().includes(q))
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
if (!isRich) {
|
|
83
|
+
const activeFilters = Object.entries(filters).filter(([, v]) => v.trim() !== "");
|
|
84
|
+
if (activeFilters.length > 0) {
|
|
85
|
+
result = result.filter(
|
|
86
|
+
(row) => activeFilters.every(([key, filterVal]) => {
|
|
87
|
+
const cellValue = String(row[key] ?? "").toLowerCase();
|
|
88
|
+
return cellValue.includes(filterVal.toLowerCase());
|
|
89
|
+
})
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return result;
|
|
94
|
+
}, [tableData, filters, isRich, filter, filterValue, searchable, query, searchKeysResolved]);
|
|
95
|
+
const sorted = useMemo(() => {
|
|
96
|
+
if (!sortKey) return filtered;
|
|
97
|
+
const col = columns.find((c) => c.key === sortKey);
|
|
98
|
+
if (!col?.sortable) return filtered;
|
|
99
|
+
return [...filtered].sort((a, b) => {
|
|
100
|
+
const aVal = a[sortKey];
|
|
101
|
+
const bVal = b[sortKey];
|
|
102
|
+
if (typeof aVal === "number" && typeof bVal === "number") {
|
|
103
|
+
return sortDir === "asc" ? aVal - bVal : bVal - aVal;
|
|
104
|
+
}
|
|
105
|
+
const aStr = String(aVal ?? "");
|
|
106
|
+
const bStr = String(bVal ?? "");
|
|
107
|
+
const cmp = aStr.localeCompare(bStr, "nb", { numeric: true });
|
|
108
|
+
return sortDir === "asc" ? cmp : -cmp;
|
|
109
|
+
});
|
|
110
|
+
}, [filtered, sortKey, sortDir, columns]);
|
|
111
|
+
const pageCount = pageSize ? Math.max(1, Math.ceil(sorted.length / pageSize)) : 1;
|
|
112
|
+
const currentPage = Math.min(page, pageCount);
|
|
113
|
+
const pageRows = pageSize ? sorted.slice((currentPage - 1) * pageSize, currentPage * pageSize) : sorted;
|
|
114
|
+
const clearSelection = () => setSelected([]);
|
|
115
|
+
const allOnPageSelected = pageRows.length > 0 && pageRows.every((row) => selected.includes(getRowKey(row, 0)));
|
|
116
|
+
const toggleAllOnPage = () => {
|
|
117
|
+
const pageIds = pageRows.map((row, i) => getRowKey(row, i));
|
|
118
|
+
if (allOnPageSelected) {
|
|
119
|
+
setSelected((prev) => prev.filter((id) => !pageIds.includes(id)));
|
|
120
|
+
} else {
|
|
121
|
+
setSelected((prev) => Array.from(/* @__PURE__ */ new Set([...prev, ...pageIds])));
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
const toggleRow = (id) => {
|
|
125
|
+
setSelected((prev) => prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id]);
|
|
126
|
+
};
|
|
127
|
+
const hasActiveFilters = Object.values(filters).some((v) => v.trim() !== "");
|
|
128
|
+
const filterableColumns = columns.filter((c) => c.filterable);
|
|
129
|
+
const colSpan = columns.length + (selectable ? 1 : 0) + (rowMenu ? 1 : 0);
|
|
130
|
+
const sortIndicator = (key) => {
|
|
131
|
+
const active = sortKey === key;
|
|
132
|
+
return /* @__PURE__ */ jsx(
|
|
133
|
+
ChevronDown,
|
|
134
|
+
{
|
|
135
|
+
size: 12,
|
|
136
|
+
className: cn(
|
|
137
|
+
"shrink-0 transition-transform duration-150",
|
|
138
|
+
active ? "text-tollerud-yellow opacity-100" : "opacity-25",
|
|
139
|
+
active && sortDir === "desc" && "rotate-180"
|
|
140
|
+
),
|
|
141
|
+
"aria-hidden": true
|
|
142
|
+
}
|
|
143
|
+
);
|
|
144
|
+
};
|
|
145
|
+
const headerCell = (col) => /* @__PURE__ */ jsx(
|
|
146
|
+
"th",
|
|
147
|
+
{
|
|
148
|
+
className: cn(
|
|
149
|
+
"px-3 py-2.5 text-left text-xs font-semibold text-tollerud-text-muted uppercase tracking-wider",
|
|
150
|
+
col.sortable && "cursor-pointer select-none hover:text-tollerud-text-primary transition-colors",
|
|
151
|
+
col.align === "right" && "text-right",
|
|
152
|
+
col.align === "center" && "text-center"
|
|
153
|
+
),
|
|
154
|
+
style: col.width ? { width: col.width } : void 0,
|
|
155
|
+
onClick: () => col.sortable && toggleSort(col.key),
|
|
156
|
+
children: /* @__PURE__ */ jsxs(
|
|
157
|
+
"span",
|
|
158
|
+
{
|
|
159
|
+
className: cn(
|
|
160
|
+
"inline-flex items-center gap-1",
|
|
161
|
+
col.align === "right" && "justify-end w-full",
|
|
162
|
+
col.align === "center" && "justify-center w-full"
|
|
163
|
+
),
|
|
164
|
+
children: [
|
|
165
|
+
col.label,
|
|
166
|
+
col.sortable && (isRich ? sortIndicator(col.key) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
167
|
+
sortKey === col.key && /* @__PURE__ */ jsx("span", { className: "text-tollerud-accent", children: sortDir === "asc" ? "\u2191" : "\u2193" }),
|
|
168
|
+
sortKey !== col.key && /* @__PURE__ */ jsx("span", { className: "text-tollerud-text-muted/30", children: "\u2195" })
|
|
169
|
+
] })),
|
|
170
|
+
!isRich && col.filterable && /* @__PURE__ */ jsx(
|
|
171
|
+
"svg",
|
|
172
|
+
{
|
|
173
|
+
width: "12",
|
|
174
|
+
height: "12",
|
|
175
|
+
viewBox: "0 0 24 24",
|
|
176
|
+
fill: "none",
|
|
177
|
+
stroke: "currentColor",
|
|
178
|
+
strokeWidth: "2",
|
|
179
|
+
strokeLinecap: "round",
|
|
180
|
+
strokeLinejoin: "round",
|
|
181
|
+
className: cn("opacity-40", filters[col.key] && "opacity-100 text-tollerud-yellow"),
|
|
182
|
+
"aria-hidden": true,
|
|
183
|
+
children: /* @__PURE__ */ jsx("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" })
|
|
184
|
+
}
|
|
185
|
+
)
|
|
186
|
+
]
|
|
187
|
+
}
|
|
188
|
+
)
|
|
189
|
+
},
|
|
190
|
+
col.key
|
|
191
|
+
);
|
|
192
|
+
const tableBody = () => {
|
|
193
|
+
if (loading) {
|
|
194
|
+
return /* @__PURE__ */ jsx("tbody", { children: Array.from({ length: skeletonRows }).map((_, i) => /* @__PURE__ */ jsxs("tr", { className: "border-b border-tollerud-border/20", children: [
|
|
195
|
+
selectable && /* @__PURE__ */ jsx("td", { className: "px-3 py-2.5 w-10", children: /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-4 rounded" }) }),
|
|
196
|
+
columns.map((col, j) => /* @__PURE__ */ jsx("td", { className: cn("px-3 py-2.5", col.align === "right" && "text-right"), children: /* @__PURE__ */ jsx(Skeleton, { className: cn("h-3", j === 0 ? "w-[70%]" : "w-[55%]") }) }, col.key)),
|
|
197
|
+
rowMenu && /* @__PURE__ */ jsx("td", { className: "px-3 py-2.5 w-11", children: /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-4 rounded" }) })
|
|
198
|
+
] }, i)) });
|
|
199
|
+
}
|
|
200
|
+
if (sorted.length === 0) {
|
|
201
|
+
if (isRich && emptyState) {
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
return /* @__PURE__ */ jsx("tbody", { children: /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan, className: "px-3 py-8 text-center text-sm text-tollerud-text-muted", children: hasActiveFilters || query || filterValue !== "all" ? "No matching rows" : emptyMessage }) }) });
|
|
205
|
+
}
|
|
206
|
+
return /* @__PURE__ */ jsxs("tbody", { children: [
|
|
207
|
+
pageRows.map((row, i) => {
|
|
208
|
+
const id = getRowKey(row, i);
|
|
209
|
+
const isSelected = selected.includes(id);
|
|
210
|
+
return /* @__PURE__ */ jsxs(
|
|
211
|
+
"tr",
|
|
212
|
+
{
|
|
213
|
+
className: cn(
|
|
214
|
+
"border-b border-tollerud-border/20 transition-colors",
|
|
215
|
+
onRowClick && "cursor-pointer hover:bg-tollerud-surface-raised/50",
|
|
216
|
+
isSelected && "bg-tollerud-yellow/[0.05]"
|
|
217
|
+
),
|
|
218
|
+
onClick: () => onRowClick?.(row),
|
|
219
|
+
children: [
|
|
220
|
+
selectable && /* @__PURE__ */ jsx("td", { className: "px-3 py-2.5 w-10", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx(Checkbox, { checked: isSelected, onChange: () => toggleRow(id), "aria-label": `Select row ${id}` }) }),
|
|
221
|
+
columns.map((col) => {
|
|
222
|
+
const value = row[col.key];
|
|
223
|
+
return /* @__PURE__ */ jsx(
|
|
224
|
+
"td",
|
|
225
|
+
{
|
|
226
|
+
className: cn(
|
|
227
|
+
"px-3 py-2.5 text-tollerud-text-secondary",
|
|
228
|
+
col.align === "right" && "text-right",
|
|
229
|
+
col.align === "center" && "text-center",
|
|
230
|
+
!col.render && "font-mono text-xs"
|
|
231
|
+
),
|
|
232
|
+
children: col.render ? col.render(value, row) : String(value ?? "\u2014")
|
|
233
|
+
},
|
|
234
|
+
col.key
|
|
235
|
+
);
|
|
236
|
+
}),
|
|
237
|
+
rowMenu && /* @__PURE__ */ jsx("td", { className: "px-2 py-2 w-11", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
238
|
+
/* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
239
|
+
"button",
|
|
240
|
+
{
|
|
241
|
+
type: "button",
|
|
242
|
+
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",
|
|
243
|
+
"aria-label": "Row actions",
|
|
244
|
+
children: /* @__PURE__ */ jsx(MoreHorizontal, { size: 15 })
|
|
245
|
+
}
|
|
246
|
+
) }),
|
|
247
|
+
/* @__PURE__ */ jsx(DropdownMenuContent, { align: "end", children: rowMenu(row).map((item, index) => {
|
|
248
|
+
if (item.sep) return /* @__PURE__ */ jsx(DropdownMenuSeparator, {}, index);
|
|
249
|
+
if (item.heading) return /* @__PURE__ */ jsx(DropdownMenuLabel, { children: item.label }, index);
|
|
250
|
+
return /* @__PURE__ */ jsxs(DropdownMenuItem, { onSelect: () => item.onSelect?.(), children: [
|
|
251
|
+
item.icon ? /* @__PURE__ */ jsx("span", { className: "mr-2 inline-flex", children: item.icon }) : null,
|
|
252
|
+
item.label
|
|
253
|
+
] }, index);
|
|
254
|
+
}) })
|
|
255
|
+
] }) })
|
|
256
|
+
]
|
|
257
|
+
},
|
|
258
|
+
id
|
|
259
|
+
);
|
|
260
|
+
}),
|
|
261
|
+
isRich && pageSize && pageRows.length < pageSize && Array.from({ length: pageSize - pageRows.length }).map((_, i) => /* @__PURE__ */ jsx("tr", { "aria-hidden": true, className: "h-[49px]", children: /* @__PURE__ */ jsx("td", { colSpan }) }, `spacer-${i}`))
|
|
262
|
+
] });
|
|
263
|
+
};
|
|
264
|
+
const table = /* @__PURE__ */ jsxs("table", { className: "w-full min-w-[640px] text-sm", children: [
|
|
265
|
+
/* @__PURE__ */ jsxs("thead", { children: [
|
|
266
|
+
/* @__PURE__ */ jsxs("tr", { className: "border-b border-tollerud-border/30 bg-tollerud-noir-900", children: [
|
|
267
|
+
selectable && /* @__PURE__ */ jsx("th", { className: "px-3 py-2.5 w-10", children: /* @__PURE__ */ jsx(
|
|
268
|
+
Checkbox,
|
|
269
|
+
{
|
|
270
|
+
checked: allOnPageSelected,
|
|
271
|
+
onChange: toggleAllOnPage,
|
|
272
|
+
"aria-label": "Select all rows on page"
|
|
273
|
+
}
|
|
274
|
+
) }),
|
|
275
|
+
columns.map((col) => headerCell(col)),
|
|
276
|
+
rowMenu && /* @__PURE__ */ jsx("th", { className: "w-11" })
|
|
277
|
+
] }),
|
|
278
|
+
!isRich && filterableColumns.length > 0 && /* @__PURE__ */ jsx("tr", { className: "border-b border-tollerud-border/20", children: columns.map((col) => /* @__PURE__ */ jsx(
|
|
279
|
+
"th",
|
|
280
|
+
{
|
|
281
|
+
className: cn("px-1.5 py-1", col.align === "right" && "text-right", col.align === "center" && "text-center"),
|
|
282
|
+
children: col.filterable ? /* @__PURE__ */ jsx(
|
|
283
|
+
"input",
|
|
284
|
+
{
|
|
285
|
+
type: "text",
|
|
286
|
+
placeholder: `Filter ${col.label.toLowerCase()}\u2026`,
|
|
287
|
+
value: filters[col.key] ?? "",
|
|
288
|
+
onChange: (e) => updateFilter(col.key, e.target.value),
|
|
289
|
+
className: cn(
|
|
290
|
+
"w-full px-2 py-1 text-xs rounded border transition-colors outline-none",
|
|
291
|
+
"bg-tollerud-noir-900/50 border-tollerud-border/20 text-tollerud-text-primary placeholder:text-tollerud-text-muted/40",
|
|
292
|
+
"focus:border-tollerud-yellow/40 focus:ring-1 focus:ring-tollerud-yellow/20"
|
|
293
|
+
)
|
|
294
|
+
}
|
|
295
|
+
) : null
|
|
296
|
+
},
|
|
297
|
+
`filter-${col.key}`
|
|
298
|
+
)) })
|
|
299
|
+
] }),
|
|
300
|
+
tableBody()
|
|
301
|
+
] });
|
|
302
|
+
if (!isRich) {
|
|
303
|
+
return /* @__PURE__ */ jsx("div", { ref: forwardedRef, className: cn("overflow-x-auto rounded-lg border border-tollerud-border/30", className), children: table });
|
|
304
|
+
}
|
|
305
|
+
const showEmpty = !loading && sorted.length === 0;
|
|
306
|
+
return /* @__PURE__ */ jsxs(
|
|
307
|
+
"div",
|
|
308
|
+
{
|
|
309
|
+
ref: forwardedRef,
|
|
310
|
+
className: cn(
|
|
311
|
+
"overflow-hidden rounded-lg border border-tollerud-border/30 bg-tollerud-noir-900",
|
|
312
|
+
className
|
|
313
|
+
),
|
|
314
|
+
children: [
|
|
315
|
+
(searchable || filter || toolbarRight) && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 border-b border-tollerud-border/30 px-4 py-3.5", children: [
|
|
316
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2.5", children: [
|
|
317
|
+
searchable && /* @__PURE__ */ jsxs("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", children: [
|
|
318
|
+
/* @__PURE__ */ jsx(Search, { size: 15, className: "shrink-0 text-tollerud-text-muted", "aria-hidden": true }),
|
|
319
|
+
/* @__PURE__ */ jsx(
|
|
320
|
+
"input",
|
|
321
|
+
{
|
|
322
|
+
value: query,
|
|
323
|
+
onChange: (e) => {
|
|
324
|
+
setQuery(e.target.value);
|
|
325
|
+
setPage(1);
|
|
326
|
+
},
|
|
327
|
+
placeholder: searchPlaceholder,
|
|
328
|
+
className: "min-w-0 flex-1 border-none bg-transparent text-sm text-tollerud-text-primary outline-none placeholder:text-tollerud-text-muted"
|
|
329
|
+
}
|
|
330
|
+
),
|
|
331
|
+
query && /* @__PURE__ */ jsx(
|
|
332
|
+
"button",
|
|
333
|
+
{
|
|
334
|
+
type: "button",
|
|
335
|
+
onClick: () => setQuery(""),
|
|
336
|
+
className: "text-tollerud-text-muted hover:text-tollerud-text-primary",
|
|
337
|
+
"aria-label": "Clear search",
|
|
338
|
+
children: /* @__PURE__ */ jsx(X, { size: 13 })
|
|
339
|
+
}
|
|
340
|
+
)
|
|
341
|
+
] }),
|
|
342
|
+
filter && /* @__PURE__ */ jsx(
|
|
343
|
+
Segmented,
|
|
344
|
+
{
|
|
345
|
+
size: "sm",
|
|
346
|
+
value: filterValue,
|
|
347
|
+
onChange: (value) => {
|
|
348
|
+
setFilterValue(value);
|
|
349
|
+
setPage(1);
|
|
350
|
+
},
|
|
351
|
+
options: [
|
|
352
|
+
{ value: "all", label: filter.allLabel ?? "All" },
|
|
353
|
+
...filterOptions.map((opt) => ({ value: opt, label: opt }))
|
|
354
|
+
]
|
|
355
|
+
}
|
|
356
|
+
)
|
|
357
|
+
] }),
|
|
358
|
+
toolbarRight
|
|
359
|
+
] }),
|
|
360
|
+
selectable && selected.length > 0 && /* @__PURE__ */ jsxs("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", children: [
|
|
361
|
+
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2 text-sm text-tollerud-text-primary", children: [
|
|
362
|
+
/* @__PURE__ */ jsx(Badge, { variant: "accent", children: selected.length }),
|
|
363
|
+
"selected"
|
|
364
|
+
] }),
|
|
365
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-2", children: bulkActions.map((action, index) => /* @__PURE__ */ jsxs(
|
|
366
|
+
Button,
|
|
367
|
+
{
|
|
368
|
+
variant: action.variant ?? "ghost",
|
|
369
|
+
size: "sm",
|
|
370
|
+
onClick: () => action.onRun(selected, clearSelection),
|
|
371
|
+
children: [
|
|
372
|
+
action.icon,
|
|
373
|
+
action.label
|
|
374
|
+
]
|
|
375
|
+
},
|
|
376
|
+
index
|
|
377
|
+
)) })
|
|
378
|
+
] }),
|
|
379
|
+
showEmpty ? /* @__PURE__ */ jsx("div", { className: "p-2", children: emptyState ?? /* @__PURE__ */ jsx("div", { className: "py-12 text-center text-sm text-tollerud-text-muted", children: "No results." }) }) : /* @__PURE__ */ jsx("div", { className: "overflow-x-auto", children: table }),
|
|
380
|
+
!loading && sorted.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 border-t border-tollerud-border/30 px-4 py-3", children: [
|
|
381
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-tollerud-text-muted", children: pageSize ? `Showing ${(currentPage - 1) * pageSize + 1}\u2013${(currentPage - 1) * pageSize + pageRows.length} of ${sorted.length}` : `${sorted.length} row${sorted.length === 1 ? "" : "s"}` }),
|
|
382
|
+
pageSize && pageCount > 1 && /* @__PURE__ */ jsx(Pagination, { page: currentPage, pageCount, onChange: setPage, siblingCount: 1 })
|
|
383
|
+
] })
|
|
384
|
+
]
|
|
385
|
+
}
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
var DataTable = forwardRef((props, ref) => /* @__PURE__ */ jsx(DataTableInner, { ...props, forwardedRef: ref }));
|
|
389
|
+
DataTable.displayName = "DataTable";
|
|
390
|
+
|
|
391
|
+
export { DataTable };
|
|
392
|
+
//# sourceMappingURL=chunk-YPP7QHYT.js.map
|
|
393
|
+
//# sourceMappingURL=chunk-YPP7QHYT.js.map
|
|
@@ -0,0 +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"]}
|