@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.
@@ -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: 12px;
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
- padding: 8px 14px;
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: 15px;
274
- height: 15px;
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
- background-color: ${_chunkAY2DAS6Wjs.colors.surfaceHover};
318
+ height: ${btnHeight};
319
+ background-color: ${_chunkAY2DAS6Wjs.colors.surface};
309
320
  border: 1px solid ${_chunkAY2DAS6Wjs.colors.border};
310
321
  border-radius: 6px;
311
- padding: 2px;
322
+ overflow: hidden;
312
323
  `,
313
324
  viewBtn: _react3.css`
314
- padding: 6px 8px;
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.surface};
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 handleReprocess = _react.useCallback.call(void 0, () => {
395
- console.log("Reprocess clicked", selectedItems);
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: handleReprocess,
485
- disabled: !hasSelection,
610
+ onClick: handleProcessImages,
611
+ disabled: processing,
486
612
  children: [
487
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, RefreshIcon, {}),
488
- "Reprocess"
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
- // src/components/StudioBreadcrumb.tsx
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 styles4 = {
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: 4px 10px;
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: styles4.loading, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles4.spinner }) });
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
- if (items.length === 0) {
906
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.empty, children: [
907
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.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" }) }),
908
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles4.emptyText, children: "No files in this folder" }),
909
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles4.emptyText, children: "Upload images to get started" })
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 handleOpenFolder = (item) => {
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: styles4.selectAllRow, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "label", { css: styles4.selectAllLabel, children: [
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: styles4.selectAllCheckbox,
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.jsx.call(void 0, "div", { css: styles4.grid, children: sortedItems.map((item) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
957
- GridItem,
958
- {
959
- item,
960
- isSelected: selectedItems.has(item.path),
961
- onClick: (e) => handleItemClick(item, e),
962
- onOpen: () => handleOpenFolder(item)
963
- },
964
- item.path
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: [styles4.item, isSelected && styles4.itemSelected],
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: styles4.checkboxWrapper,
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: styles4.checkbox,
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: styles4.cdnBadge, children: "CDN" }),
993
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles4.content, children: 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,
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: styles4.image,
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: 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" }) }) }),
1002
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles4.label, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.labelRow, children: [
1003
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.labelText, children: [
1004
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles4.name, title: item.name, children: item.name }),
1005
- isFolder ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { css: styles4.size, children: [
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: styles4.size, children: formatFileSize(item.size) })
1075
+ ] }) : item.size !== void 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles3.size, children: formatFileSize(item.size) })
1010
1076
  ] }),
1011
- isFolder && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1077
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1012
1078
  "button",
1013
1079
  {
1014
- css: styles4.openBtn,
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 styles5 = {
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: 4px 12px;
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: styles5.loading, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.spinner }) });
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
- if (items.length === 0) {
1222
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.empty, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { children: "No files in this folder" }) });
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 handleOpenFolder = (item) => {
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: styles5.table, children: [
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: [styles5.th, styles5.thCheckbox], children: sortedItems.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
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: styles5.checkbox,
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: styles5.th, children: "Name" }),
1265
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles5.th, styles5.thSize], children: "Size" }),
1266
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles5.th, styles5.thDimensions], children: "Dimensions" }),
1267
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles5.th, styles5.thCdn], children: "CDN" })
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.jsx.call(void 0, "tbody", { css: styles5.tbody, children: sortedItems.map((item) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1270
- ListRow,
1271
- {
1272
- item,
1273
- isSelected: selectedItems.has(item.path),
1274
- onClick: (e) => handleItemClick(item, e),
1275
- onOpen: () => handleOpenFolder(item)
1276
- },
1277
- item.path
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: [styles5.row, isSelected && styles5.rowSelected],
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: [styles5.td, styles5.checkboxCell],
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: styles5.checkbox,
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: styles5.td, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.nameCell, children: [
1306
- isFolder ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.folderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M10 4H4a2 2 0 00-2 2v12a2 2 0 002 2h16a2 2 0 002-2V8a2 2 0 00-2-2h-8l-2-2z" }) }) : item.thumbnail ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { css: styles5.thumbnail, src: item.thumbnail, alt: item.name, loading: "lazy" }) : /* @__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" }) }),
1307
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles5.name, children: item.name }),
1308
- isFolder && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
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: styles5.openBtn,
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: [styles5.td, styles5.meta], children: isFolder ? item.fileCount !== void 0 ? `${item.fileCount} files` : "--" : item.size !== void 0 ? formatFileSize2(item.size) : "--" }),
1321
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles5.td, styles5.meta], children: isFolder ? item.totalSize !== void 0 ? formatFileSize2(item.totalSize) : "--" : item.dimensions ? `${item.dimensions.width}x${item.dimensions.height}` : "--" }),
1322
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles5.td, children: item.cdnSynced ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles5.cdnBadge, children: [
1323
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.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" }) }),
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: styles5.cdnEmpty, children: "--" }) })
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/StudioPreview.tsx
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 styles6 = {
1351
- panel: _react3.css`
1352
- width: 320px;
1353
- border-left: 1px solid ${_chunkAY2DAS6Wjs.colors.border};
1354
- background-color: ${_chunkAY2DAS6Wjs.colors.surface};
1355
- padding: 20px;
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
- title: _react3.css`
1359
- font-size: ${_chunkAY2DAS6Wjs.fontSize.sm};
1360
- font-weight: 600;
1361
- color: ${_chunkAY2DAS6Wjs.colors.textSecondary};
1362
- text-transform: uppercase;
1363
- letter-spacing: 0.05em;
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
- imageContainer: _react3.css`
1367
- background-color: ${_chunkAY2DAS6Wjs.colors.background};
1471
+ image: _react3.css`
1472
+ max-width: 100%;
1473
+ max-height: calc(100vh - 200px);
1474
+ object-fit: contain;
1368
1475
  border-radius: 8px;
1369
- border: 1px solid ${_chunkAY2DAS6Wjs.colors.border};
1370
- padding: 12px;
1371
- margin-bottom: 20px;
1476
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
1372
1477
  `,
1373
- image: _react3.css`
1374
- width: 100%;
1375
- height: auto;
1376
- border-radius: 6px;
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
- info: _react3.css`
1484
+ filePlaceholder: _react3.css`
1379
1485
  display: flex;
1380
1486
  flex-direction: column;
1381
- gap: 10px;
1382
- `,
1383
- row: _react3.css`
1384
- display: flex;
1385
- justify-content: space-between;
1386
- font-size: ${_chunkAY2DAS6Wjs.fontSize.sm};
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
- label: _react3.css`
1389
- color: ${_chunkAY2DAS6Wjs.colors.textSecondary};
1494
+ fileIcon: _react3.css`
1495
+ width: 80px;
1496
+ height: 80px;
1497
+ color: ${_chunkAY2DAS6Wjs.colors.textMuted};
1498
+ margin-bottom: 16px;
1390
1499
  `,
1391
- value: _react3.css`
1500
+ fileName: _react3.css`
1501
+ font-size: ${_chunkAY2DAS6Wjs.fontSize.lg};
1502
+ font-weight: 600;
1392
1503
  color: ${_chunkAY2DAS6Wjs.colors.text};
1393
- font-weight: 500;
1504
+ margin: 0;
1394
1505
  `,
1395
- valueTruncate: _react3.css`
1396
- max-width: 140px;
1397
- white-space: nowrap;
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
- section: _react3.css`
1402
- padding-top: 12px;
1403
- margin-top: 4px;
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
- gap: 8px;
1418
- font-size: ${_chunkAY2DAS6Wjs.fontSize.sm};
1419
- color: ${_chunkAY2DAS6Wjs.colors.success};
1420
- font-weight: 500;
1519
+ justify-content: space-between;
1421
1520
  `,
1422
- cdnIcon: _react3.css`
1423
- width: 16px;
1424
- height: 16px;
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
- copyBtn: _react3.css`
1427
- margin-top: 8px;
1428
- font-size: ${_chunkAY2DAS6Wjs.fontSize.sm};
1429
- font-weight: 500;
1430
- color: ${_chunkAY2DAS6Wjs.colors.primary};
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
- padding: 0;
1533
+ transition: all 0.15s ease;
1534
+ display: flex;
1535
+ align-items: center;
1536
+ justify-content: center;
1435
1537
 
1436
1538
  &:hover {
1437
- text-decoration: underline;
1539
+ background-color: ${_chunkAY2DAS6Wjs.colors.surfaceHover};
1540
+ border-color: ${_chunkAY2DAS6Wjs.colors.borderHover};
1438
1541
  }
1439
1542
  `,
1440
- colorSwatch: _react3.css`
1441
- margin-top: 8px;
1442
- height: 32px;
1443
- border-radius: 6px;
1444
- border: 1px solid ${_chunkAY2DAS6Wjs.colors.border};
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
- emptyState: _react3.css`
1553
+ info: _react3.css`
1447
1554
  display: flex;
1448
1555
  flex-direction: column;
1449
- align-items: center;
1450
- justify-content: center;
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
- filePlaceholder: _react3.css`
1559
+ infoRow: _react3.css`
1460
1560
  display: flex;
1461
- align-items: center;
1462
- justify-content: center;
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
- folderIcon: _react3.css`
1473
- width: 56px;
1474
- height: 56px;
1475
- color: #f5a623;
1564
+ infoLabel: _react3.css`
1565
+ color: ${_chunkAY2DAS6Wjs.colors.textSecondary};
1476
1566
  `,
1477
- video: _react3.css`
1478
- width: 100%;
1479
- height: auto;
1480
- border-radius: 6px;
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: 10px 14px;
1586
+ padding: 12px 14px;
1493
1587
  font-size: ${_chunkAY2DAS6Wjs.fontSize.base};
1494
1588
  font-weight: 500;
1495
- background-color: ${_chunkAY2DAS6Wjs.colors.surface};
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: #d0d5dd;
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 StudioPreview() {
1517
- const { selectedItems, meta, triggerRefresh, clearSelection } = useStudio();
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
- const handleDeleteClick = () => {
1521
- if (selectedItems.size === 0) return;
1522
- setShowDeleteConfirm(true);
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 handleDeleteConfirm = async () => {
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: Array.from(selectedItems) })
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 modals = /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
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 Items",
1555
- message: `Are you sure you want to delete ${selectedItems.size} item(s)? This action cannot be undone.`,
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: handleDeleteConfirm,
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
- if (selectedItems.size === 0) {
1572
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1573
- modals,
1574
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.panel, children: [
1575
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles6.title, children: "Preview" }),
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.jsx.call(void 0, "div", { css: styles6.actions, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: [styles6.actionBtn, styles6.actionBtnDanger], onClick: handleDeleteClick, children: [
1589
- "Delete ",
1590
- selectedItems.size,
1591
- " items"
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.jsx.call(void 0,
1663
- "button",
1664
- {
1665
- css: styles6.copyBtn,
1666
- onClick: () => {
1667
- navigator.clipboard.writeText(`${_optionalChain([imageData, 'access', _8 => _8.cdn, 'optionalAccess', _9 => _9.baseUrl])}${imageData.sizes.full.path}`);
1668
- },
1669
- children: "Copy CDN URL"
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
- imageData.blurhash && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.section, children: [
1674
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, InfoRow, { label: "Blurhash", value: imageData.blurhash, truncate: true }),
1675
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1676
- "div",
1677
- {
1678
- css: styles6.colorSwatch,
1679
- style: { backgroundColor: imageData.dominantColor },
1680
- title: `Dominant color: ${imageData.dominantColor}`
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 styles7 = {
1761
+ var btnHeight2 = "36px";
1762
+ var styles6 = {
1710
1763
  btn: _react3.css`
1711
- padding: 8px;
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: 18px;
1728
- height: 18px;
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: styles7.btn, onClick: () => setIsOpen(true), "aria-label": "Settings", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
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: styles7.icon,
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: styles7.overlay, onClick: onClose, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.panel, onClick: (e) => e.stopPropagation(), children: [
1913
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.header, children: [
1914
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { css: styles7.title, children: "Settings" }),
1915
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles7.closeBtn, onClick: onClose, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles7.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" }) }) })
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: styles7.sections, children: [
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: styles7.sectionTitle, children: "Cloudflare R2" }),
1920
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles7.description, children: "Configure in .env.local file:" }),
1921
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.code, children: [
1922
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles7.codeLine, children: "CLOUDFLARE_R2_ACCOUNT_ID" }),
1923
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles7.codeLine, children: "CLOUDFLARE_R2_ACCESS_KEY_ID" }),
1924
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles7.codeLine, children: "CLOUDFLARE_R2_SECRET_ACCESS_KEY" }),
1925
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles7.codeLine, children: "CLOUDFLARE_R2_BUCKET_NAME" }),
1926
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles7.codeLine, children: "CLOUDFLARE_R2_PUBLIC_URL" })
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: styles7.sectionTitle, children: "Custom CDN URL" }),
1931
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles7.description, children: "Override the default R2 URL with a custom domain:" }),
1932
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles7.input, type: "text", placeholder: "https://cdn.yourdomain.com" })
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: styles7.sectionTitle, children: "Thumbnail Sizes" }),
1936
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.grid, children: [
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: styles7.label, children: "Small" }),
1939
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles7.input, type: "number", defaultValue: 300 })
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: styles7.label, children: "Medium" }),
1943
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles7.input, type: "number", defaultValue: 700 })
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: styles7.label, children: "Large" }),
1947
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles7.input, type: "number", defaultValue: 1400 })
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: styles7.footer, children: [
1953
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles7.cancelBtn, onClick: onClose, children: "Cancel" }),
1954
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles7.saveBtn, children: "Save Changes" })
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 styles8 = {
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: 16px 24px;
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.xl};
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
- closeBtn: _react3.css`
1990
- padding: 8px;
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
- closeIcon: _react3.css`
2006
- width: 18px;
2007
- height: 18px;
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
- onClose();
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: styles8.container, children: [
2118
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.header, children: [
2119
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h1", { css: styles8.title, children: "Studio" }),
2120
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.headerActions, children: [
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: styles8.closeBtn,
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, StudioBreadcrumb, {}),
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: styles8.closeIcon,
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-TPVIV5T7.js.map
2225
+ //# sourceMappingURL=StudioUI-YO6WPG5E.js.map