@timbal-ai/timbal-react 0.8.0 → 0.8.2
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 +34 -0
- package/README.md +61 -5
- package/dist/app.cjs +1907 -1129
- package/dist/app.d.cts +2 -2
- package/dist/app.d.ts +2 -2
- package/dist/app.esm.js +29 -5
- package/dist/{button-CIKzUrJI.d.cts → button-ClSgD6OF.d.cts} +1 -1
- package/dist/{button-CIKzUrJI.d.ts → button-ClSgD6OF.d.ts} +1 -1
- package/dist/{chart-artifact-CqqhdSR9.d.ts → chart-artifact-Bl67kre7.d.ts} +214 -1
- package/dist/{chart-artifact-C2m891nx.d.cts → chart-artifact-BzcvblDe.d.cts} +214 -1
- package/dist/chat.esm.js +3 -3
- package/dist/{chunk-VVTTLIGT.esm.js → chunk-5ZKLPWVN.esm.js} +1 -1
- package/dist/{chunk-ZEDE2TWQ.esm.js → chunk-6YVKCVEP.esm.js} +1138 -378
- package/dist/{chunk-ZG5NBHOS.esm.js → chunk-CFU3YDTV.esm.js} +2 -2
- package/dist/{chunk-YNDXBN6C.esm.js → chunk-OISVICYF.esm.js} +1 -1
- package/dist/{chunk-LSEUKTU5.esm.js → chunk-P4SN7M67.esm.js} +1 -1
- package/dist/{chunk-Z27GBSOT.esm.js → chunk-QIABF4KB.esm.js} +53 -51
- package/dist/{chunk-QKO67F4V.esm.js → chunk-QVAUCVQA.esm.js} +93 -93
- package/dist/{chunk-4AO3HCAR.esm.js → chunk-VWHHKAHN.esm.js} +5 -5
- package/dist/index.cjs +1191 -418
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.esm.js +32 -8
- package/dist/studio.cjs +3 -1
- package/dist/studio.esm.js +6 -6
- package/dist/ui.d.cts +1 -1
- package/dist/ui.d.ts +1 -1
- package/dist/ui.esm.js +3 -3
- package/package.json +1 -1
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SIDEBAR_INSET_PX_EXPANDED,
|
|
3
|
+
STORAGE_KEYS,
|
|
3
4
|
ShellInsetProvider,
|
|
4
5
|
studioChromeShellStyle,
|
|
5
6
|
studioSidebarWidthTransition
|
|
6
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-QIABF4KB.esm.js";
|
|
7
8
|
import {
|
|
8
9
|
ChartArtifactView,
|
|
9
10
|
LineAreaChart,
|
|
@@ -16,10 +17,10 @@ import {
|
|
|
16
17
|
studioSecondaryChromeClass,
|
|
17
18
|
studioTopbarPillHeightClass,
|
|
18
19
|
toNum
|
|
19
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-5ZKLPWVN.esm.js";
|
|
20
21
|
import {
|
|
21
22
|
PillSegmentedTabs
|
|
22
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-OISVICYF.esm.js";
|
|
23
24
|
import {
|
|
24
25
|
Button,
|
|
25
26
|
Dialog,
|
|
@@ -31,7 +32,7 @@ import {
|
|
|
31
32
|
TIMBAL_V2_SWITCH_TRACK_OFF,
|
|
32
33
|
TimbalV2Button,
|
|
33
34
|
cn
|
|
34
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-QVAUCVQA.esm.js";
|
|
35
36
|
|
|
36
37
|
// src/app/agent-instructions.ts
|
|
37
38
|
var APP_KIT_AGENT_INSTRUCTIONS = `
|
|
@@ -66,6 +67,8 @@ Presentational groups \u2014 import from the package root, not from these paths:
|
|
|
66
67
|
|
|
67
68
|
Also re-exported: \`Button\`, \`TimbalChat\`, \`ChartArtifactView\`, \`APP_KIT_AGENT_INSTRUCTIONS\`.
|
|
68
69
|
|
|
70
|
+
Theming helpers (import from the package root or \`/app\`): \`createTimbalTheme\`, \`themeToCss\`, \`applyTimbalTheme\`, \`TIMBAL_THEME_PRESETS\`, \`applyThemePreset\`, \`ThemePresetGallery\`, \`TimbalThemeStyle\`, \`THEME_AGENT_INSTRUCTIONS\`.
|
|
71
|
+
|
|
69
72
|
### Design guidelines (required)
|
|
70
73
|
|
|
71
74
|
| Area | Rule |
|
|
@@ -73,7 +76,7 @@ Also re-exported: \`Button\`, \`TimbalChat\`, \`ChartArtifactView\`, \`APP_KIT_A
|
|
|
73
76
|
| **Copilot** | Use \`AppCopilotProvider\` for page context (\`useAppCopilotContext\`). Copilot is a **floating overlay** via \`AppShell\` \`chat={<AppChatPanel />}\` \u2014 not a sidebar column that shrinks main content. |
|
|
74
77
|
| **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. |
|
|
75
78
|
| **Context** | Do not show raw JSON context in the panel header; keep context in \`AppCopilotProvider\` only. |
|
|
76
|
-
| **Theming** | Use semantic Tailwind tokens (\`bg-background\`, \`text-foreground\`, \`border-border\`, \`bg-elevated-from\`, etc.) from the host app's \`styles.css\`.
|
|
79
|
+
| **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\`). To offer styles, render \`ThemePresetGallery\`. See \`THEME_AGENT_INSTRUCTIONS\`. |
|
|
77
80
|
| **Layout chrome** | \`Page\` \u2192 \`Section\` for main content hierarchy. \`AppShellTopbar\` for global actions (auth, theme). |
|
|
78
81
|
| **Data** | Prefer \`DataTable\` with typed \`columns\` / \`rows\` / \`getRowKey\`; use \`ChartPanel\` with \`ChartArtifact\` for charts. |
|
|
79
82
|
| **Modals** | Use \`AppConfirmDialog\` for destructive/export confirmations. |
|
|
@@ -173,6 +176,7 @@ Studio chrome (\`StudioSidebar\`, \`ModeToggle\`, \u2026) lives in \`@timbal-ai/
|
|
|
173
176
|
| \`resource-gallery.tsx\` | \`ResourceCard\`, \`StatusDot\`, \`Sparkline\` |
|
|
174
177
|
| \`charts-panel.tsx\` | \`ChartPanel\`, \`ChartArtifact\` |
|
|
175
178
|
| \`copilot-overlay.tsx\` | \`AppShell\`, \`AppChatPanel\` |
|
|
179
|
+
| \`theme-presets.tsx\` | \`ThemePresetGallery\`, \`applyTimbalTheme\` |
|
|
176
180
|
|
|
177
181
|
### Typical compositions
|
|
178
182
|
|
|
@@ -218,6 +222,864 @@ import {
|
|
|
218
222
|
- For rich in-chat widgets, use **artifacts** (\`ARTIFACT_AGENT_INSTRUCTIONS\`) \u2014 app kit is for the **host application shell**.
|
|
219
223
|
`.trim();
|
|
220
224
|
|
|
225
|
+
// src/design/oklch.ts
|
|
226
|
+
var clamp = (n, min, max) => Math.min(max, Math.max(min, n));
|
|
227
|
+
var round = (n, digits) => {
|
|
228
|
+
const f = 10 ** digits;
|
|
229
|
+
return Math.round(n * f) / f;
|
|
230
|
+
};
|
|
231
|
+
function srgbToLinear(channel) {
|
|
232
|
+
const c = channel / 255;
|
|
233
|
+
return c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
|
|
234
|
+
}
|
|
235
|
+
function linearRgbToOklch(r, g, b, alpha) {
|
|
236
|
+
const l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b;
|
|
237
|
+
const m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b;
|
|
238
|
+
const s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b;
|
|
239
|
+
const l_ = Math.cbrt(l);
|
|
240
|
+
const m_ = Math.cbrt(m);
|
|
241
|
+
const s_ = Math.cbrt(s);
|
|
242
|
+
const labL = 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_;
|
|
243
|
+
const labA = 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_;
|
|
244
|
+
const labB = 0.0259040371 * l_ + 0.7827717662 * m_ - 0.808675766 * s_;
|
|
245
|
+
const c = Math.sqrt(labA * labA + labB * labB);
|
|
246
|
+
let h = Math.atan2(labB, labA) * 180 / Math.PI;
|
|
247
|
+
if (h < 0) h += 360;
|
|
248
|
+
return { l: labL, c, h, alpha };
|
|
249
|
+
}
|
|
250
|
+
function oklchToLinearRgb(color) {
|
|
251
|
+
const hRad = color.h * Math.PI / 180;
|
|
252
|
+
const labA = color.c * Math.cos(hRad);
|
|
253
|
+
const labB = color.c * Math.sin(hRad);
|
|
254
|
+
const l_ = color.l + 0.3963377774 * labA + 0.2158037573 * labB;
|
|
255
|
+
const m_ = color.l - 0.1055613458 * labA - 0.0638541728 * labB;
|
|
256
|
+
const s_ = color.l - 0.0894841775 * labA - 1.291485548 * labB;
|
|
257
|
+
const l = l_ ** 3;
|
|
258
|
+
const m = m_ ** 3;
|
|
259
|
+
const s = s_ ** 3;
|
|
260
|
+
return {
|
|
261
|
+
r: 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,
|
|
262
|
+
g: -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,
|
|
263
|
+
b: -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
function parseHex(value) {
|
|
267
|
+
let hex = value.trim().replace(/^#/, "");
|
|
268
|
+
if (![3, 4, 6, 8].includes(hex.length)) return null;
|
|
269
|
+
if (hex.length === 3 || hex.length === 4) {
|
|
270
|
+
hex = hex.split("").map((ch) => ch + ch).join("");
|
|
271
|
+
}
|
|
272
|
+
const int = Number.parseInt(hex, 16);
|
|
273
|
+
if (Number.isNaN(int)) return null;
|
|
274
|
+
const hasAlpha = hex.length === 8;
|
|
275
|
+
const r = int >>> (hasAlpha ? 24 : 16) & 255;
|
|
276
|
+
const g = int >>> (hasAlpha ? 16 : 8) & 255;
|
|
277
|
+
const b = int >>> (hasAlpha ? 8 : 0) & 255;
|
|
278
|
+
const alpha = hasAlpha ? (int & 255) / 255 : 1;
|
|
279
|
+
return linearRgbToOklch(
|
|
280
|
+
srgbToLinear(r),
|
|
281
|
+
srgbToLinear(g),
|
|
282
|
+
srgbToLinear(b),
|
|
283
|
+
alpha
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
function parseRgb(value) {
|
|
287
|
+
const match = value.match(
|
|
288
|
+
/rgba?\(\s*([0-9.]+)[\s,]+([0-9.]+)[\s,]+([0-9.]+)(?:[\s,/]+([0-9.%]+))?\s*\)/i
|
|
289
|
+
);
|
|
290
|
+
if (!match) return null;
|
|
291
|
+
const r = Number.parseFloat(match[1]);
|
|
292
|
+
const g = Number.parseFloat(match[2]);
|
|
293
|
+
const b = Number.parseFloat(match[3]);
|
|
294
|
+
let alpha = 1;
|
|
295
|
+
if (match[4]) {
|
|
296
|
+
alpha = match[4].includes("%") ? Number.parseFloat(match[4]) / 100 : Number.parseFloat(match[4]);
|
|
297
|
+
}
|
|
298
|
+
if (![r, g, b].every(Number.isFinite)) return null;
|
|
299
|
+
return linearRgbToOklch(
|
|
300
|
+
srgbToLinear(r),
|
|
301
|
+
srgbToLinear(g),
|
|
302
|
+
srgbToLinear(b),
|
|
303
|
+
Number.isFinite(alpha) ? alpha : 1
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
function parseOklch(value) {
|
|
307
|
+
const match = value.match(
|
|
308
|
+
/oklch\(\s*([0-9.]+%?)\s+([0-9.]+%?)\s+([0-9.]+)(?:deg)?(?:\s*\/\s*([0-9.%]+))?\s*\)/i
|
|
309
|
+
);
|
|
310
|
+
if (!match) return null;
|
|
311
|
+
const l = match[1].includes("%") ? Number.parseFloat(match[1]) / 100 : Number.parseFloat(match[1]);
|
|
312
|
+
const c = match[2].includes("%") ? Number.parseFloat(match[2]) / 100 * 0.4 : Number.parseFloat(match[2]);
|
|
313
|
+
const h = Number.parseFloat(match[3]);
|
|
314
|
+
let alpha = 1;
|
|
315
|
+
if (match[4]) {
|
|
316
|
+
alpha = match[4].includes("%") ? Number.parseFloat(match[4]) / 100 : Number.parseFloat(match[4]);
|
|
317
|
+
}
|
|
318
|
+
if (![l, c, h].every(Number.isFinite)) return null;
|
|
319
|
+
return { l, c, h, alpha: Number.isFinite(alpha) ? alpha : 1 };
|
|
320
|
+
}
|
|
321
|
+
function parseColor(value) {
|
|
322
|
+
const parsed = parseOklch(value) ?? parseHex(value) ?? parseRgb(value);
|
|
323
|
+
if (!parsed) {
|
|
324
|
+
throw new Error(
|
|
325
|
+
`[@timbal-ai/timbal-react] Could not parse color "${value}". Use a hex (#1E40AF), rgb()/rgba(), or oklch() string.`
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
return parsed;
|
|
329
|
+
}
|
|
330
|
+
function lighten(color, delta) {
|
|
331
|
+
return { ...color, l: clamp(color.l + delta, 0, 1) };
|
|
332
|
+
}
|
|
333
|
+
function scaleChroma(color, factor) {
|
|
334
|
+
return { ...color, c: clamp(color.c * factor, 0, 0.4) };
|
|
335
|
+
}
|
|
336
|
+
function withAlpha(color, alpha) {
|
|
337
|
+
return { ...color, alpha: clamp(alpha, 0, 1) };
|
|
338
|
+
}
|
|
339
|
+
function oklchToString(color) {
|
|
340
|
+
const l = round(clamp(color.l, 0, 1), 4);
|
|
341
|
+
const c = round(clamp(color.c, 0, 0.4), 4);
|
|
342
|
+
const h = round((color.h % 360 + 360) % 360, 2);
|
|
343
|
+
const a = clamp(color.alpha, 0, 1);
|
|
344
|
+
const base = `oklch(${l} ${c} ${h}`;
|
|
345
|
+
return a >= 1 ? `${base})` : `${base} / ${round(a, 3)})`;
|
|
346
|
+
}
|
|
347
|
+
function readableForeground(bg, options) {
|
|
348
|
+
const threshold = options?.threshold ?? 0.62;
|
|
349
|
+
const lightText = options?.light ?? "oklch(0.985 0 0)";
|
|
350
|
+
const darkText = options?.dark ?? "oklch(0.205 0 0)";
|
|
351
|
+
return bg.l >= threshold ? darkText : lightText;
|
|
352
|
+
}
|
|
353
|
+
function relativeLuminance(color) {
|
|
354
|
+
const { r, g, b } = oklchToLinearRgb(color);
|
|
355
|
+
const lr = clamp(r, 0, 1);
|
|
356
|
+
const lg = clamp(g, 0, 1);
|
|
357
|
+
const lb = clamp(b, 0, 1);
|
|
358
|
+
return 0.2126 * lr + 0.7152 * lg + 0.0722 * lb;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// src/design/theme.ts
|
|
362
|
+
var SHADOW_PRESETS = {
|
|
363
|
+
none: {
|
|
364
|
+
lightCard: "none",
|
|
365
|
+
lightElevated: "none",
|
|
366
|
+
darkCard: "none",
|
|
367
|
+
darkElevated: "none"
|
|
368
|
+
},
|
|
369
|
+
hairline: {
|
|
370
|
+
lightCard: "0 0 0 1px rgba(15, 23, 42, 0.06)",
|
|
371
|
+
lightElevated: "0 1px 2px rgba(15, 23, 42, 0.06)",
|
|
372
|
+
darkCard: "0 0 0 1px rgba(255, 255, 255, 0.06)",
|
|
373
|
+
darkElevated: "0 2px 8px rgba(0, 0, 0, 0.4)"
|
|
374
|
+
},
|
|
375
|
+
soft: {
|
|
376
|
+
lightCard: "0 1px 2px rgba(15, 23, 42, 0.04)",
|
|
377
|
+
lightElevated: "0 8px 30px rgba(15, 23, 42, 0.07)",
|
|
378
|
+
darkCard: "0 1px 2px rgba(0, 0, 0, 0.3)",
|
|
379
|
+
darkElevated: "0 10px 34px rgba(0, 0, 0, 0.45)"
|
|
380
|
+
},
|
|
381
|
+
medium: {
|
|
382
|
+
lightCard: "0 1px 2px -0.5px rgba(0, 0, 0, 0.05)",
|
|
383
|
+
lightElevated: "0 4px 24px rgba(0, 0, 0, 0.06)",
|
|
384
|
+
darkCard: "0 1px 3px rgba(0, 0, 0, 0.22)",
|
|
385
|
+
darkElevated: "0 4px 24px rgba(0, 0, 0, 0.35)"
|
|
386
|
+
},
|
|
387
|
+
strong: {
|
|
388
|
+
lightCard: "0 2px 6px rgba(15, 23, 42, 0.10)",
|
|
389
|
+
lightElevated: "0 16px 48px rgba(15, 23, 42, 0.16)",
|
|
390
|
+
darkCard: "0 2px 6px rgba(0, 0, 0, 0.4)",
|
|
391
|
+
darkElevated: "0 18px 50px rgba(0, 0, 0, 0.6)"
|
|
392
|
+
}
|
|
393
|
+
};
|
|
394
|
+
function primaryForMode(brand, mode) {
|
|
395
|
+
if (mode === "light") {
|
|
396
|
+
return { ...brand, l: Math.min(Math.max(brand.l, 0.42), 0.68) };
|
|
397
|
+
}
|
|
398
|
+
const lightened = lighten(brand, 0.06);
|
|
399
|
+
return {
|
|
400
|
+
...lightened,
|
|
401
|
+
l: Math.min(Math.max(lightened.l, 0.5), 0.78),
|
|
402
|
+
c: Math.min(brand.c, 0.22)
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
function brandGradient(primary) {
|
|
406
|
+
return {
|
|
407
|
+
from: lighten(primary, 0.03),
|
|
408
|
+
to: lighten(primary, -0.02),
|
|
409
|
+
hoverFrom: lighten(primary, 0.06),
|
|
410
|
+
hoverTo: lighten(primary, 0.01),
|
|
411
|
+
activeFrom: lighten(primary, -0.02),
|
|
412
|
+
activeTo: lighten(primary, -0.06)
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
function neutralTints(brand) {
|
|
416
|
+
return {
|
|
417
|
+
lightHue: brand.h,
|
|
418
|
+
darkHue: brand.h,
|
|
419
|
+
lightChroma: 6e-3,
|
|
420
|
+
darkChroma: 8e-3
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
function createTimbalTheme(intent) {
|
|
424
|
+
const brand = parseColor(intent.brand);
|
|
425
|
+
const accent = intent.accent ? parseColor(intent.accent) : null;
|
|
426
|
+
const light = {};
|
|
427
|
+
const dark = {};
|
|
428
|
+
const root = {};
|
|
429
|
+
let fontFamily;
|
|
430
|
+
let fontImportUrl;
|
|
431
|
+
if (typeof intent.radius === "number") {
|
|
432
|
+
root["--radius"] = `${intent.radius}rem`;
|
|
433
|
+
root["--radius-2xl"] = `${Math.max(intent.radius + 0.25, 0)}rem`;
|
|
434
|
+
}
|
|
435
|
+
if (intent.typography) {
|
|
436
|
+
const { sans, display, mono, importUrl } = intent.typography;
|
|
437
|
+
root["--font-sans"] = sans;
|
|
438
|
+
if (display) root["--font-display"] = display;
|
|
439
|
+
if (mono) root["--font-mono"] = mono;
|
|
440
|
+
fontFamily = sans;
|
|
441
|
+
fontImportUrl = importUrl;
|
|
442
|
+
}
|
|
443
|
+
if (intent.shadow) {
|
|
444
|
+
const s = SHADOW_PRESETS[intent.shadow];
|
|
445
|
+
light["--shadow-card-value"] = s.lightCard;
|
|
446
|
+
light["--shadow-card-elevated-value"] = s.lightElevated;
|
|
447
|
+
dark["--shadow-card-value"] = s.darkCard;
|
|
448
|
+
dark["--shadow-card-elevated-value"] = s.darkElevated;
|
|
449
|
+
}
|
|
450
|
+
const primaryLight = primaryForMode(brand, "light");
|
|
451
|
+
const primaryDark = primaryForMode(brand, "dark");
|
|
452
|
+
light["--primary"] = oklchToString(primaryLight);
|
|
453
|
+
light["--primary-foreground"] = readableForeground(primaryLight);
|
|
454
|
+
light["--ring"] = oklchToString(
|
|
455
|
+
scaleChroma({ ...primaryLight, l: 0.6 }, 0.7)
|
|
456
|
+
);
|
|
457
|
+
dark["--primary"] = oklchToString(primaryDark);
|
|
458
|
+
dark["--primary-foreground"] = readableForeground(primaryDark);
|
|
459
|
+
dark["--ring"] = oklchToString(scaleChroma({ ...primaryDark, l: 0.62 }, 0.6));
|
|
460
|
+
const gLight = brandGradient(primaryLight);
|
|
461
|
+
light["--primary-fill-from"] = oklchToString(gLight.from);
|
|
462
|
+
light["--primary-fill-to"] = oklchToString(gLight.to);
|
|
463
|
+
light["--primary-fill-hover-from"] = oklchToString(gLight.hoverFrom);
|
|
464
|
+
light["--primary-fill-hover-to"] = oklchToString(gLight.hoverTo);
|
|
465
|
+
light["--primary-fill-active-from"] = oklchToString(gLight.activeFrom);
|
|
466
|
+
light["--primary-fill-active-to"] = oklchToString(gLight.activeTo);
|
|
467
|
+
const gDark = brandGradient(primaryDark);
|
|
468
|
+
dark["--primary-fill-from"] = oklchToString(gDark.from);
|
|
469
|
+
dark["--primary-fill-to"] = oklchToString(gDark.to);
|
|
470
|
+
dark["--primary-fill-hover-from"] = oklchToString(gDark.hoverFrom);
|
|
471
|
+
dark["--primary-fill-hover-to"] = oklchToString(gDark.hoverTo);
|
|
472
|
+
dark["--primary-fill-active-from"] = oklchToString(gDark.activeFrom);
|
|
473
|
+
dark["--primary-fill-active-to"] = oklchToString(gDark.activeTo);
|
|
474
|
+
if (accent) {
|
|
475
|
+
const accentLight = { ...accent, l: Math.min(Math.max(accent.l, 0.9), 0.97) };
|
|
476
|
+
const accentDark = { ...accent, l: 0.25, c: Math.min(accent.c, 0.04) };
|
|
477
|
+
light["--accent"] = oklchToString(accentLight);
|
|
478
|
+
light["--accent-foreground"] = readableForeground(accentLight);
|
|
479
|
+
dark["--accent"] = oklchToString(accentDark);
|
|
480
|
+
dark["--accent-foreground"] = readableForeground(accentDark);
|
|
481
|
+
}
|
|
482
|
+
light["--playground-from"] = oklchToString(
|
|
483
|
+
withAlpha({ l: 0.91, c: 0.03, h: brand.h, alpha: 0.6 }, 0.6)
|
|
484
|
+
);
|
|
485
|
+
light["--playground-via"] = oklchToString(
|
|
486
|
+
withAlpha({ l: 0.965, c: 0.015, h: brand.h, alpha: 0.3 }, 0.3)
|
|
487
|
+
);
|
|
488
|
+
dark["--playground-from"] = oklchToString({
|
|
489
|
+
l: 0.27,
|
|
490
|
+
c: 0.03,
|
|
491
|
+
h: brand.h,
|
|
492
|
+
alpha: 1
|
|
493
|
+
});
|
|
494
|
+
dark["--playground-via"] = oklchToString({
|
|
495
|
+
l: 0.19,
|
|
496
|
+
c: 0.02,
|
|
497
|
+
h: brand.h,
|
|
498
|
+
alpha: 1
|
|
499
|
+
});
|
|
500
|
+
if (intent.tintNeutrals) {
|
|
501
|
+
const t = neutralTints(brand);
|
|
502
|
+
light["--secondary"] = oklchToString({
|
|
503
|
+
l: 0.975,
|
|
504
|
+
c: t.lightChroma,
|
|
505
|
+
h: t.lightHue,
|
|
506
|
+
alpha: 1
|
|
507
|
+
});
|
|
508
|
+
light["--muted"] = light["--secondary"];
|
|
509
|
+
light["--accent"] ?? (light["--accent"] = oklchToString({
|
|
510
|
+
l: 0.965,
|
|
511
|
+
c: t.lightChroma,
|
|
512
|
+
h: t.lightHue,
|
|
513
|
+
alpha: 1
|
|
514
|
+
}));
|
|
515
|
+
light["--border"] = oklchToString({
|
|
516
|
+
l: 0.91,
|
|
517
|
+
c: t.lightChroma,
|
|
518
|
+
h: t.lightHue,
|
|
519
|
+
alpha: 1
|
|
520
|
+
});
|
|
521
|
+
dark["--secondary"] = oklchToString({
|
|
522
|
+
l: 0.22,
|
|
523
|
+
c: t.darkChroma,
|
|
524
|
+
h: t.darkHue,
|
|
525
|
+
alpha: 1
|
|
526
|
+
});
|
|
527
|
+
dark["--muted"] = dark["--secondary"];
|
|
528
|
+
dark["--border"] = oklchToString({
|
|
529
|
+
l: 1,
|
|
530
|
+
c: 0,
|
|
531
|
+
h: 0,
|
|
532
|
+
alpha: 0.1
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
if (isDev()) {
|
|
536
|
+
const lum = relativeLuminance(primaryLight);
|
|
537
|
+
const fgIsLight = light["--primary-foreground"].includes("0.985");
|
|
538
|
+
const fgLum = fgIsLight ? 1 : 0.05;
|
|
539
|
+
const ratio = (Math.max(lum, fgLum) + 0.05) / (Math.min(lum, fgLum) + 0.05);
|
|
540
|
+
if (ratio < 3.5) {
|
|
541
|
+
console.warn(
|
|
542
|
+
`[@timbal-ai/timbal-react] createTimbalTheme: brand "${intent.brand}" yields a low primary/foreground contrast (~${ratio.toFixed(2)}:1). Consider a darker or more saturated brand color for buttons/CTAs.`
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
return { light, dark, root, fontFamily, fontImportUrl };
|
|
547
|
+
}
|
|
548
|
+
function declarations(map, indent) {
|
|
549
|
+
return Object.entries(map).map(([name, value]) => `${indent}${name}: ${value};`).join("\n");
|
|
550
|
+
}
|
|
551
|
+
function themeToCss(theme, options = {}) {
|
|
552
|
+
const indent = options.indent ?? " ";
|
|
553
|
+
const blocks = [];
|
|
554
|
+
const lightVars = { ...theme.root ?? {}, ...theme.light };
|
|
555
|
+
if (options.scope) {
|
|
556
|
+
const sel = `[data-timbal-theme="${options.scope}"]`;
|
|
557
|
+
if (Object.keys(lightVars).length) {
|
|
558
|
+
blocks.push(`${sel} {
|
|
559
|
+
${declarations(lightVars, indent)}
|
|
560
|
+
}`);
|
|
561
|
+
}
|
|
562
|
+
if (Object.keys(theme.dark).length) {
|
|
563
|
+
blocks.push(
|
|
564
|
+
`.dark ${sel}, ${sel}.dark {
|
|
565
|
+
${declarations(theme.dark, indent)}
|
|
566
|
+
}`
|
|
567
|
+
);
|
|
568
|
+
}
|
|
569
|
+
if (theme.fontFamily) {
|
|
570
|
+
blocks.push(`${sel} {
|
|
571
|
+
${indent}font-family: var(--font-sans);
|
|
572
|
+
}`);
|
|
573
|
+
}
|
|
574
|
+
} else {
|
|
575
|
+
if (Object.keys(lightVars).length) {
|
|
576
|
+
blocks.push(`:root {
|
|
577
|
+
${declarations(lightVars, indent)}
|
|
578
|
+
}`);
|
|
579
|
+
}
|
|
580
|
+
if (Object.keys(theme.dark).length) {
|
|
581
|
+
blocks.push(`.dark {
|
|
582
|
+
${declarations(theme.dark, indent)}
|
|
583
|
+
}`);
|
|
584
|
+
}
|
|
585
|
+
if (theme.fontFamily) {
|
|
586
|
+
blocks.push(`:root,
|
|
587
|
+
body {
|
|
588
|
+
${indent}font-family: var(--font-sans);
|
|
589
|
+
}`);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
const css = blocks.join("\n\n");
|
|
593
|
+
if (options.includeFontImport && theme.fontImportUrl) {
|
|
594
|
+
return `@import url("${theme.fontImportUrl}");
|
|
595
|
+
|
|
596
|
+
${css}`;
|
|
597
|
+
}
|
|
598
|
+
return css;
|
|
599
|
+
}
|
|
600
|
+
var RUNTIME_STYLE_ID = "timbal-theme-runtime";
|
|
601
|
+
var FONT_LINK_ATTR = "data-timbal-theme-font";
|
|
602
|
+
function ensureThemeFontLink(url) {
|
|
603
|
+
if (typeof document === "undefined") return;
|
|
604
|
+
const existing = document.head.querySelector(
|
|
605
|
+
`link[${FONT_LINK_ATTR}]`
|
|
606
|
+
);
|
|
607
|
+
if (!url) {
|
|
608
|
+
existing?.remove();
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
if (existing?.getAttribute("href") === url) return;
|
|
612
|
+
const link = existing ?? document.createElement("link");
|
|
613
|
+
link.rel = "stylesheet";
|
|
614
|
+
link.href = url;
|
|
615
|
+
link.setAttribute(FONT_LINK_ATTR, "");
|
|
616
|
+
if (!existing) document.head.appendChild(link);
|
|
617
|
+
}
|
|
618
|
+
function applyTimbalTheme(theme) {
|
|
619
|
+
if (typeof document === "undefined") return () => {
|
|
620
|
+
};
|
|
621
|
+
ensureThemeFontLink(theme.fontImportUrl);
|
|
622
|
+
let el = document.getElementById(RUNTIME_STYLE_ID);
|
|
623
|
+
if (!el) {
|
|
624
|
+
el = document.createElement("style");
|
|
625
|
+
el.id = RUNTIME_STYLE_ID;
|
|
626
|
+
el.setAttribute("data-timbal-theme-runtime", "");
|
|
627
|
+
document.head.appendChild(el);
|
|
628
|
+
}
|
|
629
|
+
el.textContent = themeToCss(theme);
|
|
630
|
+
return () => {
|
|
631
|
+
el?.parentNode?.removeChild(el);
|
|
632
|
+
ensureThemeFontLink(void 0);
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
function clearTimbalTheme() {
|
|
636
|
+
if (typeof document === "undefined") return;
|
|
637
|
+
document.getElementById(RUNTIME_STYLE_ID)?.remove();
|
|
638
|
+
ensureThemeFontLink(void 0);
|
|
639
|
+
}
|
|
640
|
+
function isDev() {
|
|
641
|
+
if (typeof process !== "undefined" && process.env?.NODE_ENV === "production") {
|
|
642
|
+
return false;
|
|
643
|
+
}
|
|
644
|
+
return true;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
// src/design/theme-presets.ts
|
|
648
|
+
var EMPTY_TOKENS = { light: {}, dark: {}, root: {} };
|
|
649
|
+
var FONT_URL = {
|
|
650
|
+
geist: "https://fonts.googleapis.com/css2?family=Geist:wght@400..600&display=swap",
|
|
651
|
+
sora: "https://fonts.googleapis.com/css2?family=Sora:wght@400..600&display=swap",
|
|
652
|
+
lexend: "https://fonts.googleapis.com/css2?family=Lexend:wght@400..600&display=swap",
|
|
653
|
+
inter: "https://fonts.googleapis.com/css2?family=Inter:wght@400..600&display=swap",
|
|
654
|
+
fraunces: "https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,400..600&display=swap",
|
|
655
|
+
jetbrains: "https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400..600&display=swap"
|
|
656
|
+
};
|
|
657
|
+
var STACK = {
|
|
658
|
+
geist: '"Geist", ui-sans-serif, system-ui, sans-serif',
|
|
659
|
+
sora: '"Sora", ui-sans-serif, system-ui, sans-serif',
|
|
660
|
+
lexend: '"Lexend", ui-sans-serif, system-ui, sans-serif',
|
|
661
|
+
inter: '"Inter", ui-sans-serif, system-ui, sans-serif',
|
|
662
|
+
fraunces: '"Fraunces", ui-serif, Georgia, "Times New Roman", serif',
|
|
663
|
+
jetbrains: '"JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace'
|
|
664
|
+
};
|
|
665
|
+
var TIMBAL_THEME_PRESETS = [
|
|
666
|
+
{
|
|
667
|
+
id: "platform",
|
|
668
|
+
label: "Platform",
|
|
669
|
+
description: "Shipped neutral monochrome \u2014 the Timbal Platform default. Calm, brand-agnostic, system font.",
|
|
670
|
+
swatch: "oklch(0.205 0 0)",
|
|
671
|
+
font: null,
|
|
672
|
+
tokens: EMPTY_TOKENS
|
|
673
|
+
},
|
|
674
|
+
{
|
|
675
|
+
id: "indigo",
|
|
676
|
+
label: "Indigo",
|
|
677
|
+
description: "Cool, trustworthy blue-violet, Geist type, generous radius, soft shadows \u2014 analytics & ops dashboards.",
|
|
678
|
+
swatch: "#4f46e5",
|
|
679
|
+
font: "Geist",
|
|
680
|
+
tokens: createTimbalTheme({
|
|
681
|
+
brand: "#4f46e5",
|
|
682
|
+
radius: 0.875,
|
|
683
|
+
shadow: "soft",
|
|
684
|
+
typography: { sans: STACK.geist, importUrl: FONT_URL.geist }
|
|
685
|
+
})
|
|
686
|
+
},
|
|
687
|
+
{
|
|
688
|
+
id: "violet",
|
|
689
|
+
label: "Violet",
|
|
690
|
+
description: "Vivid purple, Sora type, rounded, soft shadows \u2014 expressive product / marketing surfaces.",
|
|
691
|
+
swatch: "#7c3aed",
|
|
692
|
+
font: "Sora",
|
|
693
|
+
tokens: createTimbalTheme({
|
|
694
|
+
brand: "#7c3aed",
|
|
695
|
+
radius: 1,
|
|
696
|
+
shadow: "soft",
|
|
697
|
+
typography: { sans: STACK.sora, importUrl: FONT_URL.sora }
|
|
698
|
+
})
|
|
699
|
+
},
|
|
700
|
+
{
|
|
701
|
+
id: "forest",
|
|
702
|
+
label: "Forest",
|
|
703
|
+
description: "Grounded green, Lexend type, compact radius \u2014 finance, sustainability, status-positive apps.",
|
|
704
|
+
swatch: "#16a34a",
|
|
705
|
+
font: "Lexend",
|
|
706
|
+
tokens: createTimbalTheme({
|
|
707
|
+
brand: "#16a34a",
|
|
708
|
+
radius: 0.625,
|
|
709
|
+
shadow: "soft",
|
|
710
|
+
typography: { sans: STACK.lexend, importUrl: FONT_URL.lexend }
|
|
711
|
+
})
|
|
712
|
+
},
|
|
713
|
+
{
|
|
714
|
+
id: "warm",
|
|
715
|
+
label: "Warm",
|
|
716
|
+
description: "Energetic orange, Lexend type, friendly radius \u2014 consumer, creative, high-engagement tools.",
|
|
717
|
+
swatch: "#ea580c",
|
|
718
|
+
font: "Lexend",
|
|
719
|
+
tokens: createTimbalTheme({
|
|
720
|
+
brand: "#ea580c",
|
|
721
|
+
radius: 0.875,
|
|
722
|
+
shadow: "soft",
|
|
723
|
+
typography: { sans: STACK.lexend, importUrl: FONT_URL.lexend }
|
|
724
|
+
})
|
|
725
|
+
},
|
|
726
|
+
{
|
|
727
|
+
id: "slate",
|
|
728
|
+
label: "Slate",
|
|
729
|
+
description: "Muted enterprise gray-blue, Inter type, tight radius, hairline shadows, tinted neutrals.",
|
|
730
|
+
swatch: "#475569",
|
|
731
|
+
font: "Inter",
|
|
732
|
+
tokens: createTimbalTheme({
|
|
733
|
+
brand: "#475569",
|
|
734
|
+
radius: 0.5,
|
|
735
|
+
shadow: "hairline",
|
|
736
|
+
tintNeutrals: true,
|
|
737
|
+
typography: { sans: STACK.inter, importUrl: FONT_URL.inter }
|
|
738
|
+
})
|
|
739
|
+
},
|
|
740
|
+
{
|
|
741
|
+
id: "folio",
|
|
742
|
+
label: "Folio",
|
|
743
|
+
description: "Editorial serif (Fraunces), near-sharp corners, hairline shadows \u2014 content / docs / reports.",
|
|
744
|
+
swatch: "#9a3412",
|
|
745
|
+
font: "Fraunces",
|
|
746
|
+
tokens: createTimbalTheme({
|
|
747
|
+
brand: "#9a3412",
|
|
748
|
+
radius: 0.25,
|
|
749
|
+
shadow: "hairline",
|
|
750
|
+
typography: { sans: STACK.fraunces, importUrl: FONT_URL.fraunces }
|
|
751
|
+
})
|
|
752
|
+
},
|
|
753
|
+
{
|
|
754
|
+
id: "carbon",
|
|
755
|
+
label: "Carbon",
|
|
756
|
+
description: "Terminal monospace (JetBrains Mono), crisp corners, green accent \u2014 developer / infra tools.",
|
|
757
|
+
swatch: "#15803d",
|
|
758
|
+
font: "JetBrains Mono",
|
|
759
|
+
tokens: createTimbalTheme({
|
|
760
|
+
brand: "#15803d",
|
|
761
|
+
radius: 0.375,
|
|
762
|
+
shadow: "hairline",
|
|
763
|
+
typography: { sans: STACK.jetbrains, importUrl: FONT_URL.jetbrains }
|
|
764
|
+
})
|
|
765
|
+
}
|
|
766
|
+
];
|
|
767
|
+
var PRESET_BY_ID = new Map(
|
|
768
|
+
TIMBAL_THEME_PRESETS.map((preset) => [preset.id, preset])
|
|
769
|
+
);
|
|
770
|
+
function getThemePreset(id) {
|
|
771
|
+
return PRESET_BY_ID.get(id);
|
|
772
|
+
}
|
|
773
|
+
function applyThemePreset(id) {
|
|
774
|
+
const preset = PRESET_BY_ID.get(id);
|
|
775
|
+
if (!preset) return () => {
|
|
776
|
+
};
|
|
777
|
+
if (typeof window !== "undefined") {
|
|
778
|
+
try {
|
|
779
|
+
window.localStorage.setItem(STORAGE_KEYS.themePreset, id);
|
|
780
|
+
} catch {
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
return applyTimbalTheme(preset.tokens);
|
|
784
|
+
}
|
|
785
|
+
function getStoredThemePreset() {
|
|
786
|
+
if (typeof window === "undefined") return null;
|
|
787
|
+
try {
|
|
788
|
+
const value = window.localStorage.getItem(STORAGE_KEYS.themePreset);
|
|
789
|
+
return value && PRESET_BY_ID.has(value) ? value : null;
|
|
790
|
+
} catch {
|
|
791
|
+
return null;
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
// src/design/theme-instructions.ts
|
|
796
|
+
var THEME_AGENT_INSTRUCTIONS = `
|
|
797
|
+
## Theming (@timbal-ai/timbal-react)
|
|
798
|
+
|
|
799
|
+
The package ships a complete light + dark token system (\`styles.css\`). Components are written against semantic Tailwind tokens (\`bg-background\`, \`text-primary\`, \`border-border\`, \`bg-elevated-from\`, \`bg-bubble-user\`, \u2026). To restyle, you change CSS variables \u2014 **never** hardcode colors in component code.
|
|
800
|
+
|
|
801
|
+
### Golden rule
|
|
802
|
+
|
|
803
|
+
**Never write \`oklch(...)\` / hex literals or hand-author paired \`:root\` + \`.dark\` blocks.** Express intent and let the package derive a complete, contrast-correct, paired palette.
|
|
804
|
+
|
|
805
|
+
### Generate a full personality (color + roundness + fonts + shadows)
|
|
806
|
+
|
|
807
|
+
\`\`\`ts
|
|
808
|
+
import { createTimbalTheme, themeToCss } from "@timbal-ai/timbal-react";
|
|
809
|
+
|
|
810
|
+
const theme = createTimbalTheme({
|
|
811
|
+
brand: "#4f46e5",
|
|
812
|
+
radius: 0.875, // corner roundness in rem (sets --radius + --radius-2xl)
|
|
813
|
+
shadow: "soft", // "none" | "hairline" | "soft" | "medium" | "strong"
|
|
814
|
+
tintNeutrals: false, // tint background/border toward the brand hue
|
|
815
|
+
accent: "#10b981", // optional secondary accent
|
|
816
|
+
typography: { // optional \u2014 re-skins every component's font
|
|
817
|
+
sans: '"Geist", ui-sans-serif, system-ui, sans-serif',
|
|
818
|
+
importUrl: "https://fonts.googleapis.com/css2?family=Geist:wght@400..600&display=swap",
|
|
819
|
+
// display?, mono? also supported
|
|
820
|
+
},
|
|
821
|
+
});
|
|
822
|
+
const css = themeToCss(theme); // paired light + dark, guaranteed in sync
|
|
823
|
+
\`\`\`
|
|
824
|
+
|
|
825
|
+
- \`createTimbalTheme\` derives \`--primary\`, its foreground, ring, the full button gradient, and a soft playground tint from \`brand\`. \`radius\` sets roundness, \`shadow\` sets card depth, \`typography\` sets fonts. You only supply intent \u2014 never raw OKLCH.
|
|
826
|
+
- For a real company, look up the actual brand hex first (brandfetch / "<company> brand color hex").
|
|
827
|
+
- **Web fonts must be loaded.** \`applyTimbalTheme\` / \`TimbalThemeStyle\` inject the \`<link>\` for \`typography.importUrl\` automatically. For build-time \`themeToCss\`, add the \`<link rel="stylesheet" href="\u2026">\` to your \`index.html\` yourself (or pass \`themeToCss(theme, { includeFontImport: true })\` when the result is a standalone stylesheet).
|
|
828
|
+
|
|
829
|
+
### Apply a theme
|
|
830
|
+
|
|
831
|
+
- **Build-time / SSR:** \`themeToCss(theme)\` \u2192 paste the returned CSS into your \`index.css\` (after the \`@import "@timbal-ai/timbal-react/styles.css"\`). One block, both modes.
|
|
832
|
+
- **Runtime / swappable:** \`applyTimbalTheme(theme)\` injects a managed \`<style>\` and returns a disposer. Works with the \`.dark\` toggle (next-themes / ModeToggle).
|
|
833
|
+
- **Component:** render \`<TimbalThemeStyle theme={theme} />\` (or \`preset="indigo"\`) once near the app root.
|
|
834
|
+
|
|
835
|
+
### Offer styles to the user ("show compatible styles, then apply")
|
|
836
|
+
|
|
837
|
+
Use the closed preset catalog \u2014 do not invent options:
|
|
838
|
+
|
|
839
|
+
\`\`\`ts
|
|
840
|
+
import { TIMBAL_THEME_PRESETS, applyThemePreset } from "@timbal-ai/timbal-react";
|
|
841
|
+
// TIMBAL_THEME_PRESETS: { id, label, description, swatch, tokens }[]
|
|
842
|
+
\`\`\`
|
|
843
|
+
|
|
844
|
+
Each preset is a **full personality** (color + radius + shadows + font), not just a color:
|
|
845
|
+
|
|
846
|
+
| Preset id | Personality |
|
|
847
|
+
|-----------|-------------|
|
|
848
|
+
| \`platform\` | Neutral monochrome, system font (the default \u2014 no brand) |
|
|
849
|
+
| \`indigo\` | Blue-violet, Geist, generous radius, soft shadows \u2014 analytics / ops |
|
|
850
|
+
| \`violet\` | Purple, Sora, rounded \u2014 product / marketing |
|
|
851
|
+
| \`forest\` | Green, Lexend, compact \u2014 finance / sustainability |
|
|
852
|
+
| \`warm\` | Orange, Lexend, friendly \u2014 consumer / creative |
|
|
853
|
+
| \`slate\` | Enterprise gray-blue, Inter, tight radius, hairline shadows |
|
|
854
|
+
| \`folio\` | Editorial serif (Fraunces), near-sharp corners \u2014 content / docs |
|
|
855
|
+
| \`carbon\` | Terminal monospace (JetBrains Mono), green accent \u2014 dev / infra |
|
|
856
|
+
|
|
857
|
+
- To present options visually, render \`<ThemePresetGallery value={id} onSelect={setId} />\` \u2014 each swatch previews real components (Button + metric tile) scoped via \`data-timbal-theme\`, so the live app doesn't change until the user picks.
|
|
858
|
+
- On selection, call \`applyThemePreset(id)\` (persists to \`localStorage\` and restores on reload).
|
|
859
|
+
|
|
860
|
+
### Rules
|
|
861
|
+
|
|
862
|
+
- Generated pages use **semantic Tailwind tokens only** \u2014 never literal colors or per-element \`style={{ color }}\`.
|
|
863
|
+
- Light/dark mode stays the \`.dark\` class (\`next-themes attribute="class"\` or \`ModeToggle\`). Presets are **brand**, not a second dark-mode system.
|
|
864
|
+
- Override individual tokens only for one-offs the generator doesn't cover; if you must, set the variable in **both** \`:root\` and \`.dark\` (a dev-only warning fires otherwise).
|
|
865
|
+
`.trim();
|
|
866
|
+
|
|
867
|
+
// src/app/theme/TimbalThemeStyle.tsx
|
|
868
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
869
|
+
var TimbalThemeStyle = ({
|
|
870
|
+
theme,
|
|
871
|
+
preset,
|
|
872
|
+
scope,
|
|
873
|
+
nonce
|
|
874
|
+
}) => {
|
|
875
|
+
const tokens = theme ?? (preset ? getThemePreset(preset)?.tokens : void 0);
|
|
876
|
+
if (!tokens) return null;
|
|
877
|
+
const css = themeToCss(tokens, scope ? { scope } : void 0);
|
|
878
|
+
if (!css) return null;
|
|
879
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
880
|
+
tokens.fontImportUrl ? /* @__PURE__ */ jsx("link", { rel: "stylesheet", href: tokens.fontImportUrl }) : null,
|
|
881
|
+
/* @__PURE__ */ jsx(
|
|
882
|
+
"style",
|
|
883
|
+
{
|
|
884
|
+
"data-timbal-theme-style": scope ?? "root",
|
|
885
|
+
nonce,
|
|
886
|
+
dangerouslySetInnerHTML: { __html: css }
|
|
887
|
+
}
|
|
888
|
+
)
|
|
889
|
+
] });
|
|
890
|
+
};
|
|
891
|
+
|
|
892
|
+
// src/app/data/metrics-shared.tsx
|
|
893
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
894
|
+
var metricCardShellClass = cn(
|
|
895
|
+
studioIntegrationCardClass,
|
|
896
|
+
"aui-app-metric-card shadow-none",
|
|
897
|
+
"flex flex-col overflow-hidden"
|
|
898
|
+
);
|
|
899
|
+
var metricCardHeaderClass = "flex items-start justify-between gap-3 px-4 pb-1 pt-3";
|
|
900
|
+
var metricTilesRowClass = "grid w-full min-w-0";
|
|
901
|
+
var metricChartRegionClass = "relative min-h-0 w-full border-t border-border/40 pt-2";
|
|
902
|
+
var metricChartPlotRegionClass = "relative min-h-0 w-full border-t border-border/40 px-0 pt-5 pb-3";
|
|
903
|
+
var metricCellDividerClass = "border-r border-border/40";
|
|
904
|
+
var MetricCardHeader = ({
|
|
905
|
+
title,
|
|
906
|
+
titleId,
|
|
907
|
+
description,
|
|
908
|
+
actions
|
|
909
|
+
}) => {
|
|
910
|
+
if (!title && !description && !actions) return null;
|
|
911
|
+
return /* @__PURE__ */ jsxs2("header", { className: metricCardHeaderClass, children: [
|
|
912
|
+
/* @__PURE__ */ jsxs2("div", { className: "min-w-0", children: [
|
|
913
|
+
title ? /* @__PURE__ */ jsx2("h3", { id: titleId, className: "text-base font-normal text-foreground", children: title }) : null,
|
|
914
|
+
description ? /* @__PURE__ */ jsx2("p", { className: "mt-0.5 text-sm text-muted-foreground", children: description }) : null
|
|
915
|
+
] }),
|
|
916
|
+
actions ? /* @__PURE__ */ jsx2("div", { className: "shrink-0", children: actions }) : null
|
|
917
|
+
] });
|
|
918
|
+
};
|
|
919
|
+
function metricTilesGridColsClass(n) {
|
|
920
|
+
switch (n) {
|
|
921
|
+
case 1:
|
|
922
|
+
return "grid-cols-1";
|
|
923
|
+
case 2:
|
|
924
|
+
return "grid-cols-2";
|
|
925
|
+
case 3:
|
|
926
|
+
return "grid-cols-3";
|
|
927
|
+
case 5:
|
|
928
|
+
return "grid-cols-2 sm:grid-cols-5";
|
|
929
|
+
case 6:
|
|
930
|
+
return "grid-cols-2 sm:grid-cols-3 lg:grid-cols-6";
|
|
931
|
+
default:
|
|
932
|
+
return "grid-cols-2 md:grid-cols-4";
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
// src/app/data/MetricTile.tsx
|
|
937
|
+
import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
938
|
+
var trendToneClass = {
|
|
939
|
+
up: "border-border/80 bg-muted/40 text-muted-foreground",
|
|
940
|
+
down: "border-border/80 bg-muted/40 text-muted-foreground",
|
|
941
|
+
neutral: "border-border/80 bg-muted/30 text-muted-foreground"
|
|
942
|
+
};
|
|
943
|
+
var metricTileBaseClass = "relative flex min-w-0 flex-1 flex-col gap-1 px-4 py-3 text-left font-normal";
|
|
944
|
+
var metricTileInteractiveClass = cn(
|
|
945
|
+
metricTileBaseClass,
|
|
946
|
+
"bg-transparent hover:bg-transparent active:bg-transparent",
|
|
947
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-foreground/10"
|
|
948
|
+
);
|
|
949
|
+
var MetricTile = ({
|
|
950
|
+
label,
|
|
951
|
+
value,
|
|
952
|
+
unit,
|
|
953
|
+
trend,
|
|
954
|
+
trendTone = "neutral",
|
|
955
|
+
active = false,
|
|
956
|
+
showDivider = false,
|
|
957
|
+
onSelect,
|
|
958
|
+
ariaLabel,
|
|
959
|
+
className
|
|
960
|
+
}) => {
|
|
961
|
+
const content = /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
962
|
+
active ? /* @__PURE__ */ jsx3(
|
|
963
|
+
"span",
|
|
964
|
+
{
|
|
965
|
+
"aria-hidden": true,
|
|
966
|
+
className: "absolute inset-x-0 bottom-0 h-0.5 bg-foreground dark:bg-white"
|
|
967
|
+
}
|
|
968
|
+
) : null,
|
|
969
|
+
/* @__PURE__ */ jsx3("span", { className: "text-xs font-normal text-muted-foreground", children: label }),
|
|
970
|
+
/* @__PURE__ */ jsxs3("span", { className: "flex items-center gap-2", children: [
|
|
971
|
+
/* @__PURE__ */ jsxs3("span", { className: "flex items-baseline gap-1", children: [
|
|
972
|
+
/* @__PURE__ */ jsx3("span", { className: "text-2xl font-normal tracking-tight text-foreground tabular-nums", children: value }),
|
|
973
|
+
unit ? /* @__PURE__ */ jsx3("span", { className: "text-xs font-normal text-muted-foreground", children: unit }) : null
|
|
974
|
+
] }),
|
|
975
|
+
trend ? /* @__PURE__ */ jsx3(
|
|
976
|
+
"span",
|
|
977
|
+
{
|
|
978
|
+
className: cn(
|
|
979
|
+
"rounded-full border px-1.5 py-0.5 text-xs font-normal",
|
|
980
|
+
trendToneClass[trendTone]
|
|
981
|
+
),
|
|
982
|
+
children: trend
|
|
983
|
+
}
|
|
984
|
+
) : null
|
|
985
|
+
] })
|
|
986
|
+
] });
|
|
987
|
+
const divider = showDivider ? metricCellDividerClass : void 0;
|
|
988
|
+
if (onSelect) {
|
|
989
|
+
return /* @__PURE__ */ jsx3(
|
|
990
|
+
"button",
|
|
991
|
+
{
|
|
992
|
+
type: "button",
|
|
993
|
+
onClick: onSelect,
|
|
994
|
+
"aria-pressed": active,
|
|
995
|
+
"aria-label": ariaLabel,
|
|
996
|
+
className: cn(metricTileInteractiveClass, divider, className),
|
|
997
|
+
children: content
|
|
998
|
+
}
|
|
999
|
+
);
|
|
1000
|
+
}
|
|
1001
|
+
return /* @__PURE__ */ jsx3("div", { className: cn(metricTileBaseClass, divider, className), children: content });
|
|
1002
|
+
};
|
|
1003
|
+
|
|
1004
|
+
// src/app/theme/ThemePresetGallery.tsx
|
|
1005
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1006
|
+
var ThemePresetGallery = ({
|
|
1007
|
+
value,
|
|
1008
|
+
onSelect,
|
|
1009
|
+
presets,
|
|
1010
|
+
className
|
|
1011
|
+
}) => {
|
|
1012
|
+
const items = presets ? TIMBAL_THEME_PRESETS.filter((p) => presets.includes(p.id)) : TIMBAL_THEME_PRESETS;
|
|
1013
|
+
return /* @__PURE__ */ jsx4(
|
|
1014
|
+
"div",
|
|
1015
|
+
{
|
|
1016
|
+
role: "radiogroup",
|
|
1017
|
+
"aria-label": "Theme presets",
|
|
1018
|
+
className: cn(
|
|
1019
|
+
"grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3",
|
|
1020
|
+
className
|
|
1021
|
+
),
|
|
1022
|
+
children: items.map((preset) => {
|
|
1023
|
+
const selected = value === preset.id;
|
|
1024
|
+
return /* @__PURE__ */ jsxs4("div", { "data-timbal-theme": preset.id, children: [
|
|
1025
|
+
/* @__PURE__ */ jsx4(TimbalThemeStyle, { preset: preset.id, scope: preset.id }),
|
|
1026
|
+
/* @__PURE__ */ jsxs4(
|
|
1027
|
+
"button",
|
|
1028
|
+
{
|
|
1029
|
+
type: "button",
|
|
1030
|
+
role: "radio",
|
|
1031
|
+
"aria-checked": selected,
|
|
1032
|
+
"aria-label": `${preset.label} theme`,
|
|
1033
|
+
onClick: () => onSelect?.(preset.id),
|
|
1034
|
+
className: cn(
|
|
1035
|
+
"group flex w-full flex-col gap-3 rounded-xl border bg-card p-3 text-left transition-colors",
|
|
1036
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
1037
|
+
selected ? "border-primary ring-2 ring-primary/30" : "border-border hover:border-foreground/30"
|
|
1038
|
+
),
|
|
1039
|
+
children: [
|
|
1040
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex items-center justify-between gap-2", children: [
|
|
1041
|
+
/* @__PURE__ */ jsxs4("span", { className: "flex items-center gap-2", children: [
|
|
1042
|
+
/* @__PURE__ */ jsx4(
|
|
1043
|
+
"span",
|
|
1044
|
+
{
|
|
1045
|
+
"aria-hidden": true,
|
|
1046
|
+
className: "size-4 shrink-0 rounded-full ring-1 ring-black/10",
|
|
1047
|
+
style: { background: preset.swatch }
|
|
1048
|
+
}
|
|
1049
|
+
),
|
|
1050
|
+
/* @__PURE__ */ jsx4("span", { className: "text-sm font-medium text-foreground", children: preset.label })
|
|
1051
|
+
] }),
|
|
1052
|
+
selected ? /* @__PURE__ */ jsx4("span", { className: "text-xs font-medium text-primary", children: "Selected" }) : null
|
|
1053
|
+
] }),
|
|
1054
|
+
/* @__PURE__ */ jsx4("p", { className: "text-xs leading-snug text-muted-foreground", children: preset.description }),
|
|
1055
|
+
preset.font ? /* @__PURE__ */ jsxs4("span", { className: "text-[10px] uppercase tracking-wide text-muted-foreground", children: [
|
|
1056
|
+
"Aa \xB7 ",
|
|
1057
|
+
preset.font
|
|
1058
|
+
] }) : null,
|
|
1059
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex flex-col gap-2 rounded-lg border border-border bg-background p-2", children: [
|
|
1060
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2", children: [
|
|
1061
|
+
/* @__PURE__ */ jsx4(Button, { size: "xs", className: "pointer-events-none", children: "Primary" }),
|
|
1062
|
+
/* @__PURE__ */ jsx4("span", { className: "size-5 rounded-md bg-primary", "aria-hidden": true }),
|
|
1063
|
+
/* @__PURE__ */ jsx4("span", { className: "size-5 rounded-md bg-muted", "aria-hidden": true }),
|
|
1064
|
+
/* @__PURE__ */ jsx4(
|
|
1065
|
+
"span",
|
|
1066
|
+
{
|
|
1067
|
+
className: "size-5 rounded-md border border-border bg-accent",
|
|
1068
|
+
"aria-hidden": true
|
|
1069
|
+
}
|
|
1070
|
+
)
|
|
1071
|
+
] }),
|
|
1072
|
+
/* @__PURE__ */ jsx4(MetricTile, { label: "Active users", value: "1,248", trend: "+8%" })
|
|
1073
|
+
] })
|
|
1074
|
+
]
|
|
1075
|
+
}
|
|
1076
|
+
)
|
|
1077
|
+
] }, preset.id);
|
|
1078
|
+
})
|
|
1079
|
+
}
|
|
1080
|
+
);
|
|
1081
|
+
};
|
|
1082
|
+
|
|
221
1083
|
// src/design/app-classes.ts
|
|
222
1084
|
var appPageColumnClass = "mx-auto w-full max-w-6xl px-4 md:px-6";
|
|
223
1085
|
var appShellTopbarInsetClass = "w-full px-4 md:px-6";
|
|
@@ -282,7 +1144,7 @@ function useAppShellChat() {
|
|
|
282
1144
|
// src/app/layout/AppShell.tsx
|
|
283
1145
|
import { motion, useReducedMotion } from "motion/react";
|
|
284
1146
|
import { useCallback, useState } from "react";
|
|
285
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
1147
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
286
1148
|
var floatingTriggerClass = cn(
|
|
287
1149
|
"aui-app-shell-chat-trigger-fixed fixed z-50 rounded-full px-5 py-2.5 text-sm font-medium shadow-card-elevated",
|
|
288
1150
|
"bg-primary text-primary-foreground transition-colors hover:bg-primary/90",
|
|
@@ -311,14 +1173,14 @@ var AppShellBody = ({
|
|
|
311
1173
|
layoutDirection
|
|
312
1174
|
);
|
|
313
1175
|
const insetPadding = sidebar ? insetPaddingPx : 0;
|
|
314
|
-
return /* @__PURE__ */
|
|
1176
|
+
return /* @__PURE__ */ jsx5(
|
|
315
1177
|
motion.div,
|
|
316
1178
|
{
|
|
317
1179
|
className: "aui-app-shell-body relative z-10 flex min-h-0 min-w-0 flex-1 flex-col",
|
|
318
1180
|
initial: false,
|
|
319
1181
|
animate: { paddingLeft: insetPadding },
|
|
320
1182
|
transition: layoutTransition,
|
|
321
|
-
children: /* @__PURE__ */
|
|
1183
|
+
children: /* @__PURE__ */ jsxs5(
|
|
322
1184
|
"div",
|
|
323
1185
|
{
|
|
324
1186
|
className: cn(
|
|
@@ -326,8 +1188,8 @@ var AppShellBody = ({
|
|
|
326
1188
|
!topbarContent && appShellInsetTopClass
|
|
327
1189
|
),
|
|
328
1190
|
children: [
|
|
329
|
-
topbarContent ? /* @__PURE__ */
|
|
330
|
-
/* @__PURE__ */
|
|
1191
|
+
topbarContent ? /* @__PURE__ */ jsx5("header", { className: cn("aui-app-shell-topbar-region", appShellTopbarStickyClass), children: /* @__PURE__ */ jsx5("div", { className: appShellTopbarInsetClass, children: topbarContent }) }) : null,
|
|
1192
|
+
/* @__PURE__ */ jsx5("main", { className: cn("aui-app-shell-main min-w-0 flex-1", mainClassName), children })
|
|
331
1193
|
]
|
|
332
1194
|
}
|
|
333
1195
|
)
|
|
@@ -375,7 +1237,7 @@ var AppShell = ({
|
|
|
375
1237
|
setInsetPaddingPx(insetPx);
|
|
376
1238
|
}, []);
|
|
377
1239
|
const insetExpanded = insetPaddingPx >= SIDEBAR_INSET_PX_EXPANDED;
|
|
378
|
-
const shellBody = /* @__PURE__ */
|
|
1240
|
+
const shellBody = /* @__PURE__ */ jsx5(
|
|
379
1241
|
AppShellBody,
|
|
380
1242
|
{
|
|
381
1243
|
sidebar,
|
|
@@ -386,7 +1248,7 @@ var AppShell = ({
|
|
|
386
1248
|
children
|
|
387
1249
|
}
|
|
388
1250
|
);
|
|
389
|
-
const tree = /* @__PURE__ */
|
|
1251
|
+
const tree = /* @__PURE__ */ jsx5(ShellInsetProvider, { value: sidebar ? reportShellInset : null, children: /* @__PURE__ */ jsxs5(
|
|
390
1252
|
"div",
|
|
391
1253
|
{
|
|
392
1254
|
className: cn(
|
|
@@ -397,7 +1259,7 @@ var AppShell = ({
|
|
|
397
1259
|
children: [
|
|
398
1260
|
sidebar,
|
|
399
1261
|
shellBody,
|
|
400
|
-
hasChat && chatOpen ? /* @__PURE__ */
|
|
1262
|
+
hasChat && chatOpen ? /* @__PURE__ */ jsx5(
|
|
401
1263
|
"div",
|
|
402
1264
|
{
|
|
403
1265
|
className: floatingPanelClass,
|
|
@@ -410,7 +1272,7 @@ var AppShell = ({
|
|
|
410
1272
|
children: chat
|
|
411
1273
|
}
|
|
412
1274
|
) : null,
|
|
413
|
-
hasChat && chatCollapsible && !chatOpen && !hideChatTrigger ? /* @__PURE__ */
|
|
1275
|
+
hasChat && chatCollapsible && !chatOpen && !hideChatTrigger ? /* @__PURE__ */ jsx5(
|
|
414
1276
|
"button",
|
|
415
1277
|
{
|
|
416
1278
|
type: "button",
|
|
@@ -426,7 +1288,7 @@ var AppShell = ({
|
|
|
426
1288
|
if (!hasChat) {
|
|
427
1289
|
return tree;
|
|
428
1290
|
}
|
|
429
|
-
return /* @__PURE__ */
|
|
1291
|
+
return /* @__PURE__ */ jsx5(
|
|
430
1292
|
AppShellChatProvider,
|
|
431
1293
|
{
|
|
432
1294
|
value: {
|
|
@@ -441,24 +1303,24 @@ var AppShell = ({
|
|
|
441
1303
|
};
|
|
442
1304
|
|
|
443
1305
|
// src/app/layout/AppShellTopbar.tsx
|
|
444
|
-
import { jsx as
|
|
1306
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
445
1307
|
var AppShellTopbar = ({
|
|
446
1308
|
start,
|
|
447
1309
|
actions,
|
|
448
1310
|
children,
|
|
449
1311
|
className
|
|
450
1312
|
}) => {
|
|
451
|
-
return /* @__PURE__ */
|
|
452
|
-
/* @__PURE__ */
|
|
1313
|
+
return /* @__PURE__ */ jsxs6("div", { className: cn("aui-app-shell-topbar", appShellTopbarRowClass, className), children: [
|
|
1314
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
|
|
453
1315
|
start,
|
|
454
1316
|
children
|
|
455
1317
|
] }),
|
|
456
|
-
actions ? /* @__PURE__ */
|
|
1318
|
+
actions ? /* @__PURE__ */ jsx6("div", { className: "aui-app-shell-topbar-actions flex shrink-0 items-center gap-2", children: actions }) : null
|
|
457
1319
|
] });
|
|
458
1320
|
};
|
|
459
1321
|
|
|
460
1322
|
// src/app/layout/AppShellChatTrigger.tsx
|
|
461
|
-
import { jsx as
|
|
1323
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
462
1324
|
var floatingPositionClass = "fixed bottom-6 right-6 z-50 max-sm:bottom-4 max-sm:right-4";
|
|
463
1325
|
var AppShellChatTrigger = ({
|
|
464
1326
|
className,
|
|
@@ -467,7 +1329,7 @@ var AppShellChatTrigger = ({
|
|
|
467
1329
|
}) => {
|
|
468
1330
|
const shellChat = useAppShellChat();
|
|
469
1331
|
if (!shellChat || shellChat.open) return null;
|
|
470
|
-
return /* @__PURE__ */
|
|
1332
|
+
return /* @__PURE__ */ jsx7(
|
|
471
1333
|
TimbalV2Button,
|
|
472
1334
|
{
|
|
473
1335
|
type: "button",
|
|
@@ -487,61 +1349,61 @@ var AppShellChatTrigger = ({
|
|
|
487
1349
|
};
|
|
488
1350
|
|
|
489
1351
|
// src/app/layout/PageHeader.tsx
|
|
490
|
-
import { jsx as
|
|
1352
|
+
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
491
1353
|
var PageHeader = ({
|
|
492
1354
|
title,
|
|
493
1355
|
description,
|
|
494
1356
|
actions,
|
|
495
1357
|
className
|
|
496
1358
|
}) => {
|
|
497
|
-
return /* @__PURE__ */
|
|
498
|
-
/* @__PURE__ */
|
|
499
|
-
/* @__PURE__ */
|
|
500
|
-
description ? /* @__PURE__ */
|
|
1359
|
+
return /* @__PURE__ */ jsxs7("header", { className: cn("aui-app-page-header", appPageHeaderClass, className), children: [
|
|
1360
|
+
/* @__PURE__ */ jsxs7("div", { className: "min-w-0", children: [
|
|
1361
|
+
/* @__PURE__ */ jsx8("h1", { className: "text-2xl font-semibold tracking-tight text-foreground", children: title }),
|
|
1362
|
+
description ? /* @__PURE__ */ jsx8("p", { className: "mt-1 text-sm text-muted-foreground", children: description }) : null
|
|
501
1363
|
] }),
|
|
502
|
-
actions ? /* @__PURE__ */
|
|
1364
|
+
actions ? /* @__PURE__ */ jsx8("div", { className: "aui-app-page-header-actions flex shrink-0 flex-wrap items-center gap-2", children: actions }) : null
|
|
503
1365
|
] });
|
|
504
1366
|
};
|
|
505
1367
|
|
|
506
1368
|
// src/app/layout/Page.tsx
|
|
507
|
-
import { jsx as
|
|
1369
|
+
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
508
1370
|
var Page = ({
|
|
509
1371
|
children,
|
|
510
1372
|
breadcrumbs,
|
|
511
1373
|
className,
|
|
512
1374
|
...headerProps
|
|
513
1375
|
}) => {
|
|
514
|
-
return /* @__PURE__ */
|
|
1376
|
+
return /* @__PURE__ */ jsxs8("div", { className: cn("aui-app-page", appPageColumnClass, className), children: [
|
|
515
1377
|
breadcrumbs,
|
|
516
|
-
/* @__PURE__ */
|
|
1378
|
+
/* @__PURE__ */ jsx9(PageHeader, { ...headerProps }),
|
|
517
1379
|
children
|
|
518
1380
|
] });
|
|
519
1381
|
};
|
|
520
1382
|
|
|
521
1383
|
// src/app/layout/Section.tsx
|
|
522
|
-
import { jsx as
|
|
1384
|
+
import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
523
1385
|
var Section = ({
|
|
524
1386
|
title,
|
|
525
1387
|
description,
|
|
526
1388
|
children,
|
|
527
1389
|
className
|
|
528
1390
|
}) => {
|
|
529
|
-
return /* @__PURE__ */
|
|
530
|
-
title ? /* @__PURE__ */
|
|
531
|
-
description ? /* @__PURE__ */
|
|
1391
|
+
return /* @__PURE__ */ jsxs9("section", { className: cn("aui-app-section", appSectionClass, className), children: [
|
|
1392
|
+
title ? /* @__PURE__ */ jsx10("h2", { className: appSectionTitleClass, children: title }) : null,
|
|
1393
|
+
description ? /* @__PURE__ */ jsx10("p", { className: appSectionDescriptionClass, children: description }) : null,
|
|
532
1394
|
children
|
|
533
1395
|
] });
|
|
534
1396
|
};
|
|
535
1397
|
|
|
536
1398
|
// src/app/copilot/app-copilot-context.tsx
|
|
537
1399
|
import { createContext as createContext2, useContext as useContext2 } from "react";
|
|
538
|
-
import { jsx as
|
|
1400
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
539
1401
|
var AppCopilotContext = createContext2(null);
|
|
540
1402
|
var AppCopilotProvider = ({
|
|
541
1403
|
value,
|
|
542
1404
|
children
|
|
543
1405
|
}) => {
|
|
544
|
-
return /* @__PURE__ */
|
|
1406
|
+
return /* @__PURE__ */ jsx11(AppCopilotContext.Provider, { value, children });
|
|
545
1407
|
};
|
|
546
1408
|
function useAppCopilotContext() {
|
|
547
1409
|
return useContext2(AppCopilotContext) ?? {};
|
|
@@ -549,7 +1411,7 @@ function useAppCopilotContext() {
|
|
|
549
1411
|
|
|
550
1412
|
// src/app/chat/AppChatPanel.tsx
|
|
551
1413
|
import { XIcon } from "lucide-react";
|
|
552
|
-
import { jsx as
|
|
1414
|
+
import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
553
1415
|
var shellClass = "aui-app-chat-panel flex h-full min-h-0 flex-col overflow-hidden";
|
|
554
1416
|
var chromeClass = cn(
|
|
555
1417
|
"aui-app-chat-panel-chrome relative z-20 flex min-h-10 shrink-0 items-center justify-end px-2 pt-2"
|
|
@@ -594,18 +1456,18 @@ var AppChatPanel = ({
|
|
|
594
1456
|
...rest
|
|
595
1457
|
}) => {
|
|
596
1458
|
const shellChat = useAppShellChat();
|
|
597
|
-
return /* @__PURE__ */
|
|
598
|
-
shellChat?.collapsible ? /* @__PURE__ */
|
|
1459
|
+
return /* @__PURE__ */ jsxs10("div", { className: cn(shellClass, className), children: [
|
|
1460
|
+
shellChat?.collapsible ? /* @__PURE__ */ jsx12("div", { className: chromeClass, children: /* @__PURE__ */ jsx12(
|
|
599
1461
|
"button",
|
|
600
1462
|
{
|
|
601
1463
|
type: "button",
|
|
602
1464
|
className: closeButtonClass,
|
|
603
1465
|
onClick: () => shellChat.setOpen(false),
|
|
604
1466
|
"aria-label": "Close assistant",
|
|
605
|
-
children: /* @__PURE__ */
|
|
1467
|
+
children: /* @__PURE__ */ jsx12(XIcon, { className: "size-4", "aria-hidden": true })
|
|
606
1468
|
}
|
|
607
1469
|
) }) : null,
|
|
608
|
-
/* @__PURE__ */
|
|
1470
|
+
/* @__PURE__ */ jsx12("div", { className: bodyClass, children: /* @__PURE__ */ jsx12(
|
|
609
1471
|
TimbalRuntimeProvider,
|
|
610
1472
|
{
|
|
611
1473
|
workforceId,
|
|
@@ -615,7 +1477,7 @@ var AppChatPanel = ({
|
|
|
615
1477
|
attachmentsUploadUrl,
|
|
616
1478
|
attachmentsAccept,
|
|
617
1479
|
debug,
|
|
618
|
-
children: /* @__PURE__ */
|
|
1480
|
+
children: /* @__PURE__ */ jsx12(
|
|
619
1481
|
Thread,
|
|
620
1482
|
{
|
|
621
1483
|
variant: "panel",
|
|
@@ -636,38 +1498,38 @@ var AppChatPanel = ({
|
|
|
636
1498
|
};
|
|
637
1499
|
|
|
638
1500
|
// src/app/surfaces/SurfaceCard.tsx
|
|
639
|
-
import { jsx as
|
|
1501
|
+
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
640
1502
|
var SurfaceCard = ({ children, className }) => {
|
|
641
|
-
return /* @__PURE__ */
|
|
1503
|
+
return /* @__PURE__ */ jsx13("div", { className: cn("aui-app-surface-card", appSurfaceCardClass, className), children });
|
|
642
1504
|
};
|
|
643
1505
|
|
|
644
1506
|
// src/app/surfaces/StatTile.tsx
|
|
645
|
-
import { jsx as
|
|
1507
|
+
import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
646
1508
|
var StatTile = ({ label, value, hint, className }) => {
|
|
647
|
-
return /* @__PURE__ */
|
|
648
|
-
/* @__PURE__ */
|
|
649
|
-
/* @__PURE__ */
|
|
650
|
-
hint ? /* @__PURE__ */
|
|
1509
|
+
return /* @__PURE__ */ jsxs11("div", { className: cn("aui-app-stat-tile", appStatTileClass, className), children: [
|
|
1510
|
+
/* @__PURE__ */ jsx14("span", { className: appStatLabelClass, children: label }),
|
|
1511
|
+
/* @__PURE__ */ jsx14("span", { className: appStatValueClass, children: value }),
|
|
1512
|
+
hint ? /* @__PURE__ */ jsx14("span", { className: "text-xs text-muted-foreground", children: hint }) : null
|
|
651
1513
|
] });
|
|
652
1514
|
};
|
|
653
1515
|
|
|
654
1516
|
// src/app/surfaces/EmptyState.tsx
|
|
655
|
-
import { jsx as
|
|
1517
|
+
import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
656
1518
|
var EmptyState = ({
|
|
657
1519
|
title,
|
|
658
1520
|
description,
|
|
659
1521
|
action,
|
|
660
1522
|
className
|
|
661
1523
|
}) => {
|
|
662
|
-
return /* @__PURE__ */
|
|
663
|
-
/* @__PURE__ */
|
|
664
|
-
description ? /* @__PURE__ */
|
|
1524
|
+
return /* @__PURE__ */ jsxs12("div", { className: cn("aui-app-empty-state", appEmptyStateClass, className), children: [
|
|
1525
|
+
/* @__PURE__ */ jsx15("p", { className: appEmptyStateTitleClass, children: title }),
|
|
1526
|
+
description ? /* @__PURE__ */ jsx15("p", { className: appEmptyStateDescriptionClass, children: description }) : null,
|
|
665
1527
|
action
|
|
666
1528
|
] });
|
|
667
1529
|
};
|
|
668
1530
|
|
|
669
1531
|
// src/app/surfaces/StatusBadge.tsx
|
|
670
|
-
import { jsx as
|
|
1532
|
+
import { jsx as jsx16 } from "react/jsx-runtime";
|
|
671
1533
|
var statusBadgeToneClass = {
|
|
672
1534
|
default: "bg-muted text-foreground",
|
|
673
1535
|
primary: "bg-primary/10 text-primary",
|
|
@@ -680,7 +1542,7 @@ var StatusBadge = ({
|
|
|
680
1542
|
tone = "default",
|
|
681
1543
|
className
|
|
682
1544
|
}) => {
|
|
683
|
-
return /* @__PURE__ */
|
|
1545
|
+
return /* @__PURE__ */ jsx16(
|
|
684
1546
|
"span",
|
|
685
1547
|
{
|
|
686
1548
|
className: cn(
|
|
@@ -694,7 +1556,7 @@ var StatusBadge = ({
|
|
|
694
1556
|
};
|
|
695
1557
|
|
|
696
1558
|
// src/app/surfaces/AppConfirmDialog.tsx
|
|
697
|
-
import { jsx as
|
|
1559
|
+
import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
698
1560
|
var bodyClass2 = "flex flex-col gap-4 p-6";
|
|
699
1561
|
var titleClass = "pr-8";
|
|
700
1562
|
var actionsClass = "flex flex-wrap justify-end gap-2";
|
|
@@ -709,15 +1571,15 @@ var AppConfirmDialog = ({
|
|
|
709
1571
|
destructive = false,
|
|
710
1572
|
className
|
|
711
1573
|
}) => {
|
|
712
|
-
return /* @__PURE__ */
|
|
1574
|
+
return /* @__PURE__ */ jsx17(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsx17(
|
|
713
1575
|
DialogContent,
|
|
714
1576
|
{
|
|
715
1577
|
className: cn("gap-0 p-0 sm:max-w-md", className),
|
|
716
|
-
children: /* @__PURE__ */
|
|
717
|
-
/* @__PURE__ */
|
|
718
|
-
description ? /* @__PURE__ */
|
|
719
|
-
/* @__PURE__ */
|
|
720
|
-
/* @__PURE__ */
|
|
1578
|
+
children: /* @__PURE__ */ jsxs13("div", { className: bodyClass2, children: [
|
|
1579
|
+
/* @__PURE__ */ jsx17(DialogTitle, { className: titleClass, children: title }),
|
|
1580
|
+
description ? /* @__PURE__ */ jsx17("p", { className: "text-sm text-muted-foreground", children: description }) : null,
|
|
1581
|
+
/* @__PURE__ */ jsxs13("div", { className: actionsClass, children: [
|
|
1582
|
+
/* @__PURE__ */ jsx17(
|
|
721
1583
|
TimbalV2Button,
|
|
722
1584
|
{
|
|
723
1585
|
type: "button",
|
|
@@ -727,7 +1589,7 @@ var AppConfirmDialog = ({
|
|
|
727
1589
|
children: cancelLabel
|
|
728
1590
|
}
|
|
729
1591
|
),
|
|
730
|
-
/* @__PURE__ */
|
|
1592
|
+
/* @__PURE__ */ jsx17(
|
|
731
1593
|
TimbalV2Button,
|
|
732
1594
|
{
|
|
733
1595
|
type: "button",
|
|
@@ -747,7 +1609,7 @@ var AppConfirmDialog = ({
|
|
|
747
1609
|
};
|
|
748
1610
|
|
|
749
1611
|
// src/app/surfaces/InfoCard.tsx
|
|
750
|
-
import { jsx as
|
|
1612
|
+
import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
751
1613
|
var toneClass = {
|
|
752
1614
|
neutral: "border-border bg-muted/40",
|
|
753
1615
|
info: "border-primary/25 bg-primary/5",
|
|
@@ -762,7 +1624,7 @@ var InfoCard = ({
|
|
|
762
1624
|
action,
|
|
763
1625
|
tone = "neutral",
|
|
764
1626
|
className
|
|
765
|
-
}) => /* @__PURE__ */
|
|
1627
|
+
}) => /* @__PURE__ */ jsxs14(
|
|
766
1628
|
"div",
|
|
767
1629
|
{
|
|
768
1630
|
className: cn(
|
|
@@ -771,18 +1633,18 @@ var InfoCard = ({
|
|
|
771
1633
|
className
|
|
772
1634
|
),
|
|
773
1635
|
children: [
|
|
774
|
-
icon ? /* @__PURE__ */
|
|
775
|
-
/* @__PURE__ */
|
|
776
|
-
title ? /* @__PURE__ */
|
|
777
|
-
children ? /* @__PURE__ */
|
|
1636
|
+
icon ? /* @__PURE__ */ jsx18("span", { className: "mt-0.5 shrink-0 text-muted-foreground", children: icon }) : null,
|
|
1637
|
+
/* @__PURE__ */ jsxs14("div", { className: "min-w-0 flex-1", children: [
|
|
1638
|
+
title ? /* @__PURE__ */ jsx18("p", { className: "text-sm font-medium text-foreground", children: title }) : null,
|
|
1639
|
+
children ? /* @__PURE__ */ jsx18("div", { className: cn("text-sm text-muted-foreground", title && "mt-1"), children }) : null
|
|
778
1640
|
] }),
|
|
779
|
-
action ? /* @__PURE__ */
|
|
1641
|
+
action ? /* @__PURE__ */ jsx18("div", { className: "shrink-0", children: action }) : null
|
|
780
1642
|
]
|
|
781
1643
|
}
|
|
782
1644
|
);
|
|
783
1645
|
|
|
784
1646
|
// src/app/surfaces/StatusDot.tsx
|
|
785
|
-
import { jsx as
|
|
1647
|
+
import { jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
786
1648
|
var dotClass = {
|
|
787
1649
|
online: "bg-emerald-500",
|
|
788
1650
|
busy: "bg-amber-500",
|
|
@@ -795,9 +1657,9 @@ var StatusDot = ({
|
|
|
795
1657
|
label,
|
|
796
1658
|
pulse = false,
|
|
797
1659
|
className
|
|
798
|
-
}) => /* @__PURE__ */
|
|
799
|
-
/* @__PURE__ */
|
|
800
|
-
pulse ? /* @__PURE__ */
|
|
1660
|
+
}) => /* @__PURE__ */ jsxs15("span", { className: cn("inline-flex items-center gap-1.5", className), children: [
|
|
1661
|
+
/* @__PURE__ */ jsxs15("span", { className: "relative flex size-2", children: [
|
|
1662
|
+
pulse ? /* @__PURE__ */ jsx19(
|
|
801
1663
|
"span",
|
|
802
1664
|
{
|
|
803
1665
|
className: cn(
|
|
@@ -806,25 +1668,25 @@ var StatusDot = ({
|
|
|
806
1668
|
)
|
|
807
1669
|
}
|
|
808
1670
|
) : null,
|
|
809
|
-
/* @__PURE__ */
|
|
1671
|
+
/* @__PURE__ */ jsx19("span", { className: cn("relative inline-flex size-2 rounded-full", dotClass[tone]) })
|
|
810
1672
|
] }),
|
|
811
|
-
label ? /* @__PURE__ */
|
|
1673
|
+
label ? /* @__PURE__ */ jsx19("span", { className: "text-xs text-muted-foreground", children: label }) : null
|
|
812
1674
|
] });
|
|
813
1675
|
|
|
814
1676
|
// src/app/surfaces/DescriptionList.tsx
|
|
815
|
-
import { jsx as
|
|
1677
|
+
import { jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
816
1678
|
var DescriptionList = ({
|
|
817
1679
|
items,
|
|
818
1680
|
stacked = false,
|
|
819
1681
|
className
|
|
820
|
-
}) => /* @__PURE__ */
|
|
1682
|
+
}) => /* @__PURE__ */ jsx20(
|
|
821
1683
|
"dl",
|
|
822
1684
|
{
|
|
823
1685
|
className: cn(
|
|
824
1686
|
"divide-y divide-border rounded-xl border border-border bg-card",
|
|
825
1687
|
className
|
|
826
1688
|
),
|
|
827
|
-
children: items.map((item, i) => /* @__PURE__ */
|
|
1689
|
+
children: items.map((item, i) => /* @__PURE__ */ jsxs16(
|
|
828
1690
|
"div",
|
|
829
1691
|
{
|
|
830
1692
|
className: cn(
|
|
@@ -832,8 +1694,8 @@ var DescriptionList = ({
|
|
|
832
1694
|
stacked ? "flex flex-col gap-0.5" : "flex items-center justify-between gap-4"
|
|
833
1695
|
),
|
|
834
1696
|
children: [
|
|
835
|
-
/* @__PURE__ */
|
|
836
|
-
/* @__PURE__ */
|
|
1697
|
+
/* @__PURE__ */ jsx20("dt", { className: "text-sm text-muted-foreground", children: item.label }),
|
|
1698
|
+
/* @__PURE__ */ jsx20(
|
|
837
1699
|
"dd",
|
|
838
1700
|
{
|
|
839
1701
|
className: cn(
|
|
@@ -853,8 +1715,8 @@ var DescriptionList = ({
|
|
|
853
1715
|
// src/app/surfaces/ExpandableSection.tsx
|
|
854
1716
|
import { useId, useState as useState2 } from "react";
|
|
855
1717
|
import { AnimatePresence, motion as motion2, useReducedMotion as useReducedMotion2 } from "motion/react";
|
|
856
|
-
import { jsx as
|
|
857
|
-
var Chevron = ({ open }) => /* @__PURE__ */
|
|
1718
|
+
import { jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1719
|
+
var Chevron = ({ open }) => /* @__PURE__ */ jsx21(
|
|
858
1720
|
"svg",
|
|
859
1721
|
{
|
|
860
1722
|
viewBox: "0 0 24 24",
|
|
@@ -868,7 +1730,7 @@ var Chevron = ({ open }) => /* @__PURE__ */ jsx17(
|
|
|
868
1730
|
strokeLinecap: "round",
|
|
869
1731
|
strokeLinejoin: "round",
|
|
870
1732
|
"aria-hidden": true,
|
|
871
|
-
children: /* @__PURE__ */
|
|
1733
|
+
children: /* @__PURE__ */ jsx21("path", { d: "m6 9 6 6 6-6" })
|
|
872
1734
|
}
|
|
873
1735
|
);
|
|
874
1736
|
var ExpandableSection = ({
|
|
@@ -889,8 +1751,8 @@ var ExpandableSection = ({
|
|
|
889
1751
|
if (openProp == null) setInternalOpen((o) => !o);
|
|
890
1752
|
onOpenChange?.(!open);
|
|
891
1753
|
};
|
|
892
|
-
return /* @__PURE__ */
|
|
893
|
-
/* @__PURE__ */
|
|
1754
|
+
return /* @__PURE__ */ jsxs17("div", { className: cn("border-b border-border last:border-0", className), children: [
|
|
1755
|
+
/* @__PURE__ */ jsxs17(
|
|
894
1756
|
"button",
|
|
895
1757
|
{
|
|
896
1758
|
type: "button",
|
|
@@ -899,16 +1761,16 @@ var ExpandableSection = ({
|
|
|
899
1761
|
"aria-controls": panelId,
|
|
900
1762
|
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",
|
|
901
1763
|
children: [
|
|
902
|
-
/* @__PURE__ */
|
|
903
|
-
icon ? /* @__PURE__ */
|
|
904
|
-
/* @__PURE__ */
|
|
905
|
-
count != null ? /* @__PURE__ */
|
|
1764
|
+
/* @__PURE__ */ jsxs17("span", { className: "flex min-w-0 items-center gap-3", children: [
|
|
1765
|
+
icon ? /* @__PURE__ */ jsx21("span", { className: "flex size-8 items-center justify-center rounded-lg border border-border bg-muted text-muted-foreground", children: icon }) : null,
|
|
1766
|
+
/* @__PURE__ */ jsx21("span", { className: "truncate text-sm font-medium text-foreground", children: title }),
|
|
1767
|
+
count != null ? /* @__PURE__ */ jsx21("span", { className: "rounded-full border border-border bg-muted px-2 py-0.5 text-xs text-muted-foreground", children: count }) : null
|
|
906
1768
|
] }),
|
|
907
|
-
/* @__PURE__ */
|
|
1769
|
+
/* @__PURE__ */ jsx21(Chevron, { open })
|
|
908
1770
|
]
|
|
909
1771
|
}
|
|
910
1772
|
),
|
|
911
|
-
/* @__PURE__ */
|
|
1773
|
+
/* @__PURE__ */ jsx21(AnimatePresence, { initial: false, children: open ? /* @__PURE__ */ jsx21(
|
|
912
1774
|
motion2.div,
|
|
913
1775
|
{
|
|
914
1776
|
id: panelId,
|
|
@@ -917,7 +1779,7 @@ var ExpandableSection = ({
|
|
|
917
1779
|
exit: reduceMotion ? void 0 : { height: 0, opacity: 0 },
|
|
918
1780
|
transition: { duration: 0.2, ease: "easeOut" },
|
|
919
1781
|
className: "overflow-hidden",
|
|
920
|
-
children: /* @__PURE__ */
|
|
1782
|
+
children: /* @__PURE__ */ jsx21("div", { className: "bg-muted/20", children })
|
|
921
1783
|
},
|
|
922
1784
|
"body"
|
|
923
1785
|
) : null })
|
|
@@ -925,7 +1787,7 @@ var ExpandableSection = ({
|
|
|
925
1787
|
};
|
|
926
1788
|
|
|
927
1789
|
// src/app/surfaces/ResourceCard.tsx
|
|
928
|
-
import { Fragment, jsx as
|
|
1790
|
+
import { Fragment as Fragment3, jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
929
1791
|
var resourceCardShellClass = cn(
|
|
930
1792
|
"flex min-h-[8.5rem] flex-col rounded-2xl p-4 text-left font-normal",
|
|
931
1793
|
TIMBAL_V2_ELEVATED_SURFACE
|
|
@@ -950,35 +1812,35 @@ var ResourceCard = ({
|
|
|
950
1812
|
ariaLabel,
|
|
951
1813
|
className
|
|
952
1814
|
}) => {
|
|
953
|
-
const body = /* @__PURE__ */
|
|
954
|
-
/* @__PURE__ */
|
|
955
|
-
media ? /* @__PURE__ */
|
|
956
|
-
/* @__PURE__ */
|
|
957
|
-
/* @__PURE__ */
|
|
958
|
-
subtitle ? /* @__PURE__ */
|
|
1815
|
+
const body = /* @__PURE__ */ jsxs18(Fragment3, { children: [
|
|
1816
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex items-start gap-3", children: [
|
|
1817
|
+
media ? /* @__PURE__ */ jsx22("span", { className: mediaShellClass, children: media }) : null,
|
|
1818
|
+
/* @__PURE__ */ jsxs18("div", { className: "min-w-0 flex-1 pt-0.5", children: [
|
|
1819
|
+
/* @__PURE__ */ jsx22("p", { className: "truncate text-sm font-normal leading-snug text-foreground", children: title }),
|
|
1820
|
+
subtitle ? /* @__PURE__ */ jsx22("p", { className: "mt-1 line-clamp-2 text-xs font-normal text-muted-foreground", children: subtitle }) : null
|
|
959
1821
|
] }),
|
|
960
|
-
badge ? /* @__PURE__ */
|
|
1822
|
+
badge ? /* @__PURE__ */ jsx22("span", { className: "shrink-0 pt-0.5", children: badge }) : null
|
|
961
1823
|
] }),
|
|
962
|
-
footer || action ? /* @__PURE__ */
|
|
963
|
-
/* @__PURE__ */
|
|
964
|
-
action ? /* @__PURE__ */
|
|
1824
|
+
footer || action ? /* @__PURE__ */ jsxs18("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: [
|
|
1825
|
+
/* @__PURE__ */ jsx22("span", { className: "min-w-0 truncate", children: footer }),
|
|
1826
|
+
action ? /* @__PURE__ */ jsx22("span", { className: "shrink-0 opacity-80", children: action }) : null
|
|
965
1827
|
] }) : null
|
|
966
1828
|
] });
|
|
967
1829
|
if (onClick) {
|
|
968
|
-
return /* @__PURE__ */
|
|
1830
|
+
return /* @__PURE__ */ jsx22("button", { type: "button", onClick, "aria-label": ariaLabel, className: cn(resourceCardInteractiveClass, className), children: body });
|
|
969
1831
|
}
|
|
970
|
-
return /* @__PURE__ */
|
|
1832
|
+
return /* @__PURE__ */ jsx22("article", { className: cn(resourceCardShellClass, className), children: body });
|
|
971
1833
|
};
|
|
972
1834
|
|
|
973
1835
|
// src/app/settings/SettingsSection.tsx
|
|
974
|
-
import { jsx as
|
|
1836
|
+
import { jsx as jsx23, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
975
1837
|
var SettingsSectionHeader = ({
|
|
976
1838
|
title,
|
|
977
1839
|
description,
|
|
978
1840
|
className
|
|
979
|
-
}) => /* @__PURE__ */
|
|
980
|
-
/* @__PURE__ */
|
|
981
|
-
description ? /* @__PURE__ */
|
|
1841
|
+
}) => /* @__PURE__ */ jsxs19("div", { className: cn("flex flex-col", className), children: [
|
|
1842
|
+
/* @__PURE__ */ jsx23("h3", { className: "text-[17px] font-medium leading-tight text-foreground", children: title }),
|
|
1843
|
+
description ? /* @__PURE__ */ jsx23("p", { className: "mt-1 text-sm text-muted-foreground", children: description }) : null
|
|
982
1844
|
] });
|
|
983
1845
|
var SettingsSection = ({
|
|
984
1846
|
title,
|
|
@@ -987,7 +1849,7 @@ var SettingsSection = ({
|
|
|
987
1849
|
children,
|
|
988
1850
|
noBorderTop = false,
|
|
989
1851
|
className
|
|
990
|
-
}) => /* @__PURE__ */
|
|
1852
|
+
}) => /* @__PURE__ */ jsxs19(
|
|
991
1853
|
"section",
|
|
992
1854
|
{
|
|
993
1855
|
className: cn(
|
|
@@ -996,18 +1858,18 @@ var SettingsSection = ({
|
|
|
996
1858
|
className
|
|
997
1859
|
),
|
|
998
1860
|
children: [
|
|
999
|
-
/* @__PURE__ */
|
|
1000
|
-
/* @__PURE__ */
|
|
1001
|
-
description ? /* @__PURE__ */
|
|
1002
|
-
descriptionFooter ? /* @__PURE__ */
|
|
1861
|
+
/* @__PURE__ */ jsxs19("div", { className: "min-w-0", children: [
|
|
1862
|
+
/* @__PURE__ */ jsx23("h2", { className: "text-sm font-medium text-foreground", children: title }),
|
|
1863
|
+
description ? /* @__PURE__ */ jsx23("p", { className: "mt-1 text-sm text-muted-foreground", children: description }) : null,
|
|
1864
|
+
descriptionFooter ? /* @__PURE__ */ jsx23("div", { className: "mt-3 min-w-0", children: descriptionFooter }) : null
|
|
1003
1865
|
] }),
|
|
1004
|
-
/* @__PURE__ */
|
|
1866
|
+
/* @__PURE__ */ jsx23("div", { className: "min-w-0 space-y-3", children })
|
|
1005
1867
|
]
|
|
1006
1868
|
}
|
|
1007
1869
|
);
|
|
1008
1870
|
|
|
1009
1871
|
// src/app/settings/FieldRow.tsx
|
|
1010
|
-
import { jsx as
|
|
1872
|
+
import { jsx as jsx24, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1011
1873
|
var FieldRow = ({
|
|
1012
1874
|
label,
|
|
1013
1875
|
children,
|
|
@@ -1017,7 +1879,7 @@ var FieldRow = ({
|
|
|
1017
1879
|
className
|
|
1018
1880
|
}) => {
|
|
1019
1881
|
if (inline) {
|
|
1020
|
-
return /* @__PURE__ */
|
|
1882
|
+
return /* @__PURE__ */ jsxs20(
|
|
1021
1883
|
"div",
|
|
1022
1884
|
{
|
|
1023
1885
|
className: cn(
|
|
@@ -1025,8 +1887,8 @@ var FieldRow = ({
|
|
|
1025
1887
|
className
|
|
1026
1888
|
),
|
|
1027
1889
|
children: [
|
|
1028
|
-
/* @__PURE__ */
|
|
1029
|
-
/* @__PURE__ */
|
|
1890
|
+
/* @__PURE__ */ jsxs20("div", { className: "min-w-0", children: [
|
|
1891
|
+
/* @__PURE__ */ jsx24(
|
|
1030
1892
|
"label",
|
|
1031
1893
|
{
|
|
1032
1894
|
htmlFor,
|
|
@@ -1034,17 +1896,17 @@ var FieldRow = ({
|
|
|
1034
1896
|
children: label
|
|
1035
1897
|
}
|
|
1036
1898
|
),
|
|
1037
|
-
description ? /* @__PURE__ */
|
|
1899
|
+
description ? /* @__PURE__ */ jsx24("p", { className: "mt-0.5 text-xs text-muted-foreground", children: description }) : null
|
|
1038
1900
|
] }),
|
|
1039
|
-
/* @__PURE__ */
|
|
1901
|
+
/* @__PURE__ */ jsx24("div", { className: "shrink-0", children })
|
|
1040
1902
|
]
|
|
1041
1903
|
}
|
|
1042
1904
|
);
|
|
1043
1905
|
}
|
|
1044
|
-
return /* @__PURE__ */
|
|
1045
|
-
/* @__PURE__ */
|
|
1906
|
+
return /* @__PURE__ */ jsxs20("div", { className: cn("flex flex-col gap-1.5", className), children: [
|
|
1907
|
+
/* @__PURE__ */ jsx24("label", { htmlFor, className: "text-sm font-medium text-foreground", children: label }),
|
|
1046
1908
|
children,
|
|
1047
|
-
description ? /* @__PURE__ */
|
|
1909
|
+
description ? /* @__PURE__ */ jsx24("p", { className: "text-xs text-muted-foreground", children: description }) : null
|
|
1048
1910
|
] });
|
|
1049
1911
|
};
|
|
1050
1912
|
|
|
@@ -1052,7 +1914,7 @@ var FieldRow = ({
|
|
|
1052
1914
|
import { useEffect, useState as useState3 } from "react";
|
|
1053
1915
|
import { createPortal } from "react-dom";
|
|
1054
1916
|
import { AnimatePresence as AnimatePresence2, motion as motion3, useReducedMotion as useReducedMotion3 } from "motion/react";
|
|
1055
|
-
import { jsx as
|
|
1917
|
+
import { jsx as jsx25, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1056
1918
|
var FloatingUnsavedChangesBar = ({
|
|
1057
1919
|
visible,
|
|
1058
1920
|
message = "Unsaved changes",
|
|
@@ -1070,7 +1932,7 @@ var FloatingUnsavedChangesBar = ({
|
|
|
1070
1932
|
useEffect(() => setMounted(true), []);
|
|
1071
1933
|
if (!mounted || typeof document === "undefined") return null;
|
|
1072
1934
|
return createPortal(
|
|
1073
|
-
/* @__PURE__ */
|
|
1935
|
+
/* @__PURE__ */ jsx25(AnimatePresence2, { children: visible ? /* @__PURE__ */ jsx25("div", { className: "pointer-events-none fixed inset-x-0 bottom-5 z-50 flex justify-center px-4", children: /* @__PURE__ */ jsxs21(
|
|
1074
1936
|
motion3.div,
|
|
1075
1937
|
{
|
|
1076
1938
|
role: "region",
|
|
@@ -1084,10 +1946,10 @@ var FloatingUnsavedChangesBar = ({
|
|
|
1084
1946
|
className
|
|
1085
1947
|
),
|
|
1086
1948
|
children: [
|
|
1087
|
-
/* @__PURE__ */
|
|
1088
|
-
/* @__PURE__ */
|
|
1089
|
-
/* @__PURE__ */
|
|
1090
|
-
/* @__PURE__ */
|
|
1949
|
+
/* @__PURE__ */ jsx25("span", { className: "text-sm text-muted-foreground", children: message }),
|
|
1950
|
+
/* @__PURE__ */ jsxs21("span", { className: "flex items-center gap-1.5", children: [
|
|
1951
|
+
/* @__PURE__ */ jsx25(Button, { variant: "ghost", size: "sm", onClick: onDiscard, disabled: isSaving, children: discardLabel }),
|
|
1952
|
+
/* @__PURE__ */ jsx25(Button, { size: "sm", onClick: onSave, disabled: saveDisabled || isSaving, children: isSaving ? "Saving\u2026" : saveLabel })
|
|
1091
1953
|
] })
|
|
1092
1954
|
]
|
|
1093
1955
|
}
|
|
@@ -1097,13 +1959,13 @@ var FloatingUnsavedChangesBar = ({
|
|
|
1097
1959
|
};
|
|
1098
1960
|
|
|
1099
1961
|
// src/app/settings/DangerZone.tsx
|
|
1100
|
-
import { jsx as
|
|
1962
|
+
import { jsx as jsx26, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1101
1963
|
var DangerZoneAction = ({
|
|
1102
1964
|
title,
|
|
1103
1965
|
description,
|
|
1104
1966
|
action,
|
|
1105
1967
|
className
|
|
1106
|
-
}) => /* @__PURE__ */
|
|
1968
|
+
}) => /* @__PURE__ */ jsxs22(
|
|
1107
1969
|
"div",
|
|
1108
1970
|
{
|
|
1109
1971
|
className: cn(
|
|
@@ -1111,11 +1973,11 @@ var DangerZoneAction = ({
|
|
|
1111
1973
|
className
|
|
1112
1974
|
),
|
|
1113
1975
|
children: [
|
|
1114
|
-
/* @__PURE__ */
|
|
1115
|
-
/* @__PURE__ */
|
|
1116
|
-
description ? /* @__PURE__ */
|
|
1976
|
+
/* @__PURE__ */ jsxs22("div", { className: "min-w-0", children: [
|
|
1977
|
+
/* @__PURE__ */ jsx26("p", { className: "text-sm font-medium text-foreground", children: title }),
|
|
1978
|
+
description ? /* @__PURE__ */ jsx26("p", { className: "mt-0.5 text-sm text-muted-foreground", children: description }) : null
|
|
1117
1979
|
] }),
|
|
1118
|
-
/* @__PURE__ */
|
|
1980
|
+
/* @__PURE__ */ jsx26("div", { className: "shrink-0", children: action })
|
|
1119
1981
|
]
|
|
1120
1982
|
}
|
|
1121
1983
|
);
|
|
@@ -1124,7 +1986,7 @@ var DangerZone = ({
|
|
|
1124
1986
|
description,
|
|
1125
1987
|
children,
|
|
1126
1988
|
className
|
|
1127
|
-
}) => /* @__PURE__ */
|
|
1989
|
+
}) => /* @__PURE__ */ jsxs22(
|
|
1128
1990
|
"section",
|
|
1129
1991
|
{
|
|
1130
1992
|
className: cn(
|
|
@@ -1132,18 +1994,18 @@ var DangerZone = ({
|
|
|
1132
1994
|
className
|
|
1133
1995
|
),
|
|
1134
1996
|
children: [
|
|
1135
|
-
(title || description) && /* @__PURE__ */
|
|
1136
|
-
title ? /* @__PURE__ */
|
|
1137
|
-
description ? /* @__PURE__ */
|
|
1997
|
+
(title || description) && /* @__PURE__ */ jsxs22("header", { className: "border-b border-destructive/20 bg-destructive/5 px-4 py-3", children: [
|
|
1998
|
+
title ? /* @__PURE__ */ jsx26("h3", { className: "text-sm font-semibold text-destructive", children: title }) : null,
|
|
1999
|
+
description ? /* @__PURE__ */ jsx26("p", { className: "mt-0.5 text-sm text-muted-foreground", children: description }) : null
|
|
1138
2000
|
] }),
|
|
1139
|
-
/* @__PURE__ */
|
|
2001
|
+
/* @__PURE__ */ jsx26("div", { className: "divide-y divide-border bg-card", children })
|
|
1140
2002
|
]
|
|
1141
2003
|
}
|
|
1142
2004
|
);
|
|
1143
2005
|
|
|
1144
2006
|
// src/app/integrations/IntegrationCard.tsx
|
|
1145
2007
|
import { useId as useId2 } from "react";
|
|
1146
|
-
import { Fragment as
|
|
2008
|
+
import { Fragment as Fragment4, jsx as jsx27, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
1147
2009
|
var INTEGRATION_CATALOG_CARD_HEIGHT_CLASS = "h-[12.25rem] min-h-[12.25rem] max-h-[12.25rem]";
|
|
1148
2010
|
var statusLabel = {
|
|
1149
2011
|
available: null,
|
|
@@ -1184,12 +2046,12 @@ var IntegrationCard = ({
|
|
|
1184
2046
|
const titleId = useId2();
|
|
1185
2047
|
const locked = status === "locked";
|
|
1186
2048
|
const dimmed = status === "disabled" || locked;
|
|
1187
|
-
const body = /* @__PURE__ */
|
|
1188
|
-
/* @__PURE__ */
|
|
1189
|
-
logo ? /* @__PURE__ */
|
|
1190
|
-
/* @__PURE__ */
|
|
1191
|
-
/* @__PURE__ */
|
|
1192
|
-
/* @__PURE__ */
|
|
2049
|
+
const body = /* @__PURE__ */ jsxs23("div", { className: "flex h-full min-h-0 flex-col", children: [
|
|
2050
|
+
/* @__PURE__ */ jsxs23("div", { className: "flex shrink-0 items-start gap-3 pr-2", children: [
|
|
2051
|
+
logo ? /* @__PURE__ */ jsx27("span", { className: logoShellClass, "aria-hidden": Boolean(ariaLabel), children: logo }) : null,
|
|
2052
|
+
/* @__PURE__ */ jsx27("div", { className: "min-w-0 flex-1 pt-0.5", children: /* @__PURE__ */ jsxs23("div", { className: "flex items-start justify-between gap-2", children: [
|
|
2053
|
+
/* @__PURE__ */ jsxs23("div", { className: "min-w-0", children: [
|
|
2054
|
+
/* @__PURE__ */ jsx27(
|
|
1193
2055
|
"h4",
|
|
1194
2056
|
{
|
|
1195
2057
|
id: onClick && !action ? void 0 : titleId,
|
|
@@ -1197,12 +2059,12 @@ var IntegrationCard = ({
|
|
|
1197
2059
|
children: name
|
|
1198
2060
|
}
|
|
1199
2061
|
),
|
|
1200
|
-
statusLabel[status] ? /* @__PURE__ */
|
|
2062
|
+
statusLabel[status] ? /* @__PURE__ */ jsx27("p", { className: "mt-0.5 text-xs text-muted-foreground", children: statusLabel[status] }) : null
|
|
1201
2063
|
] }),
|
|
1202
|
-
badge ? /* @__PURE__ */
|
|
2064
|
+
badge ? /* @__PURE__ */ jsx27("span", { className: "shrink-0", children: badge }) : null
|
|
1203
2065
|
] }) })
|
|
1204
2066
|
] }),
|
|
1205
|
-
description ? /* @__PURE__ */
|
|
2067
|
+
description ? /* @__PURE__ */ jsx27(
|
|
1206
2068
|
"p",
|
|
1207
2069
|
{
|
|
1208
2070
|
className: cn(
|
|
@@ -1212,9 +2074,9 @@ var IntegrationCard = ({
|
|
|
1212
2074
|
children: description
|
|
1213
2075
|
}
|
|
1214
2076
|
) : null,
|
|
1215
|
-
action ? /* @__PURE__ */
|
|
1216
|
-
/* @__PURE__ */
|
|
1217
|
-
/* @__PURE__ */
|
|
2077
|
+
action ? /* @__PURE__ */ jsxs23(Fragment4, { children: [
|
|
2078
|
+
/* @__PURE__ */ jsx27("div", { className: "min-h-0 flex-1", "aria-hidden": true }),
|
|
2079
|
+
/* @__PURE__ */ jsx27("div", { className: "relative mt-3 shrink-0", children: action })
|
|
1218
2080
|
] }) : null
|
|
1219
2081
|
] });
|
|
1220
2082
|
const shellClass3 = cn(
|
|
@@ -1224,7 +2086,7 @@ var IntegrationCard = ({
|
|
|
1224
2086
|
className
|
|
1225
2087
|
);
|
|
1226
2088
|
if (onClick && !action) {
|
|
1227
|
-
return /* @__PURE__ */
|
|
2089
|
+
return /* @__PURE__ */ jsx27(
|
|
1228
2090
|
"button",
|
|
1229
2091
|
{
|
|
1230
2092
|
type: "button",
|
|
@@ -1241,12 +2103,12 @@ var IntegrationCard = ({
|
|
|
1241
2103
|
}
|
|
1242
2104
|
);
|
|
1243
2105
|
}
|
|
1244
|
-
return /* @__PURE__ */
|
|
2106
|
+
return /* @__PURE__ */ jsx27("article", { className: shellClass3, "aria-labelledby": titleId, children: body });
|
|
1245
2107
|
};
|
|
1246
2108
|
|
|
1247
2109
|
// src/app/integrations/IntegrationsEmptyState.tsx
|
|
1248
2110
|
import { useId as useId3 } from "react";
|
|
1249
|
-
import { jsx as
|
|
2111
|
+
import { jsx as jsx28, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
1250
2112
|
var IntegrationsEmptyState = ({
|
|
1251
2113
|
title = "No integrations yet",
|
|
1252
2114
|
description = "Connect a provider to start syncing data and powering your workforce.",
|
|
@@ -1255,7 +2117,7 @@ var IntegrationsEmptyState = ({
|
|
|
1255
2117
|
className
|
|
1256
2118
|
}) => {
|
|
1257
2119
|
const titleId = useId3();
|
|
1258
|
-
return /* @__PURE__ */
|
|
2120
|
+
return /* @__PURE__ */ jsxs24(
|
|
1259
2121
|
"section",
|
|
1260
2122
|
{
|
|
1261
2123
|
className: cn(
|
|
@@ -1265,7 +2127,7 @@ var IntegrationsEmptyState = ({
|
|
|
1265
2127
|
),
|
|
1266
2128
|
"aria-labelledby": titleId,
|
|
1267
2129
|
children: [
|
|
1268
|
-
icon ? /* @__PURE__ */
|
|
2130
|
+
icon ? /* @__PURE__ */ jsx28(
|
|
1269
2131
|
"span",
|
|
1270
2132
|
{
|
|
1271
2133
|
className: cn(
|
|
@@ -1277,21 +2139,21 @@ var IntegrationsEmptyState = ({
|
|
|
1277
2139
|
children: icon
|
|
1278
2140
|
}
|
|
1279
2141
|
) : null,
|
|
1280
|
-
/* @__PURE__ */
|
|
1281
|
-
description ? /* @__PURE__ */
|
|
1282
|
-
action ? /* @__PURE__ */
|
|
2142
|
+
/* @__PURE__ */ jsx28("h3", { id: titleId, className: "text-base font-normal text-foreground", children: title }),
|
|
2143
|
+
description ? /* @__PURE__ */ jsx28("p", { className: "max-w-sm text-sm text-muted-foreground", children: description }) : null,
|
|
2144
|
+
action ? /* @__PURE__ */ jsx28("div", { className: "mt-1", children: action }) : null
|
|
1283
2145
|
]
|
|
1284
2146
|
}
|
|
1285
2147
|
);
|
|
1286
2148
|
};
|
|
1287
2149
|
|
|
1288
2150
|
// src/app/integrations/PlanBadge.tsx
|
|
1289
|
-
import { jsx as
|
|
2151
|
+
import { jsx as jsx29 } from "react/jsx-runtime";
|
|
1290
2152
|
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";
|
|
1291
|
-
var PlanBadge = ({ children, className }) => /* @__PURE__ */
|
|
2153
|
+
var PlanBadge = ({ children, className }) => /* @__PURE__ */ jsx29("span", { className: cn(planBadgeClass, className), children });
|
|
1292
2154
|
|
|
1293
2155
|
// src/app/integrations/ConnectionRow.tsx
|
|
1294
|
-
import { Fragment as
|
|
2156
|
+
import { Fragment as Fragment5, jsx as jsx30, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
1295
2157
|
var logoShellClass2 = cn(
|
|
1296
2158
|
"flex size-9 shrink-0 items-center justify-center overflow-hidden rounded-lg",
|
|
1297
2159
|
TIMBAL_V2_LOGO_TILE
|
|
@@ -1306,14 +2168,14 @@ var ConnectionRow = ({
|
|
|
1306
2168
|
ariaLabel,
|
|
1307
2169
|
className
|
|
1308
2170
|
}) => {
|
|
1309
|
-
const inner = /* @__PURE__ */
|
|
1310
|
-
logo ? /* @__PURE__ */
|
|
1311
|
-
/* @__PURE__ */
|
|
1312
|
-
/* @__PURE__ */
|
|
1313
|
-
meta ? /* @__PURE__ */
|
|
2171
|
+
const inner = /* @__PURE__ */ jsxs25(Fragment5, { children: [
|
|
2172
|
+
logo ? /* @__PURE__ */ jsx30("span", { className: logoShellClass2, children: logo }) : null,
|
|
2173
|
+
/* @__PURE__ */ jsxs25("div", { className: "min-w-0 flex-1", children: [
|
|
2174
|
+
/* @__PURE__ */ jsx30("p", { className: "truncate text-sm font-normal text-foreground", children: name }),
|
|
2175
|
+
meta ? /* @__PURE__ */ jsx30("p", { className: "truncate text-xs text-muted-foreground", children: meta }) : null
|
|
1314
2176
|
] }),
|
|
1315
|
-
badge ? /* @__PURE__ */
|
|
1316
|
-
action ? /* @__PURE__ */
|
|
2177
|
+
badge ? /* @__PURE__ */ jsx30("span", { className: "shrink-0", children: badge }) : null,
|
|
2178
|
+
action ? /* @__PURE__ */ jsx30("span", { className: "shrink-0", children: action }) : null
|
|
1317
2179
|
] });
|
|
1318
2180
|
const rowClass2 = cn(
|
|
1319
2181
|
"flex w-full items-center gap-3 px-4 py-3 text-left",
|
|
@@ -1321,7 +2183,7 @@ var ConnectionRow = ({
|
|
|
1321
2183
|
className
|
|
1322
2184
|
);
|
|
1323
2185
|
if (onClick) {
|
|
1324
|
-
return /* @__PURE__ */
|
|
2186
|
+
return /* @__PURE__ */ jsx30(
|
|
1325
2187
|
"button",
|
|
1326
2188
|
{
|
|
1327
2189
|
type: "button",
|
|
@@ -1333,7 +2195,7 @@ var ConnectionRow = ({
|
|
|
1333
2195
|
}
|
|
1334
2196
|
);
|
|
1335
2197
|
}
|
|
1336
|
-
return /* @__PURE__ */
|
|
2198
|
+
return /* @__PURE__ */ jsx30("div", { role: "listitem", className: rowClass2, children: inner });
|
|
1337
2199
|
};
|
|
1338
2200
|
var connectionRowListClass = cn(
|
|
1339
2201
|
"overflow-hidden rounded-2xl",
|
|
@@ -1341,12 +2203,12 @@ var connectionRowListClass = cn(
|
|
|
1341
2203
|
);
|
|
1342
2204
|
|
|
1343
2205
|
// src/app/integrations/ConnectionRowList.tsx
|
|
1344
|
-
import { jsx as
|
|
2206
|
+
import { jsx as jsx31 } from "react/jsx-runtime";
|
|
1345
2207
|
var ConnectionRowList = ({
|
|
1346
2208
|
children,
|
|
1347
2209
|
"aria-label": ariaLabel = "Connected integrations",
|
|
1348
2210
|
className
|
|
1349
|
-
}) => /* @__PURE__ */
|
|
2211
|
+
}) => /* @__PURE__ */ jsx31(
|
|
1350
2212
|
"div",
|
|
1351
2213
|
{
|
|
1352
2214
|
role: "list",
|
|
@@ -1357,7 +2219,7 @@ var ConnectionRowList = ({
|
|
|
1357
2219
|
);
|
|
1358
2220
|
|
|
1359
2221
|
// src/app/navigation/SubNav.tsx
|
|
1360
|
-
import { jsx as
|
|
2222
|
+
import { jsx as jsx32 } from "react/jsx-runtime";
|
|
1361
2223
|
var SubNav = ({
|
|
1362
2224
|
items,
|
|
1363
2225
|
activeId,
|
|
@@ -1366,7 +2228,7 @@ var SubNav = ({
|
|
|
1366
2228
|
"aria-label": ariaLabel = "Section navigation",
|
|
1367
2229
|
layoutId
|
|
1368
2230
|
}) => {
|
|
1369
|
-
return /* @__PURE__ */
|
|
2231
|
+
return /* @__PURE__ */ jsx32("nav", { className: cn("aui-app-sub-nav", className), "aria-label": ariaLabel, children: /* @__PURE__ */ jsx32(
|
|
1370
2232
|
PillSegmentedTabs,
|
|
1371
2233
|
{
|
|
1372
2234
|
value: activeId,
|
|
@@ -1380,13 +2242,13 @@ var SubNav = ({
|
|
|
1380
2242
|
};
|
|
1381
2243
|
|
|
1382
2244
|
// src/app/navigation/Breadcrumbs.tsx
|
|
1383
|
-
import { jsx as
|
|
2245
|
+
import { jsx as jsx33, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
1384
2246
|
var Breadcrumbs = ({ items, className }) => {
|
|
1385
|
-
return /* @__PURE__ */
|
|
2247
|
+
return /* @__PURE__ */ jsx33("nav", { className: cn("aui-app-breadcrumbs", appBreadcrumbsClass, className), "aria-label": "Breadcrumb", children: /* @__PURE__ */ jsx33("ol", { className: "flex flex-wrap items-center gap-1.5", children: items.map((item, index) => {
|
|
1386
2248
|
const isLast = index === items.length - 1;
|
|
1387
|
-
return /* @__PURE__ */
|
|
1388
|
-
index > 0 ? /* @__PURE__ */
|
|
1389
|
-
isLast ? /* @__PURE__ */
|
|
2249
|
+
return /* @__PURE__ */ jsxs26("li", { className: "inline-flex items-center gap-1.5", children: [
|
|
2250
|
+
index > 0 ? /* @__PURE__ */ jsx33("span", { className: "text-muted-foreground/50", "aria-hidden": true, children: "/" }) : null,
|
|
2251
|
+
isLast ? /* @__PURE__ */ jsx33("span", { className: "text-foreground", "aria-current": "page", children: item.label }) : item.href ? /* @__PURE__ */ jsx33("a", { href: item.href, className: appBreadcrumbLinkClass, children: item.label }) : /* @__PURE__ */ jsx33(
|
|
1390
2252
|
"button",
|
|
1391
2253
|
{
|
|
1392
2254
|
type: "button",
|
|
@@ -1400,7 +2262,7 @@ var Breadcrumbs = ({ items, className }) => {
|
|
|
1400
2262
|
};
|
|
1401
2263
|
|
|
1402
2264
|
// src/app/forms/Field.tsx
|
|
1403
|
-
import { jsx as
|
|
2265
|
+
import { jsx as jsx34, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
1404
2266
|
var Field = ({
|
|
1405
2267
|
label,
|
|
1406
2268
|
hint,
|
|
@@ -1409,11 +2271,11 @@ var Field = ({
|
|
|
1409
2271
|
className,
|
|
1410
2272
|
htmlFor
|
|
1411
2273
|
}) => {
|
|
1412
|
-
return /* @__PURE__ */
|
|
1413
|
-
/* @__PURE__ */
|
|
2274
|
+
return /* @__PURE__ */ jsxs27("div", { className: cn("aui-app-field", appFieldClass, className), children: [
|
|
2275
|
+
/* @__PURE__ */ jsx34("label", { className: appFieldLabelClass, htmlFor, children: label }),
|
|
1414
2276
|
children,
|
|
1415
|
-
hint && !error ? /* @__PURE__ */
|
|
1416
|
-
error ? /* @__PURE__ */
|
|
2277
|
+
hint && !error ? /* @__PURE__ */ jsx34("p", { className: appFieldHintClass, children: hint }) : null,
|
|
2278
|
+
error ? /* @__PURE__ */ jsx34("p", { className: "text-xs text-destructive", role: "alert", children: error }) : null
|
|
1417
2279
|
] });
|
|
1418
2280
|
};
|
|
1419
2281
|
var FieldInput = ({
|
|
@@ -1426,7 +2288,7 @@ var FieldInput = ({
|
|
|
1426
2288
|
...inputProps
|
|
1427
2289
|
}) => {
|
|
1428
2290
|
const inputId = id ?? inputProps.name;
|
|
1429
|
-
return /* @__PURE__ */
|
|
2291
|
+
return /* @__PURE__ */ jsx34(
|
|
1430
2292
|
Field,
|
|
1431
2293
|
{
|
|
1432
2294
|
label,
|
|
@@ -1434,7 +2296,7 @@ var FieldInput = ({
|
|
|
1434
2296
|
error,
|
|
1435
2297
|
htmlFor: inputId,
|
|
1436
2298
|
className: fieldClassName,
|
|
1437
|
-
children: /* @__PURE__ */
|
|
2299
|
+
children: /* @__PURE__ */ jsx34(
|
|
1438
2300
|
"input",
|
|
1439
2301
|
{
|
|
1440
2302
|
id: inputId,
|
|
@@ -1448,7 +2310,7 @@ var FieldInput = ({
|
|
|
1448
2310
|
};
|
|
1449
2311
|
|
|
1450
2312
|
// src/app/forms/FieldTextarea.tsx
|
|
1451
|
-
import { jsx as
|
|
2313
|
+
import { jsx as jsx35 } from "react/jsx-runtime";
|
|
1452
2314
|
var textareaClass = cn(
|
|
1453
2315
|
appInputClass,
|
|
1454
2316
|
"min-h-[5.5rem] resize-y py-2.5 leading-relaxed"
|
|
@@ -1463,7 +2325,7 @@ var FieldTextarea = ({
|
|
|
1463
2325
|
...props
|
|
1464
2326
|
}) => {
|
|
1465
2327
|
const textareaId = id ?? props.name;
|
|
1466
|
-
return /* @__PURE__ */
|
|
2328
|
+
return /* @__PURE__ */ jsx35(
|
|
1467
2329
|
Field,
|
|
1468
2330
|
{
|
|
1469
2331
|
label,
|
|
@@ -1471,7 +2333,7 @@ var FieldTextarea = ({
|
|
|
1471
2333
|
error,
|
|
1472
2334
|
htmlFor: textareaId,
|
|
1473
2335
|
className: fieldClassName,
|
|
1474
|
-
children: /* @__PURE__ */
|
|
2336
|
+
children: /* @__PURE__ */ jsx35(
|
|
1475
2337
|
"textarea",
|
|
1476
2338
|
{
|
|
1477
2339
|
id: textareaId,
|
|
@@ -1486,7 +2348,7 @@ var FieldTextarea = ({
|
|
|
1486
2348
|
|
|
1487
2349
|
// src/app/forms/FieldSelect.tsx
|
|
1488
2350
|
import { ChevronDownIcon } from "lucide-react";
|
|
1489
|
-
import { jsx as
|
|
2351
|
+
import { jsx as jsx36, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
1490
2352
|
var selectWrapClass = "relative";
|
|
1491
2353
|
var selectClass = cn(
|
|
1492
2354
|
appInputClass,
|
|
@@ -1503,7 +2365,7 @@ var FieldSelect = ({
|
|
|
1503
2365
|
...props
|
|
1504
2366
|
}) => {
|
|
1505
2367
|
const selectId = id ?? props.name;
|
|
1506
|
-
return /* @__PURE__ */
|
|
2368
|
+
return /* @__PURE__ */ jsx36(
|
|
1507
2369
|
Field,
|
|
1508
2370
|
{
|
|
1509
2371
|
label,
|
|
@@ -1511,8 +2373,8 @@ var FieldSelect = ({
|
|
|
1511
2373
|
error,
|
|
1512
2374
|
htmlFor: selectId,
|
|
1513
2375
|
className: fieldClassName,
|
|
1514
|
-
children: /* @__PURE__ */
|
|
1515
|
-
/* @__PURE__ */
|
|
2376
|
+
children: /* @__PURE__ */ jsxs28("div", { className: selectWrapClass, children: [
|
|
2377
|
+
/* @__PURE__ */ jsx36(
|
|
1516
2378
|
"select",
|
|
1517
2379
|
{
|
|
1518
2380
|
id: selectId,
|
|
@@ -1522,7 +2384,7 @@ var FieldSelect = ({
|
|
|
1522
2384
|
children
|
|
1523
2385
|
}
|
|
1524
2386
|
),
|
|
1525
|
-
/* @__PURE__ */
|
|
2387
|
+
/* @__PURE__ */ jsx36(
|
|
1526
2388
|
ChevronDownIcon,
|
|
1527
2389
|
{
|
|
1528
2390
|
className: "pointer-events-none absolute top-1/2 right-3 size-4 -translate-y-1/2 text-muted-foreground",
|
|
@@ -1535,7 +2397,7 @@ var FieldSelect = ({
|
|
|
1535
2397
|
};
|
|
1536
2398
|
|
|
1537
2399
|
// src/app/forms/FieldSwitch.tsx
|
|
1538
|
-
import { jsx as
|
|
2400
|
+
import { jsx as jsx37, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
1539
2401
|
var trackClass = cn(
|
|
1540
2402
|
"relative inline-flex h-5 w-9 shrink-0 items-center rounded-full transition-[background,box-shadow,border-color] duration-200",
|
|
1541
2403
|
"peer-focus-visible:ring-2 peer-focus-visible:ring-foreground/10",
|
|
@@ -1556,7 +2418,7 @@ var FieldSwitch = ({
|
|
|
1556
2418
|
...props
|
|
1557
2419
|
}) => {
|
|
1558
2420
|
const inputId = id ?? props.name ?? "switch";
|
|
1559
|
-
return /* @__PURE__ */
|
|
2421
|
+
return /* @__PURE__ */ jsxs29(
|
|
1560
2422
|
"label",
|
|
1561
2423
|
{
|
|
1562
2424
|
className: cn(
|
|
@@ -1565,8 +2427,8 @@ var FieldSwitch = ({
|
|
|
1565
2427
|
),
|
|
1566
2428
|
htmlFor: inputId,
|
|
1567
2429
|
children: [
|
|
1568
|
-
/* @__PURE__ */
|
|
1569
|
-
/* @__PURE__ */
|
|
2430
|
+
/* @__PURE__ */ jsxs29("span", { className: "relative mt-0.5", children: [
|
|
2431
|
+
/* @__PURE__ */ jsx37(
|
|
1570
2432
|
"input",
|
|
1571
2433
|
{
|
|
1572
2434
|
id: inputId,
|
|
@@ -1576,11 +2438,11 @@ var FieldSwitch = ({
|
|
|
1576
2438
|
...props
|
|
1577
2439
|
}
|
|
1578
2440
|
),
|
|
1579
|
-
/* @__PURE__ */
|
|
2441
|
+
/* @__PURE__ */ jsx37("span", { className: trackClass, "aria-hidden": true, children: /* @__PURE__ */ jsx37("span", { className: thumbClass }) })
|
|
1580
2442
|
] }),
|
|
1581
|
-
/* @__PURE__ */
|
|
1582
|
-
/* @__PURE__ */
|
|
1583
|
-
description ? /* @__PURE__ */
|
|
2443
|
+
/* @__PURE__ */ jsxs29("span", { className: "flex min-w-0 flex-col gap-0.5", children: [
|
|
2444
|
+
/* @__PURE__ */ jsx37("span", { className: "text-sm font-medium text-foreground", children: label }),
|
|
2445
|
+
description ? /* @__PURE__ */ jsx37("span", { className: "text-xs text-muted-foreground", children: description }) : null
|
|
1584
2446
|
] })
|
|
1585
2447
|
]
|
|
1586
2448
|
}
|
|
@@ -1589,13 +2451,13 @@ var FieldSwitch = ({
|
|
|
1589
2451
|
|
|
1590
2452
|
// src/app/forms/SearchInput.tsx
|
|
1591
2453
|
import { SearchIcon } from "lucide-react";
|
|
1592
|
-
import { jsx as
|
|
2454
|
+
import { jsx as jsx38, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
1593
2455
|
var SearchInput = ({
|
|
1594
2456
|
className,
|
|
1595
2457
|
placeholder = "Search\u2026",
|
|
1596
2458
|
...props
|
|
1597
2459
|
}) => {
|
|
1598
|
-
return /* @__PURE__ */
|
|
2460
|
+
return /* @__PURE__ */ jsxs30(
|
|
1599
2461
|
"label",
|
|
1600
2462
|
{
|
|
1601
2463
|
className: cn(
|
|
@@ -1604,8 +2466,8 @@ var SearchInput = ({
|
|
|
1604
2466
|
className
|
|
1605
2467
|
),
|
|
1606
2468
|
children: [
|
|
1607
|
-
/* @__PURE__ */
|
|
1608
|
-
/* @__PURE__ */
|
|
2469
|
+
/* @__PURE__ */ jsx38(SearchIcon, { className: "size-4 shrink-0 text-muted-foreground", "aria-hidden": true }),
|
|
2470
|
+
/* @__PURE__ */ jsx38(
|
|
1609
2471
|
"input",
|
|
1610
2472
|
{
|
|
1611
2473
|
type: "search",
|
|
@@ -1620,18 +2482,18 @@ var SearchInput = ({
|
|
|
1620
2482
|
};
|
|
1621
2483
|
|
|
1622
2484
|
// src/app/forms/FormSection.tsx
|
|
1623
|
-
import { jsx as
|
|
2485
|
+
import { jsx as jsx39, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
1624
2486
|
var FormSection = ({ title, children, className }) => {
|
|
1625
|
-
return /* @__PURE__ */
|
|
1626
|
-
title ? /* @__PURE__ */
|
|
1627
|
-
/* @__PURE__ */
|
|
2487
|
+
return /* @__PURE__ */ jsxs31("fieldset", { className: cn("aui-app-form-section", appSectionClass, "border-0 p-0", className), children: [
|
|
2488
|
+
title ? /* @__PURE__ */ jsx39("legend", { className: cn(appSectionTitleClass, "mb-3 px-0"), children: title }) : null,
|
|
2489
|
+
/* @__PURE__ */ jsx39("div", { className: "flex flex-col gap-4", children })
|
|
1628
2490
|
] });
|
|
1629
2491
|
};
|
|
1630
2492
|
|
|
1631
2493
|
// src/app/data/FilterBar.tsx
|
|
1632
|
-
import { jsx as
|
|
2494
|
+
import { jsx as jsx40 } from "react/jsx-runtime";
|
|
1633
2495
|
var FilterBar = ({ children, className }) => {
|
|
1634
|
-
return /* @__PURE__ */
|
|
2496
|
+
return /* @__PURE__ */ jsx40(
|
|
1635
2497
|
"div",
|
|
1636
2498
|
{
|
|
1637
2499
|
className: cn("aui-app-filter-bar", appFilterBarClass, className),
|
|
@@ -1645,7 +2507,7 @@ var FilterBar = ({ children, className }) => {
|
|
|
1645
2507
|
// src/app/data/DataTable.tsx
|
|
1646
2508
|
import { useMemo, useState as useState4 } from "react";
|
|
1647
2509
|
import { ArrowDownIcon, ArrowUpDownIcon, ArrowUpIcon } from "lucide-react";
|
|
1648
|
-
import { jsx as
|
|
2510
|
+
import { jsx as jsx41, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
1649
2511
|
var shellClass2 = "overflow-hidden rounded-xl border border-border bg-card shadow-card";
|
|
1650
2512
|
var tableClass = "w-full border-collapse bg-transparent text-sm";
|
|
1651
2513
|
var headCellClass = "border-b border-border/60 bg-transparent px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide text-muted-foreground";
|
|
@@ -1685,12 +2547,12 @@ function SortIndicator({
|
|
|
1685
2547
|
}) {
|
|
1686
2548
|
const iconClass = "size-3.5 shrink-0 opacity-60 group-hover:opacity-100";
|
|
1687
2549
|
if (!active) {
|
|
1688
|
-
return /* @__PURE__ */
|
|
2550
|
+
return /* @__PURE__ */ jsx41(ArrowUpDownIcon, { className: iconClass, "aria-hidden": true });
|
|
1689
2551
|
}
|
|
1690
2552
|
if (direction === "desc") {
|
|
1691
|
-
return /* @__PURE__ */
|
|
2553
|
+
return /* @__PURE__ */ jsx41(ArrowDownIcon, { className: iconClass, "aria-hidden": true });
|
|
1692
2554
|
}
|
|
1693
|
-
return /* @__PURE__ */
|
|
2555
|
+
return /* @__PURE__ */ jsx41(ArrowUpIcon, { className: iconClass, "aria-hidden": true });
|
|
1694
2556
|
}
|
|
1695
2557
|
function DataTable({
|
|
1696
2558
|
columns,
|
|
@@ -1741,28 +2603,28 @@ function DataTable({
|
|
|
1741
2603
|
const cellPad = dense ? "px-3 py-2" : void 0;
|
|
1742
2604
|
const headPad = dense ? "px-3 py-2" : void 0;
|
|
1743
2605
|
if (rows.length === 0 && emptyMode === "replace") {
|
|
1744
|
-
return /* @__PURE__ */
|
|
2606
|
+
return /* @__PURE__ */ jsx41(EmptyState, { title: emptyTitle, description: emptyDescription, className });
|
|
1745
2607
|
}
|
|
1746
2608
|
const rowCountText = rowCountLabel?.(sortedRows.length) ?? `${sortedRows.length} row${sortedRows.length === 1 ? "" : "s"}`;
|
|
1747
2609
|
const hasFoot = Boolean((showRowCount || footer) && sortedRows.length > 0);
|
|
1748
|
-
return /* @__PURE__ */
|
|
1749
|
-
caption ? /* @__PURE__ */
|
|
1750
|
-
/* @__PURE__ */
|
|
2610
|
+
return /* @__PURE__ */ jsx41("div", { className: cn("aui-app-data-table", shellClass2, className), children: /* @__PURE__ */ jsx41("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs32("table", { className: tableClass, children: [
|
|
2611
|
+
caption ? /* @__PURE__ */ jsx41("caption", { className: "sr-only", children: caption }) : null,
|
|
2612
|
+
/* @__PURE__ */ jsx41("thead", { className: cn(stickyHeader && stickyHeadClass), children: /* @__PURE__ */ jsx41("tr", { children: columns.map((col) => {
|
|
1751
2613
|
const isSorted = sort?.columnId === col.id;
|
|
1752
2614
|
const ariaSort = col.sortable ? isSorted ? sort.direction === "asc" ? "ascending" : "descending" : "none" : void 0;
|
|
1753
|
-
const headerContent = col.sortable ? /* @__PURE__ */
|
|
2615
|
+
const headerContent = col.sortable ? /* @__PURE__ */ jsxs32(
|
|
1754
2616
|
"button",
|
|
1755
2617
|
{
|
|
1756
2618
|
type: "button",
|
|
1757
2619
|
className: sortButtonClass,
|
|
1758
2620
|
onClick: () => setSort(nextSort(sort, col.id)),
|
|
1759
2621
|
children: [
|
|
1760
|
-
/* @__PURE__ */
|
|
1761
|
-
/* @__PURE__ */
|
|
2622
|
+
/* @__PURE__ */ jsx41("span", { className: "truncate", children: col.header }),
|
|
2623
|
+
/* @__PURE__ */ jsx41(SortIndicator, { active: Boolean(isSorted), direction: sort?.direction })
|
|
1762
2624
|
]
|
|
1763
2625
|
}
|
|
1764
2626
|
) : col.header;
|
|
1765
|
-
return /* @__PURE__ */
|
|
2627
|
+
return /* @__PURE__ */ jsx41(
|
|
1766
2628
|
"th",
|
|
1767
2629
|
{
|
|
1768
2630
|
scope: "col",
|
|
@@ -1778,10 +2640,10 @@ function DataTable({
|
|
|
1778
2640
|
col.id
|
|
1779
2641
|
);
|
|
1780
2642
|
}) }) }),
|
|
1781
|
-
/* @__PURE__ */
|
|
1782
|
-
/* @__PURE__ */
|
|
1783
|
-
emptyDescription ? /* @__PURE__ */
|
|
1784
|
-
] }) }) }) : sortedRows.map((row) => /* @__PURE__ */
|
|
2643
|
+
/* @__PURE__ */ jsx41("tbody", { className: cn(!hasFoot && "[&_tr:last-child_td]:border-b-0"), children: sortedRows.length === 0 ? /* @__PURE__ */ jsx41("tr", { children: /* @__PURE__ */ jsx41("td", { colSpan: columns.length, className: emptyCellClass, children: /* @__PURE__ */ jsxs32("div", { className: "flex flex-col items-center gap-1", children: [
|
|
2644
|
+
/* @__PURE__ */ jsx41("p", { className: "font-medium text-foreground", children: emptyTitle }),
|
|
2645
|
+
emptyDescription ? /* @__PURE__ */ jsx41("p", { className: "max-w-sm text-muted-foreground", children: emptyDescription }) : null
|
|
2646
|
+
] }) }) }) : sortedRows.map((row) => /* @__PURE__ */ jsx41(
|
|
1785
2647
|
"tr",
|
|
1786
2648
|
{
|
|
1787
2649
|
className: rowClass,
|
|
@@ -1795,7 +2657,7 @@ function DataTable({
|
|
|
1795
2657
|
} : void 0,
|
|
1796
2658
|
tabIndex: onRowClick ? 0 : void 0,
|
|
1797
2659
|
role: onRowClick ? "button" : void 0,
|
|
1798
|
-
children: columns.map((col) => /* @__PURE__ */
|
|
2660
|
+
children: columns.map((col) => /* @__PURE__ */ jsx41(
|
|
1799
2661
|
"td",
|
|
1800
2662
|
{
|
|
1801
2663
|
className: cn(
|
|
@@ -1811,7 +2673,7 @@ function DataTable({
|
|
|
1811
2673
|
},
|
|
1812
2674
|
getRowKey(row)
|
|
1813
2675
|
)) }),
|
|
1814
|
-
hasFoot ? /* @__PURE__ */
|
|
2676
|
+
hasFoot ? /* @__PURE__ */ jsx41("tfoot", { children: /* @__PURE__ */ jsx41("tr", { children: /* @__PURE__ */ jsx41("td", { colSpan: columns.length, className: footCellClass, children: /* @__PURE__ */ jsxs32(
|
|
1815
2677
|
"div",
|
|
1816
2678
|
{
|
|
1817
2679
|
className: cn(
|
|
@@ -1819,7 +2681,7 @@ function DataTable({
|
|
|
1819
2681
|
showRowCount && footer ? "justify-between" : "justify-start"
|
|
1820
2682
|
),
|
|
1821
2683
|
children: [
|
|
1822
|
-
showRowCount ? /* @__PURE__ */
|
|
2684
|
+
showRowCount ? /* @__PURE__ */ jsx41("span", { children: rowCountText }) : null,
|
|
1823
2685
|
footer
|
|
1824
2686
|
]
|
|
1825
2687
|
}
|
|
@@ -1829,53 +2691,7 @@ function DataTable({
|
|
|
1829
2691
|
|
|
1830
2692
|
// src/app/data/ChartPanel.tsx
|
|
1831
2693
|
import { useId as useId4 } from "react";
|
|
1832
|
-
|
|
1833
|
-
// src/app/data/metrics-shared.tsx
|
|
1834
|
-
import { jsx as jsx38, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
1835
|
-
var metricCardShellClass = cn(
|
|
1836
|
-
studioIntegrationCardClass,
|
|
1837
|
-
"aui-app-metric-card shadow-none",
|
|
1838
|
-
"flex flex-col overflow-hidden"
|
|
1839
|
-
);
|
|
1840
|
-
var metricCardHeaderClass = "flex items-start justify-between gap-3 px-4 pb-1 pt-3";
|
|
1841
|
-
var metricTilesRowClass = "grid w-full min-w-0";
|
|
1842
|
-
var metricChartRegionClass = "relative min-h-0 w-full border-t border-border/40 pt-2";
|
|
1843
|
-
var metricChartPlotRegionClass = "relative min-h-0 w-full border-t border-border/40 px-0 pt-5 pb-3";
|
|
1844
|
-
var metricCellDividerClass = "border-r border-border/40";
|
|
1845
|
-
var MetricCardHeader = ({
|
|
1846
|
-
title,
|
|
1847
|
-
titleId,
|
|
1848
|
-
description,
|
|
1849
|
-
actions
|
|
1850
|
-
}) => {
|
|
1851
|
-
if (!title && !description && !actions) return null;
|
|
1852
|
-
return /* @__PURE__ */ jsxs29("header", { className: metricCardHeaderClass, children: [
|
|
1853
|
-
/* @__PURE__ */ jsxs29("div", { className: "min-w-0", children: [
|
|
1854
|
-
title ? /* @__PURE__ */ jsx38("h3", { id: titleId, className: "text-base font-normal text-foreground", children: title }) : null,
|
|
1855
|
-
description ? /* @__PURE__ */ jsx38("p", { className: "mt-0.5 text-sm text-muted-foreground", children: description }) : null
|
|
1856
|
-
] }),
|
|
1857
|
-
actions ? /* @__PURE__ */ jsx38("div", { className: "shrink-0", children: actions }) : null
|
|
1858
|
-
] });
|
|
1859
|
-
};
|
|
1860
|
-
function metricTilesGridColsClass(n) {
|
|
1861
|
-
switch (n) {
|
|
1862
|
-
case 1:
|
|
1863
|
-
return "grid-cols-1";
|
|
1864
|
-
case 2:
|
|
1865
|
-
return "grid-cols-2";
|
|
1866
|
-
case 3:
|
|
1867
|
-
return "grid-cols-3";
|
|
1868
|
-
case 5:
|
|
1869
|
-
return "grid-cols-2 sm:grid-cols-5";
|
|
1870
|
-
case 6:
|
|
1871
|
-
return "grid-cols-2 sm:grid-cols-3 lg:grid-cols-6";
|
|
1872
|
-
default:
|
|
1873
|
-
return "grid-cols-2 md:grid-cols-4";
|
|
1874
|
-
}
|
|
1875
|
-
}
|
|
1876
|
-
|
|
1877
|
-
// src/app/data/ChartPanel.tsx
|
|
1878
|
-
import { jsx as jsx39, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
2694
|
+
import { jsx as jsx42, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
1879
2695
|
var ChartPanel = ({
|
|
1880
2696
|
title,
|
|
1881
2697
|
description,
|
|
@@ -1888,14 +2704,14 @@ var ChartPanel = ({
|
|
|
1888
2704
|
const titleId = useId4();
|
|
1889
2705
|
const resolvedTitle = title ?? artifact?.title;
|
|
1890
2706
|
const hasHeader = Boolean(resolvedTitle || description || actions);
|
|
1891
|
-
const body = children ?? (artifact ? /* @__PURE__ */
|
|
1892
|
-
return /* @__PURE__ */
|
|
2707
|
+
const body = children ?? (artifact ? /* @__PURE__ */ jsx42(ChartArtifactView, { artifact, embedded: true, height }) : null);
|
|
2708
|
+
return /* @__PURE__ */ jsxs33(
|
|
1893
2709
|
"section",
|
|
1894
2710
|
{
|
|
1895
2711
|
className: cn(metricCardShellClass, "aui-app-chart-panel", className),
|
|
1896
2712
|
"aria-labelledby": resolvedTitle ? titleId : void 0,
|
|
1897
2713
|
children: [
|
|
1898
|
-
/* @__PURE__ */
|
|
2714
|
+
/* @__PURE__ */ jsx42(
|
|
1899
2715
|
MetricCardHeader,
|
|
1900
2716
|
{
|
|
1901
2717
|
title: resolvedTitle,
|
|
@@ -1904,14 +2720,14 @@ var ChartPanel = ({
|
|
|
1904
2720
|
actions
|
|
1905
2721
|
}
|
|
1906
2722
|
),
|
|
1907
|
-
/* @__PURE__ */
|
|
2723
|
+
/* @__PURE__ */ jsx42(
|
|
1908
2724
|
"div",
|
|
1909
2725
|
{
|
|
1910
2726
|
className: cn(
|
|
1911
2727
|
"relative min-h-0 w-full",
|
|
1912
2728
|
hasHeader ? metricChartPlotRegionClass : "pt-2 pb-3"
|
|
1913
2729
|
),
|
|
1914
|
-
children: body ?? /* @__PURE__ */
|
|
2730
|
+
children: body ?? /* @__PURE__ */ jsx42(
|
|
1915
2731
|
"div",
|
|
1916
2732
|
{
|
|
1917
2733
|
className: "flex items-center justify-center text-sm font-normal text-muted-foreground",
|
|
@@ -1927,77 +2743,9 @@ var ChartPanel = ({
|
|
|
1927
2743
|
);
|
|
1928
2744
|
};
|
|
1929
2745
|
|
|
1930
|
-
// src/app/data/MetricTile.tsx
|
|
1931
|
-
import { Fragment as Fragment4, jsx as jsx40, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
1932
|
-
var trendToneClass = {
|
|
1933
|
-
up: "border-border/80 bg-muted/40 text-muted-foreground",
|
|
1934
|
-
down: "border-border/80 bg-muted/40 text-muted-foreground",
|
|
1935
|
-
neutral: "border-border/80 bg-muted/30 text-muted-foreground"
|
|
1936
|
-
};
|
|
1937
|
-
var metricTileBaseClass = "relative flex min-w-0 flex-1 flex-col gap-1 px-4 py-3 text-left font-normal";
|
|
1938
|
-
var metricTileInteractiveClass = cn(
|
|
1939
|
-
metricTileBaseClass,
|
|
1940
|
-
"bg-transparent hover:bg-transparent active:bg-transparent",
|
|
1941
|
-
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-foreground/10"
|
|
1942
|
-
);
|
|
1943
|
-
var MetricTile = ({
|
|
1944
|
-
label,
|
|
1945
|
-
value,
|
|
1946
|
-
unit,
|
|
1947
|
-
trend,
|
|
1948
|
-
trendTone = "neutral",
|
|
1949
|
-
active = false,
|
|
1950
|
-
showDivider = false,
|
|
1951
|
-
onSelect,
|
|
1952
|
-
ariaLabel,
|
|
1953
|
-
className
|
|
1954
|
-
}) => {
|
|
1955
|
-
const content = /* @__PURE__ */ jsxs31(Fragment4, { children: [
|
|
1956
|
-
active ? /* @__PURE__ */ jsx40(
|
|
1957
|
-
"span",
|
|
1958
|
-
{
|
|
1959
|
-
"aria-hidden": true,
|
|
1960
|
-
className: "absolute inset-x-0 bottom-0 h-0.5 bg-foreground dark:bg-white"
|
|
1961
|
-
}
|
|
1962
|
-
) : null,
|
|
1963
|
-
/* @__PURE__ */ jsx40("span", { className: "text-xs font-normal text-muted-foreground", children: label }),
|
|
1964
|
-
/* @__PURE__ */ jsxs31("span", { className: "flex items-center gap-2", children: [
|
|
1965
|
-
/* @__PURE__ */ jsxs31("span", { className: "flex items-baseline gap-1", children: [
|
|
1966
|
-
/* @__PURE__ */ jsx40("span", { className: "text-2xl font-normal tracking-tight text-foreground tabular-nums", children: value }),
|
|
1967
|
-
unit ? /* @__PURE__ */ jsx40("span", { className: "text-xs font-normal text-muted-foreground", children: unit }) : null
|
|
1968
|
-
] }),
|
|
1969
|
-
trend ? /* @__PURE__ */ jsx40(
|
|
1970
|
-
"span",
|
|
1971
|
-
{
|
|
1972
|
-
className: cn(
|
|
1973
|
-
"rounded-full border px-1.5 py-0.5 text-xs font-normal",
|
|
1974
|
-
trendToneClass[trendTone]
|
|
1975
|
-
),
|
|
1976
|
-
children: trend
|
|
1977
|
-
}
|
|
1978
|
-
) : null
|
|
1979
|
-
] })
|
|
1980
|
-
] });
|
|
1981
|
-
const divider = showDivider ? metricCellDividerClass : void 0;
|
|
1982
|
-
if (onSelect) {
|
|
1983
|
-
return /* @__PURE__ */ jsx40(
|
|
1984
|
-
"button",
|
|
1985
|
-
{
|
|
1986
|
-
type: "button",
|
|
1987
|
-
onClick: onSelect,
|
|
1988
|
-
"aria-pressed": active,
|
|
1989
|
-
"aria-label": ariaLabel,
|
|
1990
|
-
className: cn(metricTileInteractiveClass, divider, className),
|
|
1991
|
-
children: content
|
|
1992
|
-
}
|
|
1993
|
-
);
|
|
1994
|
-
}
|
|
1995
|
-
return /* @__PURE__ */ jsx40("div", { className: cn(metricTileBaseClass, divider, className), children: content });
|
|
1996
|
-
};
|
|
1997
|
-
|
|
1998
2746
|
// src/app/data/MetricRow.tsx
|
|
1999
2747
|
import { useId as useId5, useState as useState5 } from "react";
|
|
2000
|
-
import { jsx as
|
|
2748
|
+
import { jsx as jsx43, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
2001
2749
|
var MetricRow = ({
|
|
2002
2750
|
title,
|
|
2003
2751
|
description,
|
|
@@ -2019,13 +2767,13 @@ var MetricRow = ({
|
|
|
2019
2767
|
if (activeMetricId == null) setInternalId(id);
|
|
2020
2768
|
onMetricChange?.(id);
|
|
2021
2769
|
};
|
|
2022
|
-
return /* @__PURE__ */
|
|
2770
|
+
return /* @__PURE__ */ jsxs34(
|
|
2023
2771
|
"section",
|
|
2024
2772
|
{
|
|
2025
2773
|
className: cn(metricCardShellClass, className),
|
|
2026
2774
|
"aria-labelledby": title ? titleId : void 0,
|
|
2027
2775
|
children: [
|
|
2028
|
-
/* @__PURE__ */
|
|
2776
|
+
/* @__PURE__ */ jsx43(
|
|
2029
2777
|
MetricCardHeader,
|
|
2030
2778
|
{
|
|
2031
2779
|
title,
|
|
@@ -2034,7 +2782,7 @@ var MetricRow = ({
|
|
|
2034
2782
|
actions
|
|
2035
2783
|
}
|
|
2036
2784
|
),
|
|
2037
|
-
/* @__PURE__ */
|
|
2785
|
+
/* @__PURE__ */ jsx43(
|
|
2038
2786
|
"div",
|
|
2039
2787
|
{
|
|
2040
2788
|
role: selectable ? "group" : void 0,
|
|
@@ -2044,7 +2792,7 @@ var MetricRow = ({
|
|
|
2044
2792
|
metricTilesGridColsClass(metrics.length),
|
|
2045
2793
|
(title || description || actions) && "mt-3"
|
|
2046
2794
|
),
|
|
2047
|
-
children: metrics.map((m, index) => /* @__PURE__ */
|
|
2795
|
+
children: metrics.map((m, index) => /* @__PURE__ */ jsx43(
|
|
2048
2796
|
MetricTile,
|
|
2049
2797
|
{
|
|
2050
2798
|
label: m.label,
|
|
@@ -2067,7 +2815,7 @@ var MetricRow = ({
|
|
|
2067
2815
|
|
|
2068
2816
|
// src/app/data/MetricChartCard.tsx
|
|
2069
2817
|
import { useId as useId6, useState as useState6 } from "react";
|
|
2070
|
-
import { jsx as
|
|
2818
|
+
import { jsx as jsx44, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
2071
2819
|
var MetricChartCard = ({
|
|
2072
2820
|
title,
|
|
2073
2821
|
description,
|
|
@@ -2097,13 +2845,13 @@ var MetricChartCard = ({
|
|
|
2097
2845
|
};
|
|
2098
2846
|
const hasHeader = Boolean(title || description || actions);
|
|
2099
2847
|
const chartAriaLabel = typeof active?.label === "string" ? `${active.label} over time` : "Metric chart";
|
|
2100
|
-
return /* @__PURE__ */
|
|
2848
|
+
return /* @__PURE__ */ jsxs35(
|
|
2101
2849
|
"section",
|
|
2102
2850
|
{
|
|
2103
2851
|
className: cn(metricCardShellClass, className),
|
|
2104
2852
|
"aria-labelledby": title ? titleId : void 0,
|
|
2105
2853
|
children: [
|
|
2106
|
-
/* @__PURE__ */
|
|
2854
|
+
/* @__PURE__ */ jsx44(
|
|
2107
2855
|
MetricCardHeader,
|
|
2108
2856
|
{
|
|
2109
2857
|
title,
|
|
@@ -2112,7 +2860,7 @@ var MetricChartCard = ({
|
|
|
2112
2860
|
actions
|
|
2113
2861
|
}
|
|
2114
2862
|
),
|
|
2115
|
-
/* @__PURE__ */
|
|
2863
|
+
/* @__PURE__ */ jsx44(
|
|
2116
2864
|
"div",
|
|
2117
2865
|
{
|
|
2118
2866
|
role: "group",
|
|
@@ -2122,7 +2870,7 @@ var MetricChartCard = ({
|
|
|
2122
2870
|
metricTilesGridColsClass(metrics.length),
|
|
2123
2871
|
hasHeader && "mt-3"
|
|
2124
2872
|
),
|
|
2125
|
-
children: metrics.map((m, index) => /* @__PURE__ */
|
|
2873
|
+
children: metrics.map((m, index) => /* @__PURE__ */ jsx44(
|
|
2126
2874
|
MetricTile,
|
|
2127
2875
|
{
|
|
2128
2876
|
label: m.label,
|
|
@@ -2138,7 +2886,7 @@ var MetricChartCard = ({
|
|
|
2138
2886
|
))
|
|
2139
2887
|
}
|
|
2140
2888
|
),
|
|
2141
|
-
/* @__PURE__ */
|
|
2889
|
+
/* @__PURE__ */ jsx44("div", { className: metricChartRegionClass, "aria-live": "polite", "aria-atomic": "true", children: active?.data && active.data.length > 0 ? /* @__PURE__ */ jsx44(
|
|
2142
2890
|
LineAreaChart,
|
|
2143
2891
|
{
|
|
2144
2892
|
data: active.data,
|
|
@@ -2158,7 +2906,7 @@ var MetricChartCard = ({
|
|
|
2158
2906
|
ariaLabel: chartAriaLabel
|
|
2159
2907
|
},
|
|
2160
2908
|
active.id
|
|
2161
|
-
) : /* @__PURE__ */
|
|
2909
|
+
) : /* @__PURE__ */ jsx44(
|
|
2162
2910
|
"div",
|
|
2163
2911
|
{
|
|
2164
2912
|
className: "flex w-full items-center justify-center text-sm font-normal text-muted-foreground",
|
|
@@ -2174,7 +2922,7 @@ var MetricChartCard = ({
|
|
|
2174
2922
|
|
|
2175
2923
|
// src/charts/sparkline.tsx
|
|
2176
2924
|
import { useId as useId7 } from "react";
|
|
2177
|
-
import { Fragment as
|
|
2925
|
+
import { Fragment as Fragment6, jsx as jsx45, jsxs as jsxs36 } from "react/jsx-runtime";
|
|
2178
2926
|
var Sparkline = ({
|
|
2179
2927
|
data,
|
|
2180
2928
|
dataKey = "value",
|
|
@@ -2189,7 +2937,7 @@ var Sparkline = ({
|
|
|
2189
2937
|
const uid = useId7();
|
|
2190
2938
|
const values = data.map((d) => typeof d === "number" ? d : toNum(d[dataKey]));
|
|
2191
2939
|
if (values.length === 0) {
|
|
2192
|
-
return /* @__PURE__ */
|
|
2940
|
+
return /* @__PURE__ */ jsx45("span", { className: cn("inline-block", className), style: { width, height } });
|
|
2193
2941
|
}
|
|
2194
2942
|
const pad = strokeWidth + 1;
|
|
2195
2943
|
const min = Math.min(...values);
|
|
@@ -2201,7 +2949,7 @@ var Sparkline = ({
|
|
|
2201
2949
|
x: pad + (values.length > 1 ? i / (values.length - 1) * innerW : innerW / 2),
|
|
2202
2950
|
y: pad + innerH - (v - min) / range * innerH
|
|
2203
2951
|
}));
|
|
2204
|
-
return /* @__PURE__ */
|
|
2952
|
+
return /* @__PURE__ */ jsxs36(
|
|
2205
2953
|
"svg",
|
|
2206
2954
|
{
|
|
2207
2955
|
width,
|
|
@@ -2212,14 +2960,14 @@ var Sparkline = ({
|
|
|
2212
2960
|
"aria-label": ariaLabel,
|
|
2213
2961
|
preserveAspectRatio: "none",
|
|
2214
2962
|
children: [
|
|
2215
|
-
area && /* @__PURE__ */
|
|
2216
|
-
/* @__PURE__ */
|
|
2217
|
-
/* @__PURE__ */
|
|
2218
|
-
/* @__PURE__ */
|
|
2963
|
+
area && /* @__PURE__ */ jsxs36(Fragment6, { children: [
|
|
2964
|
+
/* @__PURE__ */ jsx45("defs", { children: /* @__PURE__ */ jsxs36("linearGradient", { id: `${uid}-spark`, x1: "0", x2: "0", y1: "0", y2: "1", children: [
|
|
2965
|
+
/* @__PURE__ */ jsx45("stop", { offset: "0%", style: { stopColor: color, stopOpacity: 0.25 } }),
|
|
2966
|
+
/* @__PURE__ */ jsx45("stop", { offset: "100%", style: { stopColor: color, stopOpacity: 0 } })
|
|
2219
2967
|
] }) }),
|
|
2220
|
-
/* @__PURE__ */
|
|
2968
|
+
/* @__PURE__ */ jsx45("path", { d: monotoneAreaPath(points, height - pad), fill: `url(#${uid}-spark)` })
|
|
2221
2969
|
] }),
|
|
2222
|
-
/* @__PURE__ */
|
|
2970
|
+
/* @__PURE__ */ jsx45(
|
|
2223
2971
|
"path",
|
|
2224
2972
|
{
|
|
2225
2973
|
d: monotoneLinePath(points),
|
|
@@ -2237,6 +2985,19 @@ var Sparkline = ({
|
|
|
2237
2985
|
|
|
2238
2986
|
export {
|
|
2239
2987
|
APP_KIT_AGENT_INSTRUCTIONS,
|
|
2988
|
+
createTimbalTheme,
|
|
2989
|
+
themeToCss,
|
|
2990
|
+
ensureThemeFontLink,
|
|
2991
|
+
applyTimbalTheme,
|
|
2992
|
+
clearTimbalTheme,
|
|
2993
|
+
TIMBAL_THEME_PRESETS,
|
|
2994
|
+
getThemePreset,
|
|
2995
|
+
applyThemePreset,
|
|
2996
|
+
getStoredThemePreset,
|
|
2997
|
+
THEME_AGENT_INSTRUCTIONS,
|
|
2998
|
+
TimbalThemeStyle,
|
|
2999
|
+
MetricTile,
|
|
3000
|
+
ThemePresetGallery,
|
|
2240
3001
|
appPageColumnClass,
|
|
2241
3002
|
appShellTopbarInsetClass,
|
|
2242
3003
|
appShellInsetTopClass,
|
|
@@ -2289,7 +3050,6 @@ export {
|
|
|
2289
3050
|
FilterBar,
|
|
2290
3051
|
DataTable,
|
|
2291
3052
|
ChartPanel,
|
|
2292
|
-
MetricTile,
|
|
2293
3053
|
MetricRow,
|
|
2294
3054
|
MetricChartCard,
|
|
2295
3055
|
Sparkline
|