@gallop.software/studio 0.1.88 → 0.1.90
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{StudioUI-Y35A2T7S.js → StudioUI-HWUO2H6J.js} +228 -37
- package/dist/StudioUI-HWUO2H6J.js.map +1 -0
- package/dist/{StudioUI-6CQ7MX7R.mjs → StudioUI-LWHNOTSN.mjs} +221 -30
- package/dist/StudioUI-LWHNOTSN.mjs.map +1 -0
- package/dist/{chunk-CN5NRNWB.js → chunk-JWAAU3NN.js} +1 -1
- package/dist/chunk-JWAAU3NN.js.map +1 -0
- package/dist/{chunk-3RI33B7A.mjs → chunk-ZGXOYJKZ.mjs} +1 -1
- package/dist/chunk-ZGXOYJKZ.mjs.map +1 -0
- package/dist/handlers/index.d.mts +1 -1
- package/dist/handlers/index.d.ts +1 -1
- package/dist/handlers/index.js +447 -329
- package/dist/handlers/index.js.map +1 -1
- package/dist/handlers/index.mjs +457 -339
- package/dist/handlers/index.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -3
- package/dist/index.mjs +2 -2
- package/dist/{types-C9CMIJLW.d.mts → types-DzM_J-55.d.mts} +11 -8
- package/dist/{types-C9CMIJLW.d.ts → types-DzM_J-55.d.ts} +11 -8
- package/package.json +1 -1
- package/dist/StudioUI-6CQ7MX7R.mjs.map +0 -1
- package/dist/StudioUI-Y35A2T7S.js.map +0 -1
- package/dist/chunk-3RI33B7A.mjs.map +0 -1
- package/dist/chunk-CN5NRNWB.js.map +0 -1
|
@@ -50,6 +50,11 @@ var defaultState = {
|
|
|
50
50
|
refreshKey: 0,
|
|
51
51
|
triggerRefresh: () => {
|
|
52
52
|
},
|
|
53
|
+
scanRequested: false,
|
|
54
|
+
triggerScan: () => {
|
|
55
|
+
},
|
|
56
|
+
clearScanRequest: () => {
|
|
57
|
+
},
|
|
53
58
|
searchQuery: "",
|
|
54
59
|
setSearchQuery: () => {
|
|
55
60
|
},
|
|
@@ -1285,11 +1290,11 @@ var styles4 = {
|
|
|
1285
1290
|
`
|
|
1286
1291
|
};
|
|
1287
1292
|
function StudioToolbar() {
|
|
1288
|
-
const { selectedItems, viewMode, setViewMode, clearSelection, currentPath, triggerRefresh, focusedItem } = useStudio();
|
|
1293
|
+
const { selectedItems, viewMode, setViewMode, clearSelection, currentPath, triggerRefresh, focusedItem, scanRequested, clearScanRequest } = useStudio();
|
|
1289
1294
|
const fileInputRef = _react.useRef.call(void 0, null);
|
|
1290
1295
|
const abortControllerRef = _react.useRef.call(void 0, null);
|
|
1291
1296
|
const [uploading, setUploading] = _react.useState.call(void 0, false);
|
|
1292
|
-
const [
|
|
1297
|
+
const [scanning, setScanning] = _react.useState.call(void 0, false);
|
|
1293
1298
|
const [processing, setProcessing] = _react.useState.call(void 0, false);
|
|
1294
1299
|
const [showDeleteConfirm, setShowDeleteConfirm] = _react.useState.call(void 0, false);
|
|
1295
1300
|
const [showProcessConfirm, setShowProcessConfirm] = _react.useState.call(void 0, false);
|
|
@@ -1315,11 +1320,88 @@ function StudioToolbar() {
|
|
|
1315
1320
|
const handleUpload = _react.useCallback.call(void 0, () => {
|
|
1316
1321
|
_optionalChain([fileInputRef, 'access', _2 => _2.current, 'optionalAccess', _3 => _3.click, 'call', _4 => _4()]);
|
|
1317
1322
|
}, []);
|
|
1318
|
-
const
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1323
|
+
const handleScan = _react.useCallback.call(void 0, async () => {
|
|
1324
|
+
setScanning(true);
|
|
1325
|
+
setShowProgress(true);
|
|
1326
|
+
setProgressState({
|
|
1327
|
+
current: 0,
|
|
1328
|
+
total: 0,
|
|
1329
|
+
percent: 0,
|
|
1330
|
+
status: "processing",
|
|
1331
|
+
message: "Scanning for files..."
|
|
1332
|
+
});
|
|
1333
|
+
try {
|
|
1334
|
+
const response = await fetch("/api/studio/scan", { method: "POST" });
|
|
1335
|
+
const reader = _optionalChain([response, 'access', _5 => _5.body, 'optionalAccess', _6 => _6.getReader, 'call', _7 => _7()]);
|
|
1336
|
+
if (!reader) throw new Error("No reader");
|
|
1337
|
+
const decoder = new TextDecoder();
|
|
1338
|
+
let buffer = "";
|
|
1339
|
+
while (true) {
|
|
1340
|
+
const { done, value } = await reader.read();
|
|
1341
|
+
if (done) break;
|
|
1342
|
+
buffer += decoder.decode(value, { stream: true });
|
|
1343
|
+
const lines = buffer.split("\n\n");
|
|
1344
|
+
buffer = lines.pop() || "";
|
|
1345
|
+
for (const line of lines) {
|
|
1346
|
+
if (!line.startsWith("data: ")) continue;
|
|
1347
|
+
const data = JSON.parse(line.slice(6));
|
|
1348
|
+
if (data.type === "start") {
|
|
1349
|
+
setProgressState({
|
|
1350
|
+
current: 0,
|
|
1351
|
+
total: data.total,
|
|
1352
|
+
percent: 0,
|
|
1353
|
+
status: "processing",
|
|
1354
|
+
message: `Scanning ${data.total} files...`
|
|
1355
|
+
});
|
|
1356
|
+
} else if (data.type === "progress") {
|
|
1357
|
+
setProgressState({
|
|
1358
|
+
current: data.current,
|
|
1359
|
+
total: data.total,
|
|
1360
|
+
percent: data.percent,
|
|
1361
|
+
status: "processing",
|
|
1362
|
+
currentFile: data.currentFile
|
|
1363
|
+
});
|
|
1364
|
+
} else if (data.type === "complete") {
|
|
1365
|
+
setProgressState({
|
|
1366
|
+
current: data.total || 0,
|
|
1367
|
+
total: data.total || 0,
|
|
1368
|
+
percent: 100,
|
|
1369
|
+
status: "complete",
|
|
1370
|
+
processed: data.added,
|
|
1371
|
+
errors: data.errors,
|
|
1372
|
+
message: data.renamed > 0 ? `${data.renamed} file(s) renamed due to conflicts` : void 0
|
|
1373
|
+
});
|
|
1374
|
+
triggerRefresh();
|
|
1375
|
+
} else if (data.type === "error") {
|
|
1376
|
+
setProgressState({
|
|
1377
|
+
current: 0,
|
|
1378
|
+
total: 0,
|
|
1379
|
+
percent: 0,
|
|
1380
|
+
status: "error",
|
|
1381
|
+
message: data.message || "Scan failed"
|
|
1382
|
+
});
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
} catch (error) {
|
|
1387
|
+
console.error("Scan error:", error);
|
|
1388
|
+
setProgressState({
|
|
1389
|
+
current: 0,
|
|
1390
|
+
total: 0,
|
|
1391
|
+
percent: 0,
|
|
1392
|
+
status: "error",
|
|
1393
|
+
message: "Scan failed"
|
|
1394
|
+
});
|
|
1395
|
+
} finally {
|
|
1396
|
+
setScanning(false);
|
|
1397
|
+
}
|
|
1322
1398
|
}, [triggerRefresh]);
|
|
1399
|
+
_react.useEffect.call(void 0, () => {
|
|
1400
|
+
if (scanRequested && !scanning) {
|
|
1401
|
+
clearScanRequest();
|
|
1402
|
+
handleScan();
|
|
1403
|
+
}
|
|
1404
|
+
}, [scanRequested, scanning, clearScanRequest, handleScan]);
|
|
1323
1405
|
const handleFileChange = _react.useCallback.call(void 0, async (e) => {
|
|
1324
1406
|
const files = e.target.files;
|
|
1325
1407
|
if (!files || files.length === 0) return;
|
|
@@ -1422,7 +1504,7 @@ function StudioToolbar() {
|
|
|
1422
1504
|
const selectedPaths2 = Array.from(selectedItems);
|
|
1423
1505
|
const imageExtensions = ["jpg", "jpeg", "png", "gif", "webp", "svg", "ico", "bmp", "tiff", "tif"];
|
|
1424
1506
|
const selectedImagePaths = selectedPaths2.filter((p) => {
|
|
1425
|
-
const ext = _optionalChain([p, 'access',
|
|
1507
|
+
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()]) || "";
|
|
1426
1508
|
return imageExtensions.includes(ext);
|
|
1427
1509
|
});
|
|
1428
1510
|
const selectedFolders = selectedPaths2.filter((p) => !p.includes(".") || p.endsWith("/"));
|
|
@@ -1583,12 +1665,12 @@ function StudioToolbar() {
|
|
|
1583
1665
|
const data = await response.json();
|
|
1584
1666
|
if (response.ok) {
|
|
1585
1667
|
setProgressState({
|
|
1586
|
-
current: _optionalChain([data, 'access',
|
|
1587
|
-
total: _optionalChain([data, 'access',
|
|
1668
|
+
current: _optionalChain([data, 'access', _14 => _14.processed, 'optionalAccess', _15 => _15.length]) || 0,
|
|
1669
|
+
total: _optionalChain([data, 'access', _16 => _16.processed, 'optionalAccess', _17 => _17.length]) || 0,
|
|
1588
1670
|
percent: 100,
|
|
1589
1671
|
status: "complete",
|
|
1590
|
-
processed: _optionalChain([data, 'access',
|
|
1591
|
-
errors: _optionalChain([data, 'access',
|
|
1672
|
+
processed: _optionalChain([data, 'access', _18 => _18.processed, 'optionalAccess', _19 => _19.length]) || 0,
|
|
1673
|
+
errors: _optionalChain([data, 'access', _20 => _20.errors, 'optionalAccess', _21 => _21.length]) || 0
|
|
1592
1674
|
});
|
|
1593
1675
|
clearSelection();
|
|
1594
1676
|
triggerRefresh();
|
|
@@ -1665,7 +1747,7 @@ function StudioToolbar() {
|
|
|
1665
1747
|
const selectedPaths2 = Array.from(selectedItems);
|
|
1666
1748
|
const imageExtensions = ["jpg", "jpeg", "png", "gif", "webp", "svg", "ico", "bmp", "tiff", "tif"];
|
|
1667
1749
|
const selectedImagePaths = selectedPaths2.filter((p) => {
|
|
1668
|
-
const ext = _optionalChain([p, 'access',
|
|
1750
|
+
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()]) || "";
|
|
1669
1751
|
return imageExtensions.includes(ext);
|
|
1670
1752
|
});
|
|
1671
1753
|
const selectedFolders = selectedPaths2.filter((p) => !p.includes(".") || p.endsWith("/"));
|
|
@@ -1700,7 +1782,7 @@ function StudioToolbar() {
|
|
|
1700
1782
|
const selectedPaths2 = Array.from(selectedItems);
|
|
1701
1783
|
const imageExtensions = ["jpg", "jpeg", "png", "gif", "webp", "svg", "ico", "bmp", "tiff", "tif"];
|
|
1702
1784
|
const selectedImagePaths = selectedPaths2.filter((p) => {
|
|
1703
|
-
const ext = _optionalChain([p, 'access',
|
|
1785
|
+
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()]) || "";
|
|
1704
1786
|
return imageExtensions.includes(ext);
|
|
1705
1787
|
});
|
|
1706
1788
|
const selectedFolders = selectedPaths2.filter((p) => !p.includes(".") || p.endsWith("/"));
|
|
@@ -1750,16 +1832,16 @@ function StudioToolbar() {
|
|
|
1750
1832
|
});
|
|
1751
1833
|
const data = await response.json();
|
|
1752
1834
|
if (!response.ok) {
|
|
1753
|
-
if (_optionalChain([data, 'access',
|
|
1835
|
+
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")])) {
|
|
1754
1836
|
setShowProgress(false);
|
|
1755
1837
|
setShowR2SetupModal(true);
|
|
1756
1838
|
return;
|
|
1757
1839
|
}
|
|
1758
1840
|
errors++;
|
|
1759
1841
|
errorMessages.push(data.error || `Failed: ${imageKey}`);
|
|
1760
|
-
} else if (_optionalChain([data, 'access',
|
|
1842
|
+
} else if (_optionalChain([data, 'access', _40 => _40.synced, 'optionalAccess', _41 => _41.length]) > 0) {
|
|
1761
1843
|
synced++;
|
|
1762
|
-
} else if (_optionalChain([data, 'access',
|
|
1844
|
+
} else if (_optionalChain([data, 'access', _42 => _42.errors, 'optionalAccess', _43 => _43.length]) > 0) {
|
|
1763
1845
|
errors++;
|
|
1764
1846
|
for (const errMsg of data.errors) {
|
|
1765
1847
|
errorMessages.push(errMsg);
|
|
@@ -1903,8 +1985,8 @@ function StudioToolbar() {
|
|
|
1903
1985
|
showSyncConfirm && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1904
1986
|
ConfirmModal,
|
|
1905
1987
|
{
|
|
1906
|
-
title: "
|
|
1907
|
-
message: `
|
|
1988
|
+
title: "Push to CDN",
|
|
1989
|
+
message: `Push ${syncImageCount} image${syncImageCount !== 1 ? "s" : ""} to Cloudflare R2? Images must be processed first. After pushing, local files will be deleted.`,
|
|
1908
1990
|
confirmLabel: "Sync",
|
|
1909
1991
|
onConfirm: handleSyncConfirm,
|
|
1910
1992
|
onCancel: () => setShowSyncConfirm(false)
|
|
@@ -2071,7 +2153,7 @@ function StudioToolbar() {
|
|
|
2071
2153
|
disabled: !hasSelection,
|
|
2072
2154
|
children: [
|
|
2073
2155
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, CloudIcon, {}),
|
|
2074
|
-
"
|
|
2156
|
+
"Push CDN"
|
|
2075
2157
|
]
|
|
2076
2158
|
}
|
|
2077
2159
|
),
|
|
@@ -2104,12 +2186,16 @@ function StudioToolbar() {
|
|
|
2104
2186
|
" selected",
|
|
2105
2187
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles4.clearBtn, onClick: clearSelection, children: "Clear" })
|
|
2106
2188
|
] }),
|
|
2107
|
-
/* @__PURE__ */ _jsxruntime.
|
|
2189
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
2108
2190
|
"button",
|
|
2109
2191
|
{
|
|
2110
|
-
css:
|
|
2111
|
-
onClick:
|
|
2112
|
-
|
|
2192
|
+
css: styles4.btn,
|
|
2193
|
+
onClick: handleScan,
|
|
2194
|
+
disabled: scanning,
|
|
2195
|
+
children: [
|
|
2196
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, ScanIcon, { spinning: scanning }),
|
|
2197
|
+
"Scan"
|
|
2198
|
+
]
|
|
2113
2199
|
}
|
|
2114
2200
|
),
|
|
2115
2201
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.viewToggle, children: [
|
|
@@ -2139,7 +2225,7 @@ function StudioToolbar() {
|
|
|
2139
2225
|
function UploadIcon() {
|
|
2140
2226
|
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" }) });
|
|
2141
2227
|
}
|
|
2142
|
-
function
|
|
2228
|
+
function ScanIcon({ spinning }) {
|
|
2143
2229
|
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" }) });
|
|
2144
2230
|
}
|
|
2145
2231
|
function TrashIcon() {
|
|
@@ -2268,11 +2354,13 @@ function useFileList() {
|
|
|
2268
2354
|
refreshKey,
|
|
2269
2355
|
setFocusedItem,
|
|
2270
2356
|
triggerRefresh,
|
|
2357
|
+
triggerScan,
|
|
2271
2358
|
searchQuery,
|
|
2272
2359
|
showError
|
|
2273
2360
|
} = useStudio();
|
|
2274
2361
|
const [items, setItems] = _react.useState.call(void 0, []);
|
|
2275
2362
|
const [loading, setLoading] = _react.useState.call(void 0, true);
|
|
2363
|
+
const [metaEmpty, setMetaEmpty] = _react.useState.call(void 0, false);
|
|
2276
2364
|
const isInitialLoad = _react.useRef.call(void 0, true);
|
|
2277
2365
|
const lastPath = _react.useRef.call(void 0, currentPath);
|
|
2278
2366
|
_react.useEffect.call(void 0, () => {
|
|
@@ -2285,10 +2373,12 @@ function useFileList() {
|
|
|
2285
2373
|
try {
|
|
2286
2374
|
const data = searchQuery && searchQuery.length >= 2 ? await studioApi.search(searchQuery) : await studioApi.list(currentPath);
|
|
2287
2375
|
setItems(data.items || []);
|
|
2376
|
+
setMetaEmpty(data.isEmpty === true);
|
|
2288
2377
|
} catch (error) {
|
|
2289
2378
|
const message = error instanceof Error ? error.message : "Failed to load items";
|
|
2290
2379
|
showError("Load Error", message);
|
|
2291
2380
|
setItems([]);
|
|
2381
|
+
setMetaEmpty(false);
|
|
2292
2382
|
}
|
|
2293
2383
|
setLoading(false);
|
|
2294
2384
|
isInitialLoad.current = false;
|
|
@@ -2340,6 +2430,7 @@ function useFileList() {
|
|
|
2340
2430
|
items,
|
|
2341
2431
|
loading,
|
|
2342
2432
|
sortedItems,
|
|
2433
|
+
metaEmpty,
|
|
2343
2434
|
// Computed
|
|
2344
2435
|
isAtRoot,
|
|
2345
2436
|
isSearching,
|
|
@@ -2353,7 +2444,8 @@ function useFileList() {
|
|
|
2353
2444
|
handleItemClick,
|
|
2354
2445
|
handleOpen,
|
|
2355
2446
|
handleGenerateThumbnail,
|
|
2356
|
-
handleSelectAll
|
|
2447
|
+
handleSelectAll,
|
|
2448
|
+
triggerScan
|
|
2357
2449
|
};
|
|
2358
2450
|
}
|
|
2359
2451
|
|
|
@@ -2367,7 +2459,8 @@ var styles5 = {
|
|
|
2367
2459
|
display: flex;
|
|
2368
2460
|
align-items: center;
|
|
2369
2461
|
justify-content: center;
|
|
2370
|
-
|
|
2462
|
+
flex: 1;
|
|
2463
|
+
min-height: 300px;
|
|
2371
2464
|
`,
|
|
2372
2465
|
spinner: _react3.css`
|
|
2373
2466
|
width: 32px;
|
|
@@ -2382,7 +2475,8 @@ var styles5 = {
|
|
|
2382
2475
|
flex-direction: column;
|
|
2383
2476
|
align-items: center;
|
|
2384
2477
|
justify-content: center;
|
|
2385
|
-
|
|
2478
|
+
flex: 1;
|
|
2479
|
+
min-height: 300px;
|
|
2386
2480
|
color: ${_chunkUFCWGUAGjs.colors.textSecondary};
|
|
2387
2481
|
`,
|
|
2388
2482
|
emptyIcon: _react3.css`
|
|
@@ -2400,6 +2494,27 @@ var styles5 = {
|
|
|
2400
2494
|
font-size: ${_chunkUFCWGUAGjs.fontSize.sm};
|
|
2401
2495
|
}
|
|
2402
2496
|
`,
|
|
2497
|
+
scanButton: _react3.css`
|
|
2498
|
+
margin-top: 16px;
|
|
2499
|
+
padding: 10px 24px;
|
|
2500
|
+
font-size: ${_chunkUFCWGUAGjs.fontSize.base};
|
|
2501
|
+
font-weight: 500;
|
|
2502
|
+
background: ${_chunkUFCWGUAGjs.colors.primary};
|
|
2503
|
+
color: white;
|
|
2504
|
+
border: none;
|
|
2505
|
+
border-radius: 8px;
|
|
2506
|
+
cursor: pointer;
|
|
2507
|
+
transition: background 0.15s ease;
|
|
2508
|
+
|
|
2509
|
+
&:hover:not(:disabled) {
|
|
2510
|
+
background: ${_chunkUFCWGUAGjs.colors.primaryHover};
|
|
2511
|
+
}
|
|
2512
|
+
|
|
2513
|
+
&:disabled {
|
|
2514
|
+
opacity: 0.6;
|
|
2515
|
+
cursor: not-allowed;
|
|
2516
|
+
}
|
|
2517
|
+
`,
|
|
2403
2518
|
grid: _react3.css`
|
|
2404
2519
|
display: grid;
|
|
2405
2520
|
grid-template-columns: 1fr;
|
|
@@ -2683,6 +2798,7 @@ function StudioFileGrid() {
|
|
|
2683
2798
|
const {
|
|
2684
2799
|
loading,
|
|
2685
2800
|
sortedItems,
|
|
2801
|
+
metaEmpty,
|
|
2686
2802
|
isAtRoot,
|
|
2687
2803
|
isSearching,
|
|
2688
2804
|
allItemsSelected,
|
|
@@ -2692,16 +2808,32 @@ function StudioFileGrid() {
|
|
|
2692
2808
|
handleItemClick,
|
|
2693
2809
|
handleOpen,
|
|
2694
2810
|
handleGenerateThumbnail,
|
|
2695
|
-
handleSelectAll
|
|
2811
|
+
handleSelectAll,
|
|
2812
|
+
triggerScan
|
|
2696
2813
|
} = useFileList();
|
|
2697
2814
|
if (loading) {
|
|
2698
2815
|
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.loading, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.spinner }) });
|
|
2699
2816
|
}
|
|
2817
|
+
if (metaEmpty && isAtRoot) {
|
|
2818
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.empty, children: [
|
|
2819
|
+
/* @__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" }) }),
|
|
2820
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.emptyText, children: "No files tracked yet" }),
|
|
2821
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.emptyText, children: "Click Scan to discover files in your public folder" }),
|
|
2822
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2823
|
+
"button",
|
|
2824
|
+
{
|
|
2825
|
+
css: styles5.scanButton,
|
|
2826
|
+
onClick: triggerScan,
|
|
2827
|
+
children: "Scan for Files"
|
|
2828
|
+
}
|
|
2829
|
+
)
|
|
2830
|
+
] });
|
|
2831
|
+
}
|
|
2700
2832
|
if (sortedItems.length === 0 && isAtRoot) {
|
|
2701
2833
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.empty, children: [
|
|
2702
2834
|
/* @__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" }) }),
|
|
2703
2835
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.emptyText, children: "No files in this folder" }),
|
|
2704
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.emptyText, children: "Upload images
|
|
2836
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.emptyText, children: "Upload images or click Scan in the toolbar" })
|
|
2705
2837
|
] });
|
|
2706
2838
|
}
|
|
2707
2839
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
|
|
@@ -2880,7 +3012,8 @@ var styles6 = {
|
|
|
2880
3012
|
display: flex;
|
|
2881
3013
|
align-items: center;
|
|
2882
3014
|
justify-content: center;
|
|
2883
|
-
|
|
3015
|
+
flex: 1;
|
|
3016
|
+
min-height: 300px;
|
|
2884
3017
|
`,
|
|
2885
3018
|
spinner: _react3.css`
|
|
2886
3019
|
width: 32px;
|
|
@@ -2895,9 +3028,36 @@ var styles6 = {
|
|
|
2895
3028
|
flex-direction: column;
|
|
2896
3029
|
align-items: center;
|
|
2897
3030
|
justify-content: center;
|
|
2898
|
-
|
|
3031
|
+
flex: 1;
|
|
3032
|
+
min-height: 300px;
|
|
2899
3033
|
color: ${_chunkUFCWGUAGjs.colors.textSecondary};
|
|
2900
3034
|
`,
|
|
3035
|
+
emptyHint: _react3.css`
|
|
3036
|
+
font-size: ${_chunkUFCWGUAGjs.fontSize.sm};
|
|
3037
|
+
color: ${_chunkUFCWGUAGjs.colors.textMuted};
|
|
3038
|
+
margin-top: 4px;
|
|
3039
|
+
`,
|
|
3040
|
+
scanButton: _react3.css`
|
|
3041
|
+
margin-top: 16px;
|
|
3042
|
+
padding: 10px 24px;
|
|
3043
|
+
font-size: ${_chunkUFCWGUAGjs.fontSize.base};
|
|
3044
|
+
font-weight: 500;
|
|
3045
|
+
background: ${_chunkUFCWGUAGjs.colors.primary};
|
|
3046
|
+
color: white;
|
|
3047
|
+
border: none;
|
|
3048
|
+
border-radius: 8px;
|
|
3049
|
+
cursor: pointer;
|
|
3050
|
+
transition: background 0.15s ease;
|
|
3051
|
+
|
|
3052
|
+
&:hover:not(:disabled) {
|
|
3053
|
+
background: ${_chunkUFCWGUAGjs.colors.primaryHover};
|
|
3054
|
+
}
|
|
3055
|
+
|
|
3056
|
+
&:disabled {
|
|
3057
|
+
opacity: 0.6;
|
|
3058
|
+
cursor: not-allowed;
|
|
3059
|
+
}
|
|
3060
|
+
`,
|
|
2901
3061
|
tableWrapper: _react3.css`
|
|
2902
3062
|
background: ${_chunkUFCWGUAGjs.colors.surface};
|
|
2903
3063
|
border-radius: 8px;
|
|
@@ -3184,6 +3344,7 @@ function StudioFileList() {
|
|
|
3184
3344
|
const {
|
|
3185
3345
|
loading,
|
|
3186
3346
|
sortedItems,
|
|
3347
|
+
metaEmpty,
|
|
3187
3348
|
isAtRoot,
|
|
3188
3349
|
isSearching,
|
|
3189
3350
|
allItemsSelected,
|
|
@@ -3193,13 +3354,31 @@ function StudioFileList() {
|
|
|
3193
3354
|
handleItemClick,
|
|
3194
3355
|
handleOpen,
|
|
3195
3356
|
handleGenerateThumbnail,
|
|
3196
|
-
handleSelectAll
|
|
3357
|
+
handleSelectAll,
|
|
3358
|
+
triggerScan
|
|
3197
3359
|
} = useFileList();
|
|
3198
3360
|
if (loading) {
|
|
3199
3361
|
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.loading, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.spinner }) });
|
|
3200
3362
|
}
|
|
3363
|
+
if (metaEmpty && isAtRoot) {
|
|
3364
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.empty, children: [
|
|
3365
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { children: "No files tracked yet" }),
|
|
3366
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.emptyHint, children: "Click Scan to discover files in your public folder" }),
|
|
3367
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3368
|
+
"button",
|
|
3369
|
+
{
|
|
3370
|
+
css: styles6.scanButton,
|
|
3371
|
+
onClick: triggerScan,
|
|
3372
|
+
children: "Scan for Files"
|
|
3373
|
+
}
|
|
3374
|
+
)
|
|
3375
|
+
] });
|
|
3376
|
+
}
|
|
3201
3377
|
if (sortedItems.length === 0 && isAtRoot) {
|
|
3202
|
-
return /* @__PURE__ */ _jsxruntime.
|
|
3378
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.empty, children: [
|
|
3379
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { children: "No files in this folder" }),
|
|
3380
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.emptyHint, children: "Upload images or click Scan in the toolbar" })
|
|
3381
|
+
] });
|
|
3203
3382
|
}
|
|
3204
3383
|
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.tableWrapper, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "table", { css: styles6.table, children: [
|
|
3205
3384
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "thead", { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tr", { children: [
|
|
@@ -3709,7 +3888,7 @@ function StudioDetailView() {
|
|
|
3709
3888
|
});
|
|
3710
3889
|
triggerRefresh();
|
|
3711
3890
|
} else {
|
|
3712
|
-
if (_optionalChain([data, 'access',
|
|
3891
|
+
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")])) {
|
|
3713
3892
|
setShowR2SetupModal(true);
|
|
3714
3893
|
} else {
|
|
3715
3894
|
setAlertMessage({
|
|
@@ -3748,7 +3927,7 @@ function StudioDetailView() {
|
|
|
3748
3927
|
if (!response.ok) {
|
|
3749
3928
|
throw new Error("Processing failed");
|
|
3750
3929
|
}
|
|
3751
|
-
const reader = _optionalChain([response, 'access',
|
|
3930
|
+
const reader = _optionalChain([response, 'access', _50 => _50.body, 'optionalAccess', _51 => _51.getReader, 'call', _52 => _52()]);
|
|
3752
3931
|
if (!reader) {
|
|
3753
3932
|
throw new Error("No response body");
|
|
3754
3933
|
}
|
|
@@ -3898,7 +4077,7 @@ function StudioDetailView() {
|
|
|
3898
4077
|
] }),
|
|
3899
4078
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles7.actionBtn, onClick: handleSync, disabled: syncing, children: [
|
|
3900
4079
|
/* @__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" }) }),
|
|
3901
|
-
syncing ? "
|
|
4080
|
+
syncing ? "Pushing..." : "Push to CDN"
|
|
3902
4081
|
] }),
|
|
3903
4082
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles7.actionBtn, onClick: () => setShowProcessConfirm(true), children: [
|
|
3904
4083
|
/* @__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" }) }),
|
|
@@ -4428,6 +4607,8 @@ var styles10 = {
|
|
|
4428
4607
|
min-width: 0;
|
|
4429
4608
|
overflow: auto;
|
|
4430
4609
|
padding: 20px 24px;
|
|
4610
|
+
display: flex;
|
|
4611
|
+
flex-direction: column;
|
|
4431
4612
|
`,
|
|
4432
4613
|
dropOverlay: _react3.css`
|
|
4433
4614
|
position: absolute;
|
|
@@ -4467,12 +4648,19 @@ function StudioUI({ onClose, isVisible = true }) {
|
|
|
4467
4648
|
const [meta, setMeta] = _react.useState.call(void 0, null);
|
|
4468
4649
|
const [isLoading, setIsLoading] = _react.useState.call(void 0, false);
|
|
4469
4650
|
const [refreshKey, setRefreshKey] = _react.useState.call(void 0, 0);
|
|
4651
|
+
const [scanRequested, setScanRequested] = _react.useState.call(void 0, false);
|
|
4470
4652
|
const [searchQuery, setSearchQuery] = _react.useState.call(void 0, "");
|
|
4471
4653
|
const [error, setError] = _react.useState.call(void 0, null);
|
|
4472
4654
|
const [isDragging, setIsDragging] = _react.useState.call(void 0, false);
|
|
4473
4655
|
const triggerRefresh = _react.useCallback.call(void 0, () => {
|
|
4474
4656
|
setRefreshKey((k) => k + 1);
|
|
4475
4657
|
}, []);
|
|
4658
|
+
const triggerScan = _react.useCallback.call(void 0, () => {
|
|
4659
|
+
setScanRequested(true);
|
|
4660
|
+
}, []);
|
|
4661
|
+
const clearScanRequest = _react.useCallback.call(void 0, () => {
|
|
4662
|
+
setScanRequested(false);
|
|
4663
|
+
}, []);
|
|
4476
4664
|
const showError = _react.useCallback.call(void 0, (title, message) => {
|
|
4477
4665
|
setError({ title, message });
|
|
4478
4666
|
}, []);
|
|
@@ -4609,6 +4797,9 @@ function StudioUI({ onClose, isVisible = true }) {
|
|
|
4609
4797
|
setIsLoading,
|
|
4610
4798
|
refreshKey,
|
|
4611
4799
|
triggerRefresh,
|
|
4800
|
+
scanRequested,
|
|
4801
|
+
triggerScan,
|
|
4802
|
+
clearScanRequest,
|
|
4612
4803
|
searchQuery,
|
|
4613
4804
|
setSearchQuery,
|
|
4614
4805
|
error,
|
|
@@ -4695,4 +4886,4 @@ var StudioUI_default = StudioUI;
|
|
|
4695
4886
|
|
|
4696
4887
|
|
|
4697
4888
|
exports.StudioUI = StudioUI; exports.default = StudioUI_default;
|
|
4698
|
-
//# sourceMappingURL=StudioUI-
|
|
4889
|
+
//# sourceMappingURL=StudioUI-HWUO2H6J.js.map
|