@gallop.software/studio 0.1.92 → 0.1.94

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.
@@ -355,16 +355,30 @@ function ProgressModal({
355
355
  " before stopping."
356
356
  ] }) : isComplete ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
357
357
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { css: styles.message, children: [
358
- "Processed ",
359
- progress.processed,
360
- " new image",
361
- progress.processed !== 1 ? "s" : "",
362
- ".",
363
- progress.alreadyProcessed !== void 0 && progress.alreadyProcessed > 0 ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
364
- " ",
365
- progress.alreadyProcessed,
366
- " already processed."
367
- ] }) : null,
358
+ progress.isScan ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
359
+ progress.alreadyProcessed !== void 0 && progress.alreadyProcessed > 0 ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
360
+ progress.alreadyProcessed,
361
+ " image",
362
+ progress.alreadyProcessed !== 1 ? "s" : "",
363
+ " already exist. "
364
+ ] }) : null,
365
+ "Scanned ",
366
+ progress.processed,
367
+ " new image",
368
+ progress.processed !== 1 ? "s" : "",
369
+ "."
370
+ ] }) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
371
+ "Processed ",
372
+ progress.processed,
373
+ " new image",
374
+ progress.processed !== 1 ? "s" : "",
375
+ ".",
376
+ progress.alreadyProcessed !== void 0 && progress.alreadyProcessed > 0 ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
377
+ " ",
378
+ progress.alreadyProcessed,
379
+ " already processed."
380
+ ] }) : null
381
+ ] }),
368
382
  progress.orphansRemoved !== void 0 && progress.orphansRemoved > 0 ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
369
383
  " Removed ",
370
384
  progress.orphansRemoved,
@@ -1093,13 +1107,385 @@ function R2SetupModal({ isOpen, onClose }) {
1093
1107
  ] }) });
1094
1108
  }
1095
1109
 
1110
+ // src/components/AddNewModal.tsx
1111
+
1112
+
1113
+
1114
+ var fadeIn3 = _react3.keyframes`
1115
+ from { opacity: 0; }
1116
+ to { opacity: 1; }
1117
+ `;
1118
+ var slideIn3 = _react3.keyframes`
1119
+ from {
1120
+ opacity: 0;
1121
+ transform: translateY(-8px) scale(0.98);
1122
+ }
1123
+ to {
1124
+ opacity: 1;
1125
+ transform: translateY(0) scale(1);
1126
+ }
1127
+ `;
1128
+ var styles4 = {
1129
+ overlay: _react3.css`
1130
+ position: fixed;
1131
+ inset: 0;
1132
+ background-color: rgba(26, 31, 54, 0.4);
1133
+ backdrop-filter: blur(4px);
1134
+ display: flex;
1135
+ align-items: center;
1136
+ justify-content: center;
1137
+ z-index: 10000;
1138
+ animation: ${fadeIn3} 0.15s ease-out;
1139
+ font-family: ${_chunkUFCWGUAGjs.fontStack};
1140
+ `,
1141
+ modal: _react3.css`
1142
+ ${_chunkUFCWGUAGjs.baseReset}
1143
+ background-color: ${_chunkUFCWGUAGjs.colors.surface};
1144
+ border-radius: 12px;
1145
+ box-shadow: 0 30px 60px -12px rgba(50, 50, 93, 0.25), 0 18px 36px -18px rgba(0, 0, 0, 0.3);
1146
+ max-width: 520px;
1147
+ width: 90%;
1148
+ animation: ${slideIn3} 0.2s ease-out;
1149
+ overflow: hidden;
1150
+ `,
1151
+ header: _react3.css`
1152
+ padding: 24px 24px 0;
1153
+ `,
1154
+ title: _react3.css`
1155
+ font-size: ${_chunkUFCWGUAGjs.fontSize.lg};
1156
+ font-weight: 600;
1157
+ color: ${_chunkUFCWGUAGjs.colors.text};
1158
+ margin: 0;
1159
+ letter-spacing: -0.02em;
1160
+ `,
1161
+ tabs: _react3.css`
1162
+ display: flex;
1163
+ gap: 0;
1164
+ margin-top: 16px;
1165
+ border-bottom: 1px solid ${_chunkUFCWGUAGjs.colors.border};
1166
+ `,
1167
+ tab: _react3.css`
1168
+ padding: 12px 20px;
1169
+ font-size: ${_chunkUFCWGUAGjs.fontSize.base};
1170
+ font-weight: 500;
1171
+ color: ${_chunkUFCWGUAGjs.colors.textSecondary};
1172
+ background: none;
1173
+ border: none;
1174
+ cursor: pointer;
1175
+ position: relative;
1176
+ transition: color 0.15s;
1177
+
1178
+ &:hover {
1179
+ color: ${_chunkUFCWGUAGjs.colors.text};
1180
+ }
1181
+ `,
1182
+ tabActive: _react3.css`
1183
+ color: ${_chunkUFCWGUAGjs.colors.primary};
1184
+
1185
+ &::after {
1186
+ content: '';
1187
+ position: absolute;
1188
+ bottom: -1px;
1189
+ left: 0;
1190
+ right: 0;
1191
+ height: 2px;
1192
+ background-color: ${_chunkUFCWGUAGjs.colors.primary};
1193
+ }
1194
+ `,
1195
+ body: _react3.css`
1196
+ padding: 24px;
1197
+ min-height: 200px;
1198
+ `,
1199
+ dropzone: _react3.css`
1200
+ border: 2px dashed ${_chunkUFCWGUAGjs.colors.border};
1201
+ border-radius: 8px;
1202
+ padding: 40px 24px;
1203
+ text-align: center;
1204
+ cursor: pointer;
1205
+ transition: all 0.15s;
1206
+
1207
+ &:hover {
1208
+ border-color: ${_chunkUFCWGUAGjs.colors.primary};
1209
+ background-color: ${_chunkUFCWGUAGjs.colors.primaryLight};
1210
+ }
1211
+ `,
1212
+ dropzoneActive: _react3.css`
1213
+ border-color: ${_chunkUFCWGUAGjs.colors.primary};
1214
+ background-color: ${_chunkUFCWGUAGjs.colors.primaryLight};
1215
+ `,
1216
+ dropzoneIcon: _react3.css`
1217
+ width: 48px;
1218
+ height: 48px;
1219
+ margin: 0 auto 16px;
1220
+ color: ${_chunkUFCWGUAGjs.colors.textMuted};
1221
+ `,
1222
+ dropzoneText: _react3.css`
1223
+ font-size: ${_chunkUFCWGUAGjs.fontSize.base};
1224
+ color: ${_chunkUFCWGUAGjs.colors.text};
1225
+ margin: 0 0 4px;
1226
+ `,
1227
+ dropzoneHint: _react3.css`
1228
+ font-size: ${_chunkUFCWGUAGjs.fontSize.sm};
1229
+ color: ${_chunkUFCWGUAGjs.colors.textSecondary};
1230
+ margin: 0;
1231
+ `,
1232
+ textarea: _react3.css`
1233
+ width: 100%;
1234
+ min-height: 150px;
1235
+ padding: 12px;
1236
+ font-size: ${_chunkUFCWGUAGjs.fontSize.sm};
1237
+ font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
1238
+ border: 1px solid ${_chunkUFCWGUAGjs.colors.border};
1239
+ border-radius: 8px;
1240
+ resize: vertical;
1241
+
1242
+ &:focus {
1243
+ outline: none;
1244
+ border-color: ${_chunkUFCWGUAGjs.colors.primary};
1245
+ box-shadow: 0 0 0 3px ${_chunkUFCWGUAGjs.colors.primaryLight};
1246
+ }
1247
+
1248
+ &::placeholder {
1249
+ color: ${_chunkUFCWGUAGjs.colors.textMuted};
1250
+ }
1251
+ `,
1252
+ textareaLabel: _react3.css`
1253
+ font-size: ${_chunkUFCWGUAGjs.fontSize.sm};
1254
+ color: ${_chunkUFCWGUAGjs.colors.textSecondary};
1255
+ margin: 0 0 8px;
1256
+ `,
1257
+ footer: _react3.css`
1258
+ display: flex;
1259
+ justify-content: flex-end;
1260
+ gap: 12px;
1261
+ padding: 16px 24px;
1262
+ border-top: 1px solid ${_chunkUFCWGUAGjs.colors.border};
1263
+ background-color: ${_chunkUFCWGUAGjs.colors.background};
1264
+ `,
1265
+ btn: _react3.css`
1266
+ padding: 10px 18px;
1267
+ font-size: ${_chunkUFCWGUAGjs.fontSize.base};
1268
+ font-weight: 500;
1269
+ border-radius: 6px;
1270
+ cursor: pointer;
1271
+ transition: all 0.15s ease;
1272
+ letter-spacing: -0.01em;
1273
+ `,
1274
+ btnCancel: _react3.css`
1275
+ background-color: ${_chunkUFCWGUAGjs.colors.surface};
1276
+ border: 1px solid ${_chunkUFCWGUAGjs.colors.border};
1277
+ color: ${_chunkUFCWGUAGjs.colors.text};
1278
+
1279
+ &:hover {
1280
+ background-color: ${_chunkUFCWGUAGjs.colors.surfaceHover};
1281
+ border-color: ${_chunkUFCWGUAGjs.colors.borderHover};
1282
+ }
1283
+ `,
1284
+ btnConfirm: _react3.css`
1285
+ background-color: ${_chunkUFCWGUAGjs.colors.primary};
1286
+ border: 1px solid ${_chunkUFCWGUAGjs.colors.primary};
1287
+ color: white;
1288
+
1289
+ &:hover:not(:disabled) {
1290
+ background-color: ${_chunkUFCWGUAGjs.colors.primaryHover};
1291
+ border-color: ${_chunkUFCWGUAGjs.colors.primaryHover};
1292
+ }
1293
+
1294
+ &:disabled {
1295
+ opacity: 0.6;
1296
+ cursor: not-allowed;
1297
+ }
1298
+ `,
1299
+ fileInput: _react3.css`
1300
+ display: none;
1301
+ `,
1302
+ selectedFiles: _react3.css`
1303
+ margin-top: 16px;
1304
+ padding: 12px;
1305
+ background-color: ${_chunkUFCWGUAGjs.colors.background};
1306
+ border-radius: 6px;
1307
+ font-size: ${_chunkUFCWGUAGjs.fontSize.sm};
1308
+ color: ${_chunkUFCWGUAGjs.colors.text};
1309
+ `
1310
+ };
1311
+ function AddNewModal({ currentPath, onClose, onUploadComplete }) {
1312
+ const [activeTab, setActiveTab] = _react.useState.call(void 0, "upload");
1313
+ const [selectedFiles, setSelectedFiles] = _react.useState.call(void 0, []);
1314
+ const [urlInput, setUrlInput] = _react.useState.call(void 0, "");
1315
+ const [isDragging, setIsDragging] = _react.useState.call(void 0, false);
1316
+ const [uploading, setUploading] = _react.useState.call(void 0, false);
1317
+ const [importing, setImporting] = _react.useState.call(void 0, false);
1318
+ const fileInputRef = _react.useRef.call(void 0, null);
1319
+ const handleFileSelect = _react.useCallback.call(void 0, (files) => {
1320
+ if (files) {
1321
+ setSelectedFiles(Array.from(files));
1322
+ }
1323
+ }, []);
1324
+ const handleDrop = _react.useCallback.call(void 0, (e) => {
1325
+ e.preventDefault();
1326
+ setIsDragging(false);
1327
+ handleFileSelect(e.dataTransfer.files);
1328
+ }, [handleFileSelect]);
1329
+ const handleUpload = _react.useCallback.call(void 0, async () => {
1330
+ if (selectedFiles.length === 0) return;
1331
+ setUploading(true);
1332
+ try {
1333
+ for (const file of selectedFiles) {
1334
+ const formData = new FormData();
1335
+ formData.append("file", file);
1336
+ formData.append("path", currentPath);
1337
+ await fetch("/api/studio/upload", {
1338
+ method: "POST",
1339
+ body: formData
1340
+ });
1341
+ }
1342
+ onUploadComplete();
1343
+ onClose();
1344
+ } catch (error) {
1345
+ console.error("Upload failed:", error);
1346
+ } finally {
1347
+ setUploading(false);
1348
+ }
1349
+ }, [selectedFiles, currentPath, onUploadComplete, onClose]);
1350
+ const handleImport = _react.useCallback.call(void 0, async () => {
1351
+ const urls = urlInput.split("\n").map((url) => url.trim()).filter((url) => url.length > 0);
1352
+ if (urls.length === 0) return;
1353
+ setImporting(true);
1354
+ try {
1355
+ const response = await fetch("/api/studio/import", {
1356
+ method: "POST",
1357
+ headers: { "Content-Type": "application/json" },
1358
+ body: JSON.stringify({ urls })
1359
+ });
1360
+ const reader = _optionalChain([response, 'access', _2 => _2.body, 'optionalAccess', _3 => _3.getReader, 'call', _4 => _4()]);
1361
+ if (!reader) throw new Error("No reader");
1362
+ const decoder = new TextDecoder();
1363
+ while (true) {
1364
+ const { done, value } = await reader.read();
1365
+ if (done) break;
1366
+ const text = decoder.decode(value);
1367
+ const lines = text.split("\n\n").filter((line) => line.startsWith("data: "));
1368
+ for (const line of lines) {
1369
+ const data = JSON.parse(line.replace("data: ", ""));
1370
+ if (data.type === "complete") {
1371
+ onUploadComplete();
1372
+ onClose();
1373
+ }
1374
+ }
1375
+ }
1376
+ } catch (error) {
1377
+ console.error("Import failed:", error);
1378
+ } finally {
1379
+ setImporting(false);
1380
+ }
1381
+ }, [urlInput, onUploadComplete, onClose]);
1382
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles4.overlay, onClick: onClose, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.modal, onClick: (e) => e.stopPropagation(), children: [
1383
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.header, children: [
1384
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles4.title, children: "Add New" }),
1385
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.tabs, children: [
1386
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1387
+ "button",
1388
+ {
1389
+ css: [styles4.tab, activeTab === "upload" && styles4.tabActive],
1390
+ onClick: () => setActiveTab("upload"),
1391
+ children: "Upload Files"
1392
+ }
1393
+ ),
1394
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1395
+ "button",
1396
+ {
1397
+ css: [styles4.tab, activeTab === "import" && styles4.tabActive],
1398
+ onClick: () => setActiveTab("import"),
1399
+ children: "Import URLs"
1400
+ }
1401
+ )
1402
+ ] })
1403
+ ] }),
1404
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles4.body, children: activeTab === "upload" ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1405
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1406
+ "div",
1407
+ {
1408
+ css: [styles4.dropzone, isDragging && styles4.dropzoneActive],
1409
+ onClick: () => _optionalChain([fileInputRef, 'access', _5 => _5.current, 'optionalAccess', _6 => _6.click, 'call', _7 => _7()]),
1410
+ onDragOver: (e) => {
1411
+ e.preventDefault();
1412
+ setIsDragging(true);
1413
+ },
1414
+ onDragLeave: () => setIsDragging(false),
1415
+ onDrop: handleDrop,
1416
+ children: [
1417
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.dropzoneIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" }) }),
1418
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles4.dropzoneText, children: "Drop files here or click to browse" }),
1419
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles4.dropzoneHint, children: "Supports images and other media files" })
1420
+ ]
1421
+ }
1422
+ ),
1423
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1424
+ "input",
1425
+ {
1426
+ ref: fileInputRef,
1427
+ type: "file",
1428
+ multiple: true,
1429
+ css: styles4.fileInput,
1430
+ onChange: (e) => handleFileSelect(e.target.files)
1431
+ }
1432
+ ),
1433
+ selectedFiles.length > 0 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.selectedFiles, children: [
1434
+ selectedFiles.length,
1435
+ " file",
1436
+ selectedFiles.length !== 1 ? "s" : "",
1437
+ " selected"
1438
+ ] })
1439
+ ] }) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1440
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles4.textareaLabel, children: "Paste image URLs (one per line)" }),
1441
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1442
+ "textarea",
1443
+ {
1444
+ css: styles4.textarea,
1445
+ value: urlInput,
1446
+ onChange: (e) => setUrlInput(e.target.value),
1447
+ placeholder: `https://cdn.example.com/photos/image1.jpg
1448
+ https://cdn.example.com/photos/image2.jpg`
1449
+ }
1450
+ )
1451
+ ] }) }),
1452
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.footer, children: [
1453
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1454
+ "button",
1455
+ {
1456
+ css: [styles4.btn, styles4.btnCancel],
1457
+ onClick: onClose,
1458
+ children: "Cancel"
1459
+ }
1460
+ ),
1461
+ activeTab === "upload" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1462
+ "button",
1463
+ {
1464
+ css: [styles4.btn, styles4.btnConfirm],
1465
+ onClick: handleUpload,
1466
+ disabled: selectedFiles.length === 0 || uploading,
1467
+ children: uploading ? "Uploading..." : "Upload"
1468
+ }
1469
+ ) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1470
+ "button",
1471
+ {
1472
+ css: [styles4.btn, styles4.btnConfirm],
1473
+ onClick: handleImport,
1474
+ disabled: !urlInput.trim() || importing,
1475
+ children: importing ? "Importing..." : "Import"
1476
+ }
1477
+ )
1478
+ ] })
1479
+ ] }) });
1480
+ }
1481
+
1096
1482
  // src/components/StudioToolbar.tsx
1097
1483
 
1098
1484
  var btnHeight = "36px";
1099
1485
  var spin = _react3.keyframes`
1100
1486
  to { transform: rotate(360deg); }
1101
1487
  `;
1102
- var styles4 = {
1488
+ var styles5 = {
1103
1489
  toolbar: _react3.css`
1104
1490
  display: flex;
1105
1491
  flex-wrap: nowrap;
@@ -1298,6 +1684,7 @@ function StudioToolbar() {
1298
1684
  const { selectedItems, viewMode, setViewMode, clearSelection, currentPath, triggerRefresh, focusedItem, scanRequested, clearScanRequest } = useStudio();
1299
1685
  const fileInputRef = _react.useRef.call(void 0, null);
1300
1686
  const abortControllerRef = _react.useRef.call(void 0, null);
1687
+ const [showAddNewModal, setShowAddNewModal] = _react.useState.call(void 0, false);
1301
1688
  const [uploading, setUploading] = _react.useState.call(void 0, false);
1302
1689
  const [scanning, setScanning] = _react.useState.call(void 0, false);
1303
1690
  const [processing, setProcessing] = _react.useState.call(void 0, false);
@@ -1306,6 +1693,7 @@ function StudioToolbar() {
1306
1693
  const [showSyncConfirm, setShowSyncConfirm] = _react.useState.call(void 0, false);
1307
1694
  const [syncImageCount, setSyncImageCount] = _react.useState.call(void 0, 0);
1308
1695
  const [showProgress, setShowProgress] = _react.useState.call(void 0, false);
1696
+ const [progressTitle, setProgressTitle] = _react.useState.call(void 0, "Processing Images");
1309
1697
  const [progressState, setProgressState] = _react.useState.call(void 0, {
1310
1698
  current: 0,
1311
1699
  total: 0,
@@ -1323,10 +1711,11 @@ function StudioToolbar() {
1323
1711
  const [pushing, setPushing] = _react.useState.call(void 0, false);
1324
1712
  const isInImagesFolder = currentPath === "public/images" || currentPath.startsWith("public/images/");
1325
1713
  const handleUpload = _react.useCallback.call(void 0, () => {
1326
- _optionalChain([fileInputRef, 'access', _2 => _2.current, 'optionalAccess', _3 => _3.click, 'call', _4 => _4()]);
1714
+ _optionalChain([fileInputRef, 'access', _8 => _8.current, 'optionalAccess', _9 => _9.click, 'call', _10 => _10()]);
1327
1715
  }, []);
1328
1716
  const handleScan = _react.useCallback.call(void 0, async () => {
1329
1717
  setScanning(true);
1718
+ setProgressTitle("Scanning Files");
1330
1719
  setShowProgress(true);
1331
1720
  setProgressState({
1332
1721
  current: 0,
@@ -1337,7 +1726,7 @@ function StudioToolbar() {
1337
1726
  });
1338
1727
  try {
1339
1728
  const response = await fetch("/api/studio/scan", { method: "POST" });
1340
- const reader = _optionalChain([response, 'access', _5 => _5.body, 'optionalAccess', _6 => _6.getReader, 'call', _7 => _7()]);
1729
+ const reader = _optionalChain([response, 'access', _11 => _11.body, 'optionalAccess', _12 => _12.getReader, 'call', _13 => _13()]);
1341
1730
  if (!reader) throw new Error("No reader");
1342
1731
  const decoder = new TextDecoder();
1343
1732
  let buffer = "";
@@ -1373,8 +1762,10 @@ function StudioToolbar() {
1373
1762
  percent: 100,
1374
1763
  status: "complete",
1375
1764
  processed: data.added,
1765
+ alreadyProcessed: data.existingCount,
1376
1766
  errors: data.errors,
1377
- message: data.renamed > 0 ? `${data.renamed} file(s) renamed due to conflicts` : void 0
1767
+ message: data.renamed > 0 ? `${data.renamed} file(s) renamed due to conflicts` : void 0,
1768
+ isScan: true
1378
1769
  });
1379
1770
  triggerRefresh();
1380
1771
  } else if (data.type === "error") {
@@ -1509,7 +1900,7 @@ function StudioToolbar() {
1509
1900
  const selectedPaths2 = Array.from(selectedItems);
1510
1901
  const imageExtensions = ["jpg", "jpeg", "png", "gif", "webp", "svg", "ico", "bmp", "tiff", "tif"];
1511
1902
  const selectedImagePaths = selectedPaths2.filter((p) => {
1512
- const ext = _optionalChain([p, 'access', _8 => _8.split, 'call', _9 => _9("."), 'access', _10 => _10.pop, 'call', _11 => _11(), 'optionalAccess', _12 => _12.toLowerCase, 'call', _13 => _13()]) || "";
1903
+ const ext = _optionalChain([p, 'access', _14 => _14.split, 'call', _15 => _15("."), 'access', _16 => _16.pop, 'call', _17 => _17(), 'optionalAccess', _18 => _18.toLowerCase, 'call', _19 => _19()]) || "";
1513
1904
  return imageExtensions.includes(ext);
1514
1905
  });
1515
1906
  const selectedFolders = selectedPaths2.filter((p) => !p.includes(".") || p.endsWith("/"));
@@ -1570,6 +1961,7 @@ function StudioToolbar() {
1570
1961
  const signal = abortControllerRef.current.signal;
1571
1962
  try {
1572
1963
  if (processMode === "all") {
1964
+ setProgressTitle("Processing Images");
1573
1965
  setShowProgress(true);
1574
1966
  setProgressState({
1575
1967
  current: 0,
@@ -1671,12 +2063,12 @@ function StudioToolbar() {
1671
2063
  const data = await response.json();
1672
2064
  if (response.ok) {
1673
2065
  setProgressState({
1674
- current: _optionalChain([data, 'access', _14 => _14.processed, 'optionalAccess', _15 => _15.length]) || 0,
1675
- total: _optionalChain([data, 'access', _16 => _16.processed, 'optionalAccess', _17 => _17.length]) || 0,
2066
+ current: _optionalChain([data, 'access', _20 => _20.processed, 'optionalAccess', _21 => _21.length]) || 0,
2067
+ total: _optionalChain([data, 'access', _22 => _22.processed, 'optionalAccess', _23 => _23.length]) || 0,
1676
2068
  percent: 100,
1677
2069
  status: "complete",
1678
- processed: _optionalChain([data, 'access', _18 => _18.processed, 'optionalAccess', _19 => _19.length]) || 0,
1679
- errors: _optionalChain([data, 'access', _20 => _20.errors, 'optionalAccess', _21 => _21.length]) || 0
2070
+ processed: _optionalChain([data, 'access', _24 => _24.processed, 'optionalAccess', _25 => _25.length]) || 0,
2071
+ errors: _optionalChain([data, 'access', _26 => _26.errors, 'optionalAccess', _27 => _27.length]) || 0
1680
2072
  });
1681
2073
  clearSelection();
1682
2074
  triggerRefresh();
@@ -1753,7 +2145,7 @@ function StudioToolbar() {
1753
2145
  const selectedPaths2 = Array.from(selectedItems);
1754
2146
  const imageExtensions = ["jpg", "jpeg", "png", "gif", "webp", "svg", "ico", "bmp", "tiff", "tif"];
1755
2147
  const selectedImagePaths = selectedPaths2.filter((p) => {
1756
- const ext = _optionalChain([p, 'access', _22 => _22.split, 'call', _23 => _23("."), 'access', _24 => _24.pop, 'call', _25 => _25(), 'optionalAccess', _26 => _26.toLowerCase, 'call', _27 => _27()]) || "";
2148
+ const ext = _optionalChain([p, 'access', _28 => _28.split, 'call', _29 => _29("."), 'access', _30 => _30.pop, 'call', _31 => _31(), 'optionalAccess', _32 => _32.toLowerCase, 'call', _33 => _33()]) || "";
1757
2149
  return imageExtensions.includes(ext);
1758
2150
  });
1759
2151
  const selectedFolders = selectedPaths2.filter((p) => !p.includes(".") || p.endsWith("/"));
@@ -1788,7 +2180,7 @@ function StudioToolbar() {
1788
2180
  const selectedPaths2 = Array.from(selectedItems);
1789
2181
  const imageExtensions = ["jpg", "jpeg", "png", "gif", "webp", "svg", "ico", "bmp", "tiff", "tif"];
1790
2182
  const selectedImagePaths = selectedPaths2.filter((p) => {
1791
- const ext = _optionalChain([p, 'access', _28 => _28.split, 'call', _29 => _29("."), 'access', _30 => _30.pop, 'call', _31 => _31(), 'optionalAccess', _32 => _32.toLowerCase, 'call', _33 => _33()]) || "";
2183
+ const ext = _optionalChain([p, 'access', _34 => _34.split, 'call', _35 => _35("."), 'access', _36 => _36.pop, 'call', _37 => _37(), 'optionalAccess', _38 => _38.toLowerCase, 'call', _39 => _39()]) || "";
1792
2184
  return imageExtensions.includes(ext);
1793
2185
  });
1794
2186
  const selectedFolders = selectedPaths2.filter((p) => !p.includes(".") || p.endsWith("/"));
@@ -1809,6 +2201,7 @@ function StudioToolbar() {
1809
2201
  }
1810
2202
  }
1811
2203
  const imageKeys = selectedImagePaths.map((p) => "/" + p.replace(/^public\//, ""));
2204
+ setProgressTitle("Pushing to CDN");
1812
2205
  setProgressState({
1813
2206
  current: 0,
1814
2207
  total: imageKeys.length,
@@ -1838,16 +2231,16 @@ function StudioToolbar() {
1838
2231
  });
1839
2232
  const data = await response.json();
1840
2233
  if (!response.ok) {
1841
- if (_optionalChain([data, 'access', _34 => _34.error, 'optionalAccess', _35 => _35.includes, 'call', _36 => _36("R2 not configured")]) || _optionalChain([data, 'access', _37 => _37.error, 'optionalAccess', _38 => _38.includes, 'call', _39 => _39("CLOUDFLARE_R2")])) {
2234
+ if (_optionalChain([data, 'access', _40 => _40.error, 'optionalAccess', _41 => _41.includes, 'call', _42 => _42("R2 not configured")]) || _optionalChain([data, 'access', _43 => _43.error, 'optionalAccess', _44 => _44.includes, 'call', _45 => _45("CLOUDFLARE_R2")])) {
1842
2235
  setShowProgress(false);
1843
2236
  setShowR2SetupModal(true);
1844
2237
  return;
1845
2238
  }
1846
2239
  errors++;
1847
2240
  errorMessages.push(data.error || `Failed: ${imageKey}`);
1848
- } else if (_optionalChain([data, 'access', _40 => _40.pushed, 'optionalAccess', _41 => _41.length]) > 0) {
2241
+ } else if (_optionalChain([data, 'access', _46 => _46.pushed, 'optionalAccess', _47 => _47.length]) > 0) {
1849
2242
  pushed++;
1850
- } else if (_optionalChain([data, 'access', _42 => _42.errors, 'optionalAccess', _43 => _43.length]) > 0) {
2243
+ } else if (_optionalChain([data, 'access', _48 => _48.errors, 'optionalAccess', _49 => _49.length]) > 0) {
1851
2244
  errors++;
1852
2245
  for (const errMsg of data.errors) {
1853
2246
  errorMessages.push(errMsg);
@@ -2011,7 +2404,7 @@ function StudioToolbar() {
2011
2404
  showProgress && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2012
2405
  ProgressModal,
2013
2406
  {
2014
- title: "Processing Images",
2407
+ title: progressTitle,
2015
2408
  progress: progressState,
2016
2409
  onStop: handleStopProcessing,
2017
2410
  onClose: () => {
@@ -2075,7 +2468,18 @@ function StudioToolbar() {
2075
2468
  onClose: () => setShowR2SetupModal(false)
2076
2469
  }
2077
2470
  ),
2078
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.toolbar, children: [
2471
+ showAddNewModal && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2472
+ AddNewModal,
2473
+ {
2474
+ currentPath,
2475
+ onClose: () => setShowAddNewModal(false),
2476
+ onUploadComplete: () => {
2477
+ setShowAddNewModal(false);
2478
+ triggerRefresh();
2479
+ }
2480
+ }
2481
+ ),
2482
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.toolbar, children: [
2079
2483
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2080
2484
  "input",
2081
2485
  {
@@ -2087,23 +2491,23 @@ function StudioToolbar() {
2087
2491
  style: { display: "none" }
2088
2492
  }
2089
2493
  ),
2090
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.left, children: [
2494
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.left, children: [
2091
2495
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2092
2496
  "button",
2093
2497
  {
2094
- css: [styles4.btn, styles4.btnPrimary],
2095
- onClick: handleUpload,
2498
+ css: [styles5.btn, styles5.btnPrimary],
2499
+ onClick: () => setShowAddNewModal(true),
2096
2500
  disabled: uploading || isInImagesFolder,
2097
2501
  children: [
2098
2502
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, UploadIcon, {}),
2099
- uploading ? "Uploading..." : "Upload"
2503
+ "Add New"
2100
2504
  ]
2101
2505
  }
2102
2506
  ),
2103
2507
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2104
2508
  "button",
2105
2509
  {
2106
- css: styles4.btn,
2510
+ css: styles5.btn,
2107
2511
  onClick: () => singleFolderSelected ? setShowRenameFolderModal(true) : setShowNewFolderModal(true),
2108
2512
  disabled: isInImagesFolder && !singleFolderSelected,
2109
2513
  title: isInImagesFolder && !singleFolderSelected ? "Cannot create folders in protected images folder" : void 0,
@@ -2113,11 +2517,11 @@ function StudioToolbar() {
2113
2517
  ]
2114
2518
  }
2115
2519
  ),
2116
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles4.divider }),
2520
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.divider }),
2117
2521
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2118
2522
  "button",
2119
2523
  {
2120
- css: styles4.btn,
2524
+ css: styles5.btn,
2121
2525
  onClick: handleProcessImages,
2122
2526
  disabled: processing || isInImagesFolder,
2123
2527
  title: isInImagesFolder ? "Cannot process images folder" : void 0,
@@ -2130,7 +2534,7 @@ function StudioToolbar() {
2130
2534
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2131
2535
  "button",
2132
2536
  {
2133
- css: [styles4.btn, styles4.btnDanger],
2537
+ css: [styles5.btn, styles5.btnDanger],
2134
2538
  onClick: handleDeleteClick,
2135
2539
  disabled: !hasSelection,
2136
2540
  children: [
@@ -2142,7 +2546,7 @@ function StudioToolbar() {
2142
2546
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2143
2547
  "button",
2144
2548
  {
2145
- css: styles4.btn,
2549
+ css: styles5.btn,
2146
2550
  onClick: handleMoveClick,
2147
2551
  disabled: !hasSelection,
2148
2552
  children: [
@@ -2154,7 +2558,7 @@ function StudioToolbar() {
2154
2558
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2155
2559
  "button",
2156
2560
  {
2157
- css: styles4.btn,
2561
+ css: styles5.btn,
2158
2562
  onClick: handleSyncClick,
2159
2563
  disabled: !hasSelection,
2160
2564
  children: [
@@ -2163,11 +2567,11 @@ function StudioToolbar() {
2163
2567
  ]
2164
2568
  }
2165
2569
  ),
2166
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.searchWrapper, children: [
2570
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.searchWrapper, children: [
2167
2571
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2168
2572
  "input",
2169
2573
  {
2170
- css: styles4.searchInput,
2574
+ css: styles5.searchInput,
2171
2575
  type: "text",
2172
2576
  placeholder: "Search images...",
2173
2577
  value: searchQuery,
@@ -2178,7 +2582,7 @@ function StudioToolbar() {
2178
2582
  searchQuery && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2179
2583
  "button",
2180
2584
  {
2181
- css: styles4.searchClearBtn,
2585
+ css: styles5.searchClearBtn,
2182
2586
  onClick: () => setSearchQuery(""),
2183
2587
  title: "Clear search",
2184
2588
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { width: "14", height: "14", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
@@ -2186,16 +2590,16 @@ function StudioToolbar() {
2186
2590
  )
2187
2591
  ] })
2188
2592
  ] }),
2189
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.right, children: [
2190
- hasSelection && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles4.selectionCount, children: [
2593
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.right, children: [
2594
+ hasSelection && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles5.selectionCount, children: [
2191
2595
  selectedItems.size,
2192
2596
  " selected",
2193
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles4.clearBtn, onClick: clearSelection, children: "Clear" })
2597
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles5.clearBtn, onClick: clearSelection, children: "Clear" })
2194
2598
  ] }),
2195
2599
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2196
2600
  "button",
2197
2601
  {
2198
- css: styles4.btn,
2602
+ css: styles5.btn,
2199
2603
  onClick: handleScan,
2200
2604
  disabled: scanning,
2201
2605
  children: [
@@ -2204,11 +2608,11 @@ function StudioToolbar() {
2204
2608
  ]
2205
2609
  }
2206
2610
  ),
2207
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.viewToggle, children: [
2611
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.viewToggle, children: [
2208
2612
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2209
2613
  "button",
2210
2614
  {
2211
- css: [styles4.viewBtn, viewMode === "grid" && styles4.viewBtnActive],
2615
+ css: [styles5.viewBtn, viewMode === "grid" && styles5.viewBtnActive],
2212
2616
  onClick: () => setViewMode("grid"),
2213
2617
  "aria-label": "Grid view",
2214
2618
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, GridIcon, {})
@@ -2217,7 +2621,7 @@ function StudioToolbar() {
2217
2621
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2218
2622
  "button",
2219
2623
  {
2220
- css: [styles4.viewBtn, viewMode === "list" && styles4.viewBtnActive],
2624
+ css: [styles5.viewBtn, viewMode === "list" && styles5.viewBtnActive],
2221
2625
  onClick: () => setViewMode("list"),
2222
2626
  "aria-label": "List view",
2223
2627
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ListIcon, {})
@@ -2229,34 +2633,34 @@ function StudioToolbar() {
2229
2633
  ] });
2230
2634
  }
2231
2635
  function UploadIcon() {
2232
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" }) });
2636
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" }) });
2233
2637
  }
2234
2638
  function ScanIcon({ spinning }) {
2235
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: [styles4.icon, spinning && styles4.iconSpin], fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" }) });
2639
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: [styles5.icon, spinning && styles5.iconSpin], fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" }) });
2236
2640
  }
2237
2641
  function TrashIcon() {
2238
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" }) });
2642
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" }) });
2239
2643
  }
2240
2644
  function FolderPlusIcon() {
2241
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 13h6m-3-3v6m-9 1V7a2 2 0 012-2h6l2 2h6a2 2 0 012 2v8a2 2 0 01-2 2H5a2 2 0 01-2-2z" }) });
2645
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 13h6m-3-3v6m-9 1V7a2 2 0 012-2h6l2 2h6a2 2 0 012 2v8a2 2 0 01-2 2H5a2 2 0 01-2-2z" }) });
2242
2646
  }
2243
2647
  function RenameIcon() {
2244
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" }) });
2648
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" }) });
2245
2649
  }
2246
2650
  function MoveIcon() {
2247
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4" }) });
2651
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4" }) });
2248
2652
  }
2249
2653
  function CloudIcon() {
2250
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" }) });
2654
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" }) });
2251
2655
  }
2252
2656
  function GridIcon() {
2253
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z" }) });
2657
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z" }) });
2254
2658
  }
2255
2659
  function ListIcon() {
2256
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6h16M4 10h16M4 14h16M4 18h16" }) });
2660
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6h16M4 10h16M4 14h16M4 18h16" }) });
2257
2661
  }
2258
2662
  function ImageStackIcon() {
2259
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) });
2663
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) });
2260
2664
  }
2261
2665
 
2262
2666
  // src/components/StudioFileGrid.tsx
@@ -2460,7 +2864,7 @@ function useFileList() {
2460
2864
  var spin2 = _react3.keyframes`
2461
2865
  to { transform: rotate(360deg); }
2462
2866
  `;
2463
- var styles5 = {
2867
+ var styles6 = {
2464
2868
  loading: _react3.css`
2465
2869
  display: flex;
2466
2870
  align-items: center;
@@ -2818,17 +3222,17 @@ function StudioFileGrid() {
2818
3222
  triggerScan
2819
3223
  } = useFileList();
2820
3224
  if (loading) {
2821
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.loading, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.spinner }) });
3225
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.loading, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.spinner }) });
2822
3226
  }
2823
3227
  if (metaEmpty && isAtRoot) {
2824
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.empty, children: [
2825
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.emptyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }),
2826
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.emptyText, children: "No files tracked yet" }),
2827
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.emptyText, children: "Click Scan to discover files in your public folder" }),
3228
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.empty, children: [
3229
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.emptyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }),
3230
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.emptyText, children: "No files tracked yet" }),
3231
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.emptyText, children: "Click Scan to discover files in your public folder" }),
2828
3232
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2829
3233
  "button",
2830
3234
  {
2831
- css: styles5.scanButton,
3235
+ css: styles6.scanButton,
2832
3236
  onClick: triggerScan,
2833
3237
  children: "Scan for Files"
2834
3238
  }
@@ -2836,19 +3240,19 @@ function StudioFileGrid() {
2836
3240
  ] });
2837
3241
  }
2838
3242
  if (sortedItems.length === 0 && isAtRoot) {
2839
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.empty, children: [
2840
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.emptyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) }),
2841
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.emptyText, children: "No files in this folder" }),
2842
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.emptyText, children: "Upload images or click Scan in the toolbar" })
3243
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.empty, children: [
3244
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.emptyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) }),
3245
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.emptyText, children: "No files in this folder" }),
3246
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.emptyText, children: "Upload images or click Scan in the toolbar" })
2843
3247
  ] });
2844
3248
  }
2845
3249
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
2846
- sortedItems.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.selectAllRow, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "label", { css: styles5.selectAllLabel, children: [
3250
+ sortedItems.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.selectAllRow, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "label", { css: styles6.selectAllLabel, children: [
2847
3251
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2848
3252
  "input",
2849
3253
  {
2850
3254
  type: "checkbox",
2851
- css: styles5.selectAllCheckbox,
3255
+ css: styles6.selectAllCheckbox,
2852
3256
  checked: allItemsSelected,
2853
3257
  ref: (el) => {
2854
3258
  if (el) el.indeterminate = someItemsSelected && !allItemsSelected;
@@ -2860,17 +3264,17 @@ function StudioFileGrid() {
2860
3264
  sortedItems.length,
2861
3265
  ")"
2862
3266
  ] }) }),
2863
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.grid, children: [
3267
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.grid, children: [
2864
3268
  !isAtRoot && !isSearching && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2865
3269
  "div",
2866
3270
  {
2867
- css: [styles5.item, styles5.parentItem],
3271
+ css: [styles6.item, styles6.parentItem],
2868
3272
  onClick: navigateUp,
2869
3273
  children: [
2870
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.content, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.parentIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M3 10h10a8 8 0 018 8v2M3 10l6 6m-6-6l6-6" }) }) }),
2871
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.label, children: [
2872
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.name, children: ".." }),
2873
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.size, children: "Parent folder" })
3274
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.content, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.parentIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M3 10h10a8 8 0 018 8v2M3 10l6 6m-6-6l6-6" }) }) }),
3275
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.label, children: [
3276
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.name, children: ".." }),
3277
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.size, children: "Parent folder" })
2874
3278
  ] })
2875
3279
  ]
2876
3280
  }
@@ -2904,43 +3308,43 @@ function GridItem({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
2904
3308
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2905
3309
  "div",
2906
3310
  {
2907
- css: [styles5.item, isSelected && styles5.itemSelected],
3311
+ css: [styles6.item, isSelected && styles6.itemSelected],
2908
3312
  onClick,
2909
3313
  children: [
2910
3314
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2911
3315
  "div",
2912
3316
  {
2913
- css: styles5.checkboxWrapper,
3317
+ css: styles6.checkboxWrapper,
2914
3318
  onClick: (e) => e.stopPropagation(),
2915
3319
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2916
3320
  "input",
2917
3321
  {
2918
3322
  type: "checkbox",
2919
- css: styles5.checkbox,
3323
+ css: styles6.checkbox,
2920
3324
  checked: isSelected,
2921
3325
  onChange: () => onClick({})
2922
3326
  }
2923
3327
  )
2924
3328
  }
2925
3329
  ),
2926
- item.cdnPushed && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles5.cdnBadge, children: "CDN" }),
2927
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.content, children: [
3330
+ item.cdnPushed && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles6.cdnBadge, children: "CDN" }),
3331
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.content, children: [
2928
3332
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2929
3333
  "button",
2930
3334
  {
2931
- css: styles5.copyBtn,
3335
+ css: styles6.copyBtn,
2932
3336
  onClick: handleCopyPath,
2933
3337
  title: "Copy file path",
2934
3338
  children: [
2935
- showCopied && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles5.tooltip, children: "Copied!" }),
2936
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" }) })
3339
+ showCopied && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles6.tooltip, children: "Copied!" }),
3340
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" }) })
2937
3341
  ]
2938
3342
  }
2939
3343
  ),
2940
3344
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2941
3345
  "button",
2942
3346
  {
2943
- css: styles5.openBtn,
3347
+ css: styles6.openBtn,
2944
3348
  onClick: (e) => {
2945
3349
  e.stopPropagation();
2946
3350
  onOpen();
@@ -2948,13 +3352,13 @@ function GridItem({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
2948
3352
  children: "Open"
2949
3353
  }
2950
3354
  ),
2951
- isFolder ? isImagesFolder ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.imagesFolderWrapper, children: [
2952
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.imagesFolderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M10 4H4a2 2 0 00-2 2v12a2 2 0 002 2h16a2 2 0 002-2V8a2 2 0 00-2-2h-8l-2-2z" }) }),
2953
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.lockIcon, fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { fillRule: "evenodd", d: "M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z", clipRule: "evenodd" }) })
2954
- ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.folderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M10 4H4a2 2 0 00-2 2v12a2 2 0 002 2h16a2 2 0 002-2V8a2 2 0 00-2-2h-8l-2-2z" }) }) : isImage && item.hasThumbnail ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3355
+ isFolder ? isImagesFolder ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.imagesFolderWrapper, children: [
3356
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.imagesFolderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M10 4H4a2 2 0 00-2 2v12a2 2 0 002 2h16a2 2 0 002-2V8a2 2 0 00-2-2h-8l-2-2z" }) }),
3357
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.lockIcon, fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { fillRule: "evenodd", d: "M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z", clipRule: "evenodd" }) })
3358
+ ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.folderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M10 4H4a2 2 0 00-2 2v12a2 2 0 002 2h16a2 2 0 002-2V8a2 2 0 00-2-2h-8l-2-2z" }) }) : isImage && item.hasThumbnail ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2955
3359
  "img",
2956
3360
  {
2957
- css: styles5.image,
3361
+ css: styles6.image,
2958
3362
  src: item.thumbnail,
2959
3363
  alt: item.name,
2960
3364
  loading: "lazy"
@@ -2962,26 +3366,26 @@ function GridItem({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
2962
3366
  ) : isImage && !item.hasThumbnail ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2963
3367
  "button",
2964
3368
  {
2965
- css: styles5.noThumbnail,
3369
+ css: styles6.noThumbnail,
2966
3370
  onClick: (e) => {
2967
3371
  e.stopPropagation();
2968
3372
  onGenerateThumbnail();
2969
3373
  },
2970
3374
  title: "Generate thumbnail",
2971
3375
  children: [
2972
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.noThumbnailIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) }),
2973
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles5.noThumbnailText, children: "Generate" })
3376
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.noThumbnailIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) }),
3377
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles6.noThumbnailText, children: "Generate" })
2974
3378
  ]
2975
3379
  }
2976
- ) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.fileIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" }) })
3380
+ ) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.fileIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" }) })
2977
3381
  ] }),
2978
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.label, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.labelRow, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.labelText, children: [
2979
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.name, title: item.name, children: truncateMiddle(item.name) }),
2980
- isFolder ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { css: styles5.size, children: [
3382
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.label, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.labelRow, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.labelText, children: [
3383
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.name, title: item.name, children: truncateMiddle(item.name) }),
3384
+ isFolder ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { css: styles6.size, children: [
2981
3385
  item.fileCount !== void 0 ? `${item.fileCount} files` : "",
2982
3386
  item.fileCount !== void 0 && item.totalSize !== void 0 ? " \xB7 " : "",
2983
3387
  item.totalSize !== void 0 ? formatFileSize(item.totalSize) : ""
2984
- ] }) : item.size !== void 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.size, children: formatFileSize(item.size) })
3388
+ ] }) : item.size !== void 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.size, children: formatFileSize(item.size) })
2985
3389
  ] }) }) })
2986
3390
  ]
2987
3391
  }
@@ -3013,7 +3417,7 @@ function truncateMiddle(str, maxLength = 24) {
3013
3417
  var spin3 = _react3.keyframes`
3014
3418
  to { transform: rotate(360deg); }
3015
3419
  `;
3016
- var styles6 = {
3420
+ var styles7 = {
3017
3421
  loading: _react3.css`
3018
3422
  display: flex;
3019
3423
  align-items: center;
@@ -3364,16 +3768,16 @@ function StudioFileList() {
3364
3768
  triggerScan
3365
3769
  } = useFileList();
3366
3770
  if (loading) {
3367
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.loading, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.spinner }) });
3771
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles7.loading, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles7.spinner }) });
3368
3772
  }
3369
3773
  if (metaEmpty && isAtRoot) {
3370
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.empty, children: [
3774
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.empty, children: [
3371
3775
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { children: "No files tracked yet" }),
3372
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.emptyHint, children: "Click Scan to discover files in your public folder" }),
3776
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles7.emptyHint, children: "Click Scan to discover files in your public folder" }),
3373
3777
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3374
3778
  "button",
3375
3779
  {
3376
- css: styles6.scanButton,
3780
+ css: styles7.scanButton,
3377
3781
  onClick: triggerScan,
3378
3782
  children: "Scan for Files"
3379
3783
  }
@@ -3381,18 +3785,18 @@ function StudioFileList() {
3381
3785
  ] });
3382
3786
  }
3383
3787
  if (sortedItems.length === 0 && isAtRoot) {
3384
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.empty, children: [
3788
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.empty, children: [
3385
3789
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { children: "No files in this folder" }),
3386
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.emptyHint, children: "Upload images or click Scan in the toolbar" })
3790
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles7.emptyHint, children: "Upload images or click Scan in the toolbar" })
3387
3791
  ] });
3388
3792
  }
3389
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.tableWrapper, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "table", { css: styles6.table, children: [
3793
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles7.tableWrapper, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "table", { css: styles7.table, children: [
3390
3794
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "thead", { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tr", { children: [
3391
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles6.th, styles6.thCheckbox], children: sortedItems.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3795
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles7.th, styles7.thCheckbox], children: sortedItems.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3392
3796
  "input",
3393
3797
  {
3394
3798
  type: "checkbox",
3395
- css: styles6.checkbox,
3799
+ css: styles7.checkbox,
3396
3800
  checked: allItemsSelected,
3397
3801
  ref: (el) => {
3398
3802
  if (el) el.indeterminate = someItemsSelected && !allItemsSelected;
@@ -3400,21 +3804,21 @@ function StudioFileList() {
3400
3804
  onChange: handleSelectAll
3401
3805
  }
3402
3806
  ) }),
3403
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: styles6.th, children: "Name" }),
3404
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles6.th, styles6.thSize], children: "Size" }),
3405
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles6.th, styles6.thDimensions], children: "Dimensions" }),
3406
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles6.th, styles6.thCdn], children: "CDN" })
3807
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: styles7.th, children: "Name" }),
3808
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles7.th, styles7.thSize], children: "Size" }),
3809
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles7.th, styles7.thDimensions], children: "Dimensions" }),
3810
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles7.th, styles7.thCdn], children: "CDN" })
3407
3811
  ] }) }),
3408
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tbody", { css: styles6.tbody, children: [
3409
- !isAtRoot && !isSearching && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tr", { css: styles6.parentRow, onClick: navigateUp, children: [
3410
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles6.td }),
3411
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles6.td, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.nameCell, children: [
3412
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.parentIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M3 10h10a8 8 0 018 8v2M3 10l6 6m-6-6l6-6" }) }),
3413
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles6.name, children: ".." })
3812
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tbody", { css: styles7.tbody, children: [
3813
+ !isAtRoot && !isSearching && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tr", { css: styles7.parentRow, onClick: navigateUp, children: [
3814
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles7.td }),
3815
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles7.td, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.nameCell, children: [
3816
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles7.parentIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M3 10h10a8 8 0 018 8v2M3 10l6 6m-6-6l6-6" }) }),
3817
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.name, children: ".." })
3414
3818
  ] }) }),
3415
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles6.td, styles6.meta], children: "--" }),
3416
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles6.td, styles6.meta], children: "Parent folder" }),
3417
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles6.td, children: "--" })
3819
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles7.td, styles7.meta], children: "--" }),
3820
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles7.td, styles7.meta], children: "Parent folder" }),
3821
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles7.td, children: "--" })
3418
3822
  ] }),
3419
3823
  sortedItems.map((item) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3420
3824
  ListRow,
@@ -3445,59 +3849,59 @@ function ListRow({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
3445
3849
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
3446
3850
  "tr",
3447
3851
  {
3448
- css: [styles6.row, isSelected && styles6.rowSelected],
3852
+ css: [styles7.row, isSelected && styles7.rowSelected],
3449
3853
  onClick,
3450
3854
  children: [
3451
3855
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3452
3856
  "td",
3453
3857
  {
3454
- css: [styles6.td, styles6.checkboxCell],
3858
+ css: [styles7.td, styles7.checkboxCell],
3455
3859
  onClick: (e) => e.stopPropagation(),
3456
3860
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3457
3861
  "input",
3458
3862
  {
3459
3863
  type: "checkbox",
3460
- css: styles6.checkbox,
3864
+ css: styles7.checkbox,
3461
3865
  checked: isSelected,
3462
3866
  onChange: () => onClick({})
3463
3867
  }
3464
3868
  )
3465
3869
  }
3466
3870
  ),
3467
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles6.td, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.nameCell, children: [
3468
- isFolder ? isImagesFolder ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.imagesFolderWrapper, children: [
3469
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.imagesFolderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M10 4H4a2 2 0 00-2 2v12a2 2 0 002 2h16a2 2 0 002-2V8a2 2 0 00-2-2h-8l-2-2z" }) }),
3470
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.lockIcon, fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { fillRule: "evenodd", d: "M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z", clipRule: "evenodd" }) })
3471
- ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.folderIconWrapper, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.folderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M10 4H4a2 2 0 00-2 2v12a2 2 0 002 2h16a2 2 0 002-2V8a2 2 0 00-2-2h-8l-2-2z" }) }) }) : isImage && item.hasThumbnail ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.thumbnailWrapper, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { css: styles6.thumbnail, src: item.thumbnail, alt: item.name, loading: "lazy" }) }) : isImage && !item.hasThumbnail ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.thumbnailWrapper, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3871
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles7.td, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.nameCell, children: [
3872
+ isFolder ? isImagesFolder ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.imagesFolderWrapper, children: [
3873
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles7.imagesFolderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M10 4H4a2 2 0 00-2 2v12a2 2 0 002 2h16a2 2 0 002-2V8a2 2 0 00-2-2h-8l-2-2z" }) }),
3874
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles7.lockIcon, fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { fillRule: "evenodd", d: "M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z", clipRule: "evenodd" }) })
3875
+ ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles7.folderIconWrapper, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles7.folderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M10 4H4a2 2 0 00-2 2v12a2 2 0 002 2h16a2 2 0 002-2V8a2 2 0 00-2-2h-8l-2-2z" }) }) }) : isImage && item.hasThumbnail ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles7.thumbnailWrapper, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { css: styles7.thumbnail, src: item.thumbnail, alt: item.name, loading: "lazy" }) }) : isImage && !item.hasThumbnail ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles7.thumbnailWrapper, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3472
3876
  "button",
3473
3877
  {
3474
- css: styles6.noThumbnail,
3878
+ css: styles7.noThumbnail,
3475
3879
  onClick: (e) => {
3476
3880
  e.stopPropagation();
3477
3881
  onGenerateThumbnail();
3478
3882
  },
3479
3883
  title: "Generate thumbnail",
3480
- children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.noThumbnailIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) })
3884
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles7.noThumbnailIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) })
3481
3885
  }
3482
- ) }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.thumbnailWrapper, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.fileIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" }) }) }),
3483
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles6.name, title: item.name, children: truncateMiddle2(item.name) }),
3484
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.actionsCell, children: [
3886
+ ) }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles7.thumbnailWrapper, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles7.fileIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" }) }) }),
3887
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.name, title: item.name, children: truncateMiddle2(item.name) }),
3888
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.actionsCell, children: [
3485
3889
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
3486
3890
  "button",
3487
3891
  {
3488
- css: styles6.copyBtn,
3892
+ css: styles7.copyBtn,
3489
3893
  onClick: handleCopyPath,
3490
3894
  title: "Copy file path",
3491
3895
  children: [
3492
- showCopied && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles6.tooltip, children: "Copied!" }),
3493
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" }) })
3896
+ showCopied && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.tooltip, children: "Copied!" }),
3897
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles7.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" }) })
3494
3898
  ]
3495
3899
  }
3496
3900
  ),
3497
3901
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3498
3902
  "button",
3499
3903
  {
3500
- css: styles6.openBtn,
3904
+ css: styles7.openBtn,
3501
3905
  onClick: (e) => {
3502
3906
  e.stopPropagation();
3503
3907
  onOpen();
@@ -3507,12 +3911,12 @@ function ListRow({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
3507
3911
  )
3508
3912
  ] })
3509
3913
  ] }) }),
3510
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles6.td, styles6.meta], children: isFolder ? item.fileCount !== void 0 ? `${item.fileCount} files` : "--" : item.size !== void 0 ? formatFileSize2(item.size) : "--" }),
3511
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles6.td, styles6.meta], children: isFolder ? item.totalSize !== void 0 ? formatFileSize2(item.totalSize) : "--" : item.dimensions ? `${item.dimensions.width}x${item.dimensions.height}` : "--" }),
3512
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles6.td, children: item.cdnPushed ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles6.cdnBadge, children: [
3513
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.cdnIcon, fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }),
3914
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles7.td, styles7.meta], children: isFolder ? item.fileCount !== void 0 ? `${item.fileCount} files` : "--" : item.size !== void 0 ? formatFileSize2(item.size) : "--" }),
3915
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles7.td, styles7.meta], children: isFolder ? item.totalSize !== void 0 ? formatFileSize2(item.totalSize) : "--" : item.dimensions ? `${item.dimensions.width}x${item.dimensions.height}` : "--" }),
3916
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles7.td, children: item.cdnPushed ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles7.cdnBadge, children: [
3917
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles7.cdnIcon, fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }),
3514
3918
  "Synced"
3515
- ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles6.cdnEmpty, children: "--" }) })
3919
+ ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.cdnEmpty, children: "--" }) })
3516
3920
  ]
3517
3921
  }
3518
3922
  );
@@ -3550,7 +3954,7 @@ function isVideoFile(filename) {
3550
3954
  const ext = filename.toLowerCase().substring(filename.lastIndexOf("."));
3551
3955
  return VIDEO_EXTENSIONS.includes(ext);
3552
3956
  }
3553
- var styles7 = {
3957
+ var styles8 = {
3554
3958
  overlay: _react3.css`
3555
3959
  position: absolute;
3556
3960
  top: 0;
@@ -3894,7 +4298,7 @@ function StudioDetailView() {
3894
4298
  });
3895
4299
  triggerRefresh();
3896
4300
  } else {
3897
- if (_optionalChain([data, 'access', _44 => _44.error, 'optionalAccess', _45 => _45.includes, 'call', _46 => _46("R2 not configured")]) || _optionalChain([data, 'access', _47 => _47.error, 'optionalAccess', _48 => _48.includes, 'call', _49 => _49("CLOUDFLARE_R2")])) {
4301
+ if (_optionalChain([data, 'access', _50 => _50.error, 'optionalAccess', _51 => _51.includes, 'call', _52 => _52("R2 not configured")]) || _optionalChain([data, 'access', _53 => _53.error, 'optionalAccess', _54 => _54.includes, 'call', _55 => _55("CLOUDFLARE_R2")])) {
3898
4302
  setShowR2SetupModal(true);
3899
4303
  } else {
3900
4304
  setAlertMessage({
@@ -3933,7 +4337,7 @@ function StudioDetailView() {
3933
4337
  if (!response.ok) {
3934
4338
  throw new Error("Processing failed");
3935
4339
  }
3936
- const reader = _optionalChain([response, 'access', _50 => _50.body, 'optionalAccess', _51 => _51.getReader, 'call', _52 => _52()]);
4340
+ const reader = _optionalChain([response, 'access', _56 => _56.body, 'optionalAccess', _57 => _57.getReader, 'call', _58 => _58()]);
3937
4341
  if (!reader) {
3938
4342
  throw new Error("No response body");
3939
4343
  }
@@ -3969,14 +4373,14 @@ function StudioDetailView() {
3969
4373
  };
3970
4374
  const renderMedia = () => {
3971
4375
  if (isImage) {
3972
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { css: styles7.image, src: imageSrc, alt: focusedItem.name });
4376
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { css: styles8.image, src: imageSrc, alt: focusedItem.name });
3973
4377
  }
3974
4378
  if (isVideo) {
3975
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "video", { css: styles7.video, src: imageSrc, controls: true });
4379
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "video", { css: styles8.video, src: imageSrc, controls: true });
3976
4380
  }
3977
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.filePlaceholder, children: [
3978
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles7.fileIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" }) }),
3979
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles7.fileName, children: focusedItem.name })
4381
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.filePlaceholder, children: [
4382
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles8.fileIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" }) }),
4383
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles8.fileName, children: focusedItem.name })
3980
4384
  ] });
3981
4385
  };
3982
4386
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
@@ -4036,61 +4440,61 @@ function StudioDetailView() {
4036
4440
  onClose: () => setProcessProgress(null)
4037
4441
  }
4038
4442
  ),
4039
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles7.overlay, onClick: handleClose, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.container, onClick: (e) => e.stopPropagation(), children: [
4040
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.main, children: [
4041
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.headerButtons, children: [
4042
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles7.copyBtn, onClick: handleCopyPath, title: "Copy file path", children: [
4043
- showCopied && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.tooltip, children: "Copied!" }),
4044
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles7.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" }) })
4443
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles8.overlay, onClick: handleClose, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.container, onClick: (e) => e.stopPropagation(), children: [
4444
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.main, children: [
4445
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.headerButtons, children: [
4446
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles8.copyBtn, onClick: handleCopyPath, title: "Copy file path", children: [
4447
+ showCopied && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles8.tooltip, children: "Copied!" }),
4448
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles8.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" }) })
4045
4449
  ] }),
4046
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles7.mainCloseBtn, onClick: handleClose, "aria-label": "Close", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles7.mainCloseIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })
4450
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles8.mainCloseBtn, onClick: handleClose, "aria-label": "Close", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles8.mainCloseIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })
4047
4451
  ] }),
4048
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles7.mediaWrapper, children: renderMedia() })
4452
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles8.mediaWrapper, children: renderMedia() })
4049
4453
  ] }),
4050
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.sidebar, children: [
4051
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles7.sidebarHeader, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles7.sidebarTitle, children: "Details" }) }),
4052
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.sidebarContent, children: [
4053
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.info, children: [
4054
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.infoRow, children: [
4055
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoLabel, children: "Name" }),
4056
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoValueWrap, children: focusedItem.name })
4454
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.sidebar, children: [
4455
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles8.sidebarHeader, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles8.sidebarTitle, children: "Details" }) }),
4456
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.sidebarContent, children: [
4457
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.info, children: [
4458
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.infoRow, children: [
4459
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles8.infoLabel, children: "Name" }),
4460
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles8.infoValueWrap, children: focusedItem.name })
4057
4461
  ] }),
4058
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.infoRow, children: [
4059
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoLabel, children: "Path" }),
4060
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoValueWrap, children: focusedItem.path.replace(/^public\//, "") })
4462
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.infoRow, children: [
4463
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles8.infoLabel, children: "Path" }),
4464
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles8.infoValueWrap, children: focusedItem.path.replace(/^public\//, "") })
4061
4465
  ] }),
4062
- focusedItem.size !== void 0 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.infoRow, children: [
4063
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoLabel, children: "Size" }),
4064
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoValue, children: formatFileSize3(focusedItem.size) })
4466
+ focusedItem.size !== void 0 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.infoRow, children: [
4467
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles8.infoLabel, children: "Size" }),
4468
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles8.infoValue, children: formatFileSize3(focusedItem.size) })
4065
4469
  ] }),
4066
- focusedItem.dimensions && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.infoRow, children: [
4067
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoLabel, children: "Dimensions" }),
4068
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles7.infoValue, children: [
4470
+ focusedItem.dimensions && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.infoRow, children: [
4471
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles8.infoLabel, children: "Dimensions" }),
4472
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles8.infoValue, children: [
4069
4473
  focusedItem.dimensions.width,
4070
4474
  " \xD7 ",
4071
4475
  focusedItem.dimensions.height
4072
4476
  ] })
4073
4477
  ] }),
4074
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.infoRow, children: [
4075
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoLabel, children: "CDN Status" }),
4076
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoValue, children: focusedItem.cdnPushed ? "Pushed" : "Not pushed" })
4478
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.infoRow, children: [
4479
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles8.infoLabel, children: "CDN Status" }),
4480
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles8.infoValue, children: focusedItem.cdnPushed ? "Pushed" : "Not pushed" })
4077
4481
  ] })
4078
4482
  ] }),
4079
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.actions, children: [
4080
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles7.actionBtn, onClick: () => setShowRenameModal(true), children: [
4081
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles7.actionIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" }) }),
4483
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.actions, children: [
4484
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles8.actionBtn, onClick: () => setShowRenameModal(true), children: [
4485
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles8.actionIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" }) }),
4082
4486
  "Rename"
4083
4487
  ] }),
4084
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles7.actionBtn, onClick: handleSync, disabled: pushing, children: [
4085
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles7.actionIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" }) }),
4488
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles8.actionBtn, onClick: handleSync, disabled: pushing, children: [
4489
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles8.actionIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" }) }),
4086
4490
  syncing ? "Pushing..." : "Push to CDN"
4087
4491
  ] }),
4088
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles7.actionBtn, onClick: () => setShowProcessConfirm(true), children: [
4089
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles7.actionIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) }),
4492
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles8.actionBtn, onClick: () => setShowProcessConfirm(true), children: [
4493
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles8.actionIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) }),
4090
4494
  "Process Image"
4091
4495
  ] }),
4092
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: [styles7.actionBtn, styles7.actionBtnDanger], onClick: () => setShowDeleteConfirm(true), children: [
4093
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles7.actionIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" }) }),
4496
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: [styles8.actionBtn, styles8.actionBtnDanger], onClick: () => setShowDeleteConfirm(true), children: [
4497
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles8.actionIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" }) }),
4094
4498
  "Delete"
4095
4499
  ] })
4096
4500
  ] })
@@ -4110,7 +4514,7 @@ function formatFileSize3(bytes) {
4110
4514
 
4111
4515
 
4112
4516
  var btnHeight2 = "36px";
4113
- var styles8 = {
4517
+ var styles9 = {
4114
4518
  btn: _react3.css`
4115
4519
  height: ${btnHeight2};
4116
4520
  padding: 0 12px;
@@ -4343,15 +4747,94 @@ var styles8 = {
4343
4747
  background-color: ${_chunkUFCWGUAGjs.colors.primaryHover};
4344
4748
  border-color: ${_chunkUFCWGUAGjs.colors.primaryHover};
4345
4749
  }
4750
+
4751
+ &:disabled {
4752
+ opacity: 0.6;
4753
+ cursor: not-allowed;
4754
+ }
4755
+ `,
4756
+ cdnList: _react3.css`
4757
+ display: flex;
4758
+ flex-direction: column;
4759
+ gap: 8px;
4760
+ `,
4761
+ cdnRow: _react3.css`
4762
+ display: flex;
4763
+ gap: 8px;
4764
+ align-items: center;
4765
+ `,
4766
+ cdnInput: _react3.css`
4767
+ flex: 1;
4768
+ padding: 8px 12px;
4769
+ border: 1px solid ${_chunkUFCWGUAGjs.colors.border};
4770
+ border-radius: 6px;
4771
+ font-size: ${_chunkUFCWGUAGjs.fontSize.sm};
4772
+ color: ${_chunkUFCWGUAGjs.colors.text};
4773
+ background: ${_chunkUFCWGUAGjs.colors.surface};
4774
+ transition: all 0.15s ease;
4775
+
4776
+ &:focus {
4777
+ outline: none;
4778
+ border-color: ${_chunkUFCWGUAGjs.colors.primary};
4779
+ box-shadow: 0 0 0 3px ${_chunkUFCWGUAGjs.colors.primaryLight};
4780
+ }
4781
+ `,
4782
+ cdnIndex: _react3.css`
4783
+ font-size: ${_chunkUFCWGUAGjs.fontSize.xs};
4784
+ color: ${_chunkUFCWGUAGjs.colors.textMuted};
4785
+ width: 24px;
4786
+ text-align: center;
4787
+ flex-shrink: 0;
4788
+ `,
4789
+ cdnDeleteBtn: _react3.css`
4790
+ padding: 6px;
4791
+ background: none;
4792
+ border: none;
4793
+ cursor: pointer;
4794
+ color: ${_chunkUFCWGUAGjs.colors.textMuted};
4795
+ transition: color 0.15s;
4796
+ flex-shrink: 0;
4797
+
4798
+ &:hover {
4799
+ color: ${_chunkUFCWGUAGjs.colors.danger};
4800
+ }
4801
+ `,
4802
+ cdnAddBtn: _react3.css`
4803
+ padding: 8px 12px;
4804
+ font-size: ${_chunkUFCWGUAGjs.fontSize.sm};
4805
+ font-weight: 500;
4806
+ color: ${_chunkUFCWGUAGjs.colors.primary};
4807
+ background: ${_chunkUFCWGUAGjs.colors.primaryLight};
4808
+ border: 1px dashed ${_chunkUFCWGUAGjs.colors.primary};
4809
+ border-radius: 6px;
4810
+ cursor: pointer;
4811
+ transition: all 0.15s ease;
4812
+ display: flex;
4813
+ align-items: center;
4814
+ justify-content: center;
4815
+ gap: 6px;
4816
+ margin-top: 8px;
4817
+
4818
+ &:hover {
4819
+ background: ${_chunkUFCWGUAGjs.colors.surface};
4820
+ }
4821
+ `,
4822
+ warning: _react3.css`
4823
+ font-size: ${_chunkUFCWGUAGjs.fontSize.xs};
4824
+ color: ${_chunkUFCWGUAGjs.colors.danger};
4825
+ margin-top: 8px;
4826
+ padding: 8px 12px;
4827
+ background: ${_chunkUFCWGUAGjs.colors.dangerLight};
4828
+ border-radius: 6px;
4346
4829
  `
4347
4830
  };
4348
4831
  function StudioSettings() {
4349
4832
  const [isOpen, setIsOpen] = _react.useState.call(void 0, false);
4350
4833
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
4351
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles8.btn, onClick: () => setIsOpen(true), "aria-label": "Settings", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
4834
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles9.btn, onClick: () => setIsOpen(true), "aria-label": "Settings", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
4352
4835
  "svg",
4353
4836
  {
4354
- css: styles8.icon,
4837
+ css: styles9.icon,
4355
4838
  xmlns: "http://www.w3.org/2000/svg",
4356
4839
  viewBox: "0 0 24 24",
4357
4840
  fill: "none",
@@ -4374,56 +4857,143 @@ CLOUDFLARE_R2_SECRET_ACCESS_KEY=your_secret_access_key_here
4374
4857
  CLOUDFLARE_R2_BUCKET_NAME=my-images-bucket
4375
4858
  CLOUDFLARE_R2_PUBLIC_URL=https://cdn.yourdomain.com`;
4376
4859
  function SettingsPanel({ onClose }) {
4860
+ const { triggerRefresh } = useStudio();
4377
4861
  const [copied, setCopied] = _react.useState.call(void 0, false);
4862
+ const [cdnUrls, setCdnUrls] = _react.useState.call(void 0, []);
4863
+ const [loading, setLoading] = _react.useState.call(void 0, true);
4864
+ const [saving, setSaving] = _react.useState.call(void 0, false);
4865
+ const [hasChanges, setHasChanges] = _react.useState.call(void 0, false);
4866
+ _react.useEffect.call(void 0, () => {
4867
+ async function loadCdns() {
4868
+ try {
4869
+ const response = await fetch("/api/studio/cdns");
4870
+ const data = await response.json();
4871
+ setCdnUrls(data.cdns || []);
4872
+ } catch (error) {
4873
+ console.error("Failed to load CDN URLs:", error);
4874
+ } finally {
4875
+ setLoading(false);
4876
+ }
4877
+ }
4878
+ loadCdns();
4879
+ }, []);
4378
4880
  const handleCopy = () => {
4379
4881
  navigator.clipboard.writeText(envTemplate);
4380
4882
  setCopied(true);
4381
4883
  setTimeout(() => setCopied(false), 2e3);
4382
4884
  };
4383
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles8.overlay, onClick: onClose, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.panel, onClick: (e) => e.stopPropagation(), children: [
4384
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.header, children: [
4385
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { css: styles8.title, children: "Settings" }),
4386
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles8.closeBtn, onClick: onClose, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles8.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })
4885
+ const handleCdnChange = _react.useCallback.call(void 0, (index, value) => {
4886
+ setCdnUrls((prev) => {
4887
+ const updated = [...prev];
4888
+ updated[index] = value;
4889
+ return updated;
4890
+ });
4891
+ setHasChanges(true);
4892
+ }, []);
4893
+ const handleAddCdn = _react.useCallback.call(void 0, () => {
4894
+ setCdnUrls((prev) => [...prev, ""]);
4895
+ setHasChanges(true);
4896
+ }, []);
4897
+ const handleDeleteCdn = _react.useCallback.call(void 0, (index) => {
4898
+ setCdnUrls((prev) => prev.filter((_, i) => i !== index));
4899
+ setHasChanges(true);
4900
+ }, []);
4901
+ const handleSave = _react.useCallback.call(void 0, async () => {
4902
+ setSaving(true);
4903
+ try {
4904
+ const response = await fetch("/api/studio/cdns", {
4905
+ method: "POST",
4906
+ headers: { "Content-Type": "application/json" },
4907
+ body: JSON.stringify({ cdns: cdnUrls.filter((url) => url.trim()) })
4908
+ });
4909
+ if (response.ok) {
4910
+ setHasChanges(false);
4911
+ triggerRefresh();
4912
+ onClose();
4913
+ }
4914
+ } catch (error) {
4915
+ console.error("Failed to save CDN URLs:", error);
4916
+ } finally {
4917
+ setSaving(false);
4918
+ }
4919
+ }, [cdnUrls, triggerRefresh, onClose]);
4920
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles9.overlay, onClick: onClose, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles9.panel, onClick: (e) => e.stopPropagation(), children: [
4921
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles9.header, children: [
4922
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { css: styles9.title, children: "Settings" }),
4923
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles9.closeBtn, onClick: onClose, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles9.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })
4387
4924
  ] }),
4388
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.sections, children: [
4925
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles9.sections, children: [
4389
4926
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "section", { children: [
4390
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles8.sectionTitle, children: "Cloudflare R2" }),
4391
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles8.description, children: "Configure in .env.local file:" }),
4392
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.codeWrapper, children: [
4393
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles8.copyBtn, onClick: handleCopy, title: "Copy to clipboard", children: [
4394
- copied && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles8.tooltip, children: "Copied!" }),
4395
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles8.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" }) })
4927
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles9.sectionTitle, children: "CDN URLs" }),
4928
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles9.description, children: "Manage CDN base URLs used by your images:" }),
4929
+ loading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles9.description, children: "Loading..." }) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
4930
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles9.cdnList, children: cdnUrls.map((url, index) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles9.cdnRow, children: [
4931
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles9.cdnIndex, children: index }),
4932
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4933
+ "input",
4934
+ {
4935
+ css: styles9.cdnInput,
4936
+ type: "text",
4937
+ value: url,
4938
+ onChange: (e) => handleCdnChange(index, e.target.value),
4939
+ placeholder: "https://cdn.example.com"
4940
+ }
4941
+ ),
4942
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4943
+ "button",
4944
+ {
4945
+ css: styles9.cdnDeleteBtn,
4946
+ onClick: () => handleDeleteCdn(index),
4947
+ title: "Delete CDN URL",
4948
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { width: "16", height: "16", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" }) })
4949
+ }
4950
+ )
4951
+ ] }, index)) }),
4952
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles9.cdnAddBtn, onClick: handleAddCdn, children: [
4953
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { width: "14", height: "14", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 4v16m8-8H4" }) }),
4954
+ "Add CDN URL"
4955
+ ] }),
4956
+ cdnUrls.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles9.warning, children: "Warning: Changing CDN URLs may break image references. The index numbers correspond to image `c` values." })
4957
+ ] })
4958
+ ] }),
4959
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "section", { children: [
4960
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles9.sectionTitle, children: "Cloudflare R2 Credentials" }),
4961
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles9.description, children: "Configure in .env.local file:" }),
4962
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles9.codeWrapper, children: [
4963
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles9.copyBtn, onClick: handleCopy, title: "Copy to clipboard", children: [
4964
+ copied && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles9.tooltip, children: "Copied!" }),
4965
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles9.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" }) })
4396
4966
  ] }),
4397
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.code, children: [
4398
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles8.codeLine, children: "CLOUDFLARE_R2_ACCOUNT_ID=abc123def456ghi789" }),
4399
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles8.codeLine, children: "CLOUDFLARE_R2_ACCESS_KEY_ID=your_access_key_id_here" }),
4400
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles8.codeLine, children: "CLOUDFLARE_R2_SECRET_ACCESS_KEY=your_secret_access_key_here" }),
4401
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles8.codeLine, children: "CLOUDFLARE_R2_BUCKET_NAME=my-images-bucket" }),
4402
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles8.codeLine, children: "CLOUDFLARE_R2_PUBLIC_URL=https://cdn.yourdomain.com" })
4967
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles9.code, children: [
4968
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles9.codeLine, children: "CLOUDFLARE_R2_ACCOUNT_ID=abc123def456ghi789" }),
4969
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles9.codeLine, children: "CLOUDFLARE_R2_ACCESS_KEY_ID=your_access_key_id_here" }),
4970
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles9.codeLine, children: "CLOUDFLARE_R2_SECRET_ACCESS_KEY=your_secret_access_key_here" }),
4971
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles9.codeLine, children: "CLOUDFLARE_R2_BUCKET_NAME=my-images-bucket" }),
4972
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles9.codeLine, children: "CLOUDFLARE_R2_PUBLIC_URL=https://cdn.yourdomain.com" })
4403
4973
  ] })
4404
4974
  ] })
4405
4975
  ] }),
4406
4976
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "section", { children: [
4407
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles8.sectionTitle, children: "Thumbnail Sizes" }),
4408
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.grid, children: [
4977
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles9.sectionTitle, children: "Thumbnail Sizes" }),
4978
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles9.grid, children: [
4409
4979
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
4410
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css: styles8.label, children: "Small" }),
4411
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles8.input, type: "number", defaultValue: 300 })
4980
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css: styles9.label, children: "Small" }),
4981
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles9.input, type: "number", defaultValue: 300 })
4412
4982
  ] }),
4413
4983
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
4414
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css: styles8.label, children: "Medium" }),
4415
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles8.input, type: "number", defaultValue: 700 })
4984
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css: styles9.label, children: "Medium" }),
4985
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles9.input, type: "number", defaultValue: 700 })
4416
4986
  ] }),
4417
4987
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
4418
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css: styles8.label, children: "Large" }),
4419
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles8.input, type: "number", defaultValue: 1400 })
4988
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css: styles9.label, children: "Large" }),
4989
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles9.input, type: "number", defaultValue: 1400 })
4420
4990
  ] })
4421
4991
  ] })
4422
4992
  ] })
4423
4993
  ] }),
4424
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.footer, children: [
4425
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles8.cancelBtn, onClick: onClose, children: "Cancel" }),
4426
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles8.saveBtn, children: "Save Changes" })
4994
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles9.footer, children: [
4995
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles9.cancelBtn, onClick: onClose, children: "Cancel" }),
4996
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles9.saveBtn, onClick: handleSave, disabled: saving || !hasChanges, children: saving ? "Saving..." : "Save Changes" })
4427
4997
  ] })
4428
4998
  ] }) });
4429
4999
  }
@@ -4431,7 +5001,7 @@ function SettingsPanel({ onClose }) {
4431
5001
  // src/components/ErrorModal.tsx
4432
5002
 
4433
5003
 
4434
- var styles9 = {
5004
+ var styles10 = {
4435
5005
  overlay: _react3.css`
4436
5006
  position: fixed;
4437
5007
  inset: 0;
@@ -4493,20 +5063,20 @@ var styles9 = {
4493
5063
  function ErrorModal() {
4494
5064
  const { error, clearError } = useStudio();
4495
5065
  if (!error) return null;
4496
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles9.overlay, onClick: clearError, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles9.modal, onClick: (e) => e.stopPropagation(), children: [
4497
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles9.header, children: [
4498
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles9.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" }) }),
4499
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles9.title, children: error.title })
5066
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles10.overlay, onClick: clearError, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles10.modal, onClick: (e) => e.stopPropagation(), children: [
5067
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles10.header, children: [
5068
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles10.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" }) }),
5069
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles10.title, children: error.title })
4500
5070
  ] }),
4501
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles9.message, children: error.message }),
4502
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles9.button, onClick: clearError, children: "OK" })
5071
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles10.message, children: error.message }),
5072
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles10.button, onClick: clearError, children: "OK" })
4503
5073
  ] }) });
4504
5074
  }
4505
5075
 
4506
5076
  // src/components/StudioUI.tsx
4507
5077
 
4508
5078
  var btnHeight3 = "36px";
4509
- var styles10 = {
5079
+ var styles11 = {
4510
5080
  container: _react3.css`
4511
5081
  ${_chunkUFCWGUAGjs.baseReset}
4512
5082
  display: flex;
@@ -4812,16 +5382,16 @@ function StudioUI({ onClose, isVisible = true }) {
4812
5382
  showError,
4813
5383
  clearError
4814
5384
  };
4815
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioContext.Provider, { value: contextValue, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles10.container, children: [
4816
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles10.header, children: [
4817
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles10.headerLeft, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h1", { css: styles10.title, children: "Studio" }) }),
4818
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles10.headerCenter, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Breadcrumbs, { currentPath, onNavigate: setCurrentPath }) }),
4819
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles10.headerActions, children: [
5385
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioContext.Provider, { value: contextValue, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles11.container, children: [
5386
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles11.header, children: [
5387
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles11.headerLeft, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h1", { css: styles11.title, children: "Studio" }) }),
5388
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles11.headerCenter, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Breadcrumbs, { currentPath, onNavigate: setCurrentPath }) }),
5389
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles11.headerActions, children: [
4820
5390
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioSettings, {}),
4821
5391
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4822
5392
  "button",
4823
5393
  {
4824
- css: styles10.headerBtn,
5394
+ css: styles11.headerBtn,
4825
5395
  onClick: onClose,
4826
5396
  "aria-label": "Close Studio",
4827
5397
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, CloseIcon, {})
@@ -4833,16 +5403,16 @@ function StudioUI({ onClose, isVisible = true }) {
4833
5403
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
4834
5404
  "div",
4835
5405
  {
4836
- css: styles10.content,
5406
+ css: styles11.content,
4837
5407
  onDragOver: handleDragOver,
4838
5408
  onDragLeave: handleDragLeave,
4839
5409
  onDrop: handleDrop,
4840
5410
  children: [
4841
- isDragging && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles10.dropOverlay, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles10.dropMessage, children: [
4842
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles10.dropIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" }) }),
5411
+ isDragging && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles11.dropOverlay, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles11.dropMessage, children: [
5412
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles11.dropIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" }) }),
4843
5413
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: "Drop files to upload" })
4844
5414
  ] }) }),
4845
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles10.fileBrowser, children: viewMode === "grid" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioFileGrid, {}) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioFileList, {}) })
5415
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles11.fileBrowser, children: viewMode === "grid" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioFileGrid, {}) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioFileList, {}) })
4846
5416
  ]
4847
5417
  }
4848
5418
  ),
@@ -4856,12 +5426,12 @@ function Breadcrumbs({ currentPath, onNavigate }) {
4856
5426
  name: part,
4857
5427
  path: parts.slice(0, index + 1).join("/")
4858
5428
  }));
4859
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles10.breadcrumbs, children: breadcrumbs.map((crumb, index) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
4860
- index > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles10.breadcrumbSeparator, children: "/" }),
4861
- index === breadcrumbs.length - 1 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles10.breadcrumbCurrent, children: crumb.name }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
5429
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles11.breadcrumbs, children: breadcrumbs.map((crumb, index) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
5430
+ index > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles11.breadcrumbSeparator, children: "/" }),
5431
+ index === breadcrumbs.length - 1 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles11.breadcrumbCurrent, children: crumb.name }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4862
5432
  "span",
4863
5433
  {
4864
- css: styles10.breadcrumbItem,
5434
+ css: styles11.breadcrumbItem,
4865
5435
  onClick: () => onNavigate(crumb.path),
4866
5436
  children: crumb.name
4867
5437
  }
@@ -4872,7 +5442,7 @@ function CloseIcon() {
4872
5442
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
4873
5443
  "svg",
4874
5444
  {
4875
- css: styles10.headerIcon,
5445
+ css: styles11.headerIcon,
4876
5446
  xmlns: "http://www.w3.org/2000/svg",
4877
5447
  viewBox: "0 0 24 24",
4878
5448
  fill: "none",
@@ -4892,4 +5462,4 @@ var StudioUI_default = StudioUI;
4892
5462
 
4893
5463
 
4894
5464
  exports.StudioUI = StudioUI; exports.default = StudioUI_default;
4895
- //# sourceMappingURL=StudioUI-VRSG32E3.js.map
5465
+ //# sourceMappingURL=StudioUI-QBIGDYYL.js.map