@gallop.software/studio 0.1.22 → 0.1.24
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-3VFEM3VE.mjs → StudioUI-F2C4N66F.mjs} +658 -598
- package/dist/StudioUI-F2C4N66F.mjs.map +1 -0
- package/dist/{StudioUI-TPVIV5T7.js → StudioUI-YO6WPG5E.js} +543 -483
- package/dist/StudioUI-YO6WPG5E.js.map +1 -0
- package/dist/handlers.d.mts +7 -0
- package/dist/handlers.d.ts +7 -0
- package/dist/handlers.js +205 -6
- package/dist/handlers.js.map +1 -1
- package/dist/handlers.mjs +203 -4
- package/dist/handlers.mjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
- package/dist/StudioUI-3VFEM3VE.mjs.map +0 -1
- package/dist/StudioUI-TPVIV5T7.js.map +0 -1
|
@@ -38,6 +38,9 @@ var defaultState = {
|
|
|
38
38
|
viewMode: "grid",
|
|
39
39
|
setViewMode: () => {
|
|
40
40
|
},
|
|
41
|
+
focusedItem: null,
|
|
42
|
+
setFocusedItem: () => {
|
|
43
|
+
},
|
|
41
44
|
meta: null,
|
|
42
45
|
setMeta: () => {
|
|
43
46
|
},
|
|
@@ -204,6 +207,7 @@ function AlertModal({
|
|
|
204
207
|
|
|
205
208
|
// src/components/StudioToolbar.tsx
|
|
206
209
|
|
|
210
|
+
var btnHeight = "36px";
|
|
207
211
|
var spin = _react3.keyframes`
|
|
208
212
|
to { transform: rotate(360deg); }
|
|
209
213
|
`;
|
|
@@ -224,13 +228,15 @@ var styles2 = {
|
|
|
224
228
|
right: _react3.css`
|
|
225
229
|
display: flex;
|
|
226
230
|
align-items: center;
|
|
227
|
-
gap:
|
|
231
|
+
gap: 8px;
|
|
228
232
|
`,
|
|
229
233
|
btn: _react3.css`
|
|
230
234
|
display: inline-flex;
|
|
231
235
|
align-items: center;
|
|
236
|
+
justify-content: center;
|
|
232
237
|
gap: 6px;
|
|
233
|
-
|
|
238
|
+
height: ${btnHeight};
|
|
239
|
+
padding: 0 14px;
|
|
234
240
|
border-radius: 6px;
|
|
235
241
|
font-size: ${_chunkAY2DAS6Wjs.fontSize.base};
|
|
236
242
|
font-weight: 500;
|
|
@@ -251,6 +257,9 @@ var styles2 = {
|
|
|
251
257
|
opacity: 0.5;
|
|
252
258
|
}
|
|
253
259
|
`,
|
|
260
|
+
btnIconOnly: _react3.css`
|
|
261
|
+
padding: 0 10px;
|
|
262
|
+
`,
|
|
254
263
|
btnPrimary: _react3.css`
|
|
255
264
|
background: ${_chunkAY2DAS6Wjs.colors.primary};
|
|
256
265
|
border-color: ${_chunkAY2DAS6Wjs.colors.primary};
|
|
@@ -270,8 +279,8 @@ var styles2 = {
|
|
|
270
279
|
}
|
|
271
280
|
`,
|
|
272
281
|
icon: _react3.css`
|
|
273
|
-
width:
|
|
274
|
-
height:
|
|
282
|
+
width: 16px;
|
|
283
|
+
height: 16px;
|
|
275
284
|
`,
|
|
276
285
|
iconSpin: _react3.css`
|
|
277
286
|
animation: ${spin} 1s linear infinite;
|
|
@@ -282,6 +291,7 @@ var styles2 = {
|
|
|
282
291
|
display: flex;
|
|
283
292
|
align-items: center;
|
|
284
293
|
gap: 8px;
|
|
294
|
+
margin-right: 8px;
|
|
285
295
|
`,
|
|
286
296
|
clearBtn: _react3.css`
|
|
287
297
|
color: ${_chunkAY2DAS6Wjs.colors.primary};
|
|
@@ -305,16 +315,17 @@ var styles2 = {
|
|
|
305
315
|
viewToggle: _react3.css`
|
|
306
316
|
display: flex;
|
|
307
317
|
align-items: center;
|
|
308
|
-
|
|
318
|
+
height: ${btnHeight};
|
|
319
|
+
background-color: ${_chunkAY2DAS6Wjs.colors.surface};
|
|
309
320
|
border: 1px solid ${_chunkAY2DAS6Wjs.colors.border};
|
|
310
321
|
border-radius: 6px;
|
|
311
|
-
|
|
322
|
+
overflow: hidden;
|
|
312
323
|
`,
|
|
313
324
|
viewBtn: _react3.css`
|
|
314
|
-
|
|
325
|
+
height: 100%;
|
|
326
|
+
padding: 0 10px;
|
|
315
327
|
background: transparent;
|
|
316
328
|
border: none;
|
|
317
|
-
border-radius: 4px;
|
|
318
329
|
cursor: pointer;
|
|
319
330
|
color: ${_chunkAY2DAS6Wjs.colors.textSecondary};
|
|
320
331
|
transition: all 0.15s ease;
|
|
@@ -324,20 +335,24 @@ var styles2 = {
|
|
|
324
335
|
|
|
325
336
|
&:hover {
|
|
326
337
|
color: ${_chunkAY2DAS6Wjs.colors.text};
|
|
338
|
+
background-color: ${_chunkAY2DAS6Wjs.colors.surfaceHover};
|
|
327
339
|
}
|
|
328
340
|
`,
|
|
329
341
|
viewBtnActive: _react3.css`
|
|
330
|
-
background-color: ${_chunkAY2DAS6Wjs.colors.
|
|
342
|
+
background-color: ${_chunkAY2DAS6Wjs.colors.background};
|
|
331
343
|
color: ${_chunkAY2DAS6Wjs.colors.text};
|
|
332
|
-
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
|
|
333
344
|
`
|
|
334
345
|
};
|
|
335
346
|
function StudioToolbar() {
|
|
336
|
-
const { selectedItems, viewMode, setViewMode, clearSelection, currentPath, triggerRefresh } = useStudio();
|
|
347
|
+
const { selectedItems, viewMode, setViewMode, clearSelection, currentPath, triggerRefresh, focusedItem } = useStudio();
|
|
337
348
|
const fileInputRef = _react.useRef.call(void 0, null);
|
|
338
349
|
const [uploading, setUploading] = _react.useState.call(void 0, false);
|
|
339
350
|
const [refreshing, setRefreshing] = _react.useState.call(void 0, false);
|
|
351
|
+
const [processing, setProcessing] = _react.useState.call(void 0, false);
|
|
340
352
|
const [showDeleteConfirm, setShowDeleteConfirm] = _react.useState.call(void 0, false);
|
|
353
|
+
const [showProcessConfirm, setShowProcessConfirm] = _react.useState.call(void 0, false);
|
|
354
|
+
const [processCount, setProcessCount] = _react.useState.call(void 0, 0);
|
|
355
|
+
const [processMode, setProcessMode] = _react.useState.call(void 0, "all");
|
|
341
356
|
const [alertMessage, setAlertMessage] = _react.useState.call(void 0, null);
|
|
342
357
|
const isInImagesFolder = currentPath === "public/images" || currentPath.startsWith("public/images/");
|
|
343
358
|
const handleUpload = _react.useCallback.call(void 0, () => {
|
|
@@ -391,9 +406,107 @@ function StudioToolbar() {
|
|
|
391
406
|
}
|
|
392
407
|
}
|
|
393
408
|
}, [currentPath, triggerRefresh]);
|
|
394
|
-
const
|
|
395
|
-
|
|
409
|
+
const handleProcessImages = _react.useCallback.call(void 0, async () => {
|
|
410
|
+
const hasSelection2 = selectedItems.size > 0;
|
|
411
|
+
if (hasSelection2) {
|
|
412
|
+
const selectedImagePaths = Array.from(selectedItems).filter((p) => {
|
|
413
|
+
const ext = _optionalChain([p, 'access', _4 => _4.split, 'call', _5 => _5("."), 'access', _6 => _6.pop, 'call', _7 => _7(), 'optionalAccess', _8 => _8.toLowerCase, 'call', _9 => _9()]) || "";
|
|
414
|
+
return ["jpg", "jpeg", "png", "gif", "webp", "svg", "ico", "bmp", "tiff", "tif"].includes(ext);
|
|
415
|
+
});
|
|
416
|
+
if (selectedImagePaths.length === 0) {
|
|
417
|
+
setAlertMessage({
|
|
418
|
+
title: "No Images Selected",
|
|
419
|
+
message: "Please select image files to process."
|
|
420
|
+
});
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
setProcessCount(selectedImagePaths.length);
|
|
424
|
+
setProcessMode("selected");
|
|
425
|
+
setShowProcessConfirm(true);
|
|
426
|
+
} else {
|
|
427
|
+
try {
|
|
428
|
+
const response = await fetch("/api/studio/count-unprocessed");
|
|
429
|
+
const data = await response.json();
|
|
430
|
+
if (data.count === 0) {
|
|
431
|
+
setAlertMessage({
|
|
432
|
+
title: "All Images Processed",
|
|
433
|
+
message: "All images in the public folder have already been processed."
|
|
434
|
+
});
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
setProcessCount(data.count);
|
|
438
|
+
setProcessMode("all");
|
|
439
|
+
setShowProcessConfirm(true);
|
|
440
|
+
} catch (error) {
|
|
441
|
+
console.error("Failed to count unprocessed images:", error);
|
|
442
|
+
setAlertMessage({
|
|
443
|
+
title: "Error",
|
|
444
|
+
message: "Failed to count unprocessed images."
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
}
|
|
396
448
|
}, [selectedItems]);
|
|
449
|
+
const handleProcessConfirm = _react.useCallback.call(void 0, async () => {
|
|
450
|
+
setShowProcessConfirm(false);
|
|
451
|
+
setProcessing(true);
|
|
452
|
+
try {
|
|
453
|
+
if (processMode === "all") {
|
|
454
|
+
const response = await fetch("/api/studio/process-all", {
|
|
455
|
+
method: "POST"
|
|
456
|
+
});
|
|
457
|
+
const data = await response.json();
|
|
458
|
+
if (response.ok) {
|
|
459
|
+
const message = [
|
|
460
|
+
`Processed ${_optionalChain([data, 'access', _10 => _10.processed, 'optionalAccess', _11 => _11.length]) || 0} images.`,
|
|
461
|
+
_optionalChain([data, 'access', _12 => _12.orphansRemoved, 'optionalAccess', _13 => _13.length]) > 0 ? `Removed ${data.orphansRemoved.length} orphaned thumbnails.` : "",
|
|
462
|
+
_optionalChain([data, 'access', _14 => _14.errors, 'optionalAccess', _15 => _15.length]) > 0 ? `${data.errors.length} errors occurred.` : ""
|
|
463
|
+
].filter(Boolean).join(" ");
|
|
464
|
+
setAlertMessage({
|
|
465
|
+
title: "Processing Complete",
|
|
466
|
+
message
|
|
467
|
+
});
|
|
468
|
+
triggerRefresh();
|
|
469
|
+
} else {
|
|
470
|
+
setAlertMessage({
|
|
471
|
+
title: "Processing Failed",
|
|
472
|
+
message: data.error || "Unknown error"
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
} else {
|
|
476
|
+
const selectedImageKeys = Array.from(selectedItems).filter((p) => {
|
|
477
|
+
const ext = _optionalChain([p, 'access', _16 => _16.split, 'call', _17 => _17("."), 'access', _18 => _18.pop, 'call', _19 => _19(), 'optionalAccess', _20 => _20.toLowerCase, 'call', _21 => _21()]) || "";
|
|
478
|
+
return ["jpg", "jpeg", "png", "gif", "webp", "svg", "ico", "bmp", "tiff", "tif"].includes(ext);
|
|
479
|
+
}).map((p) => p.replace(/^public\//, ""));
|
|
480
|
+
const response = await fetch("/api/studio/reprocess", {
|
|
481
|
+
method: "POST",
|
|
482
|
+
headers: { "Content-Type": "application/json" },
|
|
483
|
+
body: JSON.stringify({ imageKeys: selectedImageKeys })
|
|
484
|
+
});
|
|
485
|
+
const data = await response.json();
|
|
486
|
+
if (response.ok) {
|
|
487
|
+
setAlertMessage({
|
|
488
|
+
title: "Processing Complete",
|
|
489
|
+
message: `Processed ${_optionalChain([data, 'access', _22 => _22.processed, 'optionalAccess', _23 => _23.length]) || 0} images.${_optionalChain([data, 'access', _24 => _24.errors, 'optionalAccess', _25 => _25.length]) > 0 ? ` ${data.errors.length} errors occurred.` : ""}`
|
|
490
|
+
});
|
|
491
|
+
clearSelection();
|
|
492
|
+
triggerRefresh();
|
|
493
|
+
} else {
|
|
494
|
+
setAlertMessage({
|
|
495
|
+
title: "Processing Failed",
|
|
496
|
+
message: data.error || "Unknown error"
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
} catch (error) {
|
|
501
|
+
console.error("Processing error:", error);
|
|
502
|
+
setAlertMessage({
|
|
503
|
+
title: "Processing Failed",
|
|
504
|
+
message: "Processing failed. Check console for details."
|
|
505
|
+
});
|
|
506
|
+
} finally {
|
|
507
|
+
setProcessing(false);
|
|
508
|
+
}
|
|
509
|
+
}, [processMode, selectedItems, clearSelection, triggerRefresh]);
|
|
397
510
|
const handleDeleteClick = _react.useCallback.call(void 0, () => {
|
|
398
511
|
if (selectedItems.size === 0) return;
|
|
399
512
|
setShowDeleteConfirm(true);
|
|
@@ -431,6 +544,9 @@ function StudioToolbar() {
|
|
|
431
544
|
console.log("Scan clicked");
|
|
432
545
|
}, []);
|
|
433
546
|
const hasSelection = selectedItems.size > 0;
|
|
547
|
+
if (focusedItem) {
|
|
548
|
+
return null;
|
|
549
|
+
}
|
|
434
550
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
435
551
|
showDeleteConfirm && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
436
552
|
ConfirmModal,
|
|
@@ -443,6 +559,16 @@ function StudioToolbar() {
|
|
|
443
559
|
onCancel: () => setShowDeleteConfirm(false)
|
|
444
560
|
}
|
|
445
561
|
),
|
|
562
|
+
showProcessConfirm && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
563
|
+
ConfirmModal,
|
|
564
|
+
{
|
|
565
|
+
title: "Process Images",
|
|
566
|
+
message: processMode === "all" ? `Found ${processCount} unprocessed image${processCount !== 1 ? "s" : ""} in the public folder. This will generate thumbnails and remove any orphaned files from the images folder.` : `Process ${processCount} selected image${processCount !== 1 ? "s" : ""}? This will regenerate thumbnails for these files.`,
|
|
567
|
+
confirmLabel: processing ? "Processing..." : "Process",
|
|
568
|
+
onConfirm: handleProcessConfirm,
|
|
569
|
+
onCancel: () => setShowProcessConfirm(false)
|
|
570
|
+
}
|
|
571
|
+
),
|
|
446
572
|
alertMessage && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
447
573
|
AlertModal,
|
|
448
574
|
{
|
|
@@ -481,11 +607,11 @@ function StudioToolbar() {
|
|
|
481
607
|
"button",
|
|
482
608
|
{
|
|
483
609
|
css: styles2.btn,
|
|
484
|
-
onClick:
|
|
485
|
-
disabled:
|
|
610
|
+
onClick: handleProcessImages,
|
|
611
|
+
disabled: processing,
|
|
486
612
|
children: [
|
|
487
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
488
|
-
"
|
|
613
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, ImageStackIcon, {}),
|
|
614
|
+
processing ? "Processing..." : "Process Images"
|
|
489
615
|
]
|
|
490
616
|
}
|
|
491
617
|
),
|
|
@@ -527,7 +653,7 @@ function StudioToolbar() {
|
|
|
527
653
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
528
654
|
"button",
|
|
529
655
|
{
|
|
530
|
-
css: styles2.btn,
|
|
656
|
+
css: [styles2.btn, styles2.btnIconOnly],
|
|
531
657
|
onClick: handleRefresh,
|
|
532
658
|
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, RefreshIcon, { spinning: refreshing })
|
|
533
659
|
}
|
|
@@ -577,102 +703,8 @@ function GridIcon() {
|
|
|
577
703
|
function ListIcon() {
|
|
578
704
|
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles2.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" }) });
|
|
579
705
|
}
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
var styles3 = {
|
|
585
|
-
container: _react3.css`
|
|
586
|
-
display: flex;
|
|
587
|
-
align-items: center;
|
|
588
|
-
gap: 8px;
|
|
589
|
-
padding: 10px 24px;
|
|
590
|
-
background-color: ${_chunkAY2DAS6Wjs.colors.surface};
|
|
591
|
-
border-bottom: 1px solid ${_chunkAY2DAS6Wjs.colors.borderLight};
|
|
592
|
-
`,
|
|
593
|
-
backBtn: _react3.css`
|
|
594
|
-
padding: 6px;
|
|
595
|
-
background: ${_chunkAY2DAS6Wjs.colors.surface};
|
|
596
|
-
border: 1px solid ${_chunkAY2DAS6Wjs.colors.border};
|
|
597
|
-
border-radius: 6px;
|
|
598
|
-
cursor: pointer;
|
|
599
|
-
transition: all 0.15s ease;
|
|
600
|
-
display: flex;
|
|
601
|
-
align-items: center;
|
|
602
|
-
justify-content: center;
|
|
603
|
-
|
|
604
|
-
&:hover {
|
|
605
|
-
background-color: ${_chunkAY2DAS6Wjs.colors.surfaceHover};
|
|
606
|
-
border-color: ${_chunkAY2DAS6Wjs.colors.borderHover};
|
|
607
|
-
}
|
|
608
|
-
`,
|
|
609
|
-
backIcon: _react3.css`
|
|
610
|
-
width: 16px;
|
|
611
|
-
height: 16px;
|
|
612
|
-
color: ${_chunkAY2DAS6Wjs.colors.textSecondary};
|
|
613
|
-
`,
|
|
614
|
-
nav: _react3.css`
|
|
615
|
-
display: flex;
|
|
616
|
-
align-items: center;
|
|
617
|
-
gap: 2px;
|
|
618
|
-
font-size: ${_chunkAY2DAS6Wjs.fontSize.base};
|
|
619
|
-
`,
|
|
620
|
-
item: _react3.css`
|
|
621
|
-
display: flex;
|
|
622
|
-
align-items: center;
|
|
623
|
-
gap: 2px;
|
|
624
|
-
`,
|
|
625
|
-
separator: _react3.css`
|
|
626
|
-
color: ${_chunkAY2DAS6Wjs.colors.textMuted};
|
|
627
|
-
margin: 0 2px;
|
|
628
|
-
`,
|
|
629
|
-
btn: _react3.css`
|
|
630
|
-
padding: 4px 8px;
|
|
631
|
-
background: none;
|
|
632
|
-
border: none;
|
|
633
|
-
border-radius: 4px;
|
|
634
|
-
cursor: pointer;
|
|
635
|
-
transition: all 0.15s ease;
|
|
636
|
-
font-size: ${_chunkAY2DAS6Wjs.fontSize.base};
|
|
637
|
-
letter-spacing: -0.01em;
|
|
638
|
-
|
|
639
|
-
&:hover {
|
|
640
|
-
background-color: ${_chunkAY2DAS6Wjs.colors.surfaceHover};
|
|
641
|
-
}
|
|
642
|
-
`,
|
|
643
|
-
btnActive: _react3.css`
|
|
644
|
-
color: ${_chunkAY2DAS6Wjs.colors.text};
|
|
645
|
-
font-weight: 600;
|
|
646
|
-
`,
|
|
647
|
-
btnInactive: _react3.css`
|
|
648
|
-
color: ${_chunkAY2DAS6Wjs.colors.textSecondary};
|
|
649
|
-
|
|
650
|
-
&:hover {
|
|
651
|
-
color: ${_chunkAY2DAS6Wjs.colors.text};
|
|
652
|
-
}
|
|
653
|
-
`
|
|
654
|
-
};
|
|
655
|
-
function StudioBreadcrumb() {
|
|
656
|
-
const { currentPath, setCurrentPath, navigateUp } = useStudio();
|
|
657
|
-
const parts = currentPath.split("/").filter(Boolean);
|
|
658
|
-
const handleClick = (index) => {
|
|
659
|
-
const newPath = parts.slice(0, index + 1).join("/");
|
|
660
|
-
setCurrentPath(newPath);
|
|
661
|
-
};
|
|
662
|
-
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.container, children: [
|
|
663
|
-
currentPath !== "public" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles3.backBtn, onClick: navigateUp, "aria-label": "Go back", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles3.backIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) }) }),
|
|
664
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "nav", { css: styles3.nav, children: parts.map((part, index) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles3.item, children: [
|
|
665
|
-
index > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.separator, children: "/" }),
|
|
666
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
667
|
-
"button",
|
|
668
|
-
{
|
|
669
|
-
css: [styles3.btn, index === parts.length - 1 ? styles3.btnActive : styles3.btnInactive],
|
|
670
|
-
onClick: () => handleClick(index),
|
|
671
|
-
children: part
|
|
672
|
-
}
|
|
673
|
-
)
|
|
674
|
-
] }, index)) })
|
|
675
|
-
] });
|
|
706
|
+
function ImageStackIcon() {
|
|
707
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles2.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" }) });
|
|
676
708
|
}
|
|
677
709
|
|
|
678
710
|
// src/components/StudioFileGrid.tsx
|
|
@@ -682,7 +714,7 @@ function StudioBreadcrumb() {
|
|
|
682
714
|
var spin2 = _react3.keyframes`
|
|
683
715
|
to { transform: rotate(360deg); }
|
|
684
716
|
`;
|
|
685
|
-
var
|
|
717
|
+
var styles3 = {
|
|
686
718
|
loading: _react3.css`
|
|
687
719
|
display: flex;
|
|
688
720
|
align-items: center;
|
|
@@ -754,6 +786,13 @@ var styles4 = {
|
|
|
754
786
|
border-color: ${_chunkAY2DAS6Wjs.colors.primary};
|
|
755
787
|
}
|
|
756
788
|
`,
|
|
789
|
+
parentItem: _react3.css`
|
|
790
|
+
cursor: pointer;
|
|
791
|
+
|
|
792
|
+
&:hover {
|
|
793
|
+
border-color: ${_chunkAY2DAS6Wjs.colors.primary};
|
|
794
|
+
}
|
|
795
|
+
`,
|
|
757
796
|
checkboxWrapper: _react3.css`
|
|
758
797
|
position: absolute;
|
|
759
798
|
top: 0;
|
|
@@ -793,6 +832,11 @@ var styles4 = {
|
|
|
793
832
|
height: 56px;
|
|
794
833
|
color: #f5a623;
|
|
795
834
|
`,
|
|
835
|
+
parentIcon: _react3.css`
|
|
836
|
+
width: 56px;
|
|
837
|
+
height: 56px;
|
|
838
|
+
color: ${_chunkAY2DAS6Wjs.colors.textMuted};
|
|
839
|
+
`,
|
|
796
840
|
fileIcon: _react3.css`
|
|
797
841
|
width: 40px;
|
|
798
842
|
height: 40px;
|
|
@@ -836,15 +880,18 @@ var styles4 = {
|
|
|
836
880
|
`,
|
|
837
881
|
openBtn: _react3.css`
|
|
838
882
|
flex-shrink: 0;
|
|
883
|
+
height: 28px;
|
|
839
884
|
font-size: ${_chunkAY2DAS6Wjs.fontSize.xs};
|
|
840
885
|
font-weight: 500;
|
|
841
886
|
color: ${_chunkAY2DAS6Wjs.colors.primary};
|
|
842
887
|
background: ${_chunkAY2DAS6Wjs.colors.surface};
|
|
843
888
|
border: 1px solid ${_chunkAY2DAS6Wjs.colors.border};
|
|
844
|
-
padding:
|
|
889
|
+
padding: 0 10px;
|
|
845
890
|
cursor: pointer;
|
|
846
891
|
border-radius: 4px;
|
|
847
892
|
transition: all 0.15s ease;
|
|
893
|
+
display: inline-flex;
|
|
894
|
+
align-items: center;
|
|
848
895
|
|
|
849
896
|
&:hover {
|
|
850
897
|
background-color: ${_chunkAY2DAS6Wjs.colors.primaryLight};
|
|
@@ -880,7 +927,7 @@ var styles4 = {
|
|
|
880
927
|
`
|
|
881
928
|
};
|
|
882
929
|
function StudioFileGrid() {
|
|
883
|
-
const { currentPath, setCurrentPath, selectedItems, toggleSelection, selectRange, lastSelectedPath, selectAll, clearSelection, refreshKey } = useStudio();
|
|
930
|
+
const { currentPath, setCurrentPath, navigateUp, selectedItems, toggleSelection, selectRange, lastSelectedPath, selectAll, clearSelection, refreshKey, setFocusedItem } = useStudio();
|
|
884
931
|
const [items, setItems] = _react.useState.call(void 0, []);
|
|
885
932
|
const [loading, setLoading] = _react.useState.call(void 0, true);
|
|
886
933
|
_react.useEffect.call(void 0, () => {
|
|
@@ -900,13 +947,14 @@ function StudioFileGrid() {
|
|
|
900
947
|
loadItems();
|
|
901
948
|
}, [currentPath, refreshKey]);
|
|
902
949
|
if (loading) {
|
|
903
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css:
|
|
950
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles3.loading, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles3.spinner }) });
|
|
904
951
|
}
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "
|
|
909
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css:
|
|
952
|
+
const isAtRoot = currentPath === "public";
|
|
953
|
+
if (items.length === 0 && isAtRoot) {
|
|
954
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.empty, children: [
|
|
955
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles3.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" }) }),
|
|
956
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles3.emptyText, children: "No files in this folder" }),
|
|
957
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles3.emptyText, children: "Upload images to get started" })
|
|
910
958
|
] });
|
|
911
959
|
}
|
|
912
960
|
const sortedItems = [...items].sort((a, b) => {
|
|
@@ -921,9 +969,11 @@ function StudioFileGrid() {
|
|
|
921
969
|
toggleSelection(item.path);
|
|
922
970
|
}
|
|
923
971
|
};
|
|
924
|
-
const
|
|
972
|
+
const handleOpen = (item) => {
|
|
925
973
|
if (item.type === "folder") {
|
|
926
974
|
setCurrentPath(item.path);
|
|
975
|
+
} else {
|
|
976
|
+
setFocusedItem(item);
|
|
927
977
|
}
|
|
928
978
|
};
|
|
929
979
|
const allItemsSelected = sortedItems.length > 0 && sortedItems.every((item) => selectedItems.has(item.path));
|
|
@@ -936,12 +986,12 @@ function StudioFileGrid() {
|
|
|
936
986
|
}
|
|
937
987
|
};
|
|
938
988
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
|
|
939
|
-
sortedItems.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css:
|
|
989
|
+
sortedItems.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles3.selectAllRow, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "label", { css: styles3.selectAllLabel, children: [
|
|
940
990
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
941
991
|
"input",
|
|
942
992
|
{
|
|
943
993
|
type: "checkbox",
|
|
944
|
-
css:
|
|
994
|
+
css: styles3.selectAllCheckbox,
|
|
945
995
|
checked: allItemsSelected,
|
|
946
996
|
ref: (el) => {
|
|
947
997
|
if (el) el.indeterminate = someItemsSelected && !allItemsSelected;
|
|
@@ -953,16 +1003,32 @@ function StudioFileGrid() {
|
|
|
953
1003
|
sortedItems.length,
|
|
954
1004
|
")"
|
|
955
1005
|
] }) }),
|
|
956
|
-
/* @__PURE__ */ _jsxruntime.
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
1006
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.grid, children: [
|
|
1007
|
+
!isAtRoot && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1008
|
+
"div",
|
|
1009
|
+
{
|
|
1010
|
+
css: [styles3.item, styles3.parentItem],
|
|
1011
|
+
onClick: navigateUp,
|
|
1012
|
+
children: [
|
|
1013
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles3.content, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles3.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" }) }) }),
|
|
1014
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.label, children: [
|
|
1015
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles3.name, children: ".." }),
|
|
1016
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles3.size, children: "Parent folder" })
|
|
1017
|
+
] })
|
|
1018
|
+
]
|
|
1019
|
+
}
|
|
1020
|
+
),
|
|
1021
|
+
sortedItems.map((item) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1022
|
+
GridItem,
|
|
1023
|
+
{
|
|
1024
|
+
item,
|
|
1025
|
+
isSelected: selectedItems.has(item.path),
|
|
1026
|
+
onClick: (e) => handleItemClick(item, e),
|
|
1027
|
+
onOpen: () => handleOpen(item)
|
|
1028
|
+
},
|
|
1029
|
+
item.path
|
|
1030
|
+
))
|
|
1031
|
+
] })
|
|
966
1032
|
] });
|
|
967
1033
|
}
|
|
968
1034
|
function GridItem({ item, isSelected, onClick, onOpen }) {
|
|
@@ -970,48 +1036,48 @@ function GridItem({ item, isSelected, onClick, onOpen }) {
|
|
|
970
1036
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
971
1037
|
"div",
|
|
972
1038
|
{
|
|
973
|
-
css: [
|
|
1039
|
+
css: [styles3.item, isSelected && styles3.itemSelected],
|
|
974
1040
|
onClick,
|
|
975
1041
|
children: [
|
|
976
1042
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
977
1043
|
"div",
|
|
978
1044
|
{
|
|
979
|
-
css:
|
|
1045
|
+
css: styles3.checkboxWrapper,
|
|
980
1046
|
onClick: (e) => e.stopPropagation(),
|
|
981
1047
|
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
982
1048
|
"input",
|
|
983
1049
|
{
|
|
984
1050
|
type: "checkbox",
|
|
985
|
-
css:
|
|
1051
|
+
css: styles3.checkbox,
|
|
986
1052
|
checked: isSelected,
|
|
987
1053
|
onChange: () => onClick({})
|
|
988
1054
|
}
|
|
989
1055
|
)
|
|
990
1056
|
}
|
|
991
1057
|
),
|
|
992
|
-
item.cdnSynced && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css:
|
|
993
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css:
|
|
1058
|
+
item.cdnSynced && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.cdnBadge, children: "CDN" }),
|
|
1059
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles3.content, children: isFolder ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles3.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" }) }) : item.thumbnail ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
994
1060
|
"img",
|
|
995
1061
|
{
|
|
996
|
-
css:
|
|
1062
|
+
css: styles3.image,
|
|
997
1063
|
src: item.thumbnail,
|
|
998
1064
|
alt: item.name,
|
|
999
1065
|
loading: "lazy"
|
|
1000
1066
|
}
|
|
1001
|
-
) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
1002
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css:
|
|
1003
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
1004
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css:
|
|
1005
|
-
isFolder ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { css:
|
|
1067
|
+
) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles3.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" }) }) }),
|
|
1068
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles3.label, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.labelRow, children: [
|
|
1069
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.labelText, children: [
|
|
1070
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles3.name, title: item.name, children: item.name }),
|
|
1071
|
+
isFolder ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { css: styles3.size, children: [
|
|
1006
1072
|
item.fileCount !== void 0 ? `${item.fileCount} files` : "",
|
|
1007
1073
|
item.fileCount !== void 0 && item.totalSize !== void 0 ? " \xB7 " : "",
|
|
1008
1074
|
item.totalSize !== void 0 ? formatFileSize(item.totalSize) : ""
|
|
1009
|
-
] }) : item.size !== void 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css:
|
|
1075
|
+
] }) : item.size !== void 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles3.size, children: formatFileSize(item.size) })
|
|
1010
1076
|
] }),
|
|
1011
|
-
|
|
1077
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1012
1078
|
"button",
|
|
1013
1079
|
{
|
|
1014
|
-
css:
|
|
1080
|
+
css: styles3.openBtn,
|
|
1015
1081
|
onClick: (e) => {
|
|
1016
1082
|
e.stopPropagation();
|
|
1017
1083
|
onOpen();
|
|
@@ -1037,7 +1103,7 @@ function formatFileSize(bytes) {
|
|
|
1037
1103
|
var spin3 = _react3.keyframes`
|
|
1038
1104
|
to { transform: rotate(360deg); }
|
|
1039
1105
|
`;
|
|
1040
|
-
var
|
|
1106
|
+
var styles4 = {
|
|
1041
1107
|
loading: _react3.css`
|
|
1042
1108
|
display: flex;
|
|
1043
1109
|
align-items: center;
|
|
@@ -1114,6 +1180,13 @@ var styles5 = {
|
|
|
1114
1180
|
background-color: ${_chunkAY2DAS6Wjs.colors.primaryLight};
|
|
1115
1181
|
}
|
|
1116
1182
|
`,
|
|
1183
|
+
parentRow: _react3.css`
|
|
1184
|
+
cursor: pointer;
|
|
1185
|
+
|
|
1186
|
+
&:hover {
|
|
1187
|
+
background-color: ${_chunkAY2DAS6Wjs.colors.surfaceHover};
|
|
1188
|
+
}
|
|
1189
|
+
`,
|
|
1117
1190
|
td: _react3.css`
|
|
1118
1191
|
padding: 12px 16px;
|
|
1119
1192
|
`,
|
|
@@ -1138,6 +1211,12 @@ var styles5 = {
|
|
|
1138
1211
|
color: #f5a623;
|
|
1139
1212
|
flex-shrink: 0;
|
|
1140
1213
|
`,
|
|
1214
|
+
parentIcon: _react3.css`
|
|
1215
|
+
width: 20px;
|
|
1216
|
+
height: 20px;
|
|
1217
|
+
color: ${_chunkAY2DAS6Wjs.colors.textMuted};
|
|
1218
|
+
flex-shrink: 0;
|
|
1219
|
+
`,
|
|
1141
1220
|
fileIcon: _react3.css`
|
|
1142
1221
|
width: 20px;
|
|
1143
1222
|
height: 20px;
|
|
@@ -1179,15 +1258,19 @@ var styles5 = {
|
|
|
1179
1258
|
color: ${_chunkAY2DAS6Wjs.colors.textMuted};
|
|
1180
1259
|
`,
|
|
1181
1260
|
openBtn: _react3.css`
|
|
1261
|
+
height: 28px;
|
|
1182
1262
|
font-size: ${_chunkAY2DAS6Wjs.fontSize.xs};
|
|
1183
1263
|
font-weight: 500;
|
|
1184
1264
|
color: ${_chunkAY2DAS6Wjs.colors.primary};
|
|
1185
1265
|
background: ${_chunkAY2DAS6Wjs.colors.surface};
|
|
1186
1266
|
border: 1px solid ${_chunkAY2DAS6Wjs.colors.border};
|
|
1187
|
-
padding:
|
|
1267
|
+
padding: 0 12px;
|
|
1188
1268
|
cursor: pointer;
|
|
1189
1269
|
border-radius: 4px;
|
|
1190
1270
|
transition: all 0.15s ease;
|
|
1271
|
+
display: inline-flex;
|
|
1272
|
+
align-items: center;
|
|
1273
|
+
margin-left: auto;
|
|
1191
1274
|
|
|
1192
1275
|
&:hover {
|
|
1193
1276
|
background-color: ${_chunkAY2DAS6Wjs.colors.primaryLight};
|
|
@@ -1196,7 +1279,7 @@ var styles5 = {
|
|
|
1196
1279
|
`
|
|
1197
1280
|
};
|
|
1198
1281
|
function StudioFileList() {
|
|
1199
|
-
const { currentPath, setCurrentPath, selectedItems, toggleSelection, selectRange, lastSelectedPath, selectAll, clearSelection, refreshKey } = useStudio();
|
|
1282
|
+
const { currentPath, setCurrentPath, navigateUp, selectedItems, toggleSelection, selectRange, lastSelectedPath, selectAll, clearSelection, refreshKey, setFocusedItem } = useStudio();
|
|
1200
1283
|
const [items, setItems] = _react.useState.call(void 0, []);
|
|
1201
1284
|
const [loading, setLoading] = _react.useState.call(void 0, true);
|
|
1202
1285
|
_react.useEffect.call(void 0, () => {
|
|
@@ -1216,10 +1299,11 @@ function StudioFileList() {
|
|
|
1216
1299
|
loadItems();
|
|
1217
1300
|
}, [currentPath, refreshKey]);
|
|
1218
1301
|
if (loading) {
|
|
1219
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css:
|
|
1302
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles4.loading, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles4.spinner }) });
|
|
1220
1303
|
}
|
|
1221
|
-
|
|
1222
|
-
|
|
1304
|
+
const isAtRoot = currentPath === "public";
|
|
1305
|
+
if (items.length === 0 && isAtRoot) {
|
|
1306
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles4.empty, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { children: "No files in this folder" }) });
|
|
1223
1307
|
}
|
|
1224
1308
|
const sortedItems = [...items].sort((a, b) => {
|
|
1225
1309
|
if (a.type === "folder" && b.type !== "folder") return -1;
|
|
@@ -1233,9 +1317,11 @@ function StudioFileList() {
|
|
|
1233
1317
|
toggleSelection(item.path);
|
|
1234
1318
|
}
|
|
1235
1319
|
};
|
|
1236
|
-
const
|
|
1320
|
+
const handleOpen = (item) => {
|
|
1237
1321
|
if (item.type === "folder") {
|
|
1238
1322
|
setCurrentPath(item.path);
|
|
1323
|
+
} else {
|
|
1324
|
+
setFocusedItem(item);
|
|
1239
1325
|
}
|
|
1240
1326
|
};
|
|
1241
1327
|
const allItemsSelected = sortedItems.length > 0 && sortedItems.every((item) => selectedItems.has(item.path));
|
|
@@ -1247,13 +1333,13 @@ function StudioFileList() {
|
|
|
1247
1333
|
selectAll(sortedItems);
|
|
1248
1334
|
}
|
|
1249
1335
|
};
|
|
1250
|
-
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "table", { css:
|
|
1336
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles4.tableWrapper, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "table", { css: styles4.table, children: [
|
|
1251
1337
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "thead", { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tr", { children: [
|
|
1252
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [
|
|
1338
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles4.th, styles4.thCheckbox], children: sortedItems.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1253
1339
|
"input",
|
|
1254
1340
|
{
|
|
1255
1341
|
type: "checkbox",
|
|
1256
|
-
css:
|
|
1342
|
+
css: styles4.checkbox,
|
|
1257
1343
|
checked: allItemsSelected,
|
|
1258
1344
|
ref: (el) => {
|
|
1259
1345
|
if (el) el.indeterminate = someItemsSelected && !allItemsSelected;
|
|
@@ -1261,54 +1347,66 @@ function StudioFileList() {
|
|
|
1261
1347
|
onChange: handleSelectAll
|
|
1262
1348
|
}
|
|
1263
1349
|
) }),
|
|
1264
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css:
|
|
1265
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [
|
|
1266
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [
|
|
1267
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [
|
|
1350
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: styles4.th, children: "Name" }),
|
|
1351
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles4.th, styles4.thSize], children: "Size" }),
|
|
1352
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles4.th, styles4.thDimensions], children: "Dimensions" }),
|
|
1353
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles4.th, styles4.thCdn], children: "CDN" })
|
|
1268
1354
|
] }) }),
|
|
1269
|
-
/* @__PURE__ */ _jsxruntime.
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1355
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tbody", { css: styles4.tbody, children: [
|
|
1356
|
+
!isAtRoot && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tr", { css: styles4.parentRow, onClick: navigateUp, children: [
|
|
1357
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles4.td }),
|
|
1358
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles4.td, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.nameCell, children: [
|
|
1359
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.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" }) }),
|
|
1360
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles4.name, children: ".." })
|
|
1361
|
+
] }) }),
|
|
1362
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles4.td, styles4.meta], children: "--" }),
|
|
1363
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles4.td, styles4.meta], children: "Parent folder" }),
|
|
1364
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles4.td, children: "--" })
|
|
1365
|
+
] }),
|
|
1366
|
+
sortedItems.map((item) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1367
|
+
ListRow,
|
|
1368
|
+
{
|
|
1369
|
+
item,
|
|
1370
|
+
isSelected: selectedItems.has(item.path),
|
|
1371
|
+
onClick: (e) => handleItemClick(item, e),
|
|
1372
|
+
onOpen: () => handleOpen(item)
|
|
1373
|
+
},
|
|
1374
|
+
item.path
|
|
1375
|
+
))
|
|
1376
|
+
] })
|
|
1377
|
+
] }) });
|
|
1280
1378
|
}
|
|
1281
1379
|
function ListRow({ item, isSelected, onClick, onOpen }) {
|
|
1282
1380
|
const isFolder = item.type === "folder";
|
|
1283
1381
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1284
1382
|
"tr",
|
|
1285
1383
|
{
|
|
1286
|
-
css: [
|
|
1384
|
+
css: [styles4.row, isSelected && styles4.rowSelected],
|
|
1287
1385
|
onClick,
|
|
1288
1386
|
children: [
|
|
1289
1387
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1290
1388
|
"td",
|
|
1291
1389
|
{
|
|
1292
|
-
css: [
|
|
1390
|
+
css: [styles4.td, styles4.checkboxCell],
|
|
1293
1391
|
onClick: (e) => e.stopPropagation(),
|
|
1294
1392
|
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1295
1393
|
"input",
|
|
1296
1394
|
{
|
|
1297
1395
|
type: "checkbox",
|
|
1298
|
-
css:
|
|
1396
|
+
css: styles4.checkbox,
|
|
1299
1397
|
checked: isSelected,
|
|
1300
1398
|
onChange: () => onClick({})
|
|
1301
1399
|
}
|
|
1302
1400
|
)
|
|
1303
1401
|
}
|
|
1304
1402
|
),
|
|
1305
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css:
|
|
1306
|
-
isFolder ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
1307
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css:
|
|
1308
|
-
|
|
1403
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles4.td, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.nameCell, children: [
|
|
1404
|
+
isFolder ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.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" }) }) : item.thumbnail ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { css: styles4.thumbnail, src: item.thumbnail, alt: item.name, loading: "lazy" }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.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" }) }),
|
|
1405
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles4.name, children: item.name }),
|
|
1406
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1309
1407
|
"button",
|
|
1310
1408
|
{
|
|
1311
|
-
css:
|
|
1409
|
+
css: styles4.openBtn,
|
|
1312
1410
|
onClick: (e) => {
|
|
1313
1411
|
e.stopPropagation();
|
|
1314
1412
|
onOpen();
|
|
@@ -1317,12 +1415,12 @@ function ListRow({ item, isSelected, onClick, onOpen }) {
|
|
|
1317
1415
|
}
|
|
1318
1416
|
)
|
|
1319
1417
|
] }) }),
|
|
1320
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [
|
|
1321
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [
|
|
1322
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css:
|
|
1323
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
1418
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles4.td, styles4.meta], children: isFolder ? item.fileCount !== void 0 ? `${item.fileCount} files` : "--" : item.size !== void 0 ? formatFileSize2(item.size) : "--" }),
|
|
1419
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles4.td, styles4.meta], children: isFolder ? item.totalSize !== void 0 ? formatFileSize2(item.totalSize) : "--" : item.dimensions ? `${item.dimensions.width}x${item.dimensions.height}` : "--" }),
|
|
1420
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles4.td, children: item.cdnSynced ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles4.cdnBadge, children: [
|
|
1421
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.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" }) }),
|
|
1324
1422
|
"Synced"
|
|
1325
|
-
] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css:
|
|
1423
|
+
] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles4.cdnEmpty, children: "--" }) })
|
|
1326
1424
|
]
|
|
1327
1425
|
}
|
|
1328
1426
|
);
|
|
@@ -1333,7 +1431,7 @@ function formatFileSize2(bytes) {
|
|
|
1333
1431
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
1334
1432
|
}
|
|
1335
1433
|
|
|
1336
|
-
// src/components/
|
|
1434
|
+
// src/components/StudioDetailView.tsx
|
|
1337
1435
|
|
|
1338
1436
|
|
|
1339
1437
|
|
|
@@ -1347,161 +1445,158 @@ function isVideoFile(filename) {
|
|
|
1347
1445
|
const ext = filename.toLowerCase().substring(filename.lastIndexOf("."));
|
|
1348
1446
|
return VIDEO_EXTENSIONS.includes(ext);
|
|
1349
1447
|
}
|
|
1350
|
-
var
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1448
|
+
var styles5 = {
|
|
1449
|
+
container: _react3.css`
|
|
1450
|
+
display: flex;
|
|
1451
|
+
flex: 1;
|
|
1452
|
+
overflow: hidden;
|
|
1453
|
+
`,
|
|
1454
|
+
main: _react3.css`
|
|
1455
|
+
flex: 1;
|
|
1456
|
+
display: flex;
|
|
1457
|
+
flex-direction: column;
|
|
1458
|
+
align-items: center;
|
|
1459
|
+
justify-content: center;
|
|
1460
|
+
padding: 24px;
|
|
1461
|
+
background: ${_chunkAY2DAS6Wjs.colors.background};
|
|
1356
1462
|
overflow: auto;
|
|
1357
1463
|
`,
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
margin: 0 0 16px 0;
|
|
1464
|
+
mediaWrapper: _react3.css`
|
|
1465
|
+
max-width: 100%;
|
|
1466
|
+
max-height: 100%;
|
|
1467
|
+
display: flex;
|
|
1468
|
+
align-items: center;
|
|
1469
|
+
justify-content: center;
|
|
1365
1470
|
`,
|
|
1366
|
-
|
|
1367
|
-
|
|
1471
|
+
image: _react3.css`
|
|
1472
|
+
max-width: 100%;
|
|
1473
|
+
max-height: calc(100vh - 200px);
|
|
1474
|
+
object-fit: contain;
|
|
1368
1475
|
border-radius: 8px;
|
|
1369
|
-
|
|
1370
|
-
padding: 12px;
|
|
1371
|
-
margin-bottom: 20px;
|
|
1476
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
1372
1477
|
`,
|
|
1373
|
-
|
|
1374
|
-
width: 100%;
|
|
1375
|
-
height:
|
|
1376
|
-
border-radius:
|
|
1478
|
+
video: _react3.css`
|
|
1479
|
+
max-width: 100%;
|
|
1480
|
+
max-height: calc(100vh - 200px);
|
|
1481
|
+
border-radius: 8px;
|
|
1482
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
1377
1483
|
`,
|
|
1378
|
-
|
|
1484
|
+
filePlaceholder: _react3.css`
|
|
1379
1485
|
display: flex;
|
|
1380
1486
|
flex-direction: column;
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1487
|
+
align-items: center;
|
|
1488
|
+
justify-content: center;
|
|
1489
|
+
padding: 48px;
|
|
1490
|
+
background: ${_chunkAY2DAS6Wjs.colors.surface};
|
|
1491
|
+
border-radius: 12px;
|
|
1492
|
+
border: 1px solid ${_chunkAY2DAS6Wjs.colors.border};
|
|
1387
1493
|
`,
|
|
1388
|
-
|
|
1389
|
-
|
|
1494
|
+
fileIcon: _react3.css`
|
|
1495
|
+
width: 80px;
|
|
1496
|
+
height: 80px;
|
|
1497
|
+
color: ${_chunkAY2DAS6Wjs.colors.textMuted};
|
|
1498
|
+
margin-bottom: 16px;
|
|
1390
1499
|
`,
|
|
1391
|
-
|
|
1500
|
+
fileName: _react3.css`
|
|
1501
|
+
font-size: ${_chunkAY2DAS6Wjs.fontSize.lg};
|
|
1502
|
+
font-weight: 600;
|
|
1392
1503
|
color: ${_chunkAY2DAS6Wjs.colors.text};
|
|
1393
|
-
|
|
1504
|
+
margin: 0;
|
|
1394
1505
|
`,
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1506
|
+
sidebar: _react3.css`
|
|
1507
|
+
width: 280px;
|
|
1508
|
+
background: ${_chunkAY2DAS6Wjs.colors.surface};
|
|
1509
|
+
border-left: 1px solid ${_chunkAY2DAS6Wjs.colors.border};
|
|
1510
|
+
display: flex;
|
|
1511
|
+
flex-direction: column;
|
|
1398
1512
|
overflow: hidden;
|
|
1399
|
-
text-overflow: ellipsis;
|
|
1400
1513
|
`,
|
|
1401
|
-
|
|
1402
|
-
padding
|
|
1403
|
-
|
|
1404
|
-
border-top: 1px solid ${_chunkAY2DAS6Wjs.colors.borderLight};
|
|
1405
|
-
`,
|
|
1406
|
-
sectionTitle: _react3.css`
|
|
1407
|
-
font-size: ${_chunkAY2DAS6Wjs.fontSize.xs};
|
|
1408
|
-
font-weight: 600;
|
|
1409
|
-
color: ${_chunkAY2DAS6Wjs.colors.textMuted};
|
|
1410
|
-
text-transform: uppercase;
|
|
1411
|
-
letter-spacing: 0.05em;
|
|
1412
|
-
margin: 0 0 10px 0;
|
|
1413
|
-
`,
|
|
1414
|
-
cdnStatus: _react3.css`
|
|
1514
|
+
sidebarHeader: _react3.css`
|
|
1515
|
+
padding: 16px 20px;
|
|
1516
|
+
border-bottom: 1px solid ${_chunkAY2DAS6Wjs.colors.border};
|
|
1415
1517
|
display: flex;
|
|
1416
1518
|
align-items: center;
|
|
1417
|
-
|
|
1418
|
-
font-size: ${_chunkAY2DAS6Wjs.fontSize.sm};
|
|
1419
|
-
color: ${_chunkAY2DAS6Wjs.colors.success};
|
|
1420
|
-
font-weight: 500;
|
|
1519
|
+
justify-content: space-between;
|
|
1421
1520
|
`,
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1521
|
+
sidebarTitle: _react3.css`
|
|
1522
|
+
font-size: ${_chunkAY2DAS6Wjs.fontSize.base};
|
|
1523
|
+
font-weight: 600;
|
|
1524
|
+
color: ${_chunkAY2DAS6Wjs.colors.text};
|
|
1525
|
+
margin: 0;
|
|
1425
1526
|
`,
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
background: none;
|
|
1432
|
-
border: none;
|
|
1527
|
+
closeBtn: _react3.css`
|
|
1528
|
+
padding: 6px;
|
|
1529
|
+
background: ${_chunkAY2DAS6Wjs.colors.surface};
|
|
1530
|
+
border: 1px solid ${_chunkAY2DAS6Wjs.colors.border};
|
|
1531
|
+
border-radius: 6px;
|
|
1433
1532
|
cursor: pointer;
|
|
1434
|
-
|
|
1533
|
+
transition: all 0.15s ease;
|
|
1534
|
+
display: flex;
|
|
1535
|
+
align-items: center;
|
|
1536
|
+
justify-content: center;
|
|
1435
1537
|
|
|
1436
1538
|
&:hover {
|
|
1437
|
-
|
|
1539
|
+
background-color: ${_chunkAY2DAS6Wjs.colors.surfaceHover};
|
|
1540
|
+
border-color: ${_chunkAY2DAS6Wjs.colors.borderHover};
|
|
1438
1541
|
}
|
|
1439
1542
|
`,
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
height:
|
|
1443
|
-
|
|
1444
|
-
|
|
1543
|
+
closeIcon: _react3.css`
|
|
1544
|
+
width: 16px;
|
|
1545
|
+
height: 16px;
|
|
1546
|
+
color: ${_chunkAY2DAS6Wjs.colors.textSecondary};
|
|
1547
|
+
`,
|
|
1548
|
+
sidebarContent: _react3.css`
|
|
1549
|
+
flex: 1;
|
|
1550
|
+
padding: 20px;
|
|
1551
|
+
overflow: auto;
|
|
1445
1552
|
`,
|
|
1446
|
-
|
|
1553
|
+
info: _react3.css`
|
|
1447
1554
|
display: flex;
|
|
1448
1555
|
flex-direction: column;
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
height: 200px;
|
|
1452
|
-
text-align: center;
|
|
1453
|
-
`,
|
|
1454
|
-
emptyText: _react3.css`
|
|
1455
|
-
font-size: ${_chunkAY2DAS6Wjs.fontSize.sm};
|
|
1456
|
-
color: ${_chunkAY2DAS6Wjs.colors.textMuted};
|
|
1457
|
-
margin: 0;
|
|
1556
|
+
gap: 12px;
|
|
1557
|
+
margin-bottom: 24px;
|
|
1458
1558
|
`,
|
|
1459
|
-
|
|
1559
|
+
infoRow: _react3.css`
|
|
1460
1560
|
display: flex;
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
height: 120px;
|
|
1464
|
-
background: ${_chunkAY2DAS6Wjs.colors.background};
|
|
1465
|
-
border-radius: 6px;
|
|
1466
|
-
`,
|
|
1467
|
-
fileIcon: _react3.css`
|
|
1468
|
-
width: 56px;
|
|
1469
|
-
height: 56px;
|
|
1470
|
-
color: ${_chunkAY2DAS6Wjs.colors.textMuted};
|
|
1561
|
+
justify-content: space-between;
|
|
1562
|
+
font-size: ${_chunkAY2DAS6Wjs.fontSize.sm};
|
|
1471
1563
|
`,
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
height: 56px;
|
|
1475
|
-
color: #f5a623;
|
|
1564
|
+
infoLabel: _react3.css`
|
|
1565
|
+
color: ${_chunkAY2DAS6Wjs.colors.textSecondary};
|
|
1476
1566
|
`,
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1567
|
+
infoValue: _react3.css`
|
|
1568
|
+
color: ${_chunkAY2DAS6Wjs.colors.text};
|
|
1569
|
+
font-weight: 500;
|
|
1570
|
+
text-align: right;
|
|
1571
|
+
max-width: 160px;
|
|
1572
|
+
overflow: hidden;
|
|
1573
|
+
text-overflow: ellipsis;
|
|
1574
|
+
white-space: nowrap;
|
|
1481
1575
|
`,
|
|
1482
1576
|
actions: _react3.css`
|
|
1483
|
-
margin-top: 20px;
|
|
1484
|
-
padding-top: 20px;
|
|
1485
|
-
border-top: 1px solid ${_chunkAY2DAS6Wjs.colors.border};
|
|
1486
1577
|
display: flex;
|
|
1487
1578
|
flex-direction: column;
|
|
1488
1579
|
gap: 8px;
|
|
1489
1580
|
`,
|
|
1490
1581
|
actionBtn: _react3.css`
|
|
1582
|
+
display: flex;
|
|
1583
|
+
align-items: center;
|
|
1584
|
+
gap: 10px;
|
|
1491
1585
|
width: 100%;
|
|
1492
|
-
padding:
|
|
1586
|
+
padding: 12px 14px;
|
|
1493
1587
|
font-size: ${_chunkAY2DAS6Wjs.fontSize.base};
|
|
1494
1588
|
font-weight: 500;
|
|
1495
|
-
background
|
|
1589
|
+
background: ${_chunkAY2DAS6Wjs.colors.surface};
|
|
1496
1590
|
border: 1px solid ${_chunkAY2DAS6Wjs.colors.border};
|
|
1497
1591
|
border-radius: 6px;
|
|
1498
1592
|
cursor: pointer;
|
|
1499
1593
|
transition: all 0.15s ease;
|
|
1500
1594
|
color: ${_chunkAY2DAS6Wjs.colors.text};
|
|
1595
|
+
text-align: left;
|
|
1501
1596
|
|
|
1502
1597
|
&:hover {
|
|
1503
1598
|
background-color: ${_chunkAY2DAS6Wjs.colors.surfaceHover};
|
|
1504
|
-
border-color:
|
|
1599
|
+
border-color: ${_chunkAY2DAS6Wjs.colors.borderHover};
|
|
1505
1600
|
}
|
|
1506
1601
|
`,
|
|
1507
1602
|
actionBtnDanger: _react3.css`
|
|
@@ -1511,27 +1606,42 @@ var styles6 = {
|
|
|
1511
1606
|
background-color: ${_chunkAY2DAS6Wjs.colors.dangerLight};
|
|
1512
1607
|
border-color: ${_chunkAY2DAS6Wjs.colors.danger};
|
|
1513
1608
|
}
|
|
1609
|
+
`,
|
|
1610
|
+
actionIcon: _react3.css`
|
|
1611
|
+
width: 16px;
|
|
1612
|
+
height: 16px;
|
|
1613
|
+
flex-shrink: 0;
|
|
1514
1614
|
`
|
|
1515
1615
|
};
|
|
1516
|
-
function
|
|
1517
|
-
const {
|
|
1616
|
+
function StudioDetailView() {
|
|
1617
|
+
const { focusedItem, setFocusedItem, triggerRefresh, clearSelection } = useStudio();
|
|
1518
1618
|
const [showDeleteConfirm, setShowDeleteConfirm] = _react.useState.call(void 0, false);
|
|
1519
1619
|
const [alertMessage, setAlertMessage] = _react.useState.call(void 0, null);
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1620
|
+
if (!focusedItem) return null;
|
|
1621
|
+
const isImage = isImageFile(focusedItem.name);
|
|
1622
|
+
const isVideo = isVideoFile(focusedItem.name);
|
|
1623
|
+
const imageSrc = focusedItem.path.replace("public", "");
|
|
1624
|
+
const handleClose = () => {
|
|
1625
|
+
setFocusedItem(null);
|
|
1626
|
+
};
|
|
1627
|
+
const handleRename = () => {
|
|
1628
|
+
const newName = prompt("Enter new name:", focusedItem.name);
|
|
1629
|
+
if (newName && newName !== focusedItem.name) {
|
|
1630
|
+
console.log("Rename to:", newName);
|
|
1631
|
+
}
|
|
1523
1632
|
};
|
|
1524
|
-
const
|
|
1633
|
+
const handleDelete = async () => {
|
|
1525
1634
|
setShowDeleteConfirm(false);
|
|
1526
1635
|
try {
|
|
1527
1636
|
const response = await fetch("/api/studio/delete", {
|
|
1528
1637
|
method: "POST",
|
|
1529
1638
|
headers: { "Content-Type": "application/json" },
|
|
1530
|
-
body: JSON.stringify({ paths:
|
|
1639
|
+
body: JSON.stringify({ paths: [focusedItem.path] })
|
|
1531
1640
|
});
|
|
1532
1641
|
if (response.ok) {
|
|
1533
1642
|
clearSelection();
|
|
1534
1643
|
triggerRefresh();
|
|
1644
|
+
setFocusedItem(null);
|
|
1535
1645
|
} else {
|
|
1536
1646
|
const error = await response.json();
|
|
1537
1647
|
setAlertMessage({
|
|
@@ -1547,15 +1657,33 @@ function StudioPreview() {
|
|
|
1547
1657
|
});
|
|
1548
1658
|
}
|
|
1549
1659
|
};
|
|
1550
|
-
const
|
|
1660
|
+
const handleSync = () => {
|
|
1661
|
+
console.log("Sync to CDN:", focusedItem.path);
|
|
1662
|
+
};
|
|
1663
|
+
const handleRegenerate = () => {
|
|
1664
|
+
console.log("Regenerate:", focusedItem.path);
|
|
1665
|
+
};
|
|
1666
|
+
const renderMedia = () => {
|
|
1667
|
+
if (isImage) {
|
|
1668
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { css: styles5.image, src: imageSrc, alt: focusedItem.name });
|
|
1669
|
+
}
|
|
1670
|
+
if (isVideo) {
|
|
1671
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "video", { css: styles5.video, src: imageSrc, controls: true });
|
|
1672
|
+
}
|
|
1673
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.filePlaceholder, children: [
|
|
1674
|
+
/* @__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" }) }),
|
|
1675
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.fileName, children: focusedItem.name })
|
|
1676
|
+
] });
|
|
1677
|
+
};
|
|
1678
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
1551
1679
|
showDeleteConfirm && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1552
1680
|
ConfirmModal,
|
|
1553
1681
|
{
|
|
1554
|
-
title: "Delete
|
|
1555
|
-
message: `Are you sure you want to delete ${
|
|
1682
|
+
title: "Delete File",
|
|
1683
|
+
message: `Are you sure you want to delete "${focusedItem.name}"? This action cannot be undone.`,
|
|
1556
1684
|
confirmLabel: "Delete",
|
|
1557
1685
|
variant: "danger",
|
|
1558
|
-
onConfirm:
|
|
1686
|
+
onConfirm: handleDelete,
|
|
1559
1687
|
onCancel: () => setShowDeleteConfirm(false)
|
|
1560
1688
|
}
|
|
1561
1689
|
),
|
|
@@ -1566,136 +1694,60 @@ function StudioPreview() {
|
|
|
1566
1694
|
message: alertMessage.message,
|
|
1567
1695
|
onClose: () => setAlertMessage(null)
|
|
1568
1696
|
}
|
|
1569
|
-
)
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.emptyState, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.emptyText, children: "Select an image to preview" }) })
|
|
1577
|
-
] })
|
|
1578
|
-
] });
|
|
1579
|
-
}
|
|
1580
|
-
if (selectedItems.size > 1) {
|
|
1581
|
-
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
1582
|
-
modals,
|
|
1583
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.panel, children: [
|
|
1584
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "h3", { css: styles6.title, children: [
|
|
1585
|
-
selectedItems.size,
|
|
1586
|
-
" items selected"
|
|
1697
|
+
),
|
|
1698
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.container, children: [
|
|
1699
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.main, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.mediaWrapper, children: renderMedia() }) }),
|
|
1700
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.sidebar, children: [
|
|
1701
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.sidebarHeader, children: [
|
|
1702
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles5.sidebarTitle, children: "Details" }),
|
|
1703
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles5.closeBtn, onClick: handleClose, "aria-label": "Close", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.closeIcon, 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" }) }) })
|
|
1587
1704
|
] }),
|
|
1588
|
-
/* @__PURE__ */ _jsxruntime.
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
] })
|
|
1594
|
-
] });
|
|
1595
|
-
}
|
|
1596
|
-
const selectedPath = Array.from(selectedItems)[0];
|
|
1597
|
-
const isFolder = !selectedPath.includes(".") || selectedPath.endsWith("/");
|
|
1598
|
-
const filename = selectedPath.split("/").pop() || "";
|
|
1599
|
-
const isImage = isImageFile(filename);
|
|
1600
|
-
const isVideo = isVideoFile(filename);
|
|
1601
|
-
const imageKey = selectedPath.replace(/^public\/images\//, "").replace(/^public\/originals\//, "").replace(/^public\//, "");
|
|
1602
|
-
const imageData = _optionalChain([meta, 'optionalAccess', _4 => _4.images, 'optionalAccess', _5 => _5[imageKey]]);
|
|
1603
|
-
const renderPreview = () => {
|
|
1604
|
-
if (isFolder) {
|
|
1605
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.filePlaceholder, 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" }) }) });
|
|
1606
|
-
}
|
|
1607
|
-
if (isImage) {
|
|
1608
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1609
|
-
"img",
|
|
1610
|
-
{
|
|
1611
|
-
css: styles6.image,
|
|
1612
|
-
src: selectedPath.replace("public", ""),
|
|
1613
|
-
alt: "Preview"
|
|
1614
|
-
}
|
|
1615
|
-
);
|
|
1616
|
-
}
|
|
1617
|
-
if (isVideo) {
|
|
1618
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1619
|
-
"video",
|
|
1620
|
-
{
|
|
1621
|
-
css: styles6.video,
|
|
1622
|
-
src: selectedPath.replace("public", ""),
|
|
1623
|
-
controls: true,
|
|
1624
|
-
muted: true
|
|
1625
|
-
}
|
|
1626
|
-
);
|
|
1627
|
-
}
|
|
1628
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.filePlaceholder, 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" }) }) });
|
|
1629
|
-
};
|
|
1630
|
-
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
1631
|
-
modals,
|
|
1632
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.panel, children: [
|
|
1633
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles6.title, children: "Preview" }),
|
|
1634
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.imageContainer, children: renderPreview() }),
|
|
1635
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.info, children: [
|
|
1636
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, InfoRow, { label: "Filename", value: selectedPath.split("/").pop() || "" }),
|
|
1637
|
-
imageData && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
1638
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1639
|
-
InfoRow,
|
|
1640
|
-
{
|
|
1641
|
-
label: "Original",
|
|
1642
|
-
value: `${imageData.original.width}x${imageData.original.height}`
|
|
1643
|
-
}
|
|
1644
|
-
),
|
|
1645
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1646
|
-
InfoRow,
|
|
1647
|
-
{
|
|
1648
|
-
label: "File size",
|
|
1649
|
-
value: formatFileSize3(imageData.original.fileSize)
|
|
1650
|
-
}
|
|
1651
|
-
),
|
|
1652
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.section, children: [
|
|
1653
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.sectionTitle, children: "Generated sizes" }),
|
|
1654
|
-
Object.entries(imageData.sizes).map(([size, data]) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, InfoRow, { label: size, value: `${data.width}x${data.height}` }, size))
|
|
1655
|
-
] }),
|
|
1656
|
-
_optionalChain([imageData, 'access', _6 => _6.cdn, 'optionalAccess', _7 => _7.synced]) && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.section, children: [
|
|
1657
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.sectionTitle, children: "CDN" }),
|
|
1658
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.cdnStatus, children: [
|
|
1659
|
-
/* @__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" }) }),
|
|
1660
|
-
"Synced to CDN"
|
|
1705
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.sidebarContent, children: [
|
|
1706
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.info, children: [
|
|
1707
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.infoRow, children: [
|
|
1708
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles5.infoLabel, children: "Name" }),
|
|
1709
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles5.infoValue, title: focusedItem.name, children: focusedItem.name })
|
|
1661
1710
|
] }),
|
|
1662
|
-
/* @__PURE__ */ _jsxruntime.
|
|
1663
|
-
"
|
|
1664
|
-
{
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1711
|
+
focusedItem.size !== void 0 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.infoRow, children: [
|
|
1712
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles5.infoLabel, children: "Size" }),
|
|
1713
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles5.infoValue, children: formatFileSize3(focusedItem.size) })
|
|
1714
|
+
] }),
|
|
1715
|
+
focusedItem.dimensions && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.infoRow, children: [
|
|
1716
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles5.infoLabel, children: "Dimensions" }),
|
|
1717
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles5.infoValue, children: [
|
|
1718
|
+
focusedItem.dimensions.width,
|
|
1719
|
+
" \xD7 ",
|
|
1720
|
+
focusedItem.dimensions.height
|
|
1721
|
+
] })
|
|
1722
|
+
] }),
|
|
1723
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.infoRow, children: [
|
|
1724
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles5.infoLabel, children: "CDN Status" }),
|
|
1725
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles5.infoValue, children: focusedItem.cdnSynced ? "Synced" : "Not synced" })
|
|
1726
|
+
] })
|
|
1672
1727
|
] }),
|
|
1673
|
-
|
|
1674
|
-
/* @__PURE__ */ _jsxruntime.
|
|
1675
|
-
|
|
1676
|
-
"
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1728
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.actions, children: [
|
|
1729
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles5.actionBtn, onClick: handleRename, children: [
|
|
1730
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.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" }) }),
|
|
1731
|
+
"Rename"
|
|
1732
|
+
] }),
|
|
1733
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles5.actionBtn, onClick: handleSync, children: [
|
|
1734
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.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" }) }),
|
|
1735
|
+
"Sync to CDN"
|
|
1736
|
+
] }),
|
|
1737
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles5.actionBtn, onClick: handleRegenerate, children: [
|
|
1738
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.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 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" }) }),
|
|
1739
|
+
"Regenerate"
|
|
1740
|
+
] }),
|
|
1741
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: [styles5.actionBtn, styles5.actionBtnDanger], onClick: () => setShowDeleteConfirm(true), children: [
|
|
1742
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.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" }) }),
|
|
1743
|
+
"Delete"
|
|
1744
|
+
] })
|
|
1683
1745
|
] })
|
|
1684
1746
|
] })
|
|
1685
|
-
] }),
|
|
1686
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.actions, children: [
|
|
1687
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles6.actionBtn, children: "Rename" }),
|
|
1688
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: [styles6.actionBtn, styles6.actionBtnDanger], onClick: handleDeleteClick, children: "Delete" })
|
|
1689
1747
|
] })
|
|
1690
1748
|
] })
|
|
1691
1749
|
] });
|
|
1692
1750
|
}
|
|
1693
|
-
function InfoRow({ label, value, truncate }) {
|
|
1694
|
-
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.row, children: [
|
|
1695
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles6.label, children: label }),
|
|
1696
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: [styles6.value, truncate && styles6.valueTruncate], title: truncate ? value : void 0, children: value })
|
|
1697
|
-
] });
|
|
1698
|
-
}
|
|
1699
1751
|
function formatFileSize3(bytes) {
|
|
1700
1752
|
if (bytes < 1024) return `${bytes} B`;
|
|
1701
1753
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
@@ -1706,9 +1758,11 @@ function formatFileSize3(bytes) {
|
|
|
1706
1758
|
|
|
1707
1759
|
|
|
1708
1760
|
|
|
1709
|
-
var
|
|
1761
|
+
var btnHeight2 = "36px";
|
|
1762
|
+
var styles6 = {
|
|
1710
1763
|
btn: _react3.css`
|
|
1711
|
-
|
|
1764
|
+
height: ${btnHeight2};
|
|
1765
|
+
padding: 0 12px;
|
|
1712
1766
|
background: ${_chunkAY2DAS6Wjs.colors.surface};
|
|
1713
1767
|
border: 1px solid ${_chunkAY2DAS6Wjs.colors.border};
|
|
1714
1768
|
border-radius: 6px;
|
|
@@ -1724,8 +1778,8 @@ var styles7 = {
|
|
|
1724
1778
|
}
|
|
1725
1779
|
`,
|
|
1726
1780
|
icon: _react3.css`
|
|
1727
|
-
width:
|
|
1728
|
-
height:
|
|
1781
|
+
width: 16px;
|
|
1782
|
+
height: 16px;
|
|
1729
1783
|
color: ${_chunkAY2DAS6Wjs.colors.textSecondary};
|
|
1730
1784
|
`,
|
|
1731
1785
|
overlay: _react3.css`
|
|
@@ -1888,10 +1942,10 @@ var styles7 = {
|
|
|
1888
1942
|
function StudioSettings() {
|
|
1889
1943
|
const [isOpen, setIsOpen] = _react.useState.call(void 0, false);
|
|
1890
1944
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
1891
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css:
|
|
1945
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles6.btn, onClick: () => setIsOpen(true), "aria-label": "Settings", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1892
1946
|
"svg",
|
|
1893
1947
|
{
|
|
1894
|
-
css:
|
|
1948
|
+
css: styles6.icon,
|
|
1895
1949
|
xmlns: "http://www.w3.org/2000/svg",
|
|
1896
1950
|
viewBox: "0 0 24 24",
|
|
1897
1951
|
fill: "none",
|
|
@@ -1909,56 +1963,57 @@ function StudioSettings() {
|
|
|
1909
1963
|
] });
|
|
1910
1964
|
}
|
|
1911
1965
|
function SettingsPanel({ onClose }) {
|
|
1912
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css:
|
|
1913
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
1914
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { css:
|
|
1915
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css:
|
|
1966
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.overlay, onClick: onClose, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.panel, onClick: (e) => e.stopPropagation(), children: [
|
|
1967
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.header, children: [
|
|
1968
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { css: styles6.title, children: "Settings" }),
|
|
1969
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles6.closeBtn, onClick: onClose, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.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" }) }) })
|
|
1916
1970
|
] }),
|
|
1917
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
1971
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.sections, children: [
|
|
1918
1972
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "section", { children: [
|
|
1919
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css:
|
|
1920
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css:
|
|
1921
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
1922
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css:
|
|
1923
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css:
|
|
1924
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css:
|
|
1925
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css:
|
|
1926
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css:
|
|
1973
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles6.sectionTitle, children: "Cloudflare R2" }),
|
|
1974
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.description, children: "Configure in .env.local file:" }),
|
|
1975
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.code, children: [
|
|
1976
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.codeLine, children: "CLOUDFLARE_R2_ACCOUNT_ID" }),
|
|
1977
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.codeLine, children: "CLOUDFLARE_R2_ACCESS_KEY_ID" }),
|
|
1978
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.codeLine, children: "CLOUDFLARE_R2_SECRET_ACCESS_KEY" }),
|
|
1979
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.codeLine, children: "CLOUDFLARE_R2_BUCKET_NAME" }),
|
|
1980
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.codeLine, children: "CLOUDFLARE_R2_PUBLIC_URL" })
|
|
1927
1981
|
] })
|
|
1928
1982
|
] }),
|
|
1929
1983
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "section", { children: [
|
|
1930
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css:
|
|
1931
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css:
|
|
1932
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css:
|
|
1984
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles6.sectionTitle, children: "Custom CDN URL" }),
|
|
1985
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.description, children: "Override the default R2 URL with a custom domain:" }),
|
|
1986
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles6.input, type: "text", placeholder: "https://cdn.yourdomain.com" })
|
|
1933
1987
|
] }),
|
|
1934
1988
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "section", { children: [
|
|
1935
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css:
|
|
1936
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
1989
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles6.sectionTitle, children: "Thumbnail Sizes" }),
|
|
1990
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.grid, children: [
|
|
1937
1991
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
|
|
1938
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css:
|
|
1939
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css:
|
|
1992
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css: styles6.label, children: "Small" }),
|
|
1993
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles6.input, type: "number", defaultValue: 300 })
|
|
1940
1994
|
] }),
|
|
1941
1995
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
|
|
1942
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css:
|
|
1943
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css:
|
|
1996
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css: styles6.label, children: "Medium" }),
|
|
1997
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles6.input, type: "number", defaultValue: 700 })
|
|
1944
1998
|
] }),
|
|
1945
1999
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
|
|
1946
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css:
|
|
1947
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css:
|
|
2000
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css: styles6.label, children: "Large" }),
|
|
2001
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles6.input, type: "number", defaultValue: 1400 })
|
|
1948
2002
|
] })
|
|
1949
2003
|
] })
|
|
1950
2004
|
] })
|
|
1951
2005
|
] }),
|
|
1952
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
1953
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css:
|
|
1954
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css:
|
|
2006
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.footer, children: [
|
|
2007
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles6.cancelBtn, onClick: onClose, children: "Cancel" }),
|
|
2008
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles6.saveBtn, children: "Save Changes" })
|
|
1955
2009
|
] })
|
|
1956
2010
|
] }) });
|
|
1957
2011
|
}
|
|
1958
2012
|
|
|
1959
2013
|
// src/components/StudioUI.tsx
|
|
1960
2014
|
|
|
1961
|
-
var
|
|
2015
|
+
var btnHeight3 = "36px";
|
|
2016
|
+
var styles7 = {
|
|
1962
2017
|
container: _react3.css`
|
|
1963
2018
|
${_chunkAY2DAS6Wjs.baseReset}
|
|
1964
2019
|
display: flex;
|
|
@@ -1970,12 +2025,12 @@ var styles8 = {
|
|
|
1970
2025
|
display: flex;
|
|
1971
2026
|
align-items: center;
|
|
1972
2027
|
justify-content: space-between;
|
|
1973
|
-
padding:
|
|
2028
|
+
padding: 12px 24px;
|
|
1974
2029
|
background: ${_chunkAY2DAS6Wjs.colors.surface};
|
|
1975
2030
|
border-bottom: 1px solid ${_chunkAY2DAS6Wjs.colors.border};
|
|
1976
2031
|
`,
|
|
1977
2032
|
title: _react3.css`
|
|
1978
|
-
font-size: ${_chunkAY2DAS6Wjs.fontSize.
|
|
2033
|
+
font-size: ${_chunkAY2DAS6Wjs.fontSize.lg};
|
|
1979
2034
|
font-weight: 600;
|
|
1980
2035
|
color: ${_chunkAY2DAS6Wjs.colors.text};
|
|
1981
2036
|
margin: 0;
|
|
@@ -1986,8 +2041,9 @@ var styles8 = {
|
|
|
1986
2041
|
align-items: center;
|
|
1987
2042
|
gap: 8px;
|
|
1988
2043
|
`,
|
|
1989
|
-
|
|
1990
|
-
|
|
2044
|
+
headerBtn: _react3.css`
|
|
2045
|
+
height: ${btnHeight3};
|
|
2046
|
+
padding: 0 12px;
|
|
1991
2047
|
background: ${_chunkAY2DAS6Wjs.colors.surface};
|
|
1992
2048
|
border: 1px solid ${_chunkAY2DAS6Wjs.colors.border};
|
|
1993
2049
|
border-radius: 6px;
|
|
@@ -2002,9 +2058,9 @@ var styles8 = {
|
|
|
2002
2058
|
border-color: ${_chunkAY2DAS6Wjs.colors.borderHover};
|
|
2003
2059
|
}
|
|
2004
2060
|
`,
|
|
2005
|
-
|
|
2006
|
-
width:
|
|
2007
|
-
height:
|
|
2061
|
+
headerIcon: _react3.css`
|
|
2062
|
+
width: 16px;
|
|
2063
|
+
height: 16px;
|
|
2008
2064
|
color: ${_chunkAY2DAS6Wjs.colors.textSecondary};
|
|
2009
2065
|
`,
|
|
2010
2066
|
content: _react3.css`
|
|
@@ -2024,6 +2080,7 @@ function StudioUI({ onClose }) {
|
|
|
2024
2080
|
const [selectedItems, setSelectedItems] = _react.useState.call(void 0, /* @__PURE__ */ new Set());
|
|
2025
2081
|
const [lastSelectedPath, setLastSelectedPath] = _react.useState.call(void 0, null);
|
|
2026
2082
|
const [viewMode, setViewMode] = _react.useState.call(void 0, "grid");
|
|
2083
|
+
const [focusedItem, setFocusedItem] = _react.useState.call(void 0, null);
|
|
2027
2084
|
const [meta, setMeta] = _react.useState.call(void 0, null);
|
|
2028
2085
|
const [isLoading, setIsLoading] = _react.useState.call(void 0, false);
|
|
2029
2086
|
const [refreshKey, setRefreshKey] = _react.useState.call(void 0, 0);
|
|
@@ -2040,6 +2097,7 @@ function StudioUI({ onClose }) {
|
|
|
2040
2097
|
const setCurrentPath = _react.useCallback.call(void 0, (path) => {
|
|
2041
2098
|
setCurrentPathInternal(path);
|
|
2042
2099
|
setSelectedItems(/* @__PURE__ */ new Set());
|
|
2100
|
+
setFocusedItem(null);
|
|
2043
2101
|
}, []);
|
|
2044
2102
|
const toggleSelection = _react.useCallback.call(void 0, (path) => {
|
|
2045
2103
|
setSelectedItems((prev) => {
|
|
@@ -2077,10 +2135,14 @@ function StudioUI({ onClose }) {
|
|
|
2077
2135
|
const handleKeyDown = _react.useCallback.call(void 0,
|
|
2078
2136
|
(e) => {
|
|
2079
2137
|
if (e.key === "Escape") {
|
|
2080
|
-
|
|
2138
|
+
if (focusedItem) {
|
|
2139
|
+
setFocusedItem(null);
|
|
2140
|
+
} else {
|
|
2141
|
+
onClose();
|
|
2142
|
+
}
|
|
2081
2143
|
}
|
|
2082
2144
|
},
|
|
2083
|
-
[onClose]
|
|
2145
|
+
[onClose, focusedItem]
|
|
2084
2146
|
);
|
|
2085
2147
|
_react.useEffect.call(void 0, () => {
|
|
2086
2148
|
document.addEventListener("keydown", handleKeyDown);
|
|
@@ -2107,6 +2169,8 @@ function StudioUI({ onClose }) {
|
|
|
2107
2169
|
lastSelectedPath,
|
|
2108
2170
|
viewMode,
|
|
2109
2171
|
setViewMode,
|
|
2172
|
+
focusedItem,
|
|
2173
|
+
setFocusedItem,
|
|
2110
2174
|
meta,
|
|
2111
2175
|
setMeta,
|
|
2112
2176
|
isLoading,
|
|
@@ -2114,15 +2178,15 @@ function StudioUI({ onClose }) {
|
|
|
2114
2178
|
refreshKey,
|
|
2115
2179
|
triggerRefresh
|
|
2116
2180
|
};
|
|
2117
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioContext.Provider, { value: contextValue, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
2118
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
2119
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h1", { css:
|
|
2120
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
2181
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioContext.Provider, { value: contextValue, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.container, children: [
|
|
2182
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.header, children: [
|
|
2183
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h1", { css: styles7.title, children: "Studio" }),
|
|
2184
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.headerActions, children: [
|
|
2121
2185
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioSettings, {}),
|
|
2122
2186
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2123
2187
|
"button",
|
|
2124
2188
|
{
|
|
2125
|
-
css:
|
|
2189
|
+
css: styles7.headerBtn,
|
|
2126
2190
|
onClick: onClose,
|
|
2127
2191
|
"aria-label": "Close Studio",
|
|
2128
2192
|
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, CloseIcon, {})
|
|
@@ -2131,18 +2195,14 @@ function StudioUI({ onClose }) {
|
|
|
2131
2195
|
] })
|
|
2132
2196
|
] }),
|
|
2133
2197
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioToolbar, {}),
|
|
2134
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2135
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.content, children: [
|
|
2136
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles8.fileBrowser, children: viewMode === "grid" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioFileGrid, {}) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioFileList, {}) }),
|
|
2137
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioPreview, {})
|
|
2138
|
-
] })
|
|
2198
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles7.content, children: focusedItem ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioDetailView, {}) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles7.fileBrowser, children: viewMode === "grid" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioFileGrid, {}) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioFileList, {}) }) })
|
|
2139
2199
|
] }) });
|
|
2140
2200
|
}
|
|
2141
2201
|
function CloseIcon() {
|
|
2142
2202
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
2143
2203
|
"svg",
|
|
2144
2204
|
{
|
|
2145
|
-
css:
|
|
2205
|
+
css: styles7.headerIcon,
|
|
2146
2206
|
xmlns: "http://www.w3.org/2000/svg",
|
|
2147
2207
|
viewBox: "0 0 24 24",
|
|
2148
2208
|
fill: "none",
|
|
@@ -2162,4 +2222,4 @@ var StudioUI_default = StudioUI;
|
|
|
2162
2222
|
|
|
2163
2223
|
|
|
2164
2224
|
exports.StudioUI = StudioUI; exports.default = StudioUI_default;
|
|
2165
|
-
//# sourceMappingURL=StudioUI-
|
|
2225
|
+
//# sourceMappingURL=StudioUI-YO6WPG5E.js.map
|