@gallop.software/studio 0.1.82 → 0.1.83

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.
@@ -674,13 +674,312 @@ function StudioFolderPicker({ selectedItems, currentPath, onMove, onCancel }) {
674
674
  ] }) });
675
675
  }
676
676
 
677
+ // src/components/R2SetupModal.tsx
678
+
679
+
680
+ var styles3 = {
681
+ overlay: _react3.css`
682
+ position: fixed;
683
+ inset: 0;
684
+ background: rgba(0, 0, 0, 0.6);
685
+ display: flex;
686
+ align-items: center;
687
+ justify-content: center;
688
+ z-index: 1100;
689
+ padding: 20px;
690
+ `,
691
+ modal: _react3.css`
692
+ background: ${_chunkUFCWGUAGjs.colors.surface};
693
+ border-radius: 12px;
694
+ max-width: 560px;
695
+ width: 100%;
696
+ max-height: 90vh;
697
+ overflow-y: auto;
698
+ box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
699
+ `,
700
+ header: _react3.css`
701
+ display: flex;
702
+ align-items: center;
703
+ gap: 12px;
704
+ padding: 20px 24px;
705
+ border-bottom: 1px solid ${_chunkUFCWGUAGjs.colors.border};
706
+ `,
707
+ icon: _react3.css`
708
+ width: 32px;
709
+ height: 32px;
710
+ color: ${_chunkUFCWGUAGjs.colors.primary};
711
+ flex-shrink: 0;
712
+ `,
713
+ title: _react3.css`
714
+ font-size: ${_chunkUFCWGUAGjs.fontSize.xl};
715
+ font-weight: 600;
716
+ color: ${_chunkUFCWGUAGjs.colors.text};
717
+ margin: 0;
718
+ `,
719
+ closeBtn: _react3.css`
720
+ margin-left: auto;
721
+ background: none;
722
+ border: none;
723
+ padding: 4px;
724
+ cursor: pointer;
725
+ color: ${_chunkUFCWGUAGjs.colors.textMuted};
726
+ border-radius: 4px;
727
+
728
+ &:hover {
729
+ color: ${_chunkUFCWGUAGjs.colors.text};
730
+ background: ${_chunkUFCWGUAGjs.colors.surfaceHover};
731
+ }
732
+ `,
733
+ closeIcon: _react3.css`
734
+ width: 20px;
735
+ height: 20px;
736
+ `,
737
+ content: _react3.css`
738
+ padding: 24px;
739
+ `,
740
+ intro: _react3.css`
741
+ font-size: ${_chunkUFCWGUAGjs.fontSize.base};
742
+ color: ${_chunkUFCWGUAGjs.colors.textSecondary};
743
+ margin: 0 0 20px 0;
744
+ line-height: 1.6;
745
+ `,
746
+ steps: _react3.css`
747
+ list-style: none;
748
+ padding: 0;
749
+ margin: 0;
750
+ display: flex;
751
+ flex-direction: column;
752
+ gap: 16px;
753
+ `,
754
+ step: _react3.css`
755
+ display: flex;
756
+ gap: 12px;
757
+ `,
758
+ stepNumber: _react3.css`
759
+ width: 28px;
760
+ height: 28px;
761
+ border-radius: 50%;
762
+ background: ${_chunkUFCWGUAGjs.colors.primaryLight};
763
+ color: ${_chunkUFCWGUAGjs.colors.primary};
764
+ font-size: ${_chunkUFCWGUAGjs.fontSize.sm};
765
+ font-weight: 600;
766
+ display: flex;
767
+ align-items: center;
768
+ justify-content: center;
769
+ flex-shrink: 0;
770
+ `,
771
+ stepContent: _react3.css`
772
+ flex: 1;
773
+ padding-top: 3px;
774
+ `,
775
+ stepTitle: _react3.css`
776
+ font-size: ${_chunkUFCWGUAGjs.fontSize.base};
777
+ font-weight: 500;
778
+ color: ${_chunkUFCWGUAGjs.colors.text};
779
+ margin: 0 0 4px 0;
780
+ `,
781
+ stepDesc: _react3.css`
782
+ font-size: ${_chunkUFCWGUAGjs.fontSize.sm};
783
+ color: ${_chunkUFCWGUAGjs.colors.textSecondary};
784
+ margin: 0;
785
+ line-height: 1.5;
786
+ `,
787
+ link: _react3.css`
788
+ color: ${_chunkUFCWGUAGjs.colors.primary};
789
+ text-decoration: none;
790
+ font-weight: 500;
791
+
792
+ &:hover {
793
+ text-decoration: underline;
794
+ }
795
+ `,
796
+ envVars: _react3.css`
797
+ background: ${_chunkUFCWGUAGjs.colors.background};
798
+ border: 1px solid ${_chunkUFCWGUAGjs.colors.border};
799
+ border-radius: 8px;
800
+ padding: 16px;
801
+ margin-top: 20px;
802
+ font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;
803
+ font-size: 13px;
804
+ line-height: 1.8;
805
+ color: ${_chunkUFCWGUAGjs.colors.text};
806
+ overflow-x: auto;
807
+ `,
808
+ envVar: _react3.css`
809
+ display: block;
810
+ `,
811
+ envKey: _react3.css`
812
+ color: ${_chunkUFCWGUAGjs.colors.primary};
813
+ `,
814
+ envValue: _react3.css`
815
+ color: ${_chunkUFCWGUAGjs.colors.textSecondary};
816
+ `,
817
+ footer: _react3.css`
818
+ padding: 16px 24px;
819
+ border-top: 1px solid ${_chunkUFCWGUAGjs.colors.border};
820
+ display: flex;
821
+ justify-content: flex-end;
822
+ gap: 12px;
823
+ `,
824
+ docsBtn: _react3.css`
825
+ padding: 10px 16px;
826
+ border-radius: 6px;
827
+ font-size: ${_chunkUFCWGUAGjs.fontSize.base};
828
+ font-weight: 500;
829
+ border: 1px solid ${_chunkUFCWGUAGjs.colors.border};
830
+ background: ${_chunkUFCWGUAGjs.colors.surface};
831
+ color: ${_chunkUFCWGUAGjs.colors.text};
832
+ cursor: pointer;
833
+ text-decoration: none;
834
+ display: inline-flex;
835
+ align-items: center;
836
+ gap: 6px;
837
+ transition: all 0.15s ease;
838
+
839
+ &:hover {
840
+ background: ${_chunkUFCWGUAGjs.colors.surfaceHover};
841
+ border-color: #d0d5dd;
842
+ }
843
+ `,
844
+ doneBtn: _react3.css`
845
+ padding: 10px 20px;
846
+ border-radius: 6px;
847
+ font-size: ${_chunkUFCWGUAGjs.fontSize.base};
848
+ font-weight: 500;
849
+ border: none;
850
+ background: ${_chunkUFCWGUAGjs.colors.primary};
851
+ color: white;
852
+ cursor: pointer;
853
+ transition: background 0.15s ease;
854
+
855
+ &:hover {
856
+ background: ${_chunkUFCWGUAGjs.colors.primaryHover};
857
+ }
858
+ `,
859
+ externalIcon: _react3.css`
860
+ width: 14px;
861
+ height: 14px;
862
+ `
863
+ };
864
+ function R2SetupModal({ isOpen, onClose }) {
865
+ if (!isOpen) return null;
866
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles3.overlay, onClick: onClose, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.modal, onClick: (e) => e.stopPropagation(), children: [
867
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.header, children: [
868
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles3.icon, 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 15a4 4 0 004 4h9a5 5 0 10-.1-9.999 5.002 5.002 0 10-9.78 2.096A4.001 4.001 0 003 15z" }) }),
869
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { css: styles3.title, children: "Set Up CDN Storage" }),
870
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles3.closeBtn, onClick: onClose, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles3.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" }) }) })
871
+ ] }),
872
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.content, children: [
873
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles3.intro, children: "Sync your images to Cloudflare R2 for faster global delivery. R2 offers generous free tier with no egress fees." }),
874
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "ol", { css: styles3.steps, children: [
875
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "li", { css: styles3.step, children: [
876
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.stepNumber, children: "1" }),
877
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.stepContent, children: [
878
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h4", { css: styles3.stepTitle, children: "Create a Cloudflare account" }),
879
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { css: styles3.stepDesc, children: [
880
+ "Sign up at",
881
+ " ",
882
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "a", { css: styles3.link, href: "https://dash.cloudflare.com/sign-up", target: "_blank", rel: "noopener noreferrer", children: "dash.cloudflare.com" }),
883
+ " ",
884
+ "if you don't have one already."
885
+ ] })
886
+ ] })
887
+ ] }),
888
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "li", { css: styles3.step, children: [
889
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.stepNumber, children: "2" }),
890
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.stepContent, children: [
891
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h4", { css: styles3.stepTitle, children: "Create an R2 bucket" }),
892
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { css: styles3.stepDesc, children: [
893
+ "Go to R2 in your Cloudflare dashboard and create a new bucket. Choose a name like ",
894
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "code", { children: "my-images" }),
895
+ "."
896
+ ] })
897
+ ] })
898
+ ] }),
899
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "li", { css: styles3.step, children: [
900
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.stepNumber, children: "3" }),
901
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.stepContent, children: [
902
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h4", { css: styles3.stepTitle, children: "Enable public access" }),
903
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { css: styles3.stepDesc, children: [
904
+ 'In bucket settings, enable "Public Access" and copy the public URL (e.g., ',
905
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "code", { children: "https://pub-xxx.r2.dev" }),
906
+ ")."
907
+ ] })
908
+ ] })
909
+ ] }),
910
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "li", { css: styles3.step, children: [
911
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.stepNumber, children: "4" }),
912
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.stepContent, children: [
913
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h4", { css: styles3.stepTitle, children: "Create API token" }),
914
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles3.stepDesc, children: 'Go to R2 \u2192 Manage R2 API Tokens \u2192 Create API Token. Select "Object Read & Write" permissions for your bucket.' })
915
+ ] })
916
+ ] }),
917
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "li", { css: styles3.step, children: [
918
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.stepNumber, children: "5" }),
919
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.stepContent, children: [
920
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h4", { css: styles3.stepTitle, children: "Add environment variables" }),
921
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { css: styles3.stepDesc, children: [
922
+ "Add these to your ",
923
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "code", { children: ".env.local" }),
924
+ " file:"
925
+ ] })
926
+ ] })
927
+ ] })
928
+ ] }),
929
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.envVars, children: [
930
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles3.envVar, children: [
931
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.envKey, children: "CLOUDFLARE_R2_ACCOUNT_ID" }),
932
+ "=",
933
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.envValue, children: "your_account_id" })
934
+ ] }),
935
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles3.envVar, children: [
936
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.envKey, children: "CLOUDFLARE_R2_ACCESS_KEY_ID" }),
937
+ "=",
938
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.envValue, children: "your_access_key" })
939
+ ] }),
940
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles3.envVar, children: [
941
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.envKey, children: "CLOUDFLARE_R2_SECRET_ACCESS_KEY" }),
942
+ "=",
943
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.envValue, children: "your_secret_key" })
944
+ ] }),
945
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles3.envVar, children: [
946
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.envKey, children: "CLOUDFLARE_R2_BUCKET_NAME" }),
947
+ "=",
948
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.envValue, children: "your_bucket_name" })
949
+ ] }),
950
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles3.envVar, children: [
951
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.envKey, children: "CLOUDFLARE_R2_PUBLIC_URL" }),
952
+ "=",
953
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.envValue, children: "https://pub-xxx.r2.dev" })
954
+ ] })
955
+ ] })
956
+ ] }),
957
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.footer, children: [
958
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
959
+ "a",
960
+ {
961
+ css: styles3.docsBtn,
962
+ href: "https://developers.cloudflare.com/r2/get-started/",
963
+ target: "_blank",
964
+ rel: "noopener noreferrer",
965
+ children: [
966
+ "R2 Documentation",
967
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles3.externalIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" }) })
968
+ ]
969
+ }
970
+ ),
971
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles3.doneBtn, onClick: onClose, children: "Got it" })
972
+ ] })
973
+ ] }) });
974
+ }
975
+
677
976
  // src/components/StudioToolbar.tsx
678
977
 
679
978
  var btnHeight = "36px";
680
979
  var spin = _react3.keyframes`
681
980
  to { transform: rotate(360deg); }
682
981
  `;
683
- var styles3 = {
982
+ var styles4 = {
684
983
  toolbar: _react3.css`
685
984
  display: flex;
686
985
  flex-wrap: nowrap;
@@ -898,6 +1197,8 @@ function StudioToolbar() {
898
1197
  const [showNewFolderModal, setShowNewFolderModal] = _react.useState.call(void 0, false);
899
1198
  const [showRenameFolderModal, setShowRenameFolderModal] = _react.useState.call(void 0, false);
900
1199
  const [showMoveModal, setShowMoveModal] = _react.useState.call(void 0, false);
1200
+ const [showR2SetupModal, setShowR2SetupModal] = _react.useState.call(void 0, false);
1201
+ const [syncing, setSyncing] = _react.useState.call(void 0, false);
901
1202
  const isInImagesFolder = currentPath === "public/images" || currentPath.startsWith("public/images/");
902
1203
  const handleUpload = _react.useCallback.call(void 0, () => {
903
1204
  _optionalChain([fileInputRef, 'access', _2 => _2.current, 'optionalAccess', _3 => _3.click, 'call', _4 => _4()]);
@@ -1194,9 +1495,60 @@ function StudioToolbar() {
1194
1495
  });
1195
1496
  }
1196
1497
  }, [selectedItems, clearSelection, triggerRefresh]);
1197
- const handleSyncCdn = _react.useCallback.call(void 0, () => {
1198
- console.log("Sync CDN clicked", selectedItems);
1199
- }, [selectedItems]);
1498
+ const handleSyncCdn = _react.useCallback.call(void 0, async () => {
1499
+ if (selectedItems.size === 0) return;
1500
+ const imageKeys = Array.from(selectedItems).filter((p) => !p.endsWith("/")).map((p) => "/" + p.replace(/^public\//, ""));
1501
+ if (imageKeys.length === 0) {
1502
+ setAlertMessage({
1503
+ title: "No Images Selected",
1504
+ message: "Please select image files to sync to CDN."
1505
+ });
1506
+ return;
1507
+ }
1508
+ setSyncing(true);
1509
+ try {
1510
+ const response = await fetch("/api/studio/sync", {
1511
+ method: "POST",
1512
+ headers: { "Content-Type": "application/json" },
1513
+ body: JSON.stringify({ imageKeys })
1514
+ });
1515
+ const data = await response.json();
1516
+ if (response.ok) {
1517
+ const syncedCount = _optionalChain([data, 'access', _19 => _19.synced, 'optionalAccess', _20 => _20.length]) || 0;
1518
+ const errorCount = _optionalChain([data, 'access', _21 => _21.errors, 'optionalAccess', _22 => _22.length]) || 0;
1519
+ if (errorCount > 0) {
1520
+ setAlertMessage({
1521
+ title: "Sync Partially Complete",
1522
+ message: `Synced ${syncedCount} images. ${errorCount} failed.`
1523
+ });
1524
+ } else {
1525
+ setAlertMessage({
1526
+ title: "Sync Complete",
1527
+ message: `Successfully synced ${syncedCount} images to CDN.`
1528
+ });
1529
+ }
1530
+ clearSelection();
1531
+ triggerRefresh();
1532
+ } else {
1533
+ if (_optionalChain([data, 'access', _23 => _23.error, 'optionalAccess', _24 => _24.includes, 'call', _25 => _25("R2 not configured")]) || _optionalChain([data, 'access', _26 => _26.error, 'optionalAccess', _27 => _27.includes, 'call', _28 => _28("CLOUDFLARE_R2")])) {
1534
+ setShowR2SetupModal(true);
1535
+ } else {
1536
+ setAlertMessage({
1537
+ title: "Sync Failed",
1538
+ message: data.error || "Failed to sync to CDN."
1539
+ });
1540
+ }
1541
+ }
1542
+ } catch (error) {
1543
+ console.error("Sync error:", error);
1544
+ setAlertMessage({
1545
+ title: "Sync Failed",
1546
+ message: "Failed to sync to CDN. Check console for details."
1547
+ });
1548
+ } finally {
1549
+ setSyncing(false);
1550
+ }
1551
+ }, [selectedItems, clearSelection, triggerRefresh]);
1200
1552
  const handleCreateFolder = _react.useCallback.call(void 0, async (folderName) => {
1201
1553
  setShowNewFolderModal(false);
1202
1554
  try {
@@ -1375,7 +1727,14 @@ function StudioToolbar() {
1375
1727
  onClose: () => setAlertMessage(null)
1376
1728
  }
1377
1729
  ),
1378
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.toolbar, children: [
1730
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1731
+ R2SetupModal,
1732
+ {
1733
+ isOpen: showR2SetupModal,
1734
+ onClose: () => setShowR2SetupModal(false)
1735
+ }
1736
+ ),
1737
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.toolbar, children: [
1379
1738
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1380
1739
  "input",
1381
1740
  {
@@ -1387,11 +1746,11 @@ function StudioToolbar() {
1387
1746
  style: { display: "none" }
1388
1747
  }
1389
1748
  ),
1390
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.left, children: [
1749
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.left, children: [
1391
1750
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1392
1751
  "button",
1393
1752
  {
1394
- css: [styles3.btn, styles3.btnPrimary],
1753
+ css: [styles4.btn, styles4.btnPrimary],
1395
1754
  onClick: handleUpload,
1396
1755
  disabled: uploading || isInImagesFolder,
1397
1756
  children: [
@@ -1403,7 +1762,7 @@ function StudioToolbar() {
1403
1762
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1404
1763
  "button",
1405
1764
  {
1406
- css: styles3.btn,
1765
+ css: styles4.btn,
1407
1766
  onClick: () => singleFolderSelected ? setShowRenameFolderModal(true) : setShowNewFolderModal(true),
1408
1767
  disabled: isInImagesFolder && !singleFolderSelected,
1409
1768
  title: isInImagesFolder && !singleFolderSelected ? "Cannot create folders in protected images folder" : void 0,
@@ -1413,11 +1772,11 @@ function StudioToolbar() {
1413
1772
  ]
1414
1773
  }
1415
1774
  ),
1416
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles3.divider }),
1775
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles4.divider }),
1417
1776
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1418
1777
  "button",
1419
1778
  {
1420
- css: styles3.btn,
1779
+ css: styles4.btn,
1421
1780
  onClick: handleProcessImages,
1422
1781
  disabled: processing || isInImagesFolder,
1423
1782
  title: isInImagesFolder ? "Cannot process images folder" : void 0,
@@ -1430,7 +1789,7 @@ function StudioToolbar() {
1430
1789
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1431
1790
  "button",
1432
1791
  {
1433
- css: [styles3.btn, styles3.btnDanger],
1792
+ css: [styles4.btn, styles4.btnDanger],
1434
1793
  onClick: handleDeleteClick,
1435
1794
  disabled: !hasSelection,
1436
1795
  children: [
@@ -1442,7 +1801,7 @@ function StudioToolbar() {
1442
1801
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1443
1802
  "button",
1444
1803
  {
1445
- css: styles3.btn,
1804
+ css: styles4.btn,
1446
1805
  onClick: handleMoveClick,
1447
1806
  disabled: !hasSelection,
1448
1807
  children: [
@@ -1454,20 +1813,20 @@ function StudioToolbar() {
1454
1813
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1455
1814
  "button",
1456
1815
  {
1457
- css: styles3.btn,
1816
+ css: styles4.btn,
1458
1817
  onClick: handleSyncCdn,
1459
- disabled: !hasSelection,
1818
+ disabled: !hasSelection || syncing,
1460
1819
  children: [
1461
1820
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, CloudIcon, {}),
1462
- "Sync CDN"
1821
+ syncing ? "Syncing..." : "Sync CDN"
1463
1822
  ]
1464
1823
  }
1465
1824
  ),
1466
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.searchWrapper, children: [
1825
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.searchWrapper, children: [
1467
1826
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1468
1827
  "input",
1469
1828
  {
1470
- css: styles3.searchInput,
1829
+ css: styles4.searchInput,
1471
1830
  type: "text",
1472
1831
  placeholder: "Search images...",
1473
1832
  value: searchQuery,
@@ -1478,7 +1837,7 @@ function StudioToolbar() {
1478
1837
  searchQuery && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1479
1838
  "button",
1480
1839
  {
1481
- css: styles3.searchClearBtn,
1840
+ css: styles4.searchClearBtn,
1482
1841
  onClick: () => setSearchQuery(""),
1483
1842
  title: "Clear search",
1484
1843
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { width: "14", height: "14", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
@@ -1486,25 +1845,25 @@ function StudioToolbar() {
1486
1845
  )
1487
1846
  ] })
1488
1847
  ] }),
1489
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.right, children: [
1490
- hasSelection && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles3.selectionCount, children: [
1848
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.right, children: [
1849
+ hasSelection && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles4.selectionCount, children: [
1491
1850
  selectedItems.size,
1492
1851
  " selected",
1493
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles3.clearBtn, onClick: clearSelection, children: "Clear" })
1852
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles4.clearBtn, onClick: clearSelection, children: "Clear" })
1494
1853
  ] }),
1495
1854
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1496
1855
  "button",
1497
1856
  {
1498
- css: [styles3.btn, styles3.btnIconOnly],
1857
+ css: [styles4.btn, styles4.btnIconOnly],
1499
1858
  onClick: handleRefresh,
1500
1859
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, RefreshIcon, { spinning: refreshing })
1501
1860
  }
1502
1861
  ),
1503
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.viewToggle, children: [
1862
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.viewToggle, children: [
1504
1863
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1505
1864
  "button",
1506
1865
  {
1507
- css: [styles3.viewBtn, viewMode === "grid" && styles3.viewBtnActive],
1866
+ css: [styles4.viewBtn, viewMode === "grid" && styles4.viewBtnActive],
1508
1867
  onClick: () => setViewMode("grid"),
1509
1868
  "aria-label": "Grid view",
1510
1869
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, GridIcon, {})
@@ -1513,7 +1872,7 @@ function StudioToolbar() {
1513
1872
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1514
1873
  "button",
1515
1874
  {
1516
- css: [styles3.viewBtn, viewMode === "list" && styles3.viewBtnActive],
1875
+ css: [styles4.viewBtn, viewMode === "list" && styles4.viewBtnActive],
1517
1876
  onClick: () => setViewMode("list"),
1518
1877
  "aria-label": "List view",
1519
1878
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ListIcon, {})
@@ -1525,34 +1884,34 @@ function StudioToolbar() {
1525
1884
  ] });
1526
1885
  }
1527
1886
  function UploadIcon() {
1528
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles3.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" }) });
1887
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" }) });
1529
1888
  }
1530
1889
  function RefreshIcon({ spinning }) {
1531
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: [styles3.icon, spinning && styles3.iconSpin], fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" }) });
1890
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: [styles4.icon, spinning && styles4.iconSpin], fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" }) });
1532
1891
  }
1533
1892
  function TrashIcon() {
1534
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles3.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" }) });
1893
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" }) });
1535
1894
  }
1536
1895
  function FolderPlusIcon() {
1537
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles3.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 13h6m-3-3v6m-9 1V7a2 2 0 012-2h6l2 2h6a2 2 0 012 2v8a2 2 0 01-2 2H5a2 2 0 01-2-2z" }) });
1896
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 13h6m-3-3v6m-9 1V7a2 2 0 012-2h6l2 2h6a2 2 0 012 2v8a2 2 0 01-2 2H5a2 2 0 01-2-2z" }) });
1538
1897
  }
1539
1898
  function RenameIcon() {
1540
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles3.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" }) });
1899
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" }) });
1541
1900
  }
1542
1901
  function MoveIcon() {
1543
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles3.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4" }) });
1902
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4" }) });
1544
1903
  }
1545
1904
  function CloudIcon() {
1546
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles3.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" }) });
1905
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" }) });
1547
1906
  }
1548
1907
  function GridIcon() {
1549
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles3.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z" }) });
1908
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z" }) });
1550
1909
  }
1551
1910
  function ListIcon() {
1552
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles3.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" }) });
1911
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6h16M4 10h16M4 14h16M4 18h16" }) });
1553
1912
  }
1554
1913
  function ImageStackIcon() {
1555
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles3.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" }) });
1914
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) });
1556
1915
  }
1557
1916
 
1558
1917
  // src/components/StudioFileGrid.tsx
@@ -1750,7 +2109,7 @@ function useFileList() {
1750
2109
  var spin2 = _react3.keyframes`
1751
2110
  to { transform: rotate(360deg); }
1752
2111
  `;
1753
- var styles4 = {
2112
+ var styles5 = {
1754
2113
  loading: _react3.css`
1755
2114
  display: flex;
1756
2115
  align-items: center;
@@ -2083,22 +2442,22 @@ function StudioFileGrid() {
2083
2442
  handleSelectAll
2084
2443
  } = useFileList();
2085
2444
  if (loading) {
2086
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles4.loading, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles4.spinner }) });
2445
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.loading, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.spinner }) });
2087
2446
  }
2088
2447
  if (sortedItems.length === 0 && isAtRoot) {
2089
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.empty, children: [
2090
- /* @__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" }) }),
2091
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles4.emptyText, children: "No files in this folder" }),
2092
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles4.emptyText, children: "Upload images to get started" })
2448
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.empty, children: [
2449
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.emptyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) }),
2450
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.emptyText, children: "No files in this folder" }),
2451
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.emptyText, children: "Upload images to get started" })
2093
2452
  ] });
2094
2453
  }
2095
2454
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
2096
- 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: [
2455
+ sortedItems.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.selectAllRow, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "label", { css: styles5.selectAllLabel, children: [
2097
2456
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2098
2457
  "input",
2099
2458
  {
2100
2459
  type: "checkbox",
2101
- css: styles4.selectAllCheckbox,
2460
+ css: styles5.selectAllCheckbox,
2102
2461
  checked: allItemsSelected,
2103
2462
  ref: (el) => {
2104
2463
  if (el) el.indeterminate = someItemsSelected && !allItemsSelected;
@@ -2110,17 +2469,17 @@ function StudioFileGrid() {
2110
2469
  sortedItems.length,
2111
2470
  ")"
2112
2471
  ] }) }),
2113
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.grid, children: [
2472
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.grid, children: [
2114
2473
  !isAtRoot && !isSearching && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2115
2474
  "div",
2116
2475
  {
2117
- css: [styles4.item, styles4.parentItem],
2476
+ css: [styles5.item, styles5.parentItem],
2118
2477
  onClick: navigateUp,
2119
2478
  children: [
2120
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles4.content, children: /* @__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" }) }) }),
2121
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.label, children: [
2122
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles4.name, children: ".." }),
2123
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles4.size, children: "Parent folder" })
2479
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.content, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.parentIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M3 10h10a8 8 0 018 8v2M3 10l6 6m-6-6l6-6" }) }) }),
2480
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.label, children: [
2481
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.name, children: ".." }),
2482
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.size, children: "Parent folder" })
2124
2483
  ] })
2125
2484
  ]
2126
2485
  }
@@ -2154,43 +2513,43 @@ function GridItem({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
2154
2513
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2155
2514
  "div",
2156
2515
  {
2157
- css: [styles4.item, isSelected && styles4.itemSelected],
2516
+ css: [styles5.item, isSelected && styles5.itemSelected],
2158
2517
  onClick,
2159
2518
  children: [
2160
2519
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2161
2520
  "div",
2162
2521
  {
2163
- css: styles4.checkboxWrapper,
2522
+ css: styles5.checkboxWrapper,
2164
2523
  onClick: (e) => e.stopPropagation(),
2165
2524
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2166
2525
  "input",
2167
2526
  {
2168
2527
  type: "checkbox",
2169
- css: styles4.checkbox,
2528
+ css: styles5.checkbox,
2170
2529
  checked: isSelected,
2171
2530
  onChange: () => onClick({})
2172
2531
  }
2173
2532
  )
2174
2533
  }
2175
2534
  ),
2176
- item.cdnSynced && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles4.cdnBadge, children: "CDN" }),
2177
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.content, children: [
2535
+ item.cdnSynced && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles5.cdnBadge, children: "CDN" }),
2536
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.content, children: [
2178
2537
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2179
2538
  "button",
2180
2539
  {
2181
- css: styles4.copyBtn,
2540
+ css: styles5.copyBtn,
2182
2541
  onClick: handleCopyPath,
2183
2542
  title: "Copy file path",
2184
2543
  children: [
2185
- showCopied && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles4.tooltip, children: "Copied!" }),
2186
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" }) })
2544
+ showCopied && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles5.tooltip, children: "Copied!" }),
2545
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" }) })
2187
2546
  ]
2188
2547
  }
2189
2548
  ),
2190
2549
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2191
2550
  "button",
2192
2551
  {
2193
- css: styles4.openBtn,
2552
+ css: styles5.openBtn,
2194
2553
  onClick: (e) => {
2195
2554
  e.stopPropagation();
2196
2555
  onOpen();
@@ -2198,13 +2557,13 @@ function GridItem({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
2198
2557
  children: "Open"
2199
2558
  }
2200
2559
  ),
2201
- isFolder ? isImagesFolder ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.imagesFolderWrapper, children: [
2202
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.imagesFolderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M10 4H4a2 2 0 00-2 2v12a2 2 0 002 2h16a2 2 0 002-2V8a2 2 0 00-2-2h-8l-2-2z" }) }),
2203
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.lockIcon, fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { fillRule: "evenodd", d: "M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z", clipRule: "evenodd" }) })
2204
- ] }) : /* @__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" }) }) : isImage && item.hasThumbnail ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2560
+ isFolder ? isImagesFolder ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.imagesFolderWrapper, children: [
2561
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.imagesFolderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M10 4H4a2 2 0 00-2 2v12a2 2 0 002 2h16a2 2 0 002-2V8a2 2 0 00-2-2h-8l-2-2z" }) }),
2562
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.lockIcon, fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { fillRule: "evenodd", d: "M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z", clipRule: "evenodd" }) })
2563
+ ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.folderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M10 4H4a2 2 0 00-2 2v12a2 2 0 002 2h16a2 2 0 002-2V8a2 2 0 00-2-2h-8l-2-2z" }) }) : isImage && item.hasThumbnail ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2205
2564
  "img",
2206
2565
  {
2207
- css: styles4.image,
2566
+ css: styles5.image,
2208
2567
  src: item.thumbnail,
2209
2568
  alt: item.name,
2210
2569
  loading: "lazy"
@@ -2212,26 +2571,26 @@ function GridItem({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
2212
2571
  ) : isImage && !item.hasThumbnail ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2213
2572
  "button",
2214
2573
  {
2215
- css: styles4.noThumbnail,
2574
+ css: styles5.noThumbnail,
2216
2575
  onClick: (e) => {
2217
2576
  e.stopPropagation();
2218
2577
  onGenerateThumbnail();
2219
2578
  },
2220
2579
  title: "Generate thumbnail",
2221
2580
  children: [
2222
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.noThumbnailIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) }),
2223
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles4.noThumbnailText, children: "Generate" })
2581
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.noThumbnailIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) }),
2582
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles5.noThumbnailText, children: "Generate" })
2224
2583
  ]
2225
2584
  }
2226
- ) : /* @__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" }) })
2585
+ ) : /* @__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" }) })
2227
2586
  ] }),
2228
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles4.label, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles4.labelRow, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.labelText, children: [
2229
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles4.name, title: item.name, children: truncateMiddle(item.name) }),
2230
- isFolder ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { css: styles4.size, children: [
2587
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.label, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.labelRow, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.labelText, children: [
2588
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.name, title: item.name, children: truncateMiddle(item.name) }),
2589
+ isFolder ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { css: styles5.size, children: [
2231
2590
  item.fileCount !== void 0 ? `${item.fileCount} files` : "",
2232
2591
  item.fileCount !== void 0 && item.totalSize !== void 0 ? " \xB7 " : "",
2233
2592
  item.totalSize !== void 0 ? formatFileSize(item.totalSize) : ""
2234
- ] }) : item.size !== void 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles4.size, children: formatFileSize(item.size) })
2593
+ ] }) : item.size !== void 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.size, children: formatFileSize(item.size) })
2235
2594
  ] }) }) })
2236
2595
  ]
2237
2596
  }
@@ -2263,7 +2622,7 @@ function truncateMiddle(str, maxLength = 24) {
2263
2622
  var spin3 = _react3.keyframes`
2264
2623
  to { transform: rotate(360deg); }
2265
2624
  `;
2266
- var styles5 = {
2625
+ var styles6 = {
2267
2626
  loading: _react3.css`
2268
2627
  display: flex;
2269
2628
  align-items: center;
@@ -2584,18 +2943,18 @@ function StudioFileList() {
2584
2943
  handleSelectAll
2585
2944
  } = useFileList();
2586
2945
  if (loading) {
2587
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.loading, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.spinner }) });
2946
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.loading, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.spinner }) });
2588
2947
  }
2589
2948
  if (sortedItems.length === 0 && isAtRoot) {
2590
- 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" }) });
2949
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.empty, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { children: "No files in this folder" }) });
2591
2950
  }
2592
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.tableWrapper, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "table", { css: styles5.table, children: [
2951
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.tableWrapper, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "table", { css: styles6.table, children: [
2593
2952
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "thead", { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tr", { children: [
2594
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles5.th, styles5.thCheckbox], children: sortedItems.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2953
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles6.th, styles6.thCheckbox], children: sortedItems.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2595
2954
  "input",
2596
2955
  {
2597
2956
  type: "checkbox",
2598
- css: styles5.checkbox,
2957
+ css: styles6.checkbox,
2599
2958
  checked: allItemsSelected,
2600
2959
  ref: (el) => {
2601
2960
  if (el) el.indeterminate = someItemsSelected && !allItemsSelected;
@@ -2603,21 +2962,21 @@ function StudioFileList() {
2603
2962
  onChange: handleSelectAll
2604
2963
  }
2605
2964
  ) }),
2606
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: styles5.th, children: "Name" }),
2607
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles5.th, styles5.thSize], children: "Size" }),
2608
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles5.th, styles5.thDimensions], children: "Dimensions" }),
2609
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles5.th, styles5.thCdn], children: "CDN" })
2965
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: styles6.th, children: "Name" }),
2966
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles6.th, styles6.thSize], children: "Size" }),
2967
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles6.th, styles6.thDimensions], children: "Dimensions" }),
2968
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles6.th, styles6.thCdn], children: "CDN" })
2610
2969
  ] }) }),
2611
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tbody", { css: styles5.tbody, children: [
2612
- !isAtRoot && !isSearching && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tr", { css: styles5.parentRow, onClick: navigateUp, children: [
2613
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles5.td }),
2614
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles5.td, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.nameCell, children: [
2615
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.parentIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M3 10h10a8 8 0 018 8v2M3 10l6 6m-6-6l6-6" }) }),
2616
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles5.name, children: ".." })
2970
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tbody", { css: styles6.tbody, children: [
2971
+ !isAtRoot && !isSearching && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tr", { css: styles6.parentRow, onClick: navigateUp, children: [
2972
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles6.td }),
2973
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles6.td, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.nameCell, children: [
2974
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.parentIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M3 10h10a8 8 0 018 8v2M3 10l6 6m-6-6l6-6" }) }),
2975
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles6.name, children: ".." })
2617
2976
  ] }) }),
2618
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles5.td, styles5.meta], children: "--" }),
2619
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles5.td, styles5.meta], children: "Parent folder" }),
2620
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles5.td, children: "--" })
2977
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles6.td, styles6.meta], children: "--" }),
2978
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles6.td, styles6.meta], children: "Parent folder" }),
2979
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles6.td, children: "--" })
2621
2980
  ] }),
2622
2981
  sortedItems.map((item) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2623
2982
  ListRow,
@@ -2648,59 +3007,59 @@ function ListRow({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
2648
3007
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2649
3008
  "tr",
2650
3009
  {
2651
- css: [styles5.row, isSelected && styles5.rowSelected],
3010
+ css: [styles6.row, isSelected && styles6.rowSelected],
2652
3011
  onClick,
2653
3012
  children: [
2654
3013
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2655
3014
  "td",
2656
3015
  {
2657
- css: [styles5.td, styles5.checkboxCell],
3016
+ css: [styles6.td, styles6.checkboxCell],
2658
3017
  onClick: (e) => e.stopPropagation(),
2659
3018
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2660
3019
  "input",
2661
3020
  {
2662
3021
  type: "checkbox",
2663
- css: styles5.checkbox,
3022
+ css: styles6.checkbox,
2664
3023
  checked: isSelected,
2665
3024
  onChange: () => onClick({})
2666
3025
  }
2667
3026
  )
2668
3027
  }
2669
3028
  ),
2670
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles5.td, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.nameCell, children: [
2671
- isFolder ? isImagesFolder ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.imagesFolderWrapper, children: [
2672
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.imagesFolderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M10 4H4a2 2 0 00-2 2v12a2 2 0 002 2h16a2 2 0 002-2V8a2 2 0 00-2-2h-8l-2-2z" }) }),
2673
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.lockIcon, fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { fillRule: "evenodd", d: "M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z", clipRule: "evenodd" }) })
2674
- ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.folderIconWrapper, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.folderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M10 4H4a2 2 0 00-2 2v12a2 2 0 002 2h16a2 2 0 002-2V8a2 2 0 00-2-2h-8l-2-2z" }) }) }) : isImage && item.hasThumbnail ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.thumbnailWrapper, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { css: styles5.thumbnail, src: item.thumbnail, alt: item.name, loading: "lazy" }) }) : isImage && !item.hasThumbnail ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.thumbnailWrapper, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3029
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles6.td, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.nameCell, children: [
3030
+ isFolder ? isImagesFolder ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.imagesFolderWrapper, children: [
3031
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.imagesFolderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M10 4H4a2 2 0 00-2 2v12a2 2 0 002 2h16a2 2 0 002-2V8a2 2 0 00-2-2h-8l-2-2z" }) }),
3032
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.lockIcon, fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { fillRule: "evenodd", d: "M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z", clipRule: "evenodd" }) })
3033
+ ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.folderIconWrapper, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.folderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M10 4H4a2 2 0 00-2 2v12a2 2 0 002 2h16a2 2 0 002-2V8a2 2 0 00-2-2h-8l-2-2z" }) }) }) : isImage && item.hasThumbnail ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.thumbnailWrapper, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { css: styles6.thumbnail, src: item.thumbnail, alt: item.name, loading: "lazy" }) }) : isImage && !item.hasThumbnail ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.thumbnailWrapper, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2675
3034
  "button",
2676
3035
  {
2677
- css: styles5.noThumbnail,
3036
+ css: styles6.noThumbnail,
2678
3037
  onClick: (e) => {
2679
3038
  e.stopPropagation();
2680
3039
  onGenerateThumbnail();
2681
3040
  },
2682
3041
  title: "Generate thumbnail",
2683
- children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.noThumbnailIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 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" }) })
3042
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.noThumbnailIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) })
2684
3043
  }
2685
- ) }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.thumbnailWrapper, children: /* @__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" }) }) }),
2686
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles5.name, title: item.name, children: truncateMiddle2(item.name) }),
2687
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.actionsCell, children: [
3044
+ ) }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.thumbnailWrapper, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.fileIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" }) }) }),
3045
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles6.name, title: item.name, children: truncateMiddle2(item.name) }),
3046
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.actionsCell, children: [
2688
3047
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2689
3048
  "button",
2690
3049
  {
2691
- css: styles5.copyBtn,
3050
+ css: styles6.copyBtn,
2692
3051
  onClick: handleCopyPath,
2693
3052
  title: "Copy file path",
2694
3053
  children: [
2695
- showCopied && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles5.tooltip, children: "Copied!" }),
2696
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" }) })
3054
+ showCopied && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles6.tooltip, children: "Copied!" }),
3055
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" }) })
2697
3056
  ]
2698
3057
  }
2699
3058
  ),
2700
3059
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2701
3060
  "button",
2702
3061
  {
2703
- css: styles5.openBtn,
3062
+ css: styles6.openBtn,
2704
3063
  onClick: (e) => {
2705
3064
  e.stopPropagation();
2706
3065
  onOpen();
@@ -2710,12 +3069,12 @@ function ListRow({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
2710
3069
  )
2711
3070
  ] })
2712
3071
  ] }) }),
2713
- /* @__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) : "--" }),
2714
- /* @__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}` : "--" }),
2715
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles5.td, children: item.cdnSynced ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles5.cdnBadge, children: [
2716
- /* @__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" }) }),
3072
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles6.td, styles6.meta], children: isFolder ? item.fileCount !== void 0 ? `${item.fileCount} files` : "--" : item.size !== void 0 ? formatFileSize2(item.size) : "--" }),
3073
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles6.td, styles6.meta], children: isFolder ? item.totalSize !== void 0 ? formatFileSize2(item.totalSize) : "--" : item.dimensions ? `${item.dimensions.width}x${item.dimensions.height}` : "--" }),
3074
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles6.td, children: item.cdnSynced ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles6.cdnBadge, children: [
3075
+ /* @__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" }) }),
2717
3076
  "Synced"
2718
- ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles5.cdnEmpty, children: "--" }) })
3077
+ ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles6.cdnEmpty, children: "--" }) })
2719
3078
  ]
2720
3079
  }
2721
3080
  );
@@ -2753,7 +3112,7 @@ function isVideoFile(filename) {
2753
3112
  const ext = filename.toLowerCase().substring(filename.lastIndexOf("."));
2754
3113
  return VIDEO_EXTENSIONS.includes(ext);
2755
3114
  }
2756
- var styles6 = {
3115
+ var styles7 = {
2757
3116
  overlay: _react3.css`
2758
3117
  position: absolute;
2759
3118
  top: 0;
@@ -3004,9 +3363,11 @@ function StudioDetailView() {
3004
3363
  const [showDeleteConfirm, setShowDeleteConfirm] = _react.useState.call(void 0, false);
3005
3364
  const [showRenameModal, setShowRenameModal] = _react.useState.call(void 0, false);
3006
3365
  const [showProcessConfirm, setShowProcessConfirm] = _react.useState.call(void 0, false);
3366
+ const [showR2SetupModal, setShowR2SetupModal] = _react.useState.call(void 0, false);
3007
3367
  const [processProgress, setProcessProgress] = _react.useState.call(void 0, null);
3008
3368
  const [alertMessage, setAlertMessage] = _react.useState.call(void 0, null);
3009
3369
  const [showCopied, setShowCopied] = _react.useState.call(void 0, false);
3370
+ const [syncing, setSyncing] = _react.useState.call(void 0, false);
3010
3371
  if (!focusedItem) return null;
3011
3372
  const isImage = isImageFile(focusedItem.name);
3012
3373
  const isVideo = isVideoFile(focusedItem.name);
@@ -3078,8 +3439,41 @@ function StudioDetailView() {
3078
3439
  });
3079
3440
  }
3080
3441
  };
3081
- const handleSync = () => {
3082
- console.log("Sync to CDN:", focusedItem.path);
3442
+ const handleSync = async () => {
3443
+ const imageKey = "/" + focusedItem.path.replace(/^public\//, "");
3444
+ setSyncing(true);
3445
+ try {
3446
+ const response = await fetch("/api/studio/sync", {
3447
+ method: "POST",
3448
+ headers: { "Content-Type": "application/json" },
3449
+ body: JSON.stringify({ imageKeys: [imageKey] })
3450
+ });
3451
+ const data = await response.json();
3452
+ if (response.ok) {
3453
+ setAlertMessage({
3454
+ title: "Sync Complete",
3455
+ message: "Successfully synced to CDN."
3456
+ });
3457
+ triggerRefresh();
3458
+ } else {
3459
+ if (_optionalChain([data, 'access', _29 => _29.error, 'optionalAccess', _30 => _30.includes, 'call', _31 => _31("R2 not configured")]) || _optionalChain([data, 'access', _32 => _32.error, 'optionalAccess', _33 => _33.includes, 'call', _34 => _34("CLOUDFLARE_R2")])) {
3460
+ setShowR2SetupModal(true);
3461
+ } else {
3462
+ setAlertMessage({
3463
+ title: "Sync Failed",
3464
+ message: data.error || "Failed to sync to CDN."
3465
+ });
3466
+ }
3467
+ }
3468
+ } catch (error) {
3469
+ console.error("Sync error:", error);
3470
+ setAlertMessage({
3471
+ title: "Sync Failed",
3472
+ message: "Failed to sync to CDN. Check console for details."
3473
+ });
3474
+ } finally {
3475
+ setSyncing(false);
3476
+ }
3083
3477
  };
3084
3478
  const handleProcessImage = async () => {
3085
3479
  setShowProcessConfirm(false);
@@ -3101,7 +3495,7 @@ function StudioDetailView() {
3101
3495
  if (!response.ok) {
3102
3496
  throw new Error("Processing failed");
3103
3497
  }
3104
- const reader = _optionalChain([response, 'access', _19 => _19.body, 'optionalAccess', _20 => _20.getReader, 'call', _21 => _21()]);
3498
+ const reader = _optionalChain([response, 'access', _35 => _35.body, 'optionalAccess', _36 => _36.getReader, 'call', _37 => _37()]);
3105
3499
  if (!reader) {
3106
3500
  throw new Error("No response body");
3107
3501
  }
@@ -3137,14 +3531,14 @@ function StudioDetailView() {
3137
3531
  };
3138
3532
  const renderMedia = () => {
3139
3533
  if (isImage) {
3140
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { css: styles6.image, src: imageSrc, alt: focusedItem.name });
3534
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { css: styles7.image, src: imageSrc, alt: focusedItem.name });
3141
3535
  }
3142
3536
  if (isVideo) {
3143
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "video", { css: styles6.video, src: imageSrc, controls: true });
3537
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "video", { css: styles7.video, src: imageSrc, controls: true });
3144
3538
  }
3145
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.filePlaceholder, children: [
3146
- /* @__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" }) }),
3147
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.fileName, children: focusedItem.name })
3539
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.filePlaceholder, children: [
3540
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles7.fileIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" }) }),
3541
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles7.fileName, children: focusedItem.name })
3148
3542
  ] });
3149
3543
  };
3150
3544
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
@@ -3167,6 +3561,13 @@ function StudioDetailView() {
3167
3561
  onClose: () => setAlertMessage(null)
3168
3562
  }
3169
3563
  ),
3564
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3565
+ R2SetupModal,
3566
+ {
3567
+ isOpen: showR2SetupModal,
3568
+ onClose: () => setShowR2SetupModal(false)
3569
+ }
3570
+ ),
3170
3571
  showRenameModal && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3171
3572
  InputModal,
3172
3573
  {
@@ -3197,61 +3598,61 @@ function StudioDetailView() {
3197
3598
  onClose: () => setProcessProgress(null)
3198
3599
  }
3199
3600
  ),
3200
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.overlay, onClick: handleClose, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.container, onClick: (e) => e.stopPropagation(), children: [
3201
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.main, children: [
3202
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.headerButtons, children: [
3203
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles6.copyBtn, onClick: handleCopyPath, title: "Copy file path", children: [
3204
- showCopied && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles6.tooltip, children: "Copied!" }),
3205
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" }) })
3601
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles7.overlay, onClick: handleClose, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.container, onClick: (e) => e.stopPropagation(), children: [
3602
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.main, children: [
3603
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.headerButtons, children: [
3604
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles7.copyBtn, onClick: handleCopyPath, title: "Copy file path", children: [
3605
+ showCopied && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.tooltip, children: "Copied!" }),
3606
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles7.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" }) })
3206
3607
  ] }),
3207
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles6.mainCloseBtn, onClick: handleClose, "aria-label": "Close", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.mainCloseIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })
3608
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles7.mainCloseBtn, onClick: handleClose, "aria-label": "Close", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles7.mainCloseIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })
3208
3609
  ] }),
3209
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.mediaWrapper, children: renderMedia() })
3610
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles7.mediaWrapper, children: renderMedia() })
3210
3611
  ] }),
3211
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.sidebar, children: [
3212
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.sidebarHeader, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles6.sidebarTitle, children: "Details" }) }),
3213
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.sidebarContent, children: [
3214
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.info, children: [
3215
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.infoRow, children: [
3216
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles6.infoLabel, children: "Name" }),
3217
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles6.infoValueWrap, children: focusedItem.name })
3612
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.sidebar, children: [
3613
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles7.sidebarHeader, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles7.sidebarTitle, children: "Details" }) }),
3614
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.sidebarContent, children: [
3615
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.info, children: [
3616
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.infoRow, children: [
3617
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoLabel, children: "Name" }),
3618
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoValueWrap, children: focusedItem.name })
3218
3619
  ] }),
3219
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.infoRow, children: [
3220
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles6.infoLabel, children: "Path" }),
3221
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles6.infoValueWrap, children: focusedItem.path.replace(/^public\//, "") })
3620
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.infoRow, children: [
3621
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoLabel, children: "Path" }),
3622
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoValueWrap, children: focusedItem.path.replace(/^public\//, "") })
3222
3623
  ] }),
3223
- focusedItem.size !== void 0 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.infoRow, children: [
3224
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles6.infoLabel, children: "Size" }),
3225
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles6.infoValue, children: formatFileSize3(focusedItem.size) })
3624
+ focusedItem.size !== void 0 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.infoRow, children: [
3625
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoLabel, children: "Size" }),
3626
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoValue, children: formatFileSize3(focusedItem.size) })
3226
3627
  ] }),
3227
- focusedItem.dimensions && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.infoRow, children: [
3228
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles6.infoLabel, children: "Dimensions" }),
3229
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles6.infoValue, children: [
3628
+ focusedItem.dimensions && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.infoRow, children: [
3629
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoLabel, children: "Dimensions" }),
3630
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles7.infoValue, children: [
3230
3631
  focusedItem.dimensions.width,
3231
3632
  " \xD7 ",
3232
3633
  focusedItem.dimensions.height
3233
3634
  ] })
3234
3635
  ] }),
3235
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.infoRow, children: [
3236
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles6.infoLabel, children: "CDN Status" }),
3237
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles6.infoValue, children: focusedItem.cdnSynced ? "Synced" : "Not synced" })
3636
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.infoRow, children: [
3637
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoLabel, children: "CDN Status" }),
3638
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoValue, children: focusedItem.cdnSynced ? "Synced" : "Not synced" })
3238
3639
  ] })
3239
3640
  ] }),
3240
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.actions, children: [
3241
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles6.actionBtn, onClick: () => setShowRenameModal(true), children: [
3242
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.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" }) }),
3641
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.actions, children: [
3642
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles7.actionBtn, onClick: () => setShowRenameModal(true), children: [
3643
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles7.actionIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" }) }),
3243
3644
  "Rename"
3244
3645
  ] }),
3245
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles6.actionBtn, onClick: handleSync, children: [
3246
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.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" }) }),
3247
- "Sync to CDN"
3646
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles7.actionBtn, onClick: handleSync, disabled: syncing, children: [
3647
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles7.actionIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" }) }),
3648
+ syncing ? "Syncing..." : "Sync to CDN"
3248
3649
  ] }),
3249
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles6.actionBtn, onClick: () => setShowProcessConfirm(true), children: [
3250
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.actionIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) }),
3650
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles7.actionBtn, onClick: () => setShowProcessConfirm(true), children: [
3651
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles7.actionIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) }),
3251
3652
  "Process Image"
3252
3653
  ] }),
3253
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: [styles6.actionBtn, styles6.actionBtnDanger], onClick: () => setShowDeleteConfirm(true), children: [
3254
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.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" }) }),
3654
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: [styles7.actionBtn, styles7.actionBtnDanger], onClick: () => setShowDeleteConfirm(true), children: [
3655
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles7.actionIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" }) }),
3255
3656
  "Delete"
3256
3657
  ] })
3257
3658
  ] })
@@ -3271,7 +3672,7 @@ function formatFileSize3(bytes) {
3271
3672
 
3272
3673
 
3273
3674
  var btnHeight2 = "36px";
3274
- var styles7 = {
3675
+ var styles8 = {
3275
3676
  btn: _react3.css`
3276
3677
  height: ${btnHeight2};
3277
3678
  padding: 0 12px;
@@ -3509,10 +3910,10 @@ var styles7 = {
3509
3910
  function StudioSettings() {
3510
3911
  const [isOpen, setIsOpen] = _react.useState.call(void 0, false);
3511
3912
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
3512
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles7.btn, onClick: () => setIsOpen(true), "aria-label": "Settings", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
3913
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles8.btn, onClick: () => setIsOpen(true), "aria-label": "Settings", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
3513
3914
  "svg",
3514
3915
  {
3515
- css: styles7.icon,
3916
+ css: styles8.icon,
3516
3917
  xmlns: "http://www.w3.org/2000/svg",
3517
3918
  viewBox: "0 0 24 24",
3518
3919
  fill: "none",
@@ -3541,50 +3942,50 @@ function SettingsPanel({ onClose }) {
3541
3942
  setCopied(true);
3542
3943
  setTimeout(() => setCopied(false), 2e3);
3543
3944
  };
3544
- 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: [
3545
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.header, children: [
3546
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { css: styles7.title, children: "Settings" }),
3547
- /* @__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" }) }) })
3945
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles8.overlay, onClick: onClose, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.panel, onClick: (e) => e.stopPropagation(), children: [
3946
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.header, children: [
3947
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { css: styles8.title, children: "Settings" }),
3948
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles8.closeBtn, onClick: onClose, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles8.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })
3548
3949
  ] }),
3549
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.sections, children: [
3950
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.sections, children: [
3550
3951
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "section", { children: [
3551
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles7.sectionTitle, children: "Cloudflare R2" }),
3552
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles7.description, children: "Configure in .env.local file:" }),
3553
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.codeWrapper, children: [
3554
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles7.copyBtn, onClick: handleCopy, title: "Copy to clipboard", children: [
3555
- copied && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.tooltip, children: "Copied!" }),
3556
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles7.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" }) })
3952
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles8.sectionTitle, children: "Cloudflare R2" }),
3953
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles8.description, children: "Configure in .env.local file:" }),
3954
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.codeWrapper, children: [
3955
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles8.copyBtn, onClick: handleCopy, title: "Copy to clipboard", children: [
3956
+ copied && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles8.tooltip, children: "Copied!" }),
3957
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles8.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" }) })
3557
3958
  ] }),
3558
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.code, children: [
3559
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles7.codeLine, children: "CLOUDFLARE_R2_ACCOUNT_ID=abc123def456ghi789" }),
3560
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles7.codeLine, children: "CLOUDFLARE_R2_ACCESS_KEY_ID=your_access_key_id_here" }),
3561
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles7.codeLine, children: "CLOUDFLARE_R2_SECRET_ACCESS_KEY=your_secret_access_key_here" }),
3562
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles7.codeLine, children: "CLOUDFLARE_R2_BUCKET_NAME=my-images-bucket" }),
3563
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles7.codeLine, children: "CLOUDFLARE_R2_PUBLIC_URL=https://cdn.yourdomain.com" })
3959
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.code, children: [
3960
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles8.codeLine, children: "CLOUDFLARE_R2_ACCOUNT_ID=abc123def456ghi789" }),
3961
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles8.codeLine, children: "CLOUDFLARE_R2_ACCESS_KEY_ID=your_access_key_id_here" }),
3962
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles8.codeLine, children: "CLOUDFLARE_R2_SECRET_ACCESS_KEY=your_secret_access_key_here" }),
3963
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles8.codeLine, children: "CLOUDFLARE_R2_BUCKET_NAME=my-images-bucket" }),
3964
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles8.codeLine, children: "CLOUDFLARE_R2_PUBLIC_URL=https://cdn.yourdomain.com" })
3564
3965
  ] })
3565
3966
  ] })
3566
3967
  ] }),
3567
3968
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "section", { children: [
3568
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles7.sectionTitle, children: "Thumbnail Sizes" }),
3569
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.grid, children: [
3969
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles8.sectionTitle, children: "Thumbnail Sizes" }),
3970
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.grid, children: [
3570
3971
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
3571
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css: styles7.label, children: "Small" }),
3572
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles7.input, type: "number", defaultValue: 300 })
3972
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css: styles8.label, children: "Small" }),
3973
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles8.input, type: "number", defaultValue: 300 })
3573
3974
  ] }),
3574
3975
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
3575
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css: styles7.label, children: "Medium" }),
3576
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles7.input, type: "number", defaultValue: 700 })
3976
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css: styles8.label, children: "Medium" }),
3977
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles8.input, type: "number", defaultValue: 700 })
3577
3978
  ] }),
3578
3979
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
3579
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css: styles7.label, children: "Large" }),
3580
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles7.input, type: "number", defaultValue: 1400 })
3980
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css: styles8.label, children: "Large" }),
3981
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles8.input, type: "number", defaultValue: 1400 })
3581
3982
  ] })
3582
3983
  ] })
3583
3984
  ] })
3584
3985
  ] }),
3585
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.footer, children: [
3586
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles7.cancelBtn, onClick: onClose, children: "Cancel" }),
3587
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles7.saveBtn, children: "Save Changes" })
3986
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.footer, children: [
3987
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles8.cancelBtn, onClick: onClose, children: "Cancel" }),
3988
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles8.saveBtn, children: "Save Changes" })
3588
3989
  ] })
3589
3990
  ] }) });
3590
3991
  }
@@ -3592,7 +3993,7 @@ function SettingsPanel({ onClose }) {
3592
3993
  // src/components/ErrorModal.tsx
3593
3994
 
3594
3995
 
3595
- var styles8 = {
3996
+ var styles9 = {
3596
3997
  overlay: _react3.css`
3597
3998
  position: fixed;
3598
3999
  inset: 0;
@@ -3654,20 +4055,20 @@ var styles8 = {
3654
4055
  function ErrorModal() {
3655
4056
  const { error, clearError } = useStudio();
3656
4057
  if (!error) return null;
3657
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles8.overlay, onClick: clearError, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.modal, onClick: (e) => e.stopPropagation(), children: [
3658
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.header, children: [
3659
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles8.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" }) }),
3660
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles8.title, children: error.title })
4058
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles9.overlay, onClick: clearError, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles9.modal, onClick: (e) => e.stopPropagation(), children: [
4059
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles9.header, children: [
4060
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles9.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" }) }),
4061
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles9.title, children: error.title })
3661
4062
  ] }),
3662
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles8.message, children: error.message }),
3663
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles8.button, onClick: clearError, children: "OK" })
4063
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles9.message, children: error.message }),
4064
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles9.button, onClick: clearError, children: "OK" })
3664
4065
  ] }) });
3665
4066
  }
3666
4067
 
3667
4068
  // src/components/StudioUI.tsx
3668
4069
 
3669
4070
  var btnHeight3 = "36px";
3670
- var styles9 = {
4071
+ var styles10 = {
3671
4072
  container: _react3.css`
3672
4073
  ${_chunkUFCWGUAGjs.baseReset}
3673
4074
  display: flex;
@@ -3961,16 +4362,16 @@ function StudioUI({ onClose, isVisible = true }) {
3961
4362
  showError,
3962
4363
  clearError
3963
4364
  };
3964
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioContext.Provider, { value: contextValue, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles9.container, children: [
3965
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles9.header, children: [
3966
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles9.headerLeft, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h1", { css: styles9.title, children: "Studio" }) }),
3967
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles9.headerCenter, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Breadcrumbs, { currentPath, onNavigate: setCurrentPath }) }),
3968
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles9.headerActions, children: [
4365
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioContext.Provider, { value: contextValue, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles10.container, children: [
4366
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles10.header, children: [
4367
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles10.headerLeft, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h1", { css: styles10.title, children: "Studio" }) }),
4368
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles10.headerCenter, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Breadcrumbs, { currentPath, onNavigate: setCurrentPath }) }),
4369
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles10.headerActions, children: [
3969
4370
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioSettings, {}),
3970
4371
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3971
4372
  "button",
3972
4373
  {
3973
- css: styles9.headerBtn,
4374
+ css: styles10.headerBtn,
3974
4375
  onClick: onClose,
3975
4376
  "aria-label": "Close Studio",
3976
4377
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, CloseIcon, {})
@@ -3982,16 +4383,16 @@ function StudioUI({ onClose, isVisible = true }) {
3982
4383
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
3983
4384
  "div",
3984
4385
  {
3985
- css: styles9.content,
4386
+ css: styles10.content,
3986
4387
  onDragOver: handleDragOver,
3987
4388
  onDragLeave: handleDragLeave,
3988
4389
  onDrop: handleDrop,
3989
4390
  children: [
3990
- isDragging && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles9.dropOverlay, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles9.dropMessage, children: [
3991
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles9.dropIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" }) }),
4391
+ isDragging && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles10.dropOverlay, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles10.dropMessage, children: [
4392
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles10.dropIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" }) }),
3992
4393
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: "Drop files to upload" })
3993
4394
  ] }) }),
3994
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles9.fileBrowser, children: viewMode === "grid" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioFileGrid, {}) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioFileList, {}) })
4395
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles10.fileBrowser, children: viewMode === "grid" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioFileGrid, {}) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioFileList, {}) })
3995
4396
  ]
3996
4397
  }
3997
4398
  ),
@@ -4005,12 +4406,12 @@ function Breadcrumbs({ currentPath, onNavigate }) {
4005
4406
  name: part,
4006
4407
  path: parts.slice(0, index + 1).join("/")
4007
4408
  }));
4008
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles9.breadcrumbs, children: breadcrumbs.map((crumb, index) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
4009
- index > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles9.breadcrumbSeparator, children: "/" }),
4010
- index === breadcrumbs.length - 1 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles9.breadcrumbCurrent, children: crumb.name }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4409
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles10.breadcrumbs, children: breadcrumbs.map((crumb, index) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
4410
+ index > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles10.breadcrumbSeparator, children: "/" }),
4411
+ index === breadcrumbs.length - 1 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles10.breadcrumbCurrent, children: crumb.name }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4011
4412
  "span",
4012
4413
  {
4013
- css: styles9.breadcrumbItem,
4414
+ css: styles10.breadcrumbItem,
4014
4415
  onClick: () => onNavigate(crumb.path),
4015
4416
  children: crumb.name
4016
4417
  }
@@ -4021,7 +4422,7 @@ function CloseIcon() {
4021
4422
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
4022
4423
  "svg",
4023
4424
  {
4024
- css: styles9.headerIcon,
4425
+ css: styles10.headerIcon,
4025
4426
  xmlns: "http://www.w3.org/2000/svg",
4026
4427
  viewBox: "0 0 24 24",
4027
4428
  fill: "none",
@@ -4041,4 +4442,4 @@ var StudioUI_default = StudioUI;
4041
4442
 
4042
4443
 
4043
4444
  exports.StudioUI = StudioUI; exports.default = StudioUI_default;
4044
- //# sourceMappingURL=StudioUI-YFDO5MGG.js.map
4445
+ //# sourceMappingURL=StudioUI-MVIOZTZH.js.map