@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
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
|
|
9
9
|
// src/components/StudioUI.tsx
|
|
10
10
|
import { useEffect as useEffect3, useCallback as useCallback2, useState as useState6 } from "react";
|
|
11
|
-
import { css as
|
|
11
|
+
import { css as css7 } from "@emotion/react";
|
|
12
12
|
|
|
13
13
|
// src/components/StudioContext.tsx
|
|
14
14
|
import { createContext, useContext } from "react";
|
|
@@ -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
|
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "@emotion/react/jsx-runtime";
|
|
210
|
+
var btnHeight = "36px";
|
|
207
211
|
var spin = keyframes2`
|
|
208
212
|
to { transform: rotate(360deg); }
|
|
209
213
|
`;
|
|
@@ -224,13 +228,15 @@ var styles2 = {
|
|
|
224
228
|
right: css2`
|
|
225
229
|
display: flex;
|
|
226
230
|
align-items: center;
|
|
227
|
-
gap:
|
|
231
|
+
gap: 8px;
|
|
228
232
|
`,
|
|
229
233
|
btn: css2`
|
|
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: ${fontSize.base};
|
|
236
242
|
font-weight: 500;
|
|
@@ -251,6 +257,9 @@ var styles2 = {
|
|
|
251
257
|
opacity: 0.5;
|
|
252
258
|
}
|
|
253
259
|
`,
|
|
260
|
+
btnIconOnly: css2`
|
|
261
|
+
padding: 0 10px;
|
|
262
|
+
`,
|
|
254
263
|
btnPrimary: css2`
|
|
255
264
|
background: ${colors.primary};
|
|
256
265
|
border-color: ${colors.primary};
|
|
@@ -270,8 +279,8 @@ var styles2 = {
|
|
|
270
279
|
}
|
|
271
280
|
`,
|
|
272
281
|
icon: css2`
|
|
273
|
-
width:
|
|
274
|
-
height:
|
|
282
|
+
width: 16px;
|
|
283
|
+
height: 16px;
|
|
275
284
|
`,
|
|
276
285
|
iconSpin: css2`
|
|
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: css2`
|
|
287
297
|
color: ${colors.primary};
|
|
@@ -305,16 +315,17 @@ var styles2 = {
|
|
|
305
315
|
viewToggle: css2`
|
|
306
316
|
display: flex;
|
|
307
317
|
align-items: center;
|
|
308
|
-
|
|
318
|
+
height: ${btnHeight};
|
|
319
|
+
background-color: ${colors.surface};
|
|
309
320
|
border: 1px solid ${colors.border};
|
|
310
321
|
border-radius: 6px;
|
|
311
|
-
|
|
322
|
+
overflow: hidden;
|
|
312
323
|
`,
|
|
313
324
|
viewBtn: css2`
|
|
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: ${colors.textSecondary};
|
|
320
331
|
transition: all 0.15s ease;
|
|
@@ -324,20 +335,24 @@ var styles2 = {
|
|
|
324
335
|
|
|
325
336
|
&:hover {
|
|
326
337
|
color: ${colors.text};
|
|
338
|
+
background-color: ${colors.surfaceHover};
|
|
327
339
|
}
|
|
328
340
|
`,
|
|
329
341
|
viewBtnActive: css2`
|
|
330
|
-
background-color: ${colors.
|
|
342
|
+
background-color: ${colors.background};
|
|
331
343
|
color: ${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 = useRef(null);
|
|
338
349
|
const [uploading, setUploading] = useState(false);
|
|
339
350
|
const [refreshing, setRefreshing] = useState(false);
|
|
351
|
+
const [processing, setProcessing] = useState(false);
|
|
340
352
|
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
|
|
353
|
+
const [showProcessConfirm, setShowProcessConfirm] = useState(false);
|
|
354
|
+
const [processCount, setProcessCount] = useState(0);
|
|
355
|
+
const [processMode, setProcessMode] = useState("all");
|
|
341
356
|
const [alertMessage, setAlertMessage] = useState(null);
|
|
342
357
|
const isInImagesFolder = currentPath === "public/images" || currentPath.startsWith("public/images/");
|
|
343
358
|
const handleUpload = useCallback(() => {
|
|
@@ -391,9 +406,107 @@ function StudioToolbar() {
|
|
|
391
406
|
}
|
|
392
407
|
}
|
|
393
408
|
}, [currentPath, triggerRefresh]);
|
|
394
|
-
const
|
|
395
|
-
|
|
409
|
+
const handleProcessImages = useCallback(async () => {
|
|
410
|
+
const hasSelection2 = selectedItems.size > 0;
|
|
411
|
+
if (hasSelection2) {
|
|
412
|
+
const selectedImagePaths = Array.from(selectedItems).filter((p) => {
|
|
413
|
+
const ext = p.split(".").pop()?.toLowerCase() || "";
|
|
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 = useCallback(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 ${data.processed?.length || 0} images.`,
|
|
461
|
+
data.orphansRemoved?.length > 0 ? `Removed ${data.orphansRemoved.length} orphaned thumbnails.` : "",
|
|
462
|
+
data.errors?.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 = p.split(".").pop()?.toLowerCase() || "";
|
|
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 ${data.processed?.length || 0} images.${data.errors?.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 = useCallback(() => {
|
|
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__ */ jsxs2(Fragment, { children: [
|
|
435
551
|
showDeleteConfirm && /* @__PURE__ */ jsx2(
|
|
436
552
|
ConfirmModal,
|
|
@@ -443,6 +559,16 @@ function StudioToolbar() {
|
|
|
443
559
|
onCancel: () => setShowDeleteConfirm(false)
|
|
444
560
|
}
|
|
445
561
|
),
|
|
562
|
+
showProcessConfirm && /* @__PURE__ */ jsx2(
|
|
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__ */ jsx2(
|
|
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__ */ jsx2(
|
|
488
|
-
"
|
|
613
|
+
/* @__PURE__ */ jsx2(ImageStackIcon, {}),
|
|
614
|
+
processing ? "Processing..." : "Process Images"
|
|
489
615
|
]
|
|
490
616
|
}
|
|
491
617
|
),
|
|
@@ -527,7 +653,7 @@ function StudioToolbar() {
|
|
|
527
653
|
/* @__PURE__ */ jsx2(
|
|
528
654
|
"button",
|
|
529
655
|
{
|
|
530
|
-
css: styles2.btn,
|
|
656
|
+
css: [styles2.btn, styles2.btnIconOnly],
|
|
531
657
|
onClick: handleRefresh,
|
|
532
658
|
children: /* @__PURE__ */ jsx2(RefreshIcon, { spinning: refreshing })
|
|
533
659
|
}
|
|
@@ -577,119 +703,25 @@ function GridIcon() {
|
|
|
577
703
|
function ListIcon() {
|
|
578
704
|
return /* @__PURE__ */ jsx2("svg", { css: styles2.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx2("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6h16M4 10h16M4 14h16M4 18h16" }) });
|
|
579
705
|
}
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
import { css as css3 } from "@emotion/react";
|
|
583
|
-
import { jsx as jsx3, jsxs as jsxs3 } from "@emotion/react/jsx-runtime";
|
|
584
|
-
var styles3 = {
|
|
585
|
-
container: css3`
|
|
586
|
-
display: flex;
|
|
587
|
-
align-items: center;
|
|
588
|
-
gap: 8px;
|
|
589
|
-
padding: 10px 24px;
|
|
590
|
-
background-color: ${colors.surface};
|
|
591
|
-
border-bottom: 1px solid ${colors.borderLight};
|
|
592
|
-
`,
|
|
593
|
-
backBtn: css3`
|
|
594
|
-
padding: 6px;
|
|
595
|
-
background: ${colors.surface};
|
|
596
|
-
border: 1px solid ${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: ${colors.surfaceHover};
|
|
606
|
-
border-color: ${colors.borderHover};
|
|
607
|
-
}
|
|
608
|
-
`,
|
|
609
|
-
backIcon: css3`
|
|
610
|
-
width: 16px;
|
|
611
|
-
height: 16px;
|
|
612
|
-
color: ${colors.textSecondary};
|
|
613
|
-
`,
|
|
614
|
-
nav: css3`
|
|
615
|
-
display: flex;
|
|
616
|
-
align-items: center;
|
|
617
|
-
gap: 2px;
|
|
618
|
-
font-size: ${fontSize.base};
|
|
619
|
-
`,
|
|
620
|
-
item: css3`
|
|
621
|
-
display: flex;
|
|
622
|
-
align-items: center;
|
|
623
|
-
gap: 2px;
|
|
624
|
-
`,
|
|
625
|
-
separator: css3`
|
|
626
|
-
color: ${colors.textMuted};
|
|
627
|
-
margin: 0 2px;
|
|
628
|
-
`,
|
|
629
|
-
btn: css3`
|
|
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: ${fontSize.base};
|
|
637
|
-
letter-spacing: -0.01em;
|
|
638
|
-
|
|
639
|
-
&:hover {
|
|
640
|
-
background-color: ${colors.surfaceHover};
|
|
641
|
-
}
|
|
642
|
-
`,
|
|
643
|
-
btnActive: css3`
|
|
644
|
-
color: ${colors.text};
|
|
645
|
-
font-weight: 600;
|
|
646
|
-
`,
|
|
647
|
-
btnInactive: css3`
|
|
648
|
-
color: ${colors.textSecondary};
|
|
649
|
-
|
|
650
|
-
&:hover {
|
|
651
|
-
color: ${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__ */ jsxs3("div", { css: styles3.container, children: [
|
|
663
|
-
currentPath !== "public" && /* @__PURE__ */ jsx3("button", { css: styles3.backBtn, onClick: navigateUp, "aria-label": "Go back", children: /* @__PURE__ */ jsx3("svg", { css: styles3.backIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx3("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) }) }),
|
|
664
|
-
/* @__PURE__ */ jsx3("nav", { css: styles3.nav, children: parts.map((part, index) => /* @__PURE__ */ jsxs3("span", { css: styles3.item, children: [
|
|
665
|
-
index > 0 && /* @__PURE__ */ jsx3("span", { css: styles3.separator, children: "/" }),
|
|
666
|
-
/* @__PURE__ */ jsx3(
|
|
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__ */ jsx2("svg", { css: styles2.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx2("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
|
|
679
711
|
import { useEffect, useState as useState2 } from "react";
|
|
680
|
-
import { css as
|
|
681
|
-
import { jsx as
|
|
712
|
+
import { css as css3, keyframes as keyframes3 } from "@emotion/react";
|
|
713
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "@emotion/react/jsx-runtime";
|
|
682
714
|
var spin2 = keyframes3`
|
|
683
715
|
to { transform: rotate(360deg); }
|
|
684
716
|
`;
|
|
685
|
-
var
|
|
686
|
-
loading:
|
|
717
|
+
var styles3 = {
|
|
718
|
+
loading: css3`
|
|
687
719
|
display: flex;
|
|
688
720
|
align-items: center;
|
|
689
721
|
justify-content: center;
|
|
690
722
|
height: 256px;
|
|
691
723
|
`,
|
|
692
|
-
spinner:
|
|
724
|
+
spinner: css3`
|
|
693
725
|
width: 32px;
|
|
694
726
|
height: 32px;
|
|
695
727
|
border-radius: 50%;
|
|
@@ -697,7 +729,7 @@ var styles4 = {
|
|
|
697
729
|
border-top-color: ${colors.primary};
|
|
698
730
|
animation: ${spin2} 0.8s linear infinite;
|
|
699
731
|
`,
|
|
700
|
-
empty:
|
|
732
|
+
empty: css3`
|
|
701
733
|
display: flex;
|
|
702
734
|
flex-direction: column;
|
|
703
735
|
align-items: center;
|
|
@@ -705,13 +737,13 @@ var styles4 = {
|
|
|
705
737
|
height: 256px;
|
|
706
738
|
color: ${colors.textSecondary};
|
|
707
739
|
`,
|
|
708
|
-
emptyIcon:
|
|
740
|
+
emptyIcon: css3`
|
|
709
741
|
width: 48px;
|
|
710
742
|
height: 48px;
|
|
711
743
|
margin-bottom: 16px;
|
|
712
744
|
opacity: 0.5;
|
|
713
745
|
`,
|
|
714
|
-
emptyText:
|
|
746
|
+
emptyText: css3`
|
|
715
747
|
font-size: ${fontSize.base};
|
|
716
748
|
margin: 0 0 4px 0;
|
|
717
749
|
|
|
@@ -720,7 +752,7 @@ var styles4 = {
|
|
|
720
752
|
font-size: ${fontSize.sm};
|
|
721
753
|
}
|
|
722
754
|
`,
|
|
723
|
-
grid:
|
|
755
|
+
grid: css3`
|
|
724
756
|
display: grid;
|
|
725
757
|
grid-template-columns: repeat(2, 1fr);
|
|
726
758
|
gap: 12px;
|
|
@@ -730,7 +762,7 @@ var styles4 = {
|
|
|
730
762
|
@media (min-width: 1024px) { grid-template-columns: repeat(5, 1fr); }
|
|
731
763
|
@media (min-width: 1280px) { grid-template-columns: repeat(6, 1fr); }
|
|
732
764
|
`,
|
|
733
|
-
item:
|
|
765
|
+
item: css3`
|
|
734
766
|
position: relative;
|
|
735
767
|
border-radius: 8px;
|
|
736
768
|
border: 1px solid ${colors.border};
|
|
@@ -746,7 +778,7 @@ var styles4 = {
|
|
|
746
778
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.06);
|
|
747
779
|
}
|
|
748
780
|
`,
|
|
749
|
-
itemSelected:
|
|
781
|
+
itemSelected: css3`
|
|
750
782
|
border-color: ${colors.primary};
|
|
751
783
|
box-shadow: 0 0 0 1px ${colors.primary};
|
|
752
784
|
|
|
@@ -754,7 +786,14 @@ var styles4 = {
|
|
|
754
786
|
border-color: ${colors.primary};
|
|
755
787
|
}
|
|
756
788
|
`,
|
|
757
|
-
|
|
789
|
+
parentItem: css3`
|
|
790
|
+
cursor: pointer;
|
|
791
|
+
|
|
792
|
+
&:hover {
|
|
793
|
+
border-color: ${colors.primary};
|
|
794
|
+
}
|
|
795
|
+
`,
|
|
796
|
+
checkboxWrapper: css3`
|
|
758
797
|
position: absolute;
|
|
759
798
|
top: 0;
|
|
760
799
|
left: 0;
|
|
@@ -762,13 +801,13 @@ var styles4 = {
|
|
|
762
801
|
padding: 8px;
|
|
763
802
|
cursor: pointer;
|
|
764
803
|
`,
|
|
765
|
-
checkbox:
|
|
804
|
+
checkbox: css3`
|
|
766
805
|
width: 16px;
|
|
767
806
|
height: 16px;
|
|
768
807
|
accent-color: ${colors.primary};
|
|
769
808
|
cursor: pointer;
|
|
770
809
|
`,
|
|
771
|
-
cdnBadge:
|
|
810
|
+
cdnBadge: css3`
|
|
772
811
|
position: absolute;
|
|
773
812
|
top: 8px;
|
|
774
813
|
right: 8px;
|
|
@@ -780,7 +819,7 @@ var styles4 = {
|
|
|
780
819
|
padding: 2px 8px;
|
|
781
820
|
border-radius: 4px;
|
|
782
821
|
`,
|
|
783
|
-
content:
|
|
822
|
+
content: css3`
|
|
784
823
|
aspect-ratio: 1;
|
|
785
824
|
display: flex;
|
|
786
825
|
align-items: center;
|
|
@@ -788,38 +827,43 @@ var styles4 = {
|
|
|
788
827
|
padding: 16px;
|
|
789
828
|
background: ${colors.background};
|
|
790
829
|
`,
|
|
791
|
-
folderIcon:
|
|
830
|
+
folderIcon: css3`
|
|
792
831
|
width: 56px;
|
|
793
832
|
height: 56px;
|
|
794
833
|
color: #f5a623;
|
|
795
834
|
`,
|
|
796
|
-
|
|
835
|
+
parentIcon: css3`
|
|
836
|
+
width: 56px;
|
|
837
|
+
height: 56px;
|
|
838
|
+
color: ${colors.textMuted};
|
|
839
|
+
`,
|
|
840
|
+
fileIcon: css3`
|
|
797
841
|
width: 40px;
|
|
798
842
|
height: 40px;
|
|
799
843
|
color: ${colors.textMuted};
|
|
800
844
|
`,
|
|
801
|
-
image:
|
|
845
|
+
image: css3`
|
|
802
846
|
max-width: 100%;
|
|
803
847
|
max-height: 100%;
|
|
804
848
|
object-fit: contain;
|
|
805
849
|
border-radius: 4px;
|
|
806
850
|
`,
|
|
807
|
-
label:
|
|
851
|
+
label: css3`
|
|
808
852
|
padding: 10px 12px;
|
|
809
853
|
background-color: ${colors.surface};
|
|
810
854
|
border-top: 1px solid ${colors.borderLight};
|
|
811
855
|
`,
|
|
812
|
-
labelRow:
|
|
856
|
+
labelRow: css3`
|
|
813
857
|
display: flex;
|
|
814
858
|
align-items: center;
|
|
815
859
|
justify-content: space-between;
|
|
816
860
|
gap: 8px;
|
|
817
861
|
`,
|
|
818
|
-
labelText:
|
|
862
|
+
labelText: css3`
|
|
819
863
|
flex: 1;
|
|
820
864
|
min-width: 0;
|
|
821
865
|
`,
|
|
822
|
-
name:
|
|
866
|
+
name: css3`
|
|
823
867
|
font-size: ${fontSize.sm};
|
|
824
868
|
font-weight: 500;
|
|
825
869
|
color: ${colors.text};
|
|
@@ -829,29 +873,32 @@ var styles4 = {
|
|
|
829
873
|
margin: 0;
|
|
830
874
|
letter-spacing: -0.01em;
|
|
831
875
|
`,
|
|
832
|
-
size:
|
|
876
|
+
size: css3`
|
|
833
877
|
font-size: ${fontSize.xs};
|
|
834
878
|
color: ${colors.textMuted};
|
|
835
879
|
margin: 2px 0 0 0;
|
|
836
880
|
`,
|
|
837
|
-
openBtn:
|
|
881
|
+
openBtn: css3`
|
|
838
882
|
flex-shrink: 0;
|
|
883
|
+
height: 28px;
|
|
839
884
|
font-size: ${fontSize.xs};
|
|
840
885
|
font-weight: 500;
|
|
841
886
|
color: ${colors.primary};
|
|
842
887
|
background: ${colors.surface};
|
|
843
888
|
border: 1px solid ${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: ${colors.primaryLight};
|
|
851
898
|
border-color: ${colors.primary};
|
|
852
899
|
}
|
|
853
900
|
`,
|
|
854
|
-
selectAllRow:
|
|
901
|
+
selectAllRow: css3`
|
|
855
902
|
display: flex;
|
|
856
903
|
align-items: center;
|
|
857
904
|
margin-bottom: 16px;
|
|
@@ -860,7 +907,7 @@ var styles4 = {
|
|
|
860
907
|
border-radius: 8px;
|
|
861
908
|
border: 1px solid ${colors.border};
|
|
862
909
|
`,
|
|
863
|
-
selectAllLabel:
|
|
910
|
+
selectAllLabel: css3`
|
|
864
911
|
display: flex;
|
|
865
912
|
align-items: center;
|
|
866
913
|
gap: 10px;
|
|
@@ -873,14 +920,14 @@ var styles4 = {
|
|
|
873
920
|
color: ${colors.text};
|
|
874
921
|
}
|
|
875
922
|
`,
|
|
876
|
-
selectAllCheckbox:
|
|
923
|
+
selectAllCheckbox: css3`
|
|
877
924
|
width: 16px;
|
|
878
925
|
height: 16px;
|
|
879
926
|
accent-color: ${colors.primary};
|
|
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] = useState2([]);
|
|
885
932
|
const [loading, setLoading] = useState2(true);
|
|
886
933
|
useEffect(() => {
|
|
@@ -900,13 +947,14 @@ function StudioFileGrid() {
|
|
|
900
947
|
loadItems();
|
|
901
948
|
}, [currentPath, refreshKey]);
|
|
902
949
|
if (loading) {
|
|
903
|
-
return /* @__PURE__ */
|
|
950
|
+
return /* @__PURE__ */ jsx3("div", { css: styles3.loading, children: /* @__PURE__ */ jsx3("div", { css: styles3.spinner }) });
|
|
904
951
|
}
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
/* @__PURE__ */
|
|
909
|
-
/* @__PURE__ */
|
|
952
|
+
const isAtRoot = currentPath === "public";
|
|
953
|
+
if (items.length === 0 && isAtRoot) {
|
|
954
|
+
return /* @__PURE__ */ jsxs3("div", { css: styles3.empty, children: [
|
|
955
|
+
/* @__PURE__ */ jsx3("svg", { css: styles3.emptyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx3("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__ */ jsx3("p", { css: styles3.emptyText, children: "No files in this folder" }),
|
|
957
|
+
/* @__PURE__ */ jsx3("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));
|
|
@@ -935,13 +985,13 @@ function StudioFileGrid() {
|
|
|
935
985
|
selectAll(sortedItems);
|
|
936
986
|
}
|
|
937
987
|
};
|
|
938
|
-
return /* @__PURE__ */
|
|
939
|
-
sortedItems.length > 0 && /* @__PURE__ */
|
|
940
|
-
/* @__PURE__ */
|
|
988
|
+
return /* @__PURE__ */ jsxs3("div", { children: [
|
|
989
|
+
sortedItems.length > 0 && /* @__PURE__ */ jsx3("div", { css: styles3.selectAllRow, children: /* @__PURE__ */ jsxs3("label", { css: styles3.selectAllLabel, children: [
|
|
990
|
+
/* @__PURE__ */ jsx3(
|
|
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,65 +1003,81 @@ function StudioFileGrid() {
|
|
|
953
1003
|
sortedItems.length,
|
|
954
1004
|
")"
|
|
955
1005
|
] }) }),
|
|
956
|
-
/* @__PURE__ */
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
1006
|
+
/* @__PURE__ */ jsxs3("div", { css: styles3.grid, children: [
|
|
1007
|
+
!isAtRoot && /* @__PURE__ */ jsxs3(
|
|
1008
|
+
"div",
|
|
1009
|
+
{
|
|
1010
|
+
css: [styles3.item, styles3.parentItem],
|
|
1011
|
+
onClick: navigateUp,
|
|
1012
|
+
children: [
|
|
1013
|
+
/* @__PURE__ */ jsx3("div", { css: styles3.content, children: /* @__PURE__ */ jsx3("svg", { css: styles3.parentIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx3("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M3 10h10a8 8 0 018 8v2M3 10l6 6m-6-6l6-6" }) }) }),
|
|
1014
|
+
/* @__PURE__ */ jsxs3("div", { css: styles3.label, children: [
|
|
1015
|
+
/* @__PURE__ */ jsx3("p", { css: styles3.name, children: ".." }),
|
|
1016
|
+
/* @__PURE__ */ jsx3("p", { css: styles3.size, children: "Parent folder" })
|
|
1017
|
+
] })
|
|
1018
|
+
]
|
|
1019
|
+
}
|
|
1020
|
+
),
|
|
1021
|
+
sortedItems.map((item) => /* @__PURE__ */ jsx3(
|
|
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 }) {
|
|
969
1035
|
const isFolder = item.type === "folder";
|
|
970
|
-
return /* @__PURE__ */
|
|
1036
|
+
return /* @__PURE__ */ jsxs3(
|
|
971
1037
|
"div",
|
|
972
1038
|
{
|
|
973
|
-
css: [
|
|
1039
|
+
css: [styles3.item, isSelected && styles3.itemSelected],
|
|
974
1040
|
onClick,
|
|
975
1041
|
children: [
|
|
976
|
-
/* @__PURE__ */
|
|
1042
|
+
/* @__PURE__ */ jsx3(
|
|
977
1043
|
"div",
|
|
978
1044
|
{
|
|
979
|
-
css:
|
|
1045
|
+
css: styles3.checkboxWrapper,
|
|
980
1046
|
onClick: (e) => e.stopPropagation(),
|
|
981
|
-
children: /* @__PURE__ */
|
|
1047
|
+
children: /* @__PURE__ */ jsx3(
|
|
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__ */
|
|
993
|
-
/* @__PURE__ */
|
|
1058
|
+
item.cdnSynced && /* @__PURE__ */ jsx3("span", { css: styles3.cdnBadge, children: "CDN" }),
|
|
1059
|
+
/* @__PURE__ */ jsx3("div", { css: styles3.content, children: isFolder ? /* @__PURE__ */ jsx3("svg", { css: styles3.folderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx3("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__ */ jsx3(
|
|
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__ */
|
|
1002
|
-
/* @__PURE__ */
|
|
1003
|
-
/* @__PURE__ */
|
|
1004
|
-
/* @__PURE__ */
|
|
1005
|
-
isFolder ? /* @__PURE__ */
|
|
1067
|
+
) : /* @__PURE__ */ jsx3("svg", { css: styles3.fileIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx3("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__ */ jsx3("div", { css: styles3.label, children: /* @__PURE__ */ jsxs3("div", { css: styles3.labelRow, children: [
|
|
1069
|
+
/* @__PURE__ */ jsxs3("div", { css: styles3.labelText, children: [
|
|
1070
|
+
/* @__PURE__ */ jsx3("p", { css: styles3.name, title: item.name, children: item.name }),
|
|
1071
|
+
isFolder ? /* @__PURE__ */ jsxs3("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__ */
|
|
1075
|
+
] }) : item.size !== void 0 && /* @__PURE__ */ jsx3("p", { css: styles3.size, children: formatFileSize(item.size) })
|
|
1010
1076
|
] }),
|
|
1011
|
-
|
|
1077
|
+
/* @__PURE__ */ jsx3(
|
|
1012
1078
|
"button",
|
|
1013
1079
|
{
|
|
1014
|
-
css:
|
|
1080
|
+
css: styles3.openBtn,
|
|
1015
1081
|
onClick: (e) => {
|
|
1016
1082
|
e.stopPropagation();
|
|
1017
1083
|
onOpen();
|
|
@@ -1032,19 +1098,19 @@ function formatFileSize(bytes) {
|
|
|
1032
1098
|
|
|
1033
1099
|
// src/components/StudioFileList.tsx
|
|
1034
1100
|
import { useEffect as useEffect2, useState as useState3 } from "react";
|
|
1035
|
-
import { css as
|
|
1036
|
-
import { jsx as
|
|
1101
|
+
import { css as css4, keyframes as keyframes4 } from "@emotion/react";
|
|
1102
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "@emotion/react/jsx-runtime";
|
|
1037
1103
|
var spin3 = keyframes4`
|
|
1038
1104
|
to { transform: rotate(360deg); }
|
|
1039
1105
|
`;
|
|
1040
|
-
var
|
|
1041
|
-
loading:
|
|
1106
|
+
var styles4 = {
|
|
1107
|
+
loading: css4`
|
|
1042
1108
|
display: flex;
|
|
1043
1109
|
align-items: center;
|
|
1044
1110
|
justify-content: center;
|
|
1045
1111
|
height: 256px;
|
|
1046
1112
|
`,
|
|
1047
|
-
spinner:
|
|
1113
|
+
spinner: css4`
|
|
1048
1114
|
width: 32px;
|
|
1049
1115
|
height: 32px;
|
|
1050
1116
|
border-radius: 50%;
|
|
@@ -1052,7 +1118,7 @@ var styles5 = {
|
|
|
1052
1118
|
border-top-color: ${colors.primary};
|
|
1053
1119
|
animation: ${spin3} 0.8s linear infinite;
|
|
1054
1120
|
`,
|
|
1055
|
-
empty:
|
|
1121
|
+
empty: css4`
|
|
1056
1122
|
display: flex;
|
|
1057
1123
|
flex-direction: column;
|
|
1058
1124
|
align-items: center;
|
|
@@ -1060,17 +1126,17 @@ var styles5 = {
|
|
|
1060
1126
|
height: 256px;
|
|
1061
1127
|
color: ${colors.textSecondary};
|
|
1062
1128
|
`,
|
|
1063
|
-
tableWrapper:
|
|
1129
|
+
tableWrapper: css4`
|
|
1064
1130
|
background: ${colors.surface};
|
|
1065
1131
|
border-radius: 8px;
|
|
1066
1132
|
border: 1px solid ${colors.border};
|
|
1067
1133
|
overflow: hidden;
|
|
1068
1134
|
`,
|
|
1069
|
-
table:
|
|
1135
|
+
table: css4`
|
|
1070
1136
|
width: 100%;
|
|
1071
1137
|
border-collapse: collapse;
|
|
1072
1138
|
`,
|
|
1073
|
-
th:
|
|
1139
|
+
th: css4`
|
|
1074
1140
|
text-align: left;
|
|
1075
1141
|
font-size: 11px;
|
|
1076
1142
|
color: ${colors.textMuted};
|
|
@@ -1081,20 +1147,20 @@ var styles5 = {
|
|
|
1081
1147
|
background: ${colors.background};
|
|
1082
1148
|
border-bottom: 1px solid ${colors.border};
|
|
1083
1149
|
`,
|
|
1084
|
-
thCheckbox:
|
|
1150
|
+
thCheckbox: css4`
|
|
1085
1151
|
width: 48px;
|
|
1086
1152
|
`,
|
|
1087
|
-
thSize:
|
|
1153
|
+
thSize: css4`
|
|
1088
1154
|
width: 96px;
|
|
1089
1155
|
`,
|
|
1090
|
-
thDimensions:
|
|
1156
|
+
thDimensions: css4`
|
|
1091
1157
|
width: 128px;
|
|
1092
1158
|
`,
|
|
1093
|
-
thCdn:
|
|
1159
|
+
thCdn: css4`
|
|
1094
1160
|
width: 96px;
|
|
1095
1161
|
`,
|
|
1096
|
-
tbody:
|
|
1097
|
-
row:
|
|
1162
|
+
tbody: css4``,
|
|
1163
|
+
row: css4`
|
|
1098
1164
|
cursor: pointer;
|
|
1099
1165
|
transition: background-color 0.15s ease;
|
|
1100
1166
|
user-select: none;
|
|
@@ -1107,44 +1173,57 @@ var styles5 = {
|
|
|
1107
1173
|
border-bottom: 1px solid ${colors.borderLight};
|
|
1108
1174
|
}
|
|
1109
1175
|
`,
|
|
1110
|
-
rowSelected:
|
|
1176
|
+
rowSelected: css4`
|
|
1111
1177
|
background-color: ${colors.primaryLight};
|
|
1112
1178
|
|
|
1113
1179
|
&:hover {
|
|
1114
1180
|
background-color: ${colors.primaryLight};
|
|
1115
1181
|
}
|
|
1116
1182
|
`,
|
|
1117
|
-
|
|
1183
|
+
parentRow: css4`
|
|
1184
|
+
cursor: pointer;
|
|
1185
|
+
|
|
1186
|
+
&:hover {
|
|
1187
|
+
background-color: ${colors.surfaceHover};
|
|
1188
|
+
}
|
|
1189
|
+
`,
|
|
1190
|
+
td: css4`
|
|
1118
1191
|
padding: 12px 16px;
|
|
1119
1192
|
`,
|
|
1120
|
-
checkboxCell:
|
|
1193
|
+
checkboxCell: css4`
|
|
1121
1194
|
padding: 12px 16px;
|
|
1122
1195
|
cursor: pointer;
|
|
1123
1196
|
`,
|
|
1124
|
-
checkbox:
|
|
1197
|
+
checkbox: css4`
|
|
1125
1198
|
width: 16px;
|
|
1126
1199
|
height: 16px;
|
|
1127
1200
|
accent-color: ${colors.primary};
|
|
1128
1201
|
cursor: pointer;
|
|
1129
1202
|
`,
|
|
1130
|
-
nameCell:
|
|
1203
|
+
nameCell: css4`
|
|
1131
1204
|
display: flex;
|
|
1132
1205
|
align-items: center;
|
|
1133
1206
|
gap: 12px;
|
|
1134
1207
|
`,
|
|
1135
|
-
folderIcon:
|
|
1208
|
+
folderIcon: css4`
|
|
1136
1209
|
width: 20px;
|
|
1137
1210
|
height: 20px;
|
|
1138
1211
|
color: #f5a623;
|
|
1139
1212
|
flex-shrink: 0;
|
|
1140
1213
|
`,
|
|
1141
|
-
|
|
1214
|
+
parentIcon: css4`
|
|
1215
|
+
width: 20px;
|
|
1216
|
+
height: 20px;
|
|
1217
|
+
color: ${colors.textMuted};
|
|
1218
|
+
flex-shrink: 0;
|
|
1219
|
+
`,
|
|
1220
|
+
fileIcon: css4`
|
|
1142
1221
|
width: 20px;
|
|
1143
1222
|
height: 20px;
|
|
1144
1223
|
color: ${colors.textMuted};
|
|
1145
1224
|
flex-shrink: 0;
|
|
1146
1225
|
`,
|
|
1147
|
-
thumbnail:
|
|
1226
|
+
thumbnail: css4`
|
|
1148
1227
|
width: 36px;
|
|
1149
1228
|
height: 36px;
|
|
1150
1229
|
object-fit: cover;
|
|
@@ -1152,17 +1231,17 @@ var styles5 = {
|
|
|
1152
1231
|
flex-shrink: 0;
|
|
1153
1232
|
border: 1px solid ${colors.borderLight};
|
|
1154
1233
|
`,
|
|
1155
|
-
name:
|
|
1234
|
+
name: css4`
|
|
1156
1235
|
font-size: ${fontSize.base};
|
|
1157
1236
|
font-weight: 500;
|
|
1158
1237
|
color: ${colors.text};
|
|
1159
1238
|
letter-spacing: -0.01em;
|
|
1160
1239
|
`,
|
|
1161
|
-
meta:
|
|
1240
|
+
meta: css4`
|
|
1162
1241
|
font-size: ${fontSize.sm};
|
|
1163
1242
|
color: ${colors.textSecondary};
|
|
1164
1243
|
`,
|
|
1165
|
-
cdnBadge:
|
|
1244
|
+
cdnBadge: css4`
|
|
1166
1245
|
display: inline-flex;
|
|
1167
1246
|
align-items: center;
|
|
1168
1247
|
gap: 4px;
|
|
@@ -1170,24 +1249,28 @@ var styles5 = {
|
|
|
1170
1249
|
font-weight: 500;
|
|
1171
1250
|
color: ${colors.success};
|
|
1172
1251
|
`,
|
|
1173
|
-
cdnIcon:
|
|
1252
|
+
cdnIcon: css4`
|
|
1174
1253
|
width: 12px;
|
|
1175
1254
|
height: 12px;
|
|
1176
1255
|
`,
|
|
1177
|
-
cdnEmpty:
|
|
1256
|
+
cdnEmpty: css4`
|
|
1178
1257
|
font-size: ${fontSize.sm};
|
|
1179
1258
|
color: ${colors.textMuted};
|
|
1180
1259
|
`,
|
|
1181
|
-
openBtn:
|
|
1260
|
+
openBtn: css4`
|
|
1261
|
+
height: 28px;
|
|
1182
1262
|
font-size: ${fontSize.xs};
|
|
1183
1263
|
font-weight: 500;
|
|
1184
1264
|
color: ${colors.primary};
|
|
1185
1265
|
background: ${colors.surface};
|
|
1186
1266
|
border: 1px solid ${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: ${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] = useState3([]);
|
|
1201
1284
|
const [loading, setLoading] = useState3(true);
|
|
1202
1285
|
useEffect2(() => {
|
|
@@ -1216,10 +1299,11 @@ function StudioFileList() {
|
|
|
1216
1299
|
loadItems();
|
|
1217
1300
|
}, [currentPath, refreshKey]);
|
|
1218
1301
|
if (loading) {
|
|
1219
|
-
return /* @__PURE__ */
|
|
1302
|
+
return /* @__PURE__ */ jsx4("div", { css: styles4.loading, children: /* @__PURE__ */ jsx4("div", { css: styles4.spinner }) });
|
|
1220
1303
|
}
|
|
1221
|
-
|
|
1222
|
-
|
|
1304
|
+
const isAtRoot = currentPath === "public";
|
|
1305
|
+
if (items.length === 0 && isAtRoot) {
|
|
1306
|
+
return /* @__PURE__ */ jsx4("div", { css: styles4.empty, children: /* @__PURE__ */ jsx4("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__ */
|
|
1251
|
-
/* @__PURE__ */
|
|
1252
|
-
/* @__PURE__ */
|
|
1336
|
+
return /* @__PURE__ */ jsx4("div", { css: styles4.tableWrapper, children: /* @__PURE__ */ jsxs4("table", { css: styles4.table, children: [
|
|
1337
|
+
/* @__PURE__ */ jsx4("thead", { children: /* @__PURE__ */ jsxs4("tr", { children: [
|
|
1338
|
+
/* @__PURE__ */ jsx4("th", { css: [styles4.th, styles4.thCheckbox], children: sortedItems.length > 0 && /* @__PURE__ */ jsx4(
|
|
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__ */
|
|
1265
|
-
/* @__PURE__ */
|
|
1266
|
-
/* @__PURE__ */
|
|
1267
|
-
/* @__PURE__ */
|
|
1350
|
+
/* @__PURE__ */ jsx4("th", { css: styles4.th, children: "Name" }),
|
|
1351
|
+
/* @__PURE__ */ jsx4("th", { css: [styles4.th, styles4.thSize], children: "Size" }),
|
|
1352
|
+
/* @__PURE__ */ jsx4("th", { css: [styles4.th, styles4.thDimensions], children: "Dimensions" }),
|
|
1353
|
+
/* @__PURE__ */ jsx4("th", { css: [styles4.th, styles4.thCdn], children: "CDN" })
|
|
1268
1354
|
] }) }),
|
|
1269
|
-
/* @__PURE__ */
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1355
|
+
/* @__PURE__ */ jsxs4("tbody", { css: styles4.tbody, children: [
|
|
1356
|
+
!isAtRoot && /* @__PURE__ */ jsxs4("tr", { css: styles4.parentRow, onClick: navigateUp, children: [
|
|
1357
|
+
/* @__PURE__ */ jsx4("td", { css: styles4.td }),
|
|
1358
|
+
/* @__PURE__ */ jsx4("td", { css: styles4.td, children: /* @__PURE__ */ jsxs4("div", { css: styles4.nameCell, children: [
|
|
1359
|
+
/* @__PURE__ */ jsx4("svg", { css: styles4.parentIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M3 10h10a8 8 0 018 8v2M3 10l6 6m-6-6l6-6" }) }),
|
|
1360
|
+
/* @__PURE__ */ jsx4("span", { css: styles4.name, children: ".." })
|
|
1361
|
+
] }) }),
|
|
1362
|
+
/* @__PURE__ */ jsx4("td", { css: [styles4.td, styles4.meta], children: "--" }),
|
|
1363
|
+
/* @__PURE__ */ jsx4("td", { css: [styles4.td, styles4.meta], children: "Parent folder" }),
|
|
1364
|
+
/* @__PURE__ */ jsx4("td", { css: styles4.td, children: "--" })
|
|
1365
|
+
] }),
|
|
1366
|
+
sortedItems.map((item) => /* @__PURE__ */ jsx4(
|
|
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
|
-
return /* @__PURE__ */
|
|
1381
|
+
return /* @__PURE__ */ jsxs4(
|
|
1284
1382
|
"tr",
|
|
1285
1383
|
{
|
|
1286
|
-
css: [
|
|
1384
|
+
css: [styles4.row, isSelected && styles4.rowSelected],
|
|
1287
1385
|
onClick,
|
|
1288
1386
|
children: [
|
|
1289
|
-
/* @__PURE__ */
|
|
1387
|
+
/* @__PURE__ */ jsx4(
|
|
1290
1388
|
"td",
|
|
1291
1389
|
{
|
|
1292
|
-
css: [
|
|
1390
|
+
css: [styles4.td, styles4.checkboxCell],
|
|
1293
1391
|
onClick: (e) => e.stopPropagation(),
|
|
1294
|
-
children: /* @__PURE__ */
|
|
1392
|
+
children: /* @__PURE__ */ jsx4(
|
|
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__ */
|
|
1306
|
-
isFolder ? /* @__PURE__ */
|
|
1307
|
-
/* @__PURE__ */
|
|
1308
|
-
|
|
1403
|
+
/* @__PURE__ */ jsx4("td", { css: styles4.td, children: /* @__PURE__ */ jsxs4("div", { css: styles4.nameCell, children: [
|
|
1404
|
+
isFolder ? /* @__PURE__ */ jsx4("svg", { css: styles4.folderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4("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__ */ jsx4("img", { css: styles4.thumbnail, src: item.thumbnail, alt: item.name, loading: "lazy" }) : /* @__PURE__ */ jsx4("svg", { css: styles4.fileIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4("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__ */ jsx4("span", { css: styles4.name, children: item.name }),
|
|
1406
|
+
/* @__PURE__ */ jsx4(
|
|
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__ */
|
|
1321
|
-
/* @__PURE__ */
|
|
1322
|
-
/* @__PURE__ */
|
|
1323
|
-
/* @__PURE__ */
|
|
1418
|
+
/* @__PURE__ */ jsx4("td", { css: [styles4.td, styles4.meta], children: isFolder ? item.fileCount !== void 0 ? `${item.fileCount} files` : "--" : item.size !== void 0 ? formatFileSize2(item.size) : "--" }),
|
|
1419
|
+
/* @__PURE__ */ jsx4("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__ */ jsx4("td", { css: styles4.td, children: item.cdnSynced ? /* @__PURE__ */ jsxs4("span", { css: styles4.cdnBadge, children: [
|
|
1421
|
+
/* @__PURE__ */ jsx4("svg", { css: styles4.cdnIcon, fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx4("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__ */
|
|
1423
|
+
] }) : /* @__PURE__ */ jsx4("span", { css: styles4.cdnEmpty, children: "--" }) })
|
|
1326
1424
|
]
|
|
1327
1425
|
}
|
|
1328
1426
|
);
|
|
@@ -1333,10 +1431,10 @@ 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
|
import { useState as useState4 } from "react";
|
|
1338
|
-
import { css as
|
|
1339
|
-
import { Fragment as Fragment2, jsx as
|
|
1436
|
+
import { css as css5 } from "@emotion/react";
|
|
1437
|
+
import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs5 } from "@emotion/react/jsx-runtime";
|
|
1340
1438
|
var IMAGE_EXTENSIONS = [".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg", ".ico", ".bmp", ".tiff", ".tif"];
|
|
1341
1439
|
var VIDEO_EXTENSIONS = [".mp4", ".webm", ".mov", ".avi", ".mkv", ".m4v"];
|
|
1342
1440
|
function isImageFile(filename) {
|
|
@@ -1347,191 +1445,203 @@ 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: css5`
|
|
1450
|
+
display: flex;
|
|
1451
|
+
flex: 1;
|
|
1452
|
+
overflow: hidden;
|
|
1453
|
+
`,
|
|
1454
|
+
main: css5`
|
|
1455
|
+
flex: 1;
|
|
1456
|
+
display: flex;
|
|
1457
|
+
flex-direction: column;
|
|
1458
|
+
align-items: center;
|
|
1459
|
+
justify-content: center;
|
|
1460
|
+
padding: 24px;
|
|
1461
|
+
background: ${colors.background};
|
|
1356
1462
|
overflow: auto;
|
|
1357
1463
|
`,
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
margin: 0 0 16px 0;
|
|
1464
|
+
mediaWrapper: css5`
|
|
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: css5`
|
|
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: css5`
|
|
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: css5`
|
|
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: ${colors.surface};
|
|
1491
|
+
border-radius: 12px;
|
|
1492
|
+
border: 1px solid ${colors.border};
|
|
1387
1493
|
`,
|
|
1388
|
-
|
|
1389
|
-
|
|
1494
|
+
fileIcon: css5`
|
|
1495
|
+
width: 80px;
|
|
1496
|
+
height: 80px;
|
|
1497
|
+
color: ${colors.textMuted};
|
|
1498
|
+
margin-bottom: 16px;
|
|
1390
1499
|
`,
|
|
1391
|
-
|
|
1500
|
+
fileName: css5`
|
|
1501
|
+
font-size: ${fontSize.lg};
|
|
1502
|
+
font-weight: 600;
|
|
1392
1503
|
color: ${colors.text};
|
|
1393
|
-
|
|
1504
|
+
margin: 0;
|
|
1394
1505
|
`,
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1506
|
+
sidebar: css5`
|
|
1507
|
+
width: 280px;
|
|
1508
|
+
background: ${colors.surface};
|
|
1509
|
+
border-left: 1px solid ${colors.border};
|
|
1510
|
+
display: flex;
|
|
1511
|
+
flex-direction: column;
|
|
1398
1512
|
overflow: hidden;
|
|
1399
|
-
text-overflow: ellipsis;
|
|
1400
|
-
`,
|
|
1401
|
-
section: css6`
|
|
1402
|
-
padding-top: 12px;
|
|
1403
|
-
margin-top: 4px;
|
|
1404
|
-
border-top: 1px solid ${colors.borderLight};
|
|
1405
1513
|
`,
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
color: ${colors.textMuted};
|
|
1410
|
-
text-transform: uppercase;
|
|
1411
|
-
letter-spacing: 0.05em;
|
|
1412
|
-
margin: 0 0 10px 0;
|
|
1413
|
-
`,
|
|
1414
|
-
cdnStatus: css6`
|
|
1514
|
+
sidebarHeader: css5`
|
|
1515
|
+
padding: 16px 20px;
|
|
1516
|
+
border-bottom: 1px solid ${colors.border};
|
|
1415
1517
|
display: flex;
|
|
1416
1518
|
align-items: center;
|
|
1417
|
-
|
|
1418
|
-
font-size: ${fontSize.sm};
|
|
1419
|
-
color: ${colors.success};
|
|
1420
|
-
font-weight: 500;
|
|
1519
|
+
justify-content: space-between;
|
|
1421
1520
|
`,
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1521
|
+
sidebarTitle: css5`
|
|
1522
|
+
font-size: ${fontSize.base};
|
|
1523
|
+
font-weight: 600;
|
|
1524
|
+
color: ${colors.text};
|
|
1525
|
+
margin: 0;
|
|
1425
1526
|
`,
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
background: none;
|
|
1432
|
-
border: none;
|
|
1527
|
+
closeBtn: css5`
|
|
1528
|
+
padding: 6px;
|
|
1529
|
+
background: ${colors.surface};
|
|
1530
|
+
border: 1px solid ${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: ${colors.surfaceHover};
|
|
1540
|
+
border-color: ${colors.borderHover};
|
|
1438
1541
|
}
|
|
1439
1542
|
`,
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
height:
|
|
1443
|
-
|
|
1444
|
-
border: 1px solid ${colors.border};
|
|
1543
|
+
closeIcon: css5`
|
|
1544
|
+
width: 16px;
|
|
1545
|
+
height: 16px;
|
|
1546
|
+
color: ${colors.textSecondary};
|
|
1445
1547
|
`,
|
|
1446
|
-
|
|
1548
|
+
sidebarContent: css5`
|
|
1549
|
+
flex: 1;
|
|
1550
|
+
padding: 20px;
|
|
1551
|
+
overflow: auto;
|
|
1552
|
+
`,
|
|
1553
|
+
info: css5`
|
|
1447
1554
|
display: flex;
|
|
1448
1555
|
flex-direction: column;
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
height: 200px;
|
|
1452
|
-
text-align: center;
|
|
1453
|
-
`,
|
|
1454
|
-
emptyText: css6`
|
|
1455
|
-
font-size: ${fontSize.sm};
|
|
1456
|
-
color: ${colors.textMuted};
|
|
1457
|
-
margin: 0;
|
|
1556
|
+
gap: 12px;
|
|
1557
|
+
margin-bottom: 24px;
|
|
1458
1558
|
`,
|
|
1459
|
-
|
|
1559
|
+
infoRow: css5`
|
|
1460
1560
|
display: flex;
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
height: 120px;
|
|
1464
|
-
background: ${colors.background};
|
|
1465
|
-
border-radius: 6px;
|
|
1466
|
-
`,
|
|
1467
|
-
fileIcon: css6`
|
|
1468
|
-
width: 56px;
|
|
1469
|
-
height: 56px;
|
|
1470
|
-
color: ${colors.textMuted};
|
|
1561
|
+
justify-content: space-between;
|
|
1562
|
+
font-size: ${fontSize.sm};
|
|
1471
1563
|
`,
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
height: 56px;
|
|
1475
|
-
color: #f5a623;
|
|
1564
|
+
infoLabel: css5`
|
|
1565
|
+
color: ${colors.textSecondary};
|
|
1476
1566
|
`,
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1567
|
+
infoValue: css5`
|
|
1568
|
+
color: ${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
|
-
actions:
|
|
1483
|
-
margin-top: 20px;
|
|
1484
|
-
padding-top: 20px;
|
|
1485
|
-
border-top: 1px solid ${colors.border};
|
|
1576
|
+
actions: css5`
|
|
1486
1577
|
display: flex;
|
|
1487
1578
|
flex-direction: column;
|
|
1488
1579
|
gap: 8px;
|
|
1489
1580
|
`,
|
|
1490
|
-
actionBtn:
|
|
1581
|
+
actionBtn: css5`
|
|
1582
|
+
display: flex;
|
|
1583
|
+
align-items: center;
|
|
1584
|
+
gap: 10px;
|
|
1491
1585
|
width: 100%;
|
|
1492
|
-
padding:
|
|
1586
|
+
padding: 12px 14px;
|
|
1493
1587
|
font-size: ${fontSize.base};
|
|
1494
1588
|
font-weight: 500;
|
|
1495
|
-
background
|
|
1589
|
+
background: ${colors.surface};
|
|
1496
1590
|
border: 1px solid ${colors.border};
|
|
1497
1591
|
border-radius: 6px;
|
|
1498
1592
|
cursor: pointer;
|
|
1499
1593
|
transition: all 0.15s ease;
|
|
1500
1594
|
color: ${colors.text};
|
|
1595
|
+
text-align: left;
|
|
1501
1596
|
|
|
1502
1597
|
&:hover {
|
|
1503
1598
|
background-color: ${colors.surfaceHover};
|
|
1504
|
-
border-color:
|
|
1599
|
+
border-color: ${colors.borderHover};
|
|
1505
1600
|
}
|
|
1506
1601
|
`,
|
|
1507
|
-
actionBtnDanger:
|
|
1602
|
+
actionBtnDanger: css5`
|
|
1508
1603
|
color: ${colors.danger};
|
|
1509
1604
|
|
|
1510
1605
|
&:hover {
|
|
1511
1606
|
background-color: ${colors.dangerLight};
|
|
1512
1607
|
border-color: ${colors.danger};
|
|
1513
1608
|
}
|
|
1609
|
+
`,
|
|
1610
|
+
actionIcon: css5`
|
|
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] = useState4(false);
|
|
1519
1619
|
const [alertMessage, setAlertMessage] = useState4(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);
|
|
1523
1626
|
};
|
|
1524
|
-
const
|
|
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
|
+
}
|
|
1632
|
+
};
|
|
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,155 +1657,97 @@ function StudioPreview() {
|
|
|
1547
1657
|
});
|
|
1548
1658
|
}
|
|
1549
1659
|
};
|
|
1550
|
-
const
|
|
1551
|
-
|
|
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__ */ jsx5("img", { css: styles5.image, src: imageSrc, alt: focusedItem.name });
|
|
1669
|
+
}
|
|
1670
|
+
if (isVideo) {
|
|
1671
|
+
return /* @__PURE__ */ jsx5("video", { css: styles5.video, src: imageSrc, controls: true });
|
|
1672
|
+
}
|
|
1673
|
+
return /* @__PURE__ */ jsxs5("div", { css: styles5.filePlaceholder, children: [
|
|
1674
|
+
/* @__PURE__ */ jsx5("svg", { css: styles5.fileIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5("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__ */ jsx5("p", { css: styles5.fileName, children: focusedItem.name })
|
|
1676
|
+
] });
|
|
1677
|
+
};
|
|
1678
|
+
return /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
1679
|
+
showDeleteConfirm && /* @__PURE__ */ jsx5(
|
|
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
|
),
|
|
1562
|
-
alertMessage && /* @__PURE__ */
|
|
1690
|
+
alertMessage && /* @__PURE__ */ jsx5(
|
|
1563
1691
|
AlertModal,
|
|
1564
1692
|
{
|
|
1565
1693
|
title: alertMessage.title,
|
|
1566
1694
|
message: alertMessage.message,
|
|
1567
1695
|
onClose: () => setAlertMessage(null)
|
|
1568
1696
|
}
|
|
1569
|
-
)
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
/* @__PURE__ */ jsx6("div", { css: styles6.emptyState, children: /* @__PURE__ */ jsx6("p", { css: styles6.emptyText, children: "Select an image to preview" }) })
|
|
1577
|
-
] })
|
|
1578
|
-
] });
|
|
1579
|
-
}
|
|
1580
|
-
if (selectedItems.size > 1) {
|
|
1581
|
-
return /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
1582
|
-
modals,
|
|
1583
|
-
/* @__PURE__ */ jsxs6("div", { css: styles6.panel, children: [
|
|
1584
|
-
/* @__PURE__ */ jsxs6("h3", { css: styles6.title, children: [
|
|
1585
|
-
selectedItems.size,
|
|
1586
|
-
" items selected"
|
|
1697
|
+
),
|
|
1698
|
+
/* @__PURE__ */ jsxs5("div", { css: styles5.container, children: [
|
|
1699
|
+
/* @__PURE__ */ jsx5("div", { css: styles5.main, children: /* @__PURE__ */ jsx5("div", { css: styles5.mediaWrapper, children: renderMedia() }) }),
|
|
1700
|
+
/* @__PURE__ */ jsxs5("div", { css: styles5.sidebar, children: [
|
|
1701
|
+
/* @__PURE__ */ jsxs5("div", { css: styles5.sidebarHeader, children: [
|
|
1702
|
+
/* @__PURE__ */ jsx5("h3", { css: styles5.sidebarTitle, children: "Details" }),
|
|
1703
|
+
/* @__PURE__ */ jsx5("button", { css: styles5.closeBtn, onClick: handleClose, "aria-label": "Close", children: /* @__PURE__ */ jsx5("svg", { css: styles5.closeIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })
|
|
1587
1704
|
] }),
|
|
1588
|
-
/* @__PURE__ */
|
|
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 = meta?.images?.[imageKey];
|
|
1603
|
-
const renderPreview = () => {
|
|
1604
|
-
if (isFolder) {
|
|
1605
|
-
return /* @__PURE__ */ jsx6("div", { css: styles6.filePlaceholder, children: /* @__PURE__ */ jsx6("svg", { css: styles6.folderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx6("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__ */ jsx6(
|
|
1609
|
-
"img",
|
|
1610
|
-
{
|
|
1611
|
-
css: styles6.image,
|
|
1612
|
-
src: selectedPath.replace("public", ""),
|
|
1613
|
-
alt: "Preview"
|
|
1614
|
-
}
|
|
1615
|
-
);
|
|
1616
|
-
}
|
|
1617
|
-
if (isVideo) {
|
|
1618
|
-
return /* @__PURE__ */ jsx6(
|
|
1619
|
-
"video",
|
|
1620
|
-
{
|
|
1621
|
-
css: styles6.video,
|
|
1622
|
-
src: selectedPath.replace("public", ""),
|
|
1623
|
-
controls: true,
|
|
1624
|
-
muted: true
|
|
1625
|
-
}
|
|
1626
|
-
);
|
|
1627
|
-
}
|
|
1628
|
-
return /* @__PURE__ */ jsx6("div", { css: styles6.filePlaceholder, children: /* @__PURE__ */ jsx6("svg", { css: styles6.fileIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx6("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__ */ jsxs6(Fragment2, { children: [
|
|
1631
|
-
modals,
|
|
1632
|
-
/* @__PURE__ */ jsxs6("div", { css: styles6.panel, children: [
|
|
1633
|
-
/* @__PURE__ */ jsx6("h3", { css: styles6.title, children: "Preview" }),
|
|
1634
|
-
/* @__PURE__ */ jsx6("div", { css: styles6.imageContainer, children: renderPreview() }),
|
|
1635
|
-
/* @__PURE__ */ jsxs6("div", { css: styles6.info, children: [
|
|
1636
|
-
/* @__PURE__ */ jsx6(InfoRow, { label: "Filename", value: selectedPath.split("/").pop() || "" }),
|
|
1637
|
-
imageData && /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
1638
|
-
/* @__PURE__ */ jsx6(
|
|
1639
|
-
InfoRow,
|
|
1640
|
-
{
|
|
1641
|
-
label: "Original",
|
|
1642
|
-
value: `${imageData.original.width}x${imageData.original.height}`
|
|
1643
|
-
}
|
|
1644
|
-
),
|
|
1645
|
-
/* @__PURE__ */ jsx6(
|
|
1646
|
-
InfoRow,
|
|
1647
|
-
{
|
|
1648
|
-
label: "File size",
|
|
1649
|
-
value: formatFileSize3(imageData.original.fileSize)
|
|
1650
|
-
}
|
|
1651
|
-
),
|
|
1652
|
-
/* @__PURE__ */ jsxs6("div", { css: styles6.section, children: [
|
|
1653
|
-
/* @__PURE__ */ jsx6("p", { css: styles6.sectionTitle, children: "Generated sizes" }),
|
|
1654
|
-
Object.entries(imageData.sizes).map(([size, data]) => /* @__PURE__ */ jsx6(InfoRow, { label: size, value: `${data.width}x${data.height}` }, size))
|
|
1655
|
-
] }),
|
|
1656
|
-
imageData.cdn?.synced && /* @__PURE__ */ jsxs6("div", { css: styles6.section, children: [
|
|
1657
|
-
/* @__PURE__ */ jsx6("p", { css: styles6.sectionTitle, children: "CDN" }),
|
|
1658
|
-
/* @__PURE__ */ jsxs6("div", { css: styles6.cdnStatus, children: [
|
|
1659
|
-
/* @__PURE__ */ jsx6("svg", { css: styles6.cdnIcon, fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx6("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__ */ jsxs5("div", { css: styles5.sidebarContent, children: [
|
|
1706
|
+
/* @__PURE__ */ jsxs5("div", { css: styles5.info, children: [
|
|
1707
|
+
/* @__PURE__ */ jsxs5("div", { css: styles5.infoRow, children: [
|
|
1708
|
+
/* @__PURE__ */ jsx5("span", { css: styles5.infoLabel, children: "Name" }),
|
|
1709
|
+
/* @__PURE__ */ jsx5("span", { css: styles5.infoValue, title: focusedItem.name, children: focusedItem.name })
|
|
1661
1710
|
] }),
|
|
1662
|
-
/* @__PURE__ */
|
|
1663
|
-
"
|
|
1664
|
-
{
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1711
|
+
focusedItem.size !== void 0 && /* @__PURE__ */ jsxs5("div", { css: styles5.infoRow, children: [
|
|
1712
|
+
/* @__PURE__ */ jsx5("span", { css: styles5.infoLabel, children: "Size" }),
|
|
1713
|
+
/* @__PURE__ */ jsx5("span", { css: styles5.infoValue, children: formatFileSize3(focusedItem.size) })
|
|
1714
|
+
] }),
|
|
1715
|
+
focusedItem.dimensions && /* @__PURE__ */ jsxs5("div", { css: styles5.infoRow, children: [
|
|
1716
|
+
/* @__PURE__ */ jsx5("span", { css: styles5.infoLabel, children: "Dimensions" }),
|
|
1717
|
+
/* @__PURE__ */ jsxs5("span", { css: styles5.infoValue, children: [
|
|
1718
|
+
focusedItem.dimensions.width,
|
|
1719
|
+
" \xD7 ",
|
|
1720
|
+
focusedItem.dimensions.height
|
|
1721
|
+
] })
|
|
1722
|
+
] }),
|
|
1723
|
+
/* @__PURE__ */ jsxs5("div", { css: styles5.infoRow, children: [
|
|
1724
|
+
/* @__PURE__ */ jsx5("span", { css: styles5.infoLabel, children: "CDN Status" }),
|
|
1725
|
+
/* @__PURE__ */ jsx5("span", { css: styles5.infoValue, children: focusedItem.cdnSynced ? "Synced" : "Not synced" })
|
|
1726
|
+
] })
|
|
1672
1727
|
] }),
|
|
1673
|
-
|
|
1674
|
-
/* @__PURE__ */
|
|
1675
|
-
|
|
1676
|
-
"
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1728
|
+
/* @__PURE__ */ jsxs5("div", { css: styles5.actions, children: [
|
|
1729
|
+
/* @__PURE__ */ jsxs5("button", { css: styles5.actionBtn, onClick: handleRename, children: [
|
|
1730
|
+
/* @__PURE__ */ jsx5("svg", { css: styles5.actionIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5("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__ */ jsxs5("button", { css: styles5.actionBtn, onClick: handleSync, children: [
|
|
1734
|
+
/* @__PURE__ */ jsx5("svg", { css: styles5.actionIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5("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__ */ jsxs5("button", { css: styles5.actionBtn, onClick: handleRegenerate, children: [
|
|
1738
|
+
/* @__PURE__ */ jsx5("svg", { css: styles5.actionIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5("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__ */ jsxs5("button", { css: [styles5.actionBtn, styles5.actionBtnDanger], onClick: () => setShowDeleteConfirm(true), children: [
|
|
1742
|
+
/* @__PURE__ */ jsx5("svg", { css: styles5.actionIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5("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__ */ jsxs6("div", { css: styles6.actions, children: [
|
|
1687
|
-
/* @__PURE__ */ jsx6("button", { css: styles6.actionBtn, children: "Rename" }),
|
|
1688
|
-
/* @__PURE__ */ jsx6("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__ */ jsxs6("div", { css: styles6.row, children: [
|
|
1695
|
-
/* @__PURE__ */ jsx6("span", { css: styles6.label, children: label }),
|
|
1696
|
-
/* @__PURE__ */ jsx6("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`;
|
|
@@ -1704,11 +1756,13 @@ function formatFileSize3(bytes) {
|
|
|
1704
1756
|
|
|
1705
1757
|
// src/components/StudioSettings.tsx
|
|
1706
1758
|
import { useState as useState5 } from "react";
|
|
1707
|
-
import { css as
|
|
1708
|
-
import { Fragment as Fragment3, jsx as
|
|
1709
|
-
var
|
|
1710
|
-
|
|
1711
|
-
|
|
1759
|
+
import { css as css6 } from "@emotion/react";
|
|
1760
|
+
import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs6 } from "@emotion/react/jsx-runtime";
|
|
1761
|
+
var btnHeight2 = "36px";
|
|
1762
|
+
var styles6 = {
|
|
1763
|
+
btn: css6`
|
|
1764
|
+
height: ${btnHeight2};
|
|
1765
|
+
padding: 0 12px;
|
|
1712
1766
|
background: ${colors.surface};
|
|
1713
1767
|
border: 1px solid ${colors.border};
|
|
1714
1768
|
border-radius: 6px;
|
|
@@ -1723,12 +1777,12 @@ var styles7 = {
|
|
|
1723
1777
|
border-color: ${colors.borderHover};
|
|
1724
1778
|
}
|
|
1725
1779
|
`,
|
|
1726
|
-
icon:
|
|
1727
|
-
width:
|
|
1728
|
-
height:
|
|
1780
|
+
icon: css6`
|
|
1781
|
+
width: 16px;
|
|
1782
|
+
height: 16px;
|
|
1729
1783
|
color: ${colors.textSecondary};
|
|
1730
1784
|
`,
|
|
1731
|
-
overlay:
|
|
1785
|
+
overlay: css6`
|
|
1732
1786
|
position: fixed;
|
|
1733
1787
|
top: 0;
|
|
1734
1788
|
right: 0;
|
|
@@ -1741,7 +1795,7 @@ var styles7 = {
|
|
|
1741
1795
|
background-color: rgba(26, 31, 54, 0.4);
|
|
1742
1796
|
backdrop-filter: blur(4px);
|
|
1743
1797
|
`,
|
|
1744
|
-
panel:
|
|
1798
|
+
panel: css6`
|
|
1745
1799
|
${baseReset}
|
|
1746
1800
|
position: relative;
|
|
1747
1801
|
background-color: ${colors.surface};
|
|
@@ -1751,20 +1805,20 @@ var styles7 = {
|
|
|
1751
1805
|
max-width: 512px;
|
|
1752
1806
|
padding: 24px;
|
|
1753
1807
|
`,
|
|
1754
|
-
header:
|
|
1808
|
+
header: css6`
|
|
1755
1809
|
display: flex;
|
|
1756
1810
|
align-items: center;
|
|
1757
1811
|
justify-content: space-between;
|
|
1758
1812
|
margin-bottom: 24px;
|
|
1759
1813
|
`,
|
|
1760
|
-
title:
|
|
1814
|
+
title: css6`
|
|
1761
1815
|
font-size: ${fontSize.xl};
|
|
1762
1816
|
font-weight: 600;
|
|
1763
1817
|
color: ${colors.text};
|
|
1764
1818
|
margin: 0;
|
|
1765
1819
|
letter-spacing: -0.02em;
|
|
1766
1820
|
`,
|
|
1767
|
-
closeBtn:
|
|
1821
|
+
closeBtn: css6`
|
|
1768
1822
|
padding: 6px;
|
|
1769
1823
|
background: ${colors.surface};
|
|
1770
1824
|
border: 1px solid ${colors.border};
|
|
@@ -1780,23 +1834,23 @@ var styles7 = {
|
|
|
1780
1834
|
border-color: ${colors.borderHover};
|
|
1781
1835
|
}
|
|
1782
1836
|
`,
|
|
1783
|
-
sections:
|
|
1837
|
+
sections: css6`
|
|
1784
1838
|
display: flex;
|
|
1785
1839
|
flex-direction: column;
|
|
1786
1840
|
gap: 24px;
|
|
1787
1841
|
`,
|
|
1788
|
-
sectionTitle:
|
|
1842
|
+
sectionTitle: css6`
|
|
1789
1843
|
font-size: ${fontSize.base};
|
|
1790
1844
|
font-weight: 600;
|
|
1791
1845
|
color: ${colors.text};
|
|
1792
1846
|
margin: 0 0 12px 0;
|
|
1793
1847
|
`,
|
|
1794
|
-
description:
|
|
1848
|
+
description: css6`
|
|
1795
1849
|
font-size: ${fontSize.sm};
|
|
1796
1850
|
color: ${colors.textSecondary};
|
|
1797
1851
|
margin: 0 0 12px 0;
|
|
1798
1852
|
`,
|
|
1799
|
-
code:
|
|
1853
|
+
code: css6`
|
|
1800
1854
|
background-color: ${colors.background};
|
|
1801
1855
|
border-radius: 8px;
|
|
1802
1856
|
padding: 12px;
|
|
@@ -1805,14 +1859,14 @@ var styles7 = {
|
|
|
1805
1859
|
color: ${colors.textSecondary};
|
|
1806
1860
|
border: 1px solid ${colors.border};
|
|
1807
1861
|
`,
|
|
1808
|
-
codeLine:
|
|
1862
|
+
codeLine: css6`
|
|
1809
1863
|
margin: 0 0 4px 0;
|
|
1810
1864
|
|
|
1811
1865
|
&:last-child {
|
|
1812
1866
|
margin: 0;
|
|
1813
1867
|
}
|
|
1814
1868
|
`,
|
|
1815
|
-
input:
|
|
1869
|
+
input: css6`
|
|
1816
1870
|
width: 100%;
|
|
1817
1871
|
padding: 10px 14px;
|
|
1818
1872
|
border: 1px solid ${colors.border};
|
|
@@ -1832,19 +1886,19 @@ var styles7 = {
|
|
|
1832
1886
|
color: ${colors.textMuted};
|
|
1833
1887
|
}
|
|
1834
1888
|
`,
|
|
1835
|
-
grid:
|
|
1889
|
+
grid: css6`
|
|
1836
1890
|
display: grid;
|
|
1837
1891
|
grid-template-columns: repeat(3, 1fr);
|
|
1838
1892
|
gap: 12px;
|
|
1839
1893
|
`,
|
|
1840
|
-
label:
|
|
1894
|
+
label: css6`
|
|
1841
1895
|
font-size: ${fontSize.xs};
|
|
1842
1896
|
font-weight: 500;
|
|
1843
1897
|
color: ${colors.textSecondary};
|
|
1844
1898
|
display: block;
|
|
1845
1899
|
margin-bottom: 6px;
|
|
1846
1900
|
`,
|
|
1847
|
-
footer:
|
|
1901
|
+
footer: css6`
|
|
1848
1902
|
margin-top: 24px;
|
|
1849
1903
|
padding-top: 20px;
|
|
1850
1904
|
border-top: 1px solid ${colors.border};
|
|
@@ -1852,7 +1906,7 @@ var styles7 = {
|
|
|
1852
1906
|
justify-content: flex-end;
|
|
1853
1907
|
gap: 12px;
|
|
1854
1908
|
`,
|
|
1855
|
-
cancelBtn:
|
|
1909
|
+
cancelBtn: css6`
|
|
1856
1910
|
padding: 10px 18px;
|
|
1857
1911
|
font-size: ${fontSize.base};
|
|
1858
1912
|
font-weight: 500;
|
|
@@ -1868,7 +1922,7 @@ var styles7 = {
|
|
|
1868
1922
|
border-color: ${colors.borderHover};
|
|
1869
1923
|
}
|
|
1870
1924
|
`,
|
|
1871
|
-
saveBtn:
|
|
1925
|
+
saveBtn: css6`
|
|
1872
1926
|
padding: 10px 18px;
|
|
1873
1927
|
font-size: ${fontSize.base};
|
|
1874
1928
|
font-weight: 500;
|
|
@@ -1887,11 +1941,11 @@ var styles7 = {
|
|
|
1887
1941
|
};
|
|
1888
1942
|
function StudioSettings() {
|
|
1889
1943
|
const [isOpen, setIsOpen] = useState5(false);
|
|
1890
|
-
return /* @__PURE__ */
|
|
1891
|
-
/* @__PURE__ */
|
|
1944
|
+
return /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
1945
|
+
/* @__PURE__ */ jsx6("button", { css: styles6.btn, onClick: () => setIsOpen(true), "aria-label": "Settings", children: /* @__PURE__ */ jsxs6(
|
|
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",
|
|
@@ -1900,94 +1954,96 @@ function StudioSettings() {
|
|
|
1900
1954
|
strokeLinecap: "round",
|
|
1901
1955
|
strokeLinejoin: "round",
|
|
1902
1956
|
children: [
|
|
1903
|
-
/* @__PURE__ */
|
|
1904
|
-
/* @__PURE__ */
|
|
1957
|
+
/* @__PURE__ */ jsx6("circle", { cx: "12", cy: "12", r: "3" }),
|
|
1958
|
+
/* @__PURE__ */ jsx6("path", { d: "M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-2 2 2 2 0 01-2-2v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83 0 2 2 0 010-2.83l.06-.06a1.65 1.65 0 00.33-1.82 1.65 1.65 0 00-1.51-1H3a2 2 0 01-2-2 2 2 0 012-2h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 010-2.83 2 2 0 012.83 0l.06.06a1.65 1.65 0 001.82.33H9a1.65 1.65 0 001-1.51V3a2 2 0 012-2 2 2 0 012 2v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 0 2 2 0 010 2.83l-.06.06a1.65 1.65 0 00-.33 1.82V9a1.65 1.65 0 001.51 1H21a2 2 0 012 2 2 2 0 01-2 2h-.09a1.65 1.65 0 00-1.51 1z" })
|
|
1905
1959
|
]
|
|
1906
1960
|
}
|
|
1907
1961
|
) }),
|
|
1908
|
-
isOpen && /* @__PURE__ */
|
|
1962
|
+
isOpen && /* @__PURE__ */ jsx6(SettingsPanel, { onClose: () => setIsOpen(false) })
|
|
1909
1963
|
] });
|
|
1910
1964
|
}
|
|
1911
1965
|
function SettingsPanel({ onClose }) {
|
|
1912
|
-
return /* @__PURE__ */
|
|
1913
|
-
/* @__PURE__ */
|
|
1914
|
-
/* @__PURE__ */
|
|
1915
|
-
/* @__PURE__ */
|
|
1966
|
+
return /* @__PURE__ */ jsx6("div", { css: styles6.overlay, onClick: onClose, children: /* @__PURE__ */ jsxs6("div", { css: styles6.panel, onClick: (e) => e.stopPropagation(), children: [
|
|
1967
|
+
/* @__PURE__ */ jsxs6("div", { css: styles6.header, children: [
|
|
1968
|
+
/* @__PURE__ */ jsx6("h2", { css: styles6.title, children: "Settings" }),
|
|
1969
|
+
/* @__PURE__ */ jsx6("button", { css: styles6.closeBtn, onClick: onClose, children: /* @__PURE__ */ jsx6("svg", { css: styles6.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx6("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })
|
|
1916
1970
|
] }),
|
|
1917
|
-
/* @__PURE__ */
|
|
1918
|
-
/* @__PURE__ */
|
|
1919
|
-
/* @__PURE__ */
|
|
1920
|
-
/* @__PURE__ */
|
|
1921
|
-
/* @__PURE__ */
|
|
1922
|
-
/* @__PURE__ */
|
|
1923
|
-
/* @__PURE__ */
|
|
1924
|
-
/* @__PURE__ */
|
|
1925
|
-
/* @__PURE__ */
|
|
1926
|
-
/* @__PURE__ */
|
|
1971
|
+
/* @__PURE__ */ jsxs6("div", { css: styles6.sections, children: [
|
|
1972
|
+
/* @__PURE__ */ jsxs6("section", { children: [
|
|
1973
|
+
/* @__PURE__ */ jsx6("h3", { css: styles6.sectionTitle, children: "Cloudflare R2" }),
|
|
1974
|
+
/* @__PURE__ */ jsx6("p", { css: styles6.description, children: "Configure in .env.local file:" }),
|
|
1975
|
+
/* @__PURE__ */ jsxs6("div", { css: styles6.code, children: [
|
|
1976
|
+
/* @__PURE__ */ jsx6("p", { css: styles6.codeLine, children: "CLOUDFLARE_R2_ACCOUNT_ID" }),
|
|
1977
|
+
/* @__PURE__ */ jsx6("p", { css: styles6.codeLine, children: "CLOUDFLARE_R2_ACCESS_KEY_ID" }),
|
|
1978
|
+
/* @__PURE__ */ jsx6("p", { css: styles6.codeLine, children: "CLOUDFLARE_R2_SECRET_ACCESS_KEY" }),
|
|
1979
|
+
/* @__PURE__ */ jsx6("p", { css: styles6.codeLine, children: "CLOUDFLARE_R2_BUCKET_NAME" }),
|
|
1980
|
+
/* @__PURE__ */ jsx6("p", { css: styles6.codeLine, children: "CLOUDFLARE_R2_PUBLIC_URL" })
|
|
1927
1981
|
] })
|
|
1928
1982
|
] }),
|
|
1929
|
-
/* @__PURE__ */
|
|
1930
|
-
/* @__PURE__ */
|
|
1931
|
-
/* @__PURE__ */
|
|
1932
|
-
/* @__PURE__ */
|
|
1983
|
+
/* @__PURE__ */ jsxs6("section", { children: [
|
|
1984
|
+
/* @__PURE__ */ jsx6("h3", { css: styles6.sectionTitle, children: "Custom CDN URL" }),
|
|
1985
|
+
/* @__PURE__ */ jsx6("p", { css: styles6.description, children: "Override the default R2 URL with a custom domain:" }),
|
|
1986
|
+
/* @__PURE__ */ jsx6("input", { css: styles6.input, type: "text", placeholder: "https://cdn.yourdomain.com" })
|
|
1933
1987
|
] }),
|
|
1934
|
-
/* @__PURE__ */
|
|
1935
|
-
/* @__PURE__ */
|
|
1936
|
-
/* @__PURE__ */
|
|
1937
|
-
/* @__PURE__ */
|
|
1938
|
-
/* @__PURE__ */
|
|
1939
|
-
/* @__PURE__ */
|
|
1988
|
+
/* @__PURE__ */ jsxs6("section", { children: [
|
|
1989
|
+
/* @__PURE__ */ jsx6("h3", { css: styles6.sectionTitle, children: "Thumbnail Sizes" }),
|
|
1990
|
+
/* @__PURE__ */ jsxs6("div", { css: styles6.grid, children: [
|
|
1991
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
1992
|
+
/* @__PURE__ */ jsx6("label", { css: styles6.label, children: "Small" }),
|
|
1993
|
+
/* @__PURE__ */ jsx6("input", { css: styles6.input, type: "number", defaultValue: 300 })
|
|
1940
1994
|
] }),
|
|
1941
|
-
/* @__PURE__ */
|
|
1942
|
-
/* @__PURE__ */
|
|
1943
|
-
/* @__PURE__ */
|
|
1995
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
1996
|
+
/* @__PURE__ */ jsx6("label", { css: styles6.label, children: "Medium" }),
|
|
1997
|
+
/* @__PURE__ */ jsx6("input", { css: styles6.input, type: "number", defaultValue: 700 })
|
|
1944
1998
|
] }),
|
|
1945
|
-
/* @__PURE__ */
|
|
1946
|
-
/* @__PURE__ */
|
|
1947
|
-
/* @__PURE__ */
|
|
1999
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
2000
|
+
/* @__PURE__ */ jsx6("label", { css: styles6.label, children: "Large" }),
|
|
2001
|
+
/* @__PURE__ */ jsx6("input", { css: styles6.input, type: "number", defaultValue: 1400 })
|
|
1948
2002
|
] })
|
|
1949
2003
|
] })
|
|
1950
2004
|
] })
|
|
1951
2005
|
] }),
|
|
1952
|
-
/* @__PURE__ */
|
|
1953
|
-
/* @__PURE__ */
|
|
1954
|
-
/* @__PURE__ */
|
|
2006
|
+
/* @__PURE__ */ jsxs6("div", { css: styles6.footer, children: [
|
|
2007
|
+
/* @__PURE__ */ jsx6("button", { css: styles6.cancelBtn, onClick: onClose, children: "Cancel" }),
|
|
2008
|
+
/* @__PURE__ */ jsx6("button", { css: styles6.saveBtn, children: "Save Changes" })
|
|
1955
2009
|
] })
|
|
1956
2010
|
] }) });
|
|
1957
2011
|
}
|
|
1958
2012
|
|
|
1959
2013
|
// src/components/StudioUI.tsx
|
|
1960
|
-
import { jsx as
|
|
1961
|
-
var
|
|
1962
|
-
|
|
2014
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "@emotion/react/jsx-runtime";
|
|
2015
|
+
var btnHeight3 = "36px";
|
|
2016
|
+
var styles7 = {
|
|
2017
|
+
container: css7`
|
|
1963
2018
|
${baseReset}
|
|
1964
2019
|
display: flex;
|
|
1965
2020
|
flex-direction: column;
|
|
1966
2021
|
height: 100%;
|
|
1967
2022
|
background: ${colors.background};
|
|
1968
2023
|
`,
|
|
1969
|
-
header:
|
|
2024
|
+
header: css7`
|
|
1970
2025
|
display: flex;
|
|
1971
2026
|
align-items: center;
|
|
1972
2027
|
justify-content: space-between;
|
|
1973
|
-
padding:
|
|
2028
|
+
padding: 12px 24px;
|
|
1974
2029
|
background: ${colors.surface};
|
|
1975
2030
|
border-bottom: 1px solid ${colors.border};
|
|
1976
2031
|
`,
|
|
1977
|
-
title:
|
|
1978
|
-
font-size: ${fontSize.
|
|
2032
|
+
title: css7`
|
|
2033
|
+
font-size: ${fontSize.lg};
|
|
1979
2034
|
font-weight: 600;
|
|
1980
2035
|
color: ${colors.text};
|
|
1981
2036
|
margin: 0;
|
|
1982
2037
|
letter-spacing: -0.02em;
|
|
1983
2038
|
`,
|
|
1984
|
-
headerActions:
|
|
2039
|
+
headerActions: css7`
|
|
1985
2040
|
display: flex;
|
|
1986
2041
|
align-items: center;
|
|
1987
2042
|
gap: 8px;
|
|
1988
2043
|
`,
|
|
1989
|
-
|
|
1990
|
-
|
|
2044
|
+
headerBtn: css7`
|
|
2045
|
+
height: ${btnHeight3};
|
|
2046
|
+
padding: 0 12px;
|
|
1991
2047
|
background: ${colors.surface};
|
|
1992
2048
|
border: 1px solid ${colors.border};
|
|
1993
2049
|
border-radius: 6px;
|
|
@@ -2002,17 +2058,17 @@ var styles8 = {
|
|
|
2002
2058
|
border-color: ${colors.borderHover};
|
|
2003
2059
|
}
|
|
2004
2060
|
`,
|
|
2005
|
-
|
|
2006
|
-
width:
|
|
2007
|
-
height:
|
|
2061
|
+
headerIcon: css7`
|
|
2062
|
+
width: 16px;
|
|
2063
|
+
height: 16px;
|
|
2008
2064
|
color: ${colors.textSecondary};
|
|
2009
2065
|
`,
|
|
2010
|
-
content:
|
|
2066
|
+
content: css7`
|
|
2011
2067
|
flex: 1;
|
|
2012
2068
|
display: flex;
|
|
2013
2069
|
overflow: hidden;
|
|
2014
2070
|
`,
|
|
2015
|
-
fileBrowser:
|
|
2071
|
+
fileBrowser: css7`
|
|
2016
2072
|
flex: 1;
|
|
2017
2073
|
min-width: 0;
|
|
2018
2074
|
overflow: auto;
|
|
@@ -2024,6 +2080,7 @@ function StudioUI({ onClose }) {
|
|
|
2024
2080
|
const [selectedItems, setSelectedItems] = useState6(/* @__PURE__ */ new Set());
|
|
2025
2081
|
const [lastSelectedPath, setLastSelectedPath] = useState6(null);
|
|
2026
2082
|
const [viewMode, setViewMode] = useState6("grid");
|
|
2083
|
+
const [focusedItem, setFocusedItem] = useState6(null);
|
|
2027
2084
|
const [meta, setMeta] = useState6(null);
|
|
2028
2085
|
const [isLoading, setIsLoading] = useState6(false);
|
|
2029
2086
|
const [refreshKey, setRefreshKey] = useState6(0);
|
|
@@ -2040,6 +2097,7 @@ function StudioUI({ onClose }) {
|
|
|
2040
2097
|
const setCurrentPath = useCallback2((path) => {
|
|
2041
2098
|
setCurrentPathInternal(path);
|
|
2042
2099
|
setSelectedItems(/* @__PURE__ */ new Set());
|
|
2100
|
+
setFocusedItem(null);
|
|
2043
2101
|
}, []);
|
|
2044
2102
|
const toggleSelection = useCallback2((path) => {
|
|
2045
2103
|
setSelectedItems((prev) => {
|
|
@@ -2077,10 +2135,14 @@ function StudioUI({ onClose }) {
|
|
|
2077
2135
|
const handleKeyDown = useCallback2(
|
|
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
|
useEffect3(() => {
|
|
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,35 +2178,31 @@ function StudioUI({ onClose }) {
|
|
|
2114
2178
|
refreshKey,
|
|
2115
2179
|
triggerRefresh
|
|
2116
2180
|
};
|
|
2117
|
-
return /* @__PURE__ */
|
|
2118
|
-
/* @__PURE__ */
|
|
2119
|
-
/* @__PURE__ */
|
|
2120
|
-
/* @__PURE__ */
|
|
2121
|
-
/* @__PURE__ */
|
|
2122
|
-
/* @__PURE__ */
|
|
2181
|
+
return /* @__PURE__ */ jsx7(StudioContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs7("div", { css: styles7.container, children: [
|
|
2182
|
+
/* @__PURE__ */ jsxs7("div", { css: styles7.header, children: [
|
|
2183
|
+
/* @__PURE__ */ jsx7("h1", { css: styles7.title, children: "Studio" }),
|
|
2184
|
+
/* @__PURE__ */ jsxs7("div", { css: styles7.headerActions, children: [
|
|
2185
|
+
/* @__PURE__ */ jsx7(StudioSettings, {}),
|
|
2186
|
+
/* @__PURE__ */ jsx7(
|
|
2123
2187
|
"button",
|
|
2124
2188
|
{
|
|
2125
|
-
css:
|
|
2189
|
+
css: styles7.headerBtn,
|
|
2126
2190
|
onClick: onClose,
|
|
2127
2191
|
"aria-label": "Close Studio",
|
|
2128
|
-
children: /* @__PURE__ */
|
|
2192
|
+
children: /* @__PURE__ */ jsx7(CloseIcon, {})
|
|
2129
2193
|
}
|
|
2130
2194
|
)
|
|
2131
2195
|
] })
|
|
2132
2196
|
] }),
|
|
2133
|
-
/* @__PURE__ */
|
|
2134
|
-
/* @__PURE__ */
|
|
2135
|
-
/* @__PURE__ */ jsxs8("div", { css: styles8.content, children: [
|
|
2136
|
-
/* @__PURE__ */ jsx8("div", { css: styles8.fileBrowser, children: viewMode === "grid" ? /* @__PURE__ */ jsx8(StudioFileGrid, {}) : /* @__PURE__ */ jsx8(StudioFileList, {}) }),
|
|
2137
|
-
/* @__PURE__ */ jsx8(StudioPreview, {})
|
|
2138
|
-
] })
|
|
2197
|
+
/* @__PURE__ */ jsx7(StudioToolbar, {}),
|
|
2198
|
+
/* @__PURE__ */ jsx7("div", { css: styles7.content, children: focusedItem ? /* @__PURE__ */ jsx7(StudioDetailView, {}) : /* @__PURE__ */ jsx7("div", { css: styles7.fileBrowser, children: viewMode === "grid" ? /* @__PURE__ */ jsx7(StudioFileGrid, {}) : /* @__PURE__ */ jsx7(StudioFileList, {}) }) })
|
|
2139
2199
|
] }) });
|
|
2140
2200
|
}
|
|
2141
2201
|
function CloseIcon() {
|
|
2142
|
-
return /* @__PURE__ */
|
|
2202
|
+
return /* @__PURE__ */ jsxs7(
|
|
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",
|
|
@@ -2151,8 +2211,8 @@ function CloseIcon() {
|
|
|
2151
2211
|
strokeLinecap: "round",
|
|
2152
2212
|
strokeLinejoin: "round",
|
|
2153
2213
|
children: [
|
|
2154
|
-
/* @__PURE__ */
|
|
2155
|
-
/* @__PURE__ */
|
|
2214
|
+
/* @__PURE__ */ jsx7("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
2215
|
+
/* @__PURE__ */ jsx7("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
2156
2216
|
]
|
|
2157
2217
|
}
|
|
2158
2218
|
);
|
|
@@ -2162,4 +2222,4 @@ export {
|
|
|
2162
2222
|
StudioUI,
|
|
2163
2223
|
StudioUI_default as default
|
|
2164
2224
|
};
|
|
2165
|
-
//# sourceMappingURL=StudioUI-
|
|
2225
|
+
//# sourceMappingURL=StudioUI-F2C4N66F.mjs.map
|