@timbal-ai/timbal-react 1.5.0 → 1.6.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/CHANGELOG.md +17 -1
- package/README.md +25 -0
- package/dist/app.cjs +855 -640
- package/dist/app.d.cts +4 -4
- package/dist/app.d.ts +4 -4
- package/dist/app.esm.js +6 -6
- package/dist/{chart-artifact-2OTDTRwM.d.ts → chart-artifact-C2pZQsaP.d.ts} +81 -29
- package/dist/{chart-artifact-CS3qyGIY.d.cts → chart-artifact-VAqgH-My.d.cts} +81 -29
- package/dist/{chat-ClmzWzCX.d.cts → chat-DDsp-Vzz.d.cts} +1 -1
- package/dist/{chat-ClmzWzCX.d.ts → chat-DDsp-Vzz.d.ts} +1 -1
- package/dist/chat.cjs +26 -26
- package/dist/chat.d.cts +3 -3
- package/dist/chat.d.ts +3 -3
- package/dist/chat.esm.js +3 -3
- package/dist/{chunk-TZI3ID3C.esm.js → chunk-24B4I4XC.esm.js} +3 -3
- package/dist/{chunk-SZDYIRMB.esm.js → chunk-6SQMTBPL.esm.js} +618 -530
- package/dist/{chunk-QIABF4KB.esm.js → chunk-ELEY66OH.esm.js} +2 -2
- package/dist/{chunk-WMKPT5BV.esm.js → chunk-HSL36SJ4.esm.js} +6 -6
- package/dist/chunk-JJOO4PR5.esm.js +391 -0
- package/dist/{chunk-AZL2WANO.esm.js → chunk-MBS7XHV2.esm.js} +28 -28
- package/dist/{chunk-5ECRZ5O7.esm.js → chunk-NO5AWNWT.esm.js} +224 -57
- package/dist/{chunk-ZNYAETFD.esm.js → chunk-R4RQT2XQ.esm.js} +2 -2
- package/dist/{chunk-JYDJRGDE.esm.js → chunk-TMP7RIA7.esm.js} +2 -2
- package/dist/{chunk-IGHBLJV3.esm.js → chunk-WQIQW7EM.esm.js} +3 -2
- package/dist/{chunk-B4XAC4G7.esm.js → chunk-YYEI6XME.esm.js} +361 -527
- package/dist/{circular-progress-CDsJwIPF.d.cts → circular-progress-B9nnwzCu.d.cts} +1 -1
- package/dist/{circular-progress-CDsJwIPF.d.ts → circular-progress-B9nnwzCu.d.ts} +1 -1
- package/dist/index.cjs +1327 -852
- package/dist/index.d.cts +9 -8
- package/dist/index.d.ts +9 -8
- package/dist/index.esm.js +40 -20
- package/dist/{kanban-U5xNe9py.d.cts → kanban-FFBeaZPS.d.cts} +4 -4
- package/dist/{kanban-U5xNe9py.d.ts → kanban-FFBeaZPS.d.ts} +4 -4
- package/dist/{layout-B8r6Jbat.d.ts → layout-CuKeSY74.d.ts} +1 -1
- package/dist/{layout-Cu7Ijn04.d.cts → layout-PzVwkJyL.d.cts} +1 -1
- package/dist/site.cjs +71 -0
- package/dist/site.d.cts +15 -1
- package/dist/site.d.ts +15 -1
- package/dist/site.esm.js +12 -311
- package/dist/studio.cjs +31 -31
- package/dist/studio.d.cts +2 -2
- package/dist/studio.d.ts +2 -2
- package/dist/studio.esm.js +7 -7
- package/dist/{timbal-v2-button-B7vPs7gg.d.ts → timbal-v2-button-DCAZNyUx.d.cts} +1 -1
- package/dist/{timbal-v2-button-B7vPs7gg.d.cts → timbal-v2-button-DCAZNyUx.d.ts} +1 -1
- package/dist/ui.cjs +77 -77
- package/dist/ui.d.cts +3 -3
- package/dist/ui.d.ts +3 -3
- package/dist/ui.esm.js +15 -15
- package/dist/{welcome-NXZlcihe.d.cts → welcome-B00oH5Io.d.cts} +1 -1
- package/dist/{welcome-DduQAC4K.d.ts → welcome-DU-4NTjZ.d.ts} +1 -1
- package/package.json +1 -1
package/dist/app.cjs
CHANGED
|
@@ -419,7 +419,7 @@ Presentational groups \u2014 import from the package root, not from these paths:
|
|
|
419
419
|
|
|
420
420
|
| Folder | Components |
|
|
421
421
|
|--------|------------|
|
|
422
|
-
| \`data/\` | \`MetricRow\`, \`MetricChartCard\`, \`MetricTile\`, \`DataTable\`, \`FilterBar\`, \`FilterField\`, \`ChartPanel\` |
|
|
422
|
+
| \`data/\` | \`MetricRow\`, \`MetricChartCard\`, \`MetricTile\`, \`DataTable\`, \`FilterBar\`, \`FilterField\`, \`FilterDropdown\`, \`ChartPanel\` |
|
|
423
423
|
| \`integrations/\` | \`IntegrationCard\`, \`ConnectionRow\`, \`ConnectionRowList\`, \`IntegrationsEmptyState\`, \`PlanBadge\` |
|
|
424
424
|
| \`settings/\` | \`SettingsSection\`, \`FieldRow\`, \`DangerZone\`, \`FloatingUnsavedChangesBar\` |
|
|
425
425
|
| \`surfaces/\` | \`StatTile\`, \`InfoCard\`, \`AlertCard\`, \`CatalogCard\`, \`ResourceCard\`, \`DescriptionList\`, \`ExpandableSection\`, \`StatusDot\`, \`StatusBadge\`, \`EmptyState\` |
|
|
@@ -488,6 +488,7 @@ The cause of slop is dropping **below** the curated block layer into raw primiti
|
|
|
488
488
|
| \`StatusBadge\` | Status pill: \`tone\` (\`default\`\\|\`primary\`\\|\`success\`\\|\`warn\`\\|\`danger\`\\|\`muted\`), children. Use \`danger\` for critical/error severity. |
|
|
489
489
|
| \`FilterBar\` | Horizontal filter row \u2014 bottom-aligns controls. Mix \`SearchInput\` with labeled \`FilterField\` + \`Select\` (or \`Field\` + \`Select\`); labels sit above, control baselines match. |
|
|
490
490
|
| \`FilterField\` | Optional label wrapper for a filter control inside \`FilterBar\` (severity, status, \u2026). Omit \`label\` for search-only fields. |
|
|
491
|
+
| \`FilterDropdown\` | Single-button **multi-facet** filter popover for dense list/table views \u2014 **data-driven**: pass \`fields\` describing your **actual columns** (each \`{ id, label, type }\` where \`type\` is \`multiselect\` \\| \`text\` \\| \`daterange\` \\| \`numeric\`; \`multiselect\` takes \`options: [{ value, label, hint?, icon? }]\`). State is keyed by field \`id\` \u2014 controlled (\`value\` + \`onChange\`) or uncontrolled (\`defaultValue\`). Renders **removable active-filter pills** next to the trigger by default (\`showActiveChips\`); wire \`onChange\` to actually filter your rows. **Always derive \`fields\` from the table's columns/data; never ship the default example facets.** Use when one \`FilterBar\` row isn't enough. |
|
|
491
492
|
| \`SearchInput\` | Filter field with consistent app styling. |
|
|
492
493
|
| \`DataTable\` | Sortable table: \`columns\`, \`rows\`, \`getRowKey\`, optional \`sort\` / \`onSortChange\`, \`emptyTitle\`, \`showRowCount\`, \`caption\`, \`truncate: true\` on columns with long text. **Scales:** \`pageSize\` (built-in client pager), \`selectable\` + \`onSelectionChange\` (checkbox column for bulk actions), \`loading\` (skeleton rows). \`onRowClick\` for row \u2192 detail (open a \`Sheet\`). |
|
|
493
494
|
| \`Avatar\` / \`AvatarFallback\` | User initials: \`variant="secondary"\` (or \`primary\` / \`chart\` alias) on **both** \`Avatar\` and \`AvatarFallback\` \u2014 same chrome as catalog **Action** buttons (\`Button variant="secondary"\`: elevated gradient, \`border-border\`, \`shadow-card\`, \`text-foreground\`). Never dark primary CTA fill or raw \`bg-blue-600\`. |
|
|
@@ -546,6 +547,21 @@ Charts run on **recharts** with shadcn \`ChartContainer\` / \`ChartTooltipConten
|
|
|
546
547
|
| \`Banner\` | Page-level announcement bar: \`tone\` (\`default\`\\|\`primary\`\\|\`success\`\\|\`warn\`\\|\`danger\`), \`icon\`, \`title\`, body as children, right-aligned \`actions\`, \`onDismiss\` (renders the dismiss X). For in-form/field messages use \`InfoCard\` or \`Alert\` instead. |
|
|
547
548
|
| \`Timeline\` | Vertical event log: \`items: [{ id, title, description?, meta?, tone?, icon? }]\`. Presentational \u2014 pass already-formatted timestamps in \`meta\`. |
|
|
548
549
|
|
|
550
|
+
#### More \`/ui\` primitives (import from \`/ui\` or the package root)
|
|
551
|
+
|
|
552
|
+
These ship in the same design system but aren't re-exported from \`/app\`. Reach for them before hand-rolling \u2014 they're all dependency-free and on the shared tokens / control surface.
|
|
553
|
+
|
|
554
|
+
| Component | Use for |
|
|
555
|
+
|-----------|---------|
|
|
556
|
+
| \`Stepper\` | Ordered step indicator for wizards / onboarding (horizontal or vertical; complete / active / upcoming states). |
|
|
557
|
+
| \`Rating\` | Star rating \u2014 interactive (keyboard + hover preview) or \`readOnly\`; controlled or uncontrolled. |
|
|
558
|
+
| \`NumberField\` | Numeric input with \u2212/+ steppers on the control surface; clamps to \`min\`/\`max\`, steps by \`step\`. |
|
|
559
|
+
| \`TagInput\` | Chips / token input; commits on Enter/comma, removes on Backspace, optional \`dedupe\`/\`max\`. |
|
|
560
|
+
| \`AvatarGroup\` | Overlapping avatar stack with an optional \`+N\` overflow chip (\`max\`, \`spacing\`). |
|
|
561
|
+
| \`CircularProgress\` | Lightweight SVG progress ring \u2014 determinate (optional center label) or indeterminate. |
|
|
562
|
+
| \`CopyButton\` | Click-to-copy with a transient check confirmation; icon-only or with a label. |
|
|
563
|
+
| \`Snippet\` | Single-line code / command on the elevated surface with a built-in copy button. |
|
|
564
|
+
|
|
549
565
|
Studio chrome (\`StudioSidebar\`, \`ModeToggle\`, \u2026) lives in \`@timbal-ai/timbal-react/studio\` \u2014 optional, not required for every dashboard.
|
|
550
566
|
|
|
551
567
|
### Block recipes \u2014 compose these (don't clone wholesale)
|
|
@@ -612,6 +628,7 @@ import {
|
|
|
612
628
|
DataTable,
|
|
613
629
|
FilterBar,
|
|
614
630
|
FilterField,
|
|
631
|
+
FilterDropdown,
|
|
615
632
|
AlertCard,
|
|
616
633
|
CatalogCard,
|
|
617
634
|
} from "@timbal-ai/timbal-react/app";
|
|
@@ -1357,8 +1374,8 @@ var SIDEBAR_WIDTH_COLLAPSED_PX = 52;
|
|
|
1357
1374
|
var SIDEBAR_GAP_PX = 12;
|
|
1358
1375
|
var SIDEBAR_CONTENT_GAP_PX = 8;
|
|
1359
1376
|
var TOPBAR_GAP_PX = 8;
|
|
1360
|
-
var TOPBAR_HEIGHT_PX =
|
|
1361
|
-
var PILL_HEIGHT_PX =
|
|
1377
|
+
var TOPBAR_HEIGHT_PX = 44;
|
|
1378
|
+
var PILL_HEIGHT_PX = 36;
|
|
1362
1379
|
var SIDEBAR_INSET_PX_EXPANDED = SIDEBAR_GAP_PX + SIDEBAR_WIDTH_PX + SIDEBAR_CONTENT_GAP_PX;
|
|
1363
1380
|
var SIDEBAR_INSET_PX_COLLAPSED = SIDEBAR_GAP_PX + SIDEBAR_WIDTH_COLLAPSED_PX + SIDEBAR_CONTENT_GAP_PX;
|
|
1364
1381
|
var px = (n) => `${n / 16}rem`;
|
|
@@ -1728,16 +1745,16 @@ var buttonVariants = (0, import_class_variance_authority.cva)(
|
|
|
1728
1745
|
)
|
|
1729
1746
|
},
|
|
1730
1747
|
size: {
|
|
1731
|
-
xs: "h-
|
|
1732
|
-
sm: "h-
|
|
1733
|
-
md: "h-
|
|
1734
|
-
lg: "h-
|
|
1735
|
-
xl: "h-
|
|
1736
|
-
default: "h-
|
|
1737
|
-
icon: "h-
|
|
1738
|
-
"icon-xs": "h-
|
|
1739
|
-
"icon-sm": "h-
|
|
1740
|
-
"icon-lg": "h-
|
|
1748
|
+
xs: "h-7 gap-1 rounded-md px-2 text-xs",
|
|
1749
|
+
sm: "h-8 gap-1 rounded-md px-2.5 text-xs",
|
|
1750
|
+
md: "h-9 gap-1.5 rounded-lg px-3 text-sm",
|
|
1751
|
+
lg: "h-10 gap-1.5 rounded-lg px-3.5 text-sm",
|
|
1752
|
+
xl: "h-11 gap-2 rounded-lg px-4 text-base",
|
|
1753
|
+
default: "h-9 gap-1.5 rounded-lg px-3 text-sm",
|
|
1754
|
+
icon: "h-9 w-9 rounded-lg",
|
|
1755
|
+
"icon-xs": "h-7 w-7 rounded-md",
|
|
1756
|
+
"icon-sm": "h-8 w-8 rounded-md",
|
|
1757
|
+
"icon-lg": "h-10 w-10 rounded-lg"
|
|
1741
1758
|
},
|
|
1742
1759
|
shape: {
|
|
1743
1760
|
pill: "rounded-full!",
|
|
@@ -1831,22 +1848,22 @@ var TIMBAL_V2_MODAL_SURFACE = cn(
|
|
|
1831
1848
|
);
|
|
1832
1849
|
var TIMBAL_V2_PRIMARY_GRADIENT = "bg-gradient-to-b from-primary-fill-from to-primary-fill-to";
|
|
1833
1850
|
var TIMBAL_V2_SIZE_HEIGHT = {
|
|
1834
|
-
xs: "min-h-
|
|
1835
|
-
sm: "min-h-
|
|
1836
|
-
md: "min-h-
|
|
1837
|
-
lg: "min-h-
|
|
1851
|
+
xs: "min-h-7 h-7",
|
|
1852
|
+
sm: "min-h-8 h-8",
|
|
1853
|
+
md: "min-h-9 h-9",
|
|
1854
|
+
lg: "min-h-10 h-10"
|
|
1838
1855
|
};
|
|
1839
1856
|
var TIMBAL_V2_SIZE_ICON = {
|
|
1840
|
-
xs: "min-h-
|
|
1857
|
+
xs: "min-h-7 min-w-7 size-7",
|
|
1841
1858
|
sm: "min-h-8 min-w-8 size-8",
|
|
1842
|
-
md: "min-h-
|
|
1843
|
-
lg: "min-h-
|
|
1859
|
+
md: "min-h-9 min-w-9 size-9",
|
|
1860
|
+
lg: "min-h-10 min-w-10 size-10"
|
|
1844
1861
|
};
|
|
1845
1862
|
var TIMBAL_V2_SIZE_LABEL_PX = {
|
|
1846
|
-
xs: "px-
|
|
1847
|
-
sm: "px-
|
|
1848
|
-
md: "px-5",
|
|
1849
|
-
lg: "px-
|
|
1863
|
+
xs: "px-2.5",
|
|
1864
|
+
sm: "px-3",
|
|
1865
|
+
md: "px-3.5",
|
|
1866
|
+
lg: "px-4.5"
|
|
1850
1867
|
};
|
|
1851
1868
|
var TIMBAL_V2_FILL = {
|
|
1852
1869
|
primary: [
|
|
@@ -2071,8 +2088,8 @@ var import_react = require("react");
|
|
|
2071
2088
|
|
|
2072
2089
|
// src/design/control-surface.ts
|
|
2073
2090
|
var CONTROL_SIZE = {
|
|
2074
|
-
sm: "h-
|
|
2075
|
-
default: "h-
|
|
2091
|
+
sm: "h-8 px-2.5",
|
|
2092
|
+
default: "h-9 px-3"
|
|
2076
2093
|
};
|
|
2077
2094
|
var CONTROL_SHAPE = {
|
|
2078
2095
|
field: "rounded-lg",
|
|
@@ -2100,6 +2117,7 @@ var overlayListPanelClass = cn(
|
|
|
2100
2117
|
overlaySurfaceClass,
|
|
2101
2118
|
"overflow-hidden rounded-lg p-0 outline-hidden"
|
|
2102
2119
|
);
|
|
2120
|
+
var overlayItemClass = "relative flex cursor-default items-center gap-2 rounded-md px-2 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground";
|
|
2103
2121
|
|
|
2104
2122
|
// src/design/app-classes.ts
|
|
2105
2123
|
var appPageColumnClass = "mx-auto w-full max-w-[100rem] px-4 md:px-6 lg:px-8";
|
|
@@ -2394,30 +2412,36 @@ var Sparkline = ({
|
|
|
2394
2412
|
height = 28,
|
|
2395
2413
|
strokeWidth = 1.5,
|
|
2396
2414
|
className,
|
|
2397
|
-
ariaLabel = "Trend"
|
|
2415
|
+
ariaLabel = "Trend",
|
|
2416
|
+
interactive = false,
|
|
2417
|
+
labels,
|
|
2418
|
+
formatValue
|
|
2398
2419
|
}) => {
|
|
2399
2420
|
const uid = (0, import_react2.useId)();
|
|
2421
|
+
const containerRef = (0, import_react2.useRef)(null);
|
|
2422
|
+
const [activeIndex, setActiveIndex] = (0, import_react2.useState)(null);
|
|
2400
2423
|
const values = data.map((d) => typeof d === "number" ? d : toNum(d[dataKey]));
|
|
2401
2424
|
if (values.length === 0) {
|
|
2402
2425
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: cn("inline-block", className), style: { width, height } });
|
|
2403
2426
|
}
|
|
2404
|
-
const
|
|
2427
|
+
const padX = 0;
|
|
2428
|
+
const padY = strokeWidth + 1;
|
|
2405
2429
|
const min = Math.min(...values);
|
|
2406
2430
|
const max = Math.max(...values);
|
|
2407
2431
|
const range = max - min || 1;
|
|
2408
|
-
const innerW = width -
|
|
2409
|
-
const innerH = height -
|
|
2432
|
+
const innerW = width - padX * 2;
|
|
2433
|
+
const innerH = height - padY * 2;
|
|
2410
2434
|
const points = values.map((v, i) => ({
|
|
2411
|
-
x:
|
|
2412
|
-
y:
|
|
2435
|
+
x: padX + (values.length > 1 ? i / (values.length - 1) * innerW : innerW / 2),
|
|
2436
|
+
y: padY + innerH - (v - min) / range * innerH
|
|
2413
2437
|
}));
|
|
2414
|
-
|
|
2438
|
+
const svg = /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
2415
2439
|
"svg",
|
|
2416
2440
|
{
|
|
2417
2441
|
width,
|
|
2418
2442
|
height,
|
|
2419
2443
|
viewBox: `0 0 ${width} ${height}`,
|
|
2420
|
-
className: cn("block", className),
|
|
2444
|
+
className: cn("block", interactive ? "h-full w-full" : className),
|
|
2421
2445
|
role: "img",
|
|
2422
2446
|
"aria-label": ariaLabel,
|
|
2423
2447
|
preserveAspectRatio: "none",
|
|
@@ -2427,7 +2451,7 @@ var Sparkline = ({
|
|
|
2427
2451
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("stop", { offset: "0%", style: { stopColor: color, stopOpacity: 0.25 } }),
|
|
2428
2452
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("stop", { offset: "100%", style: { stopColor: color, stopOpacity: 0 } })
|
|
2429
2453
|
] }) }),
|
|
2430
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: monotoneAreaPath(points, height -
|
|
2454
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: monotoneAreaPath(points, height - padY), fill: `url(#${uid}-spark)` })
|
|
2431
2455
|
] }),
|
|
2432
2456
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2433
2457
|
"path",
|
|
@@ -2439,7 +2463,81 @@ var Sparkline = ({
|
|
|
2439
2463
|
strokeLinecap: "round",
|
|
2440
2464
|
strokeLinejoin: "round"
|
|
2441
2465
|
}
|
|
2442
|
-
)
|
|
2466
|
+
),
|
|
2467
|
+
interactive && activeIndex != null && points[activeIndex] ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
2468
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2469
|
+
"line",
|
|
2470
|
+
{
|
|
2471
|
+
x1: points[activeIndex].x,
|
|
2472
|
+
x2: points[activeIndex].x,
|
|
2473
|
+
y1: 0,
|
|
2474
|
+
y2: height,
|
|
2475
|
+
stroke: color,
|
|
2476
|
+
strokeWidth: 1,
|
|
2477
|
+
strokeOpacity: 0.3,
|
|
2478
|
+
vectorEffect: "non-scaling-stroke"
|
|
2479
|
+
}
|
|
2480
|
+
),
|
|
2481
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2482
|
+
"circle",
|
|
2483
|
+
{
|
|
2484
|
+
cx: points[activeIndex].x,
|
|
2485
|
+
cy: points[activeIndex].y,
|
|
2486
|
+
r: 2.75,
|
|
2487
|
+
fill: color,
|
|
2488
|
+
stroke: "var(--background, #fff)",
|
|
2489
|
+
strokeWidth: 1.5,
|
|
2490
|
+
vectorEffect: "non-scaling-stroke"
|
|
2491
|
+
}
|
|
2492
|
+
)
|
|
2493
|
+
] }) : null
|
|
2494
|
+
]
|
|
2495
|
+
}
|
|
2496
|
+
);
|
|
2497
|
+
if (!interactive) return svg;
|
|
2498
|
+
const onMove = (e) => {
|
|
2499
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
2500
|
+
if (rect.width === 0) return;
|
|
2501
|
+
const fraction = (e.clientX - rect.left) / rect.width;
|
|
2502
|
+
const index = Math.max(
|
|
2503
|
+
0,
|
|
2504
|
+
Math.min(values.length - 1, Math.round(fraction * (values.length - 1)))
|
|
2505
|
+
);
|
|
2506
|
+
setActiveIndex(index);
|
|
2507
|
+
};
|
|
2508
|
+
const active = activeIndex != null ? points[activeIndex] : null;
|
|
2509
|
+
const formattedValue = activeIndex != null ? formatValue ? formatValue(values[activeIndex], activeIndex) : formatCompact(values[activeIndex]) : null;
|
|
2510
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
2511
|
+
"span",
|
|
2512
|
+
{
|
|
2513
|
+
ref: containerRef,
|
|
2514
|
+
className: cn("relative block touch-none", className),
|
|
2515
|
+
style: { width: "100%", height: "100%" },
|
|
2516
|
+
onPointerMove: onMove,
|
|
2517
|
+
onPointerLeave: () => setActiveIndex(null),
|
|
2518
|
+
children: [
|
|
2519
|
+
svg,
|
|
2520
|
+
active ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
2521
|
+
"span",
|
|
2522
|
+
{
|
|
2523
|
+
"aria-hidden": true,
|
|
2524
|
+
className: cn(
|
|
2525
|
+
"pointer-events-none absolute z-30 -translate-x-1/2 -translate-y-full whitespace-nowrap",
|
|
2526
|
+
"rounded-xl border px-3 py-2 text-[11px] font-medium leading-none tabular-nums shadow-[0_12px_40px_-10px_rgba(0,0,0,0.55)]",
|
|
2527
|
+
"border-white/10 bg-gradient-to-b from-neutral-800 to-neutral-950 text-white",
|
|
2528
|
+
"dark:border-black/10 dark:from-white dark:to-neutral-100 dark:text-neutral-900"
|
|
2529
|
+
),
|
|
2530
|
+
style: {
|
|
2531
|
+
left: `${active.x / width * 100}%`,
|
|
2532
|
+
top: `${active.y / height * 100}%`,
|
|
2533
|
+
marginTop: -8
|
|
2534
|
+
},
|
|
2535
|
+
children: [
|
|
2536
|
+
labels?.[activeIndex] != null ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "mr-1.5 text-neutral-300 dark:text-neutral-500", children: labels[activeIndex] }) : null,
|
|
2537
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: formattedValue })
|
|
2538
|
+
]
|
|
2539
|
+
}
|
|
2540
|
+
) : null
|
|
2443
2541
|
]
|
|
2444
2542
|
}
|
|
2445
2543
|
);
|
|
@@ -2457,6 +2555,15 @@ var inlineTrendToneClass = {
|
|
|
2457
2555
|
down: "text-rose-500/90 dark:text-rose-400/95 font-medium",
|
|
2458
2556
|
neutral: "text-muted-foreground/80"
|
|
2459
2557
|
};
|
|
2558
|
+
var sparklineToneColor = {
|
|
2559
|
+
up: "var(--primary, #3b82f6)",
|
|
2560
|
+
down: "var(--destructive, #f43f5e)",
|
|
2561
|
+
neutral: "var(--muted-foreground, #64748b)"
|
|
2562
|
+
};
|
|
2563
|
+
var sparklineBandBleed = {
|
|
2564
|
+
default: "-mx-4 -mb-3 h-10",
|
|
2565
|
+
compact: "-mx-3 -mb-2 h-8"
|
|
2566
|
+
};
|
|
2460
2567
|
var activeToneClass = {
|
|
2461
2568
|
default: "bg-foreground dark:bg-white",
|
|
2462
2569
|
primary: "bg-primary",
|
|
@@ -2486,8 +2593,10 @@ var MetricTile = ({
|
|
|
2486
2593
|
ariaLabel,
|
|
2487
2594
|
className
|
|
2488
2595
|
}) => {
|
|
2596
|
+
const density = useAppDensity();
|
|
2489
2597
|
const metricTileBaseClass = useAppDensityClass("metricTile");
|
|
2490
2598
|
const hasSparkline = Boolean(sparkline || sparklineData);
|
|
2599
|
+
const bandBleed = sparklineBandBleed[density === "compact" ? "compact" : "default"];
|
|
2491
2600
|
const content = /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2492
2601
|
active ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2493
2602
|
"span",
|
|
@@ -2499,17 +2608,6 @@ var MetricTile = ({
|
|
|
2499
2608
|
)
|
|
2500
2609
|
}
|
|
2501
2610
|
) : null,
|
|
2502
|
-
hasSparkline ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "absolute inset-x-0 bottom-0.5 h-9 w-full overflow-hidden pointer-events-none z-0 opacity-45 dark:opacity-35 select-none", children: sparkline ?? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2503
|
-
Sparkline,
|
|
2504
|
-
{
|
|
2505
|
-
data: sparklineData,
|
|
2506
|
-
width: 160,
|
|
2507
|
-
height: 36,
|
|
2508
|
-
className: "w-full h-full",
|
|
2509
|
-
color: trendTone === "up" ? "var(--primary, #3b82f6)" : trendTone === "down" ? "var(--destructive, #f43f5e)" : "var(--muted-foreground, #64748b)",
|
|
2510
|
-
...sparklineConfig
|
|
2511
|
-
}
|
|
2512
|
-
) }) : null,
|
|
2513
2611
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "relative z-10 flex flex-col gap-1 w-full text-left", children: [
|
|
2514
2612
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-xs font-semibold text-muted-foreground/80 tracking-tight", children: label }),
|
|
2515
2613
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "flex items-center gap-2", children: [
|
|
@@ -2528,7 +2626,28 @@ var MetricTile = ({
|
|
|
2528
2626
|
}
|
|
2529
2627
|
) : null
|
|
2530
2628
|
] })
|
|
2531
|
-
] })
|
|
2629
|
+
] }),
|
|
2630
|
+
hasSparkline ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2631
|
+
"div",
|
|
2632
|
+
{
|
|
2633
|
+
className: cn(
|
|
2634
|
+
"relative z-10 mt-2",
|
|
2635
|
+
bandBleed
|
|
2636
|
+
),
|
|
2637
|
+
children: sparkline ?? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2638
|
+
Sparkline,
|
|
2639
|
+
{
|
|
2640
|
+
data: sparklineData,
|
|
2641
|
+
width: 160,
|
|
2642
|
+
height: 40,
|
|
2643
|
+
interactive: true,
|
|
2644
|
+
className: "h-full w-full opacity-90",
|
|
2645
|
+
color: sparklineToneColor[trendTone],
|
|
2646
|
+
...sparklineConfig
|
|
2647
|
+
}
|
|
2648
|
+
)
|
|
2649
|
+
}
|
|
2650
|
+
) : null
|
|
2532
2651
|
] });
|
|
2533
2652
|
const divider = showDivider ? metricCellDividerClass : void 0;
|
|
2534
2653
|
if (onSelect) {
|
|
@@ -3277,7 +3396,7 @@ function DialogContent({
|
|
|
3277
3396
|
"data-slot": "dialog-content",
|
|
3278
3397
|
className: cn(
|
|
3279
3398
|
TIMBAL_V2_MODAL_SURFACE,
|
|
3280
|
-
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-[70] grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-xl p-
|
|
3399
|
+
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-[70] grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-xl p-5 duration-200 outline-none sm:max-w-lg",
|
|
3281
3400
|
className
|
|
3282
3401
|
),
|
|
3283
3402
|
...props,
|
|
@@ -3335,9 +3454,9 @@ function isBrandedVariant(variant) {
|
|
|
3335
3454
|
return variant === "secondary" || variant === "primary" || variant === "chart";
|
|
3336
3455
|
}
|
|
3337
3456
|
var AVATAR_SIZE_CLASS = {
|
|
3338
|
-
default: "size-
|
|
3339
|
-
sm: "size-
|
|
3340
|
-
lg: "size-
|
|
3457
|
+
default: "size-7",
|
|
3458
|
+
sm: "size-5",
|
|
3459
|
+
lg: "size-9"
|
|
3341
3460
|
};
|
|
3342
3461
|
function Avatar({
|
|
3343
3462
|
className,
|
|
@@ -5274,7 +5393,7 @@ var BadgeNode = ({ node }) => {
|
|
|
5274
5393
|
"span",
|
|
5275
5394
|
{
|
|
5276
5395
|
className: cn(
|
|
5277
|
-
"aui-ui-badge inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium",
|
|
5396
|
+
"aui-ui-badge inline-flex w-fit shrink-0 items-center rounded-full px-2 py-0.5 text-xs font-medium",
|
|
5278
5397
|
BADGE_TONE[node.tone ?? "default"],
|
|
5279
5398
|
node.className
|
|
5280
5399
|
),
|
|
@@ -7935,7 +8054,7 @@ var StatusBadge = ({
|
|
|
7935
8054
|
"span",
|
|
7936
8055
|
{
|
|
7937
8056
|
className: cn(
|
|
7938
|
-
"aui-app-status-badge inline-flex items-center gap-1.5 rounded-full px-2 py-0.5",
|
|
8057
|
+
"aui-app-status-badge inline-flex w-fit shrink-0 items-center gap-1.5 rounded-full px-2 py-0.5",
|
|
7939
8058
|
"text-xs font-medium leading-none ring-1 ring-inset",
|
|
7940
8059
|
statusBadgeToneClass[tone],
|
|
7941
8060
|
className
|
|
@@ -8394,7 +8513,7 @@ function CopyButton({
|
|
|
8394
8513
|
"inline-flex items-center justify-center gap-1.5 rounded-md text-sm font-medium text-muted-foreground transition-colors",
|
|
8395
8514
|
"hover:bg-accent hover:text-foreground data-[copied=true]:text-emerald-600 dark:data-[copied=true]:text-emerald-400",
|
|
8396
8515
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15",
|
|
8397
|
-
children ? "h-
|
|
8516
|
+
children ? "h-7 px-1.5" : "size-7",
|
|
8398
8517
|
className
|
|
8399
8518
|
),
|
|
8400
8519
|
...props,
|
|
@@ -8925,10 +9044,10 @@ var pillSegmentedTrackFlushClass = cn(
|
|
|
8925
9044
|
"h-[var(--studio-chrome-pill-height)] items-center gap-0.5 overflow-visible p-0.5"
|
|
8926
9045
|
);
|
|
8927
9046
|
var pillSegmentedSegmentClass = cn(
|
|
8928
|
-
"relative flex items-center gap-1.5 rounded-full px-
|
|
9047
|
+
"relative flex items-center gap-1.5 rounded-full px-3 py-1 text-xs font-normal transition-colors"
|
|
8929
9048
|
);
|
|
8930
9049
|
var pillSegmentedFlushSegmentClass = cn(
|
|
8931
|
-
"relative box-border inline-flex h-
|
|
9050
|
+
"relative box-border inline-flex h-8 min-h-8 items-center justify-center gap-1.5 rounded-full px-3 py-0",
|
|
8932
9051
|
"text-sm font-normal leading-tight transition-colors"
|
|
8933
9052
|
);
|
|
8934
9053
|
var pillSegmentedActiveIndicatorClass = cn(
|
|
@@ -9328,7 +9447,7 @@ var FilterField = ({
|
|
|
9328
9447
|
|
|
9329
9448
|
// src/app/data/FilterDropdown.tsx
|
|
9330
9449
|
var import_react53 = require("react");
|
|
9331
|
-
var
|
|
9450
|
+
var import_lucide_react18 = require("lucide-react");
|
|
9332
9451
|
|
|
9333
9452
|
// src/ui/checkbox.tsx
|
|
9334
9453
|
var import_radix_ui6 = require("radix-ui");
|
|
@@ -9361,18 +9480,142 @@ function Checkbox({
|
|
|
9361
9480
|
);
|
|
9362
9481
|
}
|
|
9363
9482
|
|
|
9364
|
-
// src/ui/
|
|
9483
|
+
// src/ui/select.tsx
|
|
9365
9484
|
var import_radix_ui7 = require("radix-ui");
|
|
9485
|
+
var import_lucide_react17 = require("lucide-react");
|
|
9366
9486
|
var import_jsx_runtime86 = require("react/jsx-runtime");
|
|
9487
|
+
function Select({
|
|
9488
|
+
...props
|
|
9489
|
+
}) {
|
|
9490
|
+
return /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(import_radix_ui7.Select.Root, { "data-slot": "select", ...props });
|
|
9491
|
+
}
|
|
9492
|
+
function SelectValue({
|
|
9493
|
+
...props
|
|
9494
|
+
}) {
|
|
9495
|
+
return /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(import_radix_ui7.Select.Value, { "data-slot": "select-value", ...props });
|
|
9496
|
+
}
|
|
9497
|
+
function SelectTrigger({
|
|
9498
|
+
className,
|
|
9499
|
+
size = "default",
|
|
9500
|
+
children,
|
|
9501
|
+
...props
|
|
9502
|
+
}) {
|
|
9503
|
+
return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
|
|
9504
|
+
import_radix_ui7.Select.Trigger,
|
|
9505
|
+
{
|
|
9506
|
+
"data-slot": "select-trigger",
|
|
9507
|
+
"data-size": size,
|
|
9508
|
+
className: cn(
|
|
9509
|
+
controlClass({ size }),
|
|
9510
|
+
"flex w-fit items-center justify-between gap-2 whitespace-nowrap *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground",
|
|
9511
|
+
className
|
|
9512
|
+
),
|
|
9513
|
+
...props,
|
|
9514
|
+
children: [
|
|
9515
|
+
children,
|
|
9516
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)(import_radix_ui7.Select.Icon, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(import_lucide_react17.ChevronDownIcon, { className: "size-4 opacity-50" }) })
|
|
9517
|
+
]
|
|
9518
|
+
}
|
|
9519
|
+
);
|
|
9520
|
+
}
|
|
9521
|
+
function SelectContent({
|
|
9522
|
+
className,
|
|
9523
|
+
children,
|
|
9524
|
+
position = "popper",
|
|
9525
|
+
...props
|
|
9526
|
+
}) {
|
|
9527
|
+
return /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(import_radix_ui7.Select.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
|
|
9528
|
+
import_radix_ui7.Select.Content,
|
|
9529
|
+
{
|
|
9530
|
+
"data-slot": "select-content",
|
|
9531
|
+
className: cn(
|
|
9532
|
+
overlayListPanelClass,
|
|
9533
|
+
"relative max-h-[var(--radix-select-content-available-height)] min-w-[8rem] origin-[var(--radix-select-content-transform-origin)] overflow-x-hidden overflow-y-auto",
|
|
9534
|
+
position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
|
9535
|
+
className
|
|
9536
|
+
),
|
|
9537
|
+
position,
|
|
9538
|
+
...props,
|
|
9539
|
+
children: [
|
|
9540
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)(SelectScrollUpButton, {}),
|
|
9541
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
|
|
9542
|
+
import_radix_ui7.Select.Viewport,
|
|
9543
|
+
{
|
|
9544
|
+
className: cn(
|
|
9545
|
+
"p-1",
|
|
9546
|
+
position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1"
|
|
9547
|
+
),
|
|
9548
|
+
children
|
|
9549
|
+
}
|
|
9550
|
+
),
|
|
9551
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)(SelectScrollDownButton, {})
|
|
9552
|
+
]
|
|
9553
|
+
}
|
|
9554
|
+
) });
|
|
9555
|
+
}
|
|
9556
|
+
function SelectItem({
|
|
9557
|
+
className,
|
|
9558
|
+
children,
|
|
9559
|
+
...props
|
|
9560
|
+
}) {
|
|
9561
|
+
return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
|
|
9562
|
+
import_radix_ui7.Select.Item,
|
|
9563
|
+
{
|
|
9564
|
+
"data-slot": "select-item",
|
|
9565
|
+
className: cn(
|
|
9566
|
+
overlayItemClass,
|
|
9567
|
+
"w-full py-1 pr-8 pl-2 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
|
|
9568
|
+
className
|
|
9569
|
+
),
|
|
9570
|
+
...props,
|
|
9571
|
+
children: [
|
|
9572
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "absolute right-2 flex size-3.5 items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(import_radix_ui7.Select.ItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(import_lucide_react17.CheckIcon, { className: "size-4" }) }) }),
|
|
9573
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)(import_radix_ui7.Select.ItemText, { children })
|
|
9574
|
+
]
|
|
9575
|
+
}
|
|
9576
|
+
);
|
|
9577
|
+
}
|
|
9578
|
+
function SelectScrollUpButton({
|
|
9579
|
+
className,
|
|
9580
|
+
...props
|
|
9581
|
+
}) {
|
|
9582
|
+
return /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
|
|
9583
|
+
import_radix_ui7.Select.ScrollUpButton,
|
|
9584
|
+
{
|
|
9585
|
+
"data-slot": "select-scroll-up-button",
|
|
9586
|
+
className: cn("flex cursor-default items-center justify-center py-1", className),
|
|
9587
|
+
...props,
|
|
9588
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(import_lucide_react17.ChevronUpIcon, { className: "size-4" })
|
|
9589
|
+
}
|
|
9590
|
+
);
|
|
9591
|
+
}
|
|
9592
|
+
function SelectScrollDownButton({
|
|
9593
|
+
className,
|
|
9594
|
+
...props
|
|
9595
|
+
}) {
|
|
9596
|
+
return /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
|
|
9597
|
+
import_radix_ui7.Select.ScrollDownButton,
|
|
9598
|
+
{
|
|
9599
|
+
"data-slot": "select-scroll-down-button",
|
|
9600
|
+
className: cn("flex cursor-default items-center justify-center py-1", className),
|
|
9601
|
+
...props,
|
|
9602
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(import_lucide_react17.ChevronDownIcon, { className: "size-4" })
|
|
9603
|
+
}
|
|
9604
|
+
);
|
|
9605
|
+
}
|
|
9606
|
+
|
|
9607
|
+
// src/ui/popover.tsx
|
|
9608
|
+
var import_radix_ui8 = require("radix-ui");
|
|
9609
|
+
var import_jsx_runtime87 = require("react/jsx-runtime");
|
|
9367
9610
|
function Popover({
|
|
9368
9611
|
...props
|
|
9369
9612
|
}) {
|
|
9370
|
-
return /* @__PURE__ */ (0,
|
|
9613
|
+
return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(import_radix_ui8.Popover.Root, { "data-slot": "popover", ...props });
|
|
9371
9614
|
}
|
|
9372
9615
|
function PopoverTrigger({
|
|
9373
9616
|
...props
|
|
9374
9617
|
}) {
|
|
9375
|
-
return /* @__PURE__ */ (0,
|
|
9618
|
+
return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(import_radix_ui8.Popover.Trigger, { "data-slot": "popover-trigger", ...props });
|
|
9376
9619
|
}
|
|
9377
9620
|
function PopoverContent({
|
|
9378
9621
|
className,
|
|
@@ -9381,8 +9624,8 @@ function PopoverContent({
|
|
|
9381
9624
|
variant = "default",
|
|
9382
9625
|
...props
|
|
9383
9626
|
}) {
|
|
9384
|
-
return /* @__PURE__ */ (0,
|
|
9385
|
-
|
|
9627
|
+
return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(import_radix_ui8.Popover.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
9628
|
+
import_radix_ui8.Popover.Content,
|
|
9386
9629
|
{
|
|
9387
9630
|
"data-slot": "popover-content",
|
|
9388
9631
|
"data-variant": variant,
|
|
@@ -9394,7 +9637,7 @@ function PopoverContent({
|
|
|
9394
9637
|
"min-w-[8rem] origin-[var(--radix-popover-content-transform-origin)]"
|
|
9395
9638
|
) : cn(
|
|
9396
9639
|
overlaySurfaceClass,
|
|
9397
|
-
"w-72 origin-[var(--radix-popover-content-transform-origin)] rounded-xl p-
|
|
9640
|
+
"w-72 origin-[var(--radix-popover-content-transform-origin)] rounded-xl p-3 outline-hidden"
|
|
9398
9641
|
),
|
|
9399
9642
|
className
|
|
9400
9643
|
),
|
|
@@ -9404,499 +9647,471 @@ function PopoverContent({
|
|
|
9404
9647
|
}
|
|
9405
9648
|
|
|
9406
9649
|
// src/app/data/FilterDropdown.tsx
|
|
9407
|
-
var
|
|
9408
|
-
var
|
|
9409
|
-
{ id: "
|
|
9410
|
-
{ id: "
|
|
9411
|
-
{ id: "
|
|
9650
|
+
var import_jsx_runtime88 = require("react/jsx-runtime");
|
|
9651
|
+
var DEFAULT_PRESETS = [
|
|
9652
|
+
{ id: "last_7_days", label: "Last 7 days" },
|
|
9653
|
+
{ id: "last_30_days", label: "Last 30 days" },
|
|
9654
|
+
{ id: "last_90_days", label: "Last 90 days" },
|
|
9655
|
+
{ id: "this_month", label: "This month" },
|
|
9656
|
+
{ id: "this_year", label: "This year" },
|
|
9657
|
+
{ id: "custom", label: "Custom range" }
|
|
9412
9658
|
];
|
|
9413
|
-
var
|
|
9414
|
-
{ id: "
|
|
9415
|
-
{ id: "
|
|
9416
|
-
{ id: "
|
|
9659
|
+
var DEFAULT_OPERATORS = [
|
|
9660
|
+
{ id: "gt", label: "Greater than" },
|
|
9661
|
+
{ id: "lt", label: "Less than" },
|
|
9662
|
+
{ id: "eq", label: "Equals" }
|
|
9417
9663
|
];
|
|
9664
|
+
function asArray(v) {
|
|
9665
|
+
return Array.isArray(v) ? v : [];
|
|
9666
|
+
}
|
|
9667
|
+
function asText(v) {
|
|
9668
|
+
return typeof v === "string" ? v : "";
|
|
9669
|
+
}
|
|
9670
|
+
function asDate(v) {
|
|
9671
|
+
return v && !Array.isArray(v) && typeof v === "object" && "preset" in v ? v : { preset: null };
|
|
9672
|
+
}
|
|
9673
|
+
function asNumeric(v) {
|
|
9674
|
+
return v && !Array.isArray(v) && typeof v === "object" && "operator" in v ? v : { operator: "gt", value: "" };
|
|
9675
|
+
}
|
|
9676
|
+
var OPERATOR_SYMBOL = {
|
|
9677
|
+
gt: ">",
|
|
9678
|
+
lt: "<",
|
|
9679
|
+
eq: "="
|
|
9680
|
+
};
|
|
9418
9681
|
function FilterDropdown({
|
|
9419
|
-
|
|
9420
|
-
|
|
9421
|
-
|
|
9422
|
-
|
|
9682
|
+
fields,
|
|
9683
|
+
value,
|
|
9684
|
+
defaultValue,
|
|
9685
|
+
onChange,
|
|
9686
|
+
label = "Filter",
|
|
9687
|
+
align = "start",
|
|
9688
|
+
showActiveChips = true,
|
|
9423
9689
|
className
|
|
9424
9690
|
}) {
|
|
9425
9691
|
const [isOpen, setIsOpen] = (0, import_react53.useState)(false);
|
|
9426
|
-
const [
|
|
9692
|
+
const [activeId, setActiveId] = (0, import_react53.useState)(fields[0]?.id ?? null);
|
|
9427
9693
|
const [isMobile, setIsMobile] = (0, import_react53.useState)(false);
|
|
9694
|
+
const isControlled = value !== void 0;
|
|
9695
|
+
const [internal, setInternal] = (0, import_react53.useState)(defaultValue ?? {});
|
|
9696
|
+
const values = isControlled ? value : internal;
|
|
9428
9697
|
(0, import_react53.useEffect)(() => {
|
|
9429
9698
|
const checkMobile = () => setIsMobile(window.innerWidth < 768);
|
|
9430
9699
|
checkMobile();
|
|
9431
9700
|
window.addEventListener("resize", checkMobile);
|
|
9432
9701
|
return () => window.removeEventListener("resize", checkMobile);
|
|
9433
9702
|
}, []);
|
|
9434
|
-
const [selectedContacts, setSelectedContacts] = (0, import_react53.useState)(
|
|
9435
|
-
filters?.contacts ?? initialFilters?.contacts ?? []
|
|
9436
|
-
);
|
|
9437
|
-
const [walletInput, setWalletInput] = (0, import_react53.useState)(filters?.walletAddress ?? initialFilters?.walletAddress ?? "");
|
|
9438
|
-
const [appliedWallet, setAppliedWallet] = (0, import_react53.useState)(filters?.walletAddress ?? initialFilters?.walletAddress ?? "");
|
|
9439
|
-
const [selectedDatePreset, setSelectedDatePreset] = (0, import_react53.useState)(
|
|
9440
|
-
filters?.lastInvoiceDate ?? initialFilters?.lastInvoiceDate ?? null
|
|
9441
|
-
);
|
|
9442
|
-
const [customDateFrom, setCustomDateFrom] = (0, import_react53.useState)(
|
|
9443
|
-
filters?.customDateRange?.from ?? initialFilters?.customDateRange?.from ?? ""
|
|
9444
|
-
);
|
|
9445
|
-
const [customDateTo, setCustomDateTo] = (0, import_react53.useState)(
|
|
9446
|
-
filters?.customDateRange?.to ?? initialFilters?.customDateRange?.to ?? ""
|
|
9447
|
-
);
|
|
9448
|
-
const [ltvOperator, setLtvOperator] = (0, import_react53.useState)(
|
|
9449
|
-
filters?.lifetimeValue?.operator ?? initialFilters?.lifetimeValue?.operator ?? "greater_than"
|
|
9450
|
-
);
|
|
9451
|
-
const [ltvValue, setLtvValue] = (0, import_react53.useState)(filters?.lifetimeValue?.value ?? initialFilters?.lifetimeValue?.value ?? "");
|
|
9452
|
-
const [isLtvOperatorOpen, setLtvOperatorOpen] = (0, import_react53.useState)(false);
|
|
9453
|
-
const [outstandingOperator, setOutstandingOperator] = (0, import_react53.useState)(
|
|
9454
|
-
filters?.outstanding?.operator ?? initialFilters?.outstanding?.operator ?? "greater_than"
|
|
9455
|
-
);
|
|
9456
|
-
const [outstandingValue, setOutstandingValue] = (0, import_react53.useState)(filters?.outstanding?.value ?? initialFilters?.outstanding?.value ?? "");
|
|
9457
|
-
const [isOutstandingOperatorOpen, setOutstandingOperatorOpen] = (0, import_react53.useState)(false);
|
|
9458
9703
|
(0, import_react53.useEffect)(() => {
|
|
9459
|
-
if (
|
|
9460
|
-
|
|
9461
|
-
|
|
9462
|
-
|
|
9463
|
-
|
|
9464
|
-
|
|
9465
|
-
|
|
9466
|
-
|
|
9467
|
-
setLtvValue(filters.lifetimeValue?.value ?? "");
|
|
9468
|
-
setOutstandingOperator(filters.outstanding?.operator ?? "greater_than");
|
|
9469
|
-
setOutstandingValue(filters.outstanding?.value ?? "");
|
|
9470
|
-
}
|
|
9471
|
-
}, [filters]);
|
|
9472
|
-
const [contactSearch, setContactSearch] = (0, import_react53.useState)("");
|
|
9473
|
-
const [walletSearch, setWalletSearch] = (0, import_react53.useState)("");
|
|
9474
|
-
const refDate = (0, import_react53.useMemo)(() => new Date(2026, 5, 26), []);
|
|
9475
|
-
const presets = (0, import_react53.useMemo)(() => {
|
|
9476
|
-
const year = refDate.getFullYear();
|
|
9477
|
-
const month = refDate.getMonth();
|
|
9478
|
-
const lastMonthDate = new Date(year, month - 1, 1);
|
|
9479
|
-
const lastMonthLabel = lastMonthDate.toLocaleDateString("en-US", { month: "short", year: "numeric" });
|
|
9480
|
-
const thisMonthLabel = refDate.toLocaleDateString("en-US", { month: "short", year: "numeric" });
|
|
9481
|
-
const thisQuarter = Math.floor(month / 3) + 1;
|
|
9482
|
-
const thisQuarterLabel = `Q${thisQuarter} ${year}`;
|
|
9483
|
-
const lastQuarter = thisQuarter === 1 ? 4 : thisQuarter - 1;
|
|
9484
|
-
const lastQuarterYear = thisQuarter === 1 ? year - 1 : year;
|
|
9485
|
-
const lastQuarterLabel = `Q${lastQuarter} ${lastQuarterYear}`;
|
|
9486
|
-
const thisYearLabel = `${year}`;
|
|
9487
|
-
const last30 = new Date(refDate);
|
|
9488
|
-
last30.setDate(refDate.getDate() - 30);
|
|
9489
|
-
const formatDate = (d) => d.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });
|
|
9490
|
-
const last30Label = `${formatDate(last30)} - ${formatDate(refDate)}`;
|
|
9491
|
-
const last90 = new Date(refDate);
|
|
9492
|
-
last90.setDate(refDate.getDate() - 90);
|
|
9493
|
-
const last90Label = `${formatDate(last90)} - ${formatDate(refDate)}`;
|
|
9494
|
-
return [
|
|
9495
|
-
{ id: "last_month", label: "Last month", date: lastMonthLabel },
|
|
9496
|
-
{ id: "this_month", label: "This month", date: thisMonthLabel },
|
|
9497
|
-
{ id: "this_quarter", label: "This quarter", date: thisQuarterLabel },
|
|
9498
|
-
{ id: "last_quarter", label: "Last quarter", date: lastQuarterLabel },
|
|
9499
|
-
{ id: "this_year", label: "This year", date: thisYearLabel },
|
|
9500
|
-
{ id: "last_30_days", label: "Last 30 days", date: last30Label },
|
|
9501
|
-
{ id: "last_90_days", label: "Last 90 days", date: last90Label },
|
|
9502
|
-
{ id: "custom", label: "Custom range", date: "" }
|
|
9503
|
-
];
|
|
9504
|
-
}, [refDate]);
|
|
9505
|
-
const filteredContacts = (0, import_react53.useMemo)(() => {
|
|
9506
|
-
if (!contactSearch) return contacts;
|
|
9507
|
-
const query = contactSearch.toLowerCase();
|
|
9508
|
-
return contacts.filter(
|
|
9509
|
-
(c) => c.name.toLowerCase().includes(query) || c.email.toLowerCase().includes(query)
|
|
9510
|
-
);
|
|
9511
|
-
}, [contacts, contactSearch]);
|
|
9512
|
-
const handleContactToggle = (contactName) => {
|
|
9513
|
-
const next = selectedContacts.includes(contactName) ? selectedContacts.filter((name) => name !== contactName) : [...selectedContacts, contactName];
|
|
9514
|
-
setSelectedContacts(next);
|
|
9515
|
-
notifyChanges({ contacts: next });
|
|
9516
|
-
setIsOpen(false);
|
|
9517
|
-
};
|
|
9518
|
-
const handleWalletApply = () => {
|
|
9519
|
-
setAppliedWallet(walletInput);
|
|
9520
|
-
notifyChanges({ walletAddress: walletInput });
|
|
9521
|
-
setIsOpen(false);
|
|
9704
|
+
if (!fields.some((f) => f.id === activeId)) {
|
|
9705
|
+
setActiveId(fields[0]?.id ?? null);
|
|
9706
|
+
}
|
|
9707
|
+
}, [fields, activeId]);
|
|
9708
|
+
const commit = (id, next) => {
|
|
9709
|
+
const merged = { ...values, [id]: next };
|
|
9710
|
+
if (!isControlled) setInternal(merged);
|
|
9711
|
+
onChange?.(merged);
|
|
9522
9712
|
};
|
|
9523
|
-
const
|
|
9524
|
-
|
|
9525
|
-
|
|
9526
|
-
notifyChanges({ walletAddress: "" });
|
|
9527
|
-
setIsOpen(false);
|
|
9713
|
+
const clearAll = () => {
|
|
9714
|
+
if (!isControlled) setInternal({});
|
|
9715
|
+
onChange?.({});
|
|
9528
9716
|
};
|
|
9529
|
-
const
|
|
9530
|
-
|
|
9531
|
-
|
|
9532
|
-
|
|
9533
|
-
|
|
9717
|
+
const activeIdx = fields.findIndex((f) => f.id === activeId);
|
|
9718
|
+
const activeField = activeIdx >= 0 ? fields[activeIdx] : void 0;
|
|
9719
|
+
const chips = [];
|
|
9720
|
+
for (const field of fields) {
|
|
9721
|
+
const v = values[field.id];
|
|
9722
|
+
if (field.type === "multiselect") {
|
|
9723
|
+
const selected = asArray(v);
|
|
9724
|
+
for (const optionValue of selected) {
|
|
9725
|
+
const opt = field.options?.find((o) => o.value === optionValue);
|
|
9726
|
+
chips.push({
|
|
9727
|
+
id: `${field.id}:${optionValue}`,
|
|
9728
|
+
label: `${field.label}: ${opt?.label ?? optionValue}`,
|
|
9729
|
+
remove: () => commit(field.id, selected.filter((x) => x !== optionValue))
|
|
9730
|
+
});
|
|
9731
|
+
}
|
|
9732
|
+
} else if (field.type === "text") {
|
|
9733
|
+
const text = asText(v);
|
|
9734
|
+
if (text) {
|
|
9735
|
+
chips.push({
|
|
9736
|
+
id: field.id,
|
|
9737
|
+
label: `${field.label}: ${text}`,
|
|
9738
|
+
remove: () => commit(field.id, "")
|
|
9739
|
+
});
|
|
9740
|
+
}
|
|
9741
|
+
} else if (field.type === "numeric") {
|
|
9742
|
+
const n = asNumeric(v);
|
|
9743
|
+
if (n.value) {
|
|
9744
|
+
chips.push({
|
|
9745
|
+
id: field.id,
|
|
9746
|
+
label: `${field.label} ${OPERATOR_SYMBOL[n.operator]} ${n.value}`,
|
|
9747
|
+
remove: () => commit(field.id, null)
|
|
9748
|
+
});
|
|
9749
|
+
}
|
|
9750
|
+
} else if (field.type === "daterange") {
|
|
9751
|
+
const d = asDate(v);
|
|
9752
|
+
if (d.preset) {
|
|
9753
|
+
const presetLabel = d.preset === "custom" ? `${d.from || "\u2026"} \u2013 ${d.to || "\u2026"}` : (field.presets ?? DEFAULT_PRESETS).find((p) => p.id === d.preset)?.label ?? d.preset;
|
|
9754
|
+
chips.push({
|
|
9755
|
+
id: field.id,
|
|
9756
|
+
label: `${field.label}: ${presetLabel}`,
|
|
9757
|
+
remove: () => commit(field.id, { preset: null })
|
|
9758
|
+
});
|
|
9759
|
+
}
|
|
9534
9760
|
}
|
|
9761
|
+
}
|
|
9762
|
+
return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: cn("flex flex-wrap items-center gap-2", className), children: [
|
|
9763
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsxs)(Popover, { open: isOpen, onOpenChange: setIsOpen, children: [
|
|
9764
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsx)(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
|
|
9765
|
+
Button,
|
|
9766
|
+
{
|
|
9767
|
+
variant: "outline",
|
|
9768
|
+
size: "sm",
|
|
9769
|
+
className: "border-dashed font-medium text-muted-foreground hover:text-foreground",
|
|
9770
|
+
iconLeading: /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(import_lucide_react18.ListFilterIcon, { className: "size-4" }),
|
|
9771
|
+
children: label
|
|
9772
|
+
}
|
|
9773
|
+
) }),
|
|
9774
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
|
|
9775
|
+
PopoverContent,
|
|
9776
|
+
{
|
|
9777
|
+
variant: "list",
|
|
9778
|
+
align,
|
|
9779
|
+
className: "overflow-visible border-none bg-transparent p-0 shadow-none max-w-[calc(100vw-32px)] md:max-w-none",
|
|
9780
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: "relative flex flex-col md:flex-row items-stretch md:items-start w-[calc(100vw-32px)] max-w-[340px] md:w-auto md:max-w-none", children: [
|
|
9781
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsx)("div", { className: "w-full md:w-56 rounded-xl border border-border bg-popover p-1.5 shadow-lg", children: fields.map((field) => {
|
|
9782
|
+
const isActive = activeId === field.id;
|
|
9783
|
+
return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)(
|
|
9784
|
+
"button",
|
|
9785
|
+
{
|
|
9786
|
+
type: "button",
|
|
9787
|
+
className: cn(
|
|
9788
|
+
"flex w-full items-center justify-between rounded-lg px-3 py-2 text-sm text-left transition-colors outline-none",
|
|
9789
|
+
isActive ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted/50 hover:text-foreground"
|
|
9790
|
+
),
|
|
9791
|
+
onMouseEnter: () => !isMobile && setActiveId(field.id),
|
|
9792
|
+
onClick: () => setActiveId(field.id),
|
|
9793
|
+
children: [
|
|
9794
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("span", { className: "flex items-center gap-2", children: [
|
|
9795
|
+
field.icon,
|
|
9796
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { children: field.label })
|
|
9797
|
+
] }),
|
|
9798
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsx)(import_lucide_react18.ChevronRightIcon, { className: "size-4 text-muted-foreground/50" })
|
|
9799
|
+
]
|
|
9800
|
+
},
|
|
9801
|
+
field.id
|
|
9802
|
+
);
|
|
9803
|
+
}) }),
|
|
9804
|
+
activeField && /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
|
|
9805
|
+
"div",
|
|
9806
|
+
{
|
|
9807
|
+
className: "relative left-0 mt-2 w-full md:absolute md:left-[calc(100%+6px)] md:w-80 rounded-xl border border-border bg-popover p-3 shadow-lg transition-all duration-150 md:mt-0",
|
|
9808
|
+
style: isMobile ? {} : { top: `${activeIdx * 36 + 6}px` },
|
|
9809
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
|
|
9810
|
+
FilterFieldControl,
|
|
9811
|
+
{
|
|
9812
|
+
field: activeField,
|
|
9813
|
+
value: values[activeField.id],
|
|
9814
|
+
onChange: (next) => commit(activeField.id, next),
|
|
9815
|
+
onClose: () => setIsOpen(false)
|
|
9816
|
+
}
|
|
9817
|
+
)
|
|
9818
|
+
}
|
|
9819
|
+
)
|
|
9820
|
+
] })
|
|
9821
|
+
}
|
|
9822
|
+
)
|
|
9823
|
+
] }),
|
|
9824
|
+
showActiveChips && chips.map((chip) => /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(FilterChip, { label: chip.label, onRemove: chip.remove }, chip.id)),
|
|
9825
|
+
showActiveChips && chips.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
|
|
9826
|
+
"button",
|
|
9827
|
+
{
|
|
9828
|
+
type: "button",
|
|
9829
|
+
onClick: clearAll,
|
|
9830
|
+
className: "rounded-full px-3 py-1 text-sm font-medium text-muted-foreground outline-none transition-colors hover:text-foreground",
|
|
9831
|
+
children: "Clear all"
|
|
9832
|
+
}
|
|
9833
|
+
)
|
|
9834
|
+
] });
|
|
9835
|
+
}
|
|
9836
|
+
function FilterChip({ label, onRemove }) {
|
|
9837
|
+
return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("span", { className: "inline-flex h-9 items-center gap-1.5 rounded-full border border-border bg-muted/40 pl-3 pr-1.5 text-sm font-medium text-foreground", children: [
|
|
9838
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "truncate", children: label }),
|
|
9839
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
|
|
9840
|
+
"button",
|
|
9841
|
+
{
|
|
9842
|
+
type: "button",
|
|
9843
|
+
onClick: onRemove,
|
|
9844
|
+
"aria-label": `Remove ${label}`,
|
|
9845
|
+
className: "flex size-5 items-center justify-center rounded-full text-muted-foreground outline-none transition-colors hover:bg-muted hover:text-foreground",
|
|
9846
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(import_lucide_react18.XIcon, { className: "size-3.5" })
|
|
9847
|
+
}
|
|
9848
|
+
)
|
|
9849
|
+
] });
|
|
9850
|
+
}
|
|
9851
|
+
function FilterFieldControl({
|
|
9852
|
+
field,
|
|
9853
|
+
value,
|
|
9854
|
+
onChange,
|
|
9855
|
+
onClose
|
|
9856
|
+
}) {
|
|
9857
|
+
switch (field.type) {
|
|
9858
|
+
case "multiselect":
|
|
9859
|
+
return /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(MultiSelectControl, { field, value: asArray(value), onChange });
|
|
9860
|
+
case "text":
|
|
9861
|
+
return /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(TextControl, { field, value: asText(value), onChange, onClose });
|
|
9862
|
+
case "daterange":
|
|
9863
|
+
return /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(DateRangeControl, { field, value: asDate(value), onChange, onClose });
|
|
9864
|
+
case "numeric":
|
|
9865
|
+
return /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(NumericControl, { field, value: asNumeric(value), onChange, onClose });
|
|
9866
|
+
default:
|
|
9867
|
+
return null;
|
|
9868
|
+
}
|
|
9869
|
+
}
|
|
9870
|
+
function MultiSelectControl({
|
|
9871
|
+
field,
|
|
9872
|
+
value,
|
|
9873
|
+
onChange
|
|
9874
|
+
}) {
|
|
9875
|
+
const options = field.options ?? [];
|
|
9876
|
+
const [search, setSearch] = (0, import_react53.useState)("");
|
|
9877
|
+
const searchable = field.searchable ?? options.length > 8;
|
|
9878
|
+
const filtered = (0, import_react53.useMemo)(() => {
|
|
9879
|
+
if (!search) return options;
|
|
9880
|
+
const q = search.toLowerCase();
|
|
9881
|
+
return options.filter(
|
|
9882
|
+
(o) => o.label.toLowerCase().includes(q) || o.hint?.toLowerCase().includes(q)
|
|
9883
|
+
);
|
|
9884
|
+
}, [options, search]);
|
|
9885
|
+
const toggle = (optionValue) => {
|
|
9886
|
+
onChange(
|
|
9887
|
+
value.includes(optionValue) ? value.filter((v) => v !== optionValue) : [...value, optionValue]
|
|
9888
|
+
);
|
|
9535
9889
|
};
|
|
9536
|
-
|
|
9537
|
-
|
|
9538
|
-
|
|
9539
|
-
customDateRange: { from: customDateFrom, to: customDateTo }
|
|
9540
|
-
});
|
|
9541
|
-
setIsOpen(false);
|
|
9542
|
-
};
|
|
9543
|
-
const handleLtvApply = () => {
|
|
9544
|
-
notifyChanges({
|
|
9545
|
-
lifetimeValue: ltvValue ? { operator: ltvOperator, value: ltvValue } : null
|
|
9546
|
-
});
|
|
9547
|
-
setIsOpen(false);
|
|
9548
|
-
};
|
|
9549
|
-
const handleLtvClear = () => {
|
|
9550
|
-
setLtvValue("");
|
|
9551
|
-
notifyChanges({ lifetimeValue: null });
|
|
9552
|
-
setIsOpen(false);
|
|
9553
|
-
};
|
|
9554
|
-
const handleOutstandingApply = () => {
|
|
9555
|
-
notifyChanges({
|
|
9556
|
-
outstanding: outstandingValue ? { operator: outstandingOperator, value: outstandingValue } : null
|
|
9557
|
-
});
|
|
9558
|
-
setIsOpen(false);
|
|
9559
|
-
};
|
|
9560
|
-
const handleOutstandingClear = () => {
|
|
9561
|
-
setOutstandingValue("");
|
|
9562
|
-
notifyChanges({ outstanding: null });
|
|
9563
|
-
setIsOpen(false);
|
|
9564
|
-
};
|
|
9565
|
-
const notifyChanges = (overrides) => {
|
|
9566
|
-
const current = {
|
|
9567
|
-
contacts: selectedContacts,
|
|
9568
|
-
walletAddress: appliedWallet,
|
|
9569
|
-
lastInvoiceDate: selectedDatePreset,
|
|
9570
|
-
customDateRange: customDateFrom || customDateTo ? { from: customDateFrom, to: customDateTo } : void 0,
|
|
9571
|
-
lifetimeValue: ltvValue ? { operator: ltvOperator, value: ltvValue } : null,
|
|
9572
|
-
outstanding: outstandingValue ? { operator: outstandingOperator, value: outstandingValue } : null,
|
|
9573
|
-
...overrides
|
|
9574
|
-
};
|
|
9575
|
-
onFiltersChange?.(current);
|
|
9576
|
-
};
|
|
9577
|
-
const menuItems = [
|
|
9578
|
-
{ id: "contact", label: "Contact", icon: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(import_lucide_react17.UserIcon, { className: "size-4" }) },
|
|
9579
|
-
{ id: "wallet", label: "Wallet address", icon: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(import_lucide_react17.WalletIcon, { className: "size-4" }) },
|
|
9580
|
-
{ id: "date", label: "Last invoice date", icon: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(import_lucide_react17.CalendarIcon, { className: "size-4" }) },
|
|
9581
|
-
{ id: "ltv", label: "Lifetime value", icon: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(import_lucide_react17.TrendingUpIcon, { className: "size-4" }) },
|
|
9582
|
-
{ id: "outstanding", label: "Outstanding", icon: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(import_lucide_react17.CircleDollarSignIcon, { className: "size-4" }) }
|
|
9583
|
-
];
|
|
9584
|
-
const activeIdx = menuItems.findIndex((item) => item.id === activeMenu);
|
|
9585
|
-
return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("div", { className: cn("inline-block", className), children: /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(Popover, { open: isOpen, onOpenChange: setIsOpen, children: [
|
|
9586
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
9587
|
-
Button,
|
|
9890
|
+
return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: "flex flex-col gap-2.5", children: [
|
|
9891
|
+
searchable && /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
|
|
9892
|
+
SearchInput,
|
|
9588
9893
|
{
|
|
9589
|
-
|
|
9590
|
-
|
|
9591
|
-
|
|
9592
|
-
className: "
|
|
9593
|
-
iconLeading: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(import_lucide_react17.ListFilterIcon, { className: "size-4" }),
|
|
9594
|
-
children: "Filter"
|
|
9894
|
+
placeholder: field.searchPlaceholder ?? "Search\u2026",
|
|
9895
|
+
value: search,
|
|
9896
|
+
onChange: (e) => setSearch(e.target.value),
|
|
9897
|
+
className: "w-full min-w-0"
|
|
9595
9898
|
}
|
|
9596
|
-
)
|
|
9597
|
-
/* @__PURE__ */ (0,
|
|
9598
|
-
|
|
9899
|
+
),
|
|
9900
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsx)("div", { className: "flex max-h-48 flex-col gap-1 overflow-y-auto pr-1", children: filtered.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("p", { className: "py-4 text-center text-xs text-muted-foreground", children: "No options found" }) : filtered.map((option) => /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)(
|
|
9901
|
+
"label",
|
|
9599
9902
|
{
|
|
9600
|
-
|
|
9601
|
-
|
|
9602
|
-
|
|
9603
|
-
|
|
9604
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)("div", { className: "w-full md:w-56 rounded-xl border border-border bg-popover p-1.5 shadow-lg", children: menuItems.map((item) => {
|
|
9605
|
-
const isActive = activeMenu === item.id;
|
|
9606
|
-
return /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(
|
|
9607
|
-
"button",
|
|
9608
|
-
{
|
|
9609
|
-
type: "button",
|
|
9610
|
-
className: cn(
|
|
9611
|
-
"flex w-full items-center justify-between rounded-lg px-3 py-2 text-sm text-left transition-colors outline-none",
|
|
9612
|
-
isActive ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted/50 hover:text-foreground"
|
|
9613
|
-
),
|
|
9614
|
-
onMouseEnter: () => !isMobile && setActiveMenu(item.id),
|
|
9615
|
-
onClick: () => setActiveMenu(item.id),
|
|
9616
|
-
children: [
|
|
9617
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("span", { className: "flex items-center gap-2", children: [
|
|
9618
|
-
item.icon,
|
|
9619
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { children: item.label })
|
|
9620
|
-
] }),
|
|
9621
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(import_lucide_react17.ChevronRightIcon, { className: "size-4 text-muted-foreground/50" })
|
|
9622
|
-
]
|
|
9623
|
-
},
|
|
9624
|
-
item.id
|
|
9625
|
-
);
|
|
9626
|
-
}) }),
|
|
9627
|
-
activeMenu && /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(
|
|
9628
|
-
"div",
|
|
9903
|
+
className: "flex cursor-pointer items-center gap-2.5 rounded-lg px-2 py-1.5 transition-colors hover:bg-muted/50",
|
|
9904
|
+
children: [
|
|
9905
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
|
|
9906
|
+
Checkbox,
|
|
9629
9907
|
{
|
|
9630
|
-
|
|
9631
|
-
|
|
9632
|
-
children: [
|
|
9633
|
-
activeMenu === "contact" && /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "flex flex-col gap-2.5", children: [
|
|
9634
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "relative flex items-center", children: [
|
|
9635
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(import_lucide_react17.SearchIcon, { className: "absolute left-2.5 size-4 text-muted-foreground/60" }),
|
|
9636
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
9637
|
-
"input",
|
|
9638
|
-
{
|
|
9639
|
-
type: "text",
|
|
9640
|
-
placeholder: "Search by name or email...",
|
|
9641
|
-
value: contactSearch,
|
|
9642
|
-
onChange: (e) => setContactSearch(e.target.value),
|
|
9643
|
-
className: "w-full rounded-lg border border-border bg-background py-1.5 pl-8 pr-3 text-sm outline-none placeholder:text-muted-foreground/60 focus:border-border"
|
|
9644
|
-
}
|
|
9645
|
-
)
|
|
9646
|
-
] }),
|
|
9647
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)("div", { className: "max-h-48 overflow-y-auto flex flex-col gap-1 pr-1", children: filteredContacts.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("p", { className: "py-4 text-center text-xs text-muted-foreground", children: "No contacts found" }) : filteredContacts.map((contact) => {
|
|
9648
|
-
const isChecked = selectedContacts.includes(contact.name);
|
|
9649
|
-
return /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(
|
|
9650
|
-
"label",
|
|
9651
|
-
{
|
|
9652
|
-
className: "flex cursor-pointer items-center gap-2.5 rounded-lg px-2 py-1.5 hover:bg-muted/50 transition-colors",
|
|
9653
|
-
children: [
|
|
9654
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
9655
|
-
Checkbox,
|
|
9656
|
-
{
|
|
9657
|
-
checked: isChecked,
|
|
9658
|
-
onCheckedChange: () => handleContactToggle(contact.name)
|
|
9659
|
-
}
|
|
9660
|
-
),
|
|
9661
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(Avatar, { variant: "secondary", children: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(AvatarFallback, { children: contact.initials }) }),
|
|
9662
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "text-sm font-medium text-foreground", children: contact.name })
|
|
9663
|
-
]
|
|
9664
|
-
},
|
|
9665
|
-
contact.id
|
|
9666
|
-
);
|
|
9667
|
-
}) })
|
|
9668
|
-
] }),
|
|
9669
|
-
activeMenu === "wallet" && /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "flex flex-col gap-2.5", children: [
|
|
9670
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)("div", { className: "relative flex items-center", children: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
9671
|
-
"input",
|
|
9672
|
-
{
|
|
9673
|
-
type: "text",
|
|
9674
|
-
placeholder: "Search by wallet...",
|
|
9675
|
-
value: walletInput,
|
|
9676
|
-
onChange: (e) => setWalletInput(e.target.value),
|
|
9677
|
-
className: "w-full rounded-lg border border-border bg-background px-3 py-1.5 text-sm outline-none placeholder:text-muted-foreground/60"
|
|
9678
|
-
}
|
|
9679
|
-
) }),
|
|
9680
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "flex items-center justify-end gap-2 pt-1 border-t border-border/40", children: [
|
|
9681
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
9682
|
-
Button,
|
|
9683
|
-
{
|
|
9684
|
-
variant: "ghost",
|
|
9685
|
-
size: "sm",
|
|
9686
|
-
onClick: handleWalletClear,
|
|
9687
|
-
className: "text-muted-foreground hover:text-foreground h-8 px-3",
|
|
9688
|
-
children: "Clear"
|
|
9689
|
-
}
|
|
9690
|
-
),
|
|
9691
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
9692
|
-
Button,
|
|
9693
|
-
{
|
|
9694
|
-
color: "primary",
|
|
9695
|
-
size: "sm",
|
|
9696
|
-
onClick: handleWalletApply,
|
|
9697
|
-
className: "h-8 px-3",
|
|
9698
|
-
children: "Apply"
|
|
9699
|
-
}
|
|
9700
|
-
)
|
|
9701
|
-
] })
|
|
9702
|
-
] }),
|
|
9703
|
-
activeMenu === "date" && /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "flex flex-col gap-1", children: [
|
|
9704
|
-
presets.map((preset) => {
|
|
9705
|
-
const isSelected = selectedDatePreset === preset.id;
|
|
9706
|
-
return /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(
|
|
9707
|
-
"button",
|
|
9708
|
-
{
|
|
9709
|
-
type: "button",
|
|
9710
|
-
onClick: () => handleDatePresetSelect(preset.id),
|
|
9711
|
-
className: cn(
|
|
9712
|
-
"flex w-full items-center justify-between rounded-lg px-2.5 py-1.5 text-sm text-left transition-colors outline-none",
|
|
9713
|
-
isSelected ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted/50 hover:text-foreground"
|
|
9714
|
-
),
|
|
9715
|
-
children: [
|
|
9716
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { children: preset.label }),
|
|
9717
|
-
preset.date && /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "text-xs text-muted-foreground/70", children: preset.date })
|
|
9718
|
-
]
|
|
9719
|
-
},
|
|
9720
|
-
preset.id
|
|
9721
|
-
);
|
|
9722
|
-
}),
|
|
9723
|
-
selectedDatePreset === "custom" && /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "flex flex-col gap-2 mt-2 pt-2 border-t border-border/40", children: [
|
|
9724
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
9725
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
9726
|
-
"input",
|
|
9727
|
-
{
|
|
9728
|
-
type: "date",
|
|
9729
|
-
value: customDateFrom,
|
|
9730
|
-
onChange: (e) => setCustomDateFrom(e.target.value),
|
|
9731
|
-
className: "w-full rounded-lg border border-border bg-background px-2 py-1 text-xs outline-none"
|
|
9732
|
-
}
|
|
9733
|
-
),
|
|
9734
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { className: "text-xs text-muted-foreground", children: "to" }),
|
|
9735
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
9736
|
-
"input",
|
|
9737
|
-
{
|
|
9738
|
-
type: "date",
|
|
9739
|
-
value: customDateTo,
|
|
9740
|
-
onChange: (e) => setCustomDateTo(e.target.value),
|
|
9741
|
-
className: "w-full rounded-lg border border-border bg-background px-2 py-1 text-xs outline-none"
|
|
9742
|
-
}
|
|
9743
|
-
)
|
|
9744
|
-
] }),
|
|
9745
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)("div", { className: "flex justify-end gap-2", children: /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
9746
|
-
Button,
|
|
9747
|
-
{
|
|
9748
|
-
color: "primary",
|
|
9749
|
-
size: "sm",
|
|
9750
|
-
onClick: handleCustomDateApply,
|
|
9751
|
-
className: "h-7 text-xs px-2.5",
|
|
9752
|
-
children: "Apply"
|
|
9753
|
-
}
|
|
9754
|
-
) })
|
|
9755
|
-
] })
|
|
9756
|
-
] }),
|
|
9757
|
-
activeMenu === "ltv" && /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "flex flex-col gap-2.5", children: [
|
|
9758
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
9759
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "relative shrink-0", children: [
|
|
9760
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(
|
|
9761
|
-
"button",
|
|
9762
|
-
{
|
|
9763
|
-
type: "button",
|
|
9764
|
-
onClick: () => setLtvOperatorOpen(!isLtvOperatorOpen),
|
|
9765
|
-
className: "flex h-9 items-center gap-1 rounded-lg border border-border bg-background px-2.5 text-xs font-normal text-muted-foreground hover:bg-muted/50 hover:text-foreground outline-none whitespace-nowrap",
|
|
9766
|
-
children: [
|
|
9767
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { children: OPERATORS.find((op) => op.id === ltvOperator)?.label.replace("...", "") }),
|
|
9768
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(import_lucide_react17.ChevronDownIcon, { className: "size-3" })
|
|
9769
|
-
]
|
|
9770
|
-
}
|
|
9771
|
-
),
|
|
9772
|
-
isLtvOperatorOpen && /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("div", { className: "absolute left-0 top-full z-50 mt-1 w-32 rounded-lg border border-border bg-popover p-1 shadow-md", children: OPERATORS.map((op) => /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
9773
|
-
"button",
|
|
9774
|
-
{
|
|
9775
|
-
type: "button",
|
|
9776
|
-
onClick: () => {
|
|
9777
|
-
setLtvOperator(op.id);
|
|
9778
|
-
setLtvOperatorOpen(false);
|
|
9779
|
-
},
|
|
9780
|
-
className: "w-full rounded-md px-2 py-1 text-left text-xs text-foreground hover:bg-muted outline-none",
|
|
9781
|
-
children: op.label
|
|
9782
|
-
},
|
|
9783
|
-
op.id
|
|
9784
|
-
)) })
|
|
9785
|
-
] }),
|
|
9786
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
9787
|
-
"input",
|
|
9788
|
-
{
|
|
9789
|
-
type: "text",
|
|
9790
|
-
placeholder: "0.00",
|
|
9791
|
-
value: ltvValue,
|
|
9792
|
-
onChange: (e) => setLtvValue(e.target.value),
|
|
9793
|
-
className: "h-9 flex-1 min-w-0 rounded-lg border border-border bg-background px-3 py-1 text-sm outline-none placeholder:text-muted-foreground/60"
|
|
9794
|
-
}
|
|
9795
|
-
)
|
|
9796
|
-
] }),
|
|
9797
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "flex items-center justify-end gap-2 pt-1 border-t border-border/40", children: [
|
|
9798
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
9799
|
-
Button,
|
|
9800
|
-
{
|
|
9801
|
-
variant: "ghost",
|
|
9802
|
-
size: "sm",
|
|
9803
|
-
onClick: handleLtvClear,
|
|
9804
|
-
className: "text-muted-foreground hover:text-foreground h-8 px-3",
|
|
9805
|
-
children: "Clear"
|
|
9806
|
-
}
|
|
9807
|
-
),
|
|
9808
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
9809
|
-
Button,
|
|
9810
|
-
{
|
|
9811
|
-
color: "primary",
|
|
9812
|
-
size: "sm",
|
|
9813
|
-
onClick: handleLtvApply,
|
|
9814
|
-
className: "h-8 px-3",
|
|
9815
|
-
children: "Apply"
|
|
9816
|
-
}
|
|
9817
|
-
)
|
|
9818
|
-
] })
|
|
9819
|
-
] }),
|
|
9820
|
-
activeMenu === "outstanding" && /* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "flex flex-col gap-2.5", children: [
|
|
9821
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
9822
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "relative shrink-0", children: [
|
|
9823
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsxs)(
|
|
9824
|
-
"button",
|
|
9825
|
-
{
|
|
9826
|
-
type: "button",
|
|
9827
|
-
onClick: () => setOutstandingOperatorOpen(!isOutstandingOperatorOpen),
|
|
9828
|
-
className: "flex h-9 items-center gap-1 rounded-lg border border-border bg-background px-2.5 text-xs font-normal text-muted-foreground hover:bg-muted/50 hover:text-foreground outline-none whitespace-nowrap",
|
|
9829
|
-
children: [
|
|
9830
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)("span", { children: OPERATORS.find((op) => op.id === outstandingOperator)?.label.replace("...", "") }),
|
|
9831
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(import_lucide_react17.ChevronDownIcon, { className: "size-3" })
|
|
9832
|
-
]
|
|
9833
|
-
}
|
|
9834
|
-
),
|
|
9835
|
-
isOutstandingOperatorOpen && /* @__PURE__ */ (0, import_jsx_runtime87.jsx)("div", { className: "absolute left-0 top-full z-50 mt-1 w-32 rounded-lg border border-border bg-popover p-1 shadow-md", children: OPERATORS.map((op) => /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
9836
|
-
"button",
|
|
9837
|
-
{
|
|
9838
|
-
type: "button",
|
|
9839
|
-
onClick: () => {
|
|
9840
|
-
setOutstandingOperator(op.id);
|
|
9841
|
-
setOutstandingOperatorOpen(false);
|
|
9842
|
-
},
|
|
9843
|
-
className: "w-full rounded-md px-2 py-1 text-left text-xs text-foreground hover:bg-muted outline-none",
|
|
9844
|
-
children: op.label
|
|
9845
|
-
},
|
|
9846
|
-
op.id
|
|
9847
|
-
)) })
|
|
9848
|
-
] }),
|
|
9849
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
9850
|
-
"input",
|
|
9851
|
-
{
|
|
9852
|
-
type: "text",
|
|
9853
|
-
placeholder: "0.00",
|
|
9854
|
-
value: outstandingValue,
|
|
9855
|
-
onChange: (e) => setOutstandingValue(e.target.value),
|
|
9856
|
-
className: "h-9 flex-1 min-w-0 rounded-lg border border-border bg-background px-3 py-1 text-sm outline-none placeholder:text-muted-foreground/60"
|
|
9857
|
-
}
|
|
9858
|
-
)
|
|
9859
|
-
] }),
|
|
9860
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsxs)("div", { className: "flex items-center justify-end gap-2 pt-1 border-t border-border/40", children: [
|
|
9861
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
9862
|
-
Button,
|
|
9863
|
-
{
|
|
9864
|
-
variant: "ghost",
|
|
9865
|
-
size: "sm",
|
|
9866
|
-
onClick: handleOutstandingClear,
|
|
9867
|
-
className: "text-muted-foreground hover:text-foreground h-8 px-3",
|
|
9868
|
-
children: "Clear"
|
|
9869
|
-
}
|
|
9870
|
-
),
|
|
9871
|
-
/* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
|
|
9872
|
-
Button,
|
|
9873
|
-
{
|
|
9874
|
-
color: "primary",
|
|
9875
|
-
size: "sm",
|
|
9876
|
-
onClick: handleOutstandingApply,
|
|
9877
|
-
className: "h-8 px-3",
|
|
9878
|
-
children: "Apply"
|
|
9879
|
-
}
|
|
9880
|
-
)
|
|
9881
|
-
] })
|
|
9882
|
-
] })
|
|
9883
|
-
]
|
|
9908
|
+
checked: value.includes(option.value),
|
|
9909
|
+
onCheckedChange: () => toggle(option.value)
|
|
9884
9910
|
}
|
|
9885
|
-
)
|
|
9886
|
-
|
|
9911
|
+
),
|
|
9912
|
+
option.icon,
|
|
9913
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("span", { className: "flex min-w-0 flex-col", children: [
|
|
9914
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "truncate text-sm font-medium text-foreground", children: option.label }),
|
|
9915
|
+
option.hint && /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "truncate text-xs text-muted-foreground", children: option.hint })
|
|
9916
|
+
] })
|
|
9917
|
+
]
|
|
9918
|
+
},
|
|
9919
|
+
option.value
|
|
9920
|
+
)) })
|
|
9921
|
+
] });
|
|
9922
|
+
}
|
|
9923
|
+
function TextControl({
|
|
9924
|
+
field,
|
|
9925
|
+
value,
|
|
9926
|
+
onChange,
|
|
9927
|
+
onClose
|
|
9928
|
+
}) {
|
|
9929
|
+
const [draft, setDraft] = (0, import_react53.useState)(value);
|
|
9930
|
+
(0, import_react53.useEffect)(() => setDraft(value), [value]);
|
|
9931
|
+
return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: "flex flex-col gap-2.5", children: [
|
|
9932
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
|
|
9933
|
+
"input",
|
|
9934
|
+
{
|
|
9935
|
+
type: "text",
|
|
9936
|
+
placeholder: field.placeholder ?? "Type a value\u2026",
|
|
9937
|
+
value: draft,
|
|
9938
|
+
onChange: (e) => setDraft(e.target.value),
|
|
9939
|
+
onKeyDown: (e) => {
|
|
9940
|
+
if (e.key === "Enter") {
|
|
9941
|
+
onChange(draft);
|
|
9942
|
+
onClose();
|
|
9943
|
+
}
|
|
9944
|
+
},
|
|
9945
|
+
className: controlClass({ size: "sm" }, "w-full")
|
|
9946
|
+
}
|
|
9947
|
+
),
|
|
9948
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
|
|
9949
|
+
ApplyClear,
|
|
9950
|
+
{
|
|
9951
|
+
onClear: () => {
|
|
9952
|
+
setDraft("");
|
|
9953
|
+
onChange("");
|
|
9954
|
+
onClose();
|
|
9955
|
+
},
|
|
9956
|
+
onApply: () => {
|
|
9957
|
+
onChange(draft);
|
|
9958
|
+
onClose();
|
|
9959
|
+
}
|
|
9887
9960
|
}
|
|
9888
9961
|
)
|
|
9889
|
-
] })
|
|
9962
|
+
] });
|
|
9963
|
+
}
|
|
9964
|
+
function DateRangeControl({
|
|
9965
|
+
field,
|
|
9966
|
+
value,
|
|
9967
|
+
onChange,
|
|
9968
|
+
onClose
|
|
9969
|
+
}) {
|
|
9970
|
+
const presets = field.presets ?? DEFAULT_PRESETS;
|
|
9971
|
+
const [from, setFrom] = (0, import_react53.useState)(value.from ?? "");
|
|
9972
|
+
const [to, setTo] = (0, import_react53.useState)(value.to ?? "");
|
|
9973
|
+
return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: "flex flex-col gap-1", children: [
|
|
9974
|
+
presets.map((preset) => {
|
|
9975
|
+
const isSelected = value.preset === preset.id;
|
|
9976
|
+
return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)(
|
|
9977
|
+
"button",
|
|
9978
|
+
{
|
|
9979
|
+
type: "button",
|
|
9980
|
+
onClick: () => {
|
|
9981
|
+
if (preset.id === "custom") {
|
|
9982
|
+
onChange({ preset: "custom", from, to });
|
|
9983
|
+
} else {
|
|
9984
|
+
onChange({ preset: preset.id });
|
|
9985
|
+
onClose();
|
|
9986
|
+
}
|
|
9987
|
+
},
|
|
9988
|
+
className: cn(
|
|
9989
|
+
"flex w-full items-center justify-between rounded-lg px-2.5 py-1.5 text-left text-sm transition-colors outline-none",
|
|
9990
|
+
isSelected ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted/50 hover:text-foreground"
|
|
9991
|
+
),
|
|
9992
|
+
children: [
|
|
9993
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { children: preset.label }),
|
|
9994
|
+
preset.hint && /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "text-xs text-muted-foreground/70", children: preset.hint })
|
|
9995
|
+
]
|
|
9996
|
+
},
|
|
9997
|
+
preset.id
|
|
9998
|
+
);
|
|
9999
|
+
}),
|
|
10000
|
+
value.preset === "custom" && /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: "mt-2 flex flex-col gap-2 border-t border-border/40 pt-2", children: [
|
|
10001
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
10002
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
|
|
10003
|
+
"input",
|
|
10004
|
+
{
|
|
10005
|
+
type: "date",
|
|
10006
|
+
value: from,
|
|
10007
|
+
onChange: (e) => setFrom(e.target.value),
|
|
10008
|
+
className: controlClass({ size: "sm" }, "w-full text-xs")
|
|
10009
|
+
}
|
|
10010
|
+
),
|
|
10011
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsx)("span", { className: "text-xs text-muted-foreground", children: "to" }),
|
|
10012
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
|
|
10013
|
+
"input",
|
|
10014
|
+
{
|
|
10015
|
+
type: "date",
|
|
10016
|
+
value: to,
|
|
10017
|
+
onChange: (e) => setTo(e.target.value),
|
|
10018
|
+
className: controlClass({ size: "sm" }, "w-full text-xs")
|
|
10019
|
+
}
|
|
10020
|
+
)
|
|
10021
|
+
] }),
|
|
10022
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsx)("div", { className: "flex justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
|
|
10023
|
+
Button,
|
|
10024
|
+
{
|
|
10025
|
+
color: "primary",
|
|
10026
|
+
size: "sm",
|
|
10027
|
+
className: "h-8 px-3",
|
|
10028
|
+
onClick: () => {
|
|
10029
|
+
onChange({ preset: "custom", from, to });
|
|
10030
|
+
onClose();
|
|
10031
|
+
},
|
|
10032
|
+
children: "Apply"
|
|
10033
|
+
}
|
|
10034
|
+
) })
|
|
10035
|
+
] })
|
|
10036
|
+
] });
|
|
10037
|
+
}
|
|
10038
|
+
function NumericControl({
|
|
10039
|
+
field,
|
|
10040
|
+
value,
|
|
10041
|
+
onChange,
|
|
10042
|
+
onClose
|
|
10043
|
+
}) {
|
|
10044
|
+
const operators = field.operators ?? DEFAULT_OPERATORS;
|
|
10045
|
+
const [operator, setOperator] = (0, import_react53.useState)(value.operator);
|
|
10046
|
+
const [draft, setDraft] = (0, import_react53.useState)(value.value);
|
|
10047
|
+
(0, import_react53.useEffect)(() => {
|
|
10048
|
+
setOperator(value.operator);
|
|
10049
|
+
setDraft(value.value);
|
|
10050
|
+
}, [value.operator, value.value]);
|
|
10051
|
+
return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: "flex flex-col gap-2.5", children: [
|
|
10052
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
10053
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsxs)(Select, { value: operator, onValueChange: (v) => setOperator(v), children: [
|
|
10054
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsx)(SelectTrigger, { size: "sm", className: "shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(SelectValue, {}) }),
|
|
10055
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsx)(SelectContent, { children: operators.map((op) => /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(SelectItem, { value: op.id, children: op.label }, op.id)) })
|
|
10056
|
+
] }),
|
|
10057
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
|
|
10058
|
+
"input",
|
|
10059
|
+
{
|
|
10060
|
+
type: "text",
|
|
10061
|
+
inputMode: "decimal",
|
|
10062
|
+
placeholder: field.placeholder ?? "0.00",
|
|
10063
|
+
value: draft,
|
|
10064
|
+
onChange: (e) => setDraft(e.target.value),
|
|
10065
|
+
onKeyDown: (e) => {
|
|
10066
|
+
if (e.key === "Enter") {
|
|
10067
|
+
onChange(draft ? { operator, value: draft } : null);
|
|
10068
|
+
onClose();
|
|
10069
|
+
}
|
|
10070
|
+
},
|
|
10071
|
+
className: controlClass({ size: "sm" }, "min-w-0 flex-1")
|
|
10072
|
+
}
|
|
10073
|
+
)
|
|
10074
|
+
] }),
|
|
10075
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
|
|
10076
|
+
ApplyClear,
|
|
10077
|
+
{
|
|
10078
|
+
onClear: () => {
|
|
10079
|
+
setDraft("");
|
|
10080
|
+
onChange(null);
|
|
10081
|
+
onClose();
|
|
10082
|
+
},
|
|
10083
|
+
onApply: () => {
|
|
10084
|
+
onChange(draft ? { operator, value: draft } : null);
|
|
10085
|
+
onClose();
|
|
10086
|
+
}
|
|
10087
|
+
}
|
|
10088
|
+
)
|
|
10089
|
+
] });
|
|
10090
|
+
}
|
|
10091
|
+
function ApplyClear({ onClear, onApply }) {
|
|
10092
|
+
return /* @__PURE__ */ (0, import_jsx_runtime88.jsxs)("div", { className: "flex items-center justify-end gap-2 border-t border-border/40 pt-1", children: [
|
|
10093
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
|
|
10094
|
+
Button,
|
|
10095
|
+
{
|
|
10096
|
+
variant: "ghost",
|
|
10097
|
+
size: "sm",
|
|
10098
|
+
onClick: onClear,
|
|
10099
|
+
className: "h-8 px-3 text-muted-foreground hover:text-foreground",
|
|
10100
|
+
children: "Clear"
|
|
10101
|
+
}
|
|
10102
|
+
),
|
|
10103
|
+
/* @__PURE__ */ (0, import_jsx_runtime88.jsx)(Button, { color: "primary", size: "sm", onClick: onApply, className: "h-8 px-3", children: "Apply" })
|
|
10104
|
+
] });
|
|
9890
10105
|
}
|
|
9891
10106
|
|
|
9892
10107
|
// src/app/data/DataTable.tsx
|
|
9893
10108
|
var import_react54 = require("react");
|
|
9894
|
-
var
|
|
10109
|
+
var import_lucide_react19 = require("lucide-react");
|
|
9895
10110
|
|
|
9896
10111
|
// src/ui/skeleton.tsx
|
|
9897
|
-
var
|
|
10112
|
+
var import_jsx_runtime89 = require("react/jsx-runtime");
|
|
9898
10113
|
function Skeleton({ className, ...props }) {
|
|
9899
|
-
return /* @__PURE__ */ (0,
|
|
10114
|
+
return /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(
|
|
9900
10115
|
"div",
|
|
9901
10116
|
{
|
|
9902
10117
|
"data-slot": "skeleton",
|
|
@@ -9907,7 +10122,7 @@ function Skeleton({ className, ...props }) {
|
|
|
9907
10122
|
}
|
|
9908
10123
|
|
|
9909
10124
|
// src/app/data/DataTable.tsx
|
|
9910
|
-
var
|
|
10125
|
+
var import_jsx_runtime90 = require("react/jsx-runtime");
|
|
9911
10126
|
var shellClass2 = "w-full";
|
|
9912
10127
|
var tableClass = "w-full border-separate border-spacing-0 bg-transparent text-sm";
|
|
9913
10128
|
var headRowClass = "";
|
|
@@ -9950,12 +10165,12 @@ function SortIndicator({
|
|
|
9950
10165
|
}) {
|
|
9951
10166
|
const iconClass = "size-3.5 shrink-0 opacity-60 group-hover:opacity-100";
|
|
9952
10167
|
if (!active) {
|
|
9953
|
-
return /* @__PURE__ */ (0,
|
|
10168
|
+
return /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(import_lucide_react19.ArrowUpDownIcon, { className: iconClass, "aria-hidden": true });
|
|
9954
10169
|
}
|
|
9955
10170
|
if (direction === "desc") {
|
|
9956
|
-
return /* @__PURE__ */ (0,
|
|
10171
|
+
return /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(import_lucide_react19.ArrowDownIcon, { className: iconClass, "aria-hidden": true });
|
|
9957
10172
|
}
|
|
9958
|
-
return /* @__PURE__ */ (0,
|
|
10173
|
+
return /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(import_lucide_react19.ArrowUpIcon, { className: iconClass, "aria-hidden": true });
|
|
9959
10174
|
}
|
|
9960
10175
|
function DataTable({
|
|
9961
10176
|
columns,
|
|
@@ -10053,7 +10268,7 @@ function DataTable({
|
|
|
10053
10268
|
const headPad = dense ? "px-3 py-2" : void 0;
|
|
10054
10269
|
const colSpan = columns.length + (selectable ? 1 : 0);
|
|
10055
10270
|
if (!loading && rows.length === 0 && emptyMode === "replace") {
|
|
10056
|
-
return /* @__PURE__ */ (0,
|
|
10271
|
+
return /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(EmptyState, { title: emptyTitle, description: emptyDescription, className });
|
|
10057
10272
|
}
|
|
10058
10273
|
const allKeys = sortedRows.map(getRowKey);
|
|
10059
10274
|
const allSelected = allKeys.length > 0 && allKeys.every((k) => selectedSet.has(k));
|
|
@@ -10078,10 +10293,10 @@ function DataTable({
|
|
|
10078
10293
|
const hasPager = paginated && !loading && sortedRows.length > 0;
|
|
10079
10294
|
const hasFoot = (showRowCount || footer || hasPager) && (loading || sortedRows.length > 0);
|
|
10080
10295
|
const skeletonCount = loadingRows ?? pageSize ?? 5;
|
|
10081
|
-
return /* @__PURE__ */ (0,
|
|
10082
|
-
caption ? /* @__PURE__ */ (0,
|
|
10083
|
-
/* @__PURE__ */ (0,
|
|
10084
|
-
selectable ? /* @__PURE__ */ (0,
|
|
10296
|
+
return /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("div", { className: cn("aui-app-data-table", shellClass2, className), children: /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("div", { className: "overflow-x-auto", children: /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("table", { className: tableClass, children: [
|
|
10297
|
+
caption ? /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("caption", { className: "sr-only", children: caption }) : null,
|
|
10298
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsx)("thead", { className: cn(headRowClass, stickyHeader && stickyHeadClass), children: /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("tr", { children: [
|
|
10299
|
+
selectable ? /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("th", { scope: "col", className: cn(selectCellClass, headPad), children: /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
|
|
10085
10300
|
Checkbox,
|
|
10086
10301
|
{
|
|
10087
10302
|
checked: headerCheckedState,
|
|
@@ -10093,19 +10308,19 @@ function DataTable({
|
|
|
10093
10308
|
columns.map((col) => {
|
|
10094
10309
|
const isSorted = sort?.columnId === col.id;
|
|
10095
10310
|
const ariaSort = col.sortable ? isSorted ? sort.direction === "asc" ? "ascending" : "descending" : "none" : void 0;
|
|
10096
|
-
const headerContent = col.sortable ? /* @__PURE__ */ (0,
|
|
10311
|
+
const headerContent = col.sortable ? /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)(
|
|
10097
10312
|
"button",
|
|
10098
10313
|
{
|
|
10099
10314
|
type: "button",
|
|
10100
10315
|
className: sortButtonClass,
|
|
10101
10316
|
onClick: () => setSort(nextSort(sort, col.id)),
|
|
10102
10317
|
children: [
|
|
10103
|
-
/* @__PURE__ */ (0,
|
|
10104
|
-
/* @__PURE__ */ (0,
|
|
10318
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsx)("span", { className: "truncate", children: col.header }),
|
|
10319
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsx)(SortIndicator, { active: Boolean(isSorted), direction: sort?.direction })
|
|
10105
10320
|
]
|
|
10106
10321
|
}
|
|
10107
10322
|
) : col.header;
|
|
10108
|
-
return /* @__PURE__ */ (0,
|
|
10323
|
+
return /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
|
|
10109
10324
|
"th",
|
|
10110
10325
|
{
|
|
10111
10326
|
scope: "col",
|
|
@@ -10122,9 +10337,9 @@ function DataTable({
|
|
|
10122
10337
|
);
|
|
10123
10338
|
})
|
|
10124
10339
|
] }) }),
|
|
10125
|
-
/* @__PURE__ */ (0,
|
|
10126
|
-
selectable ? /* @__PURE__ */ (0,
|
|
10127
|
-
columns.map((col) => /* @__PURE__ */ (0,
|
|
10340
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsx)("tbody", { className: cn(!hasFoot && "[&_tr:last-child_td]:border-b-0"), children: loading ? Array.from({ length: skeletonCount }).map((_, rowIdx) => /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("tr", { className: rowClass, "aria-hidden": true, children: [
|
|
10341
|
+
selectable ? /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("td", { className: cn(selectCellClass, cellPad), children: /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(Skeleton, { className: "size-4 rounded-[4px]" }) }) : null,
|
|
10342
|
+
columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
|
|
10128
10343
|
"td",
|
|
10129
10344
|
{
|
|
10130
10345
|
className: cn(
|
|
@@ -10133,17 +10348,17 @@ function DataTable({
|
|
|
10133
10348
|
col.align && alignClass[col.align],
|
|
10134
10349
|
col.className
|
|
10135
10350
|
),
|
|
10136
|
-
children: /* @__PURE__ */ (0,
|
|
10351
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(Skeleton, { className: "h-4 w-[60%]" })
|
|
10137
10352
|
},
|
|
10138
10353
|
col.id
|
|
10139
10354
|
))
|
|
10140
|
-
] }, `skeleton-${rowIdx}`)) : visibleRows.length === 0 ? /* @__PURE__ */ (0,
|
|
10141
|
-
/* @__PURE__ */ (0,
|
|
10142
|
-
emptyDescription ? /* @__PURE__ */ (0,
|
|
10355
|
+
] }, `skeleton-${rowIdx}`)) : visibleRows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("td", { colSpan, className: emptyCellClass, children: /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("div", { className: "flex flex-col items-center gap-1", children: [
|
|
10356
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsx)("p", { className: "font-medium text-foreground", children: emptyTitle }),
|
|
10357
|
+
emptyDescription ? /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("p", { className: "max-w-sm text-muted-foreground", children: emptyDescription }) : null
|
|
10143
10358
|
] }) }) }) : visibleRows.map((row) => {
|
|
10144
10359
|
const key = getRowKey(row);
|
|
10145
10360
|
const isSelected = selectedSet.has(key);
|
|
10146
|
-
return /* @__PURE__ */ (0,
|
|
10361
|
+
return /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)(
|
|
10147
10362
|
"tr",
|
|
10148
10363
|
{
|
|
10149
10364
|
className: rowClass,
|
|
@@ -10159,12 +10374,12 @@ function DataTable({
|
|
|
10159
10374
|
tabIndex: onRowClick ? 0 : void 0,
|
|
10160
10375
|
role: onRowClick ? "button" : void 0,
|
|
10161
10376
|
children: [
|
|
10162
|
-
selectable ? /* @__PURE__ */ (0,
|
|
10377
|
+
selectable ? /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
|
|
10163
10378
|
"td",
|
|
10164
10379
|
{
|
|
10165
10380
|
className: cn(selectCellClass, cellPad),
|
|
10166
10381
|
onClick: (event) => event.stopPropagation(),
|
|
10167
|
-
children: /* @__PURE__ */ (0,
|
|
10382
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
|
|
10168
10383
|
Checkbox,
|
|
10169
10384
|
{
|
|
10170
10385
|
checked: isSelected,
|
|
@@ -10174,7 +10389,7 @@ function DataTable({
|
|
|
10174
10389
|
)
|
|
10175
10390
|
}
|
|
10176
10391
|
) : null,
|
|
10177
|
-
columns.map((col) => /* @__PURE__ */ (0,
|
|
10392
|
+
columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
|
|
10178
10393
|
"td",
|
|
10179
10394
|
{
|
|
10180
10395
|
className: cn(
|
|
@@ -10184,7 +10399,7 @@ function DataTable({
|
|
|
10184
10399
|
col.align && alignClass[col.align],
|
|
10185
10400
|
col.className
|
|
10186
10401
|
),
|
|
10187
|
-
children: col.truncate ? /* @__PURE__ */ (0,
|
|
10402
|
+
children: col.truncate ? /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("div", { className: "truncate", children: col.cell(row) }) : col.cell(row)
|
|
10188
10403
|
},
|
|
10189
10404
|
col.id
|
|
10190
10405
|
))
|
|
@@ -10193,7 +10408,7 @@ function DataTable({
|
|
|
10193
10408
|
key
|
|
10194
10409
|
);
|
|
10195
10410
|
}) }),
|
|
10196
|
-
hasFoot ? /* @__PURE__ */ (0,
|
|
10411
|
+
hasFoot ? /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("tfoot", { children: /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("td", { colSpan, className: footCellClass, children: /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)(
|
|
10197
10412
|
"div",
|
|
10198
10413
|
{
|
|
10199
10414
|
className: cn(
|
|
@@ -10201,18 +10416,18 @@ function DataTable({
|
|
|
10201
10416
|
(showRowCount || footer || hasPager) && "justify-between"
|
|
10202
10417
|
),
|
|
10203
10418
|
children: [
|
|
10204
|
-
/* @__PURE__ */ (0,
|
|
10205
|
-
showRowCount ? /* @__PURE__ */ (0,
|
|
10419
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("div", { className: footInnerClass, children: [
|
|
10420
|
+
showRowCount ? /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("span", { children: [
|
|
10206
10421
|
rowCountText,
|
|
10207
10422
|
selectable && selectedSet.size > 0 ? ` \xB7 ${selectedSet.size} selected` : null
|
|
10208
|
-
] }) : selectable && selectedSet.size > 0 ? /* @__PURE__ */ (0,
|
|
10423
|
+
] }) : selectable && selectedSet.size > 0 ? /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("span", { children: [
|
|
10209
10424
|
selectedSet.size,
|
|
10210
10425
|
" selected"
|
|
10211
10426
|
] }) : null,
|
|
10212
10427
|
footer
|
|
10213
10428
|
] }),
|
|
10214
|
-
hasPager ? /* @__PURE__ */ (0,
|
|
10215
|
-
/* @__PURE__ */ (0,
|
|
10429
|
+
hasPager ? /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
10430
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("span", { className: "tabular-nums", children: [
|
|
10216
10431
|
pageIndex * pageSize + 1,
|
|
10217
10432
|
"\u2013",
|
|
10218
10433
|
Math.min(
|
|
@@ -10223,8 +10438,8 @@ function DataTable({
|
|
|
10223
10438
|
"of ",
|
|
10224
10439
|
sortedRows.length
|
|
10225
10440
|
] }),
|
|
10226
|
-
/* @__PURE__ */ (0,
|
|
10227
|
-
/* @__PURE__ */ (0,
|
|
10441
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
10442
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
|
|
10228
10443
|
"button",
|
|
10229
10444
|
{
|
|
10230
10445
|
type: "button",
|
|
@@ -10232,10 +10447,10 @@ function DataTable({
|
|
|
10232
10447
|
onClick: () => setPage(pageIndex - 1),
|
|
10233
10448
|
disabled: pageIndex <= 0,
|
|
10234
10449
|
"aria-label": "Previous page",
|
|
10235
|
-
children: /* @__PURE__ */ (0,
|
|
10450
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(import_lucide_react19.ChevronLeftIcon, { className: "size-4", "aria-hidden": true })
|
|
10236
10451
|
}
|
|
10237
10452
|
),
|
|
10238
|
-
/* @__PURE__ */ (0,
|
|
10453
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
|
|
10239
10454
|
"button",
|
|
10240
10455
|
{
|
|
10241
10456
|
type: "button",
|
|
@@ -10243,7 +10458,7 @@ function DataTable({
|
|
|
10243
10458
|
onClick: () => setPage(pageIndex + 1),
|
|
10244
10459
|
disabled: pageIndex >= pageCount - 1,
|
|
10245
10460
|
"aria-label": "Next page",
|
|
10246
|
-
children: /* @__PURE__ */ (0,
|
|
10461
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(import_lucide_react19.ChevronRightIcon, { className: "size-4", "aria-hidden": true })
|
|
10247
10462
|
}
|
|
10248
10463
|
)
|
|
10249
10464
|
] })
|
|
@@ -10256,7 +10471,7 @@ function DataTable({
|
|
|
10256
10471
|
|
|
10257
10472
|
// src/app/data/ChartPanel.tsx
|
|
10258
10473
|
var import_react55 = require("react");
|
|
10259
|
-
var
|
|
10474
|
+
var import_jsx_runtime91 = require("react/jsx-runtime");
|
|
10260
10475
|
var ChartPanel = ({
|
|
10261
10476
|
title,
|
|
10262
10477
|
description,
|
|
@@ -10274,14 +10489,14 @@ var ChartPanel = ({
|
|
|
10274
10489
|
const titleId = (0, import_react55.useId)();
|
|
10275
10490
|
const resolvedTitle = title ?? artifact?.title;
|
|
10276
10491
|
const hasHeader = Boolean(resolvedTitle || description || actions);
|
|
10277
|
-
const body = loading ? /* @__PURE__ */ (0,
|
|
10278
|
-
return /* @__PURE__ */ (0,
|
|
10492
|
+
const body = loading ? /* @__PURE__ */ (0, import_jsx_runtime91.jsx)(Skeleton, { className: "w-full rounded-lg", style: { height }, "aria-hidden": true }) : children ?? (artifact ? /* @__PURE__ */ (0, import_jsx_runtime91.jsx)(ChartArtifactView, { artifact, embedded: true, height }) : null);
|
|
10493
|
+
return /* @__PURE__ */ (0, import_jsx_runtime91.jsxs)(
|
|
10279
10494
|
"section",
|
|
10280
10495
|
{
|
|
10281
10496
|
className: cn(metricCardShellClass, "aui-app-chart-panel", className),
|
|
10282
10497
|
"aria-labelledby": resolvedTitle ? titleId : void 0,
|
|
10283
10498
|
children: [
|
|
10284
|
-
/* @__PURE__ */ (0,
|
|
10499
|
+
/* @__PURE__ */ (0, import_jsx_runtime91.jsx)(
|
|
10285
10500
|
MetricCardHeader,
|
|
10286
10501
|
{
|
|
10287
10502
|
title: resolvedTitle,
|
|
@@ -10290,14 +10505,14 @@ var ChartPanel = ({
|
|
|
10290
10505
|
actions
|
|
10291
10506
|
}
|
|
10292
10507
|
),
|
|
10293
|
-
/* @__PURE__ */ (0,
|
|
10508
|
+
/* @__PURE__ */ (0, import_jsx_runtime91.jsx)(
|
|
10294
10509
|
"div",
|
|
10295
10510
|
{
|
|
10296
10511
|
className: cn(
|
|
10297
10512
|
"relative min-h-0 w-full",
|
|
10298
10513
|
hasHeader ? metricChartPlotRegionClass : chartPanelBodyClass
|
|
10299
10514
|
),
|
|
10300
|
-
children: body ?? /* @__PURE__ */ (0,
|
|
10515
|
+
children: body ?? /* @__PURE__ */ (0, import_jsx_runtime91.jsx)(
|
|
10301
10516
|
"div",
|
|
10302
10517
|
{
|
|
10303
10518
|
className: "flex items-center justify-center text-sm font-normal text-muted-foreground",
|
|
@@ -10315,7 +10530,7 @@ var ChartPanel = ({
|
|
|
10315
10530
|
|
|
10316
10531
|
// src/app/data/MetricRow.tsx
|
|
10317
10532
|
var import_react56 = require("react");
|
|
10318
|
-
var
|
|
10533
|
+
var import_jsx_runtime92 = require("react/jsx-runtime");
|
|
10319
10534
|
var MetricRow = ({
|
|
10320
10535
|
title,
|
|
10321
10536
|
titleTag,
|
|
@@ -10341,13 +10556,13 @@ var MetricRow = ({
|
|
|
10341
10556
|
onMetricChange?.(id);
|
|
10342
10557
|
};
|
|
10343
10558
|
const hasHeader = Boolean(title || titleTag || description || actions);
|
|
10344
|
-
return /* @__PURE__ */ (0,
|
|
10559
|
+
return /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)(
|
|
10345
10560
|
"section",
|
|
10346
10561
|
{
|
|
10347
10562
|
className: cn(metricCardShellClass, className),
|
|
10348
10563
|
"aria-labelledby": title ? titleId : void 0,
|
|
10349
10564
|
children: [
|
|
10350
|
-
/* @__PURE__ */ (0,
|
|
10565
|
+
/* @__PURE__ */ (0, import_jsx_runtime92.jsx)(
|
|
10351
10566
|
MetricCardHeader,
|
|
10352
10567
|
{
|
|
10353
10568
|
title,
|
|
@@ -10357,7 +10572,7 @@ var MetricRow = ({
|
|
|
10357
10572
|
actions
|
|
10358
10573
|
}
|
|
10359
10574
|
),
|
|
10360
|
-
/* @__PURE__ */ (0,
|
|
10575
|
+
/* @__PURE__ */ (0, import_jsx_runtime92.jsx)(
|
|
10361
10576
|
"div",
|
|
10362
10577
|
{
|
|
10363
10578
|
role: selectable ? "group" : void 0,
|
|
@@ -10368,18 +10583,18 @@ var MetricRow = ({
|
|
|
10368
10583
|
metricTilesGridColsClass(loading ? metrics.length || 4 : metrics.length),
|
|
10369
10584
|
hasHeader && "mt-3.5 border-t border-border/40"
|
|
10370
10585
|
),
|
|
10371
|
-
children: loading ? Array.from({ length: metrics.length || 4 }).map((_, index) => /* @__PURE__ */ (0,
|
|
10586
|
+
children: loading ? Array.from({ length: metrics.length || 4 }).map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime92.jsxs)(
|
|
10372
10587
|
"div",
|
|
10373
10588
|
{
|
|
10374
10589
|
className: cn("flex min-w-0 flex-1 flex-col gap-2", metricTileClass),
|
|
10375
10590
|
"aria-hidden": true,
|
|
10376
10591
|
children: [
|
|
10377
|
-
/* @__PURE__ */ (0,
|
|
10378
|
-
/* @__PURE__ */ (0,
|
|
10592
|
+
/* @__PURE__ */ (0, import_jsx_runtime92.jsx)(Skeleton, { className: "h-3 w-20" }),
|
|
10593
|
+
/* @__PURE__ */ (0, import_jsx_runtime92.jsx)(Skeleton, { className: "h-7 w-24" })
|
|
10379
10594
|
]
|
|
10380
10595
|
},
|
|
10381
10596
|
`skeleton-${index}`
|
|
10382
|
-
)) : metrics.map((m, index) => /* @__PURE__ */ (0,
|
|
10597
|
+
)) : metrics.map((m, index) => /* @__PURE__ */ (0, import_jsx_runtime92.jsx)(
|
|
10383
10598
|
MetricTile,
|
|
10384
10599
|
{
|
|
10385
10600
|
label: m.label,
|
|
@@ -10407,7 +10622,7 @@ var MetricRow = ({
|
|
|
10407
10622
|
|
|
10408
10623
|
// src/app/data/MetricChartCard.tsx
|
|
10409
10624
|
var import_react57 = require("react");
|
|
10410
|
-
var
|
|
10625
|
+
var import_jsx_runtime93 = require("react/jsx-runtime");
|
|
10411
10626
|
var MetricChartCard = ({
|
|
10412
10627
|
title,
|
|
10413
10628
|
titleTag,
|
|
@@ -10443,13 +10658,13 @@ var MetricChartCard = ({
|
|
|
10443
10658
|
};
|
|
10444
10659
|
const hasHeader = Boolean(title || titleTag || description || actions);
|
|
10445
10660
|
const chartAriaLabel = typeof active?.label === "string" ? `${active.label} over time` : "Metric chart";
|
|
10446
|
-
return /* @__PURE__ */ (0,
|
|
10661
|
+
return /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)(
|
|
10447
10662
|
"section",
|
|
10448
10663
|
{
|
|
10449
10664
|
className: cn(metricCardShellClass, className),
|
|
10450
10665
|
"aria-labelledby": title ? titleId : void 0,
|
|
10451
10666
|
children: [
|
|
10452
|
-
/* @__PURE__ */ (0,
|
|
10667
|
+
/* @__PURE__ */ (0, import_jsx_runtime93.jsx)(
|
|
10453
10668
|
MetricCardHeader,
|
|
10454
10669
|
{
|
|
10455
10670
|
title,
|
|
@@ -10459,7 +10674,7 @@ var MetricChartCard = ({
|
|
|
10459
10674
|
titleId
|
|
10460
10675
|
}
|
|
10461
10676
|
),
|
|
10462
|
-
/* @__PURE__ */ (0,
|
|
10677
|
+
/* @__PURE__ */ (0, import_jsx_runtime93.jsx)(
|
|
10463
10678
|
"div",
|
|
10464
10679
|
{
|
|
10465
10680
|
role: "group",
|
|
@@ -10470,18 +10685,18 @@ var MetricChartCard = ({
|
|
|
10470
10685
|
metricTilesGridColsClass(loading ? metrics.length || 4 : metrics.length),
|
|
10471
10686
|
hasHeader && "mt-3.5 border-t border-border/40"
|
|
10472
10687
|
),
|
|
10473
|
-
children: loading ? Array.from({ length: metrics.length || 4 }).map((_, index) => /* @__PURE__ */ (0,
|
|
10688
|
+
children: loading ? Array.from({ length: metrics.length || 4 }).map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime93.jsxs)(
|
|
10474
10689
|
"div",
|
|
10475
10690
|
{
|
|
10476
10691
|
className: cn("flex min-w-0 flex-1 flex-col gap-2", metricTileClass),
|
|
10477
10692
|
"aria-hidden": true,
|
|
10478
10693
|
children: [
|
|
10479
|
-
/* @__PURE__ */ (0,
|
|
10480
|
-
/* @__PURE__ */ (0,
|
|
10694
|
+
/* @__PURE__ */ (0, import_jsx_runtime93.jsx)(Skeleton, { className: "h-3 w-20" }),
|
|
10695
|
+
/* @__PURE__ */ (0, import_jsx_runtime93.jsx)(Skeleton, { className: "h-7 w-24" })
|
|
10481
10696
|
]
|
|
10482
10697
|
},
|
|
10483
10698
|
`skeleton-${index}`
|
|
10484
|
-
)) : metrics.map((m, index) => /* @__PURE__ */ (0,
|
|
10699
|
+
)) : metrics.map((m, index) => /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(
|
|
10485
10700
|
MetricTile,
|
|
10486
10701
|
{
|
|
10487
10702
|
label: m.label,
|
|
@@ -10502,14 +10717,14 @@ var MetricChartCard = ({
|
|
|
10502
10717
|
))
|
|
10503
10718
|
}
|
|
10504
10719
|
),
|
|
10505
|
-
/* @__PURE__ */ (0,
|
|
10720
|
+
/* @__PURE__ */ (0, import_jsx_runtime93.jsx)("div", { className: metricChartRegionClass, "aria-live": "polite", "aria-atomic": "true", children: loading ? /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(
|
|
10506
10721
|
Skeleton,
|
|
10507
10722
|
{
|
|
10508
10723
|
className: "w-full rounded-lg",
|
|
10509
10724
|
style: { height },
|
|
10510
10725
|
"aria-hidden": true
|
|
10511
10726
|
}
|
|
10512
|
-
) : active?.data && active.data.length > 0 ? /* @__PURE__ */ (0,
|
|
10727
|
+
) : active?.data && active.data.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(
|
|
10513
10728
|
LineAreaChart,
|
|
10514
10729
|
{
|
|
10515
10730
|
data: active.data,
|
|
@@ -10529,7 +10744,7 @@ var MetricChartCard = ({
|
|
|
10529
10744
|
ariaLabel: chartAriaLabel
|
|
10530
10745
|
},
|
|
10531
10746
|
active.id
|
|
10532
|
-
) : /* @__PURE__ */ (0,
|
|
10747
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(
|
|
10533
10748
|
"div",
|
|
10534
10749
|
{
|
|
10535
10750
|
className: "flex w-full items-center justify-center text-sm font-normal text-muted-foreground",
|
|
@@ -10635,8 +10850,8 @@ function useLiveQuery(fetcher, options = {}) {
|
|
|
10635
10850
|
|
|
10636
10851
|
// src/ui/untitled-button.tsx
|
|
10637
10852
|
var import_class_variance_authority2 = require("class-variance-authority");
|
|
10638
|
-
var
|
|
10639
|
-
var
|
|
10853
|
+
var import_radix_ui9 = require("radix-ui");
|
|
10854
|
+
var import_jsx_runtime94 = require("react/jsx-runtime");
|
|
10640
10855
|
var SOLID_SKEUOMORPHIC_SHADOW2 = "shadow-skeuomorphic-solid";
|
|
10641
10856
|
var BORDERED_SKEUOMORPHIC_SHADOW2 = "shadow-skeuomorphic-bordered";
|
|
10642
10857
|
var untitledButtonVariants = (0, import_class_variance_authority2.cva)(
|
|
@@ -10719,10 +10934,10 @@ var untitledButtonVariants = (0, import_class_variance_authority2.cva)(
|
|
|
10719
10934
|
)
|
|
10720
10935
|
},
|
|
10721
10936
|
size: {
|
|
10722
|
-
sm: "h-
|
|
10723
|
-
md: "h-
|
|
10724
|
-
lg: "h-
|
|
10725
|
-
xl: "h-
|
|
10937
|
+
sm: "h-8 gap-1 rounded-md px-2.5 text-xs",
|
|
10938
|
+
md: "h-9 gap-1.5 rounded-lg px-3 text-sm",
|
|
10939
|
+
lg: "h-10 gap-1.5 rounded-lg px-3.5 text-sm",
|
|
10940
|
+
xl: "h-11 gap-2 rounded-lg px-4 text-base"
|
|
10726
10941
|
}
|
|
10727
10942
|
},
|
|
10728
10943
|
defaultVariants: {
|
|
@@ -10747,8 +10962,8 @@ function UntitledButton({
|
|
|
10747
10962
|
const isDisabled = disabled || isLoading;
|
|
10748
10963
|
const classes = cn(untitledButtonVariants({ color, size }), className);
|
|
10749
10964
|
if (asChild) {
|
|
10750
|
-
return /* @__PURE__ */ (0,
|
|
10751
|
-
|
|
10965
|
+
return /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(
|
|
10966
|
+
import_radix_ui9.Slot.Root,
|
|
10752
10967
|
{
|
|
10753
10968
|
className: classes,
|
|
10754
10969
|
"aria-disabled": isDisabled ? true : void 0,
|
|
@@ -10758,7 +10973,7 @@ function UntitledButton({
|
|
|
10758
10973
|
}
|
|
10759
10974
|
);
|
|
10760
10975
|
}
|
|
10761
|
-
return /* @__PURE__ */ (0,
|
|
10976
|
+
return /* @__PURE__ */ (0, import_jsx_runtime94.jsxs)(
|
|
10762
10977
|
"button",
|
|
10763
10978
|
{
|
|
10764
10979
|
type,
|
|
@@ -10767,7 +10982,7 @@ function UntitledButton({
|
|
|
10767
10982
|
className: classes,
|
|
10768
10983
|
...props,
|
|
10769
10984
|
children: [
|
|
10770
|
-
isLoading ? /* @__PURE__ */ (0,
|
|
10985
|
+
isLoading ? /* @__PURE__ */ (0, import_jsx_runtime94.jsx)(
|
|
10771
10986
|
"span",
|
|
10772
10987
|
{
|
|
10773
10988
|
"aria-hidden": true,
|
|
@@ -10782,8 +10997,8 @@ function UntitledButton({
|
|
|
10782
10997
|
}
|
|
10783
10998
|
|
|
10784
10999
|
// src/ui/banner.tsx
|
|
10785
|
-
var
|
|
10786
|
-
var
|
|
11000
|
+
var import_lucide_react20 = require("lucide-react");
|
|
11001
|
+
var import_jsx_runtime95 = require("react/jsx-runtime");
|
|
10787
11002
|
var bannerSoftClass = {
|
|
10788
11003
|
default: "border-border/50 bg-muted/30 text-foreground/90 dark:bg-muted/15",
|
|
10789
11004
|
primary: "border-primary/15 bg-primary/5 text-primary-800 dark:text-primary-200 [&_[data-banner-icon]]:text-primary",
|
|
@@ -10828,7 +11043,7 @@ function Banner({
|
|
|
10828
11043
|
}) {
|
|
10829
11044
|
const isSolid = variant === "solid";
|
|
10830
11045
|
const isSingleLine = !title;
|
|
10831
|
-
return /* @__PURE__ */ (0,
|
|
11046
|
+
return /* @__PURE__ */ (0, import_jsx_runtime95.jsxs)(
|
|
10832
11047
|
"div",
|
|
10833
11048
|
{
|
|
10834
11049
|
"data-slot": "banner",
|
|
@@ -10843,7 +11058,7 @@ function Banner({
|
|
|
10843
11058
|
),
|
|
10844
11059
|
...props,
|
|
10845
11060
|
children: [
|
|
10846
|
-
icon ? /* @__PURE__ */ (0,
|
|
11061
|
+
icon ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(
|
|
10847
11062
|
"span",
|
|
10848
11063
|
{
|
|
10849
11064
|
"data-banner-icon": true,
|
|
@@ -10854,9 +11069,9 @@ function Banner({
|
|
|
10854
11069
|
children: icon
|
|
10855
11070
|
}
|
|
10856
11071
|
) : null,
|
|
10857
|
-
/* @__PURE__ */ (0,
|
|
10858
|
-
title ? /* @__PURE__ */ (0,
|
|
10859
|
-
children ? /* @__PURE__ */ (0,
|
|
11072
|
+
/* @__PURE__ */ (0, import_jsx_runtime95.jsxs)("div", { className: "min-w-0 flex-1", children: [
|
|
11073
|
+
title ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("p", { className: "font-medium tracking-tight", children: title }) : null,
|
|
11074
|
+
children ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(
|
|
10860
11075
|
"div",
|
|
10861
11076
|
{
|
|
10862
11077
|
className: cn(
|
|
@@ -10867,8 +11082,8 @@ function Banner({
|
|
|
10867
11082
|
}
|
|
10868
11083
|
) : null
|
|
10869
11084
|
] }),
|
|
10870
|
-
actions ? /* @__PURE__ */ (0,
|
|
10871
|
-
onDismiss ? /* @__PURE__ */ (0,
|
|
11085
|
+
actions ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)("div", { className: "flex shrink-0 items-center gap-2", children: actions }) : null,
|
|
11086
|
+
onDismiss ? /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(
|
|
10872
11087
|
"button",
|
|
10873
11088
|
{
|
|
10874
11089
|
type: "button",
|
|
@@ -10879,7 +11094,7 @@ function Banner({
|
|
|
10879
11094
|
isSingleLine ? "self-center" : "-mt-0.5",
|
|
10880
11095
|
isSolid ? "opacity-80 hover:bg-background/15 hover:opacity-100" : "text-muted-foreground hover:bg-foreground/10 hover:text-foreground"
|
|
10881
11096
|
),
|
|
10882
|
-
children: /* @__PURE__ */ (0,
|
|
11097
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime95.jsx)(import_lucide_react20.XIcon, { className: "size-4", "aria-hidden": true })
|
|
10883
11098
|
}
|
|
10884
11099
|
) : null
|
|
10885
11100
|
]
|
|
@@ -10888,7 +11103,7 @@ function Banner({
|
|
|
10888
11103
|
}
|
|
10889
11104
|
|
|
10890
11105
|
// src/ui/timeline.tsx
|
|
10891
|
-
var
|
|
11106
|
+
var import_jsx_runtime96 = require("react/jsx-runtime");
|
|
10892
11107
|
var timelineRowGap = {
|
|
10893
11108
|
sm: "pb-4",
|
|
10894
11109
|
default: "pb-6"
|
|
@@ -10921,16 +11136,16 @@ var toneStyles = {
|
|
|
10921
11136
|
}
|
|
10922
11137
|
};
|
|
10923
11138
|
function Timeline({ items, size = "default", className, ...props }) {
|
|
10924
|
-
return /* @__PURE__ */ (0,
|
|
11139
|
+
return /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("ol", { "data-slot": "timeline", className: cn("flex flex-col", className), ...props, children: items.map((item, index) => {
|
|
10925
11140
|
const last = index === items.length - 1;
|
|
10926
11141
|
const tone = item.tone ?? "default";
|
|
10927
11142
|
const styles = toneStyles[tone];
|
|
10928
|
-
return /* @__PURE__ */ (0,
|
|
11143
|
+
return /* @__PURE__ */ (0, import_jsx_runtime96.jsxs)(
|
|
10929
11144
|
"li",
|
|
10930
11145
|
{
|
|
10931
11146
|
className: cn("relative flex gap-3.5 last:pb-0", timelineRowGap[size]),
|
|
10932
11147
|
children: [
|
|
10933
|
-
!last ? /* @__PURE__ */ (0,
|
|
11148
|
+
!last ? /* @__PURE__ */ (0, import_jsx_runtime96.jsx)(
|
|
10934
11149
|
"span",
|
|
10935
11150
|
{
|
|
10936
11151
|
"aria-hidden": true,
|
|
@@ -10940,7 +11155,7 @@ function Timeline({ items, size = "default", className, ...props }) {
|
|
|
10940
11155
|
)
|
|
10941
11156
|
}
|
|
10942
11157
|
) : null,
|
|
10943
|
-
/* @__PURE__ */ (0,
|
|
11158
|
+
/* @__PURE__ */ (0, import_jsx_runtime96.jsx)("div", { className: "relative flex w-5 shrink-0 justify-center pt-0.5", children: /* @__PURE__ */ (0, import_jsx_runtime96.jsx)(
|
|
10944
11159
|
"span",
|
|
10945
11160
|
{
|
|
10946
11161
|
className: cn(
|
|
@@ -10948,7 +11163,7 @@ function Timeline({ items, size = "default", className, ...props }) {
|
|
|
10948
11163
|
styles.border,
|
|
10949
11164
|
item.icon ? "size-6" : "size-4"
|
|
10950
11165
|
),
|
|
10951
|
-
children: item.icon ? /* @__PURE__ */ (0,
|
|
11166
|
+
children: item.icon ? /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("div", { className: cn("text-xs", styles.icon), children: item.icon }) : /* @__PURE__ */ (0, import_jsx_runtime96.jsx)(
|
|
10952
11167
|
"span",
|
|
10953
11168
|
{
|
|
10954
11169
|
className: cn(
|
|
@@ -10959,12 +11174,12 @@ function Timeline({ items, size = "default", className, ...props }) {
|
|
|
10959
11174
|
)
|
|
10960
11175
|
}
|
|
10961
11176
|
) }),
|
|
10962
|
-
/* @__PURE__ */ (0,
|
|
10963
|
-
/* @__PURE__ */ (0,
|
|
10964
|
-
/* @__PURE__ */ (0,
|
|
10965
|
-
item.meta ? /* @__PURE__ */ (0,
|
|
11177
|
+
/* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("div", { className: "min-w-0 flex-1 pb-0.5", children: [
|
|
11178
|
+
/* @__PURE__ */ (0, import_jsx_runtime96.jsxs)("div", { className: "flex items-start justify-between gap-2", children: [
|
|
11179
|
+
/* @__PURE__ */ (0, import_jsx_runtime96.jsx)("p", { className: "text-sm font-normal text-foreground", children: item.title }),
|
|
11180
|
+
item.meta ? /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("span", { className: "shrink-0 text-xs text-muted-foreground tabular-nums", children: item.meta }) : null
|
|
10966
11181
|
] }),
|
|
10967
|
-
item.description ? /* @__PURE__ */ (0,
|
|
11182
|
+
item.description ? /* @__PURE__ */ (0, import_jsx_runtime96.jsx)("p", { className: "mt-0.5 text-[13px] leading-relaxed text-muted-foreground", children: item.description }) : null
|
|
10968
11183
|
] })
|
|
10969
11184
|
]
|
|
10970
11185
|
},
|
|
@@ -10978,8 +11193,8 @@ var React5 = __toESM(require("react"), 1);
|
|
|
10978
11193
|
var import_core2 = require("@dnd-kit/core");
|
|
10979
11194
|
var import_sortable = require("@dnd-kit/sortable");
|
|
10980
11195
|
var import_utilities = require("@dnd-kit/utilities");
|
|
10981
|
-
var
|
|
10982
|
-
var
|
|
11196
|
+
var import_lucide_react21 = require("lucide-react");
|
|
11197
|
+
var import_jsx_runtime97 = require("react/jsx-runtime");
|
|
10983
11198
|
var columnTitleToneClass = {
|
|
10984
11199
|
default: "text-foreground",
|
|
10985
11200
|
primary: "text-blue-600 dark:text-blue-400",
|
|
@@ -11041,7 +11256,7 @@ function SortableCard({
|
|
|
11041
11256
|
transition
|
|
11042
11257
|
};
|
|
11043
11258
|
const dragHandleProps = disabled ? void 0 : { ...attributes, ...listeners };
|
|
11044
|
-
return /* @__PURE__ */ (0,
|
|
11259
|
+
return /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)(
|
|
11045
11260
|
"div",
|
|
11046
11261
|
{
|
|
11047
11262
|
ref: setNodeRef,
|
|
@@ -11056,7 +11271,7 @@ function SortableCard({
|
|
|
11056
11271
|
className
|
|
11057
11272
|
),
|
|
11058
11273
|
children: [
|
|
11059
|
-
!disabled && dragHandle === "auto" ? /* @__PURE__ */ (0,
|
|
11274
|
+
!disabled && dragHandle === "auto" ? /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(
|
|
11060
11275
|
"button",
|
|
11061
11276
|
{
|
|
11062
11277
|
type: "button",
|
|
@@ -11064,7 +11279,7 @@ function SortableCard({
|
|
|
11064
11279
|
className: "absolute right-1.5 top-1.5 z-10 grid size-6 cursor-grab touch-none place-items-center rounded-md text-muted-foreground/40 opacity-0 transition hover:bg-foreground/5 hover:text-foreground focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 group-hover/kanban-card:opacity-100 active:cursor-grabbing",
|
|
11065
11280
|
...attributes,
|
|
11066
11281
|
...listeners,
|
|
11067
|
-
children: /* @__PURE__ */ (0,
|
|
11282
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(import_lucide_react21.GripVerticalIcon, { className: "size-4", "aria-hidden": true })
|
|
11068
11283
|
}
|
|
11069
11284
|
) : null,
|
|
11070
11285
|
renderCard(card, { column, isDragging, isOverlay: false, dragHandleProps })
|
|
@@ -11088,7 +11303,7 @@ function KanbanColumnView({
|
|
|
11088
11303
|
}) {
|
|
11089
11304
|
const tone = column.tone ?? "default";
|
|
11090
11305
|
const { setNodeRef, isOver } = (0, import_core2.useDroppable)({ id: column.id, disabled });
|
|
11091
|
-
return /* @__PURE__ */ (0,
|
|
11306
|
+
return /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)(
|
|
11092
11307
|
"div",
|
|
11093
11308
|
{
|
|
11094
11309
|
"data-slot": "kanban-column",
|
|
@@ -11098,9 +11313,9 @@ function KanbanColumnView({
|
|
|
11098
11313
|
className
|
|
11099
11314
|
),
|
|
11100
11315
|
children: [
|
|
11101
|
-
renderColumnHeader ? renderColumnHeader(column) : /* @__PURE__ */ (0,
|
|
11102
|
-
/* @__PURE__ */ (0,
|
|
11103
|
-
/* @__PURE__ */ (0,
|
|
11316
|
+
renderColumnHeader ? renderColumnHeader(column) : /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("div", { className: "flex flex-col gap-0.5 px-1 pb-0.5", children: [
|
|
11317
|
+
/* @__PURE__ */ (0, import_jsx_runtime97.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
11318
|
+
/* @__PURE__ */ (0, import_jsx_runtime97.jsx)(
|
|
11104
11319
|
"h3",
|
|
11105
11320
|
{
|
|
11106
11321
|
className: cn(
|
|
@@ -11110,12 +11325,12 @@ function KanbanColumnView({
|
|
|
11110
11325
|
children: column.title
|
|
11111
11326
|
}
|
|
11112
11327
|
),
|
|
11113
|
-
/* @__PURE__ */ (0,
|
|
11114
|
-
column.action ? /* @__PURE__ */ (0,
|
|
11328
|
+
/* @__PURE__ */ (0, import_jsx_runtime97.jsx)("span", { className: "shrink-0 text-xs font-normal tabular-nums text-muted-foreground/60", children: column.cards.length }),
|
|
11329
|
+
column.action ? /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("div", { className: "shrink-0", children: column.action }) : null
|
|
11115
11330
|
] }),
|
|
11116
|
-
column.description ? /* @__PURE__ */ (0,
|
|
11331
|
+
column.description ? /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("p", { className: "truncate text-xs text-muted-foreground", children: column.description }) : null
|
|
11117
11332
|
] }),
|
|
11118
|
-
/* @__PURE__ */ (0,
|
|
11333
|
+
/* @__PURE__ */ (0, import_jsx_runtime97.jsx)(import_sortable.SortableContext, { items: cardIds, strategy: import_sortable.verticalListSortingStrategy, children: /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(
|
|
11119
11334
|
"div",
|
|
11120
11335
|
{
|
|
11121
11336
|
ref: setNodeRef,
|
|
@@ -11125,9 +11340,9 @@ function KanbanColumnView({
|
|
|
11125
11340
|
densityListClass[density],
|
|
11126
11341
|
isOver && "bg-muted/50"
|
|
11127
11342
|
),
|
|
11128
|
-
children: column.cards.length === 0 ? /* @__PURE__ */ (0,
|
|
11343
|
+
children: column.cards.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("div", { className: "flex flex-1 items-center justify-center rounded-xl border border-dashed border-border/60 px-2 py-8 text-center text-xs text-muted-foreground/70", children: emptyColumnLabel ?? "Drop here" }) : column.cards.map((card) => {
|
|
11129
11344
|
const id = getCardId(card);
|
|
11130
|
-
return /* @__PURE__ */ (0,
|
|
11345
|
+
return /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(
|
|
11131
11346
|
SortableCard,
|
|
11132
11347
|
{
|
|
11133
11348
|
card,
|
|
@@ -11145,7 +11360,7 @@ function KanbanColumnView({
|
|
|
11145
11360
|
})
|
|
11146
11361
|
}
|
|
11147
11362
|
) }),
|
|
11148
|
-
column.footer ? /* @__PURE__ */ (0,
|
|
11363
|
+
column.footer ? /* @__PURE__ */ (0, import_jsx_runtime97.jsx)("div", { className: "px-0.5 pt-0.5", children: column.footer }) : null
|
|
11149
11364
|
]
|
|
11150
11365
|
}
|
|
11151
11366
|
);
|
|
@@ -11284,7 +11499,7 @@ function Kanban({
|
|
|
11284
11499
|
onColumnsChange?.(next);
|
|
11285
11500
|
}
|
|
11286
11501
|
};
|
|
11287
|
-
return /* @__PURE__ */ (0,
|
|
11502
|
+
return /* @__PURE__ */ (0, import_jsx_runtime97.jsxs)(
|
|
11288
11503
|
import_core2.DndContext,
|
|
11289
11504
|
{
|
|
11290
11505
|
sensors,
|
|
@@ -11298,7 +11513,7 @@ function Kanban({
|
|
|
11298
11513
|
if (isControlled) setInternal(cloneColumns(columnsProp));
|
|
11299
11514
|
},
|
|
11300
11515
|
children: [
|
|
11301
|
-
/* @__PURE__ */ (0,
|
|
11516
|
+
/* @__PURE__ */ (0, import_jsx_runtime97.jsx)(
|
|
11302
11517
|
"div",
|
|
11303
11518
|
{
|
|
11304
11519
|
"data-slot": "kanban",
|
|
@@ -11309,7 +11524,7 @@ function Kanban({
|
|
|
11309
11524
|
density === "compact" ? "gap-3" : "gap-4",
|
|
11310
11525
|
className
|
|
11311
11526
|
),
|
|
11312
|
-
children: columns.map((column) => /* @__PURE__ */ (0,
|
|
11527
|
+
children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(
|
|
11313
11528
|
KanbanColumnView,
|
|
11314
11529
|
{
|
|
11315
11530
|
column,
|
|
@@ -11329,7 +11544,7 @@ function Kanban({
|
|
|
11329
11544
|
))
|
|
11330
11545
|
}
|
|
11331
11546
|
),
|
|
11332
|
-
/* @__PURE__ */ (0,
|
|
11547
|
+
/* @__PURE__ */ (0, import_jsx_runtime97.jsx)(import_core2.DragOverlay, { children: activeCard ? /* @__PURE__ */ (0, import_jsx_runtime97.jsx)(
|
|
11333
11548
|
"div",
|
|
11334
11549
|
{
|
|
11335
11550
|
"data-slot": "kanban-card-overlay",
|
|
@@ -11352,7 +11567,7 @@ function Kanban({
|
|
|
11352
11567
|
}
|
|
11353
11568
|
|
|
11354
11569
|
// src/chat/chat.tsx
|
|
11355
|
-
var
|
|
11570
|
+
var import_jsx_runtime98 = require("react/jsx-runtime");
|
|
11356
11571
|
function TimbalChat({
|
|
11357
11572
|
workforceId,
|
|
11358
11573
|
baseUrl,
|
|
@@ -11363,7 +11578,7 @@ function TimbalChat({
|
|
|
11363
11578
|
debug,
|
|
11364
11579
|
...threadProps
|
|
11365
11580
|
}) {
|
|
11366
|
-
return /* @__PURE__ */ (0,
|
|
11581
|
+
return /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(
|
|
11367
11582
|
TimbalRuntimeProvider,
|
|
11368
11583
|
{
|
|
11369
11584
|
workforceId,
|
|
@@ -11373,7 +11588,7 @@ function TimbalChat({
|
|
|
11373
11588
|
attachmentsUploadUrl,
|
|
11374
11589
|
attachmentsAccept,
|
|
11375
11590
|
debug,
|
|
11376
|
-
children: /* @__PURE__ */ (0,
|
|
11591
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime98.jsx)(Thread, { ...threadProps })
|
|
11377
11592
|
}
|
|
11378
11593
|
);
|
|
11379
11594
|
}
|