@camstack/ui-library 0.1.34 → 0.1.35

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/dist/index.cjs CHANGED
@@ -32,6 +32,7 @@ var src_exports = {};
32
32
  __export(src_exports, {
33
33
  AppShell: () => AppShell,
34
34
  Badge: () => Badge,
35
+ BottomSheet: () => BottomSheet,
35
36
  Button: () => Button,
36
37
  CLASS_COLORS: () => CLASS_COLORS,
37
38
  Card: () => Card,
@@ -68,6 +69,7 @@ __export(src_exports, {
68
69
  KeyValueList: () => KeyValueList,
69
70
  Label: () => Label,
70
71
  LoginForm: () => LoginForm,
72
+ MobileDrawer: () => MobileDrawer,
71
73
  PageHeader: () => PageHeader,
72
74
  PipelineBuilder: () => PipelineBuilder,
73
75
  PipelineRuntimeSelector: () => PipelineRuntimeSelector,
@@ -107,6 +109,7 @@ __export(src_exports, {
107
109
  statusIcons: () => statusIcons,
108
110
  themeToCss: () => themeToCss,
109
111
  useDevShell: () => useDevShell,
112
+ useIsMobile: () => useIsMobile,
110
113
  useThemeMode: () => useThemeMode
111
114
  });
112
115
  module.exports = __toCommonJS(src_exports);
@@ -787,7 +790,7 @@ function DialogTrigger({ children, ...props }) {
787
790
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", onClick: () => setOpen(true), ...props, children });
788
791
  }
789
792
  var contentVariants = (0, import_class_variance_authority7.cva)(
790
- "bg-background-elevated border border-border rounded-lg p-4 backdrop:bg-black/50 backdrop:backdrop-blur-sm",
793
+ "bg-background-elevated border border-border rounded-lg p-4 backdrop:bg-black/50 backdrop:backdrop-blur-sm max-w-[calc(100vw-2rem)] max-h-[calc(100dvh-2rem)] overflow-y-auto",
791
794
  {
792
795
  variants: {
793
796
  width: {
@@ -1175,8 +1178,28 @@ var ScrollArea = (0, import_react19.forwardRef)(
1175
1178
  ScrollArea.displayName = "ScrollArea";
1176
1179
 
1177
1180
  // src/primitives/floating-panel.tsx
1178
- var import_react20 = require("react");
1181
+ var import_react21 = require("react");
1179
1182
  var import_lucide_react4 = require("lucide-react");
1183
+
1184
+ // src/hooks/use-is-mobile.ts
1185
+ var import_react20 = require("react");
1186
+ var MOBILE_QUERY = "(max-width: 767px)";
1187
+ function subscribe(callback) {
1188
+ const mql = window.matchMedia(MOBILE_QUERY);
1189
+ mql.addEventListener("change", callback);
1190
+ return () => mql.removeEventListener("change", callback);
1191
+ }
1192
+ function getSnapshot() {
1193
+ return window.matchMedia(MOBILE_QUERY).matches;
1194
+ }
1195
+ function getServerSnapshot() {
1196
+ return false;
1197
+ }
1198
+ function useIsMobile() {
1199
+ return (0, import_react20.useSyncExternalStore)(subscribe, getSnapshot, getServerSnapshot);
1200
+ }
1201
+
1202
+ // src/primitives/floating-panel.tsx
1180
1203
  var import_jsx_runtime19 = require("react/jsx-runtime");
1181
1204
  function FloatingPanel({
1182
1205
  title,
@@ -1189,24 +1212,25 @@ function FloatingPanel({
1189
1212
  offsetIndex = 0,
1190
1213
  className
1191
1214
  }) {
1192
- const [pos, setPos] = (0, import_react20.useState)({ x: 80 + offsetIndex * 30, y: 80 + offsetIndex * 30 });
1193
- const [size, setSize] = (0, import_react20.useState)({ w: defaultWidth, h: defaultHeight });
1194
- const [minimized, setMinimized] = (0, import_react20.useState)(false);
1195
- const dragging = (0, import_react20.useRef)(false);
1196
- const resizing = (0, import_react20.useRef)(false);
1197
- const offset = (0, import_react20.useRef)({ x: 0, y: 0 });
1198
- const onDragStart = (0, import_react20.useCallback)((e) => {
1215
+ const [pos, setPos] = (0, import_react21.useState)({ x: 80 + offsetIndex * 30, y: 80 + offsetIndex * 30 });
1216
+ const [size, setSize] = (0, import_react21.useState)({ w: defaultWidth, h: defaultHeight });
1217
+ const [minimized, setMinimized] = (0, import_react21.useState)(false);
1218
+ const dragging = (0, import_react21.useRef)(false);
1219
+ const resizing = (0, import_react21.useRef)(false);
1220
+ const offset = (0, import_react21.useRef)({ x: 0, y: 0 });
1221
+ const isMobile = useIsMobile();
1222
+ const onDragStart = (0, import_react21.useCallback)((e) => {
1199
1223
  e.preventDefault();
1200
1224
  dragging.current = true;
1201
1225
  offset.current = { x: e.clientX - pos.x, y: e.clientY - pos.y };
1202
1226
  }, [pos]);
1203
- const onResizeStart = (0, import_react20.useCallback)((e) => {
1227
+ const onResizeStart = (0, import_react21.useCallback)((e) => {
1204
1228
  e.preventDefault();
1205
1229
  e.stopPropagation();
1206
1230
  resizing.current = true;
1207
1231
  offset.current = { x: e.clientX, y: e.clientY };
1208
1232
  }, []);
1209
- (0, import_react20.useEffect)(() => {
1233
+ (0, import_react21.useEffect)(() => {
1210
1234
  const onMouseMove = (e) => {
1211
1235
  if (dragging.current) setPos({ x: e.clientX - offset.current.x, y: e.clientY - offset.current.y });
1212
1236
  if (resizing.current) {
@@ -1227,6 +1251,42 @@ function FloatingPanel({
1227
1251
  window.removeEventListener("mouseup", onMouseUp);
1228
1252
  };
1229
1253
  }, [minWidth, minHeight]);
1254
+ if (isMobile) {
1255
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
1256
+ "div",
1257
+ {
1258
+ className: cn(
1259
+ "fixed inset-x-0 bottom-0 z-50 rounded-t-xl border-t border-border bg-background-elevated shadow-2xl flex flex-col overflow-hidden",
1260
+ className
1261
+ ),
1262
+ style: { maxHeight: "60dvh" },
1263
+ children: [
1264
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center justify-between gap-2 px-3 py-2 border-b border-border shrink-0 bg-surface", children: [
1265
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-[11px] font-medium truncate", children: title }),
1266
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-1 shrink-0", children: [
1267
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1268
+ "button",
1269
+ {
1270
+ onClick: () => setMinimized(!minimized),
1271
+ className: "p-0.5 rounded hover:bg-surface-hover text-foreground-muted transition-colors",
1272
+ children: minimized ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react4.Maximize2, { size: 12 }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react4.Minimize2, { size: 12 })
1273
+ }
1274
+ ),
1275
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1276
+ "button",
1277
+ {
1278
+ onClick: onClose,
1279
+ className: "p-0.5 rounded hover:bg-danger/20 text-foreground-muted hover:text-danger transition-colors",
1280
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react4.X, { size: 12 })
1281
+ }
1282
+ )
1283
+ ] })
1284
+ ] }),
1285
+ !minimized && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "flex-1 min-h-0 overflow-y-auto", children })
1286
+ ]
1287
+ }
1288
+ );
1289
+ }
1230
1290
  return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
1231
1291
  "div",
1232
1292
  {
@@ -1285,8 +1345,115 @@ function FloatingPanel({
1285
1345
  );
1286
1346
  }
1287
1347
 
1288
- // src/composites/status-badge.tsx
1348
+ // src/primitives/mobile-drawer.tsx
1349
+ var import_react22 = require("react");
1289
1350
  var import_jsx_runtime20 = require("react/jsx-runtime");
1351
+ function MobileDrawer({ open, onClose, children, className, width = "w-64" }) {
1352
+ const drawerRef = (0, import_react22.useRef)(null);
1353
+ (0, import_react22.useEffect)(() => {
1354
+ if (!open) return;
1355
+ const handleKeyDown = (e) => {
1356
+ if (e.key === "Escape") onClose();
1357
+ };
1358
+ document.addEventListener("keydown", handleKeyDown);
1359
+ document.body.style.overflow = "hidden";
1360
+ return () => {
1361
+ document.removeEventListener("keydown", handleKeyDown);
1362
+ document.body.style.overflow = "";
1363
+ };
1364
+ }, [open, onClose]);
1365
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
1366
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1367
+ "div",
1368
+ {
1369
+ className: cn(
1370
+ "fixed inset-0 z-40 bg-black/50 backdrop-blur-sm transition-opacity duration-200",
1371
+ open ? "opacity-100" : "pointer-events-none opacity-0"
1372
+ ),
1373
+ onClick: onClose,
1374
+ "aria-hidden": "true"
1375
+ }
1376
+ ),
1377
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1378
+ "div",
1379
+ {
1380
+ ref: drawerRef,
1381
+ role: "dialog",
1382
+ "aria-modal": "true",
1383
+ className: cn(
1384
+ "fixed inset-y-0 left-0 z-50 flex flex-col bg-surface border-r border-border shadow-2xl transition-transform duration-200 ease-out",
1385
+ width,
1386
+ open ? "translate-x-0" : "-translate-x-full",
1387
+ className
1388
+ ),
1389
+ children
1390
+ }
1391
+ )
1392
+ ] });
1393
+ }
1394
+
1395
+ // src/primitives/bottom-sheet.tsx
1396
+ var import_react23 = require("react");
1397
+ var import_lucide_react5 = require("lucide-react");
1398
+ var import_jsx_runtime21 = require("react/jsx-runtime");
1399
+ function BottomSheet({ open, onClose, title, children, className }) {
1400
+ (0, import_react23.useEffect)(() => {
1401
+ if (!open) return;
1402
+ const handleKeyDown = (e) => {
1403
+ if (e.key === "Escape") onClose();
1404
+ };
1405
+ document.addEventListener("keydown", handleKeyDown);
1406
+ document.body.style.overflow = "hidden";
1407
+ return () => {
1408
+ document.removeEventListener("keydown", handleKeyDown);
1409
+ document.body.style.overflow = "";
1410
+ };
1411
+ }, [open, onClose]);
1412
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
1413
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1414
+ "div",
1415
+ {
1416
+ className: cn(
1417
+ "fixed inset-0 z-40 bg-black/50 transition-opacity duration-200",
1418
+ open ? "opacity-100" : "pointer-events-none opacity-0"
1419
+ ),
1420
+ onClick: onClose,
1421
+ "aria-hidden": "true"
1422
+ }
1423
+ ),
1424
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
1425
+ "div",
1426
+ {
1427
+ role: "dialog",
1428
+ "aria-modal": "true",
1429
+ className: cn(
1430
+ "fixed inset-x-0 bottom-0 z-50 flex flex-col bg-background-elevated border-t border-border rounded-t-xl shadow-2xl transition-transform duration-200 ease-out",
1431
+ "max-h-[80dvh]",
1432
+ open ? "translate-y-0" : "translate-y-full",
1433
+ className
1434
+ ),
1435
+ children: [
1436
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "flex justify-center pt-2 pb-1", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "h-1 w-8 rounded-full bg-foreground-subtle/30" }) }),
1437
+ title && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center justify-between px-4 pb-2", children: [
1438
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-sm font-medium text-foreground", children: title }),
1439
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1440
+ "button",
1441
+ {
1442
+ onClick: onClose,
1443
+ className: "p-1 rounded-md hover:bg-surface-hover text-foreground-muted transition-colors",
1444
+ children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react5.X, { className: "h-4 w-4" })
1445
+ }
1446
+ )
1447
+ ] }),
1448
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "flex-1 overflow-y-auto px-4 pb-4", children })
1449
+ ]
1450
+ }
1451
+ )
1452
+ ] });
1453
+ }
1454
+
1455
+ // src/composites/status-badge.tsx
1456
+ var import_jsx_runtime22 = require("react/jsx-runtime");
1290
1457
  var statusConfig = {
1291
1458
  online: { colorClass: "bg-success", label: "Online" },
1292
1459
  offline: { colorClass: "bg-danger", label: "Offline" },
@@ -1301,7 +1468,7 @@ function StatusBadge({
1301
1468
  className
1302
1469
  }) {
1303
1470
  const config = statusConfig[status];
1304
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
1471
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
1305
1472
  "span",
1306
1473
  {
1307
1474
  className: cn(
@@ -1310,21 +1477,21 @@ function StatusBadge({
1310
1477
  className
1311
1478
  ),
1312
1479
  children: [
1313
- showDot && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1480
+ showDot && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
1314
1481
  "span",
1315
1482
  {
1316
1483
  className: cn("h-1.5 w-1.5 shrink-0 rounded-full", config.colorClass),
1317
1484
  "aria-hidden": "true"
1318
1485
  }
1319
1486
  ),
1320
- showLabel && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-foreground", children: config.label })
1487
+ showLabel && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "text-foreground", children: config.label })
1321
1488
  ]
1322
1489
  }
1323
1490
  );
1324
1491
  }
1325
1492
 
1326
1493
  // src/composites/provider-badge.tsx
1327
- var import_jsx_runtime21 = require("react/jsx-runtime");
1494
+ var import_jsx_runtime23 = require("react/jsx-runtime");
1328
1495
  var providerConfig = {
1329
1496
  frigate: { colorClass: "bg-provider-frigate", label: "Frigate" },
1330
1497
  scrypted: { colorClass: "bg-provider-scrypted", label: "Scrypted" },
@@ -1338,20 +1505,20 @@ function ProviderBadge({
1338
1505
  className
1339
1506
  }) {
1340
1507
  const config = providerConfig[provider];
1341
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: cn("inline-flex items-center gap-1.5 text-xs", className), children: [
1342
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1508
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("span", { className: cn("inline-flex items-center gap-1.5 text-xs", className), children: [
1509
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1343
1510
  "span",
1344
1511
  {
1345
1512
  className: cn("h-1.5 w-1.5 shrink-0 rounded-sm", config.colorClass),
1346
1513
  "aria-hidden": "true"
1347
1514
  }
1348
1515
  ),
1349
- showLabel && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-foreground", children: config.label })
1516
+ showLabel && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "text-foreground", children: config.label })
1350
1517
  ] });
1351
1518
  }
1352
1519
 
1353
1520
  // src/composites/version-badge.tsx
1354
- var import_jsx_runtime22 = require("react/jsx-runtime");
1521
+ var import_jsx_runtime24 = require("react/jsx-runtime");
1355
1522
  var VARIANT_STYLES = {
1356
1523
  success: "bg-emerald-400 text-emerald-950",
1357
1524
  warning: "bg-amber-400 text-amber-950",
@@ -1360,7 +1527,7 @@ var VARIANT_STYLES = {
1360
1527
  neutral: "bg-foreground-subtle/20 text-foreground"
1361
1528
  };
1362
1529
  function SemanticBadge({ children, variant = "neutral", mono, className }) {
1363
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: cn(
1530
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: cn(
1364
1531
  "inline-flex items-center rounded-md px-2 py-0.5 text-[11px] font-bold leading-tight",
1365
1532
  mono && "font-mono",
1366
1533
  VARIANT_STYLES[variant],
@@ -1369,11 +1536,11 @@ function SemanticBadge({ children, variant = "neutral", mono, className }) {
1369
1536
  }
1370
1537
  function VersionBadge({ version, preRelease, className }) {
1371
1538
  const isPreRelease = preRelease ?? /-(alpha|beta|rc|dev|canary|next)/i.test(version);
1372
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(SemanticBadge, { variant: isPreRelease ? "warning" : "success", mono: true, className, children: version });
1539
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(SemanticBadge, { variant: isPreRelease ? "warning" : "success", mono: true, className, children: version });
1373
1540
  }
1374
1541
 
1375
1542
  // src/composites/form-field.tsx
1376
- var import_jsx_runtime23 = require("react/jsx-runtime");
1543
+ var import_jsx_runtime25 = require("react/jsx-runtime");
1377
1544
  function FormField({
1378
1545
  label,
1379
1546
  description,
@@ -1384,7 +1551,7 @@ function FormField({
1384
1551
  className
1385
1552
  }) {
1386
1553
  const isHorizontal = orientation === "horizontal";
1387
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
1554
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
1388
1555
  "div",
1389
1556
  {
1390
1557
  className: cn(
@@ -1393,34 +1560,34 @@ function FormField({
1393
1560
  className
1394
1561
  ),
1395
1562
  children: [
1396
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: cn(isHorizontal ? "flex-1" : ""), children: [
1397
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(Label, { children: [
1563
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: cn(isHorizontal ? "flex-1" : ""), children: [
1564
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(Label, { children: [
1398
1565
  label,
1399
- required && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "text-danger ml-0.5", children: "*" })
1566
+ required && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "text-danger ml-0.5", children: "*" })
1400
1567
  ] }),
1401
- description && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-foreground-subtle text-xs mt-0.5", children: description })
1568
+ description && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "text-foreground-subtle text-xs mt-0.5", children: description })
1402
1569
  ] }),
1403
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: cn(isHorizontal ? "shrink-0" : ""), children }),
1404
- error && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-danger text-xs", children: error })
1570
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: cn(isHorizontal ? "shrink-0" : ""), children }),
1571
+ error && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "text-danger text-xs", children: error })
1405
1572
  ]
1406
1573
  }
1407
1574
  );
1408
1575
  }
1409
1576
 
1410
1577
  // src/composites/page-header.tsx
1411
- var import_jsx_runtime24 = require("react/jsx-runtime");
1578
+ var import_jsx_runtime26 = require("react/jsx-runtime");
1412
1579
  function PageHeader({ title, subtitle, actions, className }) {
1413
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: cn("flex items-center justify-between mb-3", className), children: [
1414
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { children: [
1415
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("h1", { className: "text-sm font-semibold text-foreground", children: title }),
1416
- subtitle && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "text-foreground-subtle text-xs", children: subtitle })
1580
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: cn("flex flex-col gap-2 mb-3 sm:flex-row sm:items-center sm:justify-between", className), children: [
1581
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { children: [
1582
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("h1", { className: "text-sm font-semibold text-foreground", children: title }),
1583
+ subtitle && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { className: "text-foreground-subtle text-xs", children: subtitle })
1417
1584
  ] }),
1418
- actions && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "flex items-center gap-2", children: actions })
1585
+ actions && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "flex items-center gap-2 flex-wrap", children: actions })
1419
1586
  ] });
1420
1587
  }
1421
1588
 
1422
1589
  // src/composites/empty-state.tsx
1423
- var import_jsx_runtime25 = require("react/jsx-runtime");
1590
+ var import_jsx_runtime27 = require("react/jsx-runtime");
1424
1591
  function EmptyState({
1425
1592
  icon: Icon,
1426
1593
  title,
@@ -1428,18 +1595,18 @@ function EmptyState({
1428
1595
  action,
1429
1596
  className
1430
1597
  }) {
1431
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: cn("flex flex-col items-center justify-center gap-3 py-12", className), children: [
1432
- Icon && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Icon, { className: "h-12 w-12 text-foreground-subtle", "aria-hidden": "true" }),
1433
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex flex-col items-center gap-1 text-center", children: [
1434
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "text-foreground-muted text-sm font-medium", children: title }),
1435
- description && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "text-foreground-subtle text-xs max-w-xs", children: description })
1598
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: cn("flex flex-col items-center justify-center gap-3 py-12", className), children: [
1599
+ Icon && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Icon, { className: "h-12 w-12 text-foreground-subtle", "aria-hidden": "true" }),
1600
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex flex-col items-center gap-1 text-center", children: [
1601
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: "text-foreground-muted text-sm font-medium", children: title }),
1602
+ description && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: "text-foreground-subtle text-xs max-w-xs", children: description })
1436
1603
  ] }),
1437
- action && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "mt-1", children: action })
1604
+ action && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "mt-1", children: action })
1438
1605
  ] });
1439
1606
  }
1440
1607
 
1441
1608
  // src/composites/confirm-dialog.tsx
1442
- var import_jsx_runtime26 = require("react/jsx-runtime");
1609
+ var import_jsx_runtime28 = require("react/jsx-runtime");
1443
1610
  function ConfirmDialog({
1444
1611
  title,
1445
1612
  message,
@@ -1451,14 +1618,14 @@ function ConfirmDialog({
1451
1618
  open,
1452
1619
  onOpenChange
1453
1620
  }) {
1454
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Dialog, { open, onOpenChange, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(DialogContent, { children: [
1455
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(DialogHeader, { children: [
1456
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(DialogTitle, { children: title }),
1457
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(DialogDescription, { children: message })
1621
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Dialog, { open, onOpenChange, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(DialogContent, { children: [
1622
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(DialogHeader, { children: [
1623
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(DialogTitle, { children: title }),
1624
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(DialogDescription, { children: message })
1458
1625
  ] }),
1459
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(DialogFooter, { children: [
1460
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Button, { variant: "ghost", onClick: onCancel, children: cancelLabel }),
1461
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
1626
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(DialogFooter, { children: [
1627
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Button, { variant: "ghost", onClick: onCancel, children: cancelLabel }),
1628
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1462
1629
  Button,
1463
1630
  {
1464
1631
  variant: variant === "danger" ? "danger" : "primary",
@@ -1471,13 +1638,13 @@ function ConfirmDialog({
1471
1638
  }
1472
1639
 
1473
1640
  // src/composites/stat-card.tsx
1474
- var import_lucide_react5 = require("lucide-react");
1475
- var import_jsx_runtime27 = require("react/jsx-runtime");
1641
+ var import_lucide_react6 = require("lucide-react");
1642
+ var import_jsx_runtime29 = require("react/jsx-runtime");
1476
1643
  function StatCard({ value, label, trend, className }) {
1477
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(Card, { className: cn("flex flex-col gap-1", className), children: [
1478
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-baseline gap-2", children: [
1479
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "text-2xl font-semibold text-foreground", children: value }),
1480
- trend && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
1644
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(Card, { className: cn("flex flex-col gap-1", className), children: [
1645
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex items-baseline gap-2", children: [
1646
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "text-2xl font-semibold text-foreground", children: value }),
1647
+ trend && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
1481
1648
  "span",
1482
1649
  {
1483
1650
  className: cn(
@@ -1485,27 +1652,27 @@ function StatCard({ value, label, trend, className }) {
1485
1652
  trend.direction === "up" ? "text-success" : "text-danger"
1486
1653
  ),
1487
1654
  children: [
1488
- trend.direction === "up" ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react5.TrendingUp, { className: "h-3 w-3" }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react5.TrendingDown, { className: "h-3 w-3" }),
1655
+ trend.direction === "up" ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react6.TrendingUp, { className: "h-3 w-3" }) : /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react6.TrendingDown, { className: "h-3 w-3" }),
1489
1656
  trend.value,
1490
1657
  "%"
1491
1658
  ]
1492
1659
  }
1493
1660
  )
1494
1661
  ] }),
1495
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "text-xs text-foreground-muted", children: label })
1662
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "text-xs text-foreground-muted", children: label })
1496
1663
  ] });
1497
1664
  }
1498
1665
 
1499
1666
  // src/composites/key-value-list.tsx
1500
- var import_jsx_runtime28 = require("react/jsx-runtime");
1667
+ var import_jsx_runtime30 = require("react/jsx-runtime");
1501
1668
  function KeyValueList({ items, className }) {
1502
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("dl", { className: cn("flex flex-col", className), children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
1669
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("dl", { className: cn("flex flex-col", className), children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
1503
1670
  "div",
1504
1671
  {
1505
1672
  className: "flex items-center h-7",
1506
1673
  children: [
1507
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("dt", { className: "text-foreground-subtle text-xs w-1/3 shrink-0", children: item.key }),
1508
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("dd", { className: "text-foreground text-xs", children: item.value })
1674
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("dt", { className: "text-foreground-subtle text-xs w-1/3 shrink-0", children: item.key }),
1675
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("dd", { className: "text-foreground text-xs", children: item.value })
1509
1676
  ]
1510
1677
  },
1511
1678
  item.key
@@ -1513,23 +1680,23 @@ function KeyValueList({ items, className }) {
1513
1680
  }
1514
1681
 
1515
1682
  // src/composites/code-block.tsx
1516
- var import_react21 = require("react");
1517
- var import_lucide_react6 = require("lucide-react");
1518
- var import_jsx_runtime29 = require("react/jsx-runtime");
1683
+ var import_react24 = require("react");
1684
+ var import_lucide_react7 = require("lucide-react");
1685
+ var import_jsx_runtime31 = require("react/jsx-runtime");
1519
1686
  function CodeBlock({ children, maxHeight = 300, className }) {
1520
- const [copied, setCopied] = (0, import_react21.useState)(false);
1521
- const handleCopy = (0, import_react21.useCallback)(() => {
1687
+ const [copied, setCopied] = (0, import_react24.useState)(false);
1688
+ const handleCopy = (0, import_react24.useCallback)(() => {
1522
1689
  navigator.clipboard.writeText(children).then(() => {
1523
1690
  setCopied(true);
1524
1691
  setTimeout(() => setCopied(false), 2e3);
1525
1692
  });
1526
1693
  }, [children]);
1527
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: cn("relative group", className), children: [
1528
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(ScrollArea, { style: { maxHeight }, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("pre", { className: "font-mono text-xs bg-surface p-3 rounded-md border border-border-subtle", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("code", { children }) }) }),
1529
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "absolute top-2 right-2 opacity-0 group-hover:opacity-100 transition-opacity", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
1694
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: cn("relative group", className), children: [
1695
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ScrollArea, { style: { maxHeight }, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("pre", { className: "font-mono text-xs bg-surface p-3 rounded-md border border-border-subtle", children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("code", { children }) }) }),
1696
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "absolute top-2 right-2 opacity-0 group-hover:opacity-100 transition-opacity", children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
1530
1697
  IconButton,
1531
1698
  {
1532
- icon: copied ? import_lucide_react6.Check : import_lucide_react6.Copy,
1699
+ icon: copied ? import_lucide_react7.Check : import_lucide_react7.Copy,
1533
1700
  "aria-label": "Copy code",
1534
1701
  variant: "ghost",
1535
1702
  size: "sm",
@@ -1540,28 +1707,28 @@ function CodeBlock({ children, maxHeight = 300, className }) {
1540
1707
  }
1541
1708
 
1542
1709
  // src/composites/filter-bar.tsx
1543
- var import_lucide_react7 = require("lucide-react");
1544
- var import_jsx_runtime30 = require("react/jsx-runtime");
1710
+ var import_lucide_react8 = require("lucide-react");
1711
+ var import_jsx_runtime32 = require("react/jsx-runtime");
1545
1712
  function FilterBar({ filters, values, onChange, className }) {
1546
1713
  const handleChange = (key, value) => {
1547
1714
  onChange({ ...values, [key]: value });
1548
1715
  };
1549
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: cn("flex items-center gap-2 flex-wrap", className), children: filters.map((filter) => {
1716
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: cn("flex items-center gap-2 flex-wrap", className), children: filters.map((filter) => {
1550
1717
  switch (filter.type) {
1551
1718
  case "search":
1552
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1719
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
1553
1720
  Input,
1554
1721
  {
1555
1722
  placeholder: filter.placeholder ?? "Search...",
1556
1723
  value: values[filter.key] ?? "",
1557
1724
  onChange: (e) => handleChange(filter.key, e.target.value),
1558
- leftSlot: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_lucide_react7.Search, { className: "h-3 w-3 text-foreground-subtle" }),
1725
+ leftSlot: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react8.Search, { className: "h-3 w-3 text-foreground-subtle" }),
1559
1726
  className: "w-48"
1560
1727
  },
1561
1728
  filter.key
1562
1729
  );
1563
1730
  case "select":
1564
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1731
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
1565
1732
  Select,
1566
1733
  {
1567
1734
  options: filter.options,
@@ -1572,10 +1739,10 @@ function FilterBar({ filters, values, onChange, className }) {
1572
1739
  filter.key
1573
1740
  );
1574
1741
  case "badge-toggle":
1575
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "flex items-center gap-1", children: filter.options.map((option) => {
1742
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "flex items-center gap-1", children: filter.options.map((option) => {
1576
1743
  const currentValue = values[filter.key];
1577
1744
  const isActive = currentValue === option.value;
1578
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1745
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
1579
1746
  "button",
1580
1747
  {
1581
1748
  type: "button",
@@ -1583,7 +1750,7 @@ function FilterBar({ filters, values, onChange, className }) {
1583
1750
  filter.key,
1584
1751
  isActive ? void 0 : option.value
1585
1752
  ),
1586
- children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1753
+ children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
1587
1754
  Badge,
1588
1755
  {
1589
1756
  variant: isActive ? "info" : "default",
@@ -1602,7 +1769,7 @@ function FilterBar({ filters, values, onChange, className }) {
1602
1769
  }
1603
1770
 
1604
1771
  // src/composites/app-shell/sidebar-item.tsx
1605
- var import_jsx_runtime31 = require("react/jsx-runtime");
1772
+ var import_jsx_runtime33 = require("react/jsx-runtime");
1606
1773
  function SidebarItem({
1607
1774
  label,
1608
1775
  icon: Icon,
@@ -1611,7 +1778,7 @@ function SidebarItem({
1611
1778
  active = false,
1612
1779
  className
1613
1780
  }) {
1614
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
1781
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
1615
1782
  "a",
1616
1783
  {
1617
1784
  href,
@@ -1621,33 +1788,33 @@ function SidebarItem({
1621
1788
  className
1622
1789
  ),
1623
1790
  children: [
1624
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Icon, { className: "h-3.5 w-3.5 shrink-0" }),
1625
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("span", { className: "truncate flex-1", children: label }),
1626
- badge !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Badge, { className: "ml-auto text-[10px] px-1.5 py-0", children: badge })
1791
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Icon, { className: "h-3.5 w-3.5 shrink-0" }),
1792
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "truncate flex-1", children: label }),
1793
+ badge !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Badge, { className: "ml-auto text-[10px] px-1.5 py-0", children: badge })
1627
1794
  ]
1628
1795
  }
1629
1796
  );
1630
1797
  }
1631
1798
 
1632
1799
  // src/composites/app-shell/sidebar.tsx
1633
- var import_jsx_runtime32 = require("react/jsx-runtime");
1634
- function Sidebar({ logo, sections, footer, className }) {
1635
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
1800
+ var import_jsx_runtime34 = require("react/jsx-runtime");
1801
+ function Sidebar({ logo, sections, footer, onNavigate, className }) {
1802
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
1636
1803
  "nav",
1637
1804
  {
1638
1805
  className: cn(
1639
- "w-44 bg-surface border-r border-border h-full flex flex-col",
1806
+ "bg-surface border-r border-border h-full flex flex-col",
1640
1807
  className
1641
1808
  ),
1642
1809
  children: [
1643
- logo && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "px-3 py-2 shrink-0", children: logo }),
1644
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "flex-1 overflow-auto px-1 py-1", children: sections.map((section, sectionIndex) => /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: cn(sectionIndex > 0 ? "mt-3" : ""), children: [
1645
- section.label && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-[10px] text-foreground-disabled uppercase tracking-wider px-2 mb-1 block", children: section.label }),
1646
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "flex flex-col gap-0.5", children: section.items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(SidebarItem, { ...item }, item.href)) })
1810
+ logo && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "px-3 py-2 shrink-0", children: logo }),
1811
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "flex-1 overflow-auto px-1 py-1", children: sections.map((section, sectionIndex) => /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: cn(sectionIndex > 0 ? "mt-3" : ""), children: [
1812
+ section.label && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "text-[10px] text-foreground-disabled uppercase tracking-wider px-2 mb-1 block", children: section.label }),
1813
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "flex flex-col gap-0.5", onClick: onNavigate, children: section.items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(SidebarItem, { ...item }, item.href)) })
1647
1814
  ] }, sectionIndex)) }),
1648
- footer && footer.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "shrink-0 px-1 pb-1", children: [
1649
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Separator, { className: "mb-1" }),
1650
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "flex flex-col gap-0.5", children: footer.map((item) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(SidebarItem, { ...item }, item.href)) })
1815
+ footer && footer.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "shrink-0 px-1 pb-1", children: [
1816
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(Separator, { className: "mb-1" }),
1817
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "flex flex-col gap-0.5", onClick: onNavigate, children: footer.map((item) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(SidebarItem, { ...item }, item.href)) })
1651
1818
  ] })
1652
1819
  ]
1653
1820
  }
@@ -1655,54 +1822,78 @@ function Sidebar({ logo, sections, footer, className }) {
1655
1822
  }
1656
1823
 
1657
1824
  // src/composites/app-shell/app-shell.tsx
1658
- var import_lucide_react8 = require("lucide-react");
1659
- var import_jsx_runtime33 = require("react/jsx-runtime");
1660
- function AppShell({ sidebar, header, children, className }) {
1661
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: cn("flex h-screen", className), children: [
1662
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Sidebar, { ...sidebar }),
1663
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex flex-1 flex-col min-w-0", children: [
1664
- header && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("header", { className: "flex items-center h-10 border-b border-border px-4 shrink-0", children: [
1665
- header.breadcrumbs && header.breadcrumbs.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("nav", { className: "flex items-center gap-1 text-xs flex-1 min-w-0", children: header.breadcrumbs.map((crumb, index) => {
1825
+ var import_react25 = require("react");
1826
+ var import_lucide_react9 = require("lucide-react");
1827
+ var import_jsx_runtime35 = require("react/jsx-runtime");
1828
+ function AppShell({ sidebar, header, mobileLogo, mobileActions, children, className }) {
1829
+ const isMobile = useIsMobile();
1830
+ const [drawerOpen, setDrawerOpen] = (0, import_react25.useState)(false);
1831
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: cn("flex h-screen", className), children: [
1832
+ !isMobile && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Sidebar, { ...sidebar, className: cn("w-44", sidebar.className) }),
1833
+ isMobile && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(MobileDrawer, { open: drawerOpen, onClose: () => setDrawerOpen(false), width: "w-64", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
1834
+ Sidebar,
1835
+ {
1836
+ ...sidebar,
1837
+ onNavigate: () => setDrawerOpen(false),
1838
+ className: "w-full border-r-0"
1839
+ }
1840
+ ) }),
1841
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "flex flex-1 flex-col min-w-0", children: [
1842
+ isMobile && /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("header", { className: "flex items-center h-12 border-b border-border px-3 shrink-0 bg-surface/80 backdrop-blur-sm", children: [
1843
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
1844
+ "button",
1845
+ {
1846
+ onClick: () => setDrawerOpen(true),
1847
+ className: "p-1.5 -ml-1.5 rounded-md hover:bg-surface-hover text-foreground-muted transition-colors",
1848
+ "aria-label": "Open menu",
1849
+ children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_lucide_react9.Menu, { className: "h-5 w-5" })
1850
+ }
1851
+ ),
1852
+ mobileLogo && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "flex-1 flex justify-center", children: mobileLogo }),
1853
+ mobileActions && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "shrink-0", children: mobileActions })
1854
+ ] }),
1855
+ !isMobile && header && /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("header", { className: "flex items-center h-10 border-b border-border px-4 shrink-0", children: [
1856
+ header.breadcrumbs && header.breadcrumbs.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("nav", { className: "flex items-center gap-1 text-xs flex-1 min-w-0", children: header.breadcrumbs.map((crumb, index) => {
1666
1857
  const isLast = index === header.breadcrumbs.length - 1;
1667
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("span", { className: "flex items-center gap-1", children: [
1668
- index > 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react8.ChevronRight, { className: "h-3 w-3 text-foreground-subtle shrink-0" }),
1669
- crumb.href && !isLast ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
1858
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { className: "flex items-center gap-1", children: [
1859
+ index > 0 && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_lucide_react9.ChevronRight, { className: "h-3 w-3 text-foreground-subtle shrink-0" }),
1860
+ crumb.href && !isLast ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
1670
1861
  "a",
1671
1862
  {
1672
1863
  href: crumb.href,
1673
1864
  className: "text-foreground-subtle hover:text-foreground transition-colors truncate",
1674
1865
  children: crumb.label
1675
1866
  }
1676
- ) : /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "text-foreground truncate", children: crumb.label })
1867
+ ) : /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "text-foreground truncate", children: crumb.label })
1677
1868
  ] }, index);
1678
1869
  }) }),
1679
- header.actions && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex items-center gap-2 ml-auto shrink-0", children: header.actions })
1870
+ header.actions && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "flex items-center gap-2 ml-auto shrink-0", children: header.actions })
1680
1871
  ] }),
1681
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("main", { className: "flex-1 overflow-auto p-4", children })
1872
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("main", { className: "flex-1 overflow-auto p-4", children })
1682
1873
  ] })
1683
1874
  ] });
1684
1875
  }
1685
1876
 
1686
1877
  // src/composites/data-table/data-table.tsx
1687
- var import_react22 = require("react");
1878
+ var import_react26 = require("react");
1688
1879
  var import_react_table = require("@tanstack/react-table");
1689
1880
 
1690
1881
  // src/composites/data-table/data-table-header.tsx
1691
- var import_lucide_react9 = require("lucide-react");
1692
- var import_jsx_runtime34 = require("react/jsx-runtime");
1882
+ var import_lucide_react10 = require("lucide-react");
1883
+ var import_jsx_runtime36 = require("react/jsx-runtime");
1693
1884
  function DataTableHeader({
1694
1885
  headerGroups,
1695
1886
  onSortingChange,
1696
1887
  stickyHeader,
1697
1888
  flexRender: render
1698
1889
  }) {
1699
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
1890
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1700
1891
  "thead",
1701
1892
  {
1702
1893
  className: cn(
1703
1894
  stickyHeader && "sticky top-0 z-10 bg-background"
1704
1895
  ),
1705
- children: headerGroups.map((headerGroup) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("tr", { className: "h-6", children: headerGroup.headers.map((header) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
1896
+ children: headerGroups.map((headerGroup) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("tr", { className: "h-6", children: headerGroup.headers.map((header) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1706
1897
  HeaderCell,
1707
1898
  {
1708
1899
  header,
@@ -1716,8 +1907,8 @@ function DataTableHeader({
1716
1907
  }
1717
1908
  function HeaderCell({ header, sortable, flexRender: render }) {
1718
1909
  const sorted = header.column.getIsSorted();
1719
- const SortIcon = sorted === "asc" ? import_lucide_react9.ArrowUp : sorted === "desc" ? import_lucide_react9.ArrowDown : import_lucide_react9.ArrowUpDown;
1720
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
1910
+ const SortIcon = sorted === "asc" ? import_lucide_react10.ArrowUp : sorted === "desc" ? import_lucide_react10.ArrowDown : import_lucide_react10.ArrowUpDown;
1911
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1721
1912
  "th",
1722
1913
  {
1723
1914
  className: cn(
@@ -1725,17 +1916,17 @@ function HeaderCell({ header, sortable, flexRender: render }) {
1725
1916
  sortable && "cursor-pointer select-none"
1726
1917
  ),
1727
1918
  onClick: sortable ? header.column.getToggleSortingHandler() : void 0,
1728
- children: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { className: "inline-flex items-center gap-1", children: [
1919
+ children: /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("span", { className: "inline-flex items-center gap-1", children: [
1729
1920
  header.isPlaceholder ? null : render(header.column.columnDef.header, header.getContext()),
1730
- sortable && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(SortIcon, { className: "h-3 w-3" })
1921
+ sortable && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(SortIcon, { className: "h-3 w-3" })
1731
1922
  ] })
1732
1923
  }
1733
1924
  );
1734
1925
  }
1735
1926
 
1736
1927
  // src/composites/data-table/data-table-row.tsx
1737
- var import_lucide_react10 = require("lucide-react");
1738
- var import_jsx_runtime35 = require("react/jsx-runtime");
1928
+ var import_lucide_react11 = require("lucide-react");
1929
+ var import_jsx_runtime37 = require("react/jsx-runtime");
1739
1930
  function DataTableRow({
1740
1931
  row,
1741
1932
  onRowClick,
@@ -1743,7 +1934,7 @@ function DataTableRow({
1743
1934
  flexRender: render
1744
1935
  }) {
1745
1936
  const actions = rowActions ? rowActions(row.original) : [];
1746
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
1937
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
1747
1938
  "tr",
1748
1939
  {
1749
1940
  className: cn(
@@ -1753,17 +1944,17 @@ function DataTableRow({
1753
1944
  ),
1754
1945
  onClick: onRowClick ? () => onRowClick(row.original) : void 0,
1755
1946
  children: [
1756
- row.getVisibleCells().map((cell) => /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(DataTableCell, { cell, flexRender: render }, cell.id)),
1757
- actions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("td", { className: "px-2 py-1.5 w-8", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(Dropdown, { children: [
1758
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
1947
+ row.getVisibleCells().map((cell) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(DataTableCell, { cell, flexRender: render }, cell.id)),
1948
+ actions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("td", { className: "px-2 py-1.5 w-8", children: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(Dropdown, { children: [
1949
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
1759
1950
  DropdownTrigger,
1760
1951
  {
1761
1952
  className: "p-0.5 rounded hover:bg-surface-hover",
1762
1953
  onClick: (e) => e.stopPropagation(),
1763
- children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_lucide_react10.MoreHorizontal, { className: "h-3.5 w-3.5 text-foreground-muted" })
1954
+ children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_lucide_react11.MoreHorizontal, { className: "h-3.5 w-3.5 text-foreground-muted" })
1764
1955
  }
1765
1956
  ),
1766
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(DropdownContent, { className: "right-0 left-auto", children: actions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
1957
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(DropdownContent, { className: "right-0 left-auto", children: actions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
1767
1958
  DropdownItem,
1768
1959
  {
1769
1960
  icon: action.icon,
@@ -1782,12 +1973,12 @@ function DataTableRow({
1782
1973
  );
1783
1974
  }
1784
1975
  function DataTableCell({ cell, flexRender: render }) {
1785
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("td", { className: "px-2 py-1.5 text-xs text-foreground", children: render(cell.column.columnDef.cell, cell.getContext()) });
1976
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("td", { className: "px-2 py-1.5 text-xs text-foreground", children: render(cell.column.columnDef.cell, cell.getContext()) });
1786
1977
  }
1787
1978
 
1788
1979
  // src/composites/data-table/data-table-pagination.tsx
1789
- var import_lucide_react11 = require("lucide-react");
1790
- var import_jsx_runtime36 = require("react/jsx-runtime");
1980
+ var import_lucide_react12 = require("lucide-react");
1981
+ var import_jsx_runtime38 = require("react/jsx-runtime");
1791
1982
  var PAGE_SIZE_OPTIONS = [
1792
1983
  { value: "10", label: "10" },
1793
1984
  { value: "25", label: "25" },
@@ -1802,10 +1993,10 @@ function DataTablePagination({
1802
1993
  }) {
1803
1994
  const totalPages = Math.max(1, Math.ceil(total / pageSize));
1804
1995
  const currentPage = page + 1;
1805
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex items-center justify-between px-2 py-2 text-xs text-foreground-muted", children: [
1806
- /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex items-center gap-2", children: [
1807
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { children: "Rows per page" }),
1808
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "w-16", children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1996
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "flex items-center justify-between px-2 py-2 text-xs text-foreground-muted", children: [
1997
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "flex items-center gap-2", children: [
1998
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { children: "Rows per page" }),
1999
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "w-16", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
1809
2000
  Select,
1810
2001
  {
1811
2002
  options: PAGE_SIZE_OPTIONS,
@@ -1817,17 +2008,17 @@ function DataTablePagination({
1817
2008
  }
1818
2009
  ) })
1819
2010
  ] }),
1820
- /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex items-center gap-2", children: [
1821
- /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("span", { children: [
2011
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "flex items-center gap-2", children: [
2012
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("span", { children: [
1822
2013
  "Page ",
1823
2014
  currentPage,
1824
2015
  " of ",
1825
2016
  totalPages
1826
2017
  ] }),
1827
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
2018
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
1828
2019
  IconButton,
1829
2020
  {
1830
- icon: import_lucide_react11.ChevronLeft,
2021
+ icon: import_lucide_react12.ChevronLeft,
1831
2022
  "aria-label": "Previous page",
1832
2023
  variant: "ghost",
1833
2024
  size: "sm",
@@ -1835,10 +2026,10 @@ function DataTablePagination({
1835
2026
  onClick: () => onPaginationChange?.({ pageIndex: page - 1, pageSize })
1836
2027
  }
1837
2028
  ),
1838
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
2029
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
1839
2030
  IconButton,
1840
2031
  {
1841
- icon: import_lucide_react11.ChevronRight,
2032
+ icon: import_lucide_react12.ChevronRight,
1842
2033
  "aria-label": "Next page",
1843
2034
  variant: "ghost",
1844
2035
  size: "sm",
@@ -1851,7 +2042,7 @@ function DataTablePagination({
1851
2042
  }
1852
2043
 
1853
2044
  // src/composites/data-table/data-table.tsx
1854
- var import_jsx_runtime37 = require("react/jsx-runtime");
2045
+ var import_jsx_runtime39 = require("react/jsx-runtime");
1855
2046
  function DataTable({
1856
2047
  data,
1857
2048
  columns: userColumns,
@@ -1870,11 +2061,11 @@ function DataTable({
1870
2061
  stickyHeader = false,
1871
2062
  className
1872
2063
  }) {
1873
- const columns = (0, import_react22.useMemo)(() => {
2064
+ const columns = (0, import_react26.useMemo)(() => {
1874
2065
  if (!selectable) return userColumns;
1875
2066
  const selectColumn = {
1876
2067
  id: "__select",
1877
- header: ({ table: table2 }) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
2068
+ header: ({ table: table2 }) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
1878
2069
  Checkbox,
1879
2070
  {
1880
2071
  checked: table2.getIsAllPageRowsSelected(),
@@ -1882,7 +2073,7 @@ function DataTable({
1882
2073
  "aria-label": "Select all"
1883
2074
  }
1884
2075
  ),
1885
- cell: ({ row }) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
2076
+ cell: ({ row }) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
1886
2077
  Checkbox,
1887
2078
  {
1888
2079
  checked: row.getIsSelected(),
@@ -1920,9 +2111,9 @@ function DataTable({
1920
2111
  pageCount: pagination ? Math.ceil(pagination.total / pagination.pageSize) : void 0
1921
2112
  });
1922
2113
  const hasActions = !!rowActions;
1923
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: cn("overflow-auto", className), children: [
1924
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("table", { className: "w-full border-collapse", children: [
1925
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
2114
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: cn("overflow-auto", className), children: [
2115
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("table", { className: "w-full border-collapse", children: [
2116
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
1926
2117
  DataTableHeader,
1927
2118
  {
1928
2119
  headerGroups: table.getHeaderGroups(),
@@ -1931,14 +2122,14 @@ function DataTable({
1931
2122
  flexRender: import_react_table.flexRender
1932
2123
  }
1933
2124
  ),
1934
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("tbody", { children: loading ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(LoadingRows, { colSpan: columns.length + (hasActions ? 1 : 0), compact }) : table.getRowModel().rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
2125
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("tbody", { children: loading ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(LoadingRows, { colSpan: columns.length + (hasActions ? 1 : 0), compact }) : table.getRowModel().rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
1935
2126
  "td",
1936
2127
  {
1937
2128
  colSpan: columns.length + (hasActions ? 1 : 0),
1938
2129
  className: "text-center py-8 text-xs text-foreground-muted",
1939
2130
  children: emptyState ?? "No data"
1940
2131
  }
1941
- ) }) : table.getRowModel().rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
2132
+ ) }) : table.getRowModel().rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
1942
2133
  DataTableRow,
1943
2134
  {
1944
2135
  row,
@@ -1949,7 +2140,7 @@ function DataTable({
1949
2140
  row.id
1950
2141
  )) })
1951
2142
  ] }),
1952
- pagination && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
2143
+ pagination && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
1953
2144
  DataTablePagination,
1954
2145
  {
1955
2146
  page: pagination.page,
@@ -1961,11 +2152,11 @@ function DataTable({
1961
2152
  ] });
1962
2153
  }
1963
2154
  function LoadingRows({ colSpan, compact }) {
1964
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_jsx_runtime37.Fragment, { children: Array.from({ length: 5 }).map((_, rowIdx) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("tr", { className: compact ? "h-7" : "h-9", children: Array.from({ length: colSpan }).map((_2, colIdx) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("td", { className: "px-2 py-1.5", children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(Skeleton, { className: "h-3 w-full" }) }, colIdx)) }, rowIdx)) });
2155
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_jsx_runtime39.Fragment, { children: Array.from({ length: 5 }).map((_, rowIdx) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("tr", { className: compact ? "h-7" : "h-9", children: Array.from({ length: colSpan }).map((_2, colIdx) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("td", { className: "px-2 py-1.5", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Skeleton, { className: "h-3 w-full" }) }, colIdx)) }, rowIdx)) });
1965
2156
  }
1966
2157
 
1967
2158
  // src/composites/device-card.tsx
1968
- var import_jsx_runtime38 = require("react/jsx-runtime");
2159
+ var import_jsx_runtime40 = require("react/jsx-runtime");
1969
2160
  var STATUS_COLORS = {
1970
2161
  online: "bg-success",
1971
2162
  offline: "bg-danger",
@@ -1984,7 +2175,7 @@ function DeviceCard({
1984
2175
  className
1985
2176
  }) {
1986
2177
  const isOffline = status === "offline";
1987
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
2178
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
1988
2179
  "div",
1989
2180
  {
1990
2181
  onClick,
@@ -1996,18 +2187,18 @@ function DeviceCard({
1996
2187
  className
1997
2188
  ),
1998
2189
  children: [
1999
- /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "flex items-center justify-between mb-2", children: [
2000
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "text-sm font-medium truncate", children: title }),
2001
- status && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: cn("h-2 w-2 rounded-full shrink-0", STATUS_COLORS[status]) })
2190
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex items-center justify-between mb-2", children: [
2191
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "text-sm font-medium truncate", children: title }),
2192
+ status && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: cn("h-2 w-2 rounded-full shrink-0", STATUS_COLORS[status]) })
2002
2193
  ] }),
2003
- subtitle && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "text-[11px] text-foreground-muted", children: subtitle }),
2004
- badges && badges.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "flex flex-wrap gap-1 mt-2", children: badges.map((badge, i) => {
2194
+ subtitle && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "text-[11px] text-foreground-muted", children: subtitle }),
2195
+ badges && badges.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "flex flex-wrap gap-1 mt-2", children: badges.map((badge, i) => {
2005
2196
  const cls = cn(
2006
2197
  "rounded px-1.5 py-0.5 text-[10px] flex items-center gap-0.5",
2007
2198
  selected ? "bg-primary/20" : "bg-surface-hover",
2008
2199
  badge.onClick && "hover:opacity-80 transition-opacity cursor-pointer"
2009
2200
  );
2010
- return badge.onClick ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
2201
+ return badge.onClick ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
2011
2202
  "button",
2012
2203
  {
2013
2204
  onClick: (e) => {
@@ -2021,12 +2212,12 @@ function DeviceCard({
2021
2212
  ]
2022
2213
  },
2023
2214
  i
2024
- ) : /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("span", { className: cls, children: [
2215
+ ) : /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("span", { className: cls, children: [
2025
2216
  badge.icon,
2026
2217
  badge.label
2027
2218
  ] }, i);
2028
2219
  }) }),
2029
- !isOffline && actions && actions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "flex items-center gap-0.5 mt-2 -mb-1", children: actions.map((action, i) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
2220
+ !isOffline && actions && actions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "flex items-center gap-0.5 mt-2 -mb-1", children: actions.map((action, i) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
2030
2221
  "button",
2031
2222
  {
2032
2223
  onClick: (e) => {
@@ -2040,21 +2231,21 @@ function DeviceCard({
2040
2231
  },
2041
2232
  i
2042
2233
  )) }),
2043
- isOffline && offlineAction && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "mt-2", onClick: (e) => e.stopPropagation(), children: offlineAction })
2234
+ isOffline && offlineAction && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "mt-2", onClick: (e) => e.stopPropagation(), children: offlineAction })
2044
2235
  ]
2045
2236
  }
2046
2237
  );
2047
2238
  }
2048
2239
 
2049
2240
  // src/composites/device-grid.tsx
2050
- var import_jsx_runtime39 = require("react/jsx-runtime");
2241
+ var import_jsx_runtime41 = require("react/jsx-runtime");
2051
2242
  function DeviceGrid({
2052
2243
  children,
2053
2244
  minCardWidth = 220,
2054
2245
  gap = 3,
2055
2246
  className
2056
2247
  }) {
2057
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
2248
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
2058
2249
  "div",
2059
2250
  {
2060
2251
  className: cn(
@@ -2072,9 +2263,9 @@ function DeviceGrid({
2072
2263
  }
2073
2264
 
2074
2265
  // src/composites/pipeline-step.tsx
2075
- var import_react23 = require("react");
2076
- var import_lucide_react12 = require("lucide-react");
2077
- var import_jsx_runtime40 = require("react/jsx-runtime");
2266
+ var import_react27 = require("react");
2267
+ var import_lucide_react13 = require("lucide-react");
2268
+ var import_jsx_runtime42 = require("react/jsx-runtime");
2078
2269
  var ADDON_COLORS = {
2079
2270
  "object-detection": "border-l-blue-500",
2080
2271
  "motion-detection": "border-l-amber-500",
@@ -2150,7 +2341,7 @@ function PipelineStep({
2150
2341
  onDelete,
2151
2342
  readOnly = false
2152
2343
  }) {
2153
- const [expanded, setExpanded] = (0, import_react23.useState)(false);
2344
+ const [expanded, setExpanded] = (0, import_react27.useState)(false);
2154
2345
  const color = borderColor(step.addonId, step.slot);
2155
2346
  const backends = backendsForRuntime(step.runtime, capabilities, schema);
2156
2347
  const rtOptions = runtimeOptions(capabilities);
@@ -2173,7 +2364,7 @@ function PipelineStep({
2173
2364
  if (e.target.closest(".step-config")) return;
2174
2365
  setExpanded((v) => !v);
2175
2366
  }
2176
- return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "space-y-2", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
2367
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "space-y-2", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
2177
2368
  "div",
2178
2369
  {
2179
2370
  className: cn(
@@ -2182,18 +2373,18 @@ function PipelineStep({
2182
2373
  !step.enabled && "opacity-[0.45]"
2183
2374
  ),
2184
2375
  children: [
2185
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex items-center gap-2.5 px-3 py-2.5 cursor-pointer select-none", onClick: handleClick, children: [
2186
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "text-foreground-subtle", children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_lucide_react12.ChevronDown, { className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_lucide_react12.ChevronRight, { className: "h-4 w-4" }) }),
2187
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex-1 min-w-0", children: [
2188
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "text-[10px] uppercase tracking-wider font-medium text-foreground-subtle/60 block leading-none", children: step.slot }),
2189
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "text-sm font-semibold text-foreground truncate block leading-tight", children: step.addonName }),
2190
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex items-center gap-1 mt-0.5 flex-wrap", children: [
2191
- step.inputClasses.map((c) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "text-[9px] uppercase font-semibold tracking-wide px-1.5 py-0.5 rounded bg-blue-500/12 text-blue-400", children: c }, c)),
2192
- step.inputClasses.length > 0 && step.outputClasses.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "text-foreground-subtle/40 text-[10px]", children: "\u2192" }),
2193
- step.outputClasses.map((c) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "text-[9px] uppercase font-semibold tracking-wide px-1.5 py-0.5 rounded bg-green-500/12 text-green-400", children: c }, c))
2376
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex items-center gap-2.5 px-3 py-2.5 cursor-pointer select-none", onClick: handleClick, children: [
2377
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "text-foreground-subtle", children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_lucide_react13.ChevronDown, { className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_lucide_react13.ChevronRight, { className: "h-4 w-4" }) }),
2378
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex-1 min-w-0", children: [
2379
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "text-[10px] uppercase tracking-wider font-medium text-foreground-subtle/60 block leading-none", children: step.slot }),
2380
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "text-sm font-semibold text-foreground truncate block leading-tight", children: step.addonName }),
2381
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex items-center gap-1 mt-0.5 flex-wrap", children: [
2382
+ step.inputClasses.map((c) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "text-[9px] uppercase font-semibold tracking-wide px-1.5 py-0.5 rounded bg-blue-500/12 text-blue-400", children: c }, c)),
2383
+ step.inputClasses.length > 0 && step.outputClasses.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "text-foreground-subtle/40 text-[10px]", children: "\u2192" }),
2384
+ step.outputClasses.map((c) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "text-[9px] uppercase font-semibold tracking-wide px-1.5 py-0.5 rounded bg-green-500/12 text-green-400", children: c }, c))
2194
2385
  ] })
2195
2386
  ] }),
2196
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
2387
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2197
2388
  "button",
2198
2389
  {
2199
2390
  onClick: (e) => {
@@ -2204,16 +2395,16 @@ function PipelineStep({
2204
2395
  "relative inline-flex h-6 w-11 shrink-0 items-center rounded-full transition-colors",
2205
2396
  step.enabled ? "bg-success" : "bg-foreground-subtle/30"
2206
2397
  ),
2207
- children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: cn(
2398
+ children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: cn(
2208
2399
  "inline-block h-4 w-4 rounded-full bg-white shadow transition-transform",
2209
2400
  step.enabled ? "translate-x-6" : "translate-x-1"
2210
2401
  ) })
2211
2402
  }
2212
2403
  )
2213
2404
  ] }),
2214
- expanded && /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "step-config border-t border-border bg-background px-4 py-4 space-y-3", children: [
2215
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "grid grid-cols-2 gap-3", children: [
2216
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
2405
+ expanded && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "step-config border-t border-border bg-background px-4 py-4 space-y-3", children: [
2406
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "grid grid-cols-2 gap-3", children: [
2407
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2217
2408
  ConfigSelect,
2218
2409
  {
2219
2410
  label: "Agent",
@@ -2223,7 +2414,7 @@ function PipelineStep({
2223
2414
  onChange: (v) => onChange({ ...step, agentId: v })
2224
2415
  }
2225
2416
  ),
2226
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
2417
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2227
2418
  ConfigSelect,
2228
2419
  {
2229
2420
  label: "Runtime",
@@ -2233,7 +2424,7 @@ function PipelineStep({
2233
2424
  onChange: (v) => onChange({ ...step, runtime: v })
2234
2425
  }
2235
2426
  ),
2236
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
2427
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2237
2428
  ConfigSelect,
2238
2429
  {
2239
2430
  label: "Backend",
@@ -2243,7 +2434,7 @@ function PipelineStep({
2243
2434
  onChange: (v) => onChange({ ...step, backend: v })
2244
2435
  }
2245
2436
  ),
2246
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
2437
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2247
2438
  ConfigSelect,
2248
2439
  {
2249
2440
  label: "Model",
@@ -2254,15 +2445,15 @@ function PipelineStep({
2254
2445
  }
2255
2446
  )
2256
2447
  ] }),
2257
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { children: [
2258
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex items-center justify-between mb-1", children: [
2259
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "text-[10px] font-medium text-foreground-subtle uppercase tracking-wide", children: "Confidence" }),
2260
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("span", { className: "text-xs font-medium text-foreground tabular-nums", children: [
2448
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { children: [
2449
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex items-center justify-between mb-1", children: [
2450
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "text-[10px] font-medium text-foreground-subtle uppercase tracking-wide", children: "Confidence" }),
2451
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: "text-xs font-medium text-foreground tabular-nums", children: [
2261
2452
  (step.confidence * 100).toFixed(0),
2262
2453
  "%"
2263
2454
  ] })
2264
2455
  ] }),
2265
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
2456
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2266
2457
  "input",
2267
2458
  {
2268
2459
  type: "range",
@@ -2282,9 +2473,9 @@ function PipelineStep({
2282
2473
  ) });
2283
2474
  }
2284
2475
  function ConfigSelect({ label, value, options, disabled, onChange }) {
2285
- return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { children: [
2286
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("label", { className: "block text-[10px] font-medium text-foreground-subtle uppercase tracking-wide mb-1.5", children: label }),
2287
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
2476
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { children: [
2477
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("label", { className: "block text-[10px] font-medium text-foreground-subtle uppercase tracking-wide mb-1.5", children: label }),
2478
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
2288
2479
  "select",
2289
2480
  {
2290
2481
  value,
@@ -2292,8 +2483,8 @@ function ConfigSelect({ label, value, options, disabled, onChange }) {
2292
2483
  disabled,
2293
2484
  className: "w-full rounded-lg border border-border bg-surface px-3 py-2 text-xs text-foreground focus:outline-none focus:border-primary/50",
2294
2485
  children: [
2295
- options.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("option", { value, children: value || "default" }),
2296
- options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("option", { value: o.value, disabled: o.disabled, children: o.label }, o.value))
2486
+ options.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value, children: value || "default" }),
2487
+ options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: o.value, disabled: o.disabled, children: o.label }, o.value))
2297
2488
  ]
2298
2489
  }
2299
2490
  )
@@ -2301,30 +2492,30 @@ function ConfigSelect({ label, value, options, disabled, onChange }) {
2301
2492
  }
2302
2493
 
2303
2494
  // src/composites/pipeline-runtime-selector.tsx
2304
- var import_lucide_react13 = require("lucide-react");
2305
- var import_jsx_runtime41 = require("react/jsx-runtime");
2495
+ var import_lucide_react14 = require("lucide-react");
2496
+ var import_jsx_runtime43 = require("react/jsx-runtime");
2306
2497
  function PipelineRuntimeSelector({ options, value, onChange }) {
2307
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "flex flex-wrap gap-2", children: options.map((opt) => {
2498
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "flex flex-wrap gap-2", children: options.map((opt) => {
2308
2499
  const active = opt.id === value;
2309
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
2500
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
2310
2501
  "button",
2311
2502
  {
2312
2503
  onClick: () => opt.available && onChange(opt.id),
2313
2504
  disabled: !opt.available,
2314
2505
  className: `flex items-center gap-2 rounded-lg border px-3 py-2 text-xs font-medium transition-all ${active ? "border-primary/40 bg-primary/10 text-primary" : opt.available ? "border-border bg-surface text-foreground-subtle hover:bg-surface-hover hover:text-foreground" : "border-border/40 bg-surface/40 text-foreground-subtle/40 cursor-not-allowed"}`,
2315
2506
  children: [
2316
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_lucide_react13.Cpu, { className: "h-3.5 w-3.5 shrink-0" }),
2507
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react14.Cpu, { className: "h-3.5 w-3.5 shrink-0" }),
2317
2508
  opt.label,
2318
- opt.isBest && /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("span", { className: "inline-flex items-center gap-0.5 rounded-full bg-amber-500/15 px-1.5 py-0.5 text-[10px] font-semibold text-amber-400", children: [
2319
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_lucide_react13.Star, { className: "h-2.5 w-2.5" }),
2509
+ opt.isBest && /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { className: "inline-flex items-center gap-0.5 rounded-full bg-amber-500/15 px-1.5 py-0.5 text-[10px] font-semibold text-amber-400", children: [
2510
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react14.Star, { className: "h-2.5 w-2.5" }),
2320
2511
  "Best"
2321
2512
  ] }),
2322
- opt.platformScore != null && /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("span", { className: "text-[10px] text-foreground-subtle/60", children: [
2513
+ opt.platformScore != null && /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { className: "text-[10px] text-foreground-subtle/60", children: [
2323
2514
  "(",
2324
2515
  opt.platformScore,
2325
2516
  ")"
2326
2517
  ] }),
2327
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
2518
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
2328
2519
  "span",
2329
2520
  {
2330
2521
  className: `h-1.5 w-1.5 rounded-full ${opt.available ? "bg-success" : "bg-danger"}`
@@ -2338,8 +2529,8 @@ function PipelineRuntimeSelector({ options, value, onChange }) {
2338
2529
  }
2339
2530
 
2340
2531
  // src/composites/pipeline-builder.tsx
2341
- var import_react24 = require("react");
2342
- var import_lucide_react14 = require("lucide-react");
2532
+ var import_react28 = require("react");
2533
+ var import_lucide_react15 = require("lucide-react");
2343
2534
 
2344
2535
  // src/lib/validate-template.ts
2345
2536
  function validateTemplate(steps, schema) {
@@ -2371,7 +2562,7 @@ function validateTemplate(steps, schema) {
2371
2562
  }
2372
2563
 
2373
2564
  // src/composites/pipeline-builder.tsx
2374
- var import_jsx_runtime42 = require("react/jsx-runtime");
2565
+ var import_jsx_runtime44 = require("react/jsx-runtime");
2375
2566
  function buildSchemaMap(schema) {
2376
2567
  const map = /* @__PURE__ */ new Map();
2377
2568
  for (const slot of schema.slots) {
@@ -2400,20 +2591,20 @@ function createDefaultStep(addon, fallbackRuntime, fallbackBackend) {
2400
2591
  };
2401
2592
  }
2402
2593
  function PlaceholderStep({ addon, onClick }) {
2403
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2594
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
2404
2595
  "button",
2405
2596
  {
2406
2597
  type: "button",
2407
2598
  onClick,
2408
2599
  className: "w-full rounded-xl border-2 border-dashed border-border/60 px-4 py-3 text-left transition-all hover:border-primary/30 hover:bg-surface/60 group",
2409
- children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex items-center gap-3", children: [
2410
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_lucide_react14.PlusCircle, { className: "h-[18px] w-[18px] text-foreground-subtle/30 group-hover:text-primary/60 shrink-0" }),
2411
- /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex-1 min-w-0", children: [
2412
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "text-[13px] font-medium text-foreground-subtle/50 group-hover:text-foreground-subtle block truncate", children: addon.name }),
2413
- /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex items-center gap-1 mt-0.5 flex-wrap", children: [
2414
- addon.inputClasses.map((c) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "text-[9px] uppercase font-semibold tracking-wide px-1.5 py-0.5 rounded bg-blue-500/8 text-blue-400/50", children: c }, c)),
2415
- addon.inputClasses.length > 0 && addon.outputClasses.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "text-foreground-subtle/25 text-[10px]", children: "\u2192" }),
2416
- addon.outputClasses.map((c) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "text-[9px] uppercase font-semibold tracking-wide px-1.5 py-0.5 rounded bg-green-500/8 text-green-400/50", children: c }, c))
2600
+ children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex items-center gap-3", children: [
2601
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_lucide_react15.PlusCircle, { className: "h-[18px] w-[18px] text-foreground-subtle/30 group-hover:text-primary/60 shrink-0" }),
2602
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex-1 min-w-0", children: [
2603
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "text-[13px] font-medium text-foreground-subtle/50 group-hover:text-foreground-subtle block truncate", children: addon.name }),
2604
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex items-center gap-1 mt-0.5 flex-wrap", children: [
2605
+ addon.inputClasses.map((c) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "text-[9px] uppercase font-semibold tracking-wide px-1.5 py-0.5 rounded bg-blue-500/8 text-blue-400/50", children: c }, c)),
2606
+ addon.inputClasses.length > 0 && addon.outputClasses.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "text-foreground-subtle/25 text-[10px]", children: "\u2192" }),
2607
+ addon.outputClasses.map((c) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "text-[9px] uppercase font-semibold tracking-wide px-1.5 py-0.5 rounded bg-green-500/8 text-green-400/50", children: c }, c))
2417
2608
  ] })
2418
2609
  ] })
2419
2610
  ] })
@@ -2434,9 +2625,9 @@ function PipelineBuilder({
2434
2625
  readOnly = false,
2435
2626
  excludeAddons = []
2436
2627
  }) {
2437
- const excluded = (0, import_react24.useMemo)(() => new Set(excludeAddons), [excludeAddons]);
2438
- const schemaMap = (0, import_react24.useMemo)(() => buildSchemaMap(schema), [schema]);
2439
- const [warnings, setWarnings] = (0, import_react24.useState)([]);
2628
+ const excluded = (0, import_react28.useMemo)(() => new Set(excludeAddons), [excludeAddons]);
2629
+ const schemaMap = (0, import_react28.useMemo)(() => buildSchemaMap(schema), [schema]);
2630
+ const [warnings, setWarnings] = (0, import_react28.useState)([]);
2440
2631
  const bestPlatformScore = capabilities.platformScores?.find((s) => s.available);
2441
2632
  const hasPython = capabilities.runtimes.python.available && capabilities.runtimes.python.backends.some((b) => b.available);
2442
2633
  const defaultRuntime = bestPlatformScore?.runtime ?? (hasPython ? "python" : "node");
@@ -2525,8 +2716,8 @@ function PipelineBuilder({
2525
2716
  }
2526
2717
  function renderStep(step) {
2527
2718
  const childPlaceholders = getChildPlaceholders(step);
2528
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "space-y-1.5", children: [
2529
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2719
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "space-y-1.5", children: [
2720
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
2530
2721
  PipelineStep,
2531
2722
  {
2532
2723
  step,
@@ -2538,12 +2729,12 @@ function PipelineBuilder({
2538
2729
  readOnly
2539
2730
  }
2540
2731
  ),
2541
- (step.children.length > 0 || childPlaceholders.length > 0) && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "ml-6 pl-4 border-l-2 border-dashed border-border/40 space-y-1.5", children: [
2542
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "text-[10px] font-semibold uppercase tracking-widest text-foreground-subtle/40", children: "Slot: Cropper / Classifier" }),
2732
+ (step.children.length > 0 || childPlaceholders.length > 0) && /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "ml-6 pl-4 border-l-2 border-dashed border-border/40 space-y-1.5", children: [
2733
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "text-[10px] font-semibold uppercase tracking-widest text-foreground-subtle/40", children: "Slot: Cropper / Classifier" }),
2543
2734
  step.children.map((child) => {
2544
2735
  const childChildPlaceholders = getChildPlaceholders(child);
2545
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "space-y-1.5", children: [
2546
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2736
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "space-y-1.5", children: [
2737
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
2547
2738
  PipelineStep,
2548
2739
  {
2549
2740
  step: child,
@@ -2566,9 +2757,9 @@ function PipelineBuilder({
2566
2757
  readOnly
2567
2758
  }
2568
2759
  ),
2569
- (child.children.length > 0 || childChildPlaceholders.length > 0) && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "ml-6 pl-4 border-l-2 border-dashed border-border/30 space-y-1.5", children: [
2570
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "text-[10px] font-semibold uppercase tracking-widest text-foreground-subtle/30", children: "Slot: Recognizer" }),
2571
- child.children.map((grandchild) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2760
+ (child.children.length > 0 || childChildPlaceholders.length > 0) && /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "ml-6 pl-4 border-l-2 border-dashed border-border/30 space-y-1.5", children: [
2761
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "text-[10px] font-semibold uppercase tracking-widest text-foreground-subtle/30", children: "Slot: Recognizer" }),
2762
+ child.children.map((grandchild) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
2572
2763
  PipelineStep,
2573
2764
  {
2574
2765
  step: grandchild,
@@ -2596,7 +2787,7 @@ function PipelineBuilder({
2596
2787
  },
2597
2788
  grandchild.addonId
2598
2789
  )),
2599
- !readOnly && childChildPlaceholders.map((addon) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2790
+ !readOnly && childChildPlaceholders.map((addon) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
2600
2791
  PlaceholderStep,
2601
2792
  {
2602
2793
  addon,
@@ -2615,7 +2806,7 @@ function PipelineBuilder({
2615
2806
  ] })
2616
2807
  ] }, child.addonId);
2617
2808
  }),
2618
- !readOnly && childPlaceholders.map((addon) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2809
+ !readOnly && childPlaceholders.map((addon) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
2619
2810
  PlaceholderStep,
2620
2811
  {
2621
2812
  addon,
@@ -2627,22 +2818,22 @@ function PipelineBuilder({
2627
2818
  ] }, step.addonId);
2628
2819
  }
2629
2820
  const rootSlots = schema.slots.filter((s) => s.parentSlot === null).sort((a, b) => a.priority - b.priority);
2630
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "space-y-4", children: [
2631
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "rounded-xl border border-border bg-surface p-3", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex items-center gap-2", children: [
2632
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "relative flex-1 min-w-0", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
2821
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "space-y-4", children: [
2822
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "rounded-xl border border-border bg-surface p-3", children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex items-center gap-2", children: [
2823
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "relative flex-1 min-w-0", children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
2633
2824
  "select",
2634
2825
  {
2635
2826
  value: selectedTemplateId ?? "",
2636
2827
  onChange: handleSelectTemplate,
2637
2828
  className: "w-full rounded-lg border border-border bg-background px-3 py-2 text-sm text-foreground focus:outline-none focus:border-primary/50",
2638
2829
  children: [
2639
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: "", children: "No template" }),
2640
- templates.map((t) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: t.id, children: t.name }, t.id))
2830
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("option", { value: "", children: "No template" }),
2831
+ templates.map((t) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("option", { value: t.id, children: t.name }, t.id))
2641
2832
  ]
2642
2833
  }
2643
2834
  ) }),
2644
- dirty && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "h-1.5 w-1.5 rounded-full bg-amber-500 shrink-0" }),
2645
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2835
+ dirty && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "h-1.5 w-1.5 rounded-full bg-amber-500 shrink-0" }),
2836
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
2646
2837
  "button",
2647
2838
  {
2648
2839
  onClick: handleSave,
@@ -2652,10 +2843,10 @@ function PipelineBuilder({
2652
2843
  "p-2 rounded-lg border border-border transition-colors",
2653
2844
  selectedTemplateId && !readOnly ? "text-foreground-subtle hover:bg-surface-hover" : "text-foreground-subtle/30 cursor-not-allowed"
2654
2845
  ),
2655
- children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_lucide_react14.Save, { className: "h-4 w-4" })
2846
+ children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_lucide_react15.Save, { className: "h-4 w-4" })
2656
2847
  }
2657
2848
  ),
2658
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2849
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
2659
2850
  "button",
2660
2851
  {
2661
2852
  onClick: handleSaveAs,
@@ -2665,10 +2856,10 @@ function PipelineBuilder({
2665
2856
  "p-2 rounded-lg border border-border transition-colors",
2666
2857
  !readOnly ? "text-foreground-subtle hover:bg-surface-hover" : "text-foreground-subtle/30 cursor-not-allowed"
2667
2858
  ),
2668
- children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_lucide_react14.CopyPlus, { className: "h-4 w-4" })
2859
+ children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_lucide_react15.CopyPlus, { className: "h-4 w-4" })
2669
2860
  }
2670
2861
  ),
2671
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2862
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
2672
2863
  "button",
2673
2864
  {
2674
2865
  onClick: handleDelete,
@@ -2678,16 +2869,16 @@ function PipelineBuilder({
2678
2869
  "p-2 rounded-lg border border-border transition-colors",
2679
2870
  selectedTemplateId && !readOnly ? "text-foreground-subtle hover:text-danger" : "text-foreground-subtle/30 cursor-not-allowed"
2680
2871
  ),
2681
- children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_lucide_react14.Trash2, { className: "h-4 w-4" })
2872
+ children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_lucide_react15.Trash2, { className: "h-4 w-4" })
2682
2873
  }
2683
2874
  )
2684
2875
  ] }) }),
2685
- warnings.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "rounded-lg border border-amber-500/30 bg-amber-500/5 p-3 text-xs text-amber-400 space-y-1", children: [
2686
- /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex items-center justify-between", children: [
2687
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "font-medium", children: "Template loaded with warnings:" }),
2688
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("button", { onClick: () => setWarnings([]), className: "text-amber-400/60 hover:text-amber-400", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_lucide_react14.X, { className: "h-3.5 w-3.5" }) })
2876
+ warnings.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "rounded-lg border border-amber-500/30 bg-amber-500/5 p-3 text-xs text-amber-400 space-y-1", children: [
2877
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex items-center justify-between", children: [
2878
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "font-medium", children: "Template loaded with warnings:" }),
2879
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("button", { onClick: () => setWarnings([]), className: "text-amber-400/60 hover:text-amber-400", children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_lucide_react15.X, { className: "h-3.5 w-3.5" }) })
2689
2880
  ] }),
2690
- warnings.map((w, i) => /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { children: [
2881
+ warnings.map((w, i) => /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { children: [
2691
2882
  "\u2022 ",
2692
2883
  w
2693
2884
  ] }, i))
@@ -2695,13 +2886,13 @@ function PipelineBuilder({
2695
2886
  rootSlots.map((slot) => {
2696
2887
  const slotSteps = steps.filter((s) => s.slot === slot.id && !excluded.has(s.addonId));
2697
2888
  const missingRootAddons = slot.addons.filter((a) => !existingIds.has(a.id) && !excluded.has(a.id));
2698
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "space-y-2", children: [
2699
- /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: "text-[10px] font-semibold uppercase tracking-widest text-foreground-subtle/50", children: [
2889
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "space-y-2", children: [
2890
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: "text-[10px] font-semibold uppercase tracking-widest text-foreground-subtle/50", children: [
2700
2891
  "Slot: ",
2701
2892
  slot.label
2702
2893
  ] }),
2703
2894
  slotSteps.map((step) => renderStep(step)),
2704
- !readOnly && missingRootAddons.map((addon) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(PlaceholderStep, { addon, onClick: () => {
2895
+ !readOnly && missingRootAddons.map((addon) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(PlaceholderStep, { addon, onClick: () => {
2705
2896
  onChange([...steps, createDefaultStep(addon, defaultRuntime, defaultBackend)]);
2706
2897
  } }, addon.id))
2707
2898
  ] }, slot.id);
@@ -2781,8 +2972,8 @@ function getClassColor(className, customColors) {
2781
2972
  }
2782
2973
 
2783
2974
  // src/composites/detection-canvas.tsx
2784
- var import_react25 = require("react");
2785
- var import_jsx_runtime43 = require("react/jsx-runtime");
2975
+ var import_react29 = require("react");
2976
+ var import_jsx_runtime45 = require("react/jsx-runtime");
2786
2977
  var DEFAULT_CLASS_COLORS = CLASS_COLORS;
2787
2978
  function DetectionCanvas({
2788
2979
  src,
@@ -2802,7 +2993,7 @@ function DetectionCanvas({
2802
2993
  }
2803
2994
  const ratio = aspectRatio ?? (imageWidth && imageHeight ? `${imageWidth}/${imageHeight}` : "16/9");
2804
2995
  const filteredDetections = detections.filter((d) => d.confidence >= minConfidence);
2805
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
2996
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
2806
2997
  "div",
2807
2998
  {
2808
2999
  className: cn(
@@ -2810,10 +3001,10 @@ function DetectionCanvas({
2810
3001
  className
2811
3002
  ),
2812
3003
  style: { aspectRatio: ratio },
2813
- children: src ? /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_jsx_runtime43.Fragment, { children: [
2814
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("img", { src, className: "absolute inset-0 w-full h-full object-fill", alt: "" }),
3004
+ children: src ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_jsx_runtime45.Fragment, { children: [
3005
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("img", { src, className: "absolute inset-0 w-full h-full object-fill", alt: "" }),
2815
3006
  filteredDetections.map(
2816
- (d, i) => d.mask && d.maskWidth && d.maskHeight ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
3007
+ (d, i) => d.mask && d.maskWidth && d.maskHeight ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
2817
3008
  MaskOverlay,
2818
3009
  {
2819
3010
  mask: d.mask,
@@ -2827,7 +3018,7 @@ function DetectionCanvas({
2827
3018
  `mask-${i}`
2828
3019
  ) : null
2829
3020
  ),
2830
- filteredDetections.map((d, i) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
3021
+ filteredDetections.map((d, i) => /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
2831
3022
  BoundingBox,
2832
3023
  {
2833
3024
  detection: d,
@@ -2847,7 +3038,7 @@ function DetectionCanvas({
2847
3038
  const ph = py2 - py1;
2848
3039
  if (pw > 0 && ph > 0 && cw * ch / (pw * ph) > 0.8) return false;
2849
3040
  return true;
2850
- }).map((child, j) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
3041
+ }).map((child, j) => /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
2851
3042
  ChildBoundingBox,
2852
3043
  {
2853
3044
  child,
@@ -2860,7 +3051,7 @@ function DetectionCanvas({
2860
3051
  },
2861
3052
  `det-${i}`
2862
3053
  ))
2863
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "w-full h-full flex items-center justify-center text-foreground-subtle text-sm", children: placeholder ?? "No image loaded" })
3054
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "w-full h-full flex items-center justify-center text-foreground-subtle text-sm", children: placeholder ?? "No image loaded" })
2864
3055
  }
2865
3056
  );
2866
3057
  }
@@ -2877,15 +3068,15 @@ function BoundingBox({
2877
3068
  const labelCount = 1 + (detection.labelsData?.length ?? 0);
2878
3069
  const labelHeightPx = labelCount * 16 + 4;
2879
3070
  const topPct = y1 / imageHeight * 100;
2880
- const containerRef = (0, import_react25.useRef)(null);
3071
+ const containerRef = (0, import_react29.useRef)(null);
2881
3072
  const showBelow = topPct < labelHeightPx / imageHeight * 100 * 1.5;
2882
- const labelsElement = /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
3073
+ const labelsElement = /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
2883
3074
  "div",
2884
3075
  {
2885
3076
  className: `absolute left-0 flex flex-col items-start gap-px ${showBelow ? "" : ""}`,
2886
3077
  style: showBelow ? { top: "100%", marginTop: "2px" } : { bottom: "100%", marginBottom: "2px" },
2887
3078
  children: [
2888
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
3079
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
2889
3080
  "span",
2890
3081
  {
2891
3082
  className: "text-[10px] px-1 rounded-sm whitespace-nowrap text-white",
@@ -2896,7 +3087,7 @@ function BoundingBox({
2896
3087
  ]
2897
3088
  }
2898
3089
  ),
2899
- detection.labelsData?.map((l, k) => /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
3090
+ detection.labelsData?.map((l, k) => /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
2900
3091
  "span",
2901
3092
  {
2902
3093
  className: "text-[9px] font-semibold px-1 rounded-sm whitespace-nowrap text-white",
@@ -2913,7 +3104,7 @@ function BoundingBox({
2913
3104
  ]
2914
3105
  }
2915
3106
  );
2916
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
3107
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
2917
3108
  "div",
2918
3109
  {
2919
3110
  ref: containerRef,
@@ -2943,8 +3134,8 @@ function MaskOverlay({
2943
3134
  imageHeight,
2944
3135
  color
2945
3136
  }) {
2946
- const canvasRef = (0, import_react25.useRef)(null);
2947
- (0, import_react25.useEffect)(() => {
3137
+ const canvasRef = (0, import_react29.useRef)(null);
3138
+ (0, import_react29.useEffect)(() => {
2948
3139
  const canvas = canvasRef.current;
2949
3140
  if (!canvas) return;
2950
3141
  const ctx = canvas.getContext("2d");
@@ -2972,7 +3163,7 @@ function MaskOverlay({
2972
3163
  ctx.putImageData(imageData, 0, 0);
2973
3164
  }, [mask, maskWidth, maskHeight, color]);
2974
3165
  const [x1, y1, x2, y2] = bbox;
2975
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
3166
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
2976
3167
  "canvas",
2977
3168
  {
2978
3169
  ref: canvasRef,
@@ -2998,7 +3189,7 @@ function ChildBoundingBox({
2998
3189
  const pw = px2 - px1;
2999
3190
  const ph = py2 - py1;
3000
3191
  if (pw <= 0 || ph <= 0) return null;
3001
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
3192
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
3002
3193
  "div",
3003
3194
  {
3004
3195
  className: "absolute rounded-sm",
@@ -3015,13 +3206,13 @@ function ChildBoundingBox({
3015
3206
  const labelCount = 1 + (child.labelsData?.length ?? 0);
3016
3207
  const relTop = (cy1 - py1) / ph * 100;
3017
3208
  const showBelow = relTop < labelCount * 6;
3018
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
3209
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
3019
3210
  "div",
3020
3211
  {
3021
3212
  className: "absolute left-0 flex flex-col items-start gap-px",
3022
3213
  style: showBelow ? { top: "100%", marginTop: "1px" } : { bottom: "100%", marginBottom: "1px" },
3023
3214
  children: [
3024
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
3215
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
3025
3216
  "span",
3026
3217
  {
3027
3218
  className: "text-[9px] px-0.5 rounded-sm whitespace-nowrap text-white",
@@ -3032,7 +3223,7 @@ function ChildBoundingBox({
3032
3223
  ]
3033
3224
  }
3034
3225
  ),
3035
- child.labelsData?.map((l, k) => /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
3226
+ child.labelsData?.map((l, k) => /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
3036
3227
  "span",
3037
3228
  {
3038
3229
  className: "text-[8px] font-semibold px-0.5 rounded-sm whitespace-nowrap text-white",
@@ -3055,7 +3246,7 @@ function ChildBoundingBox({
3055
3246
  }
3056
3247
 
3057
3248
  // src/composites/detection-result-tree.tsx
3058
- var import_jsx_runtime44 = require("react/jsx-runtime");
3249
+ var import_jsx_runtime46 = require("react/jsx-runtime");
3059
3250
  function DetectionResultTree({
3060
3251
  detections,
3061
3252
  classColors,
@@ -3065,15 +3256,15 @@ function DetectionResultTree({
3065
3256
  }) {
3066
3257
  const colors = classColors;
3067
3258
  if (detections.length === 0) {
3068
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "text-sm text-foreground-subtle italic text-center py-4", children: "No detections" });
3259
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "text-sm text-foreground-subtle italic text-center py-4", children: "No detections" });
3069
3260
  }
3070
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className, children: [
3071
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "text-xs font-medium text-foreground-subtle uppercase tracking-wide mb-2", children: [
3261
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className, children: [
3262
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "text-xs font-medium text-foreground-subtle uppercase tracking-wide mb-2", children: [
3072
3263
  "Detections (",
3073
3264
  detections.length,
3074
3265
  ")"
3075
3266
  ] }),
3076
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "space-y-2", children: detections.map((d, i) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
3267
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "space-y-2", children: detections.map((d, i) => /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
3077
3268
  DetectionNode,
3078
3269
  {
3079
3270
  detection: d,
@@ -3095,10 +3286,10 @@ function DetectionNode({
3095
3286
  }) {
3096
3287
  const color = getClassColor(detection.className, colors);
3097
3288
  const isVisible = !hiddenKeys?.has(path);
3098
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: `rounded-md border border-border bg-surface p-3 space-y-1 ${isVisible ? "" : "opacity-40"}`, children: [
3099
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex justify-between items-center", children: [
3100
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex items-center gap-2", children: [
3101
- onToggleVisibility && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
3289
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: `rounded-md border border-border bg-surface p-3 space-y-1 ${isVisible ? "" : "opacity-40"}`, children: [
3290
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex justify-between items-center", children: [
3291
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex items-center gap-2", children: [
3292
+ onToggleVisibility && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
3102
3293
  "input",
3103
3294
  {
3104
3295
  type: "checkbox",
@@ -3107,45 +3298,45 @@ function DetectionNode({
3107
3298
  className: "h-3.5 w-3.5 rounded border-border accent-primary cursor-pointer shrink-0"
3108
3299
  }
3109
3300
  ),
3110
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
3301
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
3111
3302
  "span",
3112
3303
  {
3113
3304
  className: "h-2.5 w-2.5 rounded-full shrink-0",
3114
3305
  style: { backgroundColor: color }
3115
3306
  }
3116
3307
  ),
3117
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "text-sm font-medium text-foreground", children: detection.className }),
3118
- detection.mask && detection.maskWidth && detection.maskHeight && /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: "text-[9px] font-mono px-1 py-0.5 rounded bg-primary/10 text-primary", children: [
3308
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "text-sm font-medium text-foreground", children: detection.className }),
3309
+ detection.mask && detection.maskWidth && detection.maskHeight && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("span", { className: "text-[9px] font-mono px-1 py-0.5 rounded bg-primary/10 text-primary", children: [
3119
3310
  "mask ",
3120
3311
  detection.maskWidth,
3121
3312
  "x",
3122
3313
  detection.maskHeight
3123
3314
  ] })
3124
3315
  ] }),
3125
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ConfidenceBadge, { confidence: detection.confidence })
3316
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ConfidenceBadge, { confidence: detection.confidence })
3126
3317
  ] }),
3127
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "text-[10px] text-foreground-subtle font-mono", children: [
3318
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "text-[10px] text-foreground-subtle font-mono", children: [
3128
3319
  "bbox: [",
3129
3320
  detection.bbox.map((v) => Math.round(v)).join(", "),
3130
3321
  "]"
3131
3322
  ] }),
3132
- detection.labelsData && detection.labelsData.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "flex flex-wrap gap-1 mt-1", children: detection.labelsData.map((l, k) => /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
3323
+ detection.labelsData && detection.labelsData.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "flex flex-wrap gap-1 mt-1", children: detection.labelsData.map((l, k) => /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
3133
3324
  "span",
3134
3325
  {
3135
3326
  className: "inline-flex items-center gap-1 text-[10px] font-medium px-1.5 py-0.5 rounded-full",
3136
3327
  style: { backgroundColor: getClassColor(l.addonId ?? l.label, colors) + "20", color: getClassColor(l.addonId ?? l.label, colors) },
3137
3328
  children: [
3138
3329
  l.label,
3139
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: "opacity-60", children: [
3330
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("span", { className: "opacity-60", children: [
3140
3331
  (l.score * 100).toFixed(0),
3141
3332
  "%"
3142
3333
  ] }),
3143
- l.addonId && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "opacity-40 text-[8px]", children: l.addonId })
3334
+ l.addonId && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "opacity-40 text-[8px]", children: l.addonId })
3144
3335
  ]
3145
3336
  },
3146
3337
  k
3147
3338
  )) }),
3148
- detection.children && detection.children.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
3339
+ detection.children && detection.children.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
3149
3340
  ChildrenTree,
3150
3341
  {
3151
3342
  children: detection.children,
@@ -3164,13 +3355,13 @@ function ChildrenTree({
3164
3355
  hiddenKeys,
3165
3356
  onToggleVisibility
3166
3357
  }) {
3167
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "ml-4 mt-1.5 space-y-1.5 border-l-2 border-border pl-3", children: children.map((child, j) => {
3358
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "ml-4 mt-1.5 space-y-1.5 border-l-2 border-border pl-3", children: children.map((child, j) => {
3168
3359
  const childPath = `${parentPath}.${j}`;
3169
3360
  const childColor = getClassColor(child.className, colors);
3170
3361
  const isVisible = !hiddenKeys?.has(childPath);
3171
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: `text-xs space-y-0.5 ${isVisible ? "" : "opacity-40"}`, children: [
3172
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex items-center gap-1.5", children: [
3173
- onToggleVisibility && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
3362
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: `text-xs space-y-0.5 ${isVisible ? "" : "opacity-40"}`, children: [
3363
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex items-center gap-1.5", children: [
3364
+ onToggleVisibility && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
3174
3365
  "input",
3175
3366
  {
3176
3367
  type: "checkbox",
@@ -3179,26 +3370,26 @@ function ChildrenTree({
3179
3370
  className: "h-3 w-3 rounded border-border accent-primary cursor-pointer shrink-0"
3180
3371
  }
3181
3372
  ),
3182
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
3373
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
3183
3374
  "span",
3184
3375
  {
3185
3376
  className: "h-1.5 w-1.5 rounded-full shrink-0",
3186
3377
  style: { backgroundColor: childColor }
3187
3378
  }
3188
3379
  ),
3189
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "font-medium", style: { color: childColor }, children: child.className }),
3190
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: "text-foreground-subtle", children: [
3380
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "font-medium", style: { color: childColor }, children: child.className }),
3381
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("span", { className: "text-foreground-subtle", children: [
3191
3382
  (child.confidence * 100).toFixed(0),
3192
3383
  "%"
3193
3384
  ] }),
3194
- child.mask && child.maskWidth && child.maskHeight && /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: "text-[9px] font-mono px-1 py-0.5 rounded bg-primary/10 text-primary", children: [
3385
+ child.mask && child.maskWidth && child.maskHeight && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("span", { className: "text-[9px] font-mono px-1 py-0.5 rounded bg-primary/10 text-primary", children: [
3195
3386
  "mask ",
3196
3387
  child.maskWidth,
3197
3388
  "x",
3198
3389
  child.maskHeight
3199
3390
  ] })
3200
3391
  ] }),
3201
- child.labelsData && child.labelsData.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "flex flex-wrap gap-1 ml-5 mt-0.5", children: child.labelsData.map((l, k) => /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
3392
+ child.labelsData && child.labelsData.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "flex flex-wrap gap-1 ml-5 mt-0.5", children: child.labelsData.map((l, k) => /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
3202
3393
  "span",
3203
3394
  {
3204
3395
  className: "inline-flex items-center gap-0.5 text-[9px] font-medium px-1 py-0.5 rounded-full",
@@ -3206,7 +3397,7 @@ function ChildrenTree({
3206
3397
  children: [
3207
3398
  l.label,
3208
3399
  " ",
3209
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: "opacity-60", children: [
3400
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("span", { className: "opacity-60", children: [
3210
3401
  (l.score * 100).toFixed(0),
3211
3402
  "%"
3212
3403
  ] })
@@ -3214,7 +3405,7 @@ function ChildrenTree({
3214
3405
  },
3215
3406
  k
3216
3407
  )) }),
3217
- child.children && child.children.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
3408
+ child.children && child.children.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
3218
3409
  ChildrenTree,
3219
3410
  {
3220
3411
  children: child.children,
@@ -3229,30 +3420,30 @@ function ChildrenTree({
3229
3420
  }
3230
3421
  function ConfidenceBadge({ confidence }) {
3231
3422
  const level = confidence >= 0.8 ? "bg-success/10 text-success" : confidence >= 0.5 ? "bg-warning/10 text-warning" : "bg-danger/10 text-danger";
3232
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: `text-xs font-medium px-2 py-0.5 rounded-full ${level}`, children: [
3423
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("span", { className: `text-xs font-medium px-2 py-0.5 rounded-full ${level}`, children: [
3233
3424
  (confidence * 100).toFixed(1),
3234
3425
  "%"
3235
3426
  ] });
3236
3427
  }
3237
3428
 
3238
3429
  // src/composites/step-timings.tsx
3239
- var import_jsx_runtime45 = require("react/jsx-runtime");
3430
+ var import_jsx_runtime47 = require("react/jsx-runtime");
3240
3431
  function StepTimings({ timings, totalMs, className }) {
3241
3432
  const entries = Object.entries(timings);
3242
3433
  if (entries.length === 0 && totalMs === void 0) return null;
3243
- return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: `rounded-lg border border-border bg-surface p-3 space-y-2 ${className ?? ""}`, children: [
3244
- /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "text-xs font-medium text-foreground-subtle uppercase tracking-wide", children: "Timings" }),
3245
- /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "space-y-1 text-xs", children: [
3246
- entries.map(([step, ms]) => /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex justify-between", children: [
3247
- /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "text-foreground-subtle", children: step }),
3248
- /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "font-mono text-foreground", children: [
3434
+ return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: `rounded-lg border border-border bg-surface p-3 space-y-2 ${className ?? ""}`, children: [
3435
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "text-xs font-medium text-foreground-subtle uppercase tracking-wide", children: "Timings" }),
3436
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "space-y-1 text-xs", children: [
3437
+ entries.map(([step, ms]) => /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "flex justify-between", children: [
3438
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "text-foreground-subtle", children: step }),
3439
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "font-mono text-foreground", children: [
3249
3440
  ms.toFixed(1),
3250
3441
  "ms"
3251
3442
  ] })
3252
3443
  ] }, step)),
3253
- totalMs !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex justify-between pt-1 border-t border-border font-medium text-foreground", children: [
3254
- /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { children: "Total" }),
3255
- /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "font-mono", children: [
3444
+ totalMs !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "flex justify-between pt-1 border-t border-border font-medium text-foreground", children: [
3445
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { children: "Total" }),
3446
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "font-mono", children: [
3256
3447
  totalMs.toFixed(1),
3257
3448
  "ms"
3258
3449
  ] })
@@ -3262,7 +3453,7 @@ function StepTimings({ timings, totalMs, className }) {
3262
3453
  }
3263
3454
 
3264
3455
  // src/composites/image-selector.tsx
3265
- var import_jsx_runtime46 = require("react/jsx-runtime");
3456
+ var import_jsx_runtime48 = require("react/jsx-runtime");
3266
3457
  function ImageSelector({
3267
3458
  images,
3268
3459
  selectedFilename,
@@ -3288,8 +3479,8 @@ function ImageSelector({
3288
3479
  };
3289
3480
  input.click();
3290
3481
  };
3291
- return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: `flex flex-wrap items-center gap-2 ${className ?? ""}`, children: [
3292
- images.map((img) => /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
3482
+ return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: `flex flex-wrap items-center gap-2 ${className ?? ""}`, children: [
3483
+ images.map((img) => /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
3293
3484
  "button",
3294
3485
  {
3295
3486
  onClick: () => onSelect(img.filename),
@@ -3298,7 +3489,7 @@ function ImageSelector({
3298
3489
  },
3299
3490
  img.filename
3300
3491
  )),
3301
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
3492
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
3302
3493
  "button",
3303
3494
  {
3304
3495
  onClick: handleUploadClick,
@@ -3306,12 +3497,12 @@ function ImageSelector({
3306
3497
  children: "Upload..."
3307
3498
  }
3308
3499
  ),
3309
- uploadedName && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "text-xs text-foreground-subtle", children: uploadedName })
3500
+ uploadedName && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "text-xs text-foreground-subtle", children: uploadedName })
3310
3501
  ] });
3311
3502
  }
3312
3503
 
3313
3504
  // src/composites/inference-config-selector.tsx
3314
- var import_jsx_runtime47 = require("react/jsx-runtime");
3505
+ var import_jsx_runtime49 = require("react/jsx-runtime");
3315
3506
  var SELECT_CLASS = "w-full px-3 py-2 text-sm rounded-md border border-border bg-surface text-foreground focus:outline-none focus:ring-2 focus:ring-primary/50";
3316
3507
  function InferenceConfigSelector({
3317
3508
  runtime,
@@ -3331,16 +3522,16 @@ function InferenceConfigSelector({
3331
3522
  showAgent = false
3332
3523
  }) {
3333
3524
  const containerClass = layout === "grid" ? "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4" : layout === "horizontal" ? "flex flex-wrap items-end gap-4" : "space-y-3";
3334
- return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: `${containerClass} ${className ?? ""}`, children: [
3335
- showAgent && agents.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("label", { className: "space-y-1", children: [
3336
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "text-xs font-medium text-foreground-subtle", children: "Agent" }),
3337
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
3525
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: `${containerClass} ${className ?? ""}`, children: [
3526
+ showAgent && agents.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("label", { className: "space-y-1", children: [
3527
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "text-xs font-medium text-foreground-subtle", children: "Agent" }),
3528
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
3338
3529
  "select",
3339
3530
  {
3340
3531
  value: agentId,
3341
3532
  onChange: (e) => onAgentChange?.(e.target.value),
3342
3533
  className: SELECT_CLASS,
3343
- children: agents.map((a) => /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("option", { value: a.id, children: [
3534
+ children: agents.map((a) => /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("option", { value: a.id, children: [
3344
3535
  a.name,
3345
3536
  " (",
3346
3537
  a.status,
@@ -3349,45 +3540,45 @@ function InferenceConfigSelector({
3349
3540
  }
3350
3541
  )
3351
3542
  ] }),
3352
- /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("label", { className: "space-y-1", children: [
3353
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "text-xs font-medium text-foreground-subtle", children: "Runtime" }),
3354
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
3543
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("label", { className: "space-y-1", children: [
3544
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "text-xs font-medium text-foreground-subtle", children: "Runtime" }),
3545
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
3355
3546
  "select",
3356
3547
  {
3357
3548
  value: runtime,
3358
3549
  onChange: (e) => onRuntimeChange(e.target.value),
3359
3550
  className: SELECT_CLASS,
3360
- children: runtimes.map((r) => /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("option", { value: r.value, disabled: !r.available, children: [
3551
+ children: runtimes.map((r) => /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("option", { value: r.value, disabled: !r.available, children: [
3361
3552
  r.label,
3362
3553
  !r.available ? " (unavailable)" : ""
3363
3554
  ] }, r.value))
3364
3555
  }
3365
3556
  )
3366
3557
  ] }),
3367
- /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("label", { className: "space-y-1", children: [
3368
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "text-xs font-medium text-foreground-subtle", children: "Backend" }),
3369
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
3558
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("label", { className: "space-y-1", children: [
3559
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "text-xs font-medium text-foreground-subtle", children: "Backend" }),
3560
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
3370
3561
  "select",
3371
3562
  {
3372
3563
  value: backend,
3373
3564
  onChange: (e) => onBackendChange(e.target.value),
3374
3565
  className: SELECT_CLASS,
3375
- children: backends.map((b) => /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("option", { value: b.id, disabled: !b.available, children: [
3566
+ children: backends.map((b) => /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("option", { value: b.id, disabled: !b.available, children: [
3376
3567
  b.label,
3377
3568
  !b.available ? " (unavailable)" : ""
3378
3569
  ] }, b.id))
3379
3570
  }
3380
3571
  )
3381
3572
  ] }),
3382
- /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("label", { className: "space-y-1", children: [
3383
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "text-xs font-medium text-foreground-subtle", children: "Model" }),
3384
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
3573
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("label", { className: "space-y-1", children: [
3574
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "text-xs font-medium text-foreground-subtle", children: "Model" }),
3575
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
3385
3576
  "select",
3386
3577
  {
3387
3578
  value: modelId,
3388
3579
  onChange: (e) => onModelChange(e.target.value),
3389
3580
  className: SELECT_CLASS,
3390
- children: models.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("option", { value: "", children: "No compatible models" }) : models.map((m) => /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("option", { value: m.id, children: [
3581
+ children: models.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("option", { value: "", children: "No compatible models" }) : models.map((m) => /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("option", { value: m.id, children: [
3391
3582
  m.name,
3392
3583
  m.downloaded ? " \u2713" : ""
3393
3584
  ] }, m.id))
@@ -3398,19 +3589,19 @@ function InferenceConfigSelector({
3398
3589
  }
3399
3590
 
3400
3591
  // src/composites/mount-addon-page.tsx
3401
- var import_react28 = require("react");
3592
+ var import_react32 = require("react");
3402
3593
  var import_client2 = require("react-dom/client");
3403
3594
 
3404
3595
  // src/composites/dev-shell.tsx
3405
- var import_react27 = require("react");
3596
+ var import_react31 = require("react");
3406
3597
  var import_client = require("@trpc/client");
3407
3598
  var import_superjson = __toESM(require("superjson"), 1);
3408
3599
 
3409
3600
  // src/composites/login-form.tsx
3410
- var import_react26 = require("react");
3411
- var import_jsx_runtime48 = require("react/jsx-runtime");
3601
+ var import_react30 = require("react");
3602
+ var import_jsx_runtime50 = require("react/jsx-runtime");
3412
3603
  function EyeIcon({ className }) {
3413
- return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
3604
+ return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
3414
3605
  "svg",
3415
3606
  {
3416
3607
  xmlns: "http://www.w3.org/2000/svg",
@@ -3422,14 +3613,14 @@ function EyeIcon({ className }) {
3422
3613
  strokeLinejoin: "round",
3423
3614
  className,
3424
3615
  children: [
3425
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("path", { d: "M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0" }),
3426
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("circle", { cx: "12", cy: "12", r: "3" })
3616
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("path", { d: "M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0" }),
3617
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("circle", { cx: "12", cy: "12", r: "3" })
3427
3618
  ]
3428
3619
  }
3429
3620
  );
3430
3621
  }
3431
3622
  function EyeOffIcon({ className }) {
3432
- return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
3623
+ return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
3433
3624
  "svg",
3434
3625
  {
3435
3626
  xmlns: "http://www.w3.org/2000/svg",
@@ -3441,16 +3632,16 @@ function EyeOffIcon({ className }) {
3441
3632
  strokeLinejoin: "round",
3442
3633
  className,
3443
3634
  children: [
3444
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("path", { d: "M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49" }),
3445
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("path", { d: "M14.084 14.158a3 3 0 0 1-4.242-4.242" }),
3446
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("path", { d: "M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143" }),
3447
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("path", { d: "m2 2 20 20" })
3635
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("path", { d: "M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49" }),
3636
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("path", { d: "M14.084 14.158a3 3 0 0 1-4.242-4.242" }),
3637
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("path", { d: "M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143" }),
3638
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("path", { d: "m2 2 20 20" })
3448
3639
  ]
3449
3640
  }
3450
3641
  );
3451
3642
  }
3452
3643
  function SpinnerIcon({ className }) {
3453
- return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
3644
+ return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
3454
3645
  "svg",
3455
3646
  {
3456
3647
  xmlns: "http://www.w3.org/2000/svg",
@@ -3461,7 +3652,7 @@ function SpinnerIcon({ className }) {
3461
3652
  strokeLinecap: "round",
3462
3653
  strokeLinejoin: "round",
3463
3654
  className,
3464
- children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" })
3655
+ children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" })
3465
3656
  }
3466
3657
  );
3467
3658
  }
@@ -3472,11 +3663,11 @@ function LoginForm({
3472
3663
  error: externalError,
3473
3664
  className
3474
3665
  }) {
3475
- const [username, setUsername] = (0, import_react26.useState)("");
3476
- const [password, setPassword] = (0, import_react26.useState)("");
3477
- const [showPassword, setShowPassword] = (0, import_react26.useState)(false);
3478
- const [submitting, setSubmitting] = (0, import_react26.useState)(false);
3479
- const [internalError, setInternalError] = (0, import_react26.useState)(null);
3666
+ const [username, setUsername] = (0, import_react30.useState)("");
3667
+ const [password, setPassword] = (0, import_react30.useState)("");
3668
+ const [showPassword, setShowPassword] = (0, import_react30.useState)(false);
3669
+ const [submitting, setSubmitting] = (0, import_react30.useState)(false);
3670
+ const [internalError, setInternalError] = (0, import_react30.useState)(null);
3480
3671
  const error = externalError ?? internalError;
3481
3672
  const handleSubmit = async (e) => {
3482
3673
  e.preventDefault();
@@ -3492,26 +3683,26 @@ function LoginForm({
3492
3683
  setSubmitting(false);
3493
3684
  }
3494
3685
  };
3495
- return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
3686
+ return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
3496
3687
  "div",
3497
3688
  {
3498
3689
  className: cn(
3499
3690
  "flex min-h-screen items-center justify-center bg-background p-4",
3500
3691
  className
3501
3692
  ),
3502
- children: /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "w-full max-w-sm", children: [
3503
- logoSrc && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "flex justify-center mb-8", children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("img", { src: logoSrc, alt: "Logo", className: "h-12" }) }),
3504
- serverUrl && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("p", { className: "mb-4 text-center text-xs text-foreground-subtle truncate", children: serverUrl }),
3505
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
3693
+ children: /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "w-full max-w-sm", children: [
3694
+ logoSrc && /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { className: "flex justify-center mb-8", children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("img", { src: logoSrc, alt: "Logo", className: "h-12" }) }),
3695
+ serverUrl && /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("p", { className: "mb-4 text-center text-xs text-foreground-subtle truncate", children: serverUrl }),
3696
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
3506
3697
  "form",
3507
3698
  {
3508
3699
  onSubmit: handleSubmit,
3509
3700
  className: "space-y-4 rounded-xl border border-border bg-surface p-6 shadow-xl shadow-black/10",
3510
3701
  children: [
3511
- error && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "rounded-md bg-danger/10 border border-danger/20 px-3 py-2 text-xs text-danger", children: error }),
3512
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "space-y-1.5", children: [
3513
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("label", { className: "text-xs font-medium text-foreground-subtle", children: "Username" }),
3514
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
3702
+ error && /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { className: "rounded-md bg-danger/10 border border-danger/20 px-3 py-2 text-xs text-danger", children: error }),
3703
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "space-y-1.5", children: [
3704
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("label", { className: "text-xs font-medium text-foreground-subtle", children: "Username" }),
3705
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
3515
3706
  "input",
3516
3707
  {
3517
3708
  type: "text",
@@ -3523,10 +3714,10 @@ function LoginForm({
3523
3714
  }
3524
3715
  )
3525
3716
  ] }),
3526
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "space-y-1.5", children: [
3527
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("label", { className: "text-xs font-medium text-foreground-subtle", children: "Password" }),
3528
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "relative", children: [
3529
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
3717
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "space-y-1.5", children: [
3718
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("label", { className: "text-xs font-medium text-foreground-subtle", children: "Password" }),
3719
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "relative", children: [
3720
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
3530
3721
  "input",
3531
3722
  {
3532
3723
  type: showPassword ? "text" : "password",
@@ -3537,26 +3728,26 @@ function LoginForm({
3537
3728
  className: "w-full rounded-lg border border-border bg-background px-3 py-2.5 pr-10 text-sm text-foreground placeholder:text-foreground-subtle focus:outline-none focus:ring-2 focus:ring-primary/50 focus:border-primary"
3538
3729
  }
3539
3730
  ),
3540
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
3731
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
3541
3732
  "button",
3542
3733
  {
3543
3734
  type: "button",
3544
3735
  onClick: () => setShowPassword((prev) => !prev),
3545
3736
  className: "absolute right-2.5 top-1/2 -translate-y-1/2 text-foreground-subtle hover:text-foreground",
3546
3737
  tabIndex: -1,
3547
- children: showPassword ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(EyeOffIcon, { className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(EyeIcon, { className: "h-4 w-4" })
3738
+ children: showPassword ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(EyeOffIcon, { className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(EyeIcon, { className: "h-4 w-4" })
3548
3739
  }
3549
3740
  )
3550
3741
  ] })
3551
3742
  ] }),
3552
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
3743
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
3553
3744
  "button",
3554
3745
  {
3555
3746
  type: "submit",
3556
3747
  disabled: submitting,
3557
3748
  className: "w-full rounded-lg bg-primary px-4 py-2.5 text-sm font-semibold text-primary-foreground hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed transition-colors flex items-center justify-center gap-2",
3558
3749
  children: [
3559
- submitting && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(SpinnerIcon, { className: "h-4 w-4 animate-spin" }),
3750
+ submitting && /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(SpinnerIcon, { className: "h-4 w-4 animate-spin" }),
3560
3751
  submitting ? "Logging in..." : "Log in"
3561
3752
  ]
3562
3753
  }
@@ -3570,11 +3761,11 @@ function LoginForm({
3570
3761
  }
3571
3762
 
3572
3763
  // src/composites/dev-shell.tsx
3573
- var import_jsx_runtime49 = require("react/jsx-runtime");
3764
+ var import_jsx_runtime51 = require("react/jsx-runtime");
3574
3765
  var STORAGE_KEY = "camstack_dev_token";
3575
- var DevShellContext = (0, import_react27.createContext)(null);
3766
+ var DevShellContext = (0, import_react31.createContext)(null);
3576
3767
  function useDevShell() {
3577
- const ctx = (0, import_react27.useContext)(DevShellContext);
3768
+ const ctx = (0, import_react31.useContext)(DevShellContext);
3578
3769
  if (!ctx) {
3579
3770
  throw new Error("useDevShell must be used within a DevShell");
3580
3771
  }
@@ -3585,7 +3776,7 @@ function getStoredToken() {
3585
3776
  return localStorage.getItem(STORAGE_KEY);
3586
3777
  }
3587
3778
  function SunIcon({ className }) {
3588
- return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
3779
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(
3589
3780
  "svg",
3590
3781
  {
3591
3782
  xmlns: "http://www.w3.org/2000/svg",
@@ -3597,21 +3788,21 @@ function SunIcon({ className }) {
3597
3788
  strokeLinejoin: "round",
3598
3789
  className,
3599
3790
  children: [
3600
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("circle", { cx: "12", cy: "12", r: "4" }),
3601
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("path", { d: "M12 2v2" }),
3602
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("path", { d: "M12 20v2" }),
3603
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("path", { d: "m4.93 4.93 1.41 1.41" }),
3604
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("path", { d: "m17.66 17.66 1.41 1.41" }),
3605
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("path", { d: "M2 12h2" }),
3606
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("path", { d: "M20 12h2" }),
3607
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("path", { d: "m6.34 17.66-1.41 1.41" }),
3608
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("path", { d: "m19.07 4.93-1.41 1.41" })
3791
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("circle", { cx: "12", cy: "12", r: "4" }),
3792
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("path", { d: "M12 2v2" }),
3793
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("path", { d: "M12 20v2" }),
3794
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("path", { d: "m4.93 4.93 1.41 1.41" }),
3795
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("path", { d: "m17.66 17.66 1.41 1.41" }),
3796
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("path", { d: "M2 12h2" }),
3797
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("path", { d: "M20 12h2" }),
3798
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("path", { d: "m6.34 17.66-1.41 1.41" }),
3799
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("path", { d: "m19.07 4.93-1.41 1.41" })
3609
3800
  ]
3610
3801
  }
3611
3802
  );
3612
3803
  }
3613
3804
  function MoonIcon({ className }) {
3614
- return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
3805
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
3615
3806
  "svg",
3616
3807
  {
3617
3808
  xmlns: "http://www.w3.org/2000/svg",
@@ -3622,7 +3813,7 @@ function MoonIcon({ className }) {
3622
3813
  strokeLinecap: "round",
3623
3814
  strokeLinejoin: "round",
3624
3815
  className,
3625
- children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("path", { d: "M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z" })
3816
+ children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("path", { d: "M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z" })
3626
3817
  }
3627
3818
  );
3628
3819
  }
@@ -3634,7 +3825,7 @@ function DevShellInner({
3634
3825
  onLogout
3635
3826
  }) {
3636
3827
  const theme = useThemeMode();
3637
- const trpc = (0, import_react27.useMemo)(
3828
+ const trpc = (0, import_react31.useMemo)(
3638
3829
  () => {
3639
3830
  const wsUrl = serverUrl.replace(/^http/, "ws") + "/trpc";
3640
3831
  const wsClient = (0, import_client.createWSClient)({
@@ -3657,19 +3848,19 @@ function DevShellInner({
3657
3848
  },
3658
3849
  [serverUrl, token]
3659
3850
  );
3660
- const contextValue = (0, import_react27.useMemo)(
3851
+ const contextValue = (0, import_react31.useMemo)(
3661
3852
  () => ({ trpc, token, logout: onLogout }),
3662
3853
  [trpc, token, onLogout]
3663
3854
  );
3664
- return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(DevShellContext.Provider, { value: contextValue, children: /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "min-h-screen bg-background text-foreground", children: [
3665
- /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "flex items-center justify-between border-b border-border bg-surface px-4 py-2", children: [
3666
- /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "flex items-center gap-2", children: [
3667
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "rounded bg-warning/20 px-2 py-0.5 text-xs font-bold text-warning", children: "DEV MODE" }),
3668
- title && /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "text-sm font-medium text-foreground", children: title }),
3669
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "text-xs text-foreground-subtle", children: serverUrl })
3855
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(DevShellContext.Provider, { value: contextValue, children: /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "min-h-screen bg-background text-foreground", children: [
3856
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "flex items-center justify-between border-b border-border bg-surface px-4 py-2", children: [
3857
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "flex items-center gap-2", children: [
3858
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "rounded bg-warning/20 px-2 py-0.5 text-xs font-bold text-warning", children: "DEV MODE" }),
3859
+ title && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "text-sm font-medium text-foreground", children: title }),
3860
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "text-xs text-foreground-subtle", children: serverUrl })
3670
3861
  ] }),
3671
- /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "flex items-center gap-2", children: [
3672
- /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
3862
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "flex items-center gap-2", children: [
3863
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(
3673
3864
  "button",
3674
3865
  {
3675
3866
  type: "button",
@@ -3677,12 +3868,12 @@ function DevShellInner({
3677
3868
  className: "flex items-center gap-1.5 rounded-md px-2 py-1 text-xs font-medium text-foreground-subtle hover:text-foreground hover:bg-surface-hover transition-colors",
3678
3869
  title: `Theme: ${theme.mode}`,
3679
3870
  children: [
3680
- theme.resolvedMode === "dark" ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(SunIcon, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(MoonIcon, { className: "h-3.5 w-3.5" }),
3871
+ theme.resolvedMode === "dark" ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(SunIcon, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(MoonIcon, { className: "h-3.5 w-3.5" }),
3681
3872
  theme.mode === "dark" ? "Dark" : theme.mode === "light" ? "Light" : "System"
3682
3873
  ]
3683
3874
  }
3684
3875
  ),
3685
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
3876
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
3686
3877
  "button",
3687
3878
  {
3688
3879
  type: "button",
@@ -3693,7 +3884,7 @@ function DevShellInner({
3693
3884
  )
3694
3885
  ] })
3695
3886
  ] }),
3696
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "p-4", children: children({ trpc, theme }) })
3887
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "p-4", children: children({ trpc, theme }) })
3697
3888
  ] }) });
3698
3889
  }
3699
3890
  function DevShell({
@@ -3701,8 +3892,8 @@ function DevShell({
3701
3892
  serverUrl = "https://localhost:4443",
3702
3893
  title
3703
3894
  }) {
3704
- const [token, setToken] = (0, import_react27.useState)(getStoredToken);
3705
- const handleLogin = (0, import_react27.useCallback)(
3895
+ const [token, setToken] = (0, import_react31.useState)(getStoredToken);
3896
+ const handleLogin = (0, import_react31.useCallback)(
3706
3897
  async (username, password) => {
3707
3898
  const anonClient = (0, import_client.createTRPCClient)({
3708
3899
  links: [
@@ -3719,14 +3910,14 @@ function DevShell({
3719
3910
  },
3720
3911
  [serverUrl]
3721
3912
  );
3722
- const handleLogout = (0, import_react27.useCallback)(() => {
3913
+ const handleLogout = (0, import_react31.useCallback)(() => {
3723
3914
  localStorage.removeItem(STORAGE_KEY);
3724
3915
  setToken(null);
3725
3916
  }, []);
3726
3917
  if (!token) {
3727
- return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(ThemeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(LoginForm, { onLogin: handleLogin, serverUrl }) });
3918
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ThemeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(LoginForm, { onLogin: handleLogin, serverUrl }) });
3728
3919
  }
3729
- return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(ThemeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
3920
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ThemeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
3730
3921
  DevShellInner,
3731
3922
  {
3732
3923
  serverUrl,
@@ -3751,10 +3942,10 @@ function mountAddonPage(PageComponent, options = {}) {
3751
3942
  return;
3752
3943
  }
3753
3944
  (0, import_client2.createRoot)(root).render(
3754
- (0, import_react28.createElement)(DevShell, {
3945
+ (0, import_react32.createElement)(DevShell, {
3755
3946
  serverUrl,
3756
3947
  title,
3757
- children: ({ trpc, theme }) => (0, import_react28.createElement)(PageComponent, {
3948
+ children: ({ trpc, theme }) => (0, import_react32.createElement)(PageComponent, {
3758
3949
  trpc,
3759
3950
  theme: { isDark: theme.resolvedMode === "dark" },
3760
3951
  navigate: (path) => {
@@ -3768,6 +3959,7 @@ function mountAddonPage(PageComponent, options = {}) {
3768
3959
  0 && (module.exports = {
3769
3960
  AppShell,
3770
3961
  Badge,
3962
+ BottomSheet,
3771
3963
  Button,
3772
3964
  CLASS_COLORS,
3773
3965
  Card,
@@ -3804,6 +3996,7 @@ function mountAddonPage(PageComponent, options = {}) {
3804
3996
  KeyValueList,
3805
3997
  Label,
3806
3998
  LoginForm,
3999
+ MobileDrawer,
3807
4000
  PageHeader,
3808
4001
  PipelineBuilder,
3809
4002
  PipelineRuntimeSelector,
@@ -3843,6 +4036,7 @@ function mountAddonPage(PageComponent, options = {}) {
3843
4036
  statusIcons,
3844
4037
  themeToCss,
3845
4038
  useDevShell,
4039
+ useIsMobile,
3846
4040
  useThemeMode
3847
4041
  });
3848
4042
  //# sourceMappingURL=index.cjs.map