@camstack/ui-library 0.1.35 → 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.js CHANGED
@@ -917,12 +917,92 @@ import {
917
917
  createContext as createContext5,
918
918
  useCallback as useCallback4,
919
919
  useContext as useContext5,
920
- useEffect as useEffect4,
920
+ useEffect as useEffect5,
921
921
  useId as useId4,
922
922
  useRef as useRef4,
923
923
  useState as useState5
924
924
  } from "react";
925
- import { jsx as jsx16 } from "react/jsx-runtime";
925
+
926
+ // src/hooks/use-is-mobile.ts
927
+ import { useSyncExternalStore } from "react";
928
+ var MOBILE_QUERY = "(max-width: 767px)";
929
+ function subscribe(callback) {
930
+ const mql = window.matchMedia(MOBILE_QUERY);
931
+ mql.addEventListener("change", callback);
932
+ return () => mql.removeEventListener("change", callback);
933
+ }
934
+ function getSnapshot() {
935
+ return window.matchMedia(MOBILE_QUERY).matches;
936
+ }
937
+ function getServerSnapshot() {
938
+ return false;
939
+ }
940
+ function useIsMobile() {
941
+ return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
942
+ }
943
+
944
+ // src/primitives/bottom-sheet.tsx
945
+ import { useEffect as useEffect4 } from "react";
946
+ import { X } from "lucide-react";
947
+ import { Fragment, jsx as jsx16, jsxs as jsxs5 } from "react/jsx-runtime";
948
+ function BottomSheet({ open, onClose, title, children, className }) {
949
+ useEffect4(() => {
950
+ if (!open) return;
951
+ const handleKeyDown = (e) => {
952
+ if (e.key === "Escape") onClose();
953
+ };
954
+ document.addEventListener("keydown", handleKeyDown);
955
+ document.body.style.overflow = "hidden";
956
+ return () => {
957
+ document.removeEventListener("keydown", handleKeyDown);
958
+ document.body.style.overflow = "";
959
+ };
960
+ }, [open, onClose]);
961
+ return /* @__PURE__ */ jsxs5(Fragment, { children: [
962
+ /* @__PURE__ */ jsx16(
963
+ "div",
964
+ {
965
+ className: cn(
966
+ "fixed inset-0 z-40 bg-black/50 transition-opacity duration-200",
967
+ open ? "opacity-100" : "pointer-events-none opacity-0"
968
+ ),
969
+ onClick: onClose,
970
+ "aria-hidden": "true"
971
+ }
972
+ ),
973
+ /* @__PURE__ */ jsxs5(
974
+ "div",
975
+ {
976
+ role: "dialog",
977
+ "aria-modal": "true",
978
+ className: cn(
979
+ "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",
980
+ "max-h-[80dvh]",
981
+ open ? "translate-y-0" : "translate-y-full",
982
+ className
983
+ ),
984
+ children: [
985
+ /* @__PURE__ */ jsx16("div", { className: "flex justify-center pt-2 pb-1", children: /* @__PURE__ */ jsx16("div", { className: "h-1 w-8 rounded-full bg-foreground-subtle/30" }) }),
986
+ title && /* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between px-4 pb-2", children: [
987
+ /* @__PURE__ */ jsx16("span", { className: "text-sm font-medium text-foreground", children: title }),
988
+ /* @__PURE__ */ jsx16(
989
+ "button",
990
+ {
991
+ onClick: onClose,
992
+ className: "p-1 rounded-md hover:bg-surface-hover text-foreground-muted transition-colors",
993
+ children: /* @__PURE__ */ jsx16(X, { className: "h-4 w-4" })
994
+ }
995
+ )
996
+ ] }),
997
+ /* @__PURE__ */ jsx16("div", { className: "flex-1 overflow-y-auto px-4 pb-4", children })
998
+ ]
999
+ }
1000
+ )
1001
+ ] });
1002
+ }
1003
+
1004
+ // src/primitives/popover.tsx
1005
+ import { jsx as jsx17 } from "react/jsx-runtime";
926
1006
  var PopoverContext = createContext5(null);
927
1007
  function usePopoverContext() {
928
1008
  const ctx = useContext5(PopoverContext);
@@ -941,11 +1021,11 @@ function Popover({ children, open: controlledOpen, onOpenChange }) {
941
1021
  },
942
1022
  [controlledOpen, onOpenChange]
943
1023
  );
944
- return /* @__PURE__ */ jsx16(PopoverContext.Provider, { value: { open, setOpen, triggerId, contentId }, children: /* @__PURE__ */ jsx16("div", { className: "relative inline-block", children }) });
1024
+ return /* @__PURE__ */ jsx17(PopoverContext.Provider, { value: { open, setOpen, triggerId, contentId }, children: /* @__PURE__ */ jsx17("div", { className: "relative inline-block", children }) });
945
1025
  }
946
1026
  function PopoverTrigger({ children, ...props }) {
947
1027
  const { open, setOpen, triggerId, contentId } = usePopoverContext();
948
- return /* @__PURE__ */ jsx16(
1028
+ return /* @__PURE__ */ jsx17(
949
1029
  "button",
950
1030
  {
951
1031
  type: "button",
@@ -961,9 +1041,10 @@ function PopoverTrigger({ children, ...props }) {
961
1041
  }
962
1042
  function PopoverContent({ className, children, ...props }) {
963
1043
  const { open, setOpen, contentId, triggerId } = usePopoverContext();
1044
+ const isMobile = useIsMobile();
964
1045
  const ref = useRef4(null);
965
- useEffect4(() => {
966
- if (!open) return;
1046
+ useEffect5(() => {
1047
+ if (!open || isMobile) return;
967
1048
  const handler = (e) => {
968
1049
  const el = ref.current;
969
1050
  const trigger = document.getElementById(triggerId);
@@ -980,9 +1061,12 @@ function PopoverContent({ className, children, ...props }) {
980
1061
  document.removeEventListener("mousedown", handler);
981
1062
  document.removeEventListener("keydown", escHandler);
982
1063
  };
983
- }, [open, setOpen, triggerId]);
1064
+ }, [open, setOpen, triggerId, isMobile]);
984
1065
  if (!open) return null;
985
- return /* @__PURE__ */ jsx16(
1066
+ if (isMobile) {
1067
+ return /* @__PURE__ */ jsx17(BottomSheet, { open, onClose: () => setOpen(false), children });
1068
+ }
1069
+ return /* @__PURE__ */ jsx17(
986
1070
  "div",
987
1071
  {
988
1072
  ref,
@@ -1006,7 +1090,7 @@ import {
1006
1090
  useContext as useContext6,
1007
1091
  useState as useState6
1008
1092
  } from "react";
1009
- import { jsx as jsx17 } from "react/jsx-runtime";
1093
+ import { jsx as jsx18 } from "react/jsx-runtime";
1010
1094
  var TabsContext = createContext6(null);
1011
1095
  function useTabsContext() {
1012
1096
  const ctx = useContext6(TabsContext);
@@ -1029,10 +1113,10 @@ function Tabs({
1029
1113
  },
1030
1114
  [controlledValue, onValueChange]
1031
1115
  );
1032
- return /* @__PURE__ */ jsx17(TabsContext.Provider, { value: { value, setValue }, children: /* @__PURE__ */ jsx17("div", { className, ...props }) });
1116
+ return /* @__PURE__ */ jsx18(TabsContext.Provider, { value: { value, setValue }, children: /* @__PURE__ */ jsx18("div", { className, ...props }) });
1033
1117
  }
1034
1118
  function TabsList({ className, ...props }) {
1035
- return /* @__PURE__ */ jsx17(
1119
+ return /* @__PURE__ */ jsx18(
1036
1120
  "div",
1037
1121
  {
1038
1122
  role: "tablist",
@@ -1045,7 +1129,7 @@ function TabsTrigger({ value, className, ...props }) {
1045
1129
  const { value: activeValue, setValue } = useTabsContext();
1046
1130
  const isActive = value === activeValue;
1047
1131
  const panelId = `tabpanel-${value}`;
1048
- return /* @__PURE__ */ jsx17(
1132
+ return /* @__PURE__ */ jsx18(
1049
1133
  "button",
1050
1134
  {
1051
1135
  type: "button",
@@ -1066,7 +1150,7 @@ function TabsTrigger({ value, className, ...props }) {
1066
1150
  function TabsContent({ value, className, ...props }) {
1067
1151
  const { value: activeValue } = useTabsContext();
1068
1152
  if (value !== activeValue) return null;
1069
- return /* @__PURE__ */ jsx17(
1153
+ return /* @__PURE__ */ jsx18(
1070
1154
  "div",
1071
1155
  {
1072
1156
  role: "tabpanel",
@@ -1079,10 +1163,10 @@ function TabsContent({ value, className, ...props }) {
1079
1163
 
1080
1164
  // src/primitives/scroll-area.tsx
1081
1165
  import { forwardRef as forwardRef13 } from "react";
1082
- import { jsx as jsx18 } from "react/jsx-runtime";
1166
+ import { jsx as jsx19 } from "react/jsx-runtime";
1083
1167
  var ScrollArea = forwardRef13(
1084
1168
  ({ className, ...props }, ref) => {
1085
- return /* @__PURE__ */ jsx18(
1169
+ return /* @__PURE__ */ jsx19(
1086
1170
  "div",
1087
1171
  {
1088
1172
  ref,
@@ -1098,29 +1182,9 @@ var ScrollArea = forwardRef13(
1098
1182
  ScrollArea.displayName = "ScrollArea";
1099
1183
 
1100
1184
  // src/primitives/floating-panel.tsx
1101
- import { useRef as useRef5, useState as useState7, useCallback as useCallback6, useEffect as useEffect5 } from "react";
1102
- import { X, Minimize2, Maximize2, GripHorizontal } from "lucide-react";
1103
-
1104
- // src/hooks/use-is-mobile.ts
1105
- import { useSyncExternalStore } from "react";
1106
- var MOBILE_QUERY = "(max-width: 767px)";
1107
- function subscribe(callback) {
1108
- const mql = window.matchMedia(MOBILE_QUERY);
1109
- mql.addEventListener("change", callback);
1110
- return () => mql.removeEventListener("change", callback);
1111
- }
1112
- function getSnapshot() {
1113
- return window.matchMedia(MOBILE_QUERY).matches;
1114
- }
1115
- function getServerSnapshot() {
1116
- return false;
1117
- }
1118
- function useIsMobile() {
1119
- return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
1120
- }
1121
-
1122
- // src/primitives/floating-panel.tsx
1123
- import { jsx as jsx19, jsxs as jsxs5 } from "react/jsx-runtime";
1185
+ import { useRef as useRef5, useState as useState7, useCallback as useCallback6, useEffect as useEffect6 } from "react";
1186
+ import { X as X2, Minimize2, Maximize2, GripHorizontal } from "lucide-react";
1187
+ import { jsx as jsx20, jsxs as jsxs6 } from "react/jsx-runtime";
1124
1188
  function FloatingPanel({
1125
1189
  title,
1126
1190
  onClose,
@@ -1150,7 +1214,7 @@ function FloatingPanel({
1150
1214
  resizing.current = true;
1151
1215
  offset.current = { x: e.clientX, y: e.clientY };
1152
1216
  }, []);
1153
- useEffect5(() => {
1217
+ useEffect6(() => {
1154
1218
  const onMouseMove = (e) => {
1155
1219
  if (dragging.current) setPos({ x: e.clientX - offset.current.x, y: e.clientY - offset.current.y });
1156
1220
  if (resizing.current) {
@@ -1172,7 +1236,7 @@ function FloatingPanel({
1172
1236
  };
1173
1237
  }, [minWidth, minHeight]);
1174
1238
  if (isMobile) {
1175
- return /* @__PURE__ */ jsxs5(
1239
+ return /* @__PURE__ */ jsxs6(
1176
1240
  "div",
1177
1241
  {
1178
1242
  className: cn(
@@ -1181,33 +1245,33 @@ function FloatingPanel({
1181
1245
  ),
1182
1246
  style: { maxHeight: "60dvh" },
1183
1247
  children: [
1184
- /* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between gap-2 px-3 py-2 border-b border-border shrink-0 bg-surface", children: [
1185
- /* @__PURE__ */ jsx19("span", { className: "text-[11px] font-medium truncate", children: title }),
1186
- /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-1 shrink-0", children: [
1187
- /* @__PURE__ */ jsx19(
1248
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between gap-2 px-3 py-2 border-b border-border shrink-0 bg-surface", children: [
1249
+ /* @__PURE__ */ jsx20("span", { className: "text-[11px] font-medium truncate", children: title }),
1250
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-1 shrink-0", children: [
1251
+ /* @__PURE__ */ jsx20(
1188
1252
  "button",
1189
1253
  {
1190
1254
  onClick: () => setMinimized(!minimized),
1191
1255
  className: "p-0.5 rounded hover:bg-surface-hover text-foreground-muted transition-colors",
1192
- children: minimized ? /* @__PURE__ */ jsx19(Maximize2, { size: 12 }) : /* @__PURE__ */ jsx19(Minimize2, { size: 12 })
1256
+ children: minimized ? /* @__PURE__ */ jsx20(Maximize2, { size: 12 }) : /* @__PURE__ */ jsx20(Minimize2, { size: 12 })
1193
1257
  }
1194
1258
  ),
1195
- /* @__PURE__ */ jsx19(
1259
+ /* @__PURE__ */ jsx20(
1196
1260
  "button",
1197
1261
  {
1198
1262
  onClick: onClose,
1199
1263
  className: "p-0.5 rounded hover:bg-danger/20 text-foreground-muted hover:text-danger transition-colors",
1200
- children: /* @__PURE__ */ jsx19(X, { size: 12 })
1264
+ children: /* @__PURE__ */ jsx20(X2, { size: 12 })
1201
1265
  }
1202
1266
  )
1203
1267
  ] })
1204
1268
  ] }),
1205
- !minimized && /* @__PURE__ */ jsx19("div", { className: "flex-1 min-h-0 overflow-y-auto", children })
1269
+ !minimized && /* @__PURE__ */ jsx20("div", { className: "flex-1 min-h-0 overflow-y-auto", children })
1206
1270
  ]
1207
1271
  }
1208
1272
  );
1209
1273
  }
1210
- return /* @__PURE__ */ jsxs5(
1274
+ return /* @__PURE__ */ jsxs6(
1211
1275
  "div",
1212
1276
  {
1213
1277
  className: cn(
@@ -1216,42 +1280,42 @@ function FloatingPanel({
1216
1280
  ),
1217
1281
  style: { left: pos.x, top: pos.y, width: minimized ? 280 : size.w, height: minimized ? "auto" : size.h },
1218
1282
  children: [
1219
- /* @__PURE__ */ jsxs5(
1283
+ /* @__PURE__ */ jsxs6(
1220
1284
  "div",
1221
1285
  {
1222
1286
  onMouseDown: onDragStart,
1223
1287
  className: "flex items-center justify-between gap-2 px-3 py-2 border-b border-border cursor-move select-none shrink-0 bg-surface",
1224
1288
  children: [
1225
- /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2 min-w-0", children: [
1226
- /* @__PURE__ */ jsx19(GripHorizontal, { size: 12, className: "text-foreground-subtle shrink-0" }),
1227
- /* @__PURE__ */ jsx19("span", { className: "text-[11px] font-medium truncate", children: title })
1289
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2 min-w-0", children: [
1290
+ /* @__PURE__ */ jsx20(GripHorizontal, { size: 12, className: "text-foreground-subtle shrink-0" }),
1291
+ /* @__PURE__ */ jsx20("span", { className: "text-[11px] font-medium truncate", children: title })
1228
1292
  ] }),
1229
- /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-1 shrink-0", children: [
1230
- /* @__PURE__ */ jsx19(
1293
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-1 shrink-0", children: [
1294
+ /* @__PURE__ */ jsx20(
1231
1295
  "button",
1232
1296
  {
1233
1297
  onClick: () => setMinimized(!minimized),
1234
1298
  className: "p-0.5 rounded hover:bg-surface-hover text-foreground-muted transition-colors",
1235
1299
  title: minimized ? "Restore" : "Minimize",
1236
- children: minimized ? /* @__PURE__ */ jsx19(Maximize2, { size: 12 }) : /* @__PURE__ */ jsx19(Minimize2, { size: 12 })
1300
+ children: minimized ? /* @__PURE__ */ jsx20(Maximize2, { size: 12 }) : /* @__PURE__ */ jsx20(Minimize2, { size: 12 })
1237
1301
  }
1238
1302
  ),
1239
- /* @__PURE__ */ jsx19(
1303
+ /* @__PURE__ */ jsx20(
1240
1304
  "button",
1241
1305
  {
1242
1306
  onClick: onClose,
1243
1307
  className: "p-0.5 rounded hover:bg-danger/20 text-foreground-muted hover:text-danger transition-colors",
1244
1308
  title: "Close",
1245
- children: /* @__PURE__ */ jsx19(X, { size: 12 })
1309
+ children: /* @__PURE__ */ jsx20(X2, { size: 12 })
1246
1310
  }
1247
1311
  )
1248
1312
  ] })
1249
1313
  ]
1250
1314
  }
1251
1315
  ),
1252
- !minimized && /* @__PURE__ */ jsxs5("div", { className: "flex-1 min-h-0 overflow-y-auto relative", children: [
1316
+ !minimized && /* @__PURE__ */ jsxs6("div", { className: "flex-1 min-h-0 overflow-y-auto relative", children: [
1253
1317
  children,
1254
- /* @__PURE__ */ jsx19(
1318
+ /* @__PURE__ */ jsx20(
1255
1319
  "div",
1256
1320
  {
1257
1321
  onMouseDown: onResizeStart,
@@ -1266,11 +1330,11 @@ function FloatingPanel({
1266
1330
  }
1267
1331
 
1268
1332
  // src/primitives/mobile-drawer.tsx
1269
- import { useEffect as useEffect6, useRef as useRef6 } from "react";
1270
- import { Fragment, jsx as jsx20, jsxs as jsxs6 } from "react/jsx-runtime";
1333
+ import { useEffect as useEffect7, useRef as useRef6 } from "react";
1334
+ import { Fragment as Fragment2, jsx as jsx21, jsxs as jsxs7 } from "react/jsx-runtime";
1271
1335
  function MobileDrawer({ open, onClose, children, className, width = "w-64" }) {
1272
1336
  const drawerRef = useRef6(null);
1273
- useEffect6(() => {
1337
+ useEffect7(() => {
1274
1338
  if (!open) return;
1275
1339
  const handleKeyDown = (e) => {
1276
1340
  if (e.key === "Escape") onClose();
@@ -1282,8 +1346,8 @@ function MobileDrawer({ open, onClose, children, className, width = "w-64" }) {
1282
1346
  document.body.style.overflow = "";
1283
1347
  };
1284
1348
  }, [open, onClose]);
1285
- return /* @__PURE__ */ jsxs6(Fragment, { children: [
1286
- /* @__PURE__ */ jsx20(
1349
+ return /* @__PURE__ */ jsxs7(Fragment2, { children: [
1350
+ /* @__PURE__ */ jsx21(
1287
1351
  "div",
1288
1352
  {
1289
1353
  className: cn(
@@ -1294,7 +1358,7 @@ function MobileDrawer({ open, onClose, children, className, width = "w-64" }) {
1294
1358
  "aria-hidden": "true"
1295
1359
  }
1296
1360
  ),
1297
- /* @__PURE__ */ jsx20(
1361
+ /* @__PURE__ */ jsx21(
1298
1362
  "div",
1299
1363
  {
1300
1364
  ref: drawerRef,
@@ -1312,66 +1376,6 @@ function MobileDrawer({ open, onClose, children, className, width = "w-64" }) {
1312
1376
  ] });
1313
1377
  }
1314
1378
 
1315
- // src/primitives/bottom-sheet.tsx
1316
- import { useEffect as useEffect7 } from "react";
1317
- import { X as X2 } from "lucide-react";
1318
- import { Fragment as Fragment2, jsx as jsx21, jsxs as jsxs7 } from "react/jsx-runtime";
1319
- function BottomSheet({ open, onClose, title, children, className }) {
1320
- useEffect7(() => {
1321
- if (!open) return;
1322
- const handleKeyDown = (e) => {
1323
- if (e.key === "Escape") onClose();
1324
- };
1325
- document.addEventListener("keydown", handleKeyDown);
1326
- document.body.style.overflow = "hidden";
1327
- return () => {
1328
- document.removeEventListener("keydown", handleKeyDown);
1329
- document.body.style.overflow = "";
1330
- };
1331
- }, [open, onClose]);
1332
- return /* @__PURE__ */ jsxs7(Fragment2, { children: [
1333
- /* @__PURE__ */ jsx21(
1334
- "div",
1335
- {
1336
- className: cn(
1337
- "fixed inset-0 z-40 bg-black/50 transition-opacity duration-200",
1338
- open ? "opacity-100" : "pointer-events-none opacity-0"
1339
- ),
1340
- onClick: onClose,
1341
- "aria-hidden": "true"
1342
- }
1343
- ),
1344
- /* @__PURE__ */ jsxs7(
1345
- "div",
1346
- {
1347
- role: "dialog",
1348
- "aria-modal": "true",
1349
- className: cn(
1350
- "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",
1351
- "max-h-[80dvh]",
1352
- open ? "translate-y-0" : "translate-y-full",
1353
- className
1354
- ),
1355
- children: [
1356
- /* @__PURE__ */ jsx21("div", { className: "flex justify-center pt-2 pb-1", children: /* @__PURE__ */ jsx21("div", { className: "h-1 w-8 rounded-full bg-foreground-subtle/30" }) }),
1357
- title && /* @__PURE__ */ jsxs7("div", { className: "flex items-center justify-between px-4 pb-2", children: [
1358
- /* @__PURE__ */ jsx21("span", { className: "text-sm font-medium text-foreground", children: title }),
1359
- /* @__PURE__ */ jsx21(
1360
- "button",
1361
- {
1362
- onClick: onClose,
1363
- className: "p-1 rounded-md hover:bg-surface-hover text-foreground-muted transition-colors",
1364
- children: /* @__PURE__ */ jsx21(X2, { className: "h-4 w-4" })
1365
- }
1366
- )
1367
- ] }),
1368
- /* @__PURE__ */ jsx21("div", { className: "flex-1 overflow-y-auto px-4 pb-4", children })
1369
- ]
1370
- }
1371
- )
1372
- ] });
1373
- }
1374
-
1375
1379
  // src/composites/status-badge.tsx
1376
1380
  import { jsx as jsx22, jsxs as jsxs8 } from "react/jsx-runtime";
1377
1381
  var statusConfig = {
@@ -1627,12 +1631,79 @@ function CodeBlock({ children, maxHeight = 300, className }) {
1627
1631
  }
1628
1632
 
1629
1633
  // src/composites/filter-bar.tsx
1630
- import { Search } from "lucide-react";
1631
- import { jsx as jsx32 } from "react/jsx-runtime";
1634
+ import { useState as useState9 } from "react";
1635
+ import { Search, SlidersHorizontal } from "lucide-react";
1636
+ import { Fragment as Fragment3, jsx as jsx32, jsxs as jsxs17 } from "react/jsx-runtime";
1632
1637
  function FilterBar({ filters, values, onChange, className }) {
1638
+ const isMobile = useIsMobile();
1639
+ const [sheetOpen, setSheetOpen] = useState9(false);
1633
1640
  const handleChange = (key, value) => {
1634
1641
  onChange({ ...values, [key]: value });
1635
1642
  };
1643
+ const activeCount = Object.values(values).filter((v) => v !== void 0 && v !== "").length;
1644
+ if (isMobile) {
1645
+ const searchFilter = filters.find((f) => f.type === "search");
1646
+ const hasNonSearchFilters = filters.some((f) => f.type !== "search");
1647
+ return /* @__PURE__ */ jsxs17("div", { className: cn("flex items-center gap-2", className), children: [
1648
+ searchFilter && /* @__PURE__ */ jsx32(
1649
+ Input,
1650
+ {
1651
+ placeholder: searchFilter.placeholder ?? "Search...",
1652
+ value: values[searchFilter.key] ?? "",
1653
+ onChange: (e) => handleChange(searchFilter.key, e.target.value),
1654
+ leftSlot: /* @__PURE__ */ jsx32(Search, { className: "h-3 w-3 text-foreground-subtle" }),
1655
+ className: "flex-1"
1656
+ }
1657
+ ),
1658
+ hasNonSearchFilters && /* @__PURE__ */ jsxs17(Fragment3, { children: [
1659
+ /* @__PURE__ */ jsxs17(
1660
+ "button",
1661
+ {
1662
+ onClick: () => setSheetOpen(true),
1663
+ 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",
1664
+ children: [
1665
+ /* @__PURE__ */ jsx32(SlidersHorizontal, { className: "h-3.5 w-3.5" }),
1666
+ "Filters",
1667
+ activeCount > 0 && /* @__PURE__ */ jsx32(Badge, { variant: "info", className: "ml-1 text-[10px] px-1 py-0", children: activeCount })
1668
+ ]
1669
+ }
1670
+ ),
1671
+ /* @__PURE__ */ jsx32(BottomSheet, { open: sheetOpen, onClose: () => setSheetOpen(false), title: "Filters", children: /* @__PURE__ */ jsx32("div", { className: "flex flex-col gap-3", children: filters.filter((f) => f.type !== "search").map((filter) => {
1672
+ switch (filter.type) {
1673
+ case "select":
1674
+ return /* @__PURE__ */ jsxs17("div", { children: [
1675
+ /* @__PURE__ */ jsx32("label", { className: "text-xs text-foreground-muted mb-1 block", children: filter.label }),
1676
+ /* @__PURE__ */ jsx32(
1677
+ Select,
1678
+ {
1679
+ options: filter.options,
1680
+ value: values[filter.key] ?? "",
1681
+ onChange: (e) => handleChange(filter.key, e.target.value),
1682
+ className: "w-full"
1683
+ }
1684
+ )
1685
+ ] }, filter.key);
1686
+ case "badge-toggle":
1687
+ return /* @__PURE__ */ jsx32("div", { className: "flex items-center gap-1 flex-wrap", children: filter.options.map((option) => {
1688
+ const currentValue = values[filter.key];
1689
+ const isActive = currentValue === option.value;
1690
+ return /* @__PURE__ */ jsx32(
1691
+ "button",
1692
+ {
1693
+ type: "button",
1694
+ onClick: () => handleChange(filter.key, isActive ? void 0 : option.value),
1695
+ children: /* @__PURE__ */ jsx32(Badge, { variant: isActive ? "info" : "default", className: "cursor-pointer", children: option.label })
1696
+ },
1697
+ option.value
1698
+ );
1699
+ }) }, filter.key);
1700
+ default:
1701
+ return null;
1702
+ }
1703
+ }) }) })
1704
+ ] })
1705
+ ] });
1706
+ }
1636
1707
  return /* @__PURE__ */ jsx32("div", { className: cn("flex items-center gap-2 flex-wrap", className), children: filters.map((filter) => {
1637
1708
  switch (filter.type) {
1638
1709
  case "search":
@@ -1666,18 +1737,8 @@ function FilterBar({ filters, values, onChange, className }) {
1666
1737
  "button",
1667
1738
  {
1668
1739
  type: "button",
1669
- onClick: () => handleChange(
1670
- filter.key,
1671
- isActive ? void 0 : option.value
1672
- ),
1673
- children: /* @__PURE__ */ jsx32(
1674
- Badge,
1675
- {
1676
- variant: isActive ? "info" : "default",
1677
- className: "cursor-pointer",
1678
- children: option.label
1679
- }
1680
- )
1740
+ onClick: () => handleChange(filter.key, isActive ? void 0 : option.value),
1741
+ children: /* @__PURE__ */ jsx32(Badge, { variant: isActive ? "info" : "default", className: "cursor-pointer", children: option.label })
1681
1742
  },
1682
1743
  option.value
1683
1744
  );
@@ -1689,7 +1750,7 @@ function FilterBar({ filters, values, onChange, className }) {
1689
1750
  }
1690
1751
 
1691
1752
  // src/composites/app-shell/sidebar-item.tsx
1692
- import { jsx as jsx33, jsxs as jsxs17 } from "react/jsx-runtime";
1753
+ import { jsx as jsx33, jsxs as jsxs18 } from "react/jsx-runtime";
1693
1754
  function SidebarItem({
1694
1755
  label,
1695
1756
  icon: Icon,
@@ -1698,7 +1759,7 @@ function SidebarItem({
1698
1759
  active = false,
1699
1760
  className
1700
1761
  }) {
1701
- return /* @__PURE__ */ jsxs17(
1762
+ return /* @__PURE__ */ jsxs18(
1702
1763
  "a",
1703
1764
  {
1704
1765
  href,
@@ -1717,9 +1778,9 @@ function SidebarItem({
1717
1778
  }
1718
1779
 
1719
1780
  // src/composites/app-shell/sidebar.tsx
1720
- import { jsx as jsx34, jsxs as jsxs18 } from "react/jsx-runtime";
1781
+ import { jsx as jsx34, jsxs as jsxs19 } from "react/jsx-runtime";
1721
1782
  function Sidebar({ logo, sections, footer, onNavigate, className }) {
1722
- return /* @__PURE__ */ jsxs18(
1783
+ return /* @__PURE__ */ jsxs19(
1723
1784
  "nav",
1724
1785
  {
1725
1786
  className: cn(
@@ -1728,11 +1789,11 @@ function Sidebar({ logo, sections, footer, onNavigate, className }) {
1728
1789
  ),
1729
1790
  children: [
1730
1791
  logo && /* @__PURE__ */ jsx34("div", { className: "px-3 py-2 shrink-0", children: logo }),
1731
- /* @__PURE__ */ jsx34("div", { className: "flex-1 overflow-auto px-1 py-1", children: sections.map((section, sectionIndex) => /* @__PURE__ */ jsxs18("div", { className: cn(sectionIndex > 0 ? "mt-3" : ""), children: [
1792
+ /* @__PURE__ */ jsx34("div", { className: "flex-1 overflow-auto px-1 py-1", children: sections.map((section, sectionIndex) => /* @__PURE__ */ jsxs19("div", { className: cn(sectionIndex > 0 ? "mt-3" : ""), children: [
1732
1793
  section.label && /* @__PURE__ */ jsx34("span", { className: "text-[10px] text-foreground-disabled uppercase tracking-wider px-2 mb-1 block", children: section.label }),
1733
1794
  /* @__PURE__ */ jsx34("div", { className: "flex flex-col gap-0.5", onClick: onNavigate, children: section.items.map((item) => /* @__PURE__ */ jsx34(SidebarItem, { ...item }, item.href)) })
1734
1795
  ] }, sectionIndex)) }),
1735
- footer && footer.length > 0 && /* @__PURE__ */ jsxs18("div", { className: "shrink-0 px-1 pb-1", children: [
1796
+ footer && footer.length > 0 && /* @__PURE__ */ jsxs19("div", { className: "shrink-0 px-1 pb-1", children: [
1736
1797
  /* @__PURE__ */ jsx34(Separator, { className: "mb-1" }),
1737
1798
  /* @__PURE__ */ jsx34("div", { className: "flex flex-col gap-0.5", onClick: onNavigate, children: footer.map((item) => /* @__PURE__ */ jsx34(SidebarItem, { ...item }, item.href)) })
1738
1799
  ] })
@@ -1742,13 +1803,13 @@ function Sidebar({ logo, sections, footer, onNavigate, className }) {
1742
1803
  }
1743
1804
 
1744
1805
  // src/composites/app-shell/app-shell.tsx
1745
- import { useState as useState9 } from "react";
1806
+ import { useState as useState10 } from "react";
1746
1807
  import { ChevronRight, Menu } from "lucide-react";
1747
- import { jsx as jsx35, jsxs as jsxs19 } from "react/jsx-runtime";
1808
+ import { jsx as jsx35, jsxs as jsxs20 } from "react/jsx-runtime";
1748
1809
  function AppShell({ sidebar, header, mobileLogo, mobileActions, children, className }) {
1749
1810
  const isMobile = useIsMobile();
1750
- const [drawerOpen, setDrawerOpen] = useState9(false);
1751
- return /* @__PURE__ */ jsxs19("div", { className: cn("flex h-screen", className), children: [
1811
+ const [drawerOpen, setDrawerOpen] = useState10(false);
1812
+ return /* @__PURE__ */ jsxs20("div", { className: cn("flex h-screen", className), children: [
1752
1813
  !isMobile && /* @__PURE__ */ jsx35(Sidebar, { ...sidebar, className: cn("w-44", sidebar.className) }),
1753
1814
  isMobile && /* @__PURE__ */ jsx35(MobileDrawer, { open: drawerOpen, onClose: () => setDrawerOpen(false), width: "w-64", children: /* @__PURE__ */ jsx35(
1754
1815
  Sidebar,
@@ -1758,8 +1819,8 @@ function AppShell({ sidebar, header, mobileLogo, mobileActions, children, classN
1758
1819
  className: "w-full border-r-0"
1759
1820
  }
1760
1821
  ) }),
1761
- /* @__PURE__ */ jsxs19("div", { className: "flex flex-1 flex-col min-w-0", children: [
1762
- isMobile && /* @__PURE__ */ jsxs19("header", { className: "flex items-center h-12 border-b border-border px-3 shrink-0 bg-surface/80 backdrop-blur-sm", children: [
1822
+ /* @__PURE__ */ jsxs20("div", { className: "flex flex-1 flex-col min-w-0", children: [
1823
+ isMobile && /* @__PURE__ */ jsxs20("header", { className: "flex items-center h-12 border-b border-border px-3 shrink-0 bg-surface/80 backdrop-blur-sm", children: [
1763
1824
  /* @__PURE__ */ jsx35(
1764
1825
  "button",
1765
1826
  {
@@ -1772,10 +1833,10 @@ function AppShell({ sidebar, header, mobileLogo, mobileActions, children, classN
1772
1833
  mobileLogo && /* @__PURE__ */ jsx35("div", { className: "flex-1 flex justify-center", children: mobileLogo }),
1773
1834
  mobileActions && /* @__PURE__ */ jsx35("div", { className: "shrink-0", children: mobileActions })
1774
1835
  ] }),
1775
- !isMobile && header && /* @__PURE__ */ jsxs19("header", { className: "flex items-center h-10 border-b border-border px-4 shrink-0", children: [
1836
+ !isMobile && header && /* @__PURE__ */ jsxs20("header", { className: "flex items-center h-10 border-b border-border px-4 shrink-0", children: [
1776
1837
  header.breadcrumbs && header.breadcrumbs.length > 0 && /* @__PURE__ */ jsx35("nav", { className: "flex items-center gap-1 text-xs flex-1 min-w-0", children: header.breadcrumbs.map((crumb, index) => {
1777
1838
  const isLast = index === header.breadcrumbs.length - 1;
1778
- return /* @__PURE__ */ jsxs19("span", { className: "flex items-center gap-1", children: [
1839
+ return /* @__PURE__ */ jsxs20("span", { className: "flex items-center gap-1", children: [
1779
1840
  index > 0 && /* @__PURE__ */ jsx35(ChevronRight, { className: "h-3 w-3 text-foreground-subtle shrink-0" }),
1780
1841
  crumb.href && !isLast ? /* @__PURE__ */ jsx35(
1781
1842
  "a",
@@ -1807,7 +1868,7 @@ import {
1807
1868
 
1808
1869
  // src/composites/data-table/data-table-header.tsx
1809
1870
  import { ArrowUpDown, ArrowUp, ArrowDown } from "lucide-react";
1810
- import { jsx as jsx36, jsxs as jsxs20 } from "react/jsx-runtime";
1871
+ import { jsx as jsx36, jsxs as jsxs21 } from "react/jsx-runtime";
1811
1872
  function DataTableHeader({
1812
1873
  headerGroups,
1813
1874
  onSortingChange,
@@ -1843,7 +1904,7 @@ function HeaderCell({ header, sortable, flexRender: render }) {
1843
1904
  sortable && "cursor-pointer select-none"
1844
1905
  ),
1845
1906
  onClick: sortable ? header.column.getToggleSortingHandler() : void 0,
1846
- children: /* @__PURE__ */ jsxs20("span", { className: "inline-flex items-center gap-1", children: [
1907
+ children: /* @__PURE__ */ jsxs21("span", { className: "inline-flex items-center gap-1", children: [
1847
1908
  header.isPlaceholder ? null : render(header.column.columnDef.header, header.getContext()),
1848
1909
  sortable && /* @__PURE__ */ jsx36(SortIcon, { className: "h-3 w-3" })
1849
1910
  ] })
@@ -1853,7 +1914,7 @@ function HeaderCell({ header, sortable, flexRender: render }) {
1853
1914
 
1854
1915
  // src/composites/data-table/data-table-row.tsx
1855
1916
  import { MoreHorizontal } from "lucide-react";
1856
- import { jsx as jsx37, jsxs as jsxs21 } from "react/jsx-runtime";
1917
+ import { jsx as jsx37, jsxs as jsxs22 } from "react/jsx-runtime";
1857
1918
  function DataTableRow({
1858
1919
  row,
1859
1920
  onRowClick,
@@ -1861,7 +1922,7 @@ function DataTableRow({
1861
1922
  flexRender: render
1862
1923
  }) {
1863
1924
  const actions = rowActions ? rowActions(row.original) : [];
1864
- return /* @__PURE__ */ jsxs21(
1925
+ return /* @__PURE__ */ jsxs22(
1865
1926
  "tr",
1866
1927
  {
1867
1928
  className: cn(
@@ -1872,7 +1933,7 @@ function DataTableRow({
1872
1933
  onClick: onRowClick ? () => onRowClick(row.original) : void 0,
1873
1934
  children: [
1874
1935
  row.getVisibleCells().map((cell) => /* @__PURE__ */ jsx37(DataTableCell, { cell, flexRender: render }, cell.id)),
1875
- actions.length > 0 && /* @__PURE__ */ jsx37("td", { className: "px-2 py-1.5 w-8", children: /* @__PURE__ */ jsxs21(Dropdown, { children: [
1936
+ actions.length > 0 && /* @__PURE__ */ jsx37("td", { className: "px-2 py-1.5 w-8", children: /* @__PURE__ */ jsxs22(Dropdown, { children: [
1876
1937
  /* @__PURE__ */ jsx37(
1877
1938
  DropdownTrigger,
1878
1939
  {
@@ -1905,7 +1966,7 @@ function DataTableCell({ cell, flexRender: render }) {
1905
1966
 
1906
1967
  // src/composites/data-table/data-table-pagination.tsx
1907
1968
  import { ChevronLeft, ChevronRight as ChevronRight2 } from "lucide-react";
1908
- import { jsx as jsx38, jsxs as jsxs22 } from "react/jsx-runtime";
1969
+ import { jsx as jsx38, jsxs as jsxs23 } from "react/jsx-runtime";
1909
1970
  var PAGE_SIZE_OPTIONS = [
1910
1971
  { value: "10", label: "10" },
1911
1972
  { value: "25", label: "25" },
@@ -1920,8 +1981,8 @@ function DataTablePagination({
1920
1981
  }) {
1921
1982
  const totalPages = Math.max(1, Math.ceil(total / pageSize));
1922
1983
  const currentPage = page + 1;
1923
- return /* @__PURE__ */ jsxs22("div", { className: "flex items-center justify-between px-2 py-2 text-xs text-foreground-muted", children: [
1924
- /* @__PURE__ */ jsxs22("div", { className: "flex items-center gap-2", children: [
1984
+ return /* @__PURE__ */ jsxs23("div", { className: "flex items-center justify-between px-2 py-2 text-xs text-foreground-muted", children: [
1985
+ /* @__PURE__ */ jsxs23("div", { className: "flex items-center gap-2", children: [
1925
1986
  /* @__PURE__ */ jsx38("span", { children: "Rows per page" }),
1926
1987
  /* @__PURE__ */ jsx38("div", { className: "w-16", children: /* @__PURE__ */ jsx38(
1927
1988
  Select,
@@ -1935,8 +1996,8 @@ function DataTablePagination({
1935
1996
  }
1936
1997
  ) })
1937
1998
  ] }),
1938
- /* @__PURE__ */ jsxs22("div", { className: "flex items-center gap-2", children: [
1939
- /* @__PURE__ */ jsxs22("span", { children: [
1999
+ /* @__PURE__ */ jsxs23("div", { className: "flex items-center gap-2", children: [
2000
+ /* @__PURE__ */ jsxs23("span", { children: [
1940
2001
  "Page ",
1941
2002
  currentPage,
1942
2003
  " of ",
@@ -1969,7 +2030,7 @@ function DataTablePagination({
1969
2030
  }
1970
2031
 
1971
2032
  // src/composites/data-table/data-table.tsx
1972
- import { Fragment as Fragment3, jsx as jsx39, jsxs as jsxs23 } from "react/jsx-runtime";
2033
+ import { Fragment as Fragment4, jsx as jsx39, jsxs as jsxs24 } from "react/jsx-runtime";
1973
2034
  function DataTable({
1974
2035
  data,
1975
2036
  columns: userColumns,
@@ -1986,7 +2047,8 @@ function DataTable({
1986
2047
  selectable = false,
1987
2048
  compact = true,
1988
2049
  stickyHeader = false,
1989
- className
2050
+ className,
2051
+ mobileMode = "scroll"
1990
2052
  }) {
1991
2053
  const columns = useMemo2(() => {
1992
2054
  if (!selectable) return userColumns;
@@ -2038,8 +2100,70 @@ function DataTable({
2038
2100
  pageCount: pagination ? Math.ceil(pagination.total / pagination.pageSize) : void 0
2039
2101
  });
2040
2102
  const hasActions = !!rowActions;
2041
- return /* @__PURE__ */ jsxs23("div", { className: cn("overflow-auto", className), children: [
2042
- /* @__PURE__ */ jsxs23("table", { className: "w-full border-collapse", children: [
2103
+ const isMobile = useIsMobile();
2104
+ const showCards = isMobile && mobileMode === "cards";
2105
+ if (showCards) {
2106
+ const rows = table.getRowModel().rows;
2107
+ if (loading) {
2108
+ return /* @__PURE__ */ jsx39("div", { className: cn("space-y-2", className), children: Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ jsxs24("div", { className: "rounded-lg border border-border bg-surface p-3 space-y-2", children: [
2109
+ /* @__PURE__ */ jsx39(Skeleton, { className: "h-3 w-3/4" }),
2110
+ /* @__PURE__ */ jsx39(Skeleton, { className: "h-3 w-1/2" }),
2111
+ /* @__PURE__ */ jsx39(Skeleton, { className: "h-3 w-2/3" })
2112
+ ] }, i)) });
2113
+ }
2114
+ if (rows.length === 0) {
2115
+ return /* @__PURE__ */ jsx39("div", { className: cn("text-center py-8 text-xs text-foreground-muted", className), children: emptyState ?? "No data" });
2116
+ }
2117
+ return /* @__PURE__ */ jsxs24("div", { className: cn("space-y-2", className), children: [
2118
+ rows.map((row) => /* @__PURE__ */ jsxs24(
2119
+ "div",
2120
+ {
2121
+ className: cn(
2122
+ "rounded-lg border border-border bg-surface p-3 space-y-1.5",
2123
+ onRowClick && "cursor-pointer hover:bg-surface-hover transition-colors"
2124
+ ),
2125
+ onClick: onRowClick ? () => onRowClick(row.original) : void 0,
2126
+ children: [
2127
+ row.getVisibleCells().filter((cell) => cell.column.id !== "__select").map((cell) => {
2128
+ const header = cell.column.columnDef.header;
2129
+ const label = typeof header === "string" ? header : cell.column.id;
2130
+ return /* @__PURE__ */ jsxs24("div", { className: "flex items-baseline justify-between gap-2 text-xs", children: [
2131
+ /* @__PURE__ */ jsx39("span", { className: "text-foreground-muted shrink-0", children: label }),
2132
+ /* @__PURE__ */ jsx39("span", { className: "text-foreground text-right truncate", children: flexRender(cell.column.columnDef.cell, cell.getContext()) })
2133
+ ] }, cell.id);
2134
+ }),
2135
+ rowActions && /* @__PURE__ */ jsx39("div", { className: "flex items-center gap-1 pt-1 border-t border-border mt-1.5", children: rowActions(row.original).map((action, i) => /* @__PURE__ */ jsx39(
2136
+ "button",
2137
+ {
2138
+ onClick: (e) => {
2139
+ e.stopPropagation();
2140
+ action.onClick();
2141
+ },
2142
+ className: cn(
2143
+ "text-[11px] px-2 py-1 rounded-md transition-colors",
2144
+ action.variant === "danger" ? "text-danger hover:bg-danger/10" : "text-foreground-muted hover:bg-surface-hover"
2145
+ ),
2146
+ children: action.label
2147
+ },
2148
+ i
2149
+ )) })
2150
+ ]
2151
+ },
2152
+ row.id
2153
+ )),
2154
+ pagination && /* @__PURE__ */ jsx39(
2155
+ DataTablePagination,
2156
+ {
2157
+ page: pagination.page,
2158
+ pageSize: pagination.pageSize,
2159
+ total: pagination.total,
2160
+ onPaginationChange
2161
+ }
2162
+ )
2163
+ ] });
2164
+ }
2165
+ return /* @__PURE__ */ jsxs24("div", { className: cn("overflow-x-auto", className), children: [
2166
+ /* @__PURE__ */ jsxs24("table", { className: "w-full border-collapse", children: [
2043
2167
  /* @__PURE__ */ jsx39(
2044
2168
  DataTableHeader,
2045
2169
  {
@@ -2079,11 +2203,11 @@ function DataTable({
2079
2203
  ] });
2080
2204
  }
2081
2205
  function LoadingRows({ colSpan, compact }) {
2082
- return /* @__PURE__ */ jsx39(Fragment3, { children: Array.from({ length: 5 }).map((_, rowIdx) => /* @__PURE__ */ jsx39("tr", { className: compact ? "h-7" : "h-9", children: Array.from({ length: colSpan }).map((_2, colIdx) => /* @__PURE__ */ jsx39("td", { className: "px-2 py-1.5", children: /* @__PURE__ */ jsx39(Skeleton, { className: "h-3 w-full" }) }, colIdx)) }, rowIdx)) });
2206
+ return /* @__PURE__ */ jsx39(Fragment4, { children: Array.from({ length: 5 }).map((_, rowIdx) => /* @__PURE__ */ jsx39("tr", { className: compact ? "h-7" : "h-9", children: Array.from({ length: colSpan }).map((_2, colIdx) => /* @__PURE__ */ jsx39("td", { className: "px-2 py-1.5", children: /* @__PURE__ */ jsx39(Skeleton, { className: "h-3 w-full" }) }, colIdx)) }, rowIdx)) });
2083
2207
  }
2084
2208
 
2085
2209
  // src/composites/device-card.tsx
2086
- import { jsx as jsx40, jsxs as jsxs24 } from "react/jsx-runtime";
2210
+ import { jsx as jsx40, jsxs as jsxs25 } from "react/jsx-runtime";
2087
2211
  var STATUS_COLORS = {
2088
2212
  online: "bg-success",
2089
2213
  offline: "bg-danger",
@@ -2102,7 +2226,7 @@ function DeviceCard({
2102
2226
  className
2103
2227
  }) {
2104
2228
  const isOffline = status === "offline";
2105
- return /* @__PURE__ */ jsxs24(
2229
+ return /* @__PURE__ */ jsxs25(
2106
2230
  "div",
2107
2231
  {
2108
2232
  onClick,
@@ -2114,7 +2238,7 @@ function DeviceCard({
2114
2238
  className
2115
2239
  ),
2116
2240
  children: [
2117
- /* @__PURE__ */ jsxs24("div", { className: "flex items-center justify-between mb-2", children: [
2241
+ /* @__PURE__ */ jsxs25("div", { className: "flex items-center justify-between mb-2", children: [
2118
2242
  /* @__PURE__ */ jsx40("span", { className: "text-sm font-medium truncate", children: title }),
2119
2243
  status && /* @__PURE__ */ jsx40("span", { className: cn("h-2 w-2 rounded-full shrink-0", STATUS_COLORS[status]) })
2120
2244
  ] }),
@@ -2125,7 +2249,7 @@ function DeviceCard({
2125
2249
  selected ? "bg-primary/20" : "bg-surface-hover",
2126
2250
  badge.onClick && "hover:opacity-80 transition-opacity cursor-pointer"
2127
2251
  );
2128
- return badge.onClick ? /* @__PURE__ */ jsxs24(
2252
+ return badge.onClick ? /* @__PURE__ */ jsxs25(
2129
2253
  "button",
2130
2254
  {
2131
2255
  onClick: (e) => {
@@ -2139,7 +2263,7 @@ function DeviceCard({
2139
2263
  ]
2140
2264
  },
2141
2265
  i
2142
- ) : /* @__PURE__ */ jsxs24("span", { className: cls, children: [
2266
+ ) : /* @__PURE__ */ jsxs25("span", { className: cls, children: [
2143
2267
  badge.icon,
2144
2268
  badge.label
2145
2269
  ] }, i);
@@ -2190,9 +2314,9 @@ function DeviceGrid({
2190
2314
  }
2191
2315
 
2192
2316
  // src/composites/pipeline-step.tsx
2193
- import { useState as useState10 } from "react";
2317
+ import { useState as useState11 } from "react";
2194
2318
  import { ChevronRight as ChevronRight3, ChevronDown as ChevronDown2 } from "lucide-react";
2195
- import { jsx as jsx42, jsxs as jsxs25 } from "react/jsx-runtime";
2319
+ import { jsx as jsx42, jsxs as jsxs26 } from "react/jsx-runtime";
2196
2320
  var ADDON_COLORS = {
2197
2321
  "object-detection": "border-l-blue-500",
2198
2322
  "motion-detection": "border-l-amber-500",
@@ -2268,7 +2392,7 @@ function PipelineStep({
2268
2392
  onDelete,
2269
2393
  readOnly = false
2270
2394
  }) {
2271
- const [expanded, setExpanded] = useState10(false);
2395
+ const [expanded, setExpanded] = useState11(false);
2272
2396
  const color = borderColor(step.addonId, step.slot);
2273
2397
  const backends = backendsForRuntime(step.runtime, capabilities, schema);
2274
2398
  const rtOptions = runtimeOptions(capabilities);
@@ -2291,7 +2415,7 @@ function PipelineStep({
2291
2415
  if (e.target.closest(".step-config")) return;
2292
2416
  setExpanded((v) => !v);
2293
2417
  }
2294
- return /* @__PURE__ */ jsx42("div", { className: "space-y-2", children: /* @__PURE__ */ jsxs25(
2418
+ return /* @__PURE__ */ jsx42("div", { className: "space-y-2", children: /* @__PURE__ */ jsxs26(
2295
2419
  "div",
2296
2420
  {
2297
2421
  className: cn(
@@ -2300,12 +2424,12 @@ function PipelineStep({
2300
2424
  !step.enabled && "opacity-[0.45]"
2301
2425
  ),
2302
2426
  children: [
2303
- /* @__PURE__ */ jsxs25("div", { className: "flex items-center gap-2.5 px-3 py-2.5 cursor-pointer select-none", onClick: handleClick, children: [
2427
+ /* @__PURE__ */ jsxs26("div", { className: "flex items-center gap-2.5 px-3 py-2.5 cursor-pointer select-none", onClick: handleClick, children: [
2304
2428
  /* @__PURE__ */ jsx42("span", { className: "text-foreground-subtle", children: expanded ? /* @__PURE__ */ jsx42(ChevronDown2, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx42(ChevronRight3, { className: "h-4 w-4" }) }),
2305
- /* @__PURE__ */ jsxs25("div", { className: "flex-1 min-w-0", children: [
2429
+ /* @__PURE__ */ jsxs26("div", { className: "flex-1 min-w-0", children: [
2306
2430
  /* @__PURE__ */ jsx42("span", { className: "text-[10px] uppercase tracking-wider font-medium text-foreground-subtle/60 block leading-none", children: step.slot }),
2307
2431
  /* @__PURE__ */ jsx42("span", { className: "text-sm font-semibold text-foreground truncate block leading-tight", children: step.addonName }),
2308
- /* @__PURE__ */ jsxs25("div", { className: "flex items-center gap-1 mt-0.5 flex-wrap", children: [
2432
+ /* @__PURE__ */ jsxs26("div", { className: "flex items-center gap-1 mt-0.5 flex-wrap", children: [
2309
2433
  step.inputClasses.map((c) => /* @__PURE__ */ jsx42("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)),
2310
2434
  step.inputClasses.length > 0 && step.outputClasses.length > 0 && /* @__PURE__ */ jsx42("span", { className: "text-foreground-subtle/40 text-[10px]", children: "\u2192" }),
2311
2435
  step.outputClasses.map((c) => /* @__PURE__ */ jsx42("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))
@@ -2329,8 +2453,8 @@ function PipelineStep({
2329
2453
  }
2330
2454
  )
2331
2455
  ] }),
2332
- expanded && /* @__PURE__ */ jsxs25("div", { className: "step-config border-t border-border bg-background px-4 py-4 space-y-3", children: [
2333
- /* @__PURE__ */ jsxs25("div", { className: "grid grid-cols-2 gap-3", children: [
2456
+ expanded && /* @__PURE__ */ jsxs26("div", { className: "step-config border-t border-border bg-background px-4 py-4 space-y-3", children: [
2457
+ /* @__PURE__ */ jsxs26("div", { className: "grid grid-cols-2 gap-3", children: [
2334
2458
  /* @__PURE__ */ jsx42(
2335
2459
  ConfigSelect,
2336
2460
  {
@@ -2372,10 +2496,10 @@ function PipelineStep({
2372
2496
  }
2373
2497
  )
2374
2498
  ] }),
2375
- /* @__PURE__ */ jsxs25("div", { children: [
2376
- /* @__PURE__ */ jsxs25("div", { className: "flex items-center justify-between mb-1", children: [
2499
+ /* @__PURE__ */ jsxs26("div", { children: [
2500
+ /* @__PURE__ */ jsxs26("div", { className: "flex items-center justify-between mb-1", children: [
2377
2501
  /* @__PURE__ */ jsx42("span", { className: "text-[10px] font-medium text-foreground-subtle uppercase tracking-wide", children: "Confidence" }),
2378
- /* @__PURE__ */ jsxs25("span", { className: "text-xs font-medium text-foreground tabular-nums", children: [
2502
+ /* @__PURE__ */ jsxs26("span", { className: "text-xs font-medium text-foreground tabular-nums", children: [
2379
2503
  (step.confidence * 100).toFixed(0),
2380
2504
  "%"
2381
2505
  ] })
@@ -2400,9 +2524,9 @@ function PipelineStep({
2400
2524
  ) });
2401
2525
  }
2402
2526
  function ConfigSelect({ label, value, options, disabled, onChange }) {
2403
- return /* @__PURE__ */ jsxs25("div", { children: [
2527
+ return /* @__PURE__ */ jsxs26("div", { children: [
2404
2528
  /* @__PURE__ */ jsx42("label", { className: "block text-[10px] font-medium text-foreground-subtle uppercase tracking-wide mb-1.5", children: label }),
2405
- /* @__PURE__ */ jsxs25(
2529
+ /* @__PURE__ */ jsxs26(
2406
2530
  "select",
2407
2531
  {
2408
2532
  value,
@@ -2420,11 +2544,11 @@ function ConfigSelect({ label, value, options, disabled, onChange }) {
2420
2544
 
2421
2545
  // src/composites/pipeline-runtime-selector.tsx
2422
2546
  import { Cpu, Star } from "lucide-react";
2423
- import { jsx as jsx43, jsxs as jsxs26 } from "react/jsx-runtime";
2547
+ import { jsx as jsx43, jsxs as jsxs27 } from "react/jsx-runtime";
2424
2548
  function PipelineRuntimeSelector({ options, value, onChange }) {
2425
2549
  return /* @__PURE__ */ jsx43("div", { className: "flex flex-wrap gap-2", children: options.map((opt) => {
2426
2550
  const active = opt.id === value;
2427
- return /* @__PURE__ */ jsxs26(
2551
+ return /* @__PURE__ */ jsxs27(
2428
2552
  "button",
2429
2553
  {
2430
2554
  onClick: () => opt.available && onChange(opt.id),
@@ -2433,11 +2557,11 @@ function PipelineRuntimeSelector({ options, value, onChange }) {
2433
2557
  children: [
2434
2558
  /* @__PURE__ */ jsx43(Cpu, { className: "h-3.5 w-3.5 shrink-0" }),
2435
2559
  opt.label,
2436
- opt.isBest && /* @__PURE__ */ jsxs26("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: [
2560
+ opt.isBest && /* @__PURE__ */ jsxs27("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: [
2437
2561
  /* @__PURE__ */ jsx43(Star, { className: "h-2.5 w-2.5" }),
2438
2562
  "Best"
2439
2563
  ] }),
2440
- opt.platformScore != null && /* @__PURE__ */ jsxs26("span", { className: "text-[10px] text-foreground-subtle/60", children: [
2564
+ opt.platformScore != null && /* @__PURE__ */ jsxs27("span", { className: "text-[10px] text-foreground-subtle/60", children: [
2441
2565
  "(",
2442
2566
  opt.platformScore,
2443
2567
  ")"
@@ -2456,7 +2580,7 @@ function PipelineRuntimeSelector({ options, value, onChange }) {
2456
2580
  }
2457
2581
 
2458
2582
  // src/composites/pipeline-builder.tsx
2459
- import { useMemo as useMemo3, useState as useState11 } from "react";
2583
+ import { useMemo as useMemo3, useState as useState12 } from "react";
2460
2584
  import { Save, CopyPlus, Trash2, PlusCircle, X as X3 } from "lucide-react";
2461
2585
 
2462
2586
  // src/lib/validate-template.ts
@@ -2489,7 +2613,7 @@ function validateTemplate(steps, schema) {
2489
2613
  }
2490
2614
 
2491
2615
  // src/composites/pipeline-builder.tsx
2492
- import { jsx as jsx44, jsxs as jsxs27 } from "react/jsx-runtime";
2616
+ import { jsx as jsx44, jsxs as jsxs28 } from "react/jsx-runtime";
2493
2617
  function buildSchemaMap(schema) {
2494
2618
  const map = /* @__PURE__ */ new Map();
2495
2619
  for (const slot of schema.slots) {
@@ -2524,11 +2648,11 @@ function PlaceholderStep({ addon, onClick }) {
2524
2648
  type: "button",
2525
2649
  onClick,
2526
2650
  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",
2527
- children: /* @__PURE__ */ jsxs27("div", { className: "flex items-center gap-3", children: [
2651
+ children: /* @__PURE__ */ jsxs28("div", { className: "flex items-center gap-3", children: [
2528
2652
  /* @__PURE__ */ jsx44(PlusCircle, { className: "h-[18px] w-[18px] text-foreground-subtle/30 group-hover:text-primary/60 shrink-0" }),
2529
- /* @__PURE__ */ jsxs27("div", { className: "flex-1 min-w-0", children: [
2653
+ /* @__PURE__ */ jsxs28("div", { className: "flex-1 min-w-0", children: [
2530
2654
  /* @__PURE__ */ jsx44("span", { className: "text-[13px] font-medium text-foreground-subtle/50 group-hover:text-foreground-subtle block truncate", children: addon.name }),
2531
- /* @__PURE__ */ jsxs27("div", { className: "flex items-center gap-1 mt-0.5 flex-wrap", children: [
2655
+ /* @__PURE__ */ jsxs28("div", { className: "flex items-center gap-1 mt-0.5 flex-wrap", children: [
2532
2656
  addon.inputClasses.map((c) => /* @__PURE__ */ jsx44("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)),
2533
2657
  addon.inputClasses.length > 0 && addon.outputClasses.length > 0 && /* @__PURE__ */ jsx44("span", { className: "text-foreground-subtle/25 text-[10px]", children: "\u2192" }),
2534
2658
  addon.outputClasses.map((c) => /* @__PURE__ */ jsx44("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))
@@ -2554,7 +2678,7 @@ function PipelineBuilder({
2554
2678
  }) {
2555
2679
  const excluded = useMemo3(() => new Set(excludeAddons), [excludeAddons]);
2556
2680
  const schemaMap = useMemo3(() => buildSchemaMap(schema), [schema]);
2557
- const [warnings, setWarnings] = useState11([]);
2681
+ const [warnings, setWarnings] = useState12([]);
2558
2682
  const bestPlatformScore = capabilities.platformScores?.find((s) => s.available);
2559
2683
  const hasPython = capabilities.runtimes.python.available && capabilities.runtimes.python.backends.some((b) => b.available);
2560
2684
  const defaultRuntime = bestPlatformScore?.runtime ?? (hasPython ? "python" : "node");
@@ -2643,7 +2767,7 @@ function PipelineBuilder({
2643
2767
  }
2644
2768
  function renderStep(step) {
2645
2769
  const childPlaceholders = getChildPlaceholders(step);
2646
- return /* @__PURE__ */ jsxs27("div", { className: "space-y-1.5", children: [
2770
+ return /* @__PURE__ */ jsxs28("div", { className: "space-y-1.5", children: [
2647
2771
  /* @__PURE__ */ jsx44(
2648
2772
  PipelineStep,
2649
2773
  {
@@ -2656,11 +2780,11 @@ function PipelineBuilder({
2656
2780
  readOnly
2657
2781
  }
2658
2782
  ),
2659
- (step.children.length > 0 || childPlaceholders.length > 0) && /* @__PURE__ */ jsxs27("div", { className: "ml-6 pl-4 border-l-2 border-dashed border-border/40 space-y-1.5", children: [
2783
+ (step.children.length > 0 || childPlaceholders.length > 0) && /* @__PURE__ */ jsxs28("div", { className: "ml-6 pl-4 border-l-2 border-dashed border-border/40 space-y-1.5", children: [
2660
2784
  /* @__PURE__ */ jsx44("span", { className: "text-[10px] font-semibold uppercase tracking-widest text-foreground-subtle/40", children: "Slot: Cropper / Classifier" }),
2661
2785
  step.children.map((child) => {
2662
2786
  const childChildPlaceholders = getChildPlaceholders(child);
2663
- return /* @__PURE__ */ jsxs27("div", { className: "space-y-1.5", children: [
2787
+ return /* @__PURE__ */ jsxs28("div", { className: "space-y-1.5", children: [
2664
2788
  /* @__PURE__ */ jsx44(
2665
2789
  PipelineStep,
2666
2790
  {
@@ -2684,7 +2808,7 @@ function PipelineBuilder({
2684
2808
  readOnly
2685
2809
  }
2686
2810
  ),
2687
- (child.children.length > 0 || childChildPlaceholders.length > 0) && /* @__PURE__ */ jsxs27("div", { className: "ml-6 pl-4 border-l-2 border-dashed border-border/30 space-y-1.5", children: [
2811
+ (child.children.length > 0 || childChildPlaceholders.length > 0) && /* @__PURE__ */ jsxs28("div", { className: "ml-6 pl-4 border-l-2 border-dashed border-border/30 space-y-1.5", children: [
2688
2812
  /* @__PURE__ */ jsx44("span", { className: "text-[10px] font-semibold uppercase tracking-widest text-foreground-subtle/30", children: "Slot: Recognizer" }),
2689
2813
  child.children.map((grandchild) => /* @__PURE__ */ jsx44(
2690
2814
  PipelineStep,
@@ -2745,9 +2869,9 @@ function PipelineBuilder({
2745
2869
  ] }, step.addonId);
2746
2870
  }
2747
2871
  const rootSlots = schema.slots.filter((s) => s.parentSlot === null).sort((a, b) => a.priority - b.priority);
2748
- return /* @__PURE__ */ jsxs27("div", { className: "space-y-4", children: [
2749
- /* @__PURE__ */ jsx44("div", { className: "rounded-xl border border-border bg-surface p-3", children: /* @__PURE__ */ jsxs27("div", { className: "flex items-center gap-2", children: [
2750
- /* @__PURE__ */ jsx44("div", { className: "relative flex-1 min-w-0", children: /* @__PURE__ */ jsxs27(
2872
+ return /* @__PURE__ */ jsxs28("div", { className: "space-y-4", children: [
2873
+ /* @__PURE__ */ jsx44("div", { className: "rounded-xl border border-border bg-surface p-3", children: /* @__PURE__ */ jsxs28("div", { className: "flex items-center gap-2", children: [
2874
+ /* @__PURE__ */ jsx44("div", { className: "relative flex-1 min-w-0", children: /* @__PURE__ */ jsxs28(
2751
2875
  "select",
2752
2876
  {
2753
2877
  value: selectedTemplateId ?? "",
@@ -2800,12 +2924,12 @@ function PipelineBuilder({
2800
2924
  }
2801
2925
  )
2802
2926
  ] }) }),
2803
- warnings.length > 0 && /* @__PURE__ */ jsxs27("div", { className: "rounded-lg border border-amber-500/30 bg-amber-500/5 p-3 text-xs text-amber-400 space-y-1", children: [
2804
- /* @__PURE__ */ jsxs27("div", { className: "flex items-center justify-between", children: [
2927
+ warnings.length > 0 && /* @__PURE__ */ jsxs28("div", { className: "rounded-lg border border-amber-500/30 bg-amber-500/5 p-3 text-xs text-amber-400 space-y-1", children: [
2928
+ /* @__PURE__ */ jsxs28("div", { className: "flex items-center justify-between", children: [
2805
2929
  /* @__PURE__ */ jsx44("span", { className: "font-medium", children: "Template loaded with warnings:" }),
2806
2930
  /* @__PURE__ */ jsx44("button", { onClick: () => setWarnings([]), className: "text-amber-400/60 hover:text-amber-400", children: /* @__PURE__ */ jsx44(X3, { className: "h-3.5 w-3.5" }) })
2807
2931
  ] }),
2808
- warnings.map((w, i) => /* @__PURE__ */ jsxs27("div", { children: [
2932
+ warnings.map((w, i) => /* @__PURE__ */ jsxs28("div", { children: [
2809
2933
  "\u2022 ",
2810
2934
  w
2811
2935
  ] }, i))
@@ -2813,8 +2937,8 @@ function PipelineBuilder({
2813
2937
  rootSlots.map((slot) => {
2814
2938
  const slotSteps = steps.filter((s) => s.slot === slot.id && !excluded.has(s.addonId));
2815
2939
  const missingRootAddons = slot.addons.filter((a) => !existingIds.has(a.id) && !excluded.has(a.id));
2816
- return /* @__PURE__ */ jsxs27("div", { className: "space-y-2", children: [
2817
- /* @__PURE__ */ jsxs27("span", { className: "text-[10px] font-semibold uppercase tracking-widest text-foreground-subtle/50", children: [
2940
+ return /* @__PURE__ */ jsxs28("div", { className: "space-y-2", children: [
2941
+ /* @__PURE__ */ jsxs28("span", { className: "text-[10px] font-semibold uppercase tracking-widest text-foreground-subtle/50", children: [
2818
2942
  "Slot: ",
2819
2943
  slot.label
2820
2944
  ] }),
@@ -2900,7 +3024,7 @@ function getClassColor(className, customColors) {
2900
3024
 
2901
3025
  // src/composites/detection-canvas.tsx
2902
3026
  import { useRef as useRef7, useEffect as useEffect8 } from "react";
2903
- import { Fragment as Fragment4, jsx as jsx45, jsxs as jsxs28 } from "react/jsx-runtime";
3027
+ import { Fragment as Fragment5, jsx as jsx45, jsxs as jsxs29 } from "react/jsx-runtime";
2904
3028
  var DEFAULT_CLASS_COLORS = CLASS_COLORS;
2905
3029
  function DetectionCanvas({
2906
3030
  src,
@@ -2928,7 +3052,7 @@ function DetectionCanvas({
2928
3052
  className
2929
3053
  ),
2930
3054
  style: { aspectRatio: ratio },
2931
- children: src ? /* @__PURE__ */ jsxs28(Fragment4, { children: [
3055
+ children: src ? /* @__PURE__ */ jsxs29(Fragment5, { children: [
2932
3056
  /* @__PURE__ */ jsx45("img", { src, className: "absolute inset-0 w-full h-full object-fill", alt: "" }),
2933
3057
  filteredDetections.map(
2934
3058
  (d, i) => d.mask && d.maskWidth && d.maskHeight ? /* @__PURE__ */ jsx45(
@@ -2997,13 +3121,13 @@ function BoundingBox({
2997
3121
  const topPct = y1 / imageHeight * 100;
2998
3122
  const containerRef = useRef7(null);
2999
3123
  const showBelow = topPct < labelHeightPx / imageHeight * 100 * 1.5;
3000
- const labelsElement = /* @__PURE__ */ jsxs28(
3124
+ const labelsElement = /* @__PURE__ */ jsxs29(
3001
3125
  "div",
3002
3126
  {
3003
3127
  className: `absolute left-0 flex flex-col items-start gap-px ${showBelow ? "" : ""}`,
3004
3128
  style: showBelow ? { top: "100%", marginTop: "2px" } : { bottom: "100%", marginBottom: "2px" },
3005
3129
  children: [
3006
- /* @__PURE__ */ jsxs28(
3130
+ /* @__PURE__ */ jsxs29(
3007
3131
  "span",
3008
3132
  {
3009
3133
  className: "text-[10px] px-1 rounded-sm whitespace-nowrap text-white",
@@ -3014,7 +3138,7 @@ function BoundingBox({
3014
3138
  ]
3015
3139
  }
3016
3140
  ),
3017
- detection.labelsData?.map((l, k) => /* @__PURE__ */ jsxs28(
3141
+ detection.labelsData?.map((l, k) => /* @__PURE__ */ jsxs29(
3018
3142
  "span",
3019
3143
  {
3020
3144
  className: "text-[9px] font-semibold px-1 rounded-sm whitespace-nowrap text-white",
@@ -3031,7 +3155,7 @@ function BoundingBox({
3031
3155
  ]
3032
3156
  }
3033
3157
  );
3034
- return /* @__PURE__ */ jsxs28(
3158
+ return /* @__PURE__ */ jsxs29(
3035
3159
  "div",
3036
3160
  {
3037
3161
  ref: containerRef,
@@ -3133,13 +3257,13 @@ function ChildBoundingBox({
3133
3257
  const labelCount = 1 + (child.labelsData?.length ?? 0);
3134
3258
  const relTop = (cy1 - py1) / ph * 100;
3135
3259
  const showBelow = relTop < labelCount * 6;
3136
- return /* @__PURE__ */ jsxs28(
3260
+ return /* @__PURE__ */ jsxs29(
3137
3261
  "div",
3138
3262
  {
3139
3263
  className: "absolute left-0 flex flex-col items-start gap-px",
3140
3264
  style: showBelow ? { top: "100%", marginTop: "1px" } : { bottom: "100%", marginBottom: "1px" },
3141
3265
  children: [
3142
- /* @__PURE__ */ jsxs28(
3266
+ /* @__PURE__ */ jsxs29(
3143
3267
  "span",
3144
3268
  {
3145
3269
  className: "text-[9px] px-0.5 rounded-sm whitespace-nowrap text-white",
@@ -3150,7 +3274,7 @@ function ChildBoundingBox({
3150
3274
  ]
3151
3275
  }
3152
3276
  ),
3153
- child.labelsData?.map((l, k) => /* @__PURE__ */ jsxs28(
3277
+ child.labelsData?.map((l, k) => /* @__PURE__ */ jsxs29(
3154
3278
  "span",
3155
3279
  {
3156
3280
  className: "text-[8px] font-semibold px-0.5 rounded-sm whitespace-nowrap text-white",
@@ -3173,7 +3297,7 @@ function ChildBoundingBox({
3173
3297
  }
3174
3298
 
3175
3299
  // src/composites/detection-result-tree.tsx
3176
- import { jsx as jsx46, jsxs as jsxs29 } from "react/jsx-runtime";
3300
+ import { jsx as jsx46, jsxs as jsxs30 } from "react/jsx-runtime";
3177
3301
  function DetectionResultTree({
3178
3302
  detections,
3179
3303
  classColors,
@@ -3185,8 +3309,8 @@ function DetectionResultTree({
3185
3309
  if (detections.length === 0) {
3186
3310
  return /* @__PURE__ */ jsx46("div", { className: "text-sm text-foreground-subtle italic text-center py-4", children: "No detections" });
3187
3311
  }
3188
- return /* @__PURE__ */ jsxs29("div", { className, children: [
3189
- /* @__PURE__ */ jsxs29("div", { className: "text-xs font-medium text-foreground-subtle uppercase tracking-wide mb-2", children: [
3312
+ return /* @__PURE__ */ jsxs30("div", { className, children: [
3313
+ /* @__PURE__ */ jsxs30("div", { className: "text-xs font-medium text-foreground-subtle uppercase tracking-wide mb-2", children: [
3190
3314
  "Detections (",
3191
3315
  detections.length,
3192
3316
  ")"
@@ -3213,9 +3337,9 @@ function DetectionNode({
3213
3337
  }) {
3214
3338
  const color = getClassColor(detection.className, colors);
3215
3339
  const isVisible = !hiddenKeys?.has(path);
3216
- return /* @__PURE__ */ jsxs29("div", { className: `rounded-md border border-border bg-surface p-3 space-y-1 ${isVisible ? "" : "opacity-40"}`, children: [
3217
- /* @__PURE__ */ jsxs29("div", { className: "flex justify-between items-center", children: [
3218
- /* @__PURE__ */ jsxs29("div", { className: "flex items-center gap-2", children: [
3340
+ return /* @__PURE__ */ jsxs30("div", { className: `rounded-md border border-border bg-surface p-3 space-y-1 ${isVisible ? "" : "opacity-40"}`, children: [
3341
+ /* @__PURE__ */ jsxs30("div", { className: "flex justify-between items-center", children: [
3342
+ /* @__PURE__ */ jsxs30("div", { className: "flex items-center gap-2", children: [
3219
3343
  onToggleVisibility && /* @__PURE__ */ jsx46(
3220
3344
  "input",
3221
3345
  {
@@ -3233,7 +3357,7 @@ function DetectionNode({
3233
3357
  }
3234
3358
  ),
3235
3359
  /* @__PURE__ */ jsx46("span", { className: "text-sm font-medium text-foreground", children: detection.className }),
3236
- detection.mask && detection.maskWidth && detection.maskHeight && /* @__PURE__ */ jsxs29("span", { className: "text-[9px] font-mono px-1 py-0.5 rounded bg-primary/10 text-primary", children: [
3360
+ detection.mask && detection.maskWidth && detection.maskHeight && /* @__PURE__ */ jsxs30("span", { className: "text-[9px] font-mono px-1 py-0.5 rounded bg-primary/10 text-primary", children: [
3237
3361
  "mask ",
3238
3362
  detection.maskWidth,
3239
3363
  "x",
@@ -3242,19 +3366,19 @@ function DetectionNode({
3242
3366
  ] }),
3243
3367
  /* @__PURE__ */ jsx46(ConfidenceBadge, { confidence: detection.confidence })
3244
3368
  ] }),
3245
- /* @__PURE__ */ jsxs29("div", { className: "text-[10px] text-foreground-subtle font-mono", children: [
3369
+ /* @__PURE__ */ jsxs30("div", { className: "text-[10px] text-foreground-subtle font-mono", children: [
3246
3370
  "bbox: [",
3247
3371
  detection.bbox.map((v) => Math.round(v)).join(", "),
3248
3372
  "]"
3249
3373
  ] }),
3250
- detection.labelsData && detection.labelsData.length > 0 && /* @__PURE__ */ jsx46("div", { className: "flex flex-wrap gap-1 mt-1", children: detection.labelsData.map((l, k) => /* @__PURE__ */ jsxs29(
3374
+ detection.labelsData && detection.labelsData.length > 0 && /* @__PURE__ */ jsx46("div", { className: "flex flex-wrap gap-1 mt-1", children: detection.labelsData.map((l, k) => /* @__PURE__ */ jsxs30(
3251
3375
  "span",
3252
3376
  {
3253
3377
  className: "inline-flex items-center gap-1 text-[10px] font-medium px-1.5 py-0.5 rounded-full",
3254
3378
  style: { backgroundColor: getClassColor(l.addonId ?? l.label, colors) + "20", color: getClassColor(l.addonId ?? l.label, colors) },
3255
3379
  children: [
3256
3380
  l.label,
3257
- /* @__PURE__ */ jsxs29("span", { className: "opacity-60", children: [
3381
+ /* @__PURE__ */ jsxs30("span", { className: "opacity-60", children: [
3258
3382
  (l.score * 100).toFixed(0),
3259
3383
  "%"
3260
3384
  ] }),
@@ -3286,8 +3410,8 @@ function ChildrenTree({
3286
3410
  const childPath = `${parentPath}.${j}`;
3287
3411
  const childColor = getClassColor(child.className, colors);
3288
3412
  const isVisible = !hiddenKeys?.has(childPath);
3289
- return /* @__PURE__ */ jsxs29("div", { className: `text-xs space-y-0.5 ${isVisible ? "" : "opacity-40"}`, children: [
3290
- /* @__PURE__ */ jsxs29("div", { className: "flex items-center gap-1.5", children: [
3413
+ return /* @__PURE__ */ jsxs30("div", { className: `text-xs space-y-0.5 ${isVisible ? "" : "opacity-40"}`, children: [
3414
+ /* @__PURE__ */ jsxs30("div", { className: "flex items-center gap-1.5", children: [
3291
3415
  onToggleVisibility && /* @__PURE__ */ jsx46(
3292
3416
  "input",
3293
3417
  {
@@ -3305,18 +3429,18 @@ function ChildrenTree({
3305
3429
  }
3306
3430
  ),
3307
3431
  /* @__PURE__ */ jsx46("span", { className: "font-medium", style: { color: childColor }, children: child.className }),
3308
- /* @__PURE__ */ jsxs29("span", { className: "text-foreground-subtle", children: [
3432
+ /* @__PURE__ */ jsxs30("span", { className: "text-foreground-subtle", children: [
3309
3433
  (child.confidence * 100).toFixed(0),
3310
3434
  "%"
3311
3435
  ] }),
3312
- child.mask && child.maskWidth && child.maskHeight && /* @__PURE__ */ jsxs29("span", { className: "text-[9px] font-mono px-1 py-0.5 rounded bg-primary/10 text-primary", children: [
3436
+ child.mask && child.maskWidth && child.maskHeight && /* @__PURE__ */ jsxs30("span", { className: "text-[9px] font-mono px-1 py-0.5 rounded bg-primary/10 text-primary", children: [
3313
3437
  "mask ",
3314
3438
  child.maskWidth,
3315
3439
  "x",
3316
3440
  child.maskHeight
3317
3441
  ] })
3318
3442
  ] }),
3319
- child.labelsData && child.labelsData.length > 0 && /* @__PURE__ */ jsx46("div", { className: "flex flex-wrap gap-1 ml-5 mt-0.5", children: child.labelsData.map((l, k) => /* @__PURE__ */ jsxs29(
3443
+ child.labelsData && child.labelsData.length > 0 && /* @__PURE__ */ jsx46("div", { className: "flex flex-wrap gap-1 ml-5 mt-0.5", children: child.labelsData.map((l, k) => /* @__PURE__ */ jsxs30(
3320
3444
  "span",
3321
3445
  {
3322
3446
  className: "inline-flex items-center gap-0.5 text-[9px] font-medium px-1 py-0.5 rounded-full",
@@ -3324,7 +3448,7 @@ function ChildrenTree({
3324
3448
  children: [
3325
3449
  l.label,
3326
3450
  " ",
3327
- /* @__PURE__ */ jsxs29("span", { className: "opacity-60", children: [
3451
+ /* @__PURE__ */ jsxs30("span", { className: "opacity-60", children: [
3328
3452
  (l.score * 100).toFixed(0),
3329
3453
  "%"
3330
3454
  ] })
@@ -3347,30 +3471,30 @@ function ChildrenTree({
3347
3471
  }
3348
3472
  function ConfidenceBadge({ confidence }) {
3349
3473
  const level = confidence >= 0.8 ? "bg-success/10 text-success" : confidence >= 0.5 ? "bg-warning/10 text-warning" : "bg-danger/10 text-danger";
3350
- return /* @__PURE__ */ jsxs29("span", { className: `text-xs font-medium px-2 py-0.5 rounded-full ${level}`, children: [
3474
+ return /* @__PURE__ */ jsxs30("span", { className: `text-xs font-medium px-2 py-0.5 rounded-full ${level}`, children: [
3351
3475
  (confidence * 100).toFixed(1),
3352
3476
  "%"
3353
3477
  ] });
3354
3478
  }
3355
3479
 
3356
3480
  // src/composites/step-timings.tsx
3357
- import { jsx as jsx47, jsxs as jsxs30 } from "react/jsx-runtime";
3481
+ import { jsx as jsx47, jsxs as jsxs31 } from "react/jsx-runtime";
3358
3482
  function StepTimings({ timings, totalMs, className }) {
3359
3483
  const entries = Object.entries(timings);
3360
3484
  if (entries.length === 0 && totalMs === void 0) return null;
3361
- return /* @__PURE__ */ jsxs30("div", { className: `rounded-lg border border-border bg-surface p-3 space-y-2 ${className ?? ""}`, children: [
3485
+ return /* @__PURE__ */ jsxs31("div", { className: `rounded-lg border border-border bg-surface p-3 space-y-2 ${className ?? ""}`, children: [
3362
3486
  /* @__PURE__ */ jsx47("div", { className: "text-xs font-medium text-foreground-subtle uppercase tracking-wide", children: "Timings" }),
3363
- /* @__PURE__ */ jsxs30("div", { className: "space-y-1 text-xs", children: [
3364
- entries.map(([step, ms]) => /* @__PURE__ */ jsxs30("div", { className: "flex justify-between", children: [
3487
+ /* @__PURE__ */ jsxs31("div", { className: "space-y-1 text-xs", children: [
3488
+ entries.map(([step, ms]) => /* @__PURE__ */ jsxs31("div", { className: "flex justify-between", children: [
3365
3489
  /* @__PURE__ */ jsx47("span", { className: "text-foreground-subtle", children: step }),
3366
- /* @__PURE__ */ jsxs30("span", { className: "font-mono text-foreground", children: [
3490
+ /* @__PURE__ */ jsxs31("span", { className: "font-mono text-foreground", children: [
3367
3491
  ms.toFixed(1),
3368
3492
  "ms"
3369
3493
  ] })
3370
3494
  ] }, step)),
3371
- totalMs !== void 0 && /* @__PURE__ */ jsxs30("div", { className: "flex justify-between pt-1 border-t border-border font-medium text-foreground", children: [
3495
+ totalMs !== void 0 && /* @__PURE__ */ jsxs31("div", { className: "flex justify-between pt-1 border-t border-border font-medium text-foreground", children: [
3372
3496
  /* @__PURE__ */ jsx47("span", { children: "Total" }),
3373
- /* @__PURE__ */ jsxs30("span", { className: "font-mono", children: [
3497
+ /* @__PURE__ */ jsxs31("span", { className: "font-mono", children: [
3374
3498
  totalMs.toFixed(1),
3375
3499
  "ms"
3376
3500
  ] })
@@ -3380,7 +3504,7 @@ function StepTimings({ timings, totalMs, className }) {
3380
3504
  }
3381
3505
 
3382
3506
  // src/composites/image-selector.tsx
3383
- import { jsx as jsx48, jsxs as jsxs31 } from "react/jsx-runtime";
3507
+ import { jsx as jsx48, jsxs as jsxs32 } from "react/jsx-runtime";
3384
3508
  function ImageSelector({
3385
3509
  images,
3386
3510
  selectedFilename,
@@ -3406,7 +3530,7 @@ function ImageSelector({
3406
3530
  };
3407
3531
  input.click();
3408
3532
  };
3409
- return /* @__PURE__ */ jsxs31("div", { className: `flex flex-wrap items-center gap-2 ${className ?? ""}`, children: [
3533
+ return /* @__PURE__ */ jsxs32("div", { className: `flex flex-wrap items-center gap-2 ${className ?? ""}`, children: [
3410
3534
  images.map((img) => /* @__PURE__ */ jsx48(
3411
3535
  "button",
3412
3536
  {
@@ -3429,7 +3553,7 @@ function ImageSelector({
3429
3553
  }
3430
3554
 
3431
3555
  // src/composites/inference-config-selector.tsx
3432
- import { jsx as jsx49, jsxs as jsxs32 } from "react/jsx-runtime";
3556
+ import { jsx as jsx49, jsxs as jsxs33 } from "react/jsx-runtime";
3433
3557
  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";
3434
3558
  function InferenceConfigSelector({
3435
3559
  runtime,
@@ -3449,8 +3573,8 @@ function InferenceConfigSelector({
3449
3573
  showAgent = false
3450
3574
  }) {
3451
3575
  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";
3452
- return /* @__PURE__ */ jsxs32("div", { className: `${containerClass} ${className ?? ""}`, children: [
3453
- showAgent && agents.length > 0 && /* @__PURE__ */ jsxs32("label", { className: "space-y-1", children: [
3576
+ return /* @__PURE__ */ jsxs33("div", { className: `${containerClass} ${className ?? ""}`, children: [
3577
+ showAgent && agents.length > 0 && /* @__PURE__ */ jsxs33("label", { className: "space-y-1", children: [
3454
3578
  /* @__PURE__ */ jsx49("span", { className: "text-xs font-medium text-foreground-subtle", children: "Agent" }),
3455
3579
  /* @__PURE__ */ jsx49(
3456
3580
  "select",
@@ -3458,7 +3582,7 @@ function InferenceConfigSelector({
3458
3582
  value: agentId,
3459
3583
  onChange: (e) => onAgentChange?.(e.target.value),
3460
3584
  className: SELECT_CLASS,
3461
- children: agents.map((a) => /* @__PURE__ */ jsxs32("option", { value: a.id, children: [
3585
+ children: agents.map((a) => /* @__PURE__ */ jsxs33("option", { value: a.id, children: [
3462
3586
  a.name,
3463
3587
  " (",
3464
3588
  a.status,
@@ -3467,7 +3591,7 @@ function InferenceConfigSelector({
3467
3591
  }
3468
3592
  )
3469
3593
  ] }),
3470
- /* @__PURE__ */ jsxs32("label", { className: "space-y-1", children: [
3594
+ /* @__PURE__ */ jsxs33("label", { className: "space-y-1", children: [
3471
3595
  /* @__PURE__ */ jsx49("span", { className: "text-xs font-medium text-foreground-subtle", children: "Runtime" }),
3472
3596
  /* @__PURE__ */ jsx49(
3473
3597
  "select",
@@ -3475,14 +3599,14 @@ function InferenceConfigSelector({
3475
3599
  value: runtime,
3476
3600
  onChange: (e) => onRuntimeChange(e.target.value),
3477
3601
  className: SELECT_CLASS,
3478
- children: runtimes.map((r) => /* @__PURE__ */ jsxs32("option", { value: r.value, disabled: !r.available, children: [
3602
+ children: runtimes.map((r) => /* @__PURE__ */ jsxs33("option", { value: r.value, disabled: !r.available, children: [
3479
3603
  r.label,
3480
3604
  !r.available ? " (unavailable)" : ""
3481
3605
  ] }, r.value))
3482
3606
  }
3483
3607
  )
3484
3608
  ] }),
3485
- /* @__PURE__ */ jsxs32("label", { className: "space-y-1", children: [
3609
+ /* @__PURE__ */ jsxs33("label", { className: "space-y-1", children: [
3486
3610
  /* @__PURE__ */ jsx49("span", { className: "text-xs font-medium text-foreground-subtle", children: "Backend" }),
3487
3611
  /* @__PURE__ */ jsx49(
3488
3612
  "select",
@@ -3490,14 +3614,14 @@ function InferenceConfigSelector({
3490
3614
  value: backend,
3491
3615
  onChange: (e) => onBackendChange(e.target.value),
3492
3616
  className: SELECT_CLASS,
3493
- children: backends.map((b) => /* @__PURE__ */ jsxs32("option", { value: b.id, disabled: !b.available, children: [
3617
+ children: backends.map((b) => /* @__PURE__ */ jsxs33("option", { value: b.id, disabled: !b.available, children: [
3494
3618
  b.label,
3495
3619
  !b.available ? " (unavailable)" : ""
3496
3620
  ] }, b.id))
3497
3621
  }
3498
3622
  )
3499
3623
  ] }),
3500
- /* @__PURE__ */ jsxs32("label", { className: "space-y-1", children: [
3624
+ /* @__PURE__ */ jsxs33("label", { className: "space-y-1", children: [
3501
3625
  /* @__PURE__ */ jsx49("span", { className: "text-xs font-medium text-foreground-subtle", children: "Model" }),
3502
3626
  /* @__PURE__ */ jsx49(
3503
3627
  "select",
@@ -3505,7 +3629,7 @@ function InferenceConfigSelector({
3505
3629
  value: modelId,
3506
3630
  onChange: (e) => onModelChange(e.target.value),
3507
3631
  className: SELECT_CLASS,
3508
- children: models.length === 0 ? /* @__PURE__ */ jsx49("option", { value: "", children: "No compatible models" }) : models.map((m) => /* @__PURE__ */ jsxs32("option", { value: m.id, children: [
3632
+ children: models.length === 0 ? /* @__PURE__ */ jsx49("option", { value: "", children: "No compatible models" }) : models.map((m) => /* @__PURE__ */ jsxs33("option", { value: m.id, children: [
3509
3633
  m.name,
3510
3634
  m.downloaded ? " \u2713" : ""
3511
3635
  ] }, m.id))
@@ -3520,15 +3644,15 @@ import { createElement } from "react";
3520
3644
  import { createRoot } from "react-dom/client";
3521
3645
 
3522
3646
  // src/composites/dev-shell.tsx
3523
- import { createContext as createContext7, useCallback as useCallback8, useContext as useContext7, useMemo as useMemo4, useState as useState13 } from "react";
3647
+ import { createContext as createContext7, useCallback as useCallback8, useContext as useContext7, useMemo as useMemo4, useState as useState14 } from "react";
3524
3648
  import { createTRPCClient, createWSClient, wsLink, httpLink, splitLink } from "@trpc/client";
3525
3649
  import superjson from "superjson";
3526
3650
 
3527
3651
  // src/composites/login-form.tsx
3528
- import { useState as useState12 } from "react";
3529
- import { jsx as jsx50, jsxs as jsxs33 } from "react/jsx-runtime";
3652
+ import { useState as useState13 } from "react";
3653
+ import { jsx as jsx50, jsxs as jsxs34 } from "react/jsx-runtime";
3530
3654
  function EyeIcon({ className }) {
3531
- return /* @__PURE__ */ jsxs33(
3655
+ return /* @__PURE__ */ jsxs34(
3532
3656
  "svg",
3533
3657
  {
3534
3658
  xmlns: "http://www.w3.org/2000/svg",
@@ -3547,7 +3671,7 @@ function EyeIcon({ className }) {
3547
3671
  );
3548
3672
  }
3549
3673
  function EyeOffIcon({ className }) {
3550
- return /* @__PURE__ */ jsxs33(
3674
+ return /* @__PURE__ */ jsxs34(
3551
3675
  "svg",
3552
3676
  {
3553
3677
  xmlns: "http://www.w3.org/2000/svg",
@@ -3590,11 +3714,11 @@ function LoginForm({
3590
3714
  error: externalError,
3591
3715
  className
3592
3716
  }) {
3593
- const [username, setUsername] = useState12("");
3594
- const [password, setPassword] = useState12("");
3595
- const [showPassword, setShowPassword] = useState12(false);
3596
- const [submitting, setSubmitting] = useState12(false);
3597
- const [internalError, setInternalError] = useState12(null);
3717
+ const [username, setUsername] = useState13("");
3718
+ const [password, setPassword] = useState13("");
3719
+ const [showPassword, setShowPassword] = useState13(false);
3720
+ const [submitting, setSubmitting] = useState13(false);
3721
+ const [internalError, setInternalError] = useState13(null);
3598
3722
  const error = externalError ?? internalError;
3599
3723
  const handleSubmit = async (e) => {
3600
3724
  e.preventDefault();
@@ -3617,17 +3741,17 @@ function LoginForm({
3617
3741
  "flex min-h-screen items-center justify-center bg-background p-4",
3618
3742
  className
3619
3743
  ),
3620
- children: /* @__PURE__ */ jsxs33("div", { className: "w-full max-w-sm", children: [
3744
+ children: /* @__PURE__ */ jsxs34("div", { className: "w-full max-w-sm", children: [
3621
3745
  logoSrc && /* @__PURE__ */ jsx50("div", { className: "flex justify-center mb-8", children: /* @__PURE__ */ jsx50("img", { src: logoSrc, alt: "Logo", className: "h-12" }) }),
3622
3746
  serverUrl && /* @__PURE__ */ jsx50("p", { className: "mb-4 text-center text-xs text-foreground-subtle truncate", children: serverUrl }),
3623
- /* @__PURE__ */ jsxs33(
3747
+ /* @__PURE__ */ jsxs34(
3624
3748
  "form",
3625
3749
  {
3626
3750
  onSubmit: handleSubmit,
3627
3751
  className: "space-y-4 rounded-xl border border-border bg-surface p-6 shadow-xl shadow-black/10",
3628
3752
  children: [
3629
3753
  error && /* @__PURE__ */ jsx50("div", { className: "rounded-md bg-danger/10 border border-danger/20 px-3 py-2 text-xs text-danger", children: error }),
3630
- /* @__PURE__ */ jsxs33("div", { className: "space-y-1.5", children: [
3754
+ /* @__PURE__ */ jsxs34("div", { className: "space-y-1.5", children: [
3631
3755
  /* @__PURE__ */ jsx50("label", { className: "text-xs font-medium text-foreground-subtle", children: "Username" }),
3632
3756
  /* @__PURE__ */ jsx50(
3633
3757
  "input",
@@ -3641,9 +3765,9 @@ function LoginForm({
3641
3765
  }
3642
3766
  )
3643
3767
  ] }),
3644
- /* @__PURE__ */ jsxs33("div", { className: "space-y-1.5", children: [
3768
+ /* @__PURE__ */ jsxs34("div", { className: "space-y-1.5", children: [
3645
3769
  /* @__PURE__ */ jsx50("label", { className: "text-xs font-medium text-foreground-subtle", children: "Password" }),
3646
- /* @__PURE__ */ jsxs33("div", { className: "relative", children: [
3770
+ /* @__PURE__ */ jsxs34("div", { className: "relative", children: [
3647
3771
  /* @__PURE__ */ jsx50(
3648
3772
  "input",
3649
3773
  {
@@ -3667,7 +3791,7 @@ function LoginForm({
3667
3791
  )
3668
3792
  ] })
3669
3793
  ] }),
3670
- /* @__PURE__ */ jsxs33(
3794
+ /* @__PURE__ */ jsxs34(
3671
3795
  "button",
3672
3796
  {
3673
3797
  type: "submit",
@@ -3688,7 +3812,7 @@ function LoginForm({
3688
3812
  }
3689
3813
 
3690
3814
  // src/composites/dev-shell.tsx
3691
- import { jsx as jsx51, jsxs as jsxs34 } from "react/jsx-runtime";
3815
+ import { jsx as jsx51, jsxs as jsxs35 } from "react/jsx-runtime";
3692
3816
  var STORAGE_KEY = "camstack_dev_token";
3693
3817
  var DevShellContext = createContext7(null);
3694
3818
  function useDevShell() {
@@ -3703,7 +3827,7 @@ function getStoredToken() {
3703
3827
  return localStorage.getItem(STORAGE_KEY);
3704
3828
  }
3705
3829
  function SunIcon({ className }) {
3706
- return /* @__PURE__ */ jsxs34(
3830
+ return /* @__PURE__ */ jsxs35(
3707
3831
  "svg",
3708
3832
  {
3709
3833
  xmlns: "http://www.w3.org/2000/svg",
@@ -3779,15 +3903,15 @@ function DevShellInner({
3779
3903
  () => ({ trpc, token, logout: onLogout }),
3780
3904
  [trpc, token, onLogout]
3781
3905
  );
3782
- return /* @__PURE__ */ jsx51(DevShellContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs34("div", { className: "min-h-screen bg-background text-foreground", children: [
3783
- /* @__PURE__ */ jsxs34("div", { className: "flex items-center justify-between border-b border-border bg-surface px-4 py-2", children: [
3784
- /* @__PURE__ */ jsxs34("div", { className: "flex items-center gap-2", children: [
3906
+ return /* @__PURE__ */ jsx51(DevShellContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs35("div", { className: "min-h-screen bg-background text-foreground", children: [
3907
+ /* @__PURE__ */ jsxs35("div", { className: "flex items-center justify-between border-b border-border bg-surface px-4 py-2", children: [
3908
+ /* @__PURE__ */ jsxs35("div", { className: "flex items-center gap-2", children: [
3785
3909
  /* @__PURE__ */ jsx51("span", { className: "rounded bg-warning/20 px-2 py-0.5 text-xs font-bold text-warning", children: "DEV MODE" }),
3786
3910
  title && /* @__PURE__ */ jsx51("span", { className: "text-sm font-medium text-foreground", children: title }),
3787
3911
  /* @__PURE__ */ jsx51("span", { className: "text-xs text-foreground-subtle", children: serverUrl })
3788
3912
  ] }),
3789
- /* @__PURE__ */ jsxs34("div", { className: "flex items-center gap-2", children: [
3790
- /* @__PURE__ */ jsxs34(
3913
+ /* @__PURE__ */ jsxs35("div", { className: "flex items-center gap-2", children: [
3914
+ /* @__PURE__ */ jsxs35(
3791
3915
  "button",
3792
3916
  {
3793
3917
  type: "button",
@@ -3819,7 +3943,7 @@ function DevShell({
3819
3943
  serverUrl = "https://localhost:4443",
3820
3944
  title
3821
3945
  }) {
3822
- const [token, setToken] = useState13(getStoredToken);
3946
+ const [token, setToken] = useState14(getStoredToken);
3823
3947
  const handleLogin = useCallback8(
3824
3948
  async (username, password) => {
3825
3949
  const anonClient = createTRPCClient({