@camstack/ui-library 0.1.34 → 0.1.36

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: {
@@ -1003,31 +1006,111 @@ function TooltipContent({ className, children, ...props }) {
1003
1006
  }
1004
1007
 
1005
1008
  // src/primitives/popover.tsx
1009
+ var import_react19 = require("react");
1010
+
1011
+ // src/hooks/use-is-mobile.ts
1006
1012
  var import_react17 = require("react");
1013
+ var MOBILE_QUERY = "(max-width: 767px)";
1014
+ function subscribe(callback) {
1015
+ const mql = window.matchMedia(MOBILE_QUERY);
1016
+ mql.addEventListener("change", callback);
1017
+ return () => mql.removeEventListener("change", callback);
1018
+ }
1019
+ function getSnapshot() {
1020
+ return window.matchMedia(MOBILE_QUERY).matches;
1021
+ }
1022
+ function getServerSnapshot() {
1023
+ return false;
1024
+ }
1025
+ function useIsMobile() {
1026
+ return (0, import_react17.useSyncExternalStore)(subscribe, getSnapshot, getServerSnapshot);
1027
+ }
1028
+
1029
+ // src/primitives/bottom-sheet.tsx
1030
+ var import_react18 = require("react");
1031
+ var import_lucide_react4 = require("lucide-react");
1007
1032
  var import_jsx_runtime16 = require("react/jsx-runtime");
1008
- var PopoverContext = (0, import_react17.createContext)(null);
1033
+ function BottomSheet({ open, onClose, title, children, className }) {
1034
+ (0, import_react18.useEffect)(() => {
1035
+ if (!open) return;
1036
+ const handleKeyDown = (e) => {
1037
+ if (e.key === "Escape") onClose();
1038
+ };
1039
+ document.addEventListener("keydown", handleKeyDown);
1040
+ document.body.style.overflow = "hidden";
1041
+ return () => {
1042
+ document.removeEventListener("keydown", handleKeyDown);
1043
+ document.body.style.overflow = "";
1044
+ };
1045
+ }, [open, onClose]);
1046
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
1047
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1048
+ "div",
1049
+ {
1050
+ className: cn(
1051
+ "fixed inset-0 z-40 bg-black/50 transition-opacity duration-200",
1052
+ open ? "opacity-100" : "pointer-events-none opacity-0"
1053
+ ),
1054
+ onClick: onClose,
1055
+ "aria-hidden": "true"
1056
+ }
1057
+ ),
1058
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
1059
+ "div",
1060
+ {
1061
+ role: "dialog",
1062
+ "aria-modal": "true",
1063
+ className: cn(
1064
+ "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",
1065
+ "max-h-[80dvh]",
1066
+ open ? "translate-y-0" : "translate-y-full",
1067
+ className
1068
+ ),
1069
+ children: [
1070
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "flex justify-center pt-2 pb-1", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "h-1 w-8 rounded-full bg-foreground-subtle/30" }) }),
1071
+ title && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center justify-between px-4 pb-2", children: [
1072
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-sm font-medium text-foreground", children: title }),
1073
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1074
+ "button",
1075
+ {
1076
+ onClick: onClose,
1077
+ className: "p-1 rounded-md hover:bg-surface-hover text-foreground-muted transition-colors",
1078
+ children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react4.X, { className: "h-4 w-4" })
1079
+ }
1080
+ )
1081
+ ] }),
1082
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "flex-1 overflow-y-auto px-4 pb-4", children })
1083
+ ]
1084
+ }
1085
+ )
1086
+ ] });
1087
+ }
1088
+
1089
+ // src/primitives/popover.tsx
1090
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1091
+ var PopoverContext = (0, import_react19.createContext)(null);
1009
1092
  function usePopoverContext() {
1010
- const ctx = (0, import_react17.useContext)(PopoverContext);
1093
+ const ctx = (0, import_react19.useContext)(PopoverContext);
1011
1094
  if (!ctx) throw new Error("Popover compound components must be used within <Popover>");
1012
1095
  return ctx;
1013
1096
  }
1014
1097
  function Popover({ children, open: controlledOpen, onOpenChange }) {
1015
- const [uncontrolledOpen, setUncontrolledOpen] = (0, import_react17.useState)(false);
1098
+ const [uncontrolledOpen, setUncontrolledOpen] = (0, import_react19.useState)(false);
1016
1099
  const open = controlledOpen ?? uncontrolledOpen;
1017
- const triggerId = (0, import_react17.useId)();
1018
- const contentId = (0, import_react17.useId)();
1019
- const setOpen = (0, import_react17.useCallback)(
1100
+ const triggerId = (0, import_react19.useId)();
1101
+ const contentId = (0, import_react19.useId)();
1102
+ const setOpen = (0, import_react19.useCallback)(
1020
1103
  (next) => {
1021
1104
  onOpenChange?.(next);
1022
1105
  if (controlledOpen === void 0) setUncontrolledOpen(next);
1023
1106
  },
1024
1107
  [controlledOpen, onOpenChange]
1025
1108
  );
1026
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(PopoverContext.Provider, { value: { open, setOpen, triggerId, contentId }, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "relative inline-block", children }) });
1109
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(PopoverContext.Provider, { value: { open, setOpen, triggerId, contentId }, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "relative inline-block", children }) });
1027
1110
  }
1028
1111
  function PopoverTrigger({ children, ...props }) {
1029
1112
  const { open, setOpen, triggerId, contentId } = usePopoverContext();
1030
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1113
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1031
1114
  "button",
1032
1115
  {
1033
1116
  type: "button",
@@ -1043,9 +1126,10 @@ function PopoverTrigger({ children, ...props }) {
1043
1126
  }
1044
1127
  function PopoverContent({ className, children, ...props }) {
1045
1128
  const { open, setOpen, contentId, triggerId } = usePopoverContext();
1046
- const ref = (0, import_react17.useRef)(null);
1047
- (0, import_react17.useEffect)(() => {
1048
- if (!open) return;
1129
+ const isMobile = useIsMobile();
1130
+ const ref = (0, import_react19.useRef)(null);
1131
+ (0, import_react19.useEffect)(() => {
1132
+ if (!open || isMobile) return;
1049
1133
  const handler = (e) => {
1050
1134
  const el = ref.current;
1051
1135
  const trigger = document.getElementById(triggerId);
@@ -1062,9 +1146,12 @@ function PopoverContent({ className, children, ...props }) {
1062
1146
  document.removeEventListener("mousedown", handler);
1063
1147
  document.removeEventListener("keydown", escHandler);
1064
1148
  };
1065
- }, [open, setOpen, triggerId]);
1149
+ }, [open, setOpen, triggerId, isMobile]);
1066
1150
  if (!open) return null;
1067
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1151
+ if (isMobile) {
1152
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(BottomSheet, { open, onClose: () => setOpen(false), children });
1153
+ }
1154
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1068
1155
  "div",
1069
1156
  {
1070
1157
  ref,
@@ -1082,11 +1169,11 @@ function PopoverContent({ className, children, ...props }) {
1082
1169
  }
1083
1170
 
1084
1171
  // src/primitives/tabs.tsx
1085
- var import_react18 = require("react");
1086
- var import_jsx_runtime17 = require("react/jsx-runtime");
1087
- var TabsContext = (0, import_react18.createContext)(null);
1172
+ var import_react20 = require("react");
1173
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1174
+ var TabsContext = (0, import_react20.createContext)(null);
1088
1175
  function useTabsContext() {
1089
- const ctx = (0, import_react18.useContext)(TabsContext);
1176
+ const ctx = (0, import_react20.useContext)(TabsContext);
1090
1177
  if (!ctx) throw new Error("Tabs compound components must be used within <Tabs>");
1091
1178
  return ctx;
1092
1179
  }
@@ -1097,19 +1184,19 @@ function Tabs({
1097
1184
  className,
1098
1185
  ...props
1099
1186
  }) {
1100
- const [uncontrolledValue, setUncontrolledValue] = (0, import_react18.useState)(defaultValue);
1187
+ const [uncontrolledValue, setUncontrolledValue] = (0, import_react20.useState)(defaultValue);
1101
1188
  const value = controlledValue ?? uncontrolledValue;
1102
- const setValue = (0, import_react18.useCallback)(
1189
+ const setValue = (0, import_react20.useCallback)(
1103
1190
  (next) => {
1104
1191
  onValueChange?.(next);
1105
1192
  if (controlledValue === void 0) setUncontrolledValue(next);
1106
1193
  },
1107
1194
  [controlledValue, onValueChange]
1108
1195
  );
1109
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(TabsContext.Provider, { value: { value, setValue }, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className, ...props }) });
1196
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TabsContext.Provider, { value: { value, setValue }, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className, ...props }) });
1110
1197
  }
1111
1198
  function TabsList({ className, ...props }) {
1112
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1199
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1113
1200
  "div",
1114
1201
  {
1115
1202
  role: "tablist",
@@ -1122,7 +1209,7 @@ function TabsTrigger({ value, className, ...props }) {
1122
1209
  const { value: activeValue, setValue } = useTabsContext();
1123
1210
  const isActive = value === activeValue;
1124
1211
  const panelId = `tabpanel-${value}`;
1125
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1212
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1126
1213
  "button",
1127
1214
  {
1128
1215
  type: "button",
@@ -1143,7 +1230,7 @@ function TabsTrigger({ value, className, ...props }) {
1143
1230
  function TabsContent({ value, className, ...props }) {
1144
1231
  const { value: activeValue } = useTabsContext();
1145
1232
  if (value !== activeValue) return null;
1146
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1233
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1147
1234
  "div",
1148
1235
  {
1149
1236
  role: "tabpanel",
@@ -1155,11 +1242,11 @@ function TabsContent({ value, className, ...props }) {
1155
1242
  }
1156
1243
 
1157
1244
  // src/primitives/scroll-area.tsx
1158
- var import_react19 = require("react");
1159
- var import_jsx_runtime18 = require("react/jsx-runtime");
1160
- var ScrollArea = (0, import_react19.forwardRef)(
1245
+ var import_react21 = require("react");
1246
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1247
+ var ScrollArea = (0, import_react21.forwardRef)(
1161
1248
  ({ className, ...props }, ref) => {
1162
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1249
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1163
1250
  "div",
1164
1251
  {
1165
1252
  ref,
@@ -1175,9 +1262,9 @@ var ScrollArea = (0, import_react19.forwardRef)(
1175
1262
  ScrollArea.displayName = "ScrollArea";
1176
1263
 
1177
1264
  // src/primitives/floating-panel.tsx
1178
- var import_react20 = require("react");
1179
- var import_lucide_react4 = require("lucide-react");
1180
- var import_jsx_runtime19 = require("react/jsx-runtime");
1265
+ var import_react22 = require("react");
1266
+ var import_lucide_react5 = require("lucide-react");
1267
+ var import_jsx_runtime20 = require("react/jsx-runtime");
1181
1268
  function FloatingPanel({
1182
1269
  title,
1183
1270
  onClose,
@@ -1189,24 +1276,25 @@ function FloatingPanel({
1189
1276
  offsetIndex = 0,
1190
1277
  className
1191
1278
  }) {
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) => {
1279
+ const [pos, setPos] = (0, import_react22.useState)({ x: 80 + offsetIndex * 30, y: 80 + offsetIndex * 30 });
1280
+ const [size, setSize] = (0, import_react22.useState)({ w: defaultWidth, h: defaultHeight });
1281
+ const [minimized, setMinimized] = (0, import_react22.useState)(false);
1282
+ const dragging = (0, import_react22.useRef)(false);
1283
+ const resizing = (0, import_react22.useRef)(false);
1284
+ const offset = (0, import_react22.useRef)({ x: 0, y: 0 });
1285
+ const isMobile = useIsMobile();
1286
+ const onDragStart = (0, import_react22.useCallback)((e) => {
1199
1287
  e.preventDefault();
1200
1288
  dragging.current = true;
1201
1289
  offset.current = { x: e.clientX - pos.x, y: e.clientY - pos.y };
1202
1290
  }, [pos]);
1203
- const onResizeStart = (0, import_react20.useCallback)((e) => {
1291
+ const onResizeStart = (0, import_react22.useCallback)((e) => {
1204
1292
  e.preventDefault();
1205
1293
  e.stopPropagation();
1206
1294
  resizing.current = true;
1207
1295
  offset.current = { x: e.clientX, y: e.clientY };
1208
1296
  }, []);
1209
- (0, import_react20.useEffect)(() => {
1297
+ (0, import_react22.useEffect)(() => {
1210
1298
  const onMouseMove = (e) => {
1211
1299
  if (dragging.current) setPos({ x: e.clientX - offset.current.x, y: e.clientY - offset.current.y });
1212
1300
  if (resizing.current) {
@@ -1227,7 +1315,43 @@ function FloatingPanel({
1227
1315
  window.removeEventListener("mouseup", onMouseUp);
1228
1316
  };
1229
1317
  }, [minWidth, minHeight]);
1230
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
1318
+ if (isMobile) {
1319
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
1320
+ "div",
1321
+ {
1322
+ className: cn(
1323
+ "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",
1324
+ className
1325
+ ),
1326
+ style: { maxHeight: "60dvh" },
1327
+ children: [
1328
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center justify-between gap-2 px-3 py-2 border-b border-border shrink-0 bg-surface", children: [
1329
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-[11px] font-medium truncate", children: title }),
1330
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center gap-1 shrink-0", children: [
1331
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1332
+ "button",
1333
+ {
1334
+ onClick: () => setMinimized(!minimized),
1335
+ className: "p-0.5 rounded hover:bg-surface-hover text-foreground-muted transition-colors",
1336
+ children: minimized ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react5.Maximize2, { size: 12 }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react5.Minimize2, { size: 12 })
1337
+ }
1338
+ ),
1339
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1340
+ "button",
1341
+ {
1342
+ onClick: onClose,
1343
+ className: "p-0.5 rounded hover:bg-danger/20 text-foreground-muted hover:text-danger transition-colors",
1344
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react5.X, { size: 12 })
1345
+ }
1346
+ )
1347
+ ] })
1348
+ ] }),
1349
+ !minimized && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex-1 min-h-0 overflow-y-auto", children })
1350
+ ]
1351
+ }
1352
+ );
1353
+ }
1354
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
1231
1355
  "div",
1232
1356
  {
1233
1357
  className: cn(
@@ -1236,42 +1360,42 @@ function FloatingPanel({
1236
1360
  ),
1237
1361
  style: { left: pos.x, top: pos.y, width: minimized ? 280 : size.w, height: minimized ? "auto" : size.h },
1238
1362
  children: [
1239
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
1363
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
1240
1364
  "div",
1241
1365
  {
1242
1366
  onMouseDown: onDragStart,
1243
1367
  className: "flex items-center justify-between gap-2 px-3 py-2 border-b border-border cursor-move select-none shrink-0 bg-surface",
1244
1368
  children: [
1245
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-2 min-w-0", children: [
1246
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react4.GripHorizontal, { size: 12, className: "text-foreground-subtle shrink-0" }),
1247
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-[11px] font-medium truncate", children: title })
1369
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center gap-2 min-w-0", children: [
1370
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react5.GripHorizontal, { size: 12, className: "text-foreground-subtle shrink-0" }),
1371
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-[11px] font-medium truncate", children: title })
1248
1372
  ] }),
1249
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-1 shrink-0", children: [
1250
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1373
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center gap-1 shrink-0", children: [
1374
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1251
1375
  "button",
1252
1376
  {
1253
1377
  onClick: () => setMinimized(!minimized),
1254
1378
  className: "p-0.5 rounded hover:bg-surface-hover text-foreground-muted transition-colors",
1255
1379
  title: minimized ? "Restore" : "Minimize",
1256
- 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 })
1380
+ children: minimized ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react5.Maximize2, { size: 12 }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react5.Minimize2, { size: 12 })
1257
1381
  }
1258
1382
  ),
1259
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1383
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1260
1384
  "button",
1261
1385
  {
1262
1386
  onClick: onClose,
1263
1387
  className: "p-0.5 rounded hover:bg-danger/20 text-foreground-muted hover:text-danger transition-colors",
1264
1388
  title: "Close",
1265
- children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react4.X, { size: 12 })
1389
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react5.X, { size: 12 })
1266
1390
  }
1267
1391
  )
1268
1392
  ] })
1269
1393
  ]
1270
1394
  }
1271
1395
  ),
1272
- !minimized && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex-1 min-h-0 overflow-y-auto relative", children: [
1396
+ !minimized && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex-1 min-h-0 overflow-y-auto relative", children: [
1273
1397
  children,
1274
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1398
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1275
1399
  "div",
1276
1400
  {
1277
1401
  onMouseDown: onResizeStart,
@@ -1285,8 +1409,55 @@ function FloatingPanel({
1285
1409
  );
1286
1410
  }
1287
1411
 
1412
+ // src/primitives/mobile-drawer.tsx
1413
+ var import_react23 = require("react");
1414
+ var import_jsx_runtime21 = require("react/jsx-runtime");
1415
+ function MobileDrawer({ open, onClose, children, className, width = "w-64" }) {
1416
+ const drawerRef = (0, import_react23.useRef)(null);
1417
+ (0, import_react23.useEffect)(() => {
1418
+ if (!open) return;
1419
+ const handleKeyDown = (e) => {
1420
+ if (e.key === "Escape") onClose();
1421
+ };
1422
+ document.addEventListener("keydown", handleKeyDown);
1423
+ document.body.style.overflow = "hidden";
1424
+ return () => {
1425
+ document.removeEventListener("keydown", handleKeyDown);
1426
+ document.body.style.overflow = "";
1427
+ };
1428
+ }, [open, onClose]);
1429
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
1430
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1431
+ "div",
1432
+ {
1433
+ className: cn(
1434
+ "fixed inset-0 z-40 bg-black/50 backdrop-blur-sm transition-opacity duration-200",
1435
+ open ? "opacity-100" : "pointer-events-none opacity-0"
1436
+ ),
1437
+ onClick: onClose,
1438
+ "aria-hidden": "true"
1439
+ }
1440
+ ),
1441
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
1442
+ "div",
1443
+ {
1444
+ ref: drawerRef,
1445
+ role: "dialog",
1446
+ "aria-modal": "true",
1447
+ className: cn(
1448
+ "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",
1449
+ width,
1450
+ open ? "translate-x-0" : "-translate-x-full",
1451
+ className
1452
+ ),
1453
+ children
1454
+ }
1455
+ )
1456
+ ] });
1457
+ }
1458
+
1288
1459
  // src/composites/status-badge.tsx
1289
- var import_jsx_runtime20 = require("react/jsx-runtime");
1460
+ var import_jsx_runtime22 = require("react/jsx-runtime");
1290
1461
  var statusConfig = {
1291
1462
  online: { colorClass: "bg-success", label: "Online" },
1292
1463
  offline: { colorClass: "bg-danger", label: "Offline" },
@@ -1301,7 +1472,7 @@ function StatusBadge({
1301
1472
  className
1302
1473
  }) {
1303
1474
  const config = statusConfig[status];
1304
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
1475
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
1305
1476
  "span",
1306
1477
  {
1307
1478
  className: cn(
@@ -1310,21 +1481,21 @@ function StatusBadge({
1310
1481
  className
1311
1482
  ),
1312
1483
  children: [
1313
- showDot && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1484
+ showDot && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
1314
1485
  "span",
1315
1486
  {
1316
1487
  className: cn("h-1.5 w-1.5 shrink-0 rounded-full", config.colorClass),
1317
1488
  "aria-hidden": "true"
1318
1489
  }
1319
1490
  ),
1320
- showLabel && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-foreground", children: config.label })
1491
+ showLabel && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "text-foreground", children: config.label })
1321
1492
  ]
1322
1493
  }
1323
1494
  );
1324
1495
  }
1325
1496
 
1326
1497
  // src/composites/provider-badge.tsx
1327
- var import_jsx_runtime21 = require("react/jsx-runtime");
1498
+ var import_jsx_runtime23 = require("react/jsx-runtime");
1328
1499
  var providerConfig = {
1329
1500
  frigate: { colorClass: "bg-provider-frigate", label: "Frigate" },
1330
1501
  scrypted: { colorClass: "bg-provider-scrypted", label: "Scrypted" },
@@ -1338,20 +1509,20 @@ function ProviderBadge({
1338
1509
  className
1339
1510
  }) {
1340
1511
  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)(
1512
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("span", { className: cn("inline-flex items-center gap-1.5 text-xs", className), children: [
1513
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
1343
1514
  "span",
1344
1515
  {
1345
1516
  className: cn("h-1.5 w-1.5 shrink-0 rounded-sm", config.colorClass),
1346
1517
  "aria-hidden": "true"
1347
1518
  }
1348
1519
  ),
1349
- showLabel && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-foreground", children: config.label })
1520
+ showLabel && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "text-foreground", children: config.label })
1350
1521
  ] });
1351
1522
  }
1352
1523
 
1353
1524
  // src/composites/version-badge.tsx
1354
- var import_jsx_runtime22 = require("react/jsx-runtime");
1525
+ var import_jsx_runtime24 = require("react/jsx-runtime");
1355
1526
  var VARIANT_STYLES = {
1356
1527
  success: "bg-emerald-400 text-emerald-950",
1357
1528
  warning: "bg-amber-400 text-amber-950",
@@ -1360,7 +1531,7 @@ var VARIANT_STYLES = {
1360
1531
  neutral: "bg-foreground-subtle/20 text-foreground"
1361
1532
  };
1362
1533
  function SemanticBadge({ children, variant = "neutral", mono, className }) {
1363
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: cn(
1534
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: cn(
1364
1535
  "inline-flex items-center rounded-md px-2 py-0.5 text-[11px] font-bold leading-tight",
1365
1536
  mono && "font-mono",
1366
1537
  VARIANT_STYLES[variant],
@@ -1369,11 +1540,11 @@ function SemanticBadge({ children, variant = "neutral", mono, className }) {
1369
1540
  }
1370
1541
  function VersionBadge({ version, preRelease, className }) {
1371
1542
  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 });
1543
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(SemanticBadge, { variant: isPreRelease ? "warning" : "success", mono: true, className, children: version });
1373
1544
  }
1374
1545
 
1375
1546
  // src/composites/form-field.tsx
1376
- var import_jsx_runtime23 = require("react/jsx-runtime");
1547
+ var import_jsx_runtime25 = require("react/jsx-runtime");
1377
1548
  function FormField({
1378
1549
  label,
1379
1550
  description,
@@ -1384,7 +1555,7 @@ function FormField({
1384
1555
  className
1385
1556
  }) {
1386
1557
  const isHorizontal = orientation === "horizontal";
1387
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
1558
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
1388
1559
  "div",
1389
1560
  {
1390
1561
  className: cn(
@@ -1393,34 +1564,34 @@ function FormField({
1393
1564
  className
1394
1565
  ),
1395
1566
  children: [
1396
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: cn(isHorizontal ? "flex-1" : ""), children: [
1397
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(Label, { children: [
1567
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: cn(isHorizontal ? "flex-1" : ""), children: [
1568
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(Label, { children: [
1398
1569
  label,
1399
- required && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "text-danger ml-0.5", children: "*" })
1570
+ required && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "text-danger ml-0.5", children: "*" })
1400
1571
  ] }),
1401
- description && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-foreground-subtle text-xs mt-0.5", children: description })
1572
+ description && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "text-foreground-subtle text-xs mt-0.5", children: description })
1402
1573
  ] }),
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 })
1574
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: cn(isHorizontal ? "shrink-0" : ""), children }),
1575
+ error && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "text-danger text-xs", children: error })
1405
1576
  ]
1406
1577
  }
1407
1578
  );
1408
1579
  }
1409
1580
 
1410
1581
  // src/composites/page-header.tsx
1411
- var import_jsx_runtime24 = require("react/jsx-runtime");
1582
+ var import_jsx_runtime26 = require("react/jsx-runtime");
1412
1583
  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 })
1584
+ 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: [
1585
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { children: [
1586
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("h1", { className: "text-sm font-semibold text-foreground", children: title }),
1587
+ subtitle && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { className: "text-foreground-subtle text-xs", children: subtitle })
1417
1588
  ] }),
1418
- actions && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "flex items-center gap-2", children: actions })
1589
+ actions && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "flex items-center gap-2 flex-wrap", children: actions })
1419
1590
  ] });
1420
1591
  }
1421
1592
 
1422
1593
  // src/composites/empty-state.tsx
1423
- var import_jsx_runtime25 = require("react/jsx-runtime");
1594
+ var import_jsx_runtime27 = require("react/jsx-runtime");
1424
1595
  function EmptyState({
1425
1596
  icon: Icon,
1426
1597
  title,
@@ -1428,18 +1599,18 @@ function EmptyState({
1428
1599
  action,
1429
1600
  className
1430
1601
  }) {
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 })
1602
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: cn("flex flex-col items-center justify-center gap-3 py-12", className), children: [
1603
+ Icon && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(Icon, { className: "h-12 w-12 text-foreground-subtle", "aria-hidden": "true" }),
1604
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex flex-col items-center gap-1 text-center", children: [
1605
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: "text-foreground-muted text-sm font-medium", children: title }),
1606
+ description && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: "text-foreground-subtle text-xs max-w-xs", children: description })
1436
1607
  ] }),
1437
- action && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "mt-1", children: action })
1608
+ action && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "mt-1", children: action })
1438
1609
  ] });
1439
1610
  }
1440
1611
 
1441
1612
  // src/composites/confirm-dialog.tsx
1442
- var import_jsx_runtime26 = require("react/jsx-runtime");
1613
+ var import_jsx_runtime28 = require("react/jsx-runtime");
1443
1614
  function ConfirmDialog({
1444
1615
  title,
1445
1616
  message,
@@ -1451,14 +1622,14 @@ function ConfirmDialog({
1451
1622
  open,
1452
1623
  onOpenChange
1453
1624
  }) {
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 })
1625
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Dialog, { open, onOpenChange, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(DialogContent, { children: [
1626
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(DialogHeader, { children: [
1627
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(DialogTitle, { children: title }),
1628
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(DialogDescription, { children: message })
1458
1629
  ] }),
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)(
1630
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(DialogFooter, { children: [
1631
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Button, { variant: "ghost", onClick: onCancel, children: cancelLabel }),
1632
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
1462
1633
  Button,
1463
1634
  {
1464
1635
  variant: variant === "danger" ? "danger" : "primary",
@@ -1471,13 +1642,13 @@ function ConfirmDialog({
1471
1642
  }
1472
1643
 
1473
1644
  // src/composites/stat-card.tsx
1474
- var import_lucide_react5 = require("lucide-react");
1475
- var import_jsx_runtime27 = require("react/jsx-runtime");
1645
+ var import_lucide_react6 = require("lucide-react");
1646
+ var import_jsx_runtime29 = require("react/jsx-runtime");
1476
1647
  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)(
1648
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(Card, { className: cn("flex flex-col gap-1", className), children: [
1649
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex items-baseline gap-2", children: [
1650
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "text-2xl font-semibold text-foreground", children: value }),
1651
+ trend && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
1481
1652
  "span",
1482
1653
  {
1483
1654
  className: cn(
@@ -1485,27 +1656,27 @@ function StatCard({ value, label, trend, className }) {
1485
1656
  trend.direction === "up" ? "text-success" : "text-danger"
1486
1657
  ),
1487
1658
  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" }),
1659
+ 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
1660
  trend.value,
1490
1661
  "%"
1491
1662
  ]
1492
1663
  }
1493
1664
  )
1494
1665
  ] }),
1495
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "text-xs text-foreground-muted", children: label })
1666
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("span", { className: "text-xs text-foreground-muted", children: label })
1496
1667
  ] });
1497
1668
  }
1498
1669
 
1499
1670
  // src/composites/key-value-list.tsx
1500
- var import_jsx_runtime28 = require("react/jsx-runtime");
1671
+ var import_jsx_runtime30 = require("react/jsx-runtime");
1501
1672
  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)(
1673
+ 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
1674
  "div",
1504
1675
  {
1505
1676
  className: "flex items-center h-7",
1506
1677
  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 })
1678
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("dt", { className: "text-foreground-subtle text-xs w-1/3 shrink-0", children: item.key }),
1679
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("dd", { className: "text-foreground text-xs", children: item.value })
1509
1680
  ]
1510
1681
  },
1511
1682
  item.key
@@ -1513,23 +1684,23 @@ function KeyValueList({ items, className }) {
1513
1684
  }
1514
1685
 
1515
1686
  // 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");
1687
+ var import_react24 = require("react");
1688
+ var import_lucide_react7 = require("lucide-react");
1689
+ var import_jsx_runtime31 = require("react/jsx-runtime");
1519
1690
  function CodeBlock({ children, maxHeight = 300, className }) {
1520
- const [copied, setCopied] = (0, import_react21.useState)(false);
1521
- const handleCopy = (0, import_react21.useCallback)(() => {
1691
+ const [copied, setCopied] = (0, import_react24.useState)(false);
1692
+ const handleCopy = (0, import_react24.useCallback)(() => {
1522
1693
  navigator.clipboard.writeText(children).then(() => {
1523
1694
  setCopied(true);
1524
1695
  setTimeout(() => setCopied(false), 2e3);
1525
1696
  });
1526
1697
  }, [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)(
1698
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: cn("relative group", className), children: [
1699
+ /* @__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 }) }) }),
1700
+ /* @__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
1701
  IconButton,
1531
1702
  {
1532
- icon: copied ? import_lucide_react6.Check : import_lucide_react6.Copy,
1703
+ icon: copied ? import_lucide_react7.Check : import_lucide_react7.Copy,
1533
1704
  "aria-label": "Copy code",
1534
1705
  variant: "ghost",
1535
1706
  size: "sm",
@@ -1540,28 +1711,95 @@ function CodeBlock({ children, maxHeight = 300, className }) {
1540
1711
  }
1541
1712
 
1542
1713
  // src/composites/filter-bar.tsx
1543
- var import_lucide_react7 = require("lucide-react");
1544
- var import_jsx_runtime30 = require("react/jsx-runtime");
1714
+ var import_react25 = require("react");
1715
+ var import_lucide_react8 = require("lucide-react");
1716
+ var import_jsx_runtime32 = require("react/jsx-runtime");
1545
1717
  function FilterBar({ filters, values, onChange, className }) {
1718
+ const isMobile = useIsMobile();
1719
+ const [sheetOpen, setSheetOpen] = (0, import_react25.useState)(false);
1546
1720
  const handleChange = (key, value) => {
1547
1721
  onChange({ ...values, [key]: value });
1548
1722
  };
1549
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: cn("flex items-center gap-2 flex-wrap", className), children: filters.map((filter) => {
1723
+ const activeCount = Object.values(values).filter((v) => v !== void 0 && v !== "").length;
1724
+ if (isMobile) {
1725
+ const searchFilter = filters.find((f) => f.type === "search");
1726
+ const hasNonSearchFilters = filters.some((f) => f.type !== "search");
1727
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: cn("flex items-center gap-2", className), children: [
1728
+ searchFilter && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
1729
+ Input,
1730
+ {
1731
+ placeholder: searchFilter.placeholder ?? "Search...",
1732
+ value: values[searchFilter.key] ?? "",
1733
+ onChange: (e) => handleChange(searchFilter.key, e.target.value),
1734
+ leftSlot: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react8.Search, { className: "h-3 w-3 text-foreground-subtle" }),
1735
+ className: "flex-1"
1736
+ }
1737
+ ),
1738
+ hasNonSearchFilters && /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_jsx_runtime32.Fragment, { children: [
1739
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
1740
+ "button",
1741
+ {
1742
+ onClick: () => setSheetOpen(true),
1743
+ className: "flex items-center gap-1.5 rounded-md border border-border px-2.5 py-1.5 text-xs text-foreground-muted hover:bg-surface-hover transition-colors shrink-0",
1744
+ children: [
1745
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react8.SlidersHorizontal, { className: "h-3.5 w-3.5" }),
1746
+ "Filters",
1747
+ activeCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Badge, { variant: "info", className: "ml-1 text-[10px] px-1 py-0", children: activeCount })
1748
+ ]
1749
+ }
1750
+ ),
1751
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(BottomSheet, { open: sheetOpen, onClose: () => setSheetOpen(false), title: "Filters", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "flex flex-col gap-3", children: filters.filter((f) => f.type !== "search").map((filter) => {
1752
+ switch (filter.type) {
1753
+ case "select":
1754
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { children: [
1755
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("label", { className: "text-xs text-foreground-muted mb-1 block", children: filter.label }),
1756
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
1757
+ Select,
1758
+ {
1759
+ options: filter.options,
1760
+ value: values[filter.key] ?? "",
1761
+ onChange: (e) => handleChange(filter.key, e.target.value),
1762
+ className: "w-full"
1763
+ }
1764
+ )
1765
+ ] }, filter.key);
1766
+ case "badge-toggle":
1767
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "flex items-center gap-1 flex-wrap", children: filter.options.map((option) => {
1768
+ const currentValue = values[filter.key];
1769
+ const isActive = currentValue === option.value;
1770
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
1771
+ "button",
1772
+ {
1773
+ type: "button",
1774
+ onClick: () => handleChange(filter.key, isActive ? void 0 : option.value),
1775
+ children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Badge, { variant: isActive ? "info" : "default", className: "cursor-pointer", children: option.label })
1776
+ },
1777
+ option.value
1778
+ );
1779
+ }) }, filter.key);
1780
+ default:
1781
+ return null;
1782
+ }
1783
+ }) }) })
1784
+ ] })
1785
+ ] });
1786
+ }
1787
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: cn("flex items-center gap-2 flex-wrap", className), children: filters.map((filter) => {
1550
1788
  switch (filter.type) {
1551
1789
  case "search":
1552
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1790
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
1553
1791
  Input,
1554
1792
  {
1555
1793
  placeholder: filter.placeholder ?? "Search...",
1556
1794
  value: values[filter.key] ?? "",
1557
1795
  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" }),
1796
+ leftSlot: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react8.Search, { className: "h-3 w-3 text-foreground-subtle" }),
1559
1797
  className: "w-48"
1560
1798
  },
1561
1799
  filter.key
1562
1800
  );
1563
1801
  case "select":
1564
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1802
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
1565
1803
  Select,
1566
1804
  {
1567
1805
  options: filter.options,
@@ -1572,25 +1810,15 @@ function FilterBar({ filters, values, onChange, className }) {
1572
1810
  filter.key
1573
1811
  );
1574
1812
  case "badge-toggle":
1575
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "flex items-center gap-1", children: filter.options.map((option) => {
1813
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "flex items-center gap-1", children: filter.options.map((option) => {
1576
1814
  const currentValue = values[filter.key];
1577
1815
  const isActive = currentValue === option.value;
1578
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1816
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
1579
1817
  "button",
1580
1818
  {
1581
1819
  type: "button",
1582
- onClick: () => handleChange(
1583
- filter.key,
1584
- isActive ? void 0 : option.value
1585
- ),
1586
- children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
1587
- Badge,
1588
- {
1589
- variant: isActive ? "info" : "default",
1590
- className: "cursor-pointer",
1591
- children: option.label
1592
- }
1593
- )
1820
+ onClick: () => handleChange(filter.key, isActive ? void 0 : option.value),
1821
+ children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Badge, { variant: isActive ? "info" : "default", className: "cursor-pointer", children: option.label })
1594
1822
  },
1595
1823
  option.value
1596
1824
  );
@@ -1602,7 +1830,7 @@ function FilterBar({ filters, values, onChange, className }) {
1602
1830
  }
1603
1831
 
1604
1832
  // src/composites/app-shell/sidebar-item.tsx
1605
- var import_jsx_runtime31 = require("react/jsx-runtime");
1833
+ var import_jsx_runtime33 = require("react/jsx-runtime");
1606
1834
  function SidebarItem({
1607
1835
  label,
1608
1836
  icon: Icon,
@@ -1611,7 +1839,7 @@ function SidebarItem({
1611
1839
  active = false,
1612
1840
  className
1613
1841
  }) {
1614
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
1842
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
1615
1843
  "a",
1616
1844
  {
1617
1845
  href,
@@ -1621,33 +1849,33 @@ function SidebarItem({
1621
1849
  className
1622
1850
  ),
1623
1851
  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 })
1852
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Icon, { className: "h-3.5 w-3.5 shrink-0" }),
1853
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "truncate flex-1", children: label }),
1854
+ badge !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Badge, { className: "ml-auto text-[10px] px-1.5 py-0", children: badge })
1627
1855
  ]
1628
1856
  }
1629
1857
  );
1630
1858
  }
1631
1859
 
1632
1860
  // 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)(
1861
+ var import_jsx_runtime34 = require("react/jsx-runtime");
1862
+ function Sidebar({ logo, sections, footer, onNavigate, className }) {
1863
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
1636
1864
  "nav",
1637
1865
  {
1638
1866
  className: cn(
1639
- "w-44 bg-surface border-r border-border h-full flex flex-col",
1867
+ "bg-surface border-r border-border h-full flex flex-col",
1640
1868
  className
1641
1869
  ),
1642
1870
  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)) })
1871
+ logo && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "px-3 py-2 shrink-0", children: logo }),
1872
+ /* @__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: [
1873
+ 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 }),
1874
+ /* @__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
1875
  ] }, 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)) })
1876
+ footer && footer.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "shrink-0 px-1 pb-1", children: [
1877
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(Separator, { className: "mb-1" }),
1878
+ /* @__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
1879
  ] })
1652
1880
  ]
1653
1881
  }
@@ -1655,54 +1883,78 @@ function Sidebar({ logo, sections, footer, className }) {
1655
1883
  }
1656
1884
 
1657
1885
  // 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) => {
1886
+ var import_react26 = require("react");
1887
+ var import_lucide_react9 = require("lucide-react");
1888
+ var import_jsx_runtime35 = require("react/jsx-runtime");
1889
+ function AppShell({ sidebar, header, mobileLogo, mobileActions, children, className }) {
1890
+ const isMobile = useIsMobile();
1891
+ const [drawerOpen, setDrawerOpen] = (0, import_react26.useState)(false);
1892
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: cn("flex h-screen", className), children: [
1893
+ !isMobile && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Sidebar, { ...sidebar, className: cn("w-44", sidebar.className) }),
1894
+ isMobile && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(MobileDrawer, { open: drawerOpen, onClose: () => setDrawerOpen(false), width: "w-64", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
1895
+ Sidebar,
1896
+ {
1897
+ ...sidebar,
1898
+ onNavigate: () => setDrawerOpen(false),
1899
+ className: "w-full border-r-0"
1900
+ }
1901
+ ) }),
1902
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "flex flex-1 flex-col min-w-0", children: [
1903
+ 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: [
1904
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
1905
+ "button",
1906
+ {
1907
+ onClick: () => setDrawerOpen(true),
1908
+ className: "p-1.5 -ml-1.5 rounded-md hover:bg-surface-hover text-foreground-muted transition-colors",
1909
+ "aria-label": "Open menu",
1910
+ children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_lucide_react9.Menu, { className: "h-5 w-5" })
1911
+ }
1912
+ ),
1913
+ mobileLogo && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "flex-1 flex justify-center", children: mobileLogo }),
1914
+ mobileActions && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "shrink-0", children: mobileActions })
1915
+ ] }),
1916
+ !isMobile && header && /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("header", { className: "flex items-center h-10 border-b border-border px-4 shrink-0", children: [
1917
+ 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
1918
  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)(
1919
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { className: "flex items-center gap-1", children: [
1920
+ index > 0 && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_lucide_react9.ChevronRight, { className: "h-3 w-3 text-foreground-subtle shrink-0" }),
1921
+ crumb.href && !isLast ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
1670
1922
  "a",
1671
1923
  {
1672
1924
  href: crumb.href,
1673
1925
  className: "text-foreground-subtle hover:text-foreground transition-colors truncate",
1674
1926
  children: crumb.label
1675
1927
  }
1676
- ) : /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "text-foreground truncate", children: crumb.label })
1928
+ ) : /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "text-foreground truncate", children: crumb.label })
1677
1929
  ] }, index);
1678
1930
  }) }),
1679
- header.actions && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex items-center gap-2 ml-auto shrink-0", children: header.actions })
1931
+ header.actions && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "flex items-center gap-2 ml-auto shrink-0", children: header.actions })
1680
1932
  ] }),
1681
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("main", { className: "flex-1 overflow-auto p-4", children })
1933
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("main", { className: "flex-1 overflow-auto p-4", children })
1682
1934
  ] })
1683
1935
  ] });
1684
1936
  }
1685
1937
 
1686
1938
  // src/composites/data-table/data-table.tsx
1687
- var import_react22 = require("react");
1939
+ var import_react27 = require("react");
1688
1940
  var import_react_table = require("@tanstack/react-table");
1689
1941
 
1690
1942
  // 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");
1943
+ var import_lucide_react10 = require("lucide-react");
1944
+ var import_jsx_runtime36 = require("react/jsx-runtime");
1693
1945
  function DataTableHeader({
1694
1946
  headerGroups,
1695
1947
  onSortingChange,
1696
1948
  stickyHeader,
1697
1949
  flexRender: render
1698
1950
  }) {
1699
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
1951
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1700
1952
  "thead",
1701
1953
  {
1702
1954
  className: cn(
1703
1955
  stickyHeader && "sticky top-0 z-10 bg-background"
1704
1956
  ),
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)(
1957
+ 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
1958
  HeaderCell,
1707
1959
  {
1708
1960
  header,
@@ -1716,8 +1968,8 @@ function DataTableHeader({
1716
1968
  }
1717
1969
  function HeaderCell({ header, sortable, flexRender: render }) {
1718
1970
  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)(
1971
+ const SortIcon = sorted === "asc" ? import_lucide_react10.ArrowUp : sorted === "desc" ? import_lucide_react10.ArrowDown : import_lucide_react10.ArrowUpDown;
1972
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
1721
1973
  "th",
1722
1974
  {
1723
1975
  className: cn(
@@ -1725,17 +1977,17 @@ function HeaderCell({ header, sortable, flexRender: render }) {
1725
1977
  sortable && "cursor-pointer select-none"
1726
1978
  ),
1727
1979
  onClick: sortable ? header.column.getToggleSortingHandler() : void 0,
1728
- children: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("span", { className: "inline-flex items-center gap-1", children: [
1980
+ children: /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("span", { className: "inline-flex items-center gap-1", children: [
1729
1981
  header.isPlaceholder ? null : render(header.column.columnDef.header, header.getContext()),
1730
- sortable && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(SortIcon, { className: "h-3 w-3" })
1982
+ sortable && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(SortIcon, { className: "h-3 w-3" })
1731
1983
  ] })
1732
1984
  }
1733
1985
  );
1734
1986
  }
1735
1987
 
1736
1988
  // 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");
1989
+ var import_lucide_react11 = require("lucide-react");
1990
+ var import_jsx_runtime37 = require("react/jsx-runtime");
1739
1991
  function DataTableRow({
1740
1992
  row,
1741
1993
  onRowClick,
@@ -1743,7 +1995,7 @@ function DataTableRow({
1743
1995
  flexRender: render
1744
1996
  }) {
1745
1997
  const actions = rowActions ? rowActions(row.original) : [];
1746
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
1998
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
1747
1999
  "tr",
1748
2000
  {
1749
2001
  className: cn(
@@ -1753,17 +2005,17 @@ function DataTableRow({
1753
2005
  ),
1754
2006
  onClick: onRowClick ? () => onRowClick(row.original) : void 0,
1755
2007
  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)(
2008
+ row.getVisibleCells().map((cell) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(DataTableCell, { cell, flexRender: render }, cell.id)),
2009
+ 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: [
2010
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
1759
2011
  DropdownTrigger,
1760
2012
  {
1761
2013
  className: "p-0.5 rounded hover:bg-surface-hover",
1762
2014
  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" })
2015
+ children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_lucide_react11.MoreHorizontal, { className: "h-3.5 w-3.5 text-foreground-muted" })
1764
2016
  }
1765
2017
  ),
1766
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(DropdownContent, { className: "right-0 left-auto", children: actions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
2018
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(DropdownContent, { className: "right-0 left-auto", children: actions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
1767
2019
  DropdownItem,
1768
2020
  {
1769
2021
  icon: action.icon,
@@ -1782,12 +2034,12 @@ function DataTableRow({
1782
2034
  );
1783
2035
  }
1784
2036
  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()) });
2037
+ 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
2038
  }
1787
2039
 
1788
2040
  // 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");
2041
+ var import_lucide_react12 = require("lucide-react");
2042
+ var import_jsx_runtime38 = require("react/jsx-runtime");
1791
2043
  var PAGE_SIZE_OPTIONS = [
1792
2044
  { value: "10", label: "10" },
1793
2045
  { value: "25", label: "25" },
@@ -1802,10 +2054,10 @@ function DataTablePagination({
1802
2054
  }) {
1803
2055
  const totalPages = Math.max(1, Math.ceil(total / pageSize));
1804
2056
  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)(
2057
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "flex items-center justify-between px-2 py-2 text-xs text-foreground-muted", children: [
2058
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "flex items-center gap-2", children: [
2059
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { children: "Rows per page" }),
2060
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "w-16", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
1809
2061
  Select,
1810
2062
  {
1811
2063
  options: PAGE_SIZE_OPTIONS,
@@ -1817,17 +2069,17 @@ function DataTablePagination({
1817
2069
  }
1818
2070
  ) })
1819
2071
  ] }),
1820
- /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex items-center gap-2", children: [
1821
- /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("span", { children: [
2072
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "flex items-center gap-2", children: [
2073
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("span", { children: [
1822
2074
  "Page ",
1823
2075
  currentPage,
1824
2076
  " of ",
1825
2077
  totalPages
1826
2078
  ] }),
1827
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
2079
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
1828
2080
  IconButton,
1829
2081
  {
1830
- icon: import_lucide_react11.ChevronLeft,
2082
+ icon: import_lucide_react12.ChevronLeft,
1831
2083
  "aria-label": "Previous page",
1832
2084
  variant: "ghost",
1833
2085
  size: "sm",
@@ -1835,10 +2087,10 @@ function DataTablePagination({
1835
2087
  onClick: () => onPaginationChange?.({ pageIndex: page - 1, pageSize })
1836
2088
  }
1837
2089
  ),
1838
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
2090
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
1839
2091
  IconButton,
1840
2092
  {
1841
- icon: import_lucide_react11.ChevronRight,
2093
+ icon: import_lucide_react12.ChevronRight,
1842
2094
  "aria-label": "Next page",
1843
2095
  variant: "ghost",
1844
2096
  size: "sm",
@@ -1851,7 +2103,7 @@ function DataTablePagination({
1851
2103
  }
1852
2104
 
1853
2105
  // src/composites/data-table/data-table.tsx
1854
- var import_jsx_runtime37 = require("react/jsx-runtime");
2106
+ var import_jsx_runtime39 = require("react/jsx-runtime");
1855
2107
  function DataTable({
1856
2108
  data,
1857
2109
  columns: userColumns,
@@ -1868,13 +2120,14 @@ function DataTable({
1868
2120
  selectable = false,
1869
2121
  compact = true,
1870
2122
  stickyHeader = false,
1871
- className
2123
+ className,
2124
+ mobileMode = "scroll"
1872
2125
  }) {
1873
- const columns = (0, import_react22.useMemo)(() => {
2126
+ const columns = (0, import_react27.useMemo)(() => {
1874
2127
  if (!selectable) return userColumns;
1875
2128
  const selectColumn = {
1876
2129
  id: "__select",
1877
- header: ({ table: table2 }) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
2130
+ header: ({ table: table2 }) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
1878
2131
  Checkbox,
1879
2132
  {
1880
2133
  checked: table2.getIsAllPageRowsSelected(),
@@ -1882,7 +2135,7 @@ function DataTable({
1882
2135
  "aria-label": "Select all"
1883
2136
  }
1884
2137
  ),
1885
- cell: ({ row }) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
2138
+ cell: ({ row }) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
1886
2139
  Checkbox,
1887
2140
  {
1888
2141
  checked: row.getIsSelected(),
@@ -1920,9 +2173,71 @@ function DataTable({
1920
2173
  pageCount: pagination ? Math.ceil(pagination.total / pagination.pageSize) : void 0
1921
2174
  });
1922
2175
  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)(
2176
+ const isMobile = useIsMobile();
2177
+ const showCards = isMobile && mobileMode === "cards";
2178
+ if (showCards) {
2179
+ const rows = table.getRowModel().rows;
2180
+ if (loading) {
2181
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: cn("space-y-2", className), children: Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "rounded-lg border border-border bg-surface p-3 space-y-2", children: [
2182
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Skeleton, { className: "h-3 w-3/4" }),
2183
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Skeleton, { className: "h-3 w-1/2" }),
2184
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Skeleton, { className: "h-3 w-2/3" })
2185
+ ] }, i)) });
2186
+ }
2187
+ if (rows.length === 0) {
2188
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: cn("text-center py-8 text-xs text-foreground-muted", className), children: emptyState ?? "No data" });
2189
+ }
2190
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: cn("space-y-2", className), children: [
2191
+ rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
2192
+ "div",
2193
+ {
2194
+ className: cn(
2195
+ "rounded-lg border border-border bg-surface p-3 space-y-1.5",
2196
+ onRowClick && "cursor-pointer hover:bg-surface-hover transition-colors"
2197
+ ),
2198
+ onClick: onRowClick ? () => onRowClick(row.original) : void 0,
2199
+ children: [
2200
+ row.getVisibleCells().filter((cell) => cell.column.id !== "__select").map((cell) => {
2201
+ const header = cell.column.columnDef.header;
2202
+ const label = typeof header === "string" ? header : cell.column.id;
2203
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex items-baseline justify-between gap-2 text-xs", children: [
2204
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "text-foreground-muted shrink-0", children: label }),
2205
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "text-foreground text-right truncate", children: (0, import_react_table.flexRender)(cell.column.columnDef.cell, cell.getContext()) })
2206
+ ] }, cell.id);
2207
+ }),
2208
+ rowActions && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "flex items-center gap-1 pt-1 border-t border-border mt-1.5", children: rowActions(row.original).map((action, i) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
2209
+ "button",
2210
+ {
2211
+ onClick: (e) => {
2212
+ e.stopPropagation();
2213
+ action.onClick();
2214
+ },
2215
+ className: cn(
2216
+ "text-[11px] px-2 py-1 rounded-md transition-colors",
2217
+ action.variant === "danger" ? "text-danger hover:bg-danger/10" : "text-foreground-muted hover:bg-surface-hover"
2218
+ ),
2219
+ children: action.label
2220
+ },
2221
+ i
2222
+ )) })
2223
+ ]
2224
+ },
2225
+ row.id
2226
+ )),
2227
+ pagination && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
2228
+ DataTablePagination,
2229
+ {
2230
+ page: pagination.page,
2231
+ pageSize: pagination.pageSize,
2232
+ total: pagination.total,
2233
+ onPaginationChange
2234
+ }
2235
+ )
2236
+ ] });
2237
+ }
2238
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: cn("overflow-x-auto", className), children: [
2239
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("table", { className: "w-full border-collapse", children: [
2240
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
1926
2241
  DataTableHeader,
1927
2242
  {
1928
2243
  headerGroups: table.getHeaderGroups(),
@@ -1931,14 +2246,14 @@ function DataTable({
1931
2246
  flexRender: import_react_table.flexRender
1932
2247
  }
1933
2248
  ),
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)(
2249
+ /* @__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
2250
  "td",
1936
2251
  {
1937
2252
  colSpan: columns.length + (hasActions ? 1 : 0),
1938
2253
  className: "text-center py-8 text-xs text-foreground-muted",
1939
2254
  children: emptyState ?? "No data"
1940
2255
  }
1941
- ) }) : table.getRowModel().rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
2256
+ ) }) : table.getRowModel().rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
1942
2257
  DataTableRow,
1943
2258
  {
1944
2259
  row,
@@ -1949,7 +2264,7 @@ function DataTable({
1949
2264
  row.id
1950
2265
  )) })
1951
2266
  ] }),
1952
- pagination && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
2267
+ pagination && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
1953
2268
  DataTablePagination,
1954
2269
  {
1955
2270
  page: pagination.page,
@@ -1961,11 +2276,11 @@ function DataTable({
1961
2276
  ] });
1962
2277
  }
1963
2278
  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)) });
2279
+ 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
2280
  }
1966
2281
 
1967
2282
  // src/composites/device-card.tsx
1968
- var import_jsx_runtime38 = require("react/jsx-runtime");
2283
+ var import_jsx_runtime40 = require("react/jsx-runtime");
1969
2284
  var STATUS_COLORS = {
1970
2285
  online: "bg-success",
1971
2286
  offline: "bg-danger",
@@ -1984,7 +2299,7 @@ function DeviceCard({
1984
2299
  className
1985
2300
  }) {
1986
2301
  const isOffline = status === "offline";
1987
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
2302
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
1988
2303
  "div",
1989
2304
  {
1990
2305
  onClick,
@@ -1996,18 +2311,18 @@ function DeviceCard({
1996
2311
  className
1997
2312
  ),
1998
2313
  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]) })
2314
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex items-center justify-between mb-2", children: [
2315
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "text-sm font-medium truncate", children: title }),
2316
+ status && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: cn("h-2 w-2 rounded-full shrink-0", STATUS_COLORS[status]) })
2002
2317
  ] }),
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) => {
2318
+ subtitle && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "text-[11px] text-foreground-muted", children: subtitle }),
2319
+ 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
2320
  const cls = cn(
2006
2321
  "rounded px-1.5 py-0.5 text-[10px] flex items-center gap-0.5",
2007
2322
  selected ? "bg-primary/20" : "bg-surface-hover",
2008
2323
  badge.onClick && "hover:opacity-80 transition-opacity cursor-pointer"
2009
2324
  );
2010
- return badge.onClick ? /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
2325
+ return badge.onClick ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
2011
2326
  "button",
2012
2327
  {
2013
2328
  onClick: (e) => {
@@ -2021,12 +2336,12 @@ function DeviceCard({
2021
2336
  ]
2022
2337
  },
2023
2338
  i
2024
- ) : /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("span", { className: cls, children: [
2339
+ ) : /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("span", { className: cls, children: [
2025
2340
  badge.icon,
2026
2341
  badge.label
2027
2342
  ] }, i);
2028
2343
  }) }),
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)(
2344
+ !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
2345
  "button",
2031
2346
  {
2032
2347
  onClick: (e) => {
@@ -2040,21 +2355,21 @@ function DeviceCard({
2040
2355
  },
2041
2356
  i
2042
2357
  )) }),
2043
- isOffline && offlineAction && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "mt-2", onClick: (e) => e.stopPropagation(), children: offlineAction })
2358
+ isOffline && offlineAction && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "mt-2", onClick: (e) => e.stopPropagation(), children: offlineAction })
2044
2359
  ]
2045
2360
  }
2046
2361
  );
2047
2362
  }
2048
2363
 
2049
2364
  // src/composites/device-grid.tsx
2050
- var import_jsx_runtime39 = require("react/jsx-runtime");
2365
+ var import_jsx_runtime41 = require("react/jsx-runtime");
2051
2366
  function DeviceGrid({
2052
2367
  children,
2053
2368
  minCardWidth = 220,
2054
2369
  gap = 3,
2055
2370
  className
2056
2371
  }) {
2057
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
2372
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
2058
2373
  "div",
2059
2374
  {
2060
2375
  className: cn(
@@ -2072,9 +2387,9 @@ function DeviceGrid({
2072
2387
  }
2073
2388
 
2074
2389
  // 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");
2390
+ var import_react28 = require("react");
2391
+ var import_lucide_react13 = require("lucide-react");
2392
+ var import_jsx_runtime42 = require("react/jsx-runtime");
2078
2393
  var ADDON_COLORS = {
2079
2394
  "object-detection": "border-l-blue-500",
2080
2395
  "motion-detection": "border-l-amber-500",
@@ -2150,7 +2465,7 @@ function PipelineStep({
2150
2465
  onDelete,
2151
2466
  readOnly = false
2152
2467
  }) {
2153
- const [expanded, setExpanded] = (0, import_react23.useState)(false);
2468
+ const [expanded, setExpanded] = (0, import_react28.useState)(false);
2154
2469
  const color = borderColor(step.addonId, step.slot);
2155
2470
  const backends = backendsForRuntime(step.runtime, capabilities, schema);
2156
2471
  const rtOptions = runtimeOptions(capabilities);
@@ -2173,7 +2488,7 @@ function PipelineStep({
2173
2488
  if (e.target.closest(".step-config")) return;
2174
2489
  setExpanded((v) => !v);
2175
2490
  }
2176
- return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { className: "space-y-2", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
2491
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "space-y-2", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
2177
2492
  "div",
2178
2493
  {
2179
2494
  className: cn(
@@ -2182,18 +2497,18 @@ function PipelineStep({
2182
2497
  !step.enabled && "opacity-[0.45]"
2183
2498
  ),
2184
2499
  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))
2500
+ /* @__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: [
2501
+ /* @__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" }) }),
2502
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex-1 min-w-0", children: [
2503
+ /* @__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 }),
2504
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "text-sm font-semibold text-foreground truncate block leading-tight", children: step.addonName }),
2505
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex items-center gap-1 mt-0.5 flex-wrap", children: [
2506
+ 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)),
2507
+ step.inputClasses.length > 0 && step.outputClasses.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "text-foreground-subtle/40 text-[10px]", children: "\u2192" }),
2508
+ 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
2509
  ] })
2195
2510
  ] }),
2196
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
2511
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2197
2512
  "button",
2198
2513
  {
2199
2514
  onClick: (e) => {
@@ -2204,16 +2519,16 @@ function PipelineStep({
2204
2519
  "relative inline-flex h-6 w-11 shrink-0 items-center rounded-full transition-colors",
2205
2520
  step.enabled ? "bg-success" : "bg-foreground-subtle/30"
2206
2521
  ),
2207
- children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: cn(
2522
+ children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: cn(
2208
2523
  "inline-block h-4 w-4 rounded-full bg-white shadow transition-transform",
2209
2524
  step.enabled ? "translate-x-6" : "translate-x-1"
2210
2525
  ) })
2211
2526
  }
2212
2527
  )
2213
2528
  ] }),
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)(
2529
+ 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: [
2530
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "grid grid-cols-2 gap-3", children: [
2531
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2217
2532
  ConfigSelect,
2218
2533
  {
2219
2534
  label: "Agent",
@@ -2223,7 +2538,7 @@ function PipelineStep({
2223
2538
  onChange: (v) => onChange({ ...step, agentId: v })
2224
2539
  }
2225
2540
  ),
2226
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
2541
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2227
2542
  ConfigSelect,
2228
2543
  {
2229
2544
  label: "Runtime",
@@ -2233,7 +2548,7 @@ function PipelineStep({
2233
2548
  onChange: (v) => onChange({ ...step, runtime: v })
2234
2549
  }
2235
2550
  ),
2236
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
2551
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2237
2552
  ConfigSelect,
2238
2553
  {
2239
2554
  label: "Backend",
@@ -2243,7 +2558,7 @@ function PipelineStep({
2243
2558
  onChange: (v) => onChange({ ...step, backend: v })
2244
2559
  }
2245
2560
  ),
2246
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
2561
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2247
2562
  ConfigSelect,
2248
2563
  {
2249
2564
  label: "Model",
@@ -2254,15 +2569,15 @@ function PipelineStep({
2254
2569
  }
2255
2570
  )
2256
2571
  ] }),
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: [
2572
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { children: [
2573
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex items-center justify-between mb-1", children: [
2574
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "text-[10px] font-medium text-foreground-subtle uppercase tracking-wide", children: "Confidence" }),
2575
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: "text-xs font-medium text-foreground tabular-nums", children: [
2261
2576
  (step.confidence * 100).toFixed(0),
2262
2577
  "%"
2263
2578
  ] })
2264
2579
  ] }),
2265
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
2580
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2266
2581
  "input",
2267
2582
  {
2268
2583
  type: "range",
@@ -2282,9 +2597,9 @@ function PipelineStep({
2282
2597
  ) });
2283
2598
  }
2284
2599
  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)(
2600
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { children: [
2601
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("label", { className: "block text-[10px] font-medium text-foreground-subtle uppercase tracking-wide mb-1.5", children: label }),
2602
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
2288
2603
  "select",
2289
2604
  {
2290
2605
  value,
@@ -2292,8 +2607,8 @@ function ConfigSelect({ label, value, options, disabled, onChange }) {
2292
2607
  disabled,
2293
2608
  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
2609
  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))
2610
+ options.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value, children: value || "default" }),
2611
+ options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: o.value, disabled: o.disabled, children: o.label }, o.value))
2297
2612
  ]
2298
2613
  }
2299
2614
  )
@@ -2301,30 +2616,30 @@ function ConfigSelect({ label, value, options, disabled, onChange }) {
2301
2616
  }
2302
2617
 
2303
2618
  // src/composites/pipeline-runtime-selector.tsx
2304
- var import_lucide_react13 = require("lucide-react");
2305
- var import_jsx_runtime41 = require("react/jsx-runtime");
2619
+ var import_lucide_react14 = require("lucide-react");
2620
+ var import_jsx_runtime43 = require("react/jsx-runtime");
2306
2621
  function PipelineRuntimeSelector({ options, value, onChange }) {
2307
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "flex flex-wrap gap-2", children: options.map((opt) => {
2622
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "flex flex-wrap gap-2", children: options.map((opt) => {
2308
2623
  const active = opt.id === value;
2309
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
2624
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
2310
2625
  "button",
2311
2626
  {
2312
2627
  onClick: () => opt.available && onChange(opt.id),
2313
2628
  disabled: !opt.available,
2314
2629
  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
2630
  children: [
2316
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_lucide_react13.Cpu, { className: "h-3.5 w-3.5 shrink-0" }),
2631
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react14.Cpu, { className: "h-3.5 w-3.5 shrink-0" }),
2317
2632
  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" }),
2633
+ 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: [
2634
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react14.Star, { className: "h-2.5 w-2.5" }),
2320
2635
  "Best"
2321
2636
  ] }),
2322
- opt.platformScore != null && /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("span", { className: "text-[10px] text-foreground-subtle/60", children: [
2637
+ opt.platformScore != null && /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { className: "text-[10px] text-foreground-subtle/60", children: [
2323
2638
  "(",
2324
2639
  opt.platformScore,
2325
2640
  ")"
2326
2641
  ] }),
2327
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
2642
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
2328
2643
  "span",
2329
2644
  {
2330
2645
  className: `h-1.5 w-1.5 rounded-full ${opt.available ? "bg-success" : "bg-danger"}`
@@ -2338,8 +2653,8 @@ function PipelineRuntimeSelector({ options, value, onChange }) {
2338
2653
  }
2339
2654
 
2340
2655
  // src/composites/pipeline-builder.tsx
2341
- var import_react24 = require("react");
2342
- var import_lucide_react14 = require("lucide-react");
2656
+ var import_react29 = require("react");
2657
+ var import_lucide_react15 = require("lucide-react");
2343
2658
 
2344
2659
  // src/lib/validate-template.ts
2345
2660
  function validateTemplate(steps, schema) {
@@ -2371,7 +2686,7 @@ function validateTemplate(steps, schema) {
2371
2686
  }
2372
2687
 
2373
2688
  // src/composites/pipeline-builder.tsx
2374
- var import_jsx_runtime42 = require("react/jsx-runtime");
2689
+ var import_jsx_runtime44 = require("react/jsx-runtime");
2375
2690
  function buildSchemaMap(schema) {
2376
2691
  const map = /* @__PURE__ */ new Map();
2377
2692
  for (const slot of schema.slots) {
@@ -2400,20 +2715,20 @@ function createDefaultStep(addon, fallbackRuntime, fallbackBackend) {
2400
2715
  };
2401
2716
  }
2402
2717
  function PlaceholderStep({ addon, onClick }) {
2403
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2718
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
2404
2719
  "button",
2405
2720
  {
2406
2721
  type: "button",
2407
2722
  onClick,
2408
2723
  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))
2724
+ children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex items-center gap-3", children: [
2725
+ /* @__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" }),
2726
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex-1 min-w-0", children: [
2727
+ /* @__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 }),
2728
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex items-center gap-1 mt-0.5 flex-wrap", children: [
2729
+ 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)),
2730
+ addon.inputClasses.length > 0 && addon.outputClasses.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "text-foreground-subtle/25 text-[10px]", children: "\u2192" }),
2731
+ 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
2732
  ] })
2418
2733
  ] })
2419
2734
  ] })
@@ -2434,9 +2749,9 @@ function PipelineBuilder({
2434
2749
  readOnly = false,
2435
2750
  excludeAddons = []
2436
2751
  }) {
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)([]);
2752
+ const excluded = (0, import_react29.useMemo)(() => new Set(excludeAddons), [excludeAddons]);
2753
+ const schemaMap = (0, import_react29.useMemo)(() => buildSchemaMap(schema), [schema]);
2754
+ const [warnings, setWarnings] = (0, import_react29.useState)([]);
2440
2755
  const bestPlatformScore = capabilities.platformScores?.find((s) => s.available);
2441
2756
  const hasPython = capabilities.runtimes.python.available && capabilities.runtimes.python.backends.some((b) => b.available);
2442
2757
  const defaultRuntime = bestPlatformScore?.runtime ?? (hasPython ? "python" : "node");
@@ -2525,8 +2840,8 @@ function PipelineBuilder({
2525
2840
  }
2526
2841
  function renderStep(step) {
2527
2842
  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)(
2843
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "space-y-1.5", children: [
2844
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
2530
2845
  PipelineStep,
2531
2846
  {
2532
2847
  step,
@@ -2538,12 +2853,12 @@ function PipelineBuilder({
2538
2853
  readOnly
2539
2854
  }
2540
2855
  ),
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" }),
2856
+ (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: [
2857
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "text-[10px] font-semibold uppercase tracking-widest text-foreground-subtle/40", children: "Slot: Cropper / Classifier" }),
2543
2858
  step.children.map((child) => {
2544
2859
  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)(
2860
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "space-y-1.5", children: [
2861
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
2547
2862
  PipelineStep,
2548
2863
  {
2549
2864
  step: child,
@@ -2566,9 +2881,9 @@ function PipelineBuilder({
2566
2881
  readOnly
2567
2882
  }
2568
2883
  ),
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)(
2884
+ (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: [
2885
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "text-[10px] font-semibold uppercase tracking-widest text-foreground-subtle/30", children: "Slot: Recognizer" }),
2886
+ child.children.map((grandchild) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
2572
2887
  PipelineStep,
2573
2888
  {
2574
2889
  step: grandchild,
@@ -2596,7 +2911,7 @@ function PipelineBuilder({
2596
2911
  },
2597
2912
  grandchild.addonId
2598
2913
  )),
2599
- !readOnly && childChildPlaceholders.map((addon) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2914
+ !readOnly && childChildPlaceholders.map((addon) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
2600
2915
  PlaceholderStep,
2601
2916
  {
2602
2917
  addon,
@@ -2615,7 +2930,7 @@ function PipelineBuilder({
2615
2930
  ] })
2616
2931
  ] }, child.addonId);
2617
2932
  }),
2618
- !readOnly && childPlaceholders.map((addon) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2933
+ !readOnly && childPlaceholders.map((addon) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
2619
2934
  PlaceholderStep,
2620
2935
  {
2621
2936
  addon,
@@ -2627,22 +2942,22 @@ function PipelineBuilder({
2627
2942
  ] }, step.addonId);
2628
2943
  }
2629
2944
  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)(
2945
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "space-y-4", children: [
2946
+ /* @__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: [
2947
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "relative flex-1 min-w-0", children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
2633
2948
  "select",
2634
2949
  {
2635
2950
  value: selectedTemplateId ?? "",
2636
2951
  onChange: handleSelectTemplate,
2637
2952
  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
2953
  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))
2954
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("option", { value: "", children: "No template" }),
2955
+ templates.map((t) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("option", { value: t.id, children: t.name }, t.id))
2641
2956
  ]
2642
2957
  }
2643
2958
  ) }),
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)(
2959
+ dirty && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "h-1.5 w-1.5 rounded-full bg-amber-500 shrink-0" }),
2960
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
2646
2961
  "button",
2647
2962
  {
2648
2963
  onClick: handleSave,
@@ -2652,10 +2967,10 @@ function PipelineBuilder({
2652
2967
  "p-2 rounded-lg border border-border transition-colors",
2653
2968
  selectedTemplateId && !readOnly ? "text-foreground-subtle hover:bg-surface-hover" : "text-foreground-subtle/30 cursor-not-allowed"
2654
2969
  ),
2655
- children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_lucide_react14.Save, { className: "h-4 w-4" })
2970
+ children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_lucide_react15.Save, { className: "h-4 w-4" })
2656
2971
  }
2657
2972
  ),
2658
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2973
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
2659
2974
  "button",
2660
2975
  {
2661
2976
  onClick: handleSaveAs,
@@ -2665,10 +2980,10 @@ function PipelineBuilder({
2665
2980
  "p-2 rounded-lg border border-border transition-colors",
2666
2981
  !readOnly ? "text-foreground-subtle hover:bg-surface-hover" : "text-foreground-subtle/30 cursor-not-allowed"
2667
2982
  ),
2668
- children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_lucide_react14.CopyPlus, { className: "h-4 w-4" })
2983
+ children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_lucide_react15.CopyPlus, { className: "h-4 w-4" })
2669
2984
  }
2670
2985
  ),
2671
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
2986
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
2672
2987
  "button",
2673
2988
  {
2674
2989
  onClick: handleDelete,
@@ -2678,16 +2993,16 @@ function PipelineBuilder({
2678
2993
  "p-2 rounded-lg border border-border transition-colors",
2679
2994
  selectedTemplateId && !readOnly ? "text-foreground-subtle hover:text-danger" : "text-foreground-subtle/30 cursor-not-allowed"
2680
2995
  ),
2681
- children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_lucide_react14.Trash2, { className: "h-4 w-4" })
2996
+ children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_lucide_react15.Trash2, { className: "h-4 w-4" })
2682
2997
  }
2683
2998
  )
2684
2999
  ] }) }),
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" }) })
3000
+ 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: [
3001
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex items-center justify-between", children: [
3002
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "font-medium", children: "Template loaded with warnings:" }),
3003
+ /* @__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
3004
  ] }),
2690
- warnings.map((w, i) => /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { children: [
3005
+ warnings.map((w, i) => /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { children: [
2691
3006
  "\u2022 ",
2692
3007
  w
2693
3008
  ] }, i))
@@ -2695,13 +3010,13 @@ function PipelineBuilder({
2695
3010
  rootSlots.map((slot) => {
2696
3011
  const slotSteps = steps.filter((s) => s.slot === slot.id && !excluded.has(s.addonId));
2697
3012
  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: [
3013
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "space-y-2", children: [
3014
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: "text-[10px] font-semibold uppercase tracking-widest text-foreground-subtle/50", children: [
2700
3015
  "Slot: ",
2701
3016
  slot.label
2702
3017
  ] }),
2703
3018
  slotSteps.map((step) => renderStep(step)),
2704
- !readOnly && missingRootAddons.map((addon) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(PlaceholderStep, { addon, onClick: () => {
3019
+ !readOnly && missingRootAddons.map((addon) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(PlaceholderStep, { addon, onClick: () => {
2705
3020
  onChange([...steps, createDefaultStep(addon, defaultRuntime, defaultBackend)]);
2706
3021
  } }, addon.id))
2707
3022
  ] }, slot.id);
@@ -2781,8 +3096,8 @@ function getClassColor(className, customColors) {
2781
3096
  }
2782
3097
 
2783
3098
  // src/composites/detection-canvas.tsx
2784
- var import_react25 = require("react");
2785
- var import_jsx_runtime43 = require("react/jsx-runtime");
3099
+ var import_react30 = require("react");
3100
+ var import_jsx_runtime45 = require("react/jsx-runtime");
2786
3101
  var DEFAULT_CLASS_COLORS = CLASS_COLORS;
2787
3102
  function DetectionCanvas({
2788
3103
  src,
@@ -2802,7 +3117,7 @@ function DetectionCanvas({
2802
3117
  }
2803
3118
  const ratio = aspectRatio ?? (imageWidth && imageHeight ? `${imageWidth}/${imageHeight}` : "16/9");
2804
3119
  const filteredDetections = detections.filter((d) => d.confidence >= minConfidence);
2805
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
3120
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
2806
3121
  "div",
2807
3122
  {
2808
3123
  className: cn(
@@ -2810,10 +3125,10 @@ function DetectionCanvas({
2810
3125
  className
2811
3126
  ),
2812
3127
  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: "" }),
3128
+ children: src ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_jsx_runtime45.Fragment, { children: [
3129
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("img", { src, className: "absolute inset-0 w-full h-full object-fill", alt: "" }),
2815
3130
  filteredDetections.map(
2816
- (d, i) => d.mask && d.maskWidth && d.maskHeight ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
3131
+ (d, i) => d.mask && d.maskWidth && d.maskHeight ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
2817
3132
  MaskOverlay,
2818
3133
  {
2819
3134
  mask: d.mask,
@@ -2827,7 +3142,7 @@ function DetectionCanvas({
2827
3142
  `mask-${i}`
2828
3143
  ) : null
2829
3144
  ),
2830
- filteredDetections.map((d, i) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
3145
+ filteredDetections.map((d, i) => /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
2831
3146
  BoundingBox,
2832
3147
  {
2833
3148
  detection: d,
@@ -2847,7 +3162,7 @@ function DetectionCanvas({
2847
3162
  const ph = py2 - py1;
2848
3163
  if (pw > 0 && ph > 0 && cw * ch / (pw * ph) > 0.8) return false;
2849
3164
  return true;
2850
- }).map((child, j) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
3165
+ }).map((child, j) => /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
2851
3166
  ChildBoundingBox,
2852
3167
  {
2853
3168
  child,
@@ -2860,7 +3175,7 @@ function DetectionCanvas({
2860
3175
  },
2861
3176
  `det-${i}`
2862
3177
  ))
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" })
3178
+ ] }) : /* @__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
3179
  }
2865
3180
  );
2866
3181
  }
@@ -2877,15 +3192,15 @@ function BoundingBox({
2877
3192
  const labelCount = 1 + (detection.labelsData?.length ?? 0);
2878
3193
  const labelHeightPx = labelCount * 16 + 4;
2879
3194
  const topPct = y1 / imageHeight * 100;
2880
- const containerRef = (0, import_react25.useRef)(null);
3195
+ const containerRef = (0, import_react30.useRef)(null);
2881
3196
  const showBelow = topPct < labelHeightPx / imageHeight * 100 * 1.5;
2882
- const labelsElement = /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
3197
+ const labelsElement = /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
2883
3198
  "div",
2884
3199
  {
2885
3200
  className: `absolute left-0 flex flex-col items-start gap-px ${showBelow ? "" : ""}`,
2886
3201
  style: showBelow ? { top: "100%", marginTop: "2px" } : { bottom: "100%", marginBottom: "2px" },
2887
3202
  children: [
2888
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
3203
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
2889
3204
  "span",
2890
3205
  {
2891
3206
  className: "text-[10px] px-1 rounded-sm whitespace-nowrap text-white",
@@ -2896,7 +3211,7 @@ function BoundingBox({
2896
3211
  ]
2897
3212
  }
2898
3213
  ),
2899
- detection.labelsData?.map((l, k) => /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
3214
+ detection.labelsData?.map((l, k) => /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
2900
3215
  "span",
2901
3216
  {
2902
3217
  className: "text-[9px] font-semibold px-1 rounded-sm whitespace-nowrap text-white",
@@ -2913,7 +3228,7 @@ function BoundingBox({
2913
3228
  ]
2914
3229
  }
2915
3230
  );
2916
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
3231
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
2917
3232
  "div",
2918
3233
  {
2919
3234
  ref: containerRef,
@@ -2943,8 +3258,8 @@ function MaskOverlay({
2943
3258
  imageHeight,
2944
3259
  color
2945
3260
  }) {
2946
- const canvasRef = (0, import_react25.useRef)(null);
2947
- (0, import_react25.useEffect)(() => {
3261
+ const canvasRef = (0, import_react30.useRef)(null);
3262
+ (0, import_react30.useEffect)(() => {
2948
3263
  const canvas = canvasRef.current;
2949
3264
  if (!canvas) return;
2950
3265
  const ctx = canvas.getContext("2d");
@@ -2972,7 +3287,7 @@ function MaskOverlay({
2972
3287
  ctx.putImageData(imageData, 0, 0);
2973
3288
  }, [mask, maskWidth, maskHeight, color]);
2974
3289
  const [x1, y1, x2, y2] = bbox;
2975
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
3290
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
2976
3291
  "canvas",
2977
3292
  {
2978
3293
  ref: canvasRef,
@@ -2998,7 +3313,7 @@ function ChildBoundingBox({
2998
3313
  const pw = px2 - px1;
2999
3314
  const ph = py2 - py1;
3000
3315
  if (pw <= 0 || ph <= 0) return null;
3001
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
3316
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
3002
3317
  "div",
3003
3318
  {
3004
3319
  className: "absolute rounded-sm",
@@ -3015,13 +3330,13 @@ function ChildBoundingBox({
3015
3330
  const labelCount = 1 + (child.labelsData?.length ?? 0);
3016
3331
  const relTop = (cy1 - py1) / ph * 100;
3017
3332
  const showBelow = relTop < labelCount * 6;
3018
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
3333
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
3019
3334
  "div",
3020
3335
  {
3021
3336
  className: "absolute left-0 flex flex-col items-start gap-px",
3022
3337
  style: showBelow ? { top: "100%", marginTop: "1px" } : { bottom: "100%", marginBottom: "1px" },
3023
3338
  children: [
3024
- /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
3339
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
3025
3340
  "span",
3026
3341
  {
3027
3342
  className: "text-[9px] px-0.5 rounded-sm whitespace-nowrap text-white",
@@ -3032,7 +3347,7 @@ function ChildBoundingBox({
3032
3347
  ]
3033
3348
  }
3034
3349
  ),
3035
- child.labelsData?.map((l, k) => /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
3350
+ child.labelsData?.map((l, k) => /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
3036
3351
  "span",
3037
3352
  {
3038
3353
  className: "text-[8px] font-semibold px-0.5 rounded-sm whitespace-nowrap text-white",
@@ -3055,7 +3370,7 @@ function ChildBoundingBox({
3055
3370
  }
3056
3371
 
3057
3372
  // src/composites/detection-result-tree.tsx
3058
- var import_jsx_runtime44 = require("react/jsx-runtime");
3373
+ var import_jsx_runtime46 = require("react/jsx-runtime");
3059
3374
  function DetectionResultTree({
3060
3375
  detections,
3061
3376
  classColors,
@@ -3065,15 +3380,15 @@ function DetectionResultTree({
3065
3380
  }) {
3066
3381
  const colors = classColors;
3067
3382
  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" });
3383
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "text-sm text-foreground-subtle italic text-center py-4", children: "No detections" });
3069
3384
  }
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: [
3385
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className, children: [
3386
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "text-xs font-medium text-foreground-subtle uppercase tracking-wide mb-2", children: [
3072
3387
  "Detections (",
3073
3388
  detections.length,
3074
3389
  ")"
3075
3390
  ] }),
3076
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("div", { className: "space-y-2", children: detections.map((d, i) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
3391
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "space-y-2", children: detections.map((d, i) => /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
3077
3392
  DetectionNode,
3078
3393
  {
3079
3394
  detection: d,
@@ -3095,10 +3410,10 @@ function DetectionNode({
3095
3410
  }) {
3096
3411
  const color = getClassColor(detection.className, colors);
3097
3412
  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)(
3413
+ 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: [
3414
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex justify-between items-center", children: [
3415
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex items-center gap-2", children: [
3416
+ onToggleVisibility && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
3102
3417
  "input",
3103
3418
  {
3104
3419
  type: "checkbox",
@@ -3107,45 +3422,45 @@ function DetectionNode({
3107
3422
  className: "h-3.5 w-3.5 rounded border-border accent-primary cursor-pointer shrink-0"
3108
3423
  }
3109
3424
  ),
3110
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
3425
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
3111
3426
  "span",
3112
3427
  {
3113
3428
  className: "h-2.5 w-2.5 rounded-full shrink-0",
3114
3429
  style: { backgroundColor: color }
3115
3430
  }
3116
3431
  ),
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: [
3432
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "text-sm font-medium text-foreground", children: detection.className }),
3433
+ 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
3434
  "mask ",
3120
3435
  detection.maskWidth,
3121
3436
  "x",
3122
3437
  detection.maskHeight
3123
3438
  ] })
3124
3439
  ] }),
3125
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ConfidenceBadge, { confidence: detection.confidence })
3440
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ConfidenceBadge, { confidence: detection.confidence })
3126
3441
  ] }),
3127
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "text-[10px] text-foreground-subtle font-mono", children: [
3442
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "text-[10px] text-foreground-subtle font-mono", children: [
3128
3443
  "bbox: [",
3129
3444
  detection.bbox.map((v) => Math.round(v)).join(", "),
3130
3445
  "]"
3131
3446
  ] }),
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)(
3447
+ 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
3448
  "span",
3134
3449
  {
3135
3450
  className: "inline-flex items-center gap-1 text-[10px] font-medium px-1.5 py-0.5 rounded-full",
3136
3451
  style: { backgroundColor: getClassColor(l.addonId ?? l.label, colors) + "20", color: getClassColor(l.addonId ?? l.label, colors) },
3137
3452
  children: [
3138
3453
  l.label,
3139
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: "opacity-60", children: [
3454
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("span", { className: "opacity-60", children: [
3140
3455
  (l.score * 100).toFixed(0),
3141
3456
  "%"
3142
3457
  ] }),
3143
- l.addonId && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { className: "opacity-40 text-[8px]", children: l.addonId })
3458
+ l.addonId && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "opacity-40 text-[8px]", children: l.addonId })
3144
3459
  ]
3145
3460
  },
3146
3461
  k
3147
3462
  )) }),
3148
- detection.children && detection.children.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
3463
+ detection.children && detection.children.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
3149
3464
  ChildrenTree,
3150
3465
  {
3151
3466
  children: detection.children,
@@ -3164,13 +3479,13 @@ function ChildrenTree({
3164
3479
  hiddenKeys,
3165
3480
  onToggleVisibility
3166
3481
  }) {
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) => {
3482
+ 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
3483
  const childPath = `${parentPath}.${j}`;
3169
3484
  const childColor = getClassColor(child.className, colors);
3170
3485
  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)(
3486
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: `text-xs space-y-0.5 ${isVisible ? "" : "opacity-40"}`, children: [
3487
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "flex items-center gap-1.5", children: [
3488
+ onToggleVisibility && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
3174
3489
  "input",
3175
3490
  {
3176
3491
  type: "checkbox",
@@ -3179,26 +3494,26 @@ function ChildrenTree({
3179
3494
  className: "h-3 w-3 rounded border-border accent-primary cursor-pointer shrink-0"
3180
3495
  }
3181
3496
  ),
3182
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
3497
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
3183
3498
  "span",
3184
3499
  {
3185
3500
  className: "h-1.5 w-1.5 rounded-full shrink-0",
3186
3501
  style: { backgroundColor: childColor }
3187
3502
  }
3188
3503
  ),
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: [
3504
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "font-medium", style: { color: childColor }, children: child.className }),
3505
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("span", { className: "text-foreground-subtle", children: [
3191
3506
  (child.confidence * 100).toFixed(0),
3192
3507
  "%"
3193
3508
  ] }),
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: [
3509
+ 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
3510
  "mask ",
3196
3511
  child.maskWidth,
3197
3512
  "x",
3198
3513
  child.maskHeight
3199
3514
  ] })
3200
3515
  ] }),
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)(
3516
+ 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
3517
  "span",
3203
3518
  {
3204
3519
  className: "inline-flex items-center gap-0.5 text-[9px] font-medium px-1 py-0.5 rounded-full",
@@ -3206,7 +3521,7 @@ function ChildrenTree({
3206
3521
  children: [
3207
3522
  l.label,
3208
3523
  " ",
3209
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("span", { className: "opacity-60", children: [
3524
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("span", { className: "opacity-60", children: [
3210
3525
  (l.score * 100).toFixed(0),
3211
3526
  "%"
3212
3527
  ] })
@@ -3214,7 +3529,7 @@ function ChildrenTree({
3214
3529
  },
3215
3530
  k
3216
3531
  )) }),
3217
- child.children && child.children.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
3532
+ child.children && child.children.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
3218
3533
  ChildrenTree,
3219
3534
  {
3220
3535
  children: child.children,
@@ -3229,30 +3544,30 @@ function ChildrenTree({
3229
3544
  }
3230
3545
  function ConfidenceBadge({ confidence }) {
3231
3546
  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: [
3547
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("span", { className: `text-xs font-medium px-2 py-0.5 rounded-full ${level}`, children: [
3233
3548
  (confidence * 100).toFixed(1),
3234
3549
  "%"
3235
3550
  ] });
3236
3551
  }
3237
3552
 
3238
3553
  // src/composites/step-timings.tsx
3239
- var import_jsx_runtime45 = require("react/jsx-runtime");
3554
+ var import_jsx_runtime47 = require("react/jsx-runtime");
3240
3555
  function StepTimings({ timings, totalMs, className }) {
3241
3556
  const entries = Object.entries(timings);
3242
3557
  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: [
3558
+ return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: `rounded-lg border border-border bg-surface p-3 space-y-2 ${className ?? ""}`, children: [
3559
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "text-xs font-medium text-foreground-subtle uppercase tracking-wide", children: "Timings" }),
3560
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "space-y-1 text-xs", children: [
3561
+ entries.map(([step, ms]) => /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "flex justify-between", children: [
3562
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "text-foreground-subtle", children: step }),
3563
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "font-mono text-foreground", children: [
3249
3564
  ms.toFixed(1),
3250
3565
  "ms"
3251
3566
  ] })
3252
3567
  ] }, 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: [
3568
+ 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: [
3569
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { children: "Total" }),
3570
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("span", { className: "font-mono", children: [
3256
3571
  totalMs.toFixed(1),
3257
3572
  "ms"
3258
3573
  ] })
@@ -3262,7 +3577,7 @@ function StepTimings({ timings, totalMs, className }) {
3262
3577
  }
3263
3578
 
3264
3579
  // src/composites/image-selector.tsx
3265
- var import_jsx_runtime46 = require("react/jsx-runtime");
3580
+ var import_jsx_runtime48 = require("react/jsx-runtime");
3266
3581
  function ImageSelector({
3267
3582
  images,
3268
3583
  selectedFilename,
@@ -3288,8 +3603,8 @@ function ImageSelector({
3288
3603
  };
3289
3604
  input.click();
3290
3605
  };
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)(
3606
+ return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: `flex flex-wrap items-center gap-2 ${className ?? ""}`, children: [
3607
+ images.map((img) => /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
3293
3608
  "button",
3294
3609
  {
3295
3610
  onClick: () => onSelect(img.filename),
@@ -3298,7 +3613,7 @@ function ImageSelector({
3298
3613
  },
3299
3614
  img.filename
3300
3615
  )),
3301
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
3616
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
3302
3617
  "button",
3303
3618
  {
3304
3619
  onClick: handleUploadClick,
@@ -3306,12 +3621,12 @@ function ImageSelector({
3306
3621
  children: "Upload..."
3307
3622
  }
3308
3623
  ),
3309
- uploadedName && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "text-xs text-foreground-subtle", children: uploadedName })
3624
+ uploadedName && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "text-xs text-foreground-subtle", children: uploadedName })
3310
3625
  ] });
3311
3626
  }
3312
3627
 
3313
3628
  // src/composites/inference-config-selector.tsx
3314
- var import_jsx_runtime47 = require("react/jsx-runtime");
3629
+ var import_jsx_runtime49 = require("react/jsx-runtime");
3315
3630
  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
3631
  function InferenceConfigSelector({
3317
3632
  runtime,
@@ -3331,16 +3646,16 @@ function InferenceConfigSelector({
3331
3646
  showAgent = false
3332
3647
  }) {
3333
3648
  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)(
3649
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: `${containerClass} ${className ?? ""}`, children: [
3650
+ showAgent && agents.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("label", { className: "space-y-1", children: [
3651
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "text-xs font-medium text-foreground-subtle", children: "Agent" }),
3652
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
3338
3653
  "select",
3339
3654
  {
3340
3655
  value: agentId,
3341
3656
  onChange: (e) => onAgentChange?.(e.target.value),
3342
3657
  className: SELECT_CLASS,
3343
- children: agents.map((a) => /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("option", { value: a.id, children: [
3658
+ children: agents.map((a) => /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("option", { value: a.id, children: [
3344
3659
  a.name,
3345
3660
  " (",
3346
3661
  a.status,
@@ -3349,45 +3664,45 @@ function InferenceConfigSelector({
3349
3664
  }
3350
3665
  )
3351
3666
  ] }),
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)(
3667
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("label", { className: "space-y-1", children: [
3668
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "text-xs font-medium text-foreground-subtle", children: "Runtime" }),
3669
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
3355
3670
  "select",
3356
3671
  {
3357
3672
  value: runtime,
3358
3673
  onChange: (e) => onRuntimeChange(e.target.value),
3359
3674
  className: SELECT_CLASS,
3360
- children: runtimes.map((r) => /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("option", { value: r.value, disabled: !r.available, children: [
3675
+ children: runtimes.map((r) => /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("option", { value: r.value, disabled: !r.available, children: [
3361
3676
  r.label,
3362
3677
  !r.available ? " (unavailable)" : ""
3363
3678
  ] }, r.value))
3364
3679
  }
3365
3680
  )
3366
3681
  ] }),
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)(
3682
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("label", { className: "space-y-1", children: [
3683
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "text-xs font-medium text-foreground-subtle", children: "Backend" }),
3684
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
3370
3685
  "select",
3371
3686
  {
3372
3687
  value: backend,
3373
3688
  onChange: (e) => onBackendChange(e.target.value),
3374
3689
  className: SELECT_CLASS,
3375
- children: backends.map((b) => /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("option", { value: b.id, disabled: !b.available, children: [
3690
+ children: backends.map((b) => /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("option", { value: b.id, disabled: !b.available, children: [
3376
3691
  b.label,
3377
3692
  !b.available ? " (unavailable)" : ""
3378
3693
  ] }, b.id))
3379
3694
  }
3380
3695
  )
3381
3696
  ] }),
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)(
3697
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("label", { className: "space-y-1", children: [
3698
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "text-xs font-medium text-foreground-subtle", children: "Model" }),
3699
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
3385
3700
  "select",
3386
3701
  {
3387
3702
  value: modelId,
3388
3703
  onChange: (e) => onModelChange(e.target.value),
3389
3704
  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: [
3705
+ 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
3706
  m.name,
3392
3707
  m.downloaded ? " \u2713" : ""
3393
3708
  ] }, m.id))
@@ -3398,19 +3713,19 @@ function InferenceConfigSelector({
3398
3713
  }
3399
3714
 
3400
3715
  // src/composites/mount-addon-page.tsx
3401
- var import_react28 = require("react");
3716
+ var import_react33 = require("react");
3402
3717
  var import_client2 = require("react-dom/client");
3403
3718
 
3404
3719
  // src/composites/dev-shell.tsx
3405
- var import_react27 = require("react");
3720
+ var import_react32 = require("react");
3406
3721
  var import_client = require("@trpc/client");
3407
3722
  var import_superjson = __toESM(require("superjson"), 1);
3408
3723
 
3409
3724
  // src/composites/login-form.tsx
3410
- var import_react26 = require("react");
3411
- var import_jsx_runtime48 = require("react/jsx-runtime");
3725
+ var import_react31 = require("react");
3726
+ var import_jsx_runtime50 = require("react/jsx-runtime");
3412
3727
  function EyeIcon({ className }) {
3413
- return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
3728
+ return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
3414
3729
  "svg",
3415
3730
  {
3416
3731
  xmlns: "http://www.w3.org/2000/svg",
@@ -3422,14 +3737,14 @@ function EyeIcon({ className }) {
3422
3737
  strokeLinejoin: "round",
3423
3738
  className,
3424
3739
  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" })
3740
+ /* @__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" }),
3741
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("circle", { cx: "12", cy: "12", r: "3" })
3427
3742
  ]
3428
3743
  }
3429
3744
  );
3430
3745
  }
3431
3746
  function EyeOffIcon({ className }) {
3432
- return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
3747
+ return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
3433
3748
  "svg",
3434
3749
  {
3435
3750
  xmlns: "http://www.w3.org/2000/svg",
@@ -3441,16 +3756,16 @@ function EyeOffIcon({ className }) {
3441
3756
  strokeLinejoin: "round",
3442
3757
  className,
3443
3758
  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" })
3759
+ /* @__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" }),
3760
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("path", { d: "M14.084 14.158a3 3 0 0 1-4.242-4.242" }),
3761
+ /* @__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" }),
3762
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("path", { d: "m2 2 20 20" })
3448
3763
  ]
3449
3764
  }
3450
3765
  );
3451
3766
  }
3452
3767
  function SpinnerIcon({ className }) {
3453
- return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
3768
+ return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
3454
3769
  "svg",
3455
3770
  {
3456
3771
  xmlns: "http://www.w3.org/2000/svg",
@@ -3461,7 +3776,7 @@ function SpinnerIcon({ className }) {
3461
3776
  strokeLinecap: "round",
3462
3777
  strokeLinejoin: "round",
3463
3778
  className,
3464
- children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" })
3779
+ children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" })
3465
3780
  }
3466
3781
  );
3467
3782
  }
@@ -3472,11 +3787,11 @@ function LoginForm({
3472
3787
  error: externalError,
3473
3788
  className
3474
3789
  }) {
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);
3790
+ const [username, setUsername] = (0, import_react31.useState)("");
3791
+ const [password, setPassword] = (0, import_react31.useState)("");
3792
+ const [showPassword, setShowPassword] = (0, import_react31.useState)(false);
3793
+ const [submitting, setSubmitting] = (0, import_react31.useState)(false);
3794
+ const [internalError, setInternalError] = (0, import_react31.useState)(null);
3480
3795
  const error = externalError ?? internalError;
3481
3796
  const handleSubmit = async (e) => {
3482
3797
  e.preventDefault();
@@ -3492,26 +3807,26 @@ function LoginForm({
3492
3807
  setSubmitting(false);
3493
3808
  }
3494
3809
  };
3495
- return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
3810
+ return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
3496
3811
  "div",
3497
3812
  {
3498
3813
  className: cn(
3499
3814
  "flex min-h-screen items-center justify-center bg-background p-4",
3500
3815
  className
3501
3816
  ),
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)(
3817
+ children: /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "w-full max-w-sm", children: [
3818
+ 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" }) }),
3819
+ serverUrl && /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("p", { className: "mb-4 text-center text-xs text-foreground-subtle truncate", children: serverUrl }),
3820
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
3506
3821
  "form",
3507
3822
  {
3508
3823
  onSubmit: handleSubmit,
3509
3824
  className: "space-y-4 rounded-xl border border-border bg-surface p-6 shadow-xl shadow-black/10",
3510
3825
  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)(
3826
+ 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 }),
3827
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "space-y-1.5", children: [
3828
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("label", { className: "text-xs font-medium text-foreground-subtle", children: "Username" }),
3829
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
3515
3830
  "input",
3516
3831
  {
3517
3832
  type: "text",
@@ -3523,10 +3838,10 @@ function LoginForm({
3523
3838
  }
3524
3839
  )
3525
3840
  ] }),
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)(
3841
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "space-y-1.5", children: [
3842
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("label", { className: "text-xs font-medium text-foreground-subtle", children: "Password" }),
3843
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "relative", children: [
3844
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
3530
3845
  "input",
3531
3846
  {
3532
3847
  type: showPassword ? "text" : "password",
@@ -3537,26 +3852,26 @@ function LoginForm({
3537
3852
  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
3853
  }
3539
3854
  ),
3540
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
3855
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
3541
3856
  "button",
3542
3857
  {
3543
3858
  type: "button",
3544
3859
  onClick: () => setShowPassword((prev) => !prev),
3545
3860
  className: "absolute right-2.5 top-1/2 -translate-y-1/2 text-foreground-subtle hover:text-foreground",
3546
3861
  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" })
3862
+ 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
3863
  }
3549
3864
  )
3550
3865
  ] })
3551
3866
  ] }),
3552
- /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
3867
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
3553
3868
  "button",
3554
3869
  {
3555
3870
  type: "submit",
3556
3871
  disabled: submitting,
3557
3872
  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
3873
  children: [
3559
- submitting && /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(SpinnerIcon, { className: "h-4 w-4 animate-spin" }),
3874
+ submitting && /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(SpinnerIcon, { className: "h-4 w-4 animate-spin" }),
3560
3875
  submitting ? "Logging in..." : "Log in"
3561
3876
  ]
3562
3877
  }
@@ -3570,11 +3885,11 @@ function LoginForm({
3570
3885
  }
3571
3886
 
3572
3887
  // src/composites/dev-shell.tsx
3573
- var import_jsx_runtime49 = require("react/jsx-runtime");
3888
+ var import_jsx_runtime51 = require("react/jsx-runtime");
3574
3889
  var STORAGE_KEY = "camstack_dev_token";
3575
- var DevShellContext = (0, import_react27.createContext)(null);
3890
+ var DevShellContext = (0, import_react32.createContext)(null);
3576
3891
  function useDevShell() {
3577
- const ctx = (0, import_react27.useContext)(DevShellContext);
3892
+ const ctx = (0, import_react32.useContext)(DevShellContext);
3578
3893
  if (!ctx) {
3579
3894
  throw new Error("useDevShell must be used within a DevShell");
3580
3895
  }
@@ -3585,7 +3900,7 @@ function getStoredToken() {
3585
3900
  return localStorage.getItem(STORAGE_KEY);
3586
3901
  }
3587
3902
  function SunIcon({ className }) {
3588
- return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
3903
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(
3589
3904
  "svg",
3590
3905
  {
3591
3906
  xmlns: "http://www.w3.org/2000/svg",
@@ -3597,21 +3912,21 @@ function SunIcon({ className }) {
3597
3912
  strokeLinejoin: "round",
3598
3913
  className,
3599
3914
  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" })
3915
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("circle", { cx: "12", cy: "12", r: "4" }),
3916
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("path", { d: "M12 2v2" }),
3917
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("path", { d: "M12 20v2" }),
3918
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("path", { d: "m4.93 4.93 1.41 1.41" }),
3919
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("path", { d: "m17.66 17.66 1.41 1.41" }),
3920
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("path", { d: "M2 12h2" }),
3921
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("path", { d: "M20 12h2" }),
3922
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("path", { d: "m6.34 17.66-1.41 1.41" }),
3923
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("path", { d: "m19.07 4.93-1.41 1.41" })
3609
3924
  ]
3610
3925
  }
3611
3926
  );
3612
3927
  }
3613
3928
  function MoonIcon({ className }) {
3614
- return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
3929
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
3615
3930
  "svg",
3616
3931
  {
3617
3932
  xmlns: "http://www.w3.org/2000/svg",
@@ -3622,7 +3937,7 @@ function MoonIcon({ className }) {
3622
3937
  strokeLinecap: "round",
3623
3938
  strokeLinejoin: "round",
3624
3939
  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" })
3940
+ 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
3941
  }
3627
3942
  );
3628
3943
  }
@@ -3634,7 +3949,7 @@ function DevShellInner({
3634
3949
  onLogout
3635
3950
  }) {
3636
3951
  const theme = useThemeMode();
3637
- const trpc = (0, import_react27.useMemo)(
3952
+ const trpc = (0, import_react32.useMemo)(
3638
3953
  () => {
3639
3954
  const wsUrl = serverUrl.replace(/^http/, "ws") + "/trpc";
3640
3955
  const wsClient = (0, import_client.createWSClient)({
@@ -3657,19 +3972,19 @@ function DevShellInner({
3657
3972
  },
3658
3973
  [serverUrl, token]
3659
3974
  );
3660
- const contextValue = (0, import_react27.useMemo)(
3975
+ const contextValue = (0, import_react32.useMemo)(
3661
3976
  () => ({ trpc, token, logout: onLogout }),
3662
3977
  [trpc, token, onLogout]
3663
3978
  );
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 })
3979
+ 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: [
3980
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "flex items-center justify-between border-b border-border bg-surface px-4 py-2", children: [
3981
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "flex items-center gap-2", children: [
3982
+ /* @__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" }),
3983
+ title && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "text-sm font-medium text-foreground", children: title }),
3984
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "text-xs text-foreground-subtle", children: serverUrl })
3670
3985
  ] }),
3671
- /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "flex items-center gap-2", children: [
3672
- /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
3986
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: "flex items-center gap-2", children: [
3987
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(
3673
3988
  "button",
3674
3989
  {
3675
3990
  type: "button",
@@ -3677,12 +3992,12 @@ function DevShellInner({
3677
3992
  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
3993
  title: `Theme: ${theme.mode}`,
3679
3994
  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" }),
3995
+ 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
3996
  theme.mode === "dark" ? "Dark" : theme.mode === "light" ? "Light" : "System"
3682
3997
  ]
3683
3998
  }
3684
3999
  ),
3685
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
4000
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
3686
4001
  "button",
3687
4002
  {
3688
4003
  type: "button",
@@ -3693,7 +4008,7 @@ function DevShellInner({
3693
4008
  )
3694
4009
  ] })
3695
4010
  ] }),
3696
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "p-4", children: children({ trpc, theme }) })
4011
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "p-4", children: children({ trpc, theme }) })
3697
4012
  ] }) });
3698
4013
  }
3699
4014
  function DevShell({
@@ -3701,8 +4016,8 @@ function DevShell({
3701
4016
  serverUrl = "https://localhost:4443",
3702
4017
  title
3703
4018
  }) {
3704
- const [token, setToken] = (0, import_react27.useState)(getStoredToken);
3705
- const handleLogin = (0, import_react27.useCallback)(
4019
+ const [token, setToken] = (0, import_react32.useState)(getStoredToken);
4020
+ const handleLogin = (0, import_react32.useCallback)(
3706
4021
  async (username, password) => {
3707
4022
  const anonClient = (0, import_client.createTRPCClient)({
3708
4023
  links: [
@@ -3719,14 +4034,14 @@ function DevShell({
3719
4034
  },
3720
4035
  [serverUrl]
3721
4036
  );
3722
- const handleLogout = (0, import_react27.useCallback)(() => {
4037
+ const handleLogout = (0, import_react32.useCallback)(() => {
3723
4038
  localStorage.removeItem(STORAGE_KEY);
3724
4039
  setToken(null);
3725
4040
  }, []);
3726
4041
  if (!token) {
3727
- return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(ThemeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(LoginForm, { onLogin: handleLogin, serverUrl }) });
4042
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ThemeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(LoginForm, { onLogin: handleLogin, serverUrl }) });
3728
4043
  }
3729
- return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(ThemeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
4044
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(ThemeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
3730
4045
  DevShellInner,
3731
4046
  {
3732
4047
  serverUrl,
@@ -3751,10 +4066,10 @@ function mountAddonPage(PageComponent, options = {}) {
3751
4066
  return;
3752
4067
  }
3753
4068
  (0, import_client2.createRoot)(root).render(
3754
- (0, import_react28.createElement)(DevShell, {
4069
+ (0, import_react33.createElement)(DevShell, {
3755
4070
  serverUrl,
3756
4071
  title,
3757
- children: ({ trpc, theme }) => (0, import_react28.createElement)(PageComponent, {
4072
+ children: ({ trpc, theme }) => (0, import_react33.createElement)(PageComponent, {
3758
4073
  trpc,
3759
4074
  theme: { isDark: theme.resolvedMode === "dark" },
3760
4075
  navigate: (path) => {
@@ -3768,6 +4083,7 @@ function mountAddonPage(PageComponent, options = {}) {
3768
4083
  0 && (module.exports = {
3769
4084
  AppShell,
3770
4085
  Badge,
4086
+ BottomSheet,
3771
4087
  Button,
3772
4088
  CLASS_COLORS,
3773
4089
  Card,
@@ -3804,6 +4120,7 @@ function mountAddonPage(PageComponent, options = {}) {
3804
4120
  KeyValueList,
3805
4121
  Label,
3806
4122
  LoginForm,
4123
+ MobileDrawer,
3807
4124
  PageHeader,
3808
4125
  PipelineBuilder,
3809
4126
  PipelineRuntimeSelector,
@@ -3843,6 +4160,7 @@ function mountAddonPage(PageComponent, options = {}) {
3843
4160
  statusIcons,
3844
4161
  themeToCss,
3845
4162
  useDevShell,
4163
+ useIsMobile,
3846
4164
  useThemeMode
3847
4165
  });
3848
4166
  //# sourceMappingURL=index.cjs.map