@timbal-ai/timbal-react 1.4.0 → 1.5.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 +14 -0
- package/README.md +18 -4
- package/dist/app.cjs +3532 -1483
- package/dist/app.d.cts +75 -30
- package/dist/app.d.ts +75 -30
- package/dist/app.esm.js +29 -7
- package/dist/{chart-artifact-CMnDys2t.d.ts → chart-artifact-2OTDTRwM.d.ts} +194 -40
- package/dist/{chart-artifact-C8-Py6lc.d.cts → chart-artifact-CS3qyGIY.d.cts} +194 -40
- package/dist/chat.cjs +264 -107
- package/dist/chat.d.cts +2 -2
- package/dist/chat.d.ts +2 -2
- package/dist/chat.esm.js +4 -3
- package/dist/chunk-5ECRZ5O7.esm.js +899 -0
- package/dist/{chunk-QU7ET55D.esm.js → chunk-AZL2WANO.esm.js} +320 -177
- package/dist/{chunk-OH23AX2V.esm.js → chunk-B4XAC4G7.esm.js} +430 -780
- package/dist/chunk-EDEKQYSU.esm.js +10 -0
- package/dist/{chunk-GQBYZRD7.esm.js → chunk-IGHBLJV3.esm.js} +38 -27
- package/dist/{chunk-OFWC4MIY.esm.js → chunk-JYDJRGDE.esm.js} +5 -3
- package/dist/{chunk-VOWNCS3F.esm.js → chunk-SZDYIRMB.esm.js} +1567 -490
- package/dist/chunk-TZI3ID3C.esm.js +232 -0
- package/dist/{chunk-THBA27QY.esm.js → chunk-WMKPT5BV.esm.js} +242 -123
- package/dist/{chunk-VXMM2HX7.esm.js → chunk-ZNYAETFD.esm.js} +1 -1
- package/dist/{circular-progress-Ci8L-Hfa.d.cts → circular-progress-CDsJwIPF.d.cts} +19 -77
- package/dist/{circular-progress-Ci8L-Hfa.d.ts → circular-progress-CDsJwIPF.d.ts} +19 -77
- package/dist/index.cjs +5506 -3626
- package/dist/index.d.cts +7 -6
- package/dist/index.d.ts +7 -6
- package/dist/index.esm.js +45 -33
- package/dist/kanban-U5xNe9py.d.cts +212 -0
- package/dist/kanban-U5xNe9py.d.ts +212 -0
- package/dist/{layout-BTJyU8wd.d.ts → layout-B8r6Jbat.d.ts} +1 -1
- package/dist/{layout-C2G-FcER.d.cts → layout-Cu7Ijn04.d.cts} +1 -1
- package/dist/site.cjs +358 -0
- package/dist/site.d.cts +184 -0
- package/dist/site.d.ts +184 -0
- package/dist/site.esm.js +322 -0
- package/dist/studio.cjs +702 -343
- package/dist/studio.d.cts +1 -1
- package/dist/studio.d.ts +1 -1
- package/dist/studio.esm.js +7 -5
- package/dist/styles.css +56 -0
- package/dist/{timbal-v2-button-CNfdwGq4.d.cts → timbal-v2-button-B7vPs7gg.d.cts} +2 -2
- package/dist/{timbal-v2-button-CNfdwGq4.d.ts → timbal-v2-button-B7vPs7gg.d.ts} +2 -2
- package/dist/ui.cjs +1504 -659
- package/dist/ui.d.cts +11 -4
- package/dist/ui.d.ts +11 -4
- package/dist/ui.esm.js +35 -26
- package/dist/{welcome-DXqsGTwH.d.ts → welcome-DduQAC4K.d.ts} +4 -0
- package/dist/{welcome-BFGRoNfK.d.cts → welcome-NXZlcihe.d.cts} +4 -0
- package/package.json +9 -1
- package/dist/button-BoyX5pM_.d.cts +0 -18
- package/dist/button-BoyX5pM_.d.ts +0 -18
- package/dist/chunk-UCGVL7ZY.esm.js +0 -52
|
@@ -15,27 +15,36 @@ import {
|
|
|
15
15
|
studioIntegrationCardClass,
|
|
16
16
|
studioTopbarPillHeightClass,
|
|
17
17
|
toNum
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-IGHBLJV3.esm.js";
|
|
19
19
|
import {
|
|
20
20
|
Checkbox,
|
|
21
|
+
CopyButton,
|
|
22
|
+
Popover,
|
|
23
|
+
PopoverContent,
|
|
24
|
+
PopoverTrigger,
|
|
21
25
|
Skeleton
|
|
22
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-5ECRZ5O7.esm.js";
|
|
23
27
|
import {
|
|
24
28
|
PillSegmentedTabs
|
|
25
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-ZNYAETFD.esm.js";
|
|
26
30
|
import {
|
|
31
|
+
Avatar,
|
|
32
|
+
AvatarFallback,
|
|
27
33
|
Button,
|
|
28
34
|
Dialog,
|
|
29
35
|
DialogContent,
|
|
30
36
|
DialogTitle,
|
|
37
|
+
TIMBAL_V2_ELEVATED_GRADIENT,
|
|
31
38
|
TIMBAL_V2_ELEVATED_SURFACE,
|
|
32
39
|
TIMBAL_V2_LOGO_TILE,
|
|
33
40
|
TIMBAL_V2_SWITCH_THUMB,
|
|
34
41
|
TIMBAL_V2_SWITCH_TRACK_OFF,
|
|
35
42
|
TimbalV2Button,
|
|
36
|
-
cn,
|
|
37
43
|
controlClass
|
|
38
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-AZL2WANO.esm.js";
|
|
45
|
+
import {
|
|
46
|
+
cn
|
|
47
|
+
} from "./chunk-EDEKQYSU.esm.js";
|
|
39
48
|
|
|
40
49
|
// src/design/ui-vocabulary.ts
|
|
41
50
|
var SEMANTIC_COLOR_TOKENS = [
|
|
@@ -191,6 +200,13 @@ var HOUSE_RULES = [
|
|
|
191
200
|
rule: "Don't nest a bordered card inside another bordered card. Group with spacing or a Section instead.",
|
|
192
201
|
why: "Card-in-card doubles borders and shadows for no information gain."
|
|
193
202
|
},
|
|
203
|
+
{
|
|
204
|
+
id: "no-table-in-card",
|
|
205
|
+
rule: "Never wrap a DataTable or table inside a Card, SurfaceCard, or ArtifactCard.",
|
|
206
|
+
why: "The DataTable is already designed to sit flat with its own borders and shadows. Wrapping it inside a card adds redundant borders, margins, and shadows, which looks like slop.",
|
|
207
|
+
slop: "<Card><DataTable columns={columns} rows={rows} getRowKey={getRowKey} /></Card>",
|
|
208
|
+
good: "<DataTable columns={columns} rows={rows} getRowKey={getRowKey} />"
|
|
209
|
+
},
|
|
194
210
|
{
|
|
195
211
|
id: "no-row-dividers",
|
|
196
212
|
rule: "Don't put a divider between every list row. Use spacing or zebra striping.",
|
|
@@ -212,6 +228,27 @@ var HOUSE_RULES = [
|
|
|
212
228
|
why: "Hand-rolled controls drift from the shared control-surface skin and look foreign next to kit controls.",
|
|
213
229
|
slop: `<button className="rounded-lg border border-input bg-transparent px-3 h-9">`,
|
|
214
230
|
good: `<SelectTrigger><SelectValue /></SelectTrigger>`
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
id: "no-title-repetition",
|
|
234
|
+
rule: "Never repeat the page title/description inside a Section, Card, or Table header.",
|
|
235
|
+
why: "If the Page already has a title, repeating it in the first child section or table is redundant and wastes vertical space.",
|
|
236
|
+
slop: `<Page title="Orders"><Section title="Orders"><DataTable ... /></Section></Page>`,
|
|
237
|
+
good: `<Page title="Orders"><DataTable ... /></Page>`
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
id: "no-chat-wrapping",
|
|
241
|
+
rule: "Never wrap TimbalChat or AppChatPanel in a Card, Section, or custom bordered/padded container, and never add custom heading/status blocks above it.",
|
|
242
|
+
why: "The chat component is a full-bleed, full-height surface that handles its own layout, welcome screen, and suggestions. Wrapping it or hand-rolling headers/online badges inside the page content is redundant and wastes layout space.",
|
|
243
|
+
slop: `<Page title="Assistant"><Card><div className="flex justify-between"><h3>TIBA Concierge</h3><span>Online</span></div><TimbalChat /></Card></Page>`,
|
|
244
|
+
good: `<Page fill><TimbalChat workforceId="..." welcome={{ heading: "Hola, soy el Concierge de TIBA", subheading: "Preg\xFAntame sobre..." }} /></Page>`
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
id: "no-colored-hover",
|
|
248
|
+
rule: "Interactive cards and list items must use neutral hover states \u2014 never hard-code colored backgrounds or borders on hover.",
|
|
249
|
+
why: "Colored hover highlights (like hover:bg-primary/5 or hover:bg-emerald-500/5) look dirty and break the neutral chrome aesthetic. Use the kit's clean, neutral hover states, or AlertCard, or TIMBAL_V2_SECONDARY_CHROME hover layers.",
|
|
250
|
+
slop: `<Card className="hover:bg-emerald-500/10 hover:border-emerald-500/30">`,
|
|
251
|
+
good: `<AlertCard onClick={handleClick}>`
|
|
215
252
|
}
|
|
216
253
|
];
|
|
217
254
|
|
|
@@ -246,14 +283,14 @@ The most common failure is shipping the **same** layout every time: sidebar + to
|
|
|
246
283
|
| Archetype | When | Compose |
|
|
247
284
|
|-----------|------|---------|
|
|
248
285
|
| **Sidebar dashboard** | Multi-section product (CRM, billing, ops) with nav | \`StudioSidebar\` in \`AppShell.sidebar\` + \`Page\` \u2192 \`Section\` |
|
|
249
|
-
| **Focused / no-chrome** | A single tool or one-screen utility | \`AppShell\` (no sidebar) + \`Page\` (optionally
|
|
286
|
+
| **Focused / no-chrome** | A single tool or one-screen utility | \`AppShell\` (no sidebar) + \`Page width="narrow"\` / \`"prose"\` (optionally with a custom topbar) for a centered focused column |
|
|
250
287
|
| **Bento overview** | Home / at-a-glance dashboards | \`Page\` + an **asymmetric grid** of \`SurfaceCard\` / \`ChartPanel\` / \`StatTile\` spanning different widths (not a uniform row + table) |
|
|
251
288
|
| **Split master\u2013detail** | Inbox, triage queue, record browser, log explorer | \`AppShell contentFill\` + \`Page fill\` + a two-column flex row, each pane \`min-h-0 overflow-y-auto\` |
|
|
252
289
|
| **Full-page chat / canvas** | Chat-first app, editor, map, single full-bleed surface | \`AppShell contentFill\` + headerless \`Page fill\` + a \`min-h-0 flex-1\` child (e.g. \`TimbalChat\`) |
|
|
253
290
|
| **Copilot overlay** | A data app that also wants an assistant | any of the above + \`AppShell chat={<AppChatPanel />}\` (floating, never a second column) |
|
|
254
291
|
| **Section-switcher** | One page, several views | \`SubNav\` / \`PillSegmentedTabs\` (\`trackVariant="flush"\`) switching panels with state/router |
|
|
255
292
|
|
|
256
|
-
Mix them: vary the grid columns, density, header placement (\`Page\` actions vs. a global
|
|
293
|
+
Mix them: vary the grid columns, density, header placement (\`Page\` actions vs. a global topbar), and whether there's a sidebar at all. Two dashboards for two domains should not look identical.
|
|
257
294
|
|
|
258
295
|
### Full-height pages (chat, canvas, split views)
|
|
259
296
|
|
|
@@ -264,7 +301,7 @@ The content region is a **padded scroll area** by default \u2014 great for stack
|
|
|
264
301
|
- Give the filling child **\`min-h-0 flex-1\`** (or \`h-full\`) so its own scroll/footer resolves \u2014 e.g. \`<TimbalChat className="min-h-0 flex-1" />\`, or a two-pane row where each pane is \`min-h-0 overflow-y-auto\`.
|
|
265
302
|
|
|
266
303
|
\`\`\`tsx
|
|
267
|
-
<AppShell contentFill topbar={<
|
|
304
|
+
<AppShell contentFill topbar={<div className="flex justify-end p-4"><ModeToggle /></div>}>
|
|
268
305
|
<Page fill> {/* headerless: omit title */}
|
|
269
306
|
<TimbalChat workforceId="\u2026" className="min-h-0 flex-1" />
|
|
270
307
|
</Page>
|
|
@@ -273,6 +310,11 @@ The content region is a **padded scroll area** by default \u2014 great for stack
|
|
|
273
310
|
|
|
274
311
|
**Don't** size full-height content with \`h-[calc(100dvh-\u2026)]\` (guesses chrome height \u2192 spurious scrollbar) or \`min-h-[\u2026]\` (free-growing floor \u2192 a pinned footer like the chat composer rides down on scroll). Let \`contentFill\` + \`fill\` provide the bounded height. \`Page\` with no \`title\` renders **no header** \u2014 you don't need to abandon \`Page\` to drop a heading.
|
|
275
312
|
|
|
313
|
+
**Full-page Assistant Guidelines (Hardened Layout):**
|
|
314
|
+
When creating a full-page assistant/chat page, let the chat component own the layout and welcome state completely.
|
|
315
|
+
- **Never wrap** \`<TimbalChat>\` or \`<AppChatPanel>\` inside standard card or section elements (like \`<Card>\`, \`<Section>\`, or custom bordered/padded panels). Wrapping degrades the viewport height calculations and wastes valuable layout estate.
|
|
316
|
+
- **Never add custom headings, titles, descriptions, or status badges** (e.g., "Asistente Virtual", "Online", or subtitle text blocks) inside the page. The assistant page context is already implicit. If you need a customized title or greeting, pass it through the \`welcome\` prop config: e.g., \`<TimbalChat welcome={{ heading: "Hola, soy el Concierge de TIBA", subheading: "Preg\xFAntame sobre..." }} />\`.
|
|
317
|
+
|
|
276
318
|
### Module layout (source folders)
|
|
277
319
|
|
|
278
320
|
Presentational groups \u2014 import from the package root, not from these paths:
|
|
@@ -282,11 +324,11 @@ Presentational groups \u2014 import from the package root, not from these paths:
|
|
|
282
324
|
| \`data/\` | \`MetricRow\`, \`MetricChartCard\`, \`MetricTile\`, \`DataTable\`, \`FilterBar\`, \`FilterField\`, \`ChartPanel\` |
|
|
283
325
|
| \`integrations/\` | \`IntegrationCard\`, \`ConnectionRow\`, \`ConnectionRowList\`, \`IntegrationsEmptyState\`, \`PlanBadge\` |
|
|
284
326
|
| \`settings/\` | \`SettingsSection\`, \`FieldRow\`, \`DangerZone\`, \`FloatingUnsavedChangesBar\` |
|
|
285
|
-
| \`surfaces/\` | \`StatTile\`, \`InfoCard\`, \`ResourceCard\`, \`DescriptionList\`, \`ExpandableSection\`, \`StatusDot\`, \`StatusBadge\`, \`EmptyState\` |
|
|
286
|
-
| \`layout/\` | \`AppShell\`, \`Page
|
|
327
|
+
| \`surfaces/\` | \`StatTile\`, \`InfoCard\`, \`AlertCard\`, \`CatalogCard\`, \`ResourceCard\`, \`DescriptionList\`, \`ExpandableSection\`, \`StatusDot\`, \`StatusBadge\`, \`EmptyState\` |
|
|
328
|
+
| \`layout/\` | \`AppShell\`, \`Page\` (auto-stacks children; \`width\` ladder), \`Section\`, \`Stack\` |
|
|
287
329
|
| \`charts\` (re-exported) | \`LineAreaChart\`, \`PieChart\`, \`RadialChart\`, \`RadarChart\`, \`Sparkline\`, \`CHART_PALETTE\` |
|
|
288
330
|
|
|
289
|
-
Also re-exported
|
|
331
|
+
Also re-exported from \`/app\`: \`Button\`, \`Avatar\` / \`AvatarImage\` / \`AvatarFallback\`, \`Banner\`, \`Timeline\`, \`Kanban\` (drag-and-drop board), \`TimbalChat\`, \`ChartArtifactView\`, \`APP_KIT_AGENT_INSTRUCTIONS\`. Other UI primitives used in block recipes (\`Card\`, \`Input\`, \`Label\`, \`Sheet\`, \`Separator\`, \`AlertDialog\`, \`Badge\`, \`Select\`, \u2026) import from \`@timbal-ai/timbal-react/ui\` or the package root \u2014 **not** from \`/app\`.
|
|
290
332
|
|
|
291
333
|
Theming helpers (import from the package root or \`/app\`): \`createTimbalTheme\`, \`themeToCss\`, \`applyTimbalTheme\`, \`TIMBAL_THEME_PRESETS\`, \`applyThemePreset\`, \`TimbalThemeStyle\`, \`THEME_AGENT_INSTRUCTIONS\`. Theming is **configured by the developer**, not surfaced as an end-user theme picker.
|
|
292
334
|
|
|
@@ -298,9 +340,12 @@ Theming helpers (import from the package root or \`/app\`): \`createTimbalTheme\
|
|
|
298
340
|
| **Chat panel** | \`AppChatPanel\` only; \`Thread\` uses \`variant="panel"\` internally. Dismiss with **X**; trigger is a **text-only** pill (e.g. "Assistant") \u2014 **no** MessageSquare or chat icons on the shell trigger. |
|
|
299
341
|
| **Context** | Do not show raw JSON context in the panel header; keep context in \`AppCopilotProvider\` only. |
|
|
300
342
|
| **Theming** | Use semantic Tailwind tokens (\`bg-background\`, \`text-foreground\`, \`border-border\`, \`bg-elevated-from\`, etc.) from the host app's \`styles.css\`. To rebrand, **never hand-author OKLCH** \u2014 call \`createTimbalTheme({ brand })\` + \`themeToCss\`/\`applyTimbalTheme\`, or apply a catalog preset (\`TIMBAL_THEME_PRESETS\` / \`applyThemePreset\`). Apply the theme **programmatically** \u2014 do **not** add an end-user theme selector to generated apps. See \`THEME_AGENT_INSTRUCTIONS\`. |
|
|
301
|
-
| **Layout chrome** | \`Page\` \u2192 \`Section\` for main content hierarchy. Default to **no global topbar** \u2014 put account/theme/global actions in the \`Page\` \`actions\` slot (or the sidebar). Add
|
|
343
|
+
| **Layout chrome** | \`Page\` \u2192 \`Section\` for main content hierarchy. Default to **no global topbar** \u2014 put account/theme/global actions in the \`Page\` \`actions\` slot (or the sidebar). Add a topbar only when a full-width global bar is explicitly requested. |
|
|
344
|
+
| **Spacing / gaps** | \`Page\` **auto-stacks its direct children with a vertical gap** \u2014 drop blocks straight in (e.g. \`Page\` \u2192 \`FilterBar\` + \`DataTable\`, or \`MetricRow\` + \`ChartPanel\`) and they breathe; do **not** wrap every block in an extra \`<div>\` (that collapses the gap). For ad-hoc clusters inside a card/row use \`Stack\` (\`gap\`, \`direction\`) instead of bare flex with no gap. Grids still need their own \`gap-*\`. |
|
|
345
|
+
| **Width** | \`Page\` defaults to a wide centered column. For focused / reading / form pages pass \`width\` (\`default\`, \`centered\`, \`narrow\`, \`prose\`) instead of always running full-bleed \u2014 not everything needs the full width. \`width="full"\` opts into edge-to-edge. For full-height pages that should stay centered use \`fill\` + \`fillPadded\`. |
|
|
302
346
|
| **Density** | Set \`density="compact"\` on \`Page\` for tighter dashboards (full-width column, smaller section gaps, card padding, metric tiles, default chart height 220). Default is \`"default"\` (platform spacing). Wrap custom layouts with \`AppDensityProvider\` when not using \`Page\`. Per-section override: \`Section density="compact"\`. Do **not** hand-tune five layers of \`className\` padding when density covers the need. |
|
|
303
347
|
| **Data** | Prefer \`DataTable\` with typed \`columns\` / \`rows\` / \`getRowKey\`; use \`ChartPanel\` with a \`ChartArtifact\` for charts (set \`chartType\` + options \u2014 see the chart catalog). Chart colors come from the theme \`--chart-1..6\` tokens; pass \`series[].color\` / \`colors\` only to override, never raw hex on every series. |
|
|
348
|
+
| **Boards** | For status/triage workflows (pipelines, sprint boards, review queues) use \`Kanban\` \u2014 pass \`columns\` (each with \`cards\`) + \`renderCard\`; handle \`onColumnsChange\`/\`onMove\` to persist. It's drag-and-drop **and** keyboard accessible; don't hand-roll columns of cards. |
|
|
304
349
|
| **Modals** | Use \`AppConfirmDialog\` for destructive/export confirmations. |
|
|
305
350
|
| **Metrics** | Overview KPIs \u2192 \`MetricRow\` or \`MetricChartCard\` (not four separate heavy cards). Values use **normal** font weight, not bold. |
|
|
306
351
|
| **Integrations** | Catalog \u2192 \`IntegrationCard\` grid; connected list \u2192 \`ConnectionRow\` inside \`ConnectionRowList\`. Footer CTAs: \`Button variant="secondary"\`. |
|
|
@@ -332,7 +377,6 @@ The cause of slop is dropping **below** the curated block layer into raw primiti
|
|
|
332
377
|
| Component | Use for |
|
|
333
378
|
|-----------|---------|
|
|
334
379
|
| \`AppShell\` | Shell: optional \`sidebar\`, \`topbar\`, main \`children\`, optional floating \`chat\`. Props: \`chatTriggerLabel\`, \`chatCollapsible\`, \`chatWidth\`, \`chatHeight\`, controlled \`chatOpen\`, **\`contentFill\`** (bounded non-scrolling content region for full-bleed pages \u2014 chat/canvas/split view). |
|
|
335
|
-
| \`AppShellTopbar\` | Full-width top bar: \`start\`, \`actions\` slots. |
|
|
336
380
|
| \`AppCopilotProvider\` | React context for copilot-aware tools (page, filters, selection, etc.). |
|
|
337
381
|
| \`AppChatPanel\` | Floating thread: \`workforceId\`, \`welcome\`, \`debug\`. |
|
|
338
382
|
| \`useAppShellChat\` | Custom open/close trigger when \`hideChatTrigger\` on shell. |
|
|
@@ -341,7 +385,7 @@ The cause of slop is dropping **below** the curated block layer into raw primiti
|
|
|
341
385
|
| \`SubNav\` | **Section switcher** (Overview / Reports pill bar): \`items\`, \`activeId\`, \`onChange\`. Never use Radix/shadcn \`Tabs\` \u2014 it is not in this package. Switch panels with state or the router. |
|
|
342
386
|
| **Menus** | **Select** = short list, no search. **Combobox** = searchable (same trigger as Select). **Command** only inside \`PopoverContent variant="list"\` or Combobox \u2014 never padded default Popover. See \`examples/app-kit/src/recipes/primitives-catalog.ts\`. |
|
|
343
387
|
| \`Breadcrumbs\` | Trail: \`items: [{ label, href? }]\`. |
|
|
344
|
-
| \`Button\` | Actions
|
|
388
|
+
| \`Button\` | Actions. Untitled UI-style \`color\` alias (\`primary\` \\| \`secondary\` \\| \`tertiary\` \\| \`link\` \\| \`primary-destructive\` \\| \`secondary-destructive\`) + \`iconLeading\` / \`iconTrailing\`; or legacy \`variant="secondary"\` (catalog CTAs) / \`variant="default"\` (primary). \`color="primary-destructive"\` is the solid red delete CTA. |
|
|
345
389
|
| \`StatTile\` | Single KPI in its own card (grid of scattered stats). Prefer \`MetricRow\` for a unified overview strip. |
|
|
346
390
|
| \`StatusBadge\` | Status pill: \`tone\` (\`default\`\\|\`primary\`\\|\`success\`\\|\`warn\`\\|\`danger\`\\|\`muted\`), children. Use \`danger\` for critical/error severity. |
|
|
347
391
|
| \`FilterBar\` | Horizontal filter row \u2014 bottom-aligns controls. Mix \`SearchInput\` with labeled \`FilterField\` + \`Select\` (or \`Field\` + \`Select\`); labels sit above, control baselines match. |
|
|
@@ -350,7 +394,7 @@ The cause of slop is dropping **below** the curated block layer into raw primiti
|
|
|
350
394
|
| \`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\`). |
|
|
351
395
|
| \`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\`. |
|
|
352
396
|
| \`ChartPanel\` | Same shell as \`MetricChartCard\`: title row (\`px-4 pt-4\`), flush plot (\`pt-2\` only) with **no axis ticks** \u2014 hover tooltips show category + value. Pass \`title\` + \`artifact\` (omit \`artifact.title\` to avoid duplicates) or \`children\`. \`loading\` renders a plot-height skeleton. Default plot height follows page \`density\` (300 default, 220 compact); pass \`height\` to override. |
|
|
353
|
-
| \`FieldInput\`, \`FieldTextarea\`, \`FieldSelect\`, \`FieldSwitch\` | Settings-style forms with labels and hints. |
|
|
397
|
+
| \`FieldInput\`, \`FieldTextarea\`, \`FieldSelect\`, \`FieldSwitch\` | Settings-style forms with labels and hints. **\`label\` is required** on every \`Field*\` component; for a label-less filter control use \`FilterField\` (optional label) or \`SearchInput\`. |
|
|
354
398
|
| \`FormSection\` | Grouped form block. |
|
|
355
399
|
| \`AppConfirmDialog\` | Confirm/cancel modal: \`open\`, \`onOpenChange\`, \`title\`, \`description\`, \`onConfirm\`. |
|
|
356
400
|
| \`SurfaceCard\`, \`EmptyState\` | Generic surfaces when needed. |
|
|
@@ -396,9 +440,13 @@ Charts run on **recharts** with shadcn \`ChartContainer\` / \`ChartTooltipConten
|
|
|
396
440
|
| Component | Use for |
|
|
397
441
|
|-----------|---------|
|
|
398
442
|
| \`InfoCard\` | Soft callout: \`icon\`, \`title\`, body, \`action\`, \`tone\` (\`info\`/\`success\`/\`warn\`/\`danger\`). |
|
|
443
|
+
| \`AlertCard\` | Actionable / AI-generated alert card with integrated status tags, clear titles, descriptive bodies, and automated action footers. Supports: \`title\`, \`description?\`, \`category?\`, \`categoryTone?\`, \`status?\`, \`statusTone?\`, \`action?\` (action description text), \`trailing?\` (custom element), and \`onClick?\`. Renders with a beautiful neutral hover state, avoiding loud/colored hover background effects. |
|
|
444
|
+
| \`CatalogCard\` | Highly sophisticated marketplace/routing catalog tile (models, datasets, tools). Supports: \`title\`, \`subtitle?\`, \`logo?\` (e.g. brand logo), \`badge?\` (e.g. model type badge), \`description?\`, \`tags?\` (metadata array), \`href?\` (title link), \`footerLinks?\` (bottom-left links), \`copyValue?\` (copy ID button), \`actions?\`, and \`onClick?\` (neutral-hover interactive state). |
|
|
399
445
|
| \`DescriptionList\` | Read-only key/value metadata: \`items: [{ label, value }]\`, optional \`stacked\`. |
|
|
400
446
|
| \`ExpandableSection\` | Collapsible block: \`title\`, \`icon\`, \`count\`, animated body (\`aria-expanded\` + \`aria-controls\`). |
|
|
401
447
|
| \`StatusDot\` | Status indicator dot: \`tone\`, \`label\`, \`pulse\`. |
|
|
448
|
+
| \`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. |
|
|
449
|
+
| \`Timeline\` | Vertical event log: \`items: [{ id, title, description?, meta?, tone?, icon? }]\`. Presentational \u2014 pass already-formatted timestamps in \`meta\`. |
|
|
402
450
|
|
|
403
451
|
Studio chrome (\`StudioSidebar\`, \`ModeToggle\`, \u2026) lives in \`@timbal-ai/timbal-react/studio\` \u2014 optional, not required for every dashboard.
|
|
404
452
|
|
|
@@ -466,6 +514,8 @@ import {
|
|
|
466
514
|
DataTable,
|
|
467
515
|
FilterBar,
|
|
468
516
|
FilterField,
|
|
517
|
+
AlertCard,
|
|
518
|
+
CatalogCard,
|
|
469
519
|
} from "@timbal-ai/timbal-react/app";
|
|
470
520
|
\`\`\`
|
|
471
521
|
|
|
@@ -476,6 +526,17 @@ import {
|
|
|
476
526
|
| \`examples/app-kit/recipes/*\` | **Recipes** \u2014 one pattern each (~20\u201380 lines). Use for capability, not layout. |
|
|
477
527
|
| \`examples/app-kit/reference/operations-dashboard.tsx\` | **Reference only** \u2014 full wired app; do not treat as the default generated layout. |
|
|
478
528
|
|
|
529
|
+
### API gotchas \u2014 props that do NOT exist (don't guess, don't retry variations)
|
|
530
|
+
|
|
531
|
+
The compiler rejects these every time; write against the documented shapes above instead:
|
|
532
|
+
|
|
533
|
+
- \`FieldInput\` / \`FieldTextarea\` / \`FieldSelect\` / \`FieldSwitch\` **require \`label\`** \u2014 TS2741 if omitted. Label-less control \u2192 \`FilterField\` or \`SearchInput\`.
|
|
534
|
+
- Full-height layout: \`fill\` lives on \`Page\` (paired with \`AppShell contentFill\`) \u2014 there is no \`fill\` on \`Section\` or \`AppShell\`.
|
|
535
|
+
- \`WorkforceSelector\` (chat subpath / root) is a **controlled** picker: \`workforces\` (e.g. from \`useWorkforces()\`), \`value\`, \`onChange(id)\`, optional \`hideWhenSingle\` / \`placeholder\`. It does **not** fetch and has no \`workforceId\` prop \u2014 for an embedded assistant use \`AppChatPanel workforceId="\u2026"\`.
|
|
536
|
+
- There is **no \`Tabs\` export** \u2014 section switching uses \`SubNav\` or \`PillSegmentedTabs\`.
|
|
537
|
+
- \`Banner\` and \`Timeline\` exist (see menu) \u2014 import them from \`/app\`, \`/ui\`, or the root.
|
|
538
|
+
- If a prop still type-errors, read the actual definitions in \`node_modules/@timbal-ai/timbal-react/dist/app.d.ts\` once instead of retrying guessed prop names.
|
|
539
|
+
|
|
479
540
|
### Rules
|
|
480
541
|
|
|
481
542
|
- Prefer stable props documented above; avoid undocumented \`design/*\` class exports (\`connectionRowListClass\` is exported but \`ConnectionRowList\` is preferred).
|
|
@@ -506,6 +567,7 @@ var GRADIENT_DIRECTIONS = /* @__PURE__ */ new Set([
|
|
|
506
567
|
]);
|
|
507
568
|
var ICON_IMPORT_RE = /from\s+["']lucide-react["']/;
|
|
508
569
|
var RAW_CONTROL_SURFACE_RE = /\bborder-input\b/;
|
|
570
|
+
var COLORED_HOVER_RE = /\bhover:(?:bg|from|to|via)-(?:primary|destructive|success|warn|danger|blue|emerald|green|amber|red|indigo|violet|purple|pink|rose|sky|cyan|teal|lime|yellow|orange|fuchsia)\b/;
|
|
509
571
|
var RESERVED_GRADIENT_SET = new Set(RESERVED_GRADIENT_TOKENS);
|
|
510
572
|
function stripVariants(util) {
|
|
511
573
|
return util.replace(/^(?:[a-z-]+:)*/, "");
|
|
@@ -522,7 +584,14 @@ function lintGeneratedUi(source, options = {}) {
|
|
|
522
584
|
let usesLucide = false;
|
|
523
585
|
let iconUsageCount = 0;
|
|
524
586
|
let dividerRunCount = 0;
|
|
587
|
+
let pageTitle = null;
|
|
588
|
+
const pageTitleMatch = source.match(/<Page\s+[^>]*\btitle=(?:"([^"]+)"|\{["']([^"']+)["']\})/);
|
|
589
|
+
if (pageTitleMatch) {
|
|
590
|
+
pageTitle = (pageTitleMatch[1] || pageTitleMatch[2]).trim().toLowerCase();
|
|
591
|
+
}
|
|
592
|
+
const hasChat = /\b(?:TimbalChat|AppChatPanel|Thread)\b/.test(source);
|
|
525
593
|
const lucideNames = /* @__PURE__ */ new Set();
|
|
594
|
+
const openCards = [];
|
|
526
595
|
for (let i = 0; i < lines.length; i++) {
|
|
527
596
|
const line = lines[i];
|
|
528
597
|
const lineNo = i + 1;
|
|
@@ -538,6 +607,33 @@ function lintGeneratedUi(source, options = {}) {
|
|
|
538
607
|
continue;
|
|
539
608
|
}
|
|
540
609
|
if (isCommentOrImport(line)) continue;
|
|
610
|
+
const cardMatch = line.match(/<(Card|SurfaceCard|ArtifactCard)\b/);
|
|
611
|
+
if (cardMatch) {
|
|
612
|
+
const isSelfClosing = /\/>/.test(line) && line.indexOf(cardMatch[0]) < line.indexOf("/>");
|
|
613
|
+
if (!isSelfClosing) {
|
|
614
|
+
openCards.push({ type: cardMatch[1], line: lineNo });
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
const closeMatch = line.match(/<\/(Card|SurfaceCard|ArtifactCard)\b/);
|
|
618
|
+
if (closeMatch && openCards.length > 0) {
|
|
619
|
+
const idx = openCards.map((c) => c.type).lastIndexOf(closeMatch[1]);
|
|
620
|
+
if (idx !== -1) {
|
|
621
|
+
openCards.splice(idx, 1);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
if (openCards.length > 0) {
|
|
625
|
+
const tableMatch = line.match(/<(DataTable|table|Table)\b/);
|
|
626
|
+
if (tableMatch) {
|
|
627
|
+
const parentCard = openCards[openCards.length - 1];
|
|
628
|
+
findings.push({
|
|
629
|
+
rule: "no-table-in-card",
|
|
630
|
+
severity: "error",
|
|
631
|
+
line: lineNo,
|
|
632
|
+
message: `Table inside card. Never wrap a <${tableMatch[1]}> or table inside a <${parentCard.type}> (opened on L${parentCard.line}). Place the table directly on the Page or Section instead.`,
|
|
633
|
+
snippet: line.trim().slice(0, 120)
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
}
|
|
541
637
|
const rawColors = line.match(RAW_COLOR_RE);
|
|
542
638
|
if (rawColors) {
|
|
543
639
|
for (const m of rawColors) {
|
|
@@ -578,6 +674,15 @@ function lintGeneratedUi(source, options = {}) {
|
|
|
578
674
|
snippet: line.trim().slice(0, 120)
|
|
579
675
|
});
|
|
580
676
|
}
|
|
677
|
+
if (COLORED_HOVER_RE.test(line)) {
|
|
678
|
+
findings.push({
|
|
679
|
+
rule: "no-colored-hover",
|
|
680
|
+
severity: "warn",
|
|
681
|
+
line: lineNo,
|
|
682
|
+
message: "Colored hover background/gradient. House style: interactive cards and list items must use neutral hover states \u2014 never hard-code colored backgrounds or borders on hover.",
|
|
683
|
+
snippet: line.trim().slice(0, 120)
|
|
684
|
+
});
|
|
685
|
+
}
|
|
581
686
|
if (BOLD_VALUE_RE.test(line)) {
|
|
582
687
|
findings.push({
|
|
583
688
|
rule: "bold-metric",
|
|
@@ -624,6 +729,44 @@ function lintGeneratedUi(source, options = {}) {
|
|
|
624
729
|
if (hits) iconUsageCount += hits.length;
|
|
625
730
|
}
|
|
626
731
|
}
|
|
732
|
+
if (pageTitle) {
|
|
733
|
+
const titleMatch = line.match(/<(Section|ChartPanel|Card|DataTable|SurfaceCard)\s+[^>]*\btitle=(?:"([^"]+)"|\{["']([^"']+)["']\})/);
|
|
734
|
+
if (titleMatch) {
|
|
735
|
+
const element = titleMatch[1];
|
|
736
|
+
const titleVal = (titleMatch[2] || titleMatch[3]).trim().toLowerCase();
|
|
737
|
+
if (titleVal === pageTitle || titleVal.includes(pageTitle) || pageTitle.includes(titleVal)) {
|
|
738
|
+
findings.push({
|
|
739
|
+
rule: "no-title-repetition",
|
|
740
|
+
severity: "warn",
|
|
741
|
+
line: lineNo,
|
|
742
|
+
message: `Title repetition. The <${element}> title "${titleVal}" repeats or is very similar to the <Page> title "${pageTitle}". Drop the title from the child element or use a title-less Section to avoid redundant headings.`,
|
|
743
|
+
snippet: line.trim().slice(0, 120)
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
if (hasChat) {
|
|
749
|
+
const wrappingMatch = line.match(/<(Card|Section|SurfaceCard|FormSection|SettingsSection)\b/);
|
|
750
|
+
if (wrappingMatch) {
|
|
751
|
+
findings.push({
|
|
752
|
+
rule: "no-chat-wrapping",
|
|
753
|
+
severity: "error",
|
|
754
|
+
line: lineNo,
|
|
755
|
+
message: `Chat component wrapping. Never wrap TimbalChat or AppChatPanel inside a <${wrappingMatch[1]}> or custom bordered container. Let the chat component fill the page or slot directly.`,
|
|
756
|
+
snippet: line.trim().slice(0, 120)
|
|
757
|
+
});
|
|
758
|
+
}
|
|
759
|
+
const headingMatch = line.match(/<(h[1-6])\b/);
|
|
760
|
+
if (headingMatch) {
|
|
761
|
+
findings.push({
|
|
762
|
+
rule: "no-chat-wrapping",
|
|
763
|
+
severity: "error",
|
|
764
|
+
line: lineNo,
|
|
765
|
+
message: `Custom heading in chat view. Do not render custom <${headingMatch[1]}> headings on the chat page. Pass welcome.heading to TimbalChat if you need to customize the welcome title.`,
|
|
766
|
+
snippet: line.trim().slice(0, 120)
|
|
767
|
+
});
|
|
768
|
+
}
|
|
769
|
+
}
|
|
627
770
|
}
|
|
628
771
|
if (usesLucide && iconUsageCount > maxIcons) {
|
|
629
772
|
findings.push({
|
|
@@ -1356,7 +1499,20 @@ var TimbalThemeStyle = ({
|
|
|
1356
1499
|
|
|
1357
1500
|
// src/design/app-classes.ts
|
|
1358
1501
|
var appPageColumnClass = "mx-auto w-full max-w-[100rem] px-4 md:px-6 lg:px-8";
|
|
1359
|
-
var
|
|
1502
|
+
var PAGE_WIDTH_MAXW = {
|
|
1503
|
+
full: "max-w-none",
|
|
1504
|
+
wide: "max-w-[100rem]",
|
|
1505
|
+
default: "max-w-7xl",
|
|
1506
|
+
centered: "max-w-5xl",
|
|
1507
|
+
narrow: "max-w-3xl",
|
|
1508
|
+
prose: "max-w-2xl"
|
|
1509
|
+
};
|
|
1510
|
+
function appPageColumn(width, density = "default") {
|
|
1511
|
+
const lateral = density === "compact" ? "px-3 md:px-4" : "px-4 md:px-6 lg:px-8";
|
|
1512
|
+
const maxW = width ? PAGE_WIDTH_MAXW[width] : density === "compact" ? "max-w-none" : "max-w-[100rem]";
|
|
1513
|
+
return cn("mx-auto w-full", maxW, lateral);
|
|
1514
|
+
}
|
|
1515
|
+
var appShellTopbarInsetClass = "mx-auto w-full max-w-[100rem] px-4 md:px-6 lg:px-8";
|
|
1360
1516
|
var appShellInsetTopClass = "pt-4 md:pt-6";
|
|
1361
1517
|
var appShellInsetBottomClass = "pb-8 md:pb-10";
|
|
1362
1518
|
var appShellTopbarRowClass = cn(
|
|
@@ -1423,6 +1579,15 @@ var APP_DENSITY_CLASSES = {
|
|
|
1423
1579
|
default: appPageHeaderClass,
|
|
1424
1580
|
compact: "flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between pb-2 pt-1"
|
|
1425
1581
|
},
|
|
1582
|
+
/**
|
|
1583
|
+
* Vertical rhythm between a `Page`'s direct content blocks. Page-level gap so
|
|
1584
|
+
* stacked blocks (FilterBar + DataTable, MetricRow + ChartPanel, bare cards)
|
|
1585
|
+
* never render flush — the #1 source of gap-less generated layouts.
|
|
1586
|
+
*/
|
|
1587
|
+
pageStack: {
|
|
1588
|
+
default: "flex flex-col gap-6",
|
|
1589
|
+
compact: "flex flex-col gap-4"
|
|
1590
|
+
},
|
|
1426
1591
|
section: {
|
|
1427
1592
|
default: appSectionClass,
|
|
1428
1593
|
compact: "flex flex-col gap-2 py-2"
|
|
@@ -1448,12 +1613,12 @@ var APP_DENSITY_CLASSES = {
|
|
|
1448
1613
|
compact: "relative flex min-w-0 flex-1 flex-col gap-1 px-3 py-2 text-left font-normal"
|
|
1449
1614
|
},
|
|
1450
1615
|
metricChartRegion: {
|
|
1451
|
-
default: "relative min-h-0 w-full overflow-x-hidden
|
|
1452
|
-
compact: "relative min-h-0 w-full overflow-x-hidden
|
|
1616
|
+
default: "relative min-h-0 w-full overflow-x-hidden pt-2",
|
|
1617
|
+
compact: "relative min-h-0 w-full overflow-x-hidden pt-1"
|
|
1453
1618
|
},
|
|
1454
1619
|
metricChartPlotRegion: {
|
|
1455
|
-
default: "relative min-h-0 w-full overflow-x-hidden
|
|
1456
|
-
compact: "relative min-h-0 w-full overflow-x-hidden
|
|
1620
|
+
default: "relative min-h-0 w-full overflow-x-hidden px-0 pt-5 pb-3",
|
|
1621
|
+
compact: "relative min-h-0 w-full overflow-x-hidden px-0 pt-3 pb-2"
|
|
1457
1622
|
},
|
|
1458
1623
|
chartPanelBody: {
|
|
1459
1624
|
default: "pt-2 pb-3",
|
|
@@ -1482,8 +1647,71 @@ function useAppDensityClass(key, override) {
|
|
|
1482
1647
|
return appDensityClass(key, override ?? inherited);
|
|
1483
1648
|
}
|
|
1484
1649
|
|
|
1650
|
+
// src/charts/sparkline.tsx
|
|
1651
|
+
import { useId } from "react";
|
|
1652
|
+
import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1653
|
+
var Sparkline = ({
|
|
1654
|
+
data,
|
|
1655
|
+
dataKey = "value",
|
|
1656
|
+
color = "var(--primary, #6366f1)",
|
|
1657
|
+
area = true,
|
|
1658
|
+
width = 96,
|
|
1659
|
+
height = 28,
|
|
1660
|
+
strokeWidth = 1.5,
|
|
1661
|
+
className,
|
|
1662
|
+
ariaLabel = "Trend"
|
|
1663
|
+
}) => {
|
|
1664
|
+
const uid = useId();
|
|
1665
|
+
const values = data.map((d) => typeof d === "number" ? d : toNum(d[dataKey]));
|
|
1666
|
+
if (values.length === 0) {
|
|
1667
|
+
return /* @__PURE__ */ jsx3("span", { className: cn("inline-block", className), style: { width, height } });
|
|
1668
|
+
}
|
|
1669
|
+
const pad = strokeWidth + 1;
|
|
1670
|
+
const min = Math.min(...values);
|
|
1671
|
+
const max = Math.max(...values);
|
|
1672
|
+
const range = max - min || 1;
|
|
1673
|
+
const innerW = width - pad * 2;
|
|
1674
|
+
const innerH = height - pad * 2;
|
|
1675
|
+
const points = values.map((v, i) => ({
|
|
1676
|
+
x: pad + (values.length > 1 ? i / (values.length - 1) * innerW : innerW / 2),
|
|
1677
|
+
y: pad + innerH - (v - min) / range * innerH
|
|
1678
|
+
}));
|
|
1679
|
+
return /* @__PURE__ */ jsxs2(
|
|
1680
|
+
"svg",
|
|
1681
|
+
{
|
|
1682
|
+
width,
|
|
1683
|
+
height,
|
|
1684
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
1685
|
+
className: cn("block", className),
|
|
1686
|
+
role: "img",
|
|
1687
|
+
"aria-label": ariaLabel,
|
|
1688
|
+
preserveAspectRatio: "none",
|
|
1689
|
+
children: [
|
|
1690
|
+
area && /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
1691
|
+
/* @__PURE__ */ jsx3("defs", { children: /* @__PURE__ */ jsxs2("linearGradient", { id: `${uid}-spark`, x1: "0", x2: "0", y1: "0", y2: "1", children: [
|
|
1692
|
+
/* @__PURE__ */ jsx3("stop", { offset: "0%", style: { stopColor: color, stopOpacity: 0.25 } }),
|
|
1693
|
+
/* @__PURE__ */ jsx3("stop", { offset: "100%", style: { stopColor: color, stopOpacity: 0 } })
|
|
1694
|
+
] }) }),
|
|
1695
|
+
/* @__PURE__ */ jsx3("path", { d: monotoneAreaPath(points, height - pad), fill: `url(#${uid}-spark)` })
|
|
1696
|
+
] }),
|
|
1697
|
+
/* @__PURE__ */ jsx3(
|
|
1698
|
+
"path",
|
|
1699
|
+
{
|
|
1700
|
+
d: monotoneLinePath(points),
|
|
1701
|
+
fill: "none",
|
|
1702
|
+
stroke: color,
|
|
1703
|
+
strokeWidth,
|
|
1704
|
+
strokeLinecap: "round",
|
|
1705
|
+
strokeLinejoin: "round"
|
|
1706
|
+
}
|
|
1707
|
+
)
|
|
1708
|
+
]
|
|
1709
|
+
}
|
|
1710
|
+
);
|
|
1711
|
+
};
|
|
1712
|
+
|
|
1485
1713
|
// src/app/data/metrics-shared.tsx
|
|
1486
|
-
import { jsx as
|
|
1714
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1487
1715
|
var metricCardShellClass = cn(
|
|
1488
1716
|
studioIntegrationCardClass,
|
|
1489
1717
|
"aui-app-metric-card shadow-none",
|
|
@@ -1493,18 +1721,22 @@ var metricTilesRowClass = "grid w-full min-w-0";
|
|
|
1493
1721
|
var metricCellDividerClass = "border-r border-border/40";
|
|
1494
1722
|
var MetricCardHeader = ({
|
|
1495
1723
|
title,
|
|
1724
|
+
titleTag,
|
|
1496
1725
|
titleId,
|
|
1497
1726
|
description,
|
|
1498
1727
|
actions
|
|
1499
1728
|
}) => {
|
|
1500
1729
|
const headerClass = useAppDensityClass("metricCardHeader");
|
|
1501
1730
|
if (!title && !description && !actions) return null;
|
|
1502
|
-
return /* @__PURE__ */
|
|
1503
|
-
/* @__PURE__ */
|
|
1504
|
-
|
|
1505
|
-
|
|
1731
|
+
return /* @__PURE__ */ jsxs3("header", { className: cn(headerClass, "items-center"), children: [
|
|
1732
|
+
/* @__PURE__ */ jsxs3("div", { className: "min-w-0", children: [
|
|
1733
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2.5", children: [
|
|
1734
|
+
title ? /* @__PURE__ */ jsx4("h3", { id: titleId, className: "text-sm font-semibold text-foreground tracking-tight select-none", children: title }) : null,
|
|
1735
|
+
titleTag ? /* @__PURE__ */ jsx4("span", { className: "inline-flex rounded-full bg-muted/70 px-2 py-0.5 text-[10px] font-medium text-muted-foreground border border-border/30 tracking-tight leading-none select-none", children: titleTag }) : null
|
|
1736
|
+
] }),
|
|
1737
|
+
description ? /* @__PURE__ */ jsx4("p", { className: "mt-1 text-xs text-muted-foreground leading-normal select-none", children: description }) : null
|
|
1506
1738
|
] }),
|
|
1507
|
-
actions ? /* @__PURE__ */
|
|
1739
|
+
actions ? /* @__PURE__ */ jsx4("div", { className: "shrink-0 flex items-center", children: actions }) : null
|
|
1508
1740
|
] });
|
|
1509
1741
|
};
|
|
1510
1742
|
function metricTilesGridColsClass(n) {
|
|
@@ -1515,6 +1747,8 @@ function metricTilesGridColsClass(n) {
|
|
|
1515
1747
|
return "grid-cols-2";
|
|
1516
1748
|
case 3:
|
|
1517
1749
|
return "grid-cols-3";
|
|
1750
|
+
case 4:
|
|
1751
|
+
return "grid-cols-2 md:grid-cols-4";
|
|
1518
1752
|
case 5:
|
|
1519
1753
|
return "grid-cols-2 sm:grid-cols-5";
|
|
1520
1754
|
case 6:
|
|
@@ -1525,12 +1759,25 @@ function metricTilesGridColsClass(n) {
|
|
|
1525
1759
|
}
|
|
1526
1760
|
|
|
1527
1761
|
// src/app/data/MetricTile.tsx
|
|
1528
|
-
import { Fragment as
|
|
1762
|
+
import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1529
1763
|
var trendToneClass = {
|
|
1530
1764
|
up: "border-border/80 bg-muted/40 text-muted-foreground",
|
|
1531
1765
|
down: "border-border/80 bg-muted/40 text-muted-foreground",
|
|
1532
1766
|
neutral: "border-border/80 bg-muted/30 text-muted-foreground"
|
|
1533
1767
|
};
|
|
1768
|
+
var inlineTrendToneClass = {
|
|
1769
|
+
up: "text-blue-500/90 dark:text-blue-400/95 font-medium",
|
|
1770
|
+
down: "text-rose-500/90 dark:text-rose-400/95 font-medium",
|
|
1771
|
+
neutral: "text-muted-foreground/80"
|
|
1772
|
+
};
|
|
1773
|
+
var activeToneClass = {
|
|
1774
|
+
default: "bg-foreground dark:bg-white",
|
|
1775
|
+
primary: "bg-primary",
|
|
1776
|
+
success: "bg-emerald-500",
|
|
1777
|
+
warn: "bg-amber-500",
|
|
1778
|
+
danger: "bg-destructive",
|
|
1779
|
+
neutral: "bg-border"
|
|
1780
|
+
};
|
|
1534
1781
|
var metricTileInteractiveExtraClass = cn(
|
|
1535
1782
|
"bg-transparent hover:bg-transparent active:bg-transparent",
|
|
1536
1783
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-foreground/10"
|
|
@@ -1541,58 +1788,86 @@ var MetricTile = ({
|
|
|
1541
1788
|
unit,
|
|
1542
1789
|
trend,
|
|
1543
1790
|
trendTone = "neutral",
|
|
1791
|
+
trendVariant = "pill",
|
|
1544
1792
|
active = false,
|
|
1793
|
+
activeTone = "default",
|
|
1545
1794
|
showDivider = false,
|
|
1546
1795
|
onSelect,
|
|
1796
|
+
sparklineData,
|
|
1797
|
+
sparklineConfig,
|
|
1798
|
+
sparkline,
|
|
1547
1799
|
ariaLabel,
|
|
1548
1800
|
className
|
|
1549
1801
|
}) => {
|
|
1550
1802
|
const metricTileBaseClass = useAppDensityClass("metricTile");
|
|
1551
|
-
const
|
|
1552
|
-
|
|
1803
|
+
const hasSparkline = Boolean(sparkline || sparklineData);
|
|
1804
|
+
const content = /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
1805
|
+
active ? /* @__PURE__ */ jsx5(
|
|
1553
1806
|
"span",
|
|
1554
1807
|
{
|
|
1555
1808
|
"aria-hidden": true,
|
|
1556
|
-
className:
|
|
1809
|
+
className: cn(
|
|
1810
|
+
"absolute inset-x-0 bottom-0 h-0.5 z-20 transition-colors duration-200",
|
|
1811
|
+
activeToneClass[activeTone]
|
|
1812
|
+
)
|
|
1557
1813
|
}
|
|
1558
1814
|
) : null,
|
|
1559
|
-
/* @__PURE__ */
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
"
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1815
|
+
hasSparkline ? /* @__PURE__ */ jsx5("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__ */ jsx5(
|
|
1816
|
+
Sparkline,
|
|
1817
|
+
{
|
|
1818
|
+
data: sparklineData,
|
|
1819
|
+
width: 160,
|
|
1820
|
+
height: 36,
|
|
1821
|
+
className: "w-full h-full",
|
|
1822
|
+
color: trendTone === "up" ? "var(--primary, #3b82f6)" : trendTone === "down" ? "var(--destructive, #f43f5e)" : "var(--muted-foreground, #64748b)",
|
|
1823
|
+
...sparklineConfig
|
|
1824
|
+
}
|
|
1825
|
+
) }) : null,
|
|
1826
|
+
/* @__PURE__ */ jsxs4("div", { className: "relative z-10 flex flex-col gap-1 w-full text-left", children: [
|
|
1827
|
+
/* @__PURE__ */ jsx5("span", { className: "text-xs font-semibold text-muted-foreground/80 tracking-tight", children: label }),
|
|
1828
|
+
/* @__PURE__ */ jsxs4("span", { className: "flex items-center gap-2", children: [
|
|
1829
|
+
/* @__PURE__ */ jsxs4("span", { className: "flex items-baseline gap-1", children: [
|
|
1830
|
+
/* @__PURE__ */ jsx5("span", { className: "text-2xl font-normal tracking-tight text-foreground tabular-nums", children: value }),
|
|
1831
|
+
unit ? /* @__PURE__ */ jsx5("span", { className: "text-xs font-medium text-muted-foreground", children: unit }) : null
|
|
1832
|
+
] }),
|
|
1833
|
+
trend ? trendVariant === "inline" ? /* @__PURE__ */ jsx5("span", { className: cn("text-xs leading-none select-none", inlineTrendToneClass[trendTone]), children: trend }) : /* @__PURE__ */ jsx5(
|
|
1834
|
+
"span",
|
|
1835
|
+
{
|
|
1836
|
+
className: cn(
|
|
1837
|
+
"rounded-full border px-1.5 py-0.5 text-xs font-normal select-none",
|
|
1838
|
+
trendToneClass[trendTone]
|
|
1839
|
+
),
|
|
1840
|
+
children: trend
|
|
1841
|
+
}
|
|
1842
|
+
) : null
|
|
1843
|
+
] })
|
|
1575
1844
|
] })
|
|
1576
1845
|
] });
|
|
1577
1846
|
const divider = showDivider ? metricCellDividerClass : void 0;
|
|
1578
1847
|
if (onSelect) {
|
|
1579
|
-
return /* @__PURE__ */
|
|
1848
|
+
return /* @__PURE__ */ jsx5(
|
|
1580
1849
|
"button",
|
|
1581
1850
|
{
|
|
1582
1851
|
type: "button",
|
|
1583
1852
|
onClick: onSelect,
|
|
1584
1853
|
"aria-pressed": active,
|
|
1585
1854
|
"aria-label": ariaLabel,
|
|
1586
|
-
className: cn(
|
|
1855
|
+
className: cn(
|
|
1856
|
+
metricTileBaseClass,
|
|
1857
|
+
"transition-all duration-200 hover:bg-muted/10",
|
|
1858
|
+
metricTileInteractiveExtraClass,
|
|
1859
|
+
divider,
|
|
1860
|
+
className
|
|
1861
|
+
),
|
|
1587
1862
|
children: content
|
|
1588
1863
|
}
|
|
1589
1864
|
);
|
|
1590
1865
|
}
|
|
1591
|
-
return /* @__PURE__ */
|
|
1866
|
+
return /* @__PURE__ */ jsx5("div", { className: cn(metricTileBaseClass, divider, className), children: content });
|
|
1592
1867
|
};
|
|
1593
1868
|
|
|
1594
1869
|
// src/app/theme/ThemePresetGallery.tsx
|
|
1595
|
-
import { jsx as
|
|
1870
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1596
1871
|
|
|
1597
1872
|
// src/app/layout/app-shell-chat-context.tsx
|
|
1598
1873
|
import { createContext as createContext2, useContext as useContext2 } from "react";
|
|
@@ -1618,8 +1893,8 @@ function useAppShellNav() {
|
|
|
1618
1893
|
|
|
1619
1894
|
// src/app/layout/AppShell.tsx
|
|
1620
1895
|
import { motion, useReducedMotion } from "motion/react";
|
|
1621
|
-
import { useCallback, useMemo, useState } from "react";
|
|
1622
|
-
import { jsx as
|
|
1896
|
+
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
1897
|
+
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1623
1898
|
var floatingTriggerClass = cn(
|
|
1624
1899
|
"aui-app-shell-chat-trigger-fixed fixed z-50 rounded-full px-5 py-2.5 text-sm font-medium shadow-card-elevated",
|
|
1625
1900
|
"bg-primary text-primary-foreground transition-colors hover:bg-primary/90",
|
|
@@ -1642,21 +1917,32 @@ var AppShellBody = ({
|
|
|
1642
1917
|
insetExpanded,
|
|
1643
1918
|
children
|
|
1644
1919
|
}) => {
|
|
1920
|
+
const [isMobile, setIsMobile] = useState(() => {
|
|
1921
|
+
if (typeof window === "undefined") return false;
|
|
1922
|
+
return window.innerWidth < 768;
|
|
1923
|
+
});
|
|
1924
|
+
useEffect(() => {
|
|
1925
|
+
if (typeof window === "undefined") return;
|
|
1926
|
+
const onResize = () => setIsMobile(window.innerWidth < 768);
|
|
1927
|
+
onResize();
|
|
1928
|
+
window.addEventListener("resize", onResize);
|
|
1929
|
+
return () => window.removeEventListener("resize", onResize);
|
|
1930
|
+
}, []);
|
|
1645
1931
|
const reducedMotion = useReducedMotion();
|
|
1646
1932
|
const layoutDirection = insetExpanded ? "expand" : "collapse";
|
|
1647
1933
|
const layoutTransition = studioSidebarWidthTransition(
|
|
1648
1934
|
!!reducedMotion,
|
|
1649
1935
|
layoutDirection
|
|
1650
1936
|
);
|
|
1651
|
-
const insetPadding = sidebar ? insetPaddingPx : 0;
|
|
1652
|
-
return /* @__PURE__ */
|
|
1937
|
+
const insetPadding = sidebar && !isMobile ? insetPaddingPx : 0;
|
|
1938
|
+
return /* @__PURE__ */ jsx7(
|
|
1653
1939
|
motion.div,
|
|
1654
1940
|
{
|
|
1655
1941
|
className: "aui-app-shell-body relative z-10 flex min-h-0 min-w-0 flex-1 flex-col",
|
|
1656
1942
|
initial: false,
|
|
1657
1943
|
animate: { paddingLeft: insetPadding },
|
|
1658
1944
|
transition: layoutTransition,
|
|
1659
|
-
children: /* @__PURE__ */
|
|
1945
|
+
children: /* @__PURE__ */ jsxs6(
|
|
1660
1946
|
"div",
|
|
1661
1947
|
{
|
|
1662
1948
|
className: cn(
|
|
@@ -1667,8 +1953,8 @@ var AppShellBody = ({
|
|
|
1667
1953
|
!topbarContent && appShellInsetTopClass
|
|
1668
1954
|
),
|
|
1669
1955
|
children: [
|
|
1670
|
-
topbarContent ? /* @__PURE__ */
|
|
1671
|
-
/* @__PURE__ */
|
|
1956
|
+
topbarContent ? /* @__PURE__ */ jsx7("header", { className: cn("aui-app-shell-topbar-region", appShellTopbarStickyClass), children: /* @__PURE__ */ jsx7("div", { className: appShellTopbarInsetClass, children: topbarContent }) }) : null,
|
|
1957
|
+
/* @__PURE__ */ jsx7(
|
|
1672
1958
|
"main",
|
|
1673
1959
|
{
|
|
1674
1960
|
className: cn(
|
|
@@ -1748,7 +2034,7 @@ var AppShell = ({
|
|
|
1748
2034
|
setInsetPaddingPx(insetPx);
|
|
1749
2035
|
}, []);
|
|
1750
2036
|
const insetExpanded = insetPaddingPx >= SIDEBAR_INSET_PX_EXPANDED;
|
|
1751
|
-
const shellBody = /* @__PURE__ */
|
|
2037
|
+
const shellBody = /* @__PURE__ */ jsx7(
|
|
1752
2038
|
AppShellBody,
|
|
1753
2039
|
{
|
|
1754
2040
|
sidebar,
|
|
@@ -1760,7 +2046,7 @@ var AppShell = ({
|
|
|
1760
2046
|
children
|
|
1761
2047
|
}
|
|
1762
2048
|
);
|
|
1763
|
-
const tree = /* @__PURE__ */
|
|
2049
|
+
const tree = /* @__PURE__ */ jsx7(ShellInsetProvider, { value: sidebar ? reportShellInset : null, children: /* @__PURE__ */ jsxs6(
|
|
1764
2050
|
"div",
|
|
1765
2051
|
{
|
|
1766
2052
|
className: cn(
|
|
@@ -1770,7 +2056,7 @@ var AppShell = ({
|
|
|
1770
2056
|
style: studioChromeShellStyle,
|
|
1771
2057
|
children: [
|
|
1772
2058
|
sidebar,
|
|
1773
|
-
sidebar && navOpen ? /* @__PURE__ */
|
|
2059
|
+
sidebar && navOpen ? /* @__PURE__ */ jsx7(
|
|
1774
2060
|
"button",
|
|
1775
2061
|
{
|
|
1776
2062
|
type: "button",
|
|
@@ -1780,7 +2066,7 @@ var AppShell = ({
|
|
|
1780
2066
|
}
|
|
1781
2067
|
) : null,
|
|
1782
2068
|
shellBody,
|
|
1783
|
-
hasChat && chatOpen ? /* @__PURE__ */
|
|
2069
|
+
hasChat && chatOpen ? /* @__PURE__ */ jsx7(
|
|
1784
2070
|
"div",
|
|
1785
2071
|
{
|
|
1786
2072
|
className: floatingPanelClass,
|
|
@@ -1793,7 +2079,7 @@ var AppShell = ({
|
|
|
1793
2079
|
children: chat
|
|
1794
2080
|
}
|
|
1795
2081
|
) : null,
|
|
1796
|
-
hasChat && chatCollapsible && !chatOpen && !hideChatTrigger ? /* @__PURE__ */
|
|
2082
|
+
hasChat && chatCollapsible && !chatOpen && !hideChatTrigger ? /* @__PURE__ */ jsx7(
|
|
1797
2083
|
"button",
|
|
1798
2084
|
{
|
|
1799
2085
|
type: "button",
|
|
@@ -1806,11 +2092,11 @@ var AppShell = ({
|
|
|
1806
2092
|
]
|
|
1807
2093
|
}
|
|
1808
2094
|
) });
|
|
1809
|
-
const withNav = /* @__PURE__ */
|
|
2095
|
+
const withNav = /* @__PURE__ */ jsx7(AppShellNavProvider, { value: navControls, children: tree });
|
|
1810
2096
|
if (!hasChat) {
|
|
1811
2097
|
return withNav;
|
|
1812
2098
|
}
|
|
1813
|
-
return /* @__PURE__ */
|
|
2099
|
+
return /* @__PURE__ */ jsx7(
|
|
1814
2100
|
AppShellChatProvider,
|
|
1815
2101
|
{
|
|
1816
2102
|
value: {
|
|
@@ -1824,23 +2110,6 @@ var AppShell = ({
|
|
|
1824
2110
|
);
|
|
1825
2111
|
};
|
|
1826
2112
|
|
|
1827
|
-
// src/app/layout/AppShellTopbar.tsx
|
|
1828
|
-
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1829
|
-
var AppShellTopbar = ({
|
|
1830
|
-
start,
|
|
1831
|
-
actions,
|
|
1832
|
-
children,
|
|
1833
|
-
className
|
|
1834
|
-
}) => {
|
|
1835
|
-
return /* @__PURE__ */ jsxs6("div", { className: cn("aui-app-shell-topbar", appShellTopbarRowClass, className), children: [
|
|
1836
|
-
/* @__PURE__ */ jsxs6("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
|
|
1837
|
-
start,
|
|
1838
|
-
children
|
|
1839
|
-
] }),
|
|
1840
|
-
actions ? /* @__PURE__ */ jsx7("div", { className: "aui-app-shell-topbar-actions flex shrink-0 items-center gap-2", children: actions }) : null
|
|
1841
|
-
] });
|
|
1842
|
-
};
|
|
1843
|
-
|
|
1844
2113
|
// src/app/layout/AppShellChatTrigger.tsx
|
|
1845
2114
|
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
1846
2115
|
var floatingPositionClass = "fixed bottom-6 right-6 z-50 max-sm:bottom-4 max-sm:right-4";
|
|
@@ -1921,34 +2190,32 @@ import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
|
1921
2190
|
var PageFrame = ({
|
|
1922
2191
|
children,
|
|
1923
2192
|
breadcrumbs,
|
|
2193
|
+
width,
|
|
1924
2194
|
fill = false,
|
|
2195
|
+
fillPadded = false,
|
|
1925
2196
|
className,
|
|
1926
2197
|
...headerProps
|
|
1927
2198
|
}) => {
|
|
1928
2199
|
const density = useAppDensity();
|
|
1929
|
-
const
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
breadcrumbs,
|
|
1941
|
-
/* @__PURE__ */ jsx11(PageHeader, { ...headerProps }),
|
|
1942
|
-
children
|
|
1943
|
-
]
|
|
1944
|
-
}
|
|
1945
|
-
);
|
|
2200
|
+
const stackClass = useAppDensityClass("pageStack");
|
|
2201
|
+
const columnClass = appPageColumn(width, density);
|
|
2202
|
+
const rootClass = fill ? cn(
|
|
2203
|
+
"flex min-h-0 min-w-0 flex-1 flex-col",
|
|
2204
|
+
fillPadded && columnClass
|
|
2205
|
+
) : columnClass;
|
|
2206
|
+
return /* @__PURE__ */ jsxs8("div", { className: cn("aui-app-page", rootClass, className), "data-density": density, children: [
|
|
2207
|
+
breadcrumbs,
|
|
2208
|
+
/* @__PURE__ */ jsx11(PageHeader, { ...headerProps }),
|
|
2209
|
+
fill ? children : /* @__PURE__ */ jsx11("div", { className: cn("aui-app-page-stack", stackClass), children })
|
|
2210
|
+
] });
|
|
1946
2211
|
};
|
|
1947
2212
|
var Page = ({
|
|
1948
2213
|
density = "default",
|
|
1949
2214
|
children,
|
|
1950
2215
|
breadcrumbs,
|
|
2216
|
+
width,
|
|
1951
2217
|
fill = false,
|
|
2218
|
+
fillPadded = false,
|
|
1952
2219
|
className,
|
|
1953
2220
|
...headerProps
|
|
1954
2221
|
}) => {
|
|
@@ -1956,7 +2223,9 @@ var Page = ({
|
|
|
1956
2223
|
PageFrame,
|
|
1957
2224
|
{
|
|
1958
2225
|
breadcrumbs,
|
|
2226
|
+
width,
|
|
1959
2227
|
fill,
|
|
2228
|
+
fillPadded,
|
|
1960
2229
|
className,
|
|
1961
2230
|
...headerProps,
|
|
1962
2231
|
children
|
|
@@ -1981,15 +2250,61 @@ var Section = ({
|
|
|
1981
2250
|
] });
|
|
1982
2251
|
};
|
|
1983
2252
|
|
|
2253
|
+
// src/app/layout/Stack.tsx
|
|
2254
|
+
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
2255
|
+
var GAP_CLASS = {
|
|
2256
|
+
none: "gap-0",
|
|
2257
|
+
xs: "gap-1",
|
|
2258
|
+
sm: "gap-2",
|
|
2259
|
+
md: "gap-4",
|
|
2260
|
+
lg: "gap-6",
|
|
2261
|
+
xl: "gap-8"
|
|
2262
|
+
};
|
|
2263
|
+
var ALIGN_CLASS = {
|
|
2264
|
+
start: "items-start",
|
|
2265
|
+
center: "items-center",
|
|
2266
|
+
end: "items-end",
|
|
2267
|
+
stretch: "items-stretch"
|
|
2268
|
+
};
|
|
2269
|
+
var JUSTIFY_CLASS = {
|
|
2270
|
+
start: "justify-start",
|
|
2271
|
+
center: "justify-center",
|
|
2272
|
+
end: "justify-end",
|
|
2273
|
+
between: "justify-between"
|
|
2274
|
+
};
|
|
2275
|
+
var Stack = ({
|
|
2276
|
+
children,
|
|
2277
|
+
direction = "vertical",
|
|
2278
|
+
gap = "md",
|
|
2279
|
+
align,
|
|
2280
|
+
justify,
|
|
2281
|
+
wrap = false,
|
|
2282
|
+
className
|
|
2283
|
+
}) => /* @__PURE__ */ jsx13(
|
|
2284
|
+
"div",
|
|
2285
|
+
{
|
|
2286
|
+
className: cn(
|
|
2287
|
+
"flex min-w-0",
|
|
2288
|
+
direction === "vertical" ? "flex-col" : "flex-row",
|
|
2289
|
+
GAP_CLASS[gap],
|
|
2290
|
+
align && ALIGN_CLASS[align],
|
|
2291
|
+
justify && JUSTIFY_CLASS[justify],
|
|
2292
|
+
wrap && "flex-wrap",
|
|
2293
|
+
className
|
|
2294
|
+
),
|
|
2295
|
+
children
|
|
2296
|
+
}
|
|
2297
|
+
);
|
|
2298
|
+
|
|
1984
2299
|
// src/app/copilot/app-copilot-context.tsx
|
|
1985
2300
|
import { createContext as createContext4, useContext as useContext4 } from "react";
|
|
1986
|
-
import { jsx as
|
|
2301
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
1987
2302
|
var AppCopilotContext = createContext4(null);
|
|
1988
2303
|
var AppCopilotProvider = ({
|
|
1989
2304
|
value,
|
|
1990
2305
|
children
|
|
1991
2306
|
}) => {
|
|
1992
|
-
return /* @__PURE__ */
|
|
2307
|
+
return /* @__PURE__ */ jsx14(AppCopilotContext.Provider, { value, children });
|
|
1993
2308
|
};
|
|
1994
2309
|
function useAppCopilotContext() {
|
|
1995
2310
|
return useContext4(AppCopilotContext) ?? {};
|
|
@@ -1997,7 +2312,7 @@ function useAppCopilotContext() {
|
|
|
1997
2312
|
|
|
1998
2313
|
// src/app/chat/AppChatPanel.tsx
|
|
1999
2314
|
import { XIcon } from "lucide-react";
|
|
2000
|
-
import { jsx as
|
|
2315
|
+
import { jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2001
2316
|
var shellClass = "aui-app-chat-panel flex h-full min-h-0 flex-col overflow-hidden";
|
|
2002
2317
|
var chromeClass = cn(
|
|
2003
2318
|
"aui-app-chat-panel-chrome relative z-20 flex min-h-10 shrink-0 items-center justify-end px-2 pt-2"
|
|
@@ -2043,17 +2358,17 @@ var AppChatPanel = ({
|
|
|
2043
2358
|
}) => {
|
|
2044
2359
|
const shellChat = useAppShellChat();
|
|
2045
2360
|
return /* @__PURE__ */ jsxs10("div", { className: cn(shellClass, className), children: [
|
|
2046
|
-
shellChat?.collapsible ? /* @__PURE__ */
|
|
2361
|
+
shellChat?.collapsible ? /* @__PURE__ */ jsx15("div", { className: chromeClass, children: /* @__PURE__ */ jsx15(
|
|
2047
2362
|
"button",
|
|
2048
2363
|
{
|
|
2049
2364
|
type: "button",
|
|
2050
2365
|
className: closeButtonClass,
|
|
2051
2366
|
onClick: () => shellChat.setOpen(false),
|
|
2052
2367
|
"aria-label": "Close assistant",
|
|
2053
|
-
children: /* @__PURE__ */
|
|
2368
|
+
children: /* @__PURE__ */ jsx15(XIcon, { className: "size-4", "aria-hidden": true })
|
|
2054
2369
|
}
|
|
2055
2370
|
) }) : null,
|
|
2056
|
-
/* @__PURE__ */
|
|
2371
|
+
/* @__PURE__ */ jsx15("div", { className: bodyClass, children: /* @__PURE__ */ jsx15(
|
|
2057
2372
|
TimbalRuntimeProvider,
|
|
2058
2373
|
{
|
|
2059
2374
|
workforceId,
|
|
@@ -2063,7 +2378,7 @@ var AppChatPanel = ({
|
|
|
2063
2378
|
attachmentsUploadUrl,
|
|
2064
2379
|
attachmentsAccept,
|
|
2065
2380
|
debug,
|
|
2066
|
-
children: /* @__PURE__ */
|
|
2381
|
+
children: /* @__PURE__ */ jsx15(
|
|
2067
2382
|
Thread,
|
|
2068
2383
|
{
|
|
2069
2384
|
variant: "panel",
|
|
@@ -2084,41 +2399,121 @@ var AppChatPanel = ({
|
|
|
2084
2399
|
};
|
|
2085
2400
|
|
|
2086
2401
|
// src/app/surfaces/SurfaceCard.tsx
|
|
2087
|
-
import { jsx as
|
|
2088
|
-
var
|
|
2402
|
+
import { jsx as jsx16 } from "react/jsx-runtime";
|
|
2403
|
+
var surfaceVariantClass = {
|
|
2404
|
+
default: "",
|
|
2405
|
+
muted: "bg-none bg-muted/40 shadow-none border border-border/20",
|
|
2406
|
+
outline: "bg-none bg-transparent border border-border shadow-none",
|
|
2407
|
+
elevated: "shadow-card-elevated border border-border/80",
|
|
2408
|
+
flat: "bg-card/70 border border-border/50 shadow-[0_1px_3px_rgba(0,0,0,0.03),0_10px_15px_-3px_rgba(0,0,0,0.01)] dark:bg-card/40",
|
|
2409
|
+
hierarchical: "bg-card/90 border border-border/60 shadow-[0_1px_2px_rgba(0,0,0,0.02),0_8px_16px_rgba(0,0,0,0.01)] rounded-2xl dark:bg-card/50"
|
|
2410
|
+
};
|
|
2411
|
+
var surfaceToneClass = {
|
|
2412
|
+
default: "",
|
|
2413
|
+
primary: "ring-1 ring-inset ring-primary/25",
|
|
2414
|
+
success: "ring-1 ring-inset ring-emerald-500/25",
|
|
2415
|
+
warn: "ring-1 ring-inset ring-amber-500/30",
|
|
2416
|
+
danger: "ring-1 ring-inset ring-destructive/25"
|
|
2417
|
+
};
|
|
2418
|
+
var SurfaceCard = ({
|
|
2419
|
+
children,
|
|
2420
|
+
variant = "default",
|
|
2421
|
+
tone = "default",
|
|
2422
|
+
hoverable,
|
|
2423
|
+
onClick,
|
|
2424
|
+
ariaLabel,
|
|
2425
|
+
className
|
|
2426
|
+
}) => {
|
|
2089
2427
|
const surfaceCardClass = useAppDensityClass("surfaceCard");
|
|
2090
|
-
|
|
2428
|
+
const isInteractive = Boolean(onClick);
|
|
2429
|
+
const shouldHover = hoverable ?? isInteractive;
|
|
2430
|
+
const baseClass = cn(
|
|
2431
|
+
"aui-app-surface-card",
|
|
2432
|
+
surfaceCardClass,
|
|
2433
|
+
surfaceVariantClass[variant],
|
|
2434
|
+
surfaceToneClass[tone],
|
|
2435
|
+
shouldHover && "transition-all duration-200 hover:border-border/80 hover:shadow-md",
|
|
2436
|
+
isInteractive && "cursor-pointer select-none active:scale-[0.99] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
2437
|
+
className
|
|
2438
|
+
);
|
|
2439
|
+
if (isInteractive) {
|
|
2440
|
+
return /* @__PURE__ */ jsx16(
|
|
2441
|
+
"button",
|
|
2442
|
+
{
|
|
2443
|
+
type: "button",
|
|
2444
|
+
onClick,
|
|
2445
|
+
"aria-label": ariaLabel,
|
|
2446
|
+
className: baseClass,
|
|
2447
|
+
children
|
|
2448
|
+
}
|
|
2449
|
+
);
|
|
2450
|
+
}
|
|
2451
|
+
return /* @__PURE__ */ jsx16("div", { className: baseClass, children });
|
|
2091
2452
|
};
|
|
2092
2453
|
|
|
2093
2454
|
// src/app/surfaces/StatTile.tsx
|
|
2094
|
-
import { jsx as
|
|
2095
|
-
var
|
|
2455
|
+
import { jsx as jsx17, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2456
|
+
var statValueToneClass = {
|
|
2457
|
+
default: "",
|
|
2458
|
+
primary: "text-primary",
|
|
2459
|
+
success: "text-emerald-700 dark:text-emerald-400",
|
|
2460
|
+
warn: "text-amber-700 dark:text-amber-400",
|
|
2461
|
+
danger: "text-destructive"
|
|
2462
|
+
};
|
|
2463
|
+
var StatTile = ({
|
|
2464
|
+
label,
|
|
2465
|
+
value,
|
|
2466
|
+
hint,
|
|
2467
|
+
tone = "default",
|
|
2468
|
+
className
|
|
2469
|
+
}) => {
|
|
2096
2470
|
const statTileClass = useAppDensityClass("statTile");
|
|
2097
2471
|
return /* @__PURE__ */ jsxs11("div", { className: cn("aui-app-stat-tile", statTileClass, className), children: [
|
|
2098
|
-
/* @__PURE__ */
|
|
2099
|
-
/* @__PURE__ */
|
|
2100
|
-
hint ? /* @__PURE__ */
|
|
2472
|
+
/* @__PURE__ */ jsx17("span", { className: appStatLabelClass, children: label }),
|
|
2473
|
+
/* @__PURE__ */ jsx17("span", { className: cn(appStatValueClass, statValueToneClass[tone]), children: value }),
|
|
2474
|
+
hint ? /* @__PURE__ */ jsx17("span", { className: "text-xs text-muted-foreground", children: hint }) : null
|
|
2101
2475
|
] });
|
|
2102
2476
|
};
|
|
2103
2477
|
|
|
2104
2478
|
// src/app/surfaces/EmptyState.tsx
|
|
2105
|
-
import { jsx as
|
|
2479
|
+
import { jsx as jsx18, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
2106
2480
|
var EmptyState = ({
|
|
2107
2481
|
title,
|
|
2108
2482
|
description,
|
|
2109
2483
|
action,
|
|
2110
|
-
className
|
|
2484
|
+
className,
|
|
2485
|
+
variant = "default"
|
|
2111
2486
|
}) => {
|
|
2112
|
-
const
|
|
2113
|
-
|
|
2114
|
-
/* @__PURE__ */
|
|
2115
|
-
|
|
2116
|
-
|
|
2487
|
+
const densityClass = useAppDensityClass("emptyState");
|
|
2488
|
+
if (variant === "layered") {
|
|
2489
|
+
return /* @__PURE__ */ jsx18(
|
|
2490
|
+
"div",
|
|
2491
|
+
{
|
|
2492
|
+
className: cn(
|
|
2493
|
+
"aui-app-empty-state-layered w-full rounded-2xl border border-border/40 bg-muted/20 p-6 md:p-8 flex items-center justify-center dark:bg-muted/10",
|
|
2494
|
+
className
|
|
2495
|
+
),
|
|
2496
|
+
children: /* @__PURE__ */ jsxs12("div", { className: "w-full max-w-xl rounded-xl border border-border bg-card p-6 md:p-8 shadow-[0_1px_3px_rgba(0,0,0,0.02),0_10px_15px_-3px_rgba(0,0,0,0.01)] flex flex-col items-center justify-center text-center gap-4 transition-all duration-200 hover:border-border/80 dark:bg-card/45", children: [
|
|
2497
|
+
/* @__PURE__ */ jsxs12("div", { className: "flex flex-col gap-1.5 items-center justify-center", children: [
|
|
2498
|
+
/* @__PURE__ */ jsx18("h3", { className: "text-base font-semibold text-foreground tracking-tight", children: title }),
|
|
2499
|
+
description ? /* @__PURE__ */ jsx18("p", { className: "max-w-sm text-sm text-muted-foreground leading-relaxed", children: description }) : null
|
|
2500
|
+
] }),
|
|
2501
|
+
action ? /* @__PURE__ */ jsx18("div", { className: "mt-1", children: action }) : null
|
|
2502
|
+
] })
|
|
2503
|
+
}
|
|
2504
|
+
);
|
|
2505
|
+
}
|
|
2506
|
+
const isCompact = variant === "compact";
|
|
2507
|
+
const finalClass = isCompact ? "aui-app-empty-state rounded-xl border border-border bg-gradient-to-b from-elevated-from to-elevated-to p-3 flex flex-col items-center justify-center gap-2 py-8 text-center" : cn("aui-app-empty-state", densityClass);
|
|
2508
|
+
return /* @__PURE__ */ jsxs12("div", { className: cn(finalClass, className), children: [
|
|
2509
|
+
/* @__PURE__ */ jsx18("p", { className: cn(appEmptyStateTitleClass, "font-semibold tracking-tight"), children: title }),
|
|
2510
|
+
description ? /* @__PURE__ */ jsx18("p", { className: appEmptyStateDescriptionClass, children: description }) : null,
|
|
2511
|
+
action ? /* @__PURE__ */ jsx18("div", { className: "mt-1", children: action }) : null
|
|
2117
2512
|
] });
|
|
2118
2513
|
};
|
|
2119
2514
|
|
|
2120
2515
|
// src/app/surfaces/StatusBadge.tsx
|
|
2121
|
-
import { jsx as
|
|
2516
|
+
import { jsx as jsx19, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
2122
2517
|
var statusBadgeToneClass = {
|
|
2123
2518
|
default: "bg-muted text-foreground ring-border",
|
|
2124
2519
|
primary: "bg-primary/10 text-primary ring-primary/20",
|
|
@@ -2151,7 +2546,7 @@ var StatusBadge = ({
|
|
|
2151
2546
|
className
|
|
2152
2547
|
),
|
|
2153
2548
|
children: [
|
|
2154
|
-
dot ? /* @__PURE__ */
|
|
2549
|
+
dot ? /* @__PURE__ */ jsx19(
|
|
2155
2550
|
"span",
|
|
2156
2551
|
{
|
|
2157
2552
|
"aria-hidden": true,
|
|
@@ -2168,7 +2563,7 @@ var StatusBadge = ({
|
|
|
2168
2563
|
};
|
|
2169
2564
|
|
|
2170
2565
|
// src/app/surfaces/AppConfirmDialog.tsx
|
|
2171
|
-
import { jsx as
|
|
2566
|
+
import { jsx as jsx20, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
2172
2567
|
var bodyClass2 = "flex flex-col gap-4 p-6";
|
|
2173
2568
|
var titleClass = "pr-8";
|
|
2174
2569
|
var actionsClass = "flex flex-wrap justify-end gap-2";
|
|
@@ -2183,15 +2578,15 @@ var AppConfirmDialog = ({
|
|
|
2183
2578
|
destructive = false,
|
|
2184
2579
|
className
|
|
2185
2580
|
}) => {
|
|
2186
|
-
return /* @__PURE__ */
|
|
2581
|
+
return /* @__PURE__ */ jsx20(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsx20(
|
|
2187
2582
|
DialogContent,
|
|
2188
2583
|
{
|
|
2189
2584
|
className: cn("gap-0 p-0 sm:max-w-md", className),
|
|
2190
2585
|
children: /* @__PURE__ */ jsxs14("div", { className: bodyClass2, children: [
|
|
2191
|
-
/* @__PURE__ */
|
|
2192
|
-
description ? /* @__PURE__ */
|
|
2586
|
+
/* @__PURE__ */ jsx20(DialogTitle, { className: titleClass, children: title }),
|
|
2587
|
+
description ? /* @__PURE__ */ jsx20("p", { className: "text-sm text-muted-foreground", children: description }) : null,
|
|
2193
2588
|
/* @__PURE__ */ jsxs14("div", { className: actionsClass, children: [
|
|
2194
|
-
/* @__PURE__ */
|
|
2589
|
+
/* @__PURE__ */ jsx20(
|
|
2195
2590
|
TimbalV2Button,
|
|
2196
2591
|
{
|
|
2197
2592
|
type: "button",
|
|
@@ -2201,7 +2596,7 @@ var AppConfirmDialog = ({
|
|
|
2201
2596
|
children: cancelLabel
|
|
2202
2597
|
}
|
|
2203
2598
|
),
|
|
2204
|
-
/* @__PURE__ */
|
|
2599
|
+
/* @__PURE__ */ jsx20(
|
|
2205
2600
|
TimbalV2Button,
|
|
2206
2601
|
{
|
|
2207
2602
|
type: "button",
|
|
@@ -2221,7 +2616,7 @@ var AppConfirmDialog = ({
|
|
|
2221
2616
|
};
|
|
2222
2617
|
|
|
2223
2618
|
// src/app/surfaces/InfoCard.tsx
|
|
2224
|
-
import { jsx as
|
|
2619
|
+
import { Fragment as Fragment4, jsx as jsx21, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2225
2620
|
var toneClass = {
|
|
2226
2621
|
neutral: "border-border bg-muted/40",
|
|
2227
2622
|
info: "border-primary/25 bg-primary/5",
|
|
@@ -2229,34 +2624,67 @@ var toneClass = {
|
|
|
2229
2624
|
warn: "border-amber-500/25 bg-amber-500/5",
|
|
2230
2625
|
danger: "border-destructive/25 bg-destructive/5"
|
|
2231
2626
|
};
|
|
2627
|
+
var toneVerticalClass = {
|
|
2628
|
+
neutral: "border-border/60 bg-card hover:border-border dark:bg-card/40",
|
|
2629
|
+
info: "border-primary/20 bg-primary/5 hover:border-primary/45",
|
|
2630
|
+
success: "border-emerald-500/20 bg-emerald-500/5 hover:border-emerald-500/45",
|
|
2631
|
+
warn: "border-amber-500/25 bg-amber-500/5 hover:border-amber-500/45",
|
|
2632
|
+
danger: "border-destructive/20 bg-destructive/5 hover:border-destructive/45"
|
|
2633
|
+
};
|
|
2232
2634
|
var InfoCard = ({
|
|
2233
2635
|
title,
|
|
2234
2636
|
children,
|
|
2235
2637
|
icon,
|
|
2236
2638
|
action,
|
|
2237
2639
|
tone = "neutral",
|
|
2640
|
+
layout = "horizontal",
|
|
2641
|
+
onClick,
|
|
2642
|
+
ariaLabel,
|
|
2238
2643
|
className
|
|
2239
|
-
}) =>
|
|
2240
|
-
|
|
2241
|
-
{
|
|
2242
|
-
|
|
2243
|
-
"flex items-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
children: [
|
|
2248
|
-
icon ? /* @__PURE__ */ jsx20("span", { className: "mt-0.5 shrink-0 text-muted-foreground", children: icon }) : null,
|
|
2249
|
-
/* @__PURE__ */ jsxs15("div", { className: "min-w-0 flex-1", children: [
|
|
2250
|
-
title ? /* @__PURE__ */ jsx20("p", { className: "text-sm font-medium text-foreground", children: title }) : null,
|
|
2251
|
-
children ? /* @__PURE__ */ jsx20("div", { className: cn("text-sm text-muted-foreground", title && "mt-1"), children }) : null
|
|
2644
|
+
}) => {
|
|
2645
|
+
const isInteractive = Boolean(onClick);
|
|
2646
|
+
if (layout === "vertical") {
|
|
2647
|
+
const cardContent = /* @__PURE__ */ jsxs15(Fragment4, { children: [
|
|
2648
|
+
icon ? /* @__PURE__ */ jsx21("span", { className: "flex size-10 items-center justify-center rounded-xl bg-muted/50 border border-border/40 text-muted-foreground/80 transition-transform duration-200 group-hover:scale-105", children: icon }) : null,
|
|
2649
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex flex-col gap-1.5 w-full text-left", children: [
|
|
2650
|
+
title ? /* @__PURE__ */ jsx21("p", { className: "text-sm font-semibold text-foreground tracking-tight leading-tight", children: title }) : null,
|
|
2651
|
+
children ? /* @__PURE__ */ jsx21("div", { className: "text-xs text-muted-foreground leading-relaxed", children }) : null
|
|
2252
2652
|
] }),
|
|
2253
|
-
action ? /* @__PURE__ */
|
|
2254
|
-
]
|
|
2653
|
+
action ? /* @__PURE__ */ jsx21("div", { className: "w-full mt-1", children: action }) : null
|
|
2654
|
+
] });
|
|
2655
|
+
const baseClass2 = cn(
|
|
2656
|
+
"group flex flex-col gap-4 items-start rounded-2xl border p-5 transition-all duration-200 shadow-[0_1px_3px_rgba(0,0,0,0.03),0_10px_15px_-3px_rgba(0,0,0,0.01)]",
|
|
2657
|
+
toneVerticalClass[tone],
|
|
2658
|
+
isInteractive && "cursor-pointer select-none hover:shadow-md active:scale-[0.99] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
2659
|
+
className
|
|
2660
|
+
);
|
|
2661
|
+
if (isInteractive) {
|
|
2662
|
+
return /* @__PURE__ */ jsx21("button", { type: "button", onClick, "aria-label": ariaLabel, className: baseClass2, children: cardContent });
|
|
2663
|
+
}
|
|
2664
|
+
return /* @__PURE__ */ jsx21("div", { className: baseClass2, children: cardContent });
|
|
2255
2665
|
}
|
|
2256
|
-
|
|
2666
|
+
const horizontalContent = /* @__PURE__ */ jsxs15(Fragment4, { children: [
|
|
2667
|
+
icon ? /* @__PURE__ */ jsx21("span", { className: "mt-0.5 shrink-0 text-muted-foreground", children: icon }) : null,
|
|
2668
|
+
/* @__PURE__ */ jsxs15("div", { className: "min-w-0 flex-1 text-left", children: [
|
|
2669
|
+
title ? /* @__PURE__ */ jsx21("p", { className: "text-sm font-medium text-foreground", children: title }) : null,
|
|
2670
|
+
children ? /* @__PURE__ */ jsx21("div", { className: cn("text-sm text-muted-foreground", title && "mt-1"), children }) : null
|
|
2671
|
+
] }),
|
|
2672
|
+
action ? /* @__PURE__ */ jsx21("div", { className: "shrink-0", children: action }) : null
|
|
2673
|
+
] });
|
|
2674
|
+
const baseClass = cn(
|
|
2675
|
+
"flex items-start gap-3 rounded-xl border p-4 transition-all duration-200",
|
|
2676
|
+
toneClass[tone],
|
|
2677
|
+
isInteractive && "cursor-pointer select-none hover:bg-muted/30 active:scale-[0.995] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
2678
|
+
className
|
|
2679
|
+
);
|
|
2680
|
+
if (isInteractive) {
|
|
2681
|
+
return /* @__PURE__ */ jsx21("button", { type: "button", onClick, "aria-label": ariaLabel, className: baseClass, children: horizontalContent });
|
|
2682
|
+
}
|
|
2683
|
+
return /* @__PURE__ */ jsx21("div", { className: baseClass, children: horizontalContent });
|
|
2684
|
+
};
|
|
2257
2685
|
|
|
2258
2686
|
// src/app/surfaces/StatusDot.tsx
|
|
2259
|
-
import { jsx as
|
|
2687
|
+
import { jsx as jsx22, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2260
2688
|
var dotClass = {
|
|
2261
2689
|
online: "bg-emerald-500",
|
|
2262
2690
|
busy: "bg-amber-500",
|
|
@@ -2271,7 +2699,7 @@ var StatusDot = ({
|
|
|
2271
2699
|
className
|
|
2272
2700
|
}) => /* @__PURE__ */ jsxs16("span", { className: cn("inline-flex items-center gap-1.5", className), children: [
|
|
2273
2701
|
/* @__PURE__ */ jsxs16("span", { className: "relative flex size-2", children: [
|
|
2274
|
-
pulse ? /* @__PURE__ */
|
|
2702
|
+
pulse ? /* @__PURE__ */ jsx22(
|
|
2275
2703
|
"span",
|
|
2276
2704
|
{
|
|
2277
2705
|
className: cn(
|
|
@@ -2280,18 +2708,18 @@ var StatusDot = ({
|
|
|
2280
2708
|
)
|
|
2281
2709
|
}
|
|
2282
2710
|
) : null,
|
|
2283
|
-
/* @__PURE__ */
|
|
2711
|
+
/* @__PURE__ */ jsx22("span", { className: cn("relative inline-flex size-2 rounded-full", dotClass[tone]) })
|
|
2284
2712
|
] }),
|
|
2285
|
-
label ? /* @__PURE__ */
|
|
2713
|
+
label ? /* @__PURE__ */ jsx22("span", { className: "text-xs text-muted-foreground", children: label }) : null
|
|
2286
2714
|
] });
|
|
2287
2715
|
|
|
2288
2716
|
// src/app/surfaces/DescriptionList.tsx
|
|
2289
|
-
import { jsx as
|
|
2717
|
+
import { jsx as jsx23, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
2290
2718
|
var DescriptionList = ({
|
|
2291
2719
|
items,
|
|
2292
2720
|
stacked = false,
|
|
2293
2721
|
className
|
|
2294
|
-
}) => /* @__PURE__ */
|
|
2722
|
+
}) => /* @__PURE__ */ jsx23(
|
|
2295
2723
|
"dl",
|
|
2296
2724
|
{
|
|
2297
2725
|
className: cn(
|
|
@@ -2303,16 +2731,18 @@ var DescriptionList = ({
|
|
|
2303
2731
|
{
|
|
2304
2732
|
className: cn(
|
|
2305
2733
|
"px-4 py-3",
|
|
2306
|
-
stacked ? "flex flex-col gap-0.5" : "flex items-center justify-between gap-4"
|
|
2734
|
+
stacked ? "flex flex-col gap-0.5" : "flex items-center justify-between gap-4",
|
|
2735
|
+
item.className
|
|
2307
2736
|
),
|
|
2308
2737
|
children: [
|
|
2309
|
-
/* @__PURE__ */
|
|
2310
|
-
/* @__PURE__ */
|
|
2738
|
+
/* @__PURE__ */ jsx23("dt", { className: cn("text-sm text-muted-foreground", item.labelClassName), children: item.label }),
|
|
2739
|
+
/* @__PURE__ */ jsx23(
|
|
2311
2740
|
"dd",
|
|
2312
2741
|
{
|
|
2313
2742
|
className: cn(
|
|
2314
2743
|
"text-sm text-foreground",
|
|
2315
|
-
!stacked && "text-right tabular-nums"
|
|
2744
|
+
!stacked && "text-right tabular-nums",
|
|
2745
|
+
item.valueClassName
|
|
2316
2746
|
),
|
|
2317
2747
|
children: item.value
|
|
2318
2748
|
}
|
|
@@ -2325,10 +2755,10 @@ var DescriptionList = ({
|
|
|
2325
2755
|
);
|
|
2326
2756
|
|
|
2327
2757
|
// src/app/surfaces/ExpandableSection.tsx
|
|
2328
|
-
import { useId, useState as useState2 } from "react";
|
|
2758
|
+
import { useId as useId2, useState as useState2 } from "react";
|
|
2329
2759
|
import { AnimatePresence, motion as motion2, useReducedMotion as useReducedMotion2 } from "motion/react";
|
|
2330
|
-
import { jsx as
|
|
2331
|
-
var Chevron = ({ open }) => /* @__PURE__ */
|
|
2760
|
+
import { jsx as jsx24, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
2761
|
+
var Chevron = ({ open }) => /* @__PURE__ */ jsx24(
|
|
2332
2762
|
"svg",
|
|
2333
2763
|
{
|
|
2334
2764
|
viewBox: "0 0 24 24",
|
|
@@ -2342,7 +2772,7 @@ var Chevron = ({ open }) => /* @__PURE__ */ jsx23(
|
|
|
2342
2772
|
strokeLinecap: "round",
|
|
2343
2773
|
strokeLinejoin: "round",
|
|
2344
2774
|
"aria-hidden": true,
|
|
2345
|
-
children: /* @__PURE__ */
|
|
2775
|
+
children: /* @__PURE__ */ jsx24("path", { d: "m6 9 6 6 6-6" })
|
|
2346
2776
|
}
|
|
2347
2777
|
);
|
|
2348
2778
|
var ExpandableSection = ({
|
|
@@ -2356,7 +2786,7 @@ var ExpandableSection = ({
|
|
|
2356
2786
|
className
|
|
2357
2787
|
}) => {
|
|
2358
2788
|
const reduceMotion = useReducedMotion2();
|
|
2359
|
-
const panelId =
|
|
2789
|
+
const panelId = useId2();
|
|
2360
2790
|
const [internalOpen, setInternalOpen] = useState2(defaultOpen);
|
|
2361
2791
|
const open = openProp ?? internalOpen;
|
|
2362
2792
|
const toggle = () => {
|
|
@@ -2374,15 +2804,15 @@ var ExpandableSection = ({
|
|
|
2374
2804
|
className: "flex w-full items-center justify-between gap-3 bg-transparent px-4 py-3 text-left hover:bg-transparent active:bg-transparent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-foreground/10",
|
|
2375
2805
|
children: [
|
|
2376
2806
|
/* @__PURE__ */ jsxs18("span", { className: "flex min-w-0 items-center gap-3", children: [
|
|
2377
|
-
icon ? /* @__PURE__ */
|
|
2378
|
-
/* @__PURE__ */
|
|
2379
|
-
count != null ? /* @__PURE__ */
|
|
2807
|
+
icon ? /* @__PURE__ */ jsx24("span", { className: "flex size-8 items-center justify-center rounded-lg border border-border bg-muted text-muted-foreground", children: icon }) : null,
|
|
2808
|
+
/* @__PURE__ */ jsx24("span", { className: "truncate text-sm font-medium text-foreground", children: title }),
|
|
2809
|
+
count != null ? /* @__PURE__ */ jsx24("span", { className: "rounded-full border border-border bg-muted px-2 py-0.5 text-xs text-muted-foreground", children: count }) : null
|
|
2380
2810
|
] }),
|
|
2381
|
-
/* @__PURE__ */
|
|
2811
|
+
/* @__PURE__ */ jsx24(Chevron, { open })
|
|
2382
2812
|
]
|
|
2383
2813
|
}
|
|
2384
2814
|
),
|
|
2385
|
-
/* @__PURE__ */
|
|
2815
|
+
/* @__PURE__ */ jsx24(AnimatePresence, { initial: false, children: open ? /* @__PURE__ */ jsx24(
|
|
2386
2816
|
motion2.div,
|
|
2387
2817
|
{
|
|
2388
2818
|
id: panelId,
|
|
@@ -2391,7 +2821,7 @@ var ExpandableSection = ({
|
|
|
2391
2821
|
exit: reduceMotion ? void 0 : { height: 0, opacity: 0 },
|
|
2392
2822
|
transition: { duration: 0.2, ease: "easeOut" },
|
|
2393
2823
|
className: "overflow-hidden",
|
|
2394
|
-
children: /* @__PURE__ */
|
|
2824
|
+
children: /* @__PURE__ */ jsx24("div", { className: "bg-muted/20", children })
|
|
2395
2825
|
},
|
|
2396
2826
|
"body"
|
|
2397
2827
|
) : null })
|
|
@@ -2399,19 +2829,14 @@ var ExpandableSection = ({
|
|
|
2399
2829
|
};
|
|
2400
2830
|
|
|
2401
2831
|
// src/app/surfaces/ResourceCard.tsx
|
|
2402
|
-
import { Fragment as
|
|
2403
|
-
var resourceCardShellClass = cn(
|
|
2404
|
-
"flex min-h-[8.5rem] flex-col rounded-2xl p-4 text-left font-normal",
|
|
2405
|
-
TIMBAL_V2_ELEVATED_SURFACE
|
|
2406
|
-
);
|
|
2832
|
+
import { Fragment as Fragment5, jsx as jsx25, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
2407
2833
|
var mediaShellClass = cn(
|
|
2408
2834
|
"flex size-10 shrink-0 items-center justify-center overflow-hidden rounded-xl text-sm font-normal text-foreground",
|
|
2409
2835
|
TIMBAL_V2_LOGO_TILE
|
|
2410
2836
|
);
|
|
2411
2837
|
var resourceCardInteractiveClass = cn(
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 focus-visible:ring-offset-2 focus-visible:ring-offset-background"
|
|
2838
|
+
"flex min-h-[8.5rem] flex-col rounded-2xl p-4 text-left font-normal border border-border shadow-card",
|
|
2839
|
+
TIMBAL_V2_ELEVATED_SURFACE
|
|
2415
2840
|
);
|
|
2416
2841
|
var ResourceCard = ({
|
|
2417
2842
|
title,
|
|
@@ -2422,37 +2847,236 @@ var ResourceCard = ({
|
|
|
2422
2847
|
action,
|
|
2423
2848
|
onClick,
|
|
2424
2849
|
ariaLabel,
|
|
2425
|
-
className
|
|
2850
|
+
className,
|
|
2851
|
+
variant = "flat",
|
|
2852
|
+
avatarShape = "circle"
|
|
2426
2853
|
}) => {
|
|
2427
|
-
const
|
|
2854
|
+
const isInteractive = Boolean(onClick);
|
|
2855
|
+
const shellClass3 = cn(
|
|
2856
|
+
"flex min-h-[8.5rem] flex-col rounded-2xl p-5 text-left font-normal transition-all duration-200",
|
|
2857
|
+
variant === "default" && TIMBAL_V2_ELEVATED_SURFACE,
|
|
2858
|
+
variant === "flat" && "border border-border/50 bg-card/65 shadow-[0_1px_3px_rgba(0,0,0,0.05),0_10px_15px_-3px_rgba(0,0,0,0.01)] hover:border-border hover:shadow-md dark:bg-card/45",
|
|
2859
|
+
variant === "outline" && "border border-border/70 bg-transparent shadow-none hover:bg-muted/5",
|
|
2860
|
+
isInteractive && "cursor-pointer select-none active:scale-[0.99] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 focus-visible:ring-offset-2 focus-visible:ring-offset-background"
|
|
2861
|
+
);
|
|
2862
|
+
const dynamicMediaShellClass = cn(
|
|
2863
|
+
"flex size-10 shrink-0 items-center justify-center overflow-hidden text-sm font-normal text-foreground transition-all duration-200",
|
|
2864
|
+
avatarShape === "circle" ? "rounded-full" : "rounded-xl",
|
|
2865
|
+
TIMBAL_V2_LOGO_TILE
|
|
2866
|
+
);
|
|
2867
|
+
const body = /* @__PURE__ */ jsxs19(Fragment5, { children: [
|
|
2428
2868
|
/* @__PURE__ */ jsxs19("div", { className: "flex items-start gap-3", children: [
|
|
2429
|
-
media ? /* @__PURE__ */
|
|
2869
|
+
media ? /* @__PURE__ */ jsx25("span", { className: dynamicMediaShellClass, children: media }) : null,
|
|
2430
2870
|
/* @__PURE__ */ jsxs19("div", { className: "min-w-0 flex-1 pt-0.5", children: [
|
|
2431
|
-
/* @__PURE__ */
|
|
2432
|
-
subtitle ? /* @__PURE__ */
|
|
2871
|
+
/* @__PURE__ */ jsx25("p", { className: "truncate text-sm font-semibold leading-snug text-foreground tracking-tight", children: title }),
|
|
2872
|
+
subtitle ? /* @__PURE__ */ jsx25("p", { className: "mt-1 line-clamp-2 text-xs font-normal text-muted-foreground/90 leading-relaxed", children: subtitle }) : null
|
|
2433
2873
|
] }),
|
|
2434
|
-
badge ? /* @__PURE__ */
|
|
2874
|
+
badge ? /* @__PURE__ */ jsx25("span", { className: "shrink-0 pt-0.5", children: badge }) : null
|
|
2435
2875
|
] }),
|
|
2436
2876
|
footer || action ? /* @__PURE__ */ jsxs19("div", { className: "mt-auto flex items-center justify-between gap-3 border-t border-border/40 pt-3 text-xs font-normal text-muted-foreground", children: [
|
|
2437
|
-
/* @__PURE__ */
|
|
2438
|
-
action ? /* @__PURE__ */
|
|
2877
|
+
/* @__PURE__ */ jsx25("span", { className: "min-w-0 truncate", children: footer }),
|
|
2878
|
+
action ? /* @__PURE__ */ jsx25("span", { className: "shrink-0 opacity-90", children: action }) : null
|
|
2879
|
+
] }) : null
|
|
2880
|
+
] });
|
|
2881
|
+
if (onClick) {
|
|
2882
|
+
return /* @__PURE__ */ jsx25(
|
|
2883
|
+
"button",
|
|
2884
|
+
{
|
|
2885
|
+
type: "button",
|
|
2886
|
+
onClick,
|
|
2887
|
+
"aria-label": ariaLabel,
|
|
2888
|
+
className: cn(shellClass3, className),
|
|
2889
|
+
children: body
|
|
2890
|
+
}
|
|
2891
|
+
);
|
|
2892
|
+
}
|
|
2893
|
+
return /* @__PURE__ */ jsx25("article", { className: cn(shellClass3, className), children: body });
|
|
2894
|
+
};
|
|
2895
|
+
|
|
2896
|
+
// src/app/surfaces/AlertCard.tsx
|
|
2897
|
+
import { ChevronRight } from "lucide-react";
|
|
2898
|
+
import { jsx as jsx26, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
2899
|
+
var alertCardShellClass = cn(
|
|
2900
|
+
"flex flex-col rounded-2xl p-4 text-left font-normal border border-border shadow-card",
|
|
2901
|
+
TIMBAL_V2_ELEVATED_GRADIENT
|
|
2902
|
+
);
|
|
2903
|
+
var alertCardInteractiveClass = cn(
|
|
2904
|
+
"flex flex-col rounded-2xl p-4 text-left font-normal border border-border shadow-card cursor-pointer",
|
|
2905
|
+
TIMBAL_V2_ELEVATED_GRADIENT,
|
|
2906
|
+
"transition-[background-color,box-shadow,border-color] duration-150 ease-in-out",
|
|
2907
|
+
"hover:border-foreground/20",
|
|
2908
|
+
"hover:from-secondary-fill-hover-from hover:to-secondary-fill-hover-to",
|
|
2909
|
+
"active:from-secondary-fill-active-from active:to-secondary-fill-active-to",
|
|
2910
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 focus-visible:ring-offset-2 focus-visible:ring-offset-background"
|
|
2911
|
+
);
|
|
2912
|
+
var AlertCard = ({
|
|
2913
|
+
title,
|
|
2914
|
+
description,
|
|
2915
|
+
category,
|
|
2916
|
+
categoryTone = "default",
|
|
2917
|
+
status,
|
|
2918
|
+
statusTone = "default",
|
|
2919
|
+
action,
|
|
2920
|
+
trailing,
|
|
2921
|
+
onClick,
|
|
2922
|
+
ariaLabel,
|
|
2923
|
+
className
|
|
2924
|
+
}) => {
|
|
2925
|
+
const showTags = Boolean(category || status);
|
|
2926
|
+
const showTrailing = Boolean(trailing || onClick);
|
|
2927
|
+
const bodyContent = /* @__PURE__ */ jsxs20("div", { className: "flex-1 min-w-0 flex flex-col h-full", children: [
|
|
2928
|
+
showTags ? /* @__PURE__ */ jsxs20("div", { className: "flex flex-wrap items-center gap-1.5 mb-2.5", children: [
|
|
2929
|
+
category ? /* @__PURE__ */ jsx26(StatusBadge, { tone: categoryTone, children: category }) : null,
|
|
2930
|
+
status ? /* @__PURE__ */ jsx26(StatusBadge, { tone: statusTone, children: status }) : null
|
|
2931
|
+
] }) : null,
|
|
2932
|
+
/* @__PURE__ */ jsx26("h4", { className: "text-sm font-medium leading-snug text-foreground", children: title }),
|
|
2933
|
+
description ? /* @__PURE__ */ jsx26("p", { className: "mt-1.5 text-xs text-muted-foreground leading-normal", children: description }) : null,
|
|
2934
|
+
action ? /* @__PURE__ */ jsxs20("div", { className: "mt-auto pt-3 text-xs text-muted-foreground/90 leading-normal", children: [
|
|
2935
|
+
/* @__PURE__ */ jsx26("strong", { className: "font-semibold text-foreground/80", children: "Action: " }),
|
|
2936
|
+
action
|
|
2439
2937
|
] }) : null
|
|
2440
2938
|
] });
|
|
2939
|
+
const cardContent = /* @__PURE__ */ jsxs20("div", { className: "flex items-start justify-between gap-4 w-full h-full", children: [
|
|
2940
|
+
bodyContent,
|
|
2941
|
+
showTrailing ? /* @__PURE__ */ jsx26("div", { className: "shrink-0 flex items-center justify-center self-center text-muted-foreground/50", children: trailing || /* @__PURE__ */ jsx26(ChevronRight, { className: "size-4" }) }) : null
|
|
2942
|
+
] });
|
|
2943
|
+
if (onClick) {
|
|
2944
|
+
return /* @__PURE__ */ jsx26(
|
|
2945
|
+
"button",
|
|
2946
|
+
{
|
|
2947
|
+
type: "button",
|
|
2948
|
+
onClick,
|
|
2949
|
+
"aria-label": ariaLabel,
|
|
2950
|
+
className: cn(alertCardInteractiveClass, className),
|
|
2951
|
+
children: cardContent
|
|
2952
|
+
}
|
|
2953
|
+
);
|
|
2954
|
+
}
|
|
2955
|
+
return /* @__PURE__ */ jsx26("article", { className: cn(alertCardShellClass, className), children: cardContent });
|
|
2956
|
+
};
|
|
2957
|
+
|
|
2958
|
+
// src/app/surfaces/CatalogCard.tsx
|
|
2959
|
+
import { ExternalLink } from "lucide-react";
|
|
2960
|
+
import { jsx as jsx27, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
2961
|
+
var catalogCardShellClass = cn(
|
|
2962
|
+
"flex flex-col rounded-2xl border border-border shadow-card overflow-hidden text-left font-normal",
|
|
2963
|
+
TIMBAL_V2_ELEVATED_GRADIENT
|
|
2964
|
+
);
|
|
2965
|
+
var catalogCardInteractiveClass = cn(
|
|
2966
|
+
"flex flex-col rounded-2xl border border-border shadow-card overflow-hidden text-left font-normal cursor-pointer",
|
|
2967
|
+
TIMBAL_V2_ELEVATED_GRADIENT,
|
|
2968
|
+
"transition-[background-color,box-shadow,border-color] duration-150 ease-in-out",
|
|
2969
|
+
"hover:border-foreground/20",
|
|
2970
|
+
"hover:from-secondary-fill-hover-from hover:to-secondary-fill-hover-to",
|
|
2971
|
+
"active:from-secondary-fill-active-from active:to-secondary-fill-active-to",
|
|
2972
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 focus-visible:ring-offset-2 focus-visible:ring-offset-background"
|
|
2973
|
+
);
|
|
2974
|
+
var CatalogCard = ({
|
|
2975
|
+
title,
|
|
2976
|
+
subtitle,
|
|
2977
|
+
logo,
|
|
2978
|
+
href,
|
|
2979
|
+
badge,
|
|
2980
|
+
description,
|
|
2981
|
+
tags,
|
|
2982
|
+
footerLinks,
|
|
2983
|
+
copyValue,
|
|
2984
|
+
copyLabel = "Copy ID",
|
|
2985
|
+
actions,
|
|
2986
|
+
onClick,
|
|
2987
|
+
ariaLabel,
|
|
2988
|
+
className
|
|
2989
|
+
}) => {
|
|
2990
|
+
const showHeaderTags = Boolean(subtitle || badge);
|
|
2991
|
+
const showFooter = Boolean(footerLinks && footerLinks.length > 0 || copyValue || actions);
|
|
2992
|
+
const mainContent = /* @__PURE__ */ jsxs21("div", { className: "flex-1 p-5 flex flex-col h-full min-h-0", children: [
|
|
2993
|
+
/* @__PURE__ */ jsxs21("div", { className: "flex items-start gap-3", children: [
|
|
2994
|
+
logo ? /* @__PURE__ */ jsx27("div", { className: "size-8 shrink-0 flex items-center justify-center overflow-hidden rounded-lg bg-muted/40", children: logo }) : null,
|
|
2995
|
+
/* @__PURE__ */ jsxs21("div", { className: "min-w-0 flex-1 pt-0.5", children: [
|
|
2996
|
+
/* @__PURE__ */ jsx27("div", { className: "flex items-center gap-1.5 flex-wrap", children: href ? /* @__PURE__ */ jsxs21(
|
|
2997
|
+
"a",
|
|
2998
|
+
{
|
|
2999
|
+
href,
|
|
3000
|
+
target: "_blank",
|
|
3001
|
+
rel: "noopener noreferrer",
|
|
3002
|
+
className: "inline-flex items-center gap-1 hover:underline text-sm font-medium leading-snug text-foreground focus-visible:outline-none focus-visible:underline",
|
|
3003
|
+
onClick: (e) => e.stopPropagation(),
|
|
3004
|
+
children: [
|
|
3005
|
+
/* @__PURE__ */ jsx27("span", { className: "truncate", children: title }),
|
|
3006
|
+
/* @__PURE__ */ jsx27(ExternalLink, { className: "size-3.5 shrink-0 text-muted-foreground/60" })
|
|
3007
|
+
]
|
|
3008
|
+
}
|
|
3009
|
+
) : /* @__PURE__ */ jsx27("h4", { className: "text-sm font-medium leading-snug text-foreground truncate", children: title }) }),
|
|
3010
|
+
showHeaderTags ? /* @__PURE__ */ jsxs21("div", { className: "flex flex-wrap items-center gap-2 mt-1", children: [
|
|
3011
|
+
subtitle ? /* @__PURE__ */ jsx27("span", { className: "text-xs font-medium text-muted-foreground", children: subtitle }) : null,
|
|
3012
|
+
badge ? /* @__PURE__ */ jsx27("div", { className: "shrink-0 flex items-center", children: badge }) : null
|
|
3013
|
+
] }) : null
|
|
3014
|
+
] })
|
|
3015
|
+
] }),
|
|
3016
|
+
description ? /* @__PURE__ */ jsx27("p", { className: "mt-3 text-xs leading-relaxed text-muted-foreground line-clamp-3", children: description }) : null,
|
|
3017
|
+
tags && tags.length > 0 ? /* @__PURE__ */ jsx27("div", { className: "flex flex-wrap items-center gap-2 mt-4", children: tags.map((tag, idx) => /* @__PURE__ */ jsxs21("div", { className: "flex items-center text-xs text-muted-foreground/80", children: [
|
|
3018
|
+
idx > 0 && /* @__PURE__ */ jsx27("span", { className: "mr-2 text-muted-foreground/30", children: "\u2022" }),
|
|
3019
|
+
tag
|
|
3020
|
+
] }, idx)) }) : null
|
|
3021
|
+
] });
|
|
3022
|
+
const footerMarkup = showFooter ? /* @__PURE__ */ jsxs21("div", { className: "border-t border-border/40 px-5 py-3 flex items-center justify-between gap-4 bg-muted/[0.02]", children: [
|
|
3023
|
+
/* @__PURE__ */ jsx27("div", { className: "flex flex-wrap items-center gap-4", children: footerLinks && footerLinks.length > 0 ? footerLinks.map((link, idx) => /* @__PURE__ */ jsxs21(
|
|
3024
|
+
"a",
|
|
3025
|
+
{
|
|
3026
|
+
href: link.href,
|
|
3027
|
+
target: "_blank",
|
|
3028
|
+
rel: "noopener noreferrer",
|
|
3029
|
+
className: "inline-flex items-center gap-1 text-xs font-medium text-muted-foreground hover:text-foreground hover:underline transition-colors focus-visible:outline-none focus-visible:underline",
|
|
3030
|
+
onClick: (e) => e.stopPropagation(),
|
|
3031
|
+
children: [
|
|
3032
|
+
/* @__PURE__ */ jsx27("span", { children: link.label }),
|
|
3033
|
+
/* @__PURE__ */ jsx27(ExternalLink, { className: "size-2.5 shrink-0 text-muted-foreground/50" })
|
|
3034
|
+
]
|
|
3035
|
+
},
|
|
3036
|
+
idx
|
|
3037
|
+
)) : null }),
|
|
3038
|
+
/* @__PURE__ */ jsxs21("div", { className: "flex items-center gap-2", onClick: (e) => e.stopPropagation(), children: [
|
|
3039
|
+
actions ? actions : null,
|
|
3040
|
+
!actions && copyValue ? /* @__PURE__ */ jsx27(
|
|
3041
|
+
CopyButton,
|
|
3042
|
+
{
|
|
3043
|
+
value: copyValue,
|
|
3044
|
+
className: "h-7 text-xs px-2 hover:bg-muted/40 text-muted-foreground/80 hover:text-foreground",
|
|
3045
|
+
children: copyLabel
|
|
3046
|
+
}
|
|
3047
|
+
) : null
|
|
3048
|
+
] })
|
|
3049
|
+
] }) : null;
|
|
2441
3050
|
if (onClick) {
|
|
2442
|
-
return /* @__PURE__ */
|
|
3051
|
+
return /* @__PURE__ */ jsxs21(
|
|
3052
|
+
"button",
|
|
3053
|
+
{
|
|
3054
|
+
type: "button",
|
|
3055
|
+
onClick,
|
|
3056
|
+
"aria-label": ariaLabel,
|
|
3057
|
+
className: cn(catalogCardInteractiveClass, className),
|
|
3058
|
+
children: [
|
|
3059
|
+
mainContent,
|
|
3060
|
+
footerMarkup
|
|
3061
|
+
]
|
|
3062
|
+
}
|
|
3063
|
+
);
|
|
2443
3064
|
}
|
|
2444
|
-
return /* @__PURE__ */
|
|
3065
|
+
return /* @__PURE__ */ jsxs21("article", { className: cn(catalogCardShellClass, className), children: [
|
|
3066
|
+
mainContent,
|
|
3067
|
+
footerMarkup
|
|
3068
|
+
] });
|
|
2445
3069
|
};
|
|
2446
3070
|
|
|
2447
3071
|
// src/app/settings/SettingsSection.tsx
|
|
2448
|
-
import { jsx as
|
|
3072
|
+
import { jsx as jsx28, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
2449
3073
|
var SettingsSectionHeader = ({
|
|
2450
3074
|
title,
|
|
2451
3075
|
description,
|
|
2452
3076
|
className
|
|
2453
|
-
}) => /* @__PURE__ */
|
|
2454
|
-
/* @__PURE__ */
|
|
2455
|
-
description ? /* @__PURE__ */
|
|
3077
|
+
}) => /* @__PURE__ */ jsxs22("div", { className: cn("flex flex-col", className), children: [
|
|
3078
|
+
/* @__PURE__ */ jsx28("h3", { className: "text-[17px] font-medium leading-tight text-foreground", children: title }),
|
|
3079
|
+
description ? /* @__PURE__ */ jsx28("p", { className: "mt-1 text-sm text-muted-foreground", children: description }) : null
|
|
2456
3080
|
] });
|
|
2457
3081
|
var SettingsSection = ({
|
|
2458
3082
|
title,
|
|
@@ -2461,7 +3085,7 @@ var SettingsSection = ({
|
|
|
2461
3085
|
children,
|
|
2462
3086
|
noBorderTop = false,
|
|
2463
3087
|
className
|
|
2464
|
-
}) => /* @__PURE__ */
|
|
3088
|
+
}) => /* @__PURE__ */ jsxs22(
|
|
2465
3089
|
"section",
|
|
2466
3090
|
{
|
|
2467
3091
|
className: cn(
|
|
@@ -2470,18 +3094,18 @@ var SettingsSection = ({
|
|
|
2470
3094
|
className
|
|
2471
3095
|
),
|
|
2472
3096
|
children: [
|
|
2473
|
-
/* @__PURE__ */
|
|
2474
|
-
/* @__PURE__ */
|
|
2475
|
-
description ? /* @__PURE__ */
|
|
2476
|
-
descriptionFooter ? /* @__PURE__ */
|
|
3097
|
+
/* @__PURE__ */ jsxs22("div", { className: "min-w-0", children: [
|
|
3098
|
+
/* @__PURE__ */ jsx28("h2", { className: "text-sm font-medium text-foreground", children: title }),
|
|
3099
|
+
description ? /* @__PURE__ */ jsx28("p", { className: "mt-1 text-sm text-muted-foreground", children: description }) : null,
|
|
3100
|
+
descriptionFooter ? /* @__PURE__ */ jsx28("div", { className: "mt-3 min-w-0", children: descriptionFooter }) : null
|
|
2477
3101
|
] }),
|
|
2478
|
-
/* @__PURE__ */
|
|
3102
|
+
/* @__PURE__ */ jsx28("div", { className: "min-w-0 space-y-3", children })
|
|
2479
3103
|
]
|
|
2480
3104
|
}
|
|
2481
3105
|
);
|
|
2482
3106
|
|
|
2483
3107
|
// src/app/settings/FieldRow.tsx
|
|
2484
|
-
import { jsx as
|
|
3108
|
+
import { jsx as jsx29, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
2485
3109
|
var FieldRow = ({
|
|
2486
3110
|
label,
|
|
2487
3111
|
children,
|
|
@@ -2491,7 +3115,7 @@ var FieldRow = ({
|
|
|
2491
3115
|
className
|
|
2492
3116
|
}) => {
|
|
2493
3117
|
if (inline) {
|
|
2494
|
-
return /* @__PURE__ */
|
|
3118
|
+
return /* @__PURE__ */ jsxs23(
|
|
2495
3119
|
"div",
|
|
2496
3120
|
{
|
|
2497
3121
|
className: cn(
|
|
@@ -2499,8 +3123,8 @@ var FieldRow = ({
|
|
|
2499
3123
|
className
|
|
2500
3124
|
),
|
|
2501
3125
|
children: [
|
|
2502
|
-
/* @__PURE__ */
|
|
2503
|
-
/* @__PURE__ */
|
|
3126
|
+
/* @__PURE__ */ jsxs23("div", { className: "min-w-0", children: [
|
|
3127
|
+
/* @__PURE__ */ jsx29(
|
|
2504
3128
|
"label",
|
|
2505
3129
|
{
|
|
2506
3130
|
htmlFor,
|
|
@@ -2508,25 +3132,25 @@ var FieldRow = ({
|
|
|
2508
3132
|
children: label
|
|
2509
3133
|
}
|
|
2510
3134
|
),
|
|
2511
|
-
description ? /* @__PURE__ */
|
|
3135
|
+
description ? /* @__PURE__ */ jsx29("p", { className: "mt-0.5 text-xs text-muted-foreground", children: description }) : null
|
|
2512
3136
|
] }),
|
|
2513
|
-
/* @__PURE__ */
|
|
3137
|
+
/* @__PURE__ */ jsx29("div", { className: "shrink-0", children })
|
|
2514
3138
|
]
|
|
2515
3139
|
}
|
|
2516
3140
|
);
|
|
2517
3141
|
}
|
|
2518
|
-
return /* @__PURE__ */
|
|
2519
|
-
/* @__PURE__ */
|
|
3142
|
+
return /* @__PURE__ */ jsxs23("div", { className: cn("flex flex-col gap-1.5", className), children: [
|
|
3143
|
+
/* @__PURE__ */ jsx29("label", { htmlFor, className: "text-sm font-medium text-foreground", children: label }),
|
|
2520
3144
|
children,
|
|
2521
|
-
description ? /* @__PURE__ */
|
|
3145
|
+
description ? /* @__PURE__ */ jsx29("p", { className: "text-xs text-muted-foreground", children: description }) : null
|
|
2522
3146
|
] });
|
|
2523
3147
|
};
|
|
2524
3148
|
|
|
2525
3149
|
// src/app/settings/FloatingUnsavedChangesBar.tsx
|
|
2526
|
-
import { useEffect, useState as useState3 } from "react";
|
|
3150
|
+
import { useEffect as useEffect2, useState as useState3 } from "react";
|
|
2527
3151
|
import { createPortal } from "react-dom";
|
|
2528
3152
|
import { AnimatePresence as AnimatePresence2, motion as motion3, useReducedMotion as useReducedMotion3 } from "motion/react";
|
|
2529
|
-
import { jsx as
|
|
3153
|
+
import { jsx as jsx30, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
2530
3154
|
var FloatingUnsavedChangesBar = ({
|
|
2531
3155
|
visible,
|
|
2532
3156
|
message = "Unsaved changes",
|
|
@@ -2541,10 +3165,10 @@ var FloatingUnsavedChangesBar = ({
|
|
|
2541
3165
|
}) => {
|
|
2542
3166
|
const reduceMotion = useReducedMotion3();
|
|
2543
3167
|
const [mounted, setMounted] = useState3(false);
|
|
2544
|
-
|
|
3168
|
+
useEffect2(() => setMounted(true), []);
|
|
2545
3169
|
if (!mounted || typeof document === "undefined") return null;
|
|
2546
3170
|
return createPortal(
|
|
2547
|
-
/* @__PURE__ */
|
|
3171
|
+
/* @__PURE__ */ jsx30(AnimatePresence2, { children: visible ? /* @__PURE__ */ jsx30("div", { className: "pointer-events-none fixed inset-x-0 bottom-5 z-50 flex justify-center px-4", children: /* @__PURE__ */ jsxs24(
|
|
2548
3172
|
motion3.div,
|
|
2549
3173
|
{
|
|
2550
3174
|
role: "region",
|
|
@@ -2558,10 +3182,10 @@ var FloatingUnsavedChangesBar = ({
|
|
|
2558
3182
|
className
|
|
2559
3183
|
),
|
|
2560
3184
|
children: [
|
|
2561
|
-
/* @__PURE__ */
|
|
2562
|
-
/* @__PURE__ */
|
|
2563
|
-
/* @__PURE__ */
|
|
2564
|
-
/* @__PURE__ */
|
|
3185
|
+
/* @__PURE__ */ jsx30("span", { className: "text-sm text-muted-foreground", children: message }),
|
|
3186
|
+
/* @__PURE__ */ jsxs24("span", { className: "flex items-center gap-1.5", children: [
|
|
3187
|
+
/* @__PURE__ */ jsx30(Button, { variant: "ghost", size: "sm", onClick: onDiscard, disabled: isSaving, children: discardLabel }),
|
|
3188
|
+
/* @__PURE__ */ jsx30(Button, { size: "sm", onClick: onSave, disabled: saveDisabled || isSaving, children: isSaving ? "Saving\u2026" : saveLabel })
|
|
2565
3189
|
] })
|
|
2566
3190
|
]
|
|
2567
3191
|
}
|
|
@@ -2571,13 +3195,13 @@ var FloatingUnsavedChangesBar = ({
|
|
|
2571
3195
|
};
|
|
2572
3196
|
|
|
2573
3197
|
// src/app/settings/DangerZone.tsx
|
|
2574
|
-
import { jsx as
|
|
3198
|
+
import { jsx as jsx31, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
2575
3199
|
var DangerZoneAction = ({
|
|
2576
3200
|
title,
|
|
2577
3201
|
description,
|
|
2578
3202
|
action,
|
|
2579
3203
|
className
|
|
2580
|
-
}) => /* @__PURE__ */
|
|
3204
|
+
}) => /* @__PURE__ */ jsxs25(
|
|
2581
3205
|
"div",
|
|
2582
3206
|
{
|
|
2583
3207
|
className: cn(
|
|
@@ -2585,11 +3209,11 @@ var DangerZoneAction = ({
|
|
|
2585
3209
|
className
|
|
2586
3210
|
),
|
|
2587
3211
|
children: [
|
|
2588
|
-
/* @__PURE__ */
|
|
2589
|
-
/* @__PURE__ */
|
|
2590
|
-
description ? /* @__PURE__ */
|
|
3212
|
+
/* @__PURE__ */ jsxs25("div", { className: "min-w-0", children: [
|
|
3213
|
+
/* @__PURE__ */ jsx31("p", { className: "text-sm font-medium text-foreground", children: title }),
|
|
3214
|
+
description ? /* @__PURE__ */ jsx31("p", { className: "mt-0.5 text-sm text-muted-foreground", children: description }) : null
|
|
2591
3215
|
] }),
|
|
2592
|
-
/* @__PURE__ */
|
|
3216
|
+
/* @__PURE__ */ jsx31("div", { className: "shrink-0", children: action })
|
|
2593
3217
|
]
|
|
2594
3218
|
}
|
|
2595
3219
|
);
|
|
@@ -2598,7 +3222,7 @@ var DangerZone = ({
|
|
|
2598
3222
|
description,
|
|
2599
3223
|
children,
|
|
2600
3224
|
className
|
|
2601
|
-
}) => /* @__PURE__ */
|
|
3225
|
+
}) => /* @__PURE__ */ jsxs25(
|
|
2602
3226
|
"section",
|
|
2603
3227
|
{
|
|
2604
3228
|
className: cn(
|
|
@@ -2606,18 +3230,18 @@ var DangerZone = ({
|
|
|
2606
3230
|
className
|
|
2607
3231
|
),
|
|
2608
3232
|
children: [
|
|
2609
|
-
(title || description) && /* @__PURE__ */
|
|
2610
|
-
title ? /* @__PURE__ */
|
|
2611
|
-
description ? /* @__PURE__ */
|
|
3233
|
+
(title || description) && /* @__PURE__ */ jsxs25("header", { className: "border-b border-destructive/20 bg-destructive/5 px-4 py-3", children: [
|
|
3234
|
+
title ? /* @__PURE__ */ jsx31("h3", { className: "text-sm font-semibold text-destructive", children: title }) : null,
|
|
3235
|
+
description ? /* @__PURE__ */ jsx31("p", { className: "mt-0.5 text-sm text-muted-foreground", children: description }) : null
|
|
2612
3236
|
] }),
|
|
2613
|
-
/* @__PURE__ */
|
|
3237
|
+
/* @__PURE__ */ jsx31("div", { className: "divide-y divide-border bg-card", children })
|
|
2614
3238
|
]
|
|
2615
3239
|
}
|
|
2616
3240
|
);
|
|
2617
3241
|
|
|
2618
3242
|
// src/app/integrations/IntegrationCard.tsx
|
|
2619
|
-
import { useId as
|
|
2620
|
-
import { Fragment as
|
|
3243
|
+
import { useId as useId3 } from "react";
|
|
3244
|
+
import { Fragment as Fragment6, jsx as jsx32, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2621
3245
|
var INTEGRATION_CATALOG_CARD_HEIGHT_CLASS = "h-[12.25rem] min-h-[12.25rem] max-h-[12.25rem]";
|
|
2622
3246
|
var statusLabel = {
|
|
2623
3247
|
available: null,
|
|
@@ -2625,14 +3249,14 @@ var statusLabel = {
|
|
|
2625
3249
|
disabled: "Disabled",
|
|
2626
3250
|
locked: "Locked"
|
|
2627
3251
|
};
|
|
2628
|
-
var
|
|
3252
|
+
var catalogCardShellClass2 = cn(
|
|
2629
3253
|
"group relative box-border flex flex-col overflow-hidden rounded-2xl px-4 pb-4 pt-4 text-left font-normal",
|
|
2630
3254
|
INTEGRATION_CATALOG_CARD_HEIGHT_CLASS,
|
|
2631
3255
|
TIMBAL_V2_ELEVATED_SURFACE,
|
|
2632
3256
|
"transition-opacity duration-200 ease-out"
|
|
2633
3257
|
);
|
|
2634
|
-
var
|
|
2635
|
-
|
|
3258
|
+
var catalogCardInteractiveClass2 = cn(
|
|
3259
|
+
catalogCardShellClass2,
|
|
2636
3260
|
"cursor-pointer bg-transparent hover:bg-transparent active:bg-transparent",
|
|
2637
3261
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/15 focus-visible:ring-offset-2 focus-visible:ring-offset-background"
|
|
2638
3262
|
);
|
|
@@ -2655,15 +3279,15 @@ var IntegrationCard = ({
|
|
|
2655
3279
|
ariaLabel,
|
|
2656
3280
|
className
|
|
2657
3281
|
}) => {
|
|
2658
|
-
const titleId =
|
|
3282
|
+
const titleId = useId3();
|
|
2659
3283
|
const locked = status === "locked";
|
|
2660
3284
|
const dimmed = status === "disabled" || locked;
|
|
2661
|
-
const body = /* @__PURE__ */
|
|
2662
|
-
/* @__PURE__ */
|
|
2663
|
-
logo ? /* @__PURE__ */
|
|
2664
|
-
/* @__PURE__ */
|
|
2665
|
-
/* @__PURE__ */
|
|
2666
|
-
/* @__PURE__ */
|
|
3285
|
+
const body = /* @__PURE__ */ jsxs26("div", { className: "flex h-full min-h-0 flex-col", children: [
|
|
3286
|
+
/* @__PURE__ */ jsxs26("div", { className: "flex shrink-0 items-start gap-3 pr-2", children: [
|
|
3287
|
+
logo ? /* @__PURE__ */ jsx32("span", { className: logoShellClass, "aria-hidden": Boolean(ariaLabel), children: logo }) : null,
|
|
3288
|
+
/* @__PURE__ */ jsx32("div", { className: "min-w-0 flex-1 pt-0.5", children: /* @__PURE__ */ jsxs26("div", { className: "flex items-start justify-between gap-2", children: [
|
|
3289
|
+
/* @__PURE__ */ jsxs26("div", { className: "min-w-0", children: [
|
|
3290
|
+
/* @__PURE__ */ jsx32(
|
|
2667
3291
|
"h4",
|
|
2668
3292
|
{
|
|
2669
3293
|
id: onClick && !action ? void 0 : titleId,
|
|
@@ -2671,12 +3295,12 @@ var IntegrationCard = ({
|
|
|
2671
3295
|
children: name
|
|
2672
3296
|
}
|
|
2673
3297
|
),
|
|
2674
|
-
statusLabel[status] ? /* @__PURE__ */
|
|
3298
|
+
statusLabel[status] ? /* @__PURE__ */ jsx32("p", { className: "mt-0.5 text-xs text-muted-foreground", children: statusLabel[status] }) : null
|
|
2675
3299
|
] }),
|
|
2676
|
-
badge ? /* @__PURE__ */
|
|
3300
|
+
badge ? /* @__PURE__ */ jsx32("span", { className: "shrink-0", children: badge }) : null
|
|
2677
3301
|
] }) })
|
|
2678
3302
|
] }),
|
|
2679
|
-
description ? /* @__PURE__ */
|
|
3303
|
+
description ? /* @__PURE__ */ jsx32(
|
|
2680
3304
|
"p",
|
|
2681
3305
|
{
|
|
2682
3306
|
className: cn(
|
|
@@ -2686,19 +3310,19 @@ var IntegrationCard = ({
|
|
|
2686
3310
|
children: description
|
|
2687
3311
|
}
|
|
2688
3312
|
) : null,
|
|
2689
|
-
action ? /* @__PURE__ */
|
|
2690
|
-
/* @__PURE__ */
|
|
2691
|
-
/* @__PURE__ */
|
|
3313
|
+
action ? /* @__PURE__ */ jsxs26(Fragment6, { children: [
|
|
3314
|
+
/* @__PURE__ */ jsx32("div", { className: "min-h-0 flex-1", "aria-hidden": true }),
|
|
3315
|
+
/* @__PURE__ */ jsx32("div", { className: "relative mt-3 shrink-0", children: action })
|
|
2692
3316
|
] }) : null
|
|
2693
3317
|
] });
|
|
2694
3318
|
const shellClass3 = cn(
|
|
2695
|
-
|
|
3319
|
+
catalogCardShellClass2,
|
|
2696
3320
|
dimmed && catalogCardMutedClass,
|
|
2697
3321
|
locked && "cursor-default opacity-75",
|
|
2698
3322
|
className
|
|
2699
3323
|
);
|
|
2700
3324
|
if (onClick && !action) {
|
|
2701
|
-
return /* @__PURE__ */
|
|
3325
|
+
return /* @__PURE__ */ jsx32(
|
|
2702
3326
|
"button",
|
|
2703
3327
|
{
|
|
2704
3328
|
type: "button",
|
|
@@ -2706,7 +3330,7 @@ var IntegrationCard = ({
|
|
|
2706
3330
|
disabled: locked,
|
|
2707
3331
|
"aria-label": ariaLabel,
|
|
2708
3332
|
className: cn(
|
|
2709
|
-
|
|
3333
|
+
catalogCardInteractiveClass2,
|
|
2710
3334
|
dimmed && catalogCardMutedClass,
|
|
2711
3335
|
locked && "cursor-default opacity-75",
|
|
2712
3336
|
className
|
|
@@ -2715,12 +3339,12 @@ var IntegrationCard = ({
|
|
|
2715
3339
|
}
|
|
2716
3340
|
);
|
|
2717
3341
|
}
|
|
2718
|
-
return /* @__PURE__ */
|
|
3342
|
+
return /* @__PURE__ */ jsx32("article", { className: shellClass3, "aria-labelledby": titleId, children: body });
|
|
2719
3343
|
};
|
|
2720
3344
|
|
|
2721
3345
|
// src/app/integrations/IntegrationsEmptyState.tsx
|
|
2722
|
-
import { useId as
|
|
2723
|
-
import { jsx as
|
|
3346
|
+
import { useId as useId4 } from "react";
|
|
3347
|
+
import { jsx as jsx33, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
2724
3348
|
var IntegrationsEmptyState = ({
|
|
2725
3349
|
title = "No integrations yet",
|
|
2726
3350
|
description = "Connect a provider to start syncing data and powering your workforce.",
|
|
@@ -2728,8 +3352,8 @@ var IntegrationsEmptyState = ({
|
|
|
2728
3352
|
action,
|
|
2729
3353
|
className
|
|
2730
3354
|
}) => {
|
|
2731
|
-
const titleId =
|
|
2732
|
-
return /* @__PURE__ */
|
|
3355
|
+
const titleId = useId4();
|
|
3356
|
+
return /* @__PURE__ */ jsxs27(
|
|
2733
3357
|
"section",
|
|
2734
3358
|
{
|
|
2735
3359
|
className: cn(
|
|
@@ -2739,7 +3363,7 @@ var IntegrationsEmptyState = ({
|
|
|
2739
3363
|
),
|
|
2740
3364
|
"aria-labelledby": titleId,
|
|
2741
3365
|
children: [
|
|
2742
|
-
icon ? /* @__PURE__ */
|
|
3366
|
+
icon ? /* @__PURE__ */ jsx33(
|
|
2743
3367
|
"span",
|
|
2744
3368
|
{
|
|
2745
3369
|
className: cn(
|
|
@@ -2751,21 +3375,21 @@ var IntegrationsEmptyState = ({
|
|
|
2751
3375
|
children: icon
|
|
2752
3376
|
}
|
|
2753
3377
|
) : null,
|
|
2754
|
-
/* @__PURE__ */
|
|
2755
|
-
description ? /* @__PURE__ */
|
|
2756
|
-
action ? /* @__PURE__ */
|
|
3378
|
+
/* @__PURE__ */ jsx33("h3", { id: titleId, className: "text-base font-normal text-foreground", children: title }),
|
|
3379
|
+
description ? /* @__PURE__ */ jsx33("p", { className: "max-w-sm text-sm text-muted-foreground", children: description }) : null,
|
|
3380
|
+
action ? /* @__PURE__ */ jsx33("div", { className: "mt-1", children: action }) : null
|
|
2757
3381
|
]
|
|
2758
3382
|
}
|
|
2759
3383
|
);
|
|
2760
3384
|
};
|
|
2761
3385
|
|
|
2762
3386
|
// src/app/integrations/PlanBadge.tsx
|
|
2763
|
-
import { jsx as
|
|
3387
|
+
import { jsx as jsx34 } from "react/jsx-runtime";
|
|
2764
3388
|
var planBadgeClass = "inline-flex h-5 max-w-full shrink-0 items-center rounded-md border border-border bg-muted/90 px-2 text-[11px] font-normal text-muted-foreground dark:border-white/10 dark:bg-white/5 dark:text-muted-foreground";
|
|
2765
|
-
var PlanBadge = ({ children, className }) => /* @__PURE__ */
|
|
3389
|
+
var PlanBadge = ({ children, className }) => /* @__PURE__ */ jsx34("span", { className: cn(planBadgeClass, className), children });
|
|
2766
3390
|
|
|
2767
3391
|
// src/app/integrations/ConnectionRow.tsx
|
|
2768
|
-
import { Fragment as
|
|
3392
|
+
import { Fragment as Fragment7, jsx as jsx35, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
2769
3393
|
var logoShellClass2 = cn(
|
|
2770
3394
|
"flex size-9 shrink-0 items-center justify-center overflow-hidden rounded-lg",
|
|
2771
3395
|
TIMBAL_V2_LOGO_TILE
|
|
@@ -2780,14 +3404,14 @@ var ConnectionRow = ({
|
|
|
2780
3404
|
ariaLabel,
|
|
2781
3405
|
className
|
|
2782
3406
|
}) => {
|
|
2783
|
-
const inner = /* @__PURE__ */
|
|
2784
|
-
logo ? /* @__PURE__ */
|
|
2785
|
-
/* @__PURE__ */
|
|
2786
|
-
/* @__PURE__ */
|
|
2787
|
-
meta ? /* @__PURE__ */
|
|
3407
|
+
const inner = /* @__PURE__ */ jsxs28(Fragment7, { children: [
|
|
3408
|
+
logo ? /* @__PURE__ */ jsx35("span", { className: logoShellClass2, children: logo }) : null,
|
|
3409
|
+
/* @__PURE__ */ jsxs28("div", { className: "min-w-0 flex-1", children: [
|
|
3410
|
+
/* @__PURE__ */ jsx35("p", { className: "truncate text-sm font-normal text-foreground", children: name }),
|
|
3411
|
+
meta ? /* @__PURE__ */ jsx35("p", { className: "truncate text-xs text-muted-foreground", children: meta }) : null
|
|
2788
3412
|
] }),
|
|
2789
|
-
badge ? /* @__PURE__ */
|
|
2790
|
-
action ? /* @__PURE__ */
|
|
3413
|
+
badge ? /* @__PURE__ */ jsx35("span", { className: "shrink-0", children: badge }) : null,
|
|
3414
|
+
action ? /* @__PURE__ */ jsx35("span", { className: "shrink-0", children: action }) : null
|
|
2791
3415
|
] });
|
|
2792
3416
|
const rowClass2 = cn(
|
|
2793
3417
|
"flex w-full items-center gap-3 px-4 py-3 text-left",
|
|
@@ -2795,7 +3419,7 @@ var ConnectionRow = ({
|
|
|
2795
3419
|
className
|
|
2796
3420
|
);
|
|
2797
3421
|
if (onClick) {
|
|
2798
|
-
return /* @__PURE__ */
|
|
3422
|
+
return /* @__PURE__ */ jsx35(
|
|
2799
3423
|
"button",
|
|
2800
3424
|
{
|
|
2801
3425
|
type: "button",
|
|
@@ -2807,7 +3431,7 @@ var ConnectionRow = ({
|
|
|
2807
3431
|
}
|
|
2808
3432
|
);
|
|
2809
3433
|
}
|
|
2810
|
-
return /* @__PURE__ */
|
|
3434
|
+
return /* @__PURE__ */ jsx35("div", { role: "listitem", className: rowClass2, children: inner });
|
|
2811
3435
|
};
|
|
2812
3436
|
var connectionRowListClass = cn(
|
|
2813
3437
|
"overflow-hidden rounded-2xl",
|
|
@@ -2815,12 +3439,12 @@ var connectionRowListClass = cn(
|
|
|
2815
3439
|
);
|
|
2816
3440
|
|
|
2817
3441
|
// src/app/integrations/ConnectionRowList.tsx
|
|
2818
|
-
import { jsx as
|
|
3442
|
+
import { jsx as jsx36 } from "react/jsx-runtime";
|
|
2819
3443
|
var ConnectionRowList = ({
|
|
2820
3444
|
children,
|
|
2821
3445
|
"aria-label": ariaLabel = "Connected integrations",
|
|
2822
3446
|
className
|
|
2823
|
-
}) => /* @__PURE__ */
|
|
3447
|
+
}) => /* @__PURE__ */ jsx36(
|
|
2824
3448
|
"div",
|
|
2825
3449
|
{
|
|
2826
3450
|
role: "list",
|
|
@@ -2831,7 +3455,7 @@ var ConnectionRowList = ({
|
|
|
2831
3455
|
);
|
|
2832
3456
|
|
|
2833
3457
|
// src/app/navigation/SubNav.tsx
|
|
2834
|
-
import { jsx as
|
|
3458
|
+
import { jsx as jsx37 } from "react/jsx-runtime";
|
|
2835
3459
|
var SubNav = ({
|
|
2836
3460
|
items,
|
|
2837
3461
|
activeId,
|
|
@@ -2840,7 +3464,7 @@ var SubNav = ({
|
|
|
2840
3464
|
"aria-label": ariaLabel = "Section navigation",
|
|
2841
3465
|
layoutId
|
|
2842
3466
|
}) => {
|
|
2843
|
-
return /* @__PURE__ */
|
|
3467
|
+
return /* @__PURE__ */ jsx37("nav", { className: cn("aui-app-sub-nav", className), "aria-label": ariaLabel, children: /* @__PURE__ */ jsx37(
|
|
2844
3468
|
PillSegmentedTabs,
|
|
2845
3469
|
{
|
|
2846
3470
|
value: activeId,
|
|
@@ -2854,13 +3478,13 @@ var SubNav = ({
|
|
|
2854
3478
|
};
|
|
2855
3479
|
|
|
2856
3480
|
// src/app/navigation/Breadcrumbs.tsx
|
|
2857
|
-
import { jsx as
|
|
3481
|
+
import { jsx as jsx38, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
2858
3482
|
var Breadcrumbs = ({ items, className }) => {
|
|
2859
|
-
return /* @__PURE__ */
|
|
3483
|
+
return /* @__PURE__ */ jsx38("nav", { className: cn("aui-app-breadcrumbs", appBreadcrumbsClass, className), "aria-label": "Breadcrumb", children: /* @__PURE__ */ jsx38("ol", { className: "flex flex-wrap items-center gap-1.5", children: items.map((item, index) => {
|
|
2860
3484
|
const isLast = index === items.length - 1;
|
|
2861
|
-
return /* @__PURE__ */
|
|
2862
|
-
index > 0 ? /* @__PURE__ */
|
|
2863
|
-
isLast ? /* @__PURE__ */
|
|
3485
|
+
return /* @__PURE__ */ jsxs29("li", { className: "inline-flex items-center gap-1.5", children: [
|
|
3486
|
+
index > 0 ? /* @__PURE__ */ jsx38("span", { className: "text-muted-foreground/50", "aria-hidden": true, children: "/" }) : null,
|
|
3487
|
+
isLast ? /* @__PURE__ */ jsx38("span", { className: "text-foreground", "aria-current": "page", children: item.label }) : item.href ? /* @__PURE__ */ jsx38("a", { href: item.href, className: appBreadcrumbLinkClass, children: item.label }) : /* @__PURE__ */ jsx38(
|
|
2864
3488
|
"button",
|
|
2865
3489
|
{
|
|
2866
3490
|
type: "button",
|
|
@@ -2874,8 +3498,8 @@ var Breadcrumbs = ({ items, className }) => {
|
|
|
2874
3498
|
};
|
|
2875
3499
|
|
|
2876
3500
|
// src/app/forms/Field.tsx
|
|
2877
|
-
import { useId as
|
|
2878
|
-
import { jsx as
|
|
3501
|
+
import { useId as useId5 } from "react";
|
|
3502
|
+
import { jsx as jsx39, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
2879
3503
|
var Field = ({
|
|
2880
3504
|
label,
|
|
2881
3505
|
hint,
|
|
@@ -2884,11 +3508,11 @@ var Field = ({
|
|
|
2884
3508
|
className,
|
|
2885
3509
|
htmlFor
|
|
2886
3510
|
}) => {
|
|
2887
|
-
return /* @__PURE__ */
|
|
2888
|
-
/* @__PURE__ */
|
|
3511
|
+
return /* @__PURE__ */ jsxs30("div", { className: cn("aui-app-field", appFieldClass, className), children: [
|
|
3512
|
+
/* @__PURE__ */ jsx39("label", { className: appFieldLabelClass, htmlFor, children: label }),
|
|
2889
3513
|
children,
|
|
2890
|
-
hint && !error ? /* @__PURE__ */
|
|
2891
|
-
error ? /* @__PURE__ */
|
|
3514
|
+
hint && !error ? /* @__PURE__ */ jsx39("p", { className: appFieldHintClass, children: hint }) : null,
|
|
3515
|
+
error ? /* @__PURE__ */ jsx39("p", { className: "text-xs text-destructive", role: "alert", children: error }) : null
|
|
2892
3516
|
] });
|
|
2893
3517
|
};
|
|
2894
3518
|
var FieldInput = ({
|
|
@@ -2900,9 +3524,9 @@ var FieldInput = ({
|
|
|
2900
3524
|
id,
|
|
2901
3525
|
...inputProps
|
|
2902
3526
|
}) => {
|
|
2903
|
-
const autoId =
|
|
3527
|
+
const autoId = useId5();
|
|
2904
3528
|
const inputId = id ?? inputProps.name ?? autoId;
|
|
2905
|
-
return /* @__PURE__ */
|
|
3529
|
+
return /* @__PURE__ */ jsx39(
|
|
2906
3530
|
Field,
|
|
2907
3531
|
{
|
|
2908
3532
|
label,
|
|
@@ -2910,7 +3534,7 @@ var FieldInput = ({
|
|
|
2910
3534
|
error,
|
|
2911
3535
|
htmlFor: inputId,
|
|
2912
3536
|
className: fieldClassName,
|
|
2913
|
-
children: /* @__PURE__ */
|
|
3537
|
+
children: /* @__PURE__ */ jsx39(
|
|
2914
3538
|
"input",
|
|
2915
3539
|
{
|
|
2916
3540
|
id: inputId,
|
|
@@ -2924,8 +3548,8 @@ var FieldInput = ({
|
|
|
2924
3548
|
};
|
|
2925
3549
|
|
|
2926
3550
|
// src/app/forms/FieldTextarea.tsx
|
|
2927
|
-
import { useId as
|
|
2928
|
-
import { jsx as
|
|
3551
|
+
import { useId as useId6 } from "react";
|
|
3552
|
+
import { jsx as jsx40 } from "react/jsx-runtime";
|
|
2929
3553
|
var textareaClass = cn(
|
|
2930
3554
|
appInputClass,
|
|
2931
3555
|
"min-h-[5.5rem] resize-y py-2.5 leading-relaxed"
|
|
@@ -2939,9 +3563,9 @@ var FieldTextarea = ({
|
|
|
2939
3563
|
id,
|
|
2940
3564
|
...props
|
|
2941
3565
|
}) => {
|
|
2942
|
-
const autoId =
|
|
3566
|
+
const autoId = useId6();
|
|
2943
3567
|
const textareaId = id ?? props.name ?? autoId;
|
|
2944
|
-
return /* @__PURE__ */
|
|
3568
|
+
return /* @__PURE__ */ jsx40(
|
|
2945
3569
|
Field,
|
|
2946
3570
|
{
|
|
2947
3571
|
label,
|
|
@@ -2949,7 +3573,7 @@ var FieldTextarea = ({
|
|
|
2949
3573
|
error,
|
|
2950
3574
|
htmlFor: textareaId,
|
|
2951
3575
|
className: fieldClassName,
|
|
2952
|
-
children: /* @__PURE__ */
|
|
3576
|
+
children: /* @__PURE__ */ jsx40(
|
|
2953
3577
|
"textarea",
|
|
2954
3578
|
{
|
|
2955
3579
|
id: textareaId,
|
|
@@ -2963,9 +3587,9 @@ var FieldTextarea = ({
|
|
|
2963
3587
|
};
|
|
2964
3588
|
|
|
2965
3589
|
// src/app/forms/FieldSelect.tsx
|
|
2966
|
-
import { useId as
|
|
3590
|
+
import { useId as useId7 } from "react";
|
|
2967
3591
|
import { ChevronDownIcon } from "lucide-react";
|
|
2968
|
-
import { jsx as
|
|
3592
|
+
import { jsx as jsx41, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
2969
3593
|
var selectWrapClass = "relative";
|
|
2970
3594
|
var selectClass = cn(
|
|
2971
3595
|
appInputClass,
|
|
@@ -2981,9 +3605,9 @@ var FieldSelect = ({
|
|
|
2981
3605
|
id,
|
|
2982
3606
|
...props
|
|
2983
3607
|
}) => {
|
|
2984
|
-
const autoId =
|
|
3608
|
+
const autoId = useId7();
|
|
2985
3609
|
const selectId = id ?? props.name ?? autoId;
|
|
2986
|
-
return /* @__PURE__ */
|
|
3610
|
+
return /* @__PURE__ */ jsx41(
|
|
2987
3611
|
Field,
|
|
2988
3612
|
{
|
|
2989
3613
|
label,
|
|
@@ -2991,8 +3615,8 @@ var FieldSelect = ({
|
|
|
2991
3615
|
error,
|
|
2992
3616
|
htmlFor: selectId,
|
|
2993
3617
|
className: fieldClassName,
|
|
2994
|
-
children: /* @__PURE__ */
|
|
2995
|
-
/* @__PURE__ */
|
|
3618
|
+
children: /* @__PURE__ */ jsxs31("div", { className: selectWrapClass, children: [
|
|
3619
|
+
/* @__PURE__ */ jsx41(
|
|
2996
3620
|
"select",
|
|
2997
3621
|
{
|
|
2998
3622
|
id: selectId,
|
|
@@ -3002,7 +3626,7 @@ var FieldSelect = ({
|
|
|
3002
3626
|
children
|
|
3003
3627
|
}
|
|
3004
3628
|
),
|
|
3005
|
-
/* @__PURE__ */
|
|
3629
|
+
/* @__PURE__ */ jsx41(
|
|
3006
3630
|
ChevronDownIcon,
|
|
3007
3631
|
{
|
|
3008
3632
|
className: "pointer-events-none absolute top-1/2 right-3 size-4 -translate-y-1/2 text-muted-foreground",
|
|
@@ -3015,8 +3639,8 @@ var FieldSelect = ({
|
|
|
3015
3639
|
};
|
|
3016
3640
|
|
|
3017
3641
|
// src/app/forms/FieldSwitch.tsx
|
|
3018
|
-
import { useId as
|
|
3019
|
-
import { jsx as
|
|
3642
|
+
import { useId as useId8 } from "react";
|
|
3643
|
+
import { jsx as jsx42, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
3020
3644
|
var trackClass = cn(
|
|
3021
3645
|
"relative inline-flex h-5 w-9 shrink-0 items-center rounded-full transition-[background,box-shadow,border-color] duration-200",
|
|
3022
3646
|
"peer-focus-visible:ring-2 peer-focus-visible:ring-foreground/10",
|
|
@@ -3036,9 +3660,9 @@ var FieldSwitch = ({
|
|
|
3036
3660
|
id,
|
|
3037
3661
|
...props
|
|
3038
3662
|
}) => {
|
|
3039
|
-
const autoId =
|
|
3663
|
+
const autoId = useId8();
|
|
3040
3664
|
const inputId = id ?? props.name ?? autoId;
|
|
3041
|
-
return /* @__PURE__ */
|
|
3665
|
+
return /* @__PURE__ */ jsxs32(
|
|
3042
3666
|
"label",
|
|
3043
3667
|
{
|
|
3044
3668
|
className: cn(
|
|
@@ -3047,8 +3671,8 @@ var FieldSwitch = ({
|
|
|
3047
3671
|
),
|
|
3048
3672
|
htmlFor: inputId,
|
|
3049
3673
|
children: [
|
|
3050
|
-
/* @__PURE__ */
|
|
3051
|
-
/* @__PURE__ */
|
|
3674
|
+
/* @__PURE__ */ jsxs32("span", { className: "relative mt-0.5", children: [
|
|
3675
|
+
/* @__PURE__ */ jsx42(
|
|
3052
3676
|
"input",
|
|
3053
3677
|
{
|
|
3054
3678
|
id: inputId,
|
|
@@ -3058,11 +3682,11 @@ var FieldSwitch = ({
|
|
|
3058
3682
|
...props
|
|
3059
3683
|
}
|
|
3060
3684
|
),
|
|
3061
|
-
/* @__PURE__ */
|
|
3685
|
+
/* @__PURE__ */ jsx42("span", { className: trackClass, "aria-hidden": true, children: /* @__PURE__ */ jsx42("span", { className: thumbClass }) })
|
|
3062
3686
|
] }),
|
|
3063
|
-
/* @__PURE__ */
|
|
3064
|
-
/* @__PURE__ */
|
|
3065
|
-
description ? /* @__PURE__ */
|
|
3687
|
+
/* @__PURE__ */ jsxs32("span", { className: "flex min-w-0 flex-col gap-0.5", children: [
|
|
3688
|
+
/* @__PURE__ */ jsx42("span", { className: "text-sm font-medium text-foreground", children: label }),
|
|
3689
|
+
description ? /* @__PURE__ */ jsx42("span", { className: "text-xs text-muted-foreground", children: description }) : null
|
|
3066
3690
|
] })
|
|
3067
3691
|
]
|
|
3068
3692
|
}
|
|
@@ -3071,13 +3695,13 @@ var FieldSwitch = ({
|
|
|
3071
3695
|
|
|
3072
3696
|
// src/app/forms/SearchInput.tsx
|
|
3073
3697
|
import { SearchIcon } from "lucide-react";
|
|
3074
|
-
import { jsx as
|
|
3698
|
+
import { jsx as jsx43, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
3075
3699
|
var SearchInput = ({
|
|
3076
3700
|
className,
|
|
3077
3701
|
placeholder = "Search\u2026",
|
|
3078
3702
|
...props
|
|
3079
3703
|
}) => {
|
|
3080
|
-
return /* @__PURE__ */
|
|
3704
|
+
return /* @__PURE__ */ jsxs33(
|
|
3081
3705
|
"label",
|
|
3082
3706
|
{
|
|
3083
3707
|
className: cn(
|
|
@@ -3086,8 +3710,8 @@ var SearchInput = ({
|
|
|
3086
3710
|
className
|
|
3087
3711
|
),
|
|
3088
3712
|
children: [
|
|
3089
|
-
/* @__PURE__ */
|
|
3090
|
-
/* @__PURE__ */
|
|
3713
|
+
/* @__PURE__ */ jsx43(SearchIcon, { className: "size-4 shrink-0 text-muted-foreground", "aria-hidden": true }),
|
|
3714
|
+
/* @__PURE__ */ jsx43(
|
|
3091
3715
|
"input",
|
|
3092
3716
|
{
|
|
3093
3717
|
type: "search",
|
|
@@ -3102,26 +3726,26 @@ var SearchInput = ({
|
|
|
3102
3726
|
};
|
|
3103
3727
|
|
|
3104
3728
|
// src/app/forms/FormSection.tsx
|
|
3105
|
-
import { jsx as
|
|
3729
|
+
import { jsx as jsx44, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
3106
3730
|
var FormSection = ({ title, children, className }) => {
|
|
3107
3731
|
const density = useAppDensity();
|
|
3108
3732
|
const sectionClass = useAppDensityClass("section");
|
|
3109
|
-
return /* @__PURE__ */
|
|
3733
|
+
return /* @__PURE__ */ jsxs34(
|
|
3110
3734
|
"fieldset",
|
|
3111
3735
|
{
|
|
3112
3736
|
className: cn("aui-app-form-section", sectionClass, "border-0 p-0", className),
|
|
3113
3737
|
children: [
|
|
3114
|
-
title ? /* @__PURE__ */
|
|
3115
|
-
/* @__PURE__ */
|
|
3738
|
+
title ? /* @__PURE__ */ jsx44("legend", { className: cn(appSectionTitleClass, "mb-3 px-0"), children: title }) : null,
|
|
3739
|
+
/* @__PURE__ */ jsx44("div", { className: cn("flex flex-col", density === "compact" ? "gap-2" : "gap-4"), children })
|
|
3116
3740
|
]
|
|
3117
3741
|
}
|
|
3118
3742
|
);
|
|
3119
3743
|
};
|
|
3120
3744
|
|
|
3121
3745
|
// src/app/data/FilterBar.tsx
|
|
3122
|
-
import { jsx as
|
|
3746
|
+
import { jsx as jsx45 } from "react/jsx-runtime";
|
|
3123
3747
|
var FilterBar = ({ children, className }) => {
|
|
3124
|
-
return /* @__PURE__ */
|
|
3748
|
+
return /* @__PURE__ */ jsx45(
|
|
3125
3749
|
"div",
|
|
3126
3750
|
{
|
|
3127
3751
|
className: cn("aui-app-filter-bar", appFilterBarClass, className),
|
|
@@ -3133,41 +3757,539 @@ var FilterBar = ({ children, className }) => {
|
|
|
3133
3757
|
};
|
|
3134
3758
|
|
|
3135
3759
|
// src/app/data/FilterField.tsx
|
|
3136
|
-
import { jsx as
|
|
3760
|
+
import { jsx as jsx46, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
3137
3761
|
var FilterField = ({
|
|
3138
3762
|
label,
|
|
3139
3763
|
children,
|
|
3140
3764
|
className
|
|
3141
3765
|
}) => {
|
|
3142
|
-
return /* @__PURE__ */
|
|
3143
|
-
label ? /* @__PURE__ */
|
|
3766
|
+
return /* @__PURE__ */ jsxs35("div", { className: cn("aui-app-filter-field", appFieldClass, className), children: [
|
|
3767
|
+
label ? /* @__PURE__ */ jsx46("span", { className: appFieldLabelClass, children: label }) : null,
|
|
3144
3768
|
children
|
|
3145
3769
|
] });
|
|
3146
3770
|
};
|
|
3147
3771
|
|
|
3772
|
+
// src/app/data/FilterDropdown.tsx
|
|
3773
|
+
import { useState as useState4, useMemo as useMemo2, useEffect as useEffect3 } from "react";
|
|
3774
|
+
import {
|
|
3775
|
+
CalendarIcon,
|
|
3776
|
+
ChevronDownIcon as ChevronDownIcon2,
|
|
3777
|
+
ChevronRightIcon,
|
|
3778
|
+
CircleDollarSignIcon,
|
|
3779
|
+
ListFilterIcon,
|
|
3780
|
+
SearchIcon as SearchIcon2,
|
|
3781
|
+
TrendingUpIcon,
|
|
3782
|
+
UserIcon,
|
|
3783
|
+
WalletIcon
|
|
3784
|
+
} from "lucide-react";
|
|
3785
|
+
import { jsx as jsx47, jsxs as jsxs36 } from "react/jsx-runtime";
|
|
3786
|
+
var DEFAULT_CONTACTS = [
|
|
3787
|
+
{ id: "1", name: "Pedro Olivares Sanchez", email: "polivares@timbal.ai", initials: "PE" },
|
|
3788
|
+
{ id: "2", name: "John Doe", email: "john@example.com", initials: "JD" },
|
|
3789
|
+
{ id: "3", name: "Sarah Smith", email: "sarah@example.com", initials: "SS" }
|
|
3790
|
+
];
|
|
3791
|
+
var OPERATORS = [
|
|
3792
|
+
{ id: "greater_than", label: "Greater than..." },
|
|
3793
|
+
{ id: "less_than", label: "Less than..." },
|
|
3794
|
+
{ id: "equals", label: "Equals..." }
|
|
3795
|
+
];
|
|
3796
|
+
function FilterDropdown({
|
|
3797
|
+
filters,
|
|
3798
|
+
onFiltersChange,
|
|
3799
|
+
initialFilters,
|
|
3800
|
+
contacts = DEFAULT_CONTACTS,
|
|
3801
|
+
className
|
|
3802
|
+
}) {
|
|
3803
|
+
const [isOpen, setIsOpen] = useState4(false);
|
|
3804
|
+
const [activeMenu, setActiveMenu] = useState4("contact");
|
|
3805
|
+
const [isMobile, setIsMobile] = useState4(false);
|
|
3806
|
+
useEffect3(() => {
|
|
3807
|
+
const checkMobile = () => setIsMobile(window.innerWidth < 768);
|
|
3808
|
+
checkMobile();
|
|
3809
|
+
window.addEventListener("resize", checkMobile);
|
|
3810
|
+
return () => window.removeEventListener("resize", checkMobile);
|
|
3811
|
+
}, []);
|
|
3812
|
+
const [selectedContacts, setSelectedContacts] = useState4(
|
|
3813
|
+
filters?.contacts ?? initialFilters?.contacts ?? []
|
|
3814
|
+
);
|
|
3815
|
+
const [walletInput, setWalletInput] = useState4(filters?.walletAddress ?? initialFilters?.walletAddress ?? "");
|
|
3816
|
+
const [appliedWallet, setAppliedWallet] = useState4(filters?.walletAddress ?? initialFilters?.walletAddress ?? "");
|
|
3817
|
+
const [selectedDatePreset, setSelectedDatePreset] = useState4(
|
|
3818
|
+
filters?.lastInvoiceDate ?? initialFilters?.lastInvoiceDate ?? null
|
|
3819
|
+
);
|
|
3820
|
+
const [customDateFrom, setCustomDateFrom] = useState4(
|
|
3821
|
+
filters?.customDateRange?.from ?? initialFilters?.customDateRange?.from ?? ""
|
|
3822
|
+
);
|
|
3823
|
+
const [customDateTo, setCustomDateTo] = useState4(
|
|
3824
|
+
filters?.customDateRange?.to ?? initialFilters?.customDateRange?.to ?? ""
|
|
3825
|
+
);
|
|
3826
|
+
const [ltvOperator, setLtvOperator] = useState4(
|
|
3827
|
+
filters?.lifetimeValue?.operator ?? initialFilters?.lifetimeValue?.operator ?? "greater_than"
|
|
3828
|
+
);
|
|
3829
|
+
const [ltvValue, setLtvValue] = useState4(filters?.lifetimeValue?.value ?? initialFilters?.lifetimeValue?.value ?? "");
|
|
3830
|
+
const [isLtvOperatorOpen, setLtvOperatorOpen] = useState4(false);
|
|
3831
|
+
const [outstandingOperator, setOutstandingOperator] = useState4(
|
|
3832
|
+
filters?.outstanding?.operator ?? initialFilters?.outstanding?.operator ?? "greater_than"
|
|
3833
|
+
);
|
|
3834
|
+
const [outstandingValue, setOutstandingValue] = useState4(filters?.outstanding?.value ?? initialFilters?.outstanding?.value ?? "");
|
|
3835
|
+
const [isOutstandingOperatorOpen, setOutstandingOperatorOpen] = useState4(false);
|
|
3836
|
+
useEffect3(() => {
|
|
3837
|
+
if (filters) {
|
|
3838
|
+
setSelectedContacts(filters.contacts ?? []);
|
|
3839
|
+
setWalletInput(filters.walletAddress ?? "");
|
|
3840
|
+
setAppliedWallet(filters.walletAddress ?? "");
|
|
3841
|
+
setSelectedDatePreset(filters.lastInvoiceDate ?? null);
|
|
3842
|
+
setCustomDateFrom(filters.customDateRange?.from ?? "");
|
|
3843
|
+
setCustomDateTo(filters.customDateRange?.to ?? "");
|
|
3844
|
+
setLtvOperator(filters.lifetimeValue?.operator ?? "greater_than");
|
|
3845
|
+
setLtvValue(filters.lifetimeValue?.value ?? "");
|
|
3846
|
+
setOutstandingOperator(filters.outstanding?.operator ?? "greater_than");
|
|
3847
|
+
setOutstandingValue(filters.outstanding?.value ?? "");
|
|
3848
|
+
}
|
|
3849
|
+
}, [filters]);
|
|
3850
|
+
const [contactSearch, setContactSearch] = useState4("");
|
|
3851
|
+
const [walletSearch, setWalletSearch] = useState4("");
|
|
3852
|
+
const refDate = useMemo2(() => new Date(2026, 5, 26), []);
|
|
3853
|
+
const presets = useMemo2(() => {
|
|
3854
|
+
const year = refDate.getFullYear();
|
|
3855
|
+
const month = refDate.getMonth();
|
|
3856
|
+
const lastMonthDate = new Date(year, month - 1, 1);
|
|
3857
|
+
const lastMonthLabel = lastMonthDate.toLocaleDateString("en-US", { month: "short", year: "numeric" });
|
|
3858
|
+
const thisMonthLabel = refDate.toLocaleDateString("en-US", { month: "short", year: "numeric" });
|
|
3859
|
+
const thisQuarter = Math.floor(month / 3) + 1;
|
|
3860
|
+
const thisQuarterLabel = `Q${thisQuarter} ${year}`;
|
|
3861
|
+
const lastQuarter = thisQuarter === 1 ? 4 : thisQuarter - 1;
|
|
3862
|
+
const lastQuarterYear = thisQuarter === 1 ? year - 1 : year;
|
|
3863
|
+
const lastQuarterLabel = `Q${lastQuarter} ${lastQuarterYear}`;
|
|
3864
|
+
const thisYearLabel = `${year}`;
|
|
3865
|
+
const last30 = new Date(refDate);
|
|
3866
|
+
last30.setDate(refDate.getDate() - 30);
|
|
3867
|
+
const formatDate = (d) => d.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });
|
|
3868
|
+
const last30Label = `${formatDate(last30)} - ${formatDate(refDate)}`;
|
|
3869
|
+
const last90 = new Date(refDate);
|
|
3870
|
+
last90.setDate(refDate.getDate() - 90);
|
|
3871
|
+
const last90Label = `${formatDate(last90)} - ${formatDate(refDate)}`;
|
|
3872
|
+
return [
|
|
3873
|
+
{ id: "last_month", label: "Last month", date: lastMonthLabel },
|
|
3874
|
+
{ id: "this_month", label: "This month", date: thisMonthLabel },
|
|
3875
|
+
{ id: "this_quarter", label: "This quarter", date: thisQuarterLabel },
|
|
3876
|
+
{ id: "last_quarter", label: "Last quarter", date: lastQuarterLabel },
|
|
3877
|
+
{ id: "this_year", label: "This year", date: thisYearLabel },
|
|
3878
|
+
{ id: "last_30_days", label: "Last 30 days", date: last30Label },
|
|
3879
|
+
{ id: "last_90_days", label: "Last 90 days", date: last90Label },
|
|
3880
|
+
{ id: "custom", label: "Custom range", date: "" }
|
|
3881
|
+
];
|
|
3882
|
+
}, [refDate]);
|
|
3883
|
+
const filteredContacts = useMemo2(() => {
|
|
3884
|
+
if (!contactSearch) return contacts;
|
|
3885
|
+
const query = contactSearch.toLowerCase();
|
|
3886
|
+
return contacts.filter(
|
|
3887
|
+
(c) => c.name.toLowerCase().includes(query) || c.email.toLowerCase().includes(query)
|
|
3888
|
+
);
|
|
3889
|
+
}, [contacts, contactSearch]);
|
|
3890
|
+
const handleContactToggle = (contactName) => {
|
|
3891
|
+
const next = selectedContacts.includes(contactName) ? selectedContacts.filter((name) => name !== contactName) : [...selectedContacts, contactName];
|
|
3892
|
+
setSelectedContacts(next);
|
|
3893
|
+
notifyChanges({ contacts: next });
|
|
3894
|
+
setIsOpen(false);
|
|
3895
|
+
};
|
|
3896
|
+
const handleWalletApply = () => {
|
|
3897
|
+
setAppliedWallet(walletInput);
|
|
3898
|
+
notifyChanges({ walletAddress: walletInput });
|
|
3899
|
+
setIsOpen(false);
|
|
3900
|
+
};
|
|
3901
|
+
const handleWalletClear = () => {
|
|
3902
|
+
setWalletInput("");
|
|
3903
|
+
setAppliedWallet("");
|
|
3904
|
+
notifyChanges({ walletAddress: "" });
|
|
3905
|
+
setIsOpen(false);
|
|
3906
|
+
};
|
|
3907
|
+
const handleDatePresetSelect = (presetId) => {
|
|
3908
|
+
setSelectedDatePreset(presetId);
|
|
3909
|
+
if (presetId !== "custom") {
|
|
3910
|
+
notifyChanges({ lastInvoiceDate: presetId, customDateRange: void 0 });
|
|
3911
|
+
setIsOpen(false);
|
|
3912
|
+
}
|
|
3913
|
+
};
|
|
3914
|
+
const handleCustomDateApply = () => {
|
|
3915
|
+
notifyChanges({
|
|
3916
|
+
lastInvoiceDate: "custom",
|
|
3917
|
+
customDateRange: { from: customDateFrom, to: customDateTo }
|
|
3918
|
+
});
|
|
3919
|
+
setIsOpen(false);
|
|
3920
|
+
};
|
|
3921
|
+
const handleLtvApply = () => {
|
|
3922
|
+
notifyChanges({
|
|
3923
|
+
lifetimeValue: ltvValue ? { operator: ltvOperator, value: ltvValue } : null
|
|
3924
|
+
});
|
|
3925
|
+
setIsOpen(false);
|
|
3926
|
+
};
|
|
3927
|
+
const handleLtvClear = () => {
|
|
3928
|
+
setLtvValue("");
|
|
3929
|
+
notifyChanges({ lifetimeValue: null });
|
|
3930
|
+
setIsOpen(false);
|
|
3931
|
+
};
|
|
3932
|
+
const handleOutstandingApply = () => {
|
|
3933
|
+
notifyChanges({
|
|
3934
|
+
outstanding: outstandingValue ? { operator: outstandingOperator, value: outstandingValue } : null
|
|
3935
|
+
});
|
|
3936
|
+
setIsOpen(false);
|
|
3937
|
+
};
|
|
3938
|
+
const handleOutstandingClear = () => {
|
|
3939
|
+
setOutstandingValue("");
|
|
3940
|
+
notifyChanges({ outstanding: null });
|
|
3941
|
+
setIsOpen(false);
|
|
3942
|
+
};
|
|
3943
|
+
const notifyChanges = (overrides) => {
|
|
3944
|
+
const current = {
|
|
3945
|
+
contacts: selectedContacts,
|
|
3946
|
+
walletAddress: appliedWallet,
|
|
3947
|
+
lastInvoiceDate: selectedDatePreset,
|
|
3948
|
+
customDateRange: customDateFrom || customDateTo ? { from: customDateFrom, to: customDateTo } : void 0,
|
|
3949
|
+
lifetimeValue: ltvValue ? { operator: ltvOperator, value: ltvValue } : null,
|
|
3950
|
+
outstanding: outstandingValue ? { operator: outstandingOperator, value: outstandingValue } : null,
|
|
3951
|
+
...overrides
|
|
3952
|
+
};
|
|
3953
|
+
onFiltersChange?.(current);
|
|
3954
|
+
};
|
|
3955
|
+
const menuItems = [
|
|
3956
|
+
{ id: "contact", label: "Contact", icon: /* @__PURE__ */ jsx47(UserIcon, { className: "size-4" }) },
|
|
3957
|
+
{ id: "wallet", label: "Wallet address", icon: /* @__PURE__ */ jsx47(WalletIcon, { className: "size-4" }) },
|
|
3958
|
+
{ id: "date", label: "Last invoice date", icon: /* @__PURE__ */ jsx47(CalendarIcon, { className: "size-4" }) },
|
|
3959
|
+
{ id: "ltv", label: "Lifetime value", icon: /* @__PURE__ */ jsx47(TrendingUpIcon, { className: "size-4" }) },
|
|
3960
|
+
{ id: "outstanding", label: "Outstanding", icon: /* @__PURE__ */ jsx47(CircleDollarSignIcon, { className: "size-4" }) }
|
|
3961
|
+
];
|
|
3962
|
+
const activeIdx = menuItems.findIndex((item) => item.id === activeMenu);
|
|
3963
|
+
return /* @__PURE__ */ jsx47("div", { className: cn("inline-block", className), children: /* @__PURE__ */ jsxs36(Popover, { open: isOpen, onOpenChange: setIsOpen, children: [
|
|
3964
|
+
/* @__PURE__ */ jsx47(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx47(
|
|
3965
|
+
Button,
|
|
3966
|
+
{
|
|
3967
|
+
variant: "outline",
|
|
3968
|
+
size: "sm",
|
|
3969
|
+
shape: "pill",
|
|
3970
|
+
className: "border-dashed font-medium text-muted-foreground hover:text-foreground",
|
|
3971
|
+
iconLeading: /* @__PURE__ */ jsx47(ListFilterIcon, { className: "size-4" }),
|
|
3972
|
+
children: "Filter"
|
|
3973
|
+
}
|
|
3974
|
+
) }),
|
|
3975
|
+
/* @__PURE__ */ jsx47(
|
|
3976
|
+
PopoverContent,
|
|
3977
|
+
{
|
|
3978
|
+
variant: "list",
|
|
3979
|
+
align: "start",
|
|
3980
|
+
className: "overflow-visible border-none bg-transparent p-0 shadow-none max-w-[calc(100vw-32px)] md:max-w-none",
|
|
3981
|
+
children: /* @__PURE__ */ jsxs36("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: [
|
|
3982
|
+
/* @__PURE__ */ jsx47("div", { className: "w-full md:w-56 rounded-xl border border-border bg-popover p-1.5 shadow-lg", children: menuItems.map((item) => {
|
|
3983
|
+
const isActive = activeMenu === item.id;
|
|
3984
|
+
return /* @__PURE__ */ jsxs36(
|
|
3985
|
+
"button",
|
|
3986
|
+
{
|
|
3987
|
+
type: "button",
|
|
3988
|
+
className: cn(
|
|
3989
|
+
"flex w-full items-center justify-between rounded-lg px-3 py-2 text-sm text-left transition-colors outline-none",
|
|
3990
|
+
isActive ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted/50 hover:text-foreground"
|
|
3991
|
+
),
|
|
3992
|
+
onMouseEnter: () => !isMobile && setActiveMenu(item.id),
|
|
3993
|
+
onClick: () => setActiveMenu(item.id),
|
|
3994
|
+
children: [
|
|
3995
|
+
/* @__PURE__ */ jsxs36("span", { className: "flex items-center gap-2", children: [
|
|
3996
|
+
item.icon,
|
|
3997
|
+
/* @__PURE__ */ jsx47("span", { children: item.label })
|
|
3998
|
+
] }),
|
|
3999
|
+
/* @__PURE__ */ jsx47(ChevronRightIcon, { className: "size-4 text-muted-foreground/50" })
|
|
4000
|
+
]
|
|
4001
|
+
},
|
|
4002
|
+
item.id
|
|
4003
|
+
);
|
|
4004
|
+
}) }),
|
|
4005
|
+
activeMenu && /* @__PURE__ */ jsxs36(
|
|
4006
|
+
"div",
|
|
4007
|
+
{
|
|
4008
|
+
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",
|
|
4009
|
+
style: isMobile ? {} : { top: `${activeIdx * 36 + 6}px` },
|
|
4010
|
+
children: [
|
|
4011
|
+
activeMenu === "contact" && /* @__PURE__ */ jsxs36("div", { className: "flex flex-col gap-2.5", children: [
|
|
4012
|
+
/* @__PURE__ */ jsxs36("div", { className: "relative flex items-center", children: [
|
|
4013
|
+
/* @__PURE__ */ jsx47(SearchIcon2, { className: "absolute left-2.5 size-4 text-muted-foreground/60" }),
|
|
4014
|
+
/* @__PURE__ */ jsx47(
|
|
4015
|
+
"input",
|
|
4016
|
+
{
|
|
4017
|
+
type: "text",
|
|
4018
|
+
placeholder: "Search by name or email...",
|
|
4019
|
+
value: contactSearch,
|
|
4020
|
+
onChange: (e) => setContactSearch(e.target.value),
|
|
4021
|
+
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"
|
|
4022
|
+
}
|
|
4023
|
+
)
|
|
4024
|
+
] }),
|
|
4025
|
+
/* @__PURE__ */ jsx47("div", { className: "max-h-48 overflow-y-auto flex flex-col gap-1 pr-1", children: filteredContacts.length === 0 ? /* @__PURE__ */ jsx47("p", { className: "py-4 text-center text-xs text-muted-foreground", children: "No contacts found" }) : filteredContacts.map((contact) => {
|
|
4026
|
+
const isChecked = selectedContacts.includes(contact.name);
|
|
4027
|
+
return /* @__PURE__ */ jsxs36(
|
|
4028
|
+
"label",
|
|
4029
|
+
{
|
|
4030
|
+
className: "flex cursor-pointer items-center gap-2.5 rounded-lg px-2 py-1.5 hover:bg-muted/50 transition-colors",
|
|
4031
|
+
children: [
|
|
4032
|
+
/* @__PURE__ */ jsx47(
|
|
4033
|
+
Checkbox,
|
|
4034
|
+
{
|
|
4035
|
+
checked: isChecked,
|
|
4036
|
+
onCheckedChange: () => handleContactToggle(contact.name)
|
|
4037
|
+
}
|
|
4038
|
+
),
|
|
4039
|
+
/* @__PURE__ */ jsx47(Avatar, { variant: "secondary", children: /* @__PURE__ */ jsx47(AvatarFallback, { children: contact.initials }) }),
|
|
4040
|
+
/* @__PURE__ */ jsx47("span", { className: "text-sm font-medium text-foreground", children: contact.name })
|
|
4041
|
+
]
|
|
4042
|
+
},
|
|
4043
|
+
contact.id
|
|
4044
|
+
);
|
|
4045
|
+
}) })
|
|
4046
|
+
] }),
|
|
4047
|
+
activeMenu === "wallet" && /* @__PURE__ */ jsxs36("div", { className: "flex flex-col gap-2.5", children: [
|
|
4048
|
+
/* @__PURE__ */ jsx47("div", { className: "relative flex items-center", children: /* @__PURE__ */ jsx47(
|
|
4049
|
+
"input",
|
|
4050
|
+
{
|
|
4051
|
+
type: "text",
|
|
4052
|
+
placeholder: "Search by wallet...",
|
|
4053
|
+
value: walletInput,
|
|
4054
|
+
onChange: (e) => setWalletInput(e.target.value),
|
|
4055
|
+
className: "w-full rounded-lg border border-border bg-background px-3 py-1.5 text-sm outline-none placeholder:text-muted-foreground/60"
|
|
4056
|
+
}
|
|
4057
|
+
) }),
|
|
4058
|
+
/* @__PURE__ */ jsxs36("div", { className: "flex items-center justify-end gap-2 pt-1 border-t border-border/40", children: [
|
|
4059
|
+
/* @__PURE__ */ jsx47(
|
|
4060
|
+
Button,
|
|
4061
|
+
{
|
|
4062
|
+
variant: "ghost",
|
|
4063
|
+
size: "sm",
|
|
4064
|
+
onClick: handleWalletClear,
|
|
4065
|
+
className: "text-muted-foreground hover:text-foreground h-8 px-3",
|
|
4066
|
+
children: "Clear"
|
|
4067
|
+
}
|
|
4068
|
+
),
|
|
4069
|
+
/* @__PURE__ */ jsx47(
|
|
4070
|
+
Button,
|
|
4071
|
+
{
|
|
4072
|
+
color: "primary",
|
|
4073
|
+
size: "sm",
|
|
4074
|
+
onClick: handleWalletApply,
|
|
4075
|
+
className: "h-8 px-3",
|
|
4076
|
+
children: "Apply"
|
|
4077
|
+
}
|
|
4078
|
+
)
|
|
4079
|
+
] })
|
|
4080
|
+
] }),
|
|
4081
|
+
activeMenu === "date" && /* @__PURE__ */ jsxs36("div", { className: "flex flex-col gap-1", children: [
|
|
4082
|
+
presets.map((preset) => {
|
|
4083
|
+
const isSelected = selectedDatePreset === preset.id;
|
|
4084
|
+
return /* @__PURE__ */ jsxs36(
|
|
4085
|
+
"button",
|
|
4086
|
+
{
|
|
4087
|
+
type: "button",
|
|
4088
|
+
onClick: () => handleDatePresetSelect(preset.id),
|
|
4089
|
+
className: cn(
|
|
4090
|
+
"flex w-full items-center justify-between rounded-lg px-2.5 py-1.5 text-sm text-left transition-colors outline-none",
|
|
4091
|
+
isSelected ? "bg-muted text-foreground" : "text-muted-foreground hover:bg-muted/50 hover:text-foreground"
|
|
4092
|
+
),
|
|
4093
|
+
children: [
|
|
4094
|
+
/* @__PURE__ */ jsx47("span", { children: preset.label }),
|
|
4095
|
+
preset.date && /* @__PURE__ */ jsx47("span", { className: "text-xs text-muted-foreground/70", children: preset.date })
|
|
4096
|
+
]
|
|
4097
|
+
},
|
|
4098
|
+
preset.id
|
|
4099
|
+
);
|
|
4100
|
+
}),
|
|
4101
|
+
selectedDatePreset === "custom" && /* @__PURE__ */ jsxs36("div", { className: "flex flex-col gap-2 mt-2 pt-2 border-t border-border/40", children: [
|
|
4102
|
+
/* @__PURE__ */ jsxs36("div", { className: "flex items-center gap-2", children: [
|
|
4103
|
+
/* @__PURE__ */ jsx47(
|
|
4104
|
+
"input",
|
|
4105
|
+
{
|
|
4106
|
+
type: "date",
|
|
4107
|
+
value: customDateFrom,
|
|
4108
|
+
onChange: (e) => setCustomDateFrom(e.target.value),
|
|
4109
|
+
className: "w-full rounded-lg border border-border bg-background px-2 py-1 text-xs outline-none"
|
|
4110
|
+
}
|
|
4111
|
+
),
|
|
4112
|
+
/* @__PURE__ */ jsx47("span", { className: "text-xs text-muted-foreground", children: "to" }),
|
|
4113
|
+
/* @__PURE__ */ jsx47(
|
|
4114
|
+
"input",
|
|
4115
|
+
{
|
|
4116
|
+
type: "date",
|
|
4117
|
+
value: customDateTo,
|
|
4118
|
+
onChange: (e) => setCustomDateTo(e.target.value),
|
|
4119
|
+
className: "w-full rounded-lg border border-border bg-background px-2 py-1 text-xs outline-none"
|
|
4120
|
+
}
|
|
4121
|
+
)
|
|
4122
|
+
] }),
|
|
4123
|
+
/* @__PURE__ */ jsx47("div", { className: "flex justify-end gap-2", children: /* @__PURE__ */ jsx47(
|
|
4124
|
+
Button,
|
|
4125
|
+
{
|
|
4126
|
+
color: "primary",
|
|
4127
|
+
size: "sm",
|
|
4128
|
+
onClick: handleCustomDateApply,
|
|
4129
|
+
className: "h-7 text-xs px-2.5",
|
|
4130
|
+
children: "Apply"
|
|
4131
|
+
}
|
|
4132
|
+
) })
|
|
4133
|
+
] })
|
|
4134
|
+
] }),
|
|
4135
|
+
activeMenu === "ltv" && /* @__PURE__ */ jsxs36("div", { className: "flex flex-col gap-2.5", children: [
|
|
4136
|
+
/* @__PURE__ */ jsxs36("div", { className: "flex items-center gap-2", children: [
|
|
4137
|
+
/* @__PURE__ */ jsxs36("div", { className: "relative shrink-0", children: [
|
|
4138
|
+
/* @__PURE__ */ jsxs36(
|
|
4139
|
+
"button",
|
|
4140
|
+
{
|
|
4141
|
+
type: "button",
|
|
4142
|
+
onClick: () => setLtvOperatorOpen(!isLtvOperatorOpen),
|
|
4143
|
+
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",
|
|
4144
|
+
children: [
|
|
4145
|
+
/* @__PURE__ */ jsx47("span", { children: OPERATORS.find((op) => op.id === ltvOperator)?.label.replace("...", "") }),
|
|
4146
|
+
/* @__PURE__ */ jsx47(ChevronDownIcon2, { className: "size-3" })
|
|
4147
|
+
]
|
|
4148
|
+
}
|
|
4149
|
+
),
|
|
4150
|
+
isLtvOperatorOpen && /* @__PURE__ */ jsx47("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__ */ jsx47(
|
|
4151
|
+
"button",
|
|
4152
|
+
{
|
|
4153
|
+
type: "button",
|
|
4154
|
+
onClick: () => {
|
|
4155
|
+
setLtvOperator(op.id);
|
|
4156
|
+
setLtvOperatorOpen(false);
|
|
4157
|
+
},
|
|
4158
|
+
className: "w-full rounded-md px-2 py-1 text-left text-xs text-foreground hover:bg-muted outline-none",
|
|
4159
|
+
children: op.label
|
|
4160
|
+
},
|
|
4161
|
+
op.id
|
|
4162
|
+
)) })
|
|
4163
|
+
] }),
|
|
4164
|
+
/* @__PURE__ */ jsx47(
|
|
4165
|
+
"input",
|
|
4166
|
+
{
|
|
4167
|
+
type: "text",
|
|
4168
|
+
placeholder: "0.00",
|
|
4169
|
+
value: ltvValue,
|
|
4170
|
+
onChange: (e) => setLtvValue(e.target.value),
|
|
4171
|
+
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"
|
|
4172
|
+
}
|
|
4173
|
+
)
|
|
4174
|
+
] }),
|
|
4175
|
+
/* @__PURE__ */ jsxs36("div", { className: "flex items-center justify-end gap-2 pt-1 border-t border-border/40", children: [
|
|
4176
|
+
/* @__PURE__ */ jsx47(
|
|
4177
|
+
Button,
|
|
4178
|
+
{
|
|
4179
|
+
variant: "ghost",
|
|
4180
|
+
size: "sm",
|
|
4181
|
+
onClick: handleLtvClear,
|
|
4182
|
+
className: "text-muted-foreground hover:text-foreground h-8 px-3",
|
|
4183
|
+
children: "Clear"
|
|
4184
|
+
}
|
|
4185
|
+
),
|
|
4186
|
+
/* @__PURE__ */ jsx47(
|
|
4187
|
+
Button,
|
|
4188
|
+
{
|
|
4189
|
+
color: "primary",
|
|
4190
|
+
size: "sm",
|
|
4191
|
+
onClick: handleLtvApply,
|
|
4192
|
+
className: "h-8 px-3",
|
|
4193
|
+
children: "Apply"
|
|
4194
|
+
}
|
|
4195
|
+
)
|
|
4196
|
+
] })
|
|
4197
|
+
] }),
|
|
4198
|
+
activeMenu === "outstanding" && /* @__PURE__ */ jsxs36("div", { className: "flex flex-col gap-2.5", children: [
|
|
4199
|
+
/* @__PURE__ */ jsxs36("div", { className: "flex items-center gap-2", children: [
|
|
4200
|
+
/* @__PURE__ */ jsxs36("div", { className: "relative shrink-0", children: [
|
|
4201
|
+
/* @__PURE__ */ jsxs36(
|
|
4202
|
+
"button",
|
|
4203
|
+
{
|
|
4204
|
+
type: "button",
|
|
4205
|
+
onClick: () => setOutstandingOperatorOpen(!isOutstandingOperatorOpen),
|
|
4206
|
+
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",
|
|
4207
|
+
children: [
|
|
4208
|
+
/* @__PURE__ */ jsx47("span", { children: OPERATORS.find((op) => op.id === outstandingOperator)?.label.replace("...", "") }),
|
|
4209
|
+
/* @__PURE__ */ jsx47(ChevronDownIcon2, { className: "size-3" })
|
|
4210
|
+
]
|
|
4211
|
+
}
|
|
4212
|
+
),
|
|
4213
|
+
isOutstandingOperatorOpen && /* @__PURE__ */ jsx47("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__ */ jsx47(
|
|
4214
|
+
"button",
|
|
4215
|
+
{
|
|
4216
|
+
type: "button",
|
|
4217
|
+
onClick: () => {
|
|
4218
|
+
setOutstandingOperator(op.id);
|
|
4219
|
+
setOutstandingOperatorOpen(false);
|
|
4220
|
+
},
|
|
4221
|
+
className: "w-full rounded-md px-2 py-1 text-left text-xs text-foreground hover:bg-muted outline-none",
|
|
4222
|
+
children: op.label
|
|
4223
|
+
},
|
|
4224
|
+
op.id
|
|
4225
|
+
)) })
|
|
4226
|
+
] }),
|
|
4227
|
+
/* @__PURE__ */ jsx47(
|
|
4228
|
+
"input",
|
|
4229
|
+
{
|
|
4230
|
+
type: "text",
|
|
4231
|
+
placeholder: "0.00",
|
|
4232
|
+
value: outstandingValue,
|
|
4233
|
+
onChange: (e) => setOutstandingValue(e.target.value),
|
|
4234
|
+
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"
|
|
4235
|
+
}
|
|
4236
|
+
)
|
|
4237
|
+
] }),
|
|
4238
|
+
/* @__PURE__ */ jsxs36("div", { className: "flex items-center justify-end gap-2 pt-1 border-t border-border/40", children: [
|
|
4239
|
+
/* @__PURE__ */ jsx47(
|
|
4240
|
+
Button,
|
|
4241
|
+
{
|
|
4242
|
+
variant: "ghost",
|
|
4243
|
+
size: "sm",
|
|
4244
|
+
onClick: handleOutstandingClear,
|
|
4245
|
+
className: "text-muted-foreground hover:text-foreground h-8 px-3",
|
|
4246
|
+
children: "Clear"
|
|
4247
|
+
}
|
|
4248
|
+
),
|
|
4249
|
+
/* @__PURE__ */ jsx47(
|
|
4250
|
+
Button,
|
|
4251
|
+
{
|
|
4252
|
+
color: "primary",
|
|
4253
|
+
size: "sm",
|
|
4254
|
+
onClick: handleOutstandingApply,
|
|
4255
|
+
className: "h-8 px-3",
|
|
4256
|
+
children: "Apply"
|
|
4257
|
+
}
|
|
4258
|
+
)
|
|
4259
|
+
] })
|
|
4260
|
+
] })
|
|
4261
|
+
]
|
|
4262
|
+
}
|
|
4263
|
+
)
|
|
4264
|
+
] })
|
|
4265
|
+
}
|
|
4266
|
+
)
|
|
4267
|
+
] }) });
|
|
4268
|
+
}
|
|
4269
|
+
|
|
3148
4270
|
// src/app/data/DataTable.tsx
|
|
3149
|
-
import { useEffect as
|
|
4271
|
+
import { useEffect as useEffect4, useMemo as useMemo3, useState as useState5 } from "react";
|
|
3150
4272
|
import {
|
|
3151
4273
|
ArrowDownIcon,
|
|
3152
4274
|
ArrowUpDownIcon,
|
|
3153
4275
|
ArrowUpIcon,
|
|
3154
4276
|
ChevronLeftIcon,
|
|
3155
|
-
ChevronRightIcon
|
|
4277
|
+
ChevronRightIcon as ChevronRightIcon2
|
|
3156
4278
|
} from "lucide-react";
|
|
3157
|
-
import { jsx as
|
|
3158
|
-
var shellClass2 = "
|
|
3159
|
-
var tableClass = "w-full border-
|
|
3160
|
-
var headRowClass = "
|
|
3161
|
-
var headCellClass = "border-b border-border
|
|
3162
|
-
var bodyCellClass = "border-b border-border/40 bg-transparent px-4 py-
|
|
3163
|
-
var rowClass = "bg-transparent transition-colors hover:bg-muted/
|
|
3164
|
-
var footCellClass = "border-t border-border/
|
|
4279
|
+
import { jsx as jsx48, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
4280
|
+
var shellClass2 = "w-full";
|
|
4281
|
+
var tableClass = "w-full border-separate border-spacing-0 bg-transparent text-sm";
|
|
4282
|
+
var headRowClass = "";
|
|
4283
|
+
var headCellClass = "bg-gradient-to-b from-white to-[#F9FAFB] dark:from-[#1F242F] dark:to-[#10121C] border-t border-b border-border px-4 py-2.5 text-left text-xs font-medium text-muted-foreground/90 first:rounded-l-lg first:border-l last:rounded-r-lg last:border-r shadow-skeuomorphic-bordered";
|
|
4284
|
+
var bodyCellClass = "border-b border-border/40 bg-transparent px-4 py-4 text-foreground";
|
|
4285
|
+
var rowClass = "bg-transparent transition-colors hover:bg-muted/20 data-[clickable=true]:cursor-pointer data-[selected=true]:bg-primary/[0.04]";
|
|
4286
|
+
var footCellClass = "border-t border-border/40 bg-transparent px-4 py-3 text-xs text-muted-foreground";
|
|
3165
4287
|
var footInnerClass = "flex flex-wrap items-center gap-2";
|
|
3166
4288
|
var emptyCellClass = "bg-transparent px-4 py-10 text-center text-sm text-muted-foreground";
|
|
3167
|
-
var sortButtonClass = "group inline-flex min-w-0 items-center gap-1.5 rounded-md -mx-1 px-1 py-0.5 text-left font-
|
|
3168
|
-
var stickyHeadClass = "sticky top-0 z-[1] bg-
|
|
3169
|
-
var selectCellClass = "w-10 px-4 py-
|
|
3170
|
-
var pagerButtonClass = "inline-flex size-7 items-center justify-center rounded-md border border-border bg-
|
|
4289
|
+
var sortButtonClass = "group inline-flex min-w-0 items-center gap-1.5 rounded-md -mx-1 px-1 py-0.5 text-left font-medium text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/10";
|
|
4290
|
+
var stickyHeadClass = "sticky top-0 z-[1] bg-background/95 shadow-[0_1px_0_0_hsl(var(--border)/0.4)] backdrop-blur-sm";
|
|
4291
|
+
var selectCellClass = "w-10 px-4 py-4 align-middle";
|
|
4292
|
+
var pagerButtonClass = "inline-flex size-7 items-center justify-center rounded-md border border-border bg-background text-muted-foreground transition-colors hover:bg-muted hover:text-foreground disabled:pointer-events-none disabled:opacity-40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground/10";
|
|
3171
4293
|
var alignClass = {
|
|
3172
4294
|
left: "text-left",
|
|
3173
4295
|
center: "text-center",
|
|
@@ -3197,12 +4319,12 @@ function SortIndicator({
|
|
|
3197
4319
|
}) {
|
|
3198
4320
|
const iconClass = "size-3.5 shrink-0 opacity-60 group-hover:opacity-100";
|
|
3199
4321
|
if (!active) {
|
|
3200
|
-
return /* @__PURE__ */
|
|
4322
|
+
return /* @__PURE__ */ jsx48(ArrowUpDownIcon, { className: iconClass, "aria-hidden": true });
|
|
3201
4323
|
}
|
|
3202
4324
|
if (direction === "desc") {
|
|
3203
|
-
return /* @__PURE__ */
|
|
4325
|
+
return /* @__PURE__ */ jsx48(ArrowDownIcon, { className: iconClass, "aria-hidden": true });
|
|
3204
4326
|
}
|
|
3205
|
-
return /* @__PURE__ */
|
|
4327
|
+
return /* @__PURE__ */ jsx48(ArrowUpIcon, { className: iconClass, "aria-hidden": true });
|
|
3206
4328
|
}
|
|
3207
4329
|
function DataTable({
|
|
3208
4330
|
columns,
|
|
@@ -3234,7 +4356,7 @@ function DataTable({
|
|
|
3234
4356
|
defaultPageIndex = 0,
|
|
3235
4357
|
onPageChange
|
|
3236
4358
|
}) {
|
|
3237
|
-
const [uncontrolledSort, setUncontrolledSort] =
|
|
4359
|
+
const [uncontrolledSort, setUncontrolledSort] = useState5(
|
|
3238
4360
|
defaultSort
|
|
3239
4361
|
);
|
|
3240
4362
|
const isSortControlled = sortProp !== void 0;
|
|
@@ -3245,19 +4367,19 @@ function DataTable({
|
|
|
3245
4367
|
}
|
|
3246
4368
|
onSortChange?.(next);
|
|
3247
4369
|
};
|
|
3248
|
-
const [uncontrolledSelected, setUncontrolledSelected] =
|
|
4370
|
+
const [uncontrolledSelected, setUncontrolledSelected] = useState5(
|
|
3249
4371
|
defaultSelectedKeys ?? []
|
|
3250
4372
|
);
|
|
3251
4373
|
const isSelectionControlled = selectedKeysProp !== void 0;
|
|
3252
4374
|
const selectedKeys = isSelectionControlled ? selectedKeysProp : uncontrolledSelected;
|
|
3253
|
-
const selectedSet =
|
|
4375
|
+
const selectedSet = useMemo3(() => new Set(selectedKeys), [selectedKeys]);
|
|
3254
4376
|
const setSelected = (next) => {
|
|
3255
4377
|
if (!isSelectionControlled) {
|
|
3256
4378
|
setUncontrolledSelected(next);
|
|
3257
4379
|
}
|
|
3258
4380
|
onSelectionChange?.(next);
|
|
3259
4381
|
};
|
|
3260
|
-
const [uncontrolledPage, setUncontrolledPage] =
|
|
4382
|
+
const [uncontrolledPage, setUncontrolledPage] = useState5(defaultPageIndex);
|
|
3261
4383
|
const isPageControlled = pageIndexProp !== void 0;
|
|
3262
4384
|
const rawPageIndex = isPageControlled ? pageIndexProp : uncontrolledPage;
|
|
3263
4385
|
const setPage = (next) => {
|
|
@@ -3266,7 +4388,7 @@ function DataTable({
|
|
|
3266
4388
|
}
|
|
3267
4389
|
onPageChange?.(next);
|
|
3268
4390
|
};
|
|
3269
|
-
const sortedRows =
|
|
4391
|
+
const sortedRows = useMemo3(() => {
|
|
3270
4392
|
if (!sort) return rows;
|
|
3271
4393
|
const column = columns.find((col) => col.id === sort.columnId);
|
|
3272
4394
|
if (!column?.sortable) return rows;
|
|
@@ -3285,13 +4407,13 @@ function DataTable({
|
|
|
3285
4407
|
const paginated = typeof pageSize === "number" && pageSize > 0;
|
|
3286
4408
|
const pageCount = paginated ? Math.max(1, Math.ceil(sortedRows.length / pageSize)) : 1;
|
|
3287
4409
|
const pageIndex = Math.min(Math.max(0, rawPageIndex), pageCount - 1);
|
|
3288
|
-
|
|
4410
|
+
useEffect4(() => {
|
|
3289
4411
|
if (!paginated || isPageControlled) return;
|
|
3290
4412
|
if (uncontrolledPage > pageCount - 1) {
|
|
3291
4413
|
setUncontrolledPage(pageCount - 1);
|
|
3292
4414
|
}
|
|
3293
4415
|
}, [paginated, isPageControlled, uncontrolledPage, pageCount]);
|
|
3294
|
-
const visibleRows =
|
|
4416
|
+
const visibleRows = useMemo3(() => {
|
|
3295
4417
|
if (!paginated) return sortedRows;
|
|
3296
4418
|
const start = pageIndex * pageSize;
|
|
3297
4419
|
return sortedRows.slice(start, start + pageSize);
|
|
@@ -3300,7 +4422,7 @@ function DataTable({
|
|
|
3300
4422
|
const headPad = dense ? "px-3 py-2" : void 0;
|
|
3301
4423
|
const colSpan = columns.length + (selectable ? 1 : 0);
|
|
3302
4424
|
if (!loading && rows.length === 0 && emptyMode === "replace") {
|
|
3303
|
-
return /* @__PURE__ */
|
|
4425
|
+
return /* @__PURE__ */ jsx48(EmptyState, { title: emptyTitle, description: emptyDescription, className });
|
|
3304
4426
|
}
|
|
3305
4427
|
const allKeys = sortedRows.map(getRowKey);
|
|
3306
4428
|
const allSelected = allKeys.length > 0 && allKeys.every((k) => selectedSet.has(k));
|
|
@@ -3325,10 +4447,10 @@ function DataTable({
|
|
|
3325
4447
|
const hasPager = paginated && !loading && sortedRows.length > 0;
|
|
3326
4448
|
const hasFoot = (showRowCount || footer || hasPager) && (loading || sortedRows.length > 0);
|
|
3327
4449
|
const skeletonCount = loadingRows ?? pageSize ?? 5;
|
|
3328
|
-
return /* @__PURE__ */
|
|
3329
|
-
caption ? /* @__PURE__ */
|
|
3330
|
-
/* @__PURE__ */
|
|
3331
|
-
selectable ? /* @__PURE__ */
|
|
4450
|
+
return /* @__PURE__ */ jsx48("div", { className: cn("aui-app-data-table", shellClass2, className), children: /* @__PURE__ */ jsx48("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs37("table", { className: tableClass, children: [
|
|
4451
|
+
caption ? /* @__PURE__ */ jsx48("caption", { className: "sr-only", children: caption }) : null,
|
|
4452
|
+
/* @__PURE__ */ jsx48("thead", { className: cn(headRowClass, stickyHeader && stickyHeadClass), children: /* @__PURE__ */ jsxs37("tr", { children: [
|
|
4453
|
+
selectable ? /* @__PURE__ */ jsx48("th", { scope: "col", className: cn(selectCellClass, headPad), children: /* @__PURE__ */ jsx48(
|
|
3332
4454
|
Checkbox,
|
|
3333
4455
|
{
|
|
3334
4456
|
checked: headerCheckedState,
|
|
@@ -3340,19 +4462,19 @@ function DataTable({
|
|
|
3340
4462
|
columns.map((col) => {
|
|
3341
4463
|
const isSorted = sort?.columnId === col.id;
|
|
3342
4464
|
const ariaSort = col.sortable ? isSorted ? sort.direction === "asc" ? "ascending" : "descending" : "none" : void 0;
|
|
3343
|
-
const headerContent = col.sortable ? /* @__PURE__ */
|
|
4465
|
+
const headerContent = col.sortable ? /* @__PURE__ */ jsxs37(
|
|
3344
4466
|
"button",
|
|
3345
4467
|
{
|
|
3346
4468
|
type: "button",
|
|
3347
4469
|
className: sortButtonClass,
|
|
3348
4470
|
onClick: () => setSort(nextSort(sort, col.id)),
|
|
3349
4471
|
children: [
|
|
3350
|
-
/* @__PURE__ */
|
|
3351
|
-
/* @__PURE__ */
|
|
4472
|
+
/* @__PURE__ */ jsx48("span", { className: "truncate", children: col.header }),
|
|
4473
|
+
/* @__PURE__ */ jsx48(SortIndicator, { active: Boolean(isSorted), direction: sort?.direction })
|
|
3352
4474
|
]
|
|
3353
4475
|
}
|
|
3354
4476
|
) : col.header;
|
|
3355
|
-
return /* @__PURE__ */
|
|
4477
|
+
return /* @__PURE__ */ jsx48(
|
|
3356
4478
|
"th",
|
|
3357
4479
|
{
|
|
3358
4480
|
scope: "col",
|
|
@@ -3369,9 +4491,9 @@ function DataTable({
|
|
|
3369
4491
|
);
|
|
3370
4492
|
})
|
|
3371
4493
|
] }) }),
|
|
3372
|
-
/* @__PURE__ */
|
|
3373
|
-
selectable ? /* @__PURE__ */
|
|
3374
|
-
columns.map((col) => /* @__PURE__ */
|
|
4494
|
+
/* @__PURE__ */ jsx48("tbody", { className: cn(!hasFoot && "[&_tr:last-child_td]:border-b-0"), children: loading ? Array.from({ length: skeletonCount }).map((_, rowIdx) => /* @__PURE__ */ jsxs37("tr", { className: rowClass, "aria-hidden": true, children: [
|
|
4495
|
+
selectable ? /* @__PURE__ */ jsx48("td", { className: cn(selectCellClass, cellPad), children: /* @__PURE__ */ jsx48(Skeleton, { className: "size-4 rounded-[4px]" }) }) : null,
|
|
4496
|
+
columns.map((col) => /* @__PURE__ */ jsx48(
|
|
3375
4497
|
"td",
|
|
3376
4498
|
{
|
|
3377
4499
|
className: cn(
|
|
@@ -3380,17 +4502,17 @@ function DataTable({
|
|
|
3380
4502
|
col.align && alignClass[col.align],
|
|
3381
4503
|
col.className
|
|
3382
4504
|
),
|
|
3383
|
-
children: /* @__PURE__ */
|
|
4505
|
+
children: /* @__PURE__ */ jsx48(Skeleton, { className: "h-4 w-[60%]" })
|
|
3384
4506
|
},
|
|
3385
4507
|
col.id
|
|
3386
4508
|
))
|
|
3387
|
-
] }, `skeleton-${rowIdx}`)) : visibleRows.length === 0 ? /* @__PURE__ */
|
|
3388
|
-
/* @__PURE__ */
|
|
3389
|
-
emptyDescription ? /* @__PURE__ */
|
|
4509
|
+
] }, `skeleton-${rowIdx}`)) : visibleRows.length === 0 ? /* @__PURE__ */ jsx48("tr", { children: /* @__PURE__ */ jsx48("td", { colSpan, className: emptyCellClass, children: /* @__PURE__ */ jsxs37("div", { className: "flex flex-col items-center gap-1", children: [
|
|
4510
|
+
/* @__PURE__ */ jsx48("p", { className: "font-medium text-foreground", children: emptyTitle }),
|
|
4511
|
+
emptyDescription ? /* @__PURE__ */ jsx48("p", { className: "max-w-sm text-muted-foreground", children: emptyDescription }) : null
|
|
3390
4512
|
] }) }) }) : visibleRows.map((row) => {
|
|
3391
4513
|
const key = getRowKey(row);
|
|
3392
4514
|
const isSelected = selectedSet.has(key);
|
|
3393
|
-
return /* @__PURE__ */
|
|
4515
|
+
return /* @__PURE__ */ jsxs37(
|
|
3394
4516
|
"tr",
|
|
3395
4517
|
{
|
|
3396
4518
|
className: rowClass,
|
|
@@ -3406,12 +4528,12 @@ function DataTable({
|
|
|
3406
4528
|
tabIndex: onRowClick ? 0 : void 0,
|
|
3407
4529
|
role: onRowClick ? "button" : void 0,
|
|
3408
4530
|
children: [
|
|
3409
|
-
selectable ? /* @__PURE__ */
|
|
4531
|
+
selectable ? /* @__PURE__ */ jsx48(
|
|
3410
4532
|
"td",
|
|
3411
4533
|
{
|
|
3412
4534
|
className: cn(selectCellClass, cellPad),
|
|
3413
4535
|
onClick: (event) => event.stopPropagation(),
|
|
3414
|
-
children: /* @__PURE__ */
|
|
4536
|
+
children: /* @__PURE__ */ jsx48(
|
|
3415
4537
|
Checkbox,
|
|
3416
4538
|
{
|
|
3417
4539
|
checked: isSelected,
|
|
@@ -3421,7 +4543,7 @@ function DataTable({
|
|
|
3421
4543
|
)
|
|
3422
4544
|
}
|
|
3423
4545
|
) : null,
|
|
3424
|
-
columns.map((col) => /* @__PURE__ */
|
|
4546
|
+
columns.map((col) => /* @__PURE__ */ jsx48(
|
|
3425
4547
|
"td",
|
|
3426
4548
|
{
|
|
3427
4549
|
className: cn(
|
|
@@ -3431,7 +4553,7 @@ function DataTable({
|
|
|
3431
4553
|
col.align && alignClass[col.align],
|
|
3432
4554
|
col.className
|
|
3433
4555
|
),
|
|
3434
|
-
children: col.truncate ? /* @__PURE__ */
|
|
4556
|
+
children: col.truncate ? /* @__PURE__ */ jsx48("div", { className: "truncate", children: col.cell(row) }) : col.cell(row)
|
|
3435
4557
|
},
|
|
3436
4558
|
col.id
|
|
3437
4559
|
))
|
|
@@ -3440,7 +4562,7 @@ function DataTable({
|
|
|
3440
4562
|
key
|
|
3441
4563
|
);
|
|
3442
4564
|
}) }),
|
|
3443
|
-
hasFoot ? /* @__PURE__ */
|
|
4565
|
+
hasFoot ? /* @__PURE__ */ jsx48("tfoot", { children: /* @__PURE__ */ jsx48("tr", { children: /* @__PURE__ */ jsx48("td", { colSpan, className: footCellClass, children: /* @__PURE__ */ jsxs37(
|
|
3444
4566
|
"div",
|
|
3445
4567
|
{
|
|
3446
4568
|
className: cn(
|
|
@@ -3448,18 +4570,18 @@ function DataTable({
|
|
|
3448
4570
|
(showRowCount || footer || hasPager) && "justify-between"
|
|
3449
4571
|
),
|
|
3450
4572
|
children: [
|
|
3451
|
-
/* @__PURE__ */
|
|
3452
|
-
showRowCount ? /* @__PURE__ */
|
|
4573
|
+
/* @__PURE__ */ jsxs37("div", { className: footInnerClass, children: [
|
|
4574
|
+
showRowCount ? /* @__PURE__ */ jsxs37("span", { children: [
|
|
3453
4575
|
rowCountText,
|
|
3454
4576
|
selectable && selectedSet.size > 0 ? ` \xB7 ${selectedSet.size} selected` : null
|
|
3455
|
-
] }) : selectable && selectedSet.size > 0 ? /* @__PURE__ */
|
|
4577
|
+
] }) : selectable && selectedSet.size > 0 ? /* @__PURE__ */ jsxs37("span", { children: [
|
|
3456
4578
|
selectedSet.size,
|
|
3457
4579
|
" selected"
|
|
3458
4580
|
] }) : null,
|
|
3459
4581
|
footer
|
|
3460
4582
|
] }),
|
|
3461
|
-
hasPager ? /* @__PURE__ */
|
|
3462
|
-
/* @__PURE__ */
|
|
4583
|
+
hasPager ? /* @__PURE__ */ jsxs37("div", { className: "flex items-center gap-2", children: [
|
|
4584
|
+
/* @__PURE__ */ jsxs37("span", { className: "tabular-nums", children: [
|
|
3463
4585
|
pageIndex * pageSize + 1,
|
|
3464
4586
|
"\u2013",
|
|
3465
4587
|
Math.min(
|
|
@@ -3470,8 +4592,8 @@ function DataTable({
|
|
|
3470
4592
|
"of ",
|
|
3471
4593
|
sortedRows.length
|
|
3472
4594
|
] }),
|
|
3473
|
-
/* @__PURE__ */
|
|
3474
|
-
/* @__PURE__ */
|
|
4595
|
+
/* @__PURE__ */ jsxs37("div", { className: "flex items-center gap-1", children: [
|
|
4596
|
+
/* @__PURE__ */ jsx48(
|
|
3475
4597
|
"button",
|
|
3476
4598
|
{
|
|
3477
4599
|
type: "button",
|
|
@@ -3479,10 +4601,10 @@ function DataTable({
|
|
|
3479
4601
|
onClick: () => setPage(pageIndex - 1),
|
|
3480
4602
|
disabled: pageIndex <= 0,
|
|
3481
4603
|
"aria-label": "Previous page",
|
|
3482
|
-
children: /* @__PURE__ */
|
|
4604
|
+
children: /* @__PURE__ */ jsx48(ChevronLeftIcon, { className: "size-4", "aria-hidden": true })
|
|
3483
4605
|
}
|
|
3484
4606
|
),
|
|
3485
|
-
/* @__PURE__ */
|
|
4607
|
+
/* @__PURE__ */ jsx48(
|
|
3486
4608
|
"button",
|
|
3487
4609
|
{
|
|
3488
4610
|
type: "button",
|
|
@@ -3490,7 +4612,7 @@ function DataTable({
|
|
|
3490
4612
|
onClick: () => setPage(pageIndex + 1),
|
|
3491
4613
|
disabled: pageIndex >= pageCount - 1,
|
|
3492
4614
|
"aria-label": "Next page",
|
|
3493
|
-
children: /* @__PURE__ */
|
|
4615
|
+
children: /* @__PURE__ */ jsx48(ChevronRightIcon2, { className: "size-4", "aria-hidden": true })
|
|
3494
4616
|
}
|
|
3495
4617
|
)
|
|
3496
4618
|
] })
|
|
@@ -3502,8 +4624,8 @@ function DataTable({
|
|
|
3502
4624
|
}
|
|
3503
4625
|
|
|
3504
4626
|
// src/app/data/ChartPanel.tsx
|
|
3505
|
-
import { useId as
|
|
3506
|
-
import { jsx as
|
|
4627
|
+
import { useId as useId9 } from "react";
|
|
4628
|
+
import { jsx as jsx49, jsxs as jsxs38 } from "react/jsx-runtime";
|
|
3507
4629
|
var ChartPanel = ({
|
|
3508
4630
|
title,
|
|
3509
4631
|
description,
|
|
@@ -3518,17 +4640,17 @@ var ChartPanel = ({
|
|
|
3518
4640
|
const height = heightProp ?? APP_DENSITY_CHART_HEIGHT[density];
|
|
3519
4641
|
const metricChartPlotRegionClass = useAppDensityClass("metricChartPlotRegion");
|
|
3520
4642
|
const chartPanelBodyClass = useAppDensityClass("chartPanelBody");
|
|
3521
|
-
const titleId =
|
|
4643
|
+
const titleId = useId9();
|
|
3522
4644
|
const resolvedTitle = title ?? artifact?.title;
|
|
3523
4645
|
const hasHeader = Boolean(resolvedTitle || description || actions);
|
|
3524
|
-
const body = loading ? /* @__PURE__ */
|
|
3525
|
-
return /* @__PURE__ */
|
|
4646
|
+
const body = loading ? /* @__PURE__ */ jsx49(Skeleton, { className: "w-full rounded-lg", style: { height }, "aria-hidden": true }) : children ?? (artifact ? /* @__PURE__ */ jsx49(ChartArtifactView, { artifact, embedded: true, height }) : null);
|
|
4647
|
+
return /* @__PURE__ */ jsxs38(
|
|
3526
4648
|
"section",
|
|
3527
4649
|
{
|
|
3528
4650
|
className: cn(metricCardShellClass, "aui-app-chart-panel", className),
|
|
3529
4651
|
"aria-labelledby": resolvedTitle ? titleId : void 0,
|
|
3530
4652
|
children: [
|
|
3531
|
-
/* @__PURE__ */
|
|
4653
|
+
/* @__PURE__ */ jsx49(
|
|
3532
4654
|
MetricCardHeader,
|
|
3533
4655
|
{
|
|
3534
4656
|
title: resolvedTitle,
|
|
@@ -3537,14 +4659,14 @@ var ChartPanel = ({
|
|
|
3537
4659
|
actions
|
|
3538
4660
|
}
|
|
3539
4661
|
),
|
|
3540
|
-
/* @__PURE__ */
|
|
4662
|
+
/* @__PURE__ */ jsx49(
|
|
3541
4663
|
"div",
|
|
3542
4664
|
{
|
|
3543
4665
|
className: cn(
|
|
3544
4666
|
"relative min-h-0 w-full",
|
|
3545
4667
|
hasHeader ? metricChartPlotRegionClass : chartPanelBodyClass
|
|
3546
4668
|
),
|
|
3547
|
-
children: body ?? /* @__PURE__ */
|
|
4669
|
+
children: body ?? /* @__PURE__ */ jsx49(
|
|
3548
4670
|
"div",
|
|
3549
4671
|
{
|
|
3550
4672
|
className: "flex items-center justify-center text-sm font-normal text-muted-foreground",
|
|
@@ -3561,10 +4683,11 @@ var ChartPanel = ({
|
|
|
3561
4683
|
};
|
|
3562
4684
|
|
|
3563
4685
|
// src/app/data/MetricRow.tsx
|
|
3564
|
-
import { useId as
|
|
3565
|
-
import { jsx as
|
|
4686
|
+
import { useId as useId10, useState as useState6 } from "react";
|
|
4687
|
+
import { jsx as jsx50, jsxs as jsxs39 } from "react/jsx-runtime";
|
|
3566
4688
|
var MetricRow = ({
|
|
3567
4689
|
title,
|
|
4690
|
+
titleTag,
|
|
3568
4691
|
description,
|
|
3569
4692
|
actions,
|
|
3570
4693
|
metrics,
|
|
@@ -3576,9 +4699,9 @@ var MetricRow = ({
|
|
|
3576
4699
|
className
|
|
3577
4700
|
}) => {
|
|
3578
4701
|
const metricTileClass = useAppDensityClass("metricTile");
|
|
3579
|
-
const titleId =
|
|
4702
|
+
const titleId = useId10();
|
|
3580
4703
|
const selectable = onMetricChange != null || activeMetricId != null;
|
|
3581
|
-
const [internalId, setInternalId] =
|
|
4704
|
+
const [internalId, setInternalId] = useState6(
|
|
3582
4705
|
defaultActiveMetricId ?? metrics[0]?.id
|
|
3583
4706
|
);
|
|
3584
4707
|
const activeId = activeMetricId ?? internalId;
|
|
@@ -3586,22 +4709,24 @@ var MetricRow = ({
|
|
|
3586
4709
|
if (activeMetricId == null) setInternalId(id);
|
|
3587
4710
|
onMetricChange?.(id);
|
|
3588
4711
|
};
|
|
3589
|
-
|
|
4712
|
+
const hasHeader = Boolean(title || titleTag || description || actions);
|
|
4713
|
+
return /* @__PURE__ */ jsxs39(
|
|
3590
4714
|
"section",
|
|
3591
4715
|
{
|
|
3592
4716
|
className: cn(metricCardShellClass, className),
|
|
3593
4717
|
"aria-labelledby": title ? titleId : void 0,
|
|
3594
4718
|
children: [
|
|
3595
|
-
/* @__PURE__ */
|
|
4719
|
+
/* @__PURE__ */ jsx50(
|
|
3596
4720
|
MetricCardHeader,
|
|
3597
4721
|
{
|
|
3598
4722
|
title,
|
|
4723
|
+
titleTag,
|
|
3599
4724
|
titleId,
|
|
3600
4725
|
description,
|
|
3601
4726
|
actions
|
|
3602
4727
|
}
|
|
3603
4728
|
),
|
|
3604
|
-
/* @__PURE__ */
|
|
4729
|
+
/* @__PURE__ */ jsx50(
|
|
3605
4730
|
"div",
|
|
3606
4731
|
{
|
|
3607
4732
|
role: selectable ? "group" : void 0,
|
|
@@ -3610,20 +4735,20 @@ var MetricRow = ({
|
|
|
3610
4735
|
className: cn(
|
|
3611
4736
|
metricTilesRowClass,
|
|
3612
4737
|
metricTilesGridColsClass(loading ? metrics.length || 4 : metrics.length),
|
|
3613
|
-
|
|
4738
|
+
hasHeader && "mt-3.5 border-t border-border/40"
|
|
3614
4739
|
),
|
|
3615
|
-
children: loading ? Array.from({ length: metrics.length || 4 }).map((_, index) => /* @__PURE__ */
|
|
4740
|
+
children: loading ? Array.from({ length: metrics.length || 4 }).map((_, index) => /* @__PURE__ */ jsxs39(
|
|
3616
4741
|
"div",
|
|
3617
4742
|
{
|
|
3618
4743
|
className: cn("flex min-w-0 flex-1 flex-col gap-2", metricTileClass),
|
|
3619
4744
|
"aria-hidden": true,
|
|
3620
4745
|
children: [
|
|
3621
|
-
/* @__PURE__ */
|
|
3622
|
-
/* @__PURE__ */
|
|
4746
|
+
/* @__PURE__ */ jsx50(Skeleton, { className: "h-3 w-20" }),
|
|
4747
|
+
/* @__PURE__ */ jsx50(Skeleton, { className: "h-7 w-24" })
|
|
3623
4748
|
]
|
|
3624
4749
|
},
|
|
3625
4750
|
`skeleton-${index}`
|
|
3626
|
-
)) : metrics.map((m, index) => /* @__PURE__ */
|
|
4751
|
+
)) : metrics.map((m, index) => /* @__PURE__ */ jsx50(
|
|
3627
4752
|
MetricTile,
|
|
3628
4753
|
{
|
|
3629
4754
|
label: m.label,
|
|
@@ -3631,6 +4756,11 @@ var MetricRow = ({
|
|
|
3631
4756
|
unit: m.unit,
|
|
3632
4757
|
trend: m.trend,
|
|
3633
4758
|
trendTone: m.trendTone,
|
|
4759
|
+
trendVariant: m.trendVariant,
|
|
4760
|
+
activeTone: m.activeTone,
|
|
4761
|
+
sparklineData: m.sparklineData,
|
|
4762
|
+
sparklineConfig: m.sparklineConfig,
|
|
4763
|
+
sparkline: m.sparkline,
|
|
3634
4764
|
active: selectable && m.id === activeId,
|
|
3635
4765
|
showDivider: index < metrics.length - 1,
|
|
3636
4766
|
onSelect: selectable ? () => select(m.id) : void 0
|
|
@@ -3645,10 +4775,11 @@ var MetricRow = ({
|
|
|
3645
4775
|
};
|
|
3646
4776
|
|
|
3647
4777
|
// src/app/data/MetricChartCard.tsx
|
|
3648
|
-
import { useId as
|
|
3649
|
-
import { jsx as
|
|
4778
|
+
import { useId as useId11, useState as useState7 } from "react";
|
|
4779
|
+
import { jsx as jsx51, jsxs as jsxs40 } from "react/jsx-runtime";
|
|
3650
4780
|
var MetricChartCard = ({
|
|
3651
4781
|
title,
|
|
4782
|
+
titleTag,
|
|
3652
4783
|
description,
|
|
3653
4784
|
actions,
|
|
3654
4785
|
metrics,
|
|
@@ -3669,8 +4800,8 @@ var MetricChartCard = ({
|
|
|
3669
4800
|
const height = heightProp ?? APP_DENSITY_CHART_HEIGHT[density];
|
|
3670
4801
|
const metricChartRegionClass = useAppDensityClass("metricChartRegion");
|
|
3671
4802
|
const metricTileClass = useAppDensityClass("metricTile");
|
|
3672
|
-
const titleId =
|
|
3673
|
-
const [internalId, setInternalId] =
|
|
4803
|
+
const titleId = useId11();
|
|
4804
|
+
const [internalId, setInternalId] = useState7(
|
|
3674
4805
|
defaultActiveMetricId ?? metrics[0]?.id
|
|
3675
4806
|
);
|
|
3676
4807
|
const activeId = activeMetricId ?? internalId;
|
|
@@ -3679,24 +4810,25 @@ var MetricChartCard = ({
|
|
|
3679
4810
|
if (activeMetricId == null) setInternalId(id);
|
|
3680
4811
|
onMetricChange?.(id);
|
|
3681
4812
|
};
|
|
3682
|
-
const hasHeader = Boolean(title || description || actions);
|
|
4813
|
+
const hasHeader = Boolean(title || titleTag || description || actions);
|
|
3683
4814
|
const chartAriaLabel = typeof active?.label === "string" ? `${active.label} over time` : "Metric chart";
|
|
3684
|
-
return /* @__PURE__ */
|
|
4815
|
+
return /* @__PURE__ */ jsxs40(
|
|
3685
4816
|
"section",
|
|
3686
4817
|
{
|
|
3687
4818
|
className: cn(metricCardShellClass, className),
|
|
3688
4819
|
"aria-labelledby": title ? titleId : void 0,
|
|
3689
4820
|
children: [
|
|
3690
|
-
/* @__PURE__ */
|
|
4821
|
+
/* @__PURE__ */ jsx51(
|
|
3691
4822
|
MetricCardHeader,
|
|
3692
4823
|
{
|
|
3693
4824
|
title,
|
|
3694
|
-
|
|
4825
|
+
titleTag,
|
|
3695
4826
|
description,
|
|
3696
|
-
actions
|
|
4827
|
+
actions,
|
|
4828
|
+
titleId
|
|
3697
4829
|
}
|
|
3698
4830
|
),
|
|
3699
|
-
/* @__PURE__ */
|
|
4831
|
+
/* @__PURE__ */ jsx51(
|
|
3700
4832
|
"div",
|
|
3701
4833
|
{
|
|
3702
4834
|
role: "group",
|
|
@@ -3705,20 +4837,20 @@ var MetricChartCard = ({
|
|
|
3705
4837
|
className: cn(
|
|
3706
4838
|
metricTilesRowClass,
|
|
3707
4839
|
metricTilesGridColsClass(loading ? metrics.length || 4 : metrics.length),
|
|
3708
|
-
hasHeader && "mt-3"
|
|
4840
|
+
hasHeader && "mt-3.5 border-t border-border/40"
|
|
3709
4841
|
),
|
|
3710
|
-
children: loading ? Array.from({ length: metrics.length || 4 }).map((_, index) => /* @__PURE__ */
|
|
4842
|
+
children: loading ? Array.from({ length: metrics.length || 4 }).map((_, index) => /* @__PURE__ */ jsxs40(
|
|
3711
4843
|
"div",
|
|
3712
4844
|
{
|
|
3713
4845
|
className: cn("flex min-w-0 flex-1 flex-col gap-2", metricTileClass),
|
|
3714
4846
|
"aria-hidden": true,
|
|
3715
4847
|
children: [
|
|
3716
|
-
/* @__PURE__ */
|
|
3717
|
-
/* @__PURE__ */
|
|
4848
|
+
/* @__PURE__ */ jsx51(Skeleton, { className: "h-3 w-20" }),
|
|
4849
|
+
/* @__PURE__ */ jsx51(Skeleton, { className: "h-7 w-24" })
|
|
3718
4850
|
]
|
|
3719
4851
|
},
|
|
3720
4852
|
`skeleton-${index}`
|
|
3721
|
-
)) : metrics.map((m, index) => /* @__PURE__ */
|
|
4853
|
+
)) : metrics.map((m, index) => /* @__PURE__ */ jsx51(
|
|
3722
4854
|
MetricTile,
|
|
3723
4855
|
{
|
|
3724
4856
|
label: m.label,
|
|
@@ -3726,6 +4858,11 @@ var MetricChartCard = ({
|
|
|
3726
4858
|
unit: m.unit,
|
|
3727
4859
|
trend: m.trend,
|
|
3728
4860
|
trendTone: m.trendTone,
|
|
4861
|
+
trendVariant: m.trendVariant,
|
|
4862
|
+
activeTone: m.activeTone,
|
|
4863
|
+
sparklineData: m.sparklineData,
|
|
4864
|
+
sparklineConfig: m.sparklineConfig,
|
|
4865
|
+
sparkline: m.sparkline,
|
|
3729
4866
|
active: m.id === active?.id,
|
|
3730
4867
|
showDivider: index < metrics.length - 1,
|
|
3731
4868
|
onSelect: () => select(m.id)
|
|
@@ -3734,14 +4871,14 @@ var MetricChartCard = ({
|
|
|
3734
4871
|
))
|
|
3735
4872
|
}
|
|
3736
4873
|
),
|
|
3737
|
-
/* @__PURE__ */
|
|
4874
|
+
/* @__PURE__ */ jsx51("div", { className: metricChartRegionClass, "aria-live": "polite", "aria-atomic": "true", children: loading ? /* @__PURE__ */ jsx51(
|
|
3738
4875
|
Skeleton,
|
|
3739
4876
|
{
|
|
3740
4877
|
className: "w-full rounded-lg",
|
|
3741
4878
|
style: { height },
|
|
3742
4879
|
"aria-hidden": true
|
|
3743
4880
|
}
|
|
3744
|
-
) : active?.data && active.data.length > 0 ? /* @__PURE__ */
|
|
4881
|
+
) : active?.data && active.data.length > 0 ? /* @__PURE__ */ jsx51(
|
|
3745
4882
|
LineAreaChart,
|
|
3746
4883
|
{
|
|
3747
4884
|
data: active.data,
|
|
@@ -3761,7 +4898,7 @@ var MetricChartCard = ({
|
|
|
3761
4898
|
ariaLabel: chartAriaLabel
|
|
3762
4899
|
},
|
|
3763
4900
|
active.id
|
|
3764
|
-
) : /* @__PURE__ */
|
|
4901
|
+
) : /* @__PURE__ */ jsx51(
|
|
3765
4902
|
"div",
|
|
3766
4903
|
{
|
|
3767
4904
|
className: "flex w-full items-center justify-center text-sm font-normal text-muted-foreground",
|
|
@@ -3776,13 +4913,13 @@ var MetricChartCard = ({
|
|
|
3776
4913
|
};
|
|
3777
4914
|
|
|
3778
4915
|
// src/hooks/use-live-query.ts
|
|
3779
|
-
import { useCallback as useCallback2, useEffect as
|
|
4916
|
+
import { useCallback as useCallback2, useEffect as useEffect5, useRef, useState as useState8 } from "react";
|
|
3780
4917
|
function useInterval(callback, delayMs) {
|
|
3781
4918
|
const saved = useRef(callback);
|
|
3782
|
-
|
|
4919
|
+
useEffect5(() => {
|
|
3783
4920
|
saved.current = callback;
|
|
3784
4921
|
}, [callback]);
|
|
3785
|
-
|
|
4922
|
+
useEffect5(() => {
|
|
3786
4923
|
if (delayMs === null) return;
|
|
3787
4924
|
const id = setInterval(() => saved.current(), delayMs);
|
|
3788
4925
|
return () => clearInterval(id);
|
|
@@ -3795,19 +4932,19 @@ function useLiveQuery(fetcher, options = {}) {
|
|
|
3795
4932
|
immediate = true,
|
|
3796
4933
|
refetchOnFocus = true
|
|
3797
4934
|
} = options;
|
|
3798
|
-
const [data, setData] =
|
|
3799
|
-
const [error, setError] =
|
|
3800
|
-
const [loading, setLoading] =
|
|
3801
|
-
const [refreshing, setRefreshing] =
|
|
3802
|
-
const [lastUpdated, setLastUpdated] =
|
|
4935
|
+
const [data, setData] = useState8(void 0);
|
|
4936
|
+
const [error, setError] = useState8(void 0);
|
|
4937
|
+
const [loading, setLoading] = useState8(enabled);
|
|
4938
|
+
const [refreshing, setRefreshing] = useState8(false);
|
|
4939
|
+
const [lastUpdated, setLastUpdated] = useState8(null);
|
|
3803
4940
|
const fetcherRef = useRef(fetcher);
|
|
3804
|
-
|
|
4941
|
+
useEffect5(() => {
|
|
3805
4942
|
fetcherRef.current = fetcher;
|
|
3806
4943
|
}, [fetcher]);
|
|
3807
4944
|
const mounted = useRef(true);
|
|
3808
4945
|
const requestId = useRef(0);
|
|
3809
4946
|
const hasData = useRef(false);
|
|
3810
|
-
|
|
4947
|
+
useEffect5(() => {
|
|
3811
4948
|
mounted.current = true;
|
|
3812
4949
|
return () => {
|
|
3813
4950
|
mounted.current = false;
|
|
@@ -3839,11 +4976,11 @@ function useLiveQuery(fetcher, options = {}) {
|
|
|
3839
4976
|
if (!enabled) return;
|
|
3840
4977
|
run();
|
|
3841
4978
|
}, [enabled, run]);
|
|
3842
|
-
|
|
4979
|
+
useEffect5(() => {
|
|
3843
4980
|
if (!enabled) return;
|
|
3844
4981
|
if (immediate) run();
|
|
3845
4982
|
}, [enabled, immediate, run]);
|
|
3846
|
-
|
|
4983
|
+
useEffect5(() => {
|
|
3847
4984
|
if (!enabled || intervalMs === null) return;
|
|
3848
4985
|
const tick = () => {
|
|
3849
4986
|
if (refetchOnFocus && typeof document !== "undefined" && document.visibilityState === "hidden") {
|
|
@@ -3854,7 +4991,7 @@ function useLiveQuery(fetcher, options = {}) {
|
|
|
3854
4991
|
const handle = setInterval(tick, intervalMs);
|
|
3855
4992
|
return () => clearInterval(handle);
|
|
3856
4993
|
}, [enabled, intervalMs, refetchOnFocus, run]);
|
|
3857
|
-
|
|
4994
|
+
useEffect5(() => {
|
|
3858
4995
|
if (!enabled || !refetchOnFocus || typeof document === "undefined") return;
|
|
3859
4996
|
const onVisible = () => {
|
|
3860
4997
|
if (document.visibilityState === "visible") run();
|
|
@@ -3865,69 +5002,6 @@ function useLiveQuery(fetcher, options = {}) {
|
|
|
3865
5002
|
return { data, error, loading, refreshing, lastUpdated, refetch };
|
|
3866
5003
|
}
|
|
3867
5004
|
|
|
3868
|
-
// src/charts/sparkline.tsx
|
|
3869
|
-
import { useId as useId11 } from "react";
|
|
3870
|
-
import { Fragment as Fragment6, jsx as jsx48, jsxs as jsxs38 } from "react/jsx-runtime";
|
|
3871
|
-
var Sparkline = ({
|
|
3872
|
-
data,
|
|
3873
|
-
dataKey = "value",
|
|
3874
|
-
color = "var(--primary, #6366f1)",
|
|
3875
|
-
area = true,
|
|
3876
|
-
width = 96,
|
|
3877
|
-
height = 28,
|
|
3878
|
-
strokeWidth = 1.5,
|
|
3879
|
-
className,
|
|
3880
|
-
ariaLabel = "Trend"
|
|
3881
|
-
}) => {
|
|
3882
|
-
const uid = useId11();
|
|
3883
|
-
const values = data.map((d) => typeof d === "number" ? d : toNum(d[dataKey]));
|
|
3884
|
-
if (values.length === 0) {
|
|
3885
|
-
return /* @__PURE__ */ jsx48("span", { className: cn("inline-block", className), style: { width, height } });
|
|
3886
|
-
}
|
|
3887
|
-
const pad = strokeWidth + 1;
|
|
3888
|
-
const min = Math.min(...values);
|
|
3889
|
-
const max = Math.max(...values);
|
|
3890
|
-
const range = max - min || 1;
|
|
3891
|
-
const innerW = width - pad * 2;
|
|
3892
|
-
const innerH = height - pad * 2;
|
|
3893
|
-
const points = values.map((v, i) => ({
|
|
3894
|
-
x: pad + (values.length > 1 ? i / (values.length - 1) * innerW : innerW / 2),
|
|
3895
|
-
y: pad + innerH - (v - min) / range * innerH
|
|
3896
|
-
}));
|
|
3897
|
-
return /* @__PURE__ */ jsxs38(
|
|
3898
|
-
"svg",
|
|
3899
|
-
{
|
|
3900
|
-
width,
|
|
3901
|
-
height,
|
|
3902
|
-
viewBox: `0 0 ${width} ${height}`,
|
|
3903
|
-
className: cn("block", className),
|
|
3904
|
-
role: "img",
|
|
3905
|
-
"aria-label": ariaLabel,
|
|
3906
|
-
preserveAspectRatio: "none",
|
|
3907
|
-
children: [
|
|
3908
|
-
area && /* @__PURE__ */ jsxs38(Fragment6, { children: [
|
|
3909
|
-
/* @__PURE__ */ jsx48("defs", { children: /* @__PURE__ */ jsxs38("linearGradient", { id: `${uid}-spark`, x1: "0", x2: "0", y1: "0", y2: "1", children: [
|
|
3910
|
-
/* @__PURE__ */ jsx48("stop", { offset: "0%", style: { stopColor: color, stopOpacity: 0.25 } }),
|
|
3911
|
-
/* @__PURE__ */ jsx48("stop", { offset: "100%", style: { stopColor: color, stopOpacity: 0 } })
|
|
3912
|
-
] }) }),
|
|
3913
|
-
/* @__PURE__ */ jsx48("path", { d: monotoneAreaPath(points, height - pad), fill: `url(#${uid}-spark)` })
|
|
3914
|
-
] }),
|
|
3915
|
-
/* @__PURE__ */ jsx48(
|
|
3916
|
-
"path",
|
|
3917
|
-
{
|
|
3918
|
-
d: monotoneLinePath(points),
|
|
3919
|
-
fill: "none",
|
|
3920
|
-
stroke: color,
|
|
3921
|
-
strokeWidth,
|
|
3922
|
-
strokeLinecap: "round",
|
|
3923
|
-
strokeLinejoin: "round"
|
|
3924
|
-
}
|
|
3925
|
-
)
|
|
3926
|
-
]
|
|
3927
|
-
}
|
|
3928
|
-
);
|
|
3929
|
-
};
|
|
3930
|
-
|
|
3931
5005
|
export {
|
|
3932
5006
|
SEMANTIC_COLOR_TOKENS,
|
|
3933
5007
|
RESERVED_GRADIENT_TOKENS,
|
|
@@ -3964,16 +5038,17 @@ export {
|
|
|
3964
5038
|
AppDensityProvider,
|
|
3965
5039
|
useAppDensity,
|
|
3966
5040
|
useAppDensityClass,
|
|
5041
|
+
Sparkline,
|
|
3967
5042
|
MetricTile,
|
|
3968
5043
|
useAppShellChat,
|
|
3969
5044
|
useAppShellNav,
|
|
3970
5045
|
AppShell,
|
|
3971
|
-
AppShellTopbar,
|
|
3972
5046
|
AppShellChatTrigger,
|
|
3973
5047
|
AppShellSidebarTrigger,
|
|
3974
5048
|
PageHeader,
|
|
3975
5049
|
Page,
|
|
3976
5050
|
Section,
|
|
5051
|
+
Stack,
|
|
3977
5052
|
AppCopilotProvider,
|
|
3978
5053
|
useAppCopilotContext,
|
|
3979
5054
|
AppChatPanel,
|
|
@@ -3987,6 +5062,8 @@ export {
|
|
|
3987
5062
|
DescriptionList,
|
|
3988
5063
|
ExpandableSection,
|
|
3989
5064
|
ResourceCard,
|
|
5065
|
+
AlertCard,
|
|
5066
|
+
CatalogCard,
|
|
3990
5067
|
SettingsSectionHeader,
|
|
3991
5068
|
SettingsSection,
|
|
3992
5069
|
FieldRow,
|
|
@@ -4011,11 +5088,11 @@ export {
|
|
|
4011
5088
|
FormSection,
|
|
4012
5089
|
FilterBar,
|
|
4013
5090
|
FilterField,
|
|
5091
|
+
FilterDropdown,
|
|
4014
5092
|
DataTable,
|
|
4015
5093
|
ChartPanel,
|
|
4016
5094
|
MetricRow,
|
|
4017
5095
|
MetricChartCard,
|
|
4018
5096
|
useInterval,
|
|
4019
|
-
useLiveQuery
|
|
4020
|
-
Sparkline
|
|
5097
|
+
useLiveQuery
|
|
4021
5098
|
};
|