@gallop.software/studio 0.1.82 → 0.1.84

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,389 @@ function StudioFolderPicker({ selectedItems, currentPath, onMove, onCancel }) {
674
674
  ] }) });
675
675
  }
676
676
 
677
+ // src/components/R2SetupModal.tsx
678
+
679
+
680
+
681
+ var ENV_TEMPLATE = `CLOUDFLARE_R2_ACCOUNT_ID=your_account_id
682
+ CLOUDFLARE_R2_ACCESS_KEY_ID=your_access_key
683
+ CLOUDFLARE_R2_SECRET_ACCESS_KEY=your_secret_key
684
+ CLOUDFLARE_R2_BUCKET_NAME=your_bucket_name
685
+ CLOUDFLARE_R2_PUBLIC_URL=https://pub-xxx.r2.dev`;
686
+ var styles3 = {
687
+ overlay: _react3.css`
688
+ position: fixed;
689
+ inset: 0;
690
+ background: rgba(0, 0, 0, 0.6);
691
+ display: flex;
692
+ align-items: center;
693
+ justify-content: center;
694
+ z-index: 1100;
695
+ padding: 20px;
696
+ `,
697
+ modal: _react3.css`
698
+ background: ${_chunkUFCWGUAGjs.colors.surface};
699
+ border-radius: 12px;
700
+ max-width: 560px;
701
+ width: 100%;
702
+ max-height: 90vh;
703
+ overflow-y: auto;
704
+ box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
705
+ `,
706
+ header: _react3.css`
707
+ display: flex;
708
+ align-items: center;
709
+ gap: 12px;
710
+ padding: 20px 24px;
711
+ border-bottom: 1px solid ${_chunkUFCWGUAGjs.colors.border};
712
+ `,
713
+ icon: _react3.css`
714
+ width: 32px;
715
+ height: 32px;
716
+ color: ${_chunkUFCWGUAGjs.colors.primary};
717
+ flex-shrink: 0;
718
+ `,
719
+ title: _react3.css`
720
+ font-size: ${_chunkUFCWGUAGjs.fontSize.xl};
721
+ font-weight: 600;
722
+ color: ${_chunkUFCWGUAGjs.colors.text};
723
+ margin: 0;
724
+ `,
725
+ closeBtn: _react3.css`
726
+ margin-left: auto;
727
+ background: none;
728
+ border: none;
729
+ padding: 4px;
730
+ cursor: pointer;
731
+ color: ${_chunkUFCWGUAGjs.colors.textMuted};
732
+ border-radius: 4px;
733
+
734
+ &:hover {
735
+ color: ${_chunkUFCWGUAGjs.colors.text};
736
+ background: ${_chunkUFCWGUAGjs.colors.surfaceHover};
737
+ }
738
+ `,
739
+ closeIcon: _react3.css`
740
+ width: 20px;
741
+ height: 20px;
742
+ `,
743
+ content: _react3.css`
744
+ padding: 24px;
745
+ `,
746
+ intro: _react3.css`
747
+ font-size: ${_chunkUFCWGUAGjs.fontSize.base};
748
+ color: ${_chunkUFCWGUAGjs.colors.textSecondary};
749
+ margin: 0 0 20px 0;
750
+ line-height: 1.6;
751
+ `,
752
+ steps: _react3.css`
753
+ list-style: none;
754
+ padding: 0;
755
+ margin: 0;
756
+ display: flex;
757
+ flex-direction: column;
758
+ gap: 16px;
759
+ `,
760
+ step: _react3.css`
761
+ display: flex;
762
+ gap: 12px;
763
+ `,
764
+ stepNumber: _react3.css`
765
+ width: 28px;
766
+ height: 28px;
767
+ border-radius: 50%;
768
+ background: ${_chunkUFCWGUAGjs.colors.primaryLight};
769
+ color: ${_chunkUFCWGUAGjs.colors.primary};
770
+ font-size: ${_chunkUFCWGUAGjs.fontSize.sm};
771
+ font-weight: 600;
772
+ display: flex;
773
+ align-items: center;
774
+ justify-content: center;
775
+ flex-shrink: 0;
776
+ `,
777
+ stepContent: _react3.css`
778
+ flex: 1;
779
+ padding-top: 3px;
780
+ `,
781
+ stepTitle: _react3.css`
782
+ font-size: ${_chunkUFCWGUAGjs.fontSize.base};
783
+ font-weight: 500;
784
+ color: ${_chunkUFCWGUAGjs.colors.text};
785
+ margin: 0 0 4px 0;
786
+ `,
787
+ stepDesc: _react3.css`
788
+ font-size: ${_chunkUFCWGUAGjs.fontSize.sm};
789
+ color: ${_chunkUFCWGUAGjs.colors.textSecondary};
790
+ margin: 0;
791
+ line-height: 1.5;
792
+ `,
793
+ link: _react3.css`
794
+ color: ${_chunkUFCWGUAGjs.colors.primary};
795
+ text-decoration: none;
796
+ font-weight: 500;
797
+
798
+ &:hover {
799
+ text-decoration: underline;
800
+ }
801
+ `,
802
+ envVarsWrapper: _react3.css`
803
+ position: relative;
804
+ margin-top: 20px;
805
+ `,
806
+ envVars: _react3.css`
807
+ background: ${_chunkUFCWGUAGjs.colors.background};
808
+ border: 1px solid ${_chunkUFCWGUAGjs.colors.border};
809
+ border-radius: 8px;
810
+ padding: 16px;
811
+ padding-right: 48px;
812
+ font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;
813
+ font-size: 13px;
814
+ line-height: 1.8;
815
+ color: ${_chunkUFCWGUAGjs.colors.text};
816
+ overflow-x: auto;
817
+ `,
818
+ envVar: _react3.css`
819
+ display: block;
820
+ `,
821
+ envKey: _react3.css`
822
+ color: ${_chunkUFCWGUAGjs.colors.primary};
823
+ `,
824
+ envValue: _react3.css`
825
+ color: ${_chunkUFCWGUAGjs.colors.textSecondary};
826
+ `,
827
+ copyBtn: _react3.css`
828
+ position: absolute;
829
+ top: 8px;
830
+ right: 8px;
831
+ width: 32px;
832
+ height: 32px;
833
+ display: flex;
834
+ align-items: center;
835
+ justify-content: center;
836
+ background: ${_chunkUFCWGUAGjs.colors.surface};
837
+ border: 1px solid ${_chunkUFCWGUAGjs.colors.border};
838
+ border-radius: 6px;
839
+ cursor: pointer;
840
+ color: ${_chunkUFCWGUAGjs.colors.textMuted};
841
+ transition: all 0.15s ease;
842
+
843
+ &:hover {
844
+ background: ${_chunkUFCWGUAGjs.colors.surfaceHover};
845
+ color: ${_chunkUFCWGUAGjs.colors.text};
846
+ border-color: #d0d5dd;
847
+ }
848
+ `,
849
+ copyIcon: _react3.css`
850
+ width: 16px;
851
+ height: 16px;
852
+ `,
853
+ copiedTooltip: _react3.css`
854
+ position: absolute;
855
+ top: 50%;
856
+ right: 100%;
857
+ transform: translateY(-50%);
858
+ background: #1a1f36;
859
+ color: white;
860
+ padding: 4px 8px;
861
+ border-radius: 4px;
862
+ font-size: 12px;
863
+ white-space: nowrap;
864
+ margin-right: 6px;
865
+ pointer-events: none;
866
+
867
+ &::before {
868
+ content: '';
869
+ position: absolute;
870
+ right: -4px;
871
+ top: 50%;
872
+ transform: translateY(-50%);
873
+ border-left: 4px solid #1a1f36;
874
+ border-top: 4px solid transparent;
875
+ border-bottom: 4px solid transparent;
876
+ }
877
+ `,
878
+ footer: _react3.css`
879
+ padding: 16px 24px;
880
+ border-top: 1px solid ${_chunkUFCWGUAGjs.colors.border};
881
+ display: flex;
882
+ justify-content: flex-end;
883
+ gap: 12px;
884
+ `,
885
+ docsBtn: _react3.css`
886
+ padding: 10px 16px;
887
+ border-radius: 6px;
888
+ font-size: ${_chunkUFCWGUAGjs.fontSize.base};
889
+ font-weight: 500;
890
+ border: 1px solid ${_chunkUFCWGUAGjs.colors.border};
891
+ background: ${_chunkUFCWGUAGjs.colors.surface};
892
+ color: ${_chunkUFCWGUAGjs.colors.text};
893
+ cursor: pointer;
894
+ text-decoration: none;
895
+ display: inline-flex;
896
+ align-items: center;
897
+ gap: 6px;
898
+ transition: all 0.15s ease;
899
+
900
+ &:hover {
901
+ background: ${_chunkUFCWGUAGjs.colors.surfaceHover};
902
+ border-color: #d0d5dd;
903
+ }
904
+ `,
905
+ doneBtn: _react3.css`
906
+ padding: 10px 20px;
907
+ border-radius: 6px;
908
+ font-size: ${_chunkUFCWGUAGjs.fontSize.base};
909
+ font-weight: 500;
910
+ border: none;
911
+ background: ${_chunkUFCWGUAGjs.colors.primary};
912
+ color: white;
913
+ cursor: pointer;
914
+ transition: background 0.15s ease;
915
+
916
+ &:hover {
917
+ background: ${_chunkUFCWGUAGjs.colors.primaryHover};
918
+ }
919
+ `,
920
+ externalIcon: _react3.css`
921
+ width: 14px;
922
+ height: 14px;
923
+ `
924
+ };
925
+ function R2SetupModal({ isOpen, onClose }) {
926
+ const [copied, setCopied] = _react.useState.call(void 0, false);
927
+ const handleCopy = async () => {
928
+ try {
929
+ await navigator.clipboard.writeText(ENV_TEMPLATE);
930
+ setCopied(true);
931
+ setTimeout(() => setCopied(false), 2e3);
932
+ } catch (error) {
933
+ console.error("Failed to copy:", error);
934
+ }
935
+ };
936
+ if (!isOpen) return null;
937
+ 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: [
938
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.header, children: [
939
+ /* @__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" }) }),
940
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { css: styles3.title, children: "Set Up CDN Storage" }),
941
+ /* @__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" }) }) })
942
+ ] }),
943
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.content, children: [
944
+ /* @__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." }),
945
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "ol", { css: styles3.steps, children: [
946
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "li", { css: styles3.step, children: [
947
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.stepNumber, children: "1" }),
948
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.stepContent, children: [
949
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h4", { css: styles3.stepTitle, children: "Create a Cloudflare account" }),
950
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { css: styles3.stepDesc, children: [
951
+ "Sign up at",
952
+ " ",
953
+ /* @__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" }),
954
+ " ",
955
+ "if you don't have one already."
956
+ ] })
957
+ ] })
958
+ ] }),
959
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "li", { css: styles3.step, children: [
960
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.stepNumber, children: "2" }),
961
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.stepContent, children: [
962
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h4", { css: styles3.stepTitle, children: "Create an R2 bucket" }),
963
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { css: styles3.stepDesc, children: [
964
+ "Go to R2 in your Cloudflare dashboard and create a new bucket. Choose a name like ",
965
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "code", { children: "my-images" }),
966
+ "."
967
+ ] })
968
+ ] })
969
+ ] }),
970
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "li", { css: styles3.step, children: [
971
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.stepNumber, children: "3" }),
972
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.stepContent, children: [
973
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h4", { css: styles3.stepTitle, children: "Enable public access" }),
974
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { css: styles3.stepDesc, children: [
975
+ 'In bucket settings, enable "Public Access" and copy the public URL (e.g., ',
976
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "code", { children: "https://pub-xxx.r2.dev" }),
977
+ ")."
978
+ ] })
979
+ ] })
980
+ ] }),
981
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "li", { css: styles3.step, children: [
982
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.stepNumber, children: "4" }),
983
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.stepContent, children: [
984
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h4", { css: styles3.stepTitle, children: "Create API token" }),
985
+ /* @__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.' })
986
+ ] })
987
+ ] }),
988
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "li", { css: styles3.step, children: [
989
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.stepNumber, children: "5" }),
990
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.stepContent, children: [
991
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h4", { css: styles3.stepTitle, children: "Add environment variables" }),
992
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { css: styles3.stepDesc, children: [
993
+ "Add these to your ",
994
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "code", { children: ".env.local" }),
995
+ " file:"
996
+ ] })
997
+ ] })
998
+ ] })
999
+ ] }),
1000
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.envVarsWrapper, children: [
1001
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.envVars, children: [
1002
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles3.envVar, children: [
1003
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.envKey, children: "CLOUDFLARE_R2_ACCOUNT_ID" }),
1004
+ "=",
1005
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.envValue, children: "your_account_id" })
1006
+ ] }),
1007
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles3.envVar, children: [
1008
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.envKey, children: "CLOUDFLARE_R2_ACCESS_KEY_ID" }),
1009
+ "=",
1010
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.envValue, children: "your_access_key" })
1011
+ ] }),
1012
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles3.envVar, children: [
1013
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.envKey, children: "CLOUDFLARE_R2_SECRET_ACCESS_KEY" }),
1014
+ "=",
1015
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.envValue, children: "your_secret_key" })
1016
+ ] }),
1017
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles3.envVar, children: [
1018
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.envKey, children: "CLOUDFLARE_R2_BUCKET_NAME" }),
1019
+ "=",
1020
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.envValue, children: "your_bucket_name" })
1021
+ ] }),
1022
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles3.envVar, children: [
1023
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.envKey, children: "CLOUDFLARE_R2_PUBLIC_URL" }),
1024
+ "=",
1025
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.envValue, children: "https://pub-xxx.r2.dev" })
1026
+ ] })
1027
+ ] }),
1028
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles3.copyBtn, onClick: handleCopy, title: "Copy to clipboard", children: [
1029
+ copied && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.copiedTooltip, children: "Copied!" }),
1030
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles3.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: "M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" }) })
1031
+ ] })
1032
+ ] })
1033
+ ] }),
1034
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.footer, children: [
1035
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1036
+ "a",
1037
+ {
1038
+ css: styles3.docsBtn,
1039
+ href: "https://developers.cloudflare.com/r2/get-started/",
1040
+ target: "_blank",
1041
+ rel: "noopener noreferrer",
1042
+ children: [
1043
+ "R2 Documentation",
1044
+ /* @__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" }) })
1045
+ ]
1046
+ }
1047
+ ),
1048
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles3.doneBtn, onClick: onClose, children: "Got it" })
1049
+ ] })
1050
+ ] }) });
1051
+ }
1052
+
677
1053
  // src/components/StudioToolbar.tsx
678
1054
 
679
1055
  var btnHeight = "36px";
680
1056
  var spin = _react3.keyframes`
681
1057
  to { transform: rotate(360deg); }
682
1058
  `;
683
- var styles3 = {
1059
+ var styles4 = {
684
1060
  toolbar: _react3.css`
685
1061
  display: flex;
686
1062
  flex-wrap: nowrap;
@@ -898,6 +1274,8 @@ function StudioToolbar() {
898
1274
  const [showNewFolderModal, setShowNewFolderModal] = _react.useState.call(void 0, false);
899
1275
  const [showRenameFolderModal, setShowRenameFolderModal] = _react.useState.call(void 0, false);
900
1276
  const [showMoveModal, setShowMoveModal] = _react.useState.call(void 0, false);
1277
+ const [showR2SetupModal, setShowR2SetupModal] = _react.useState.call(void 0, false);
1278
+ const [syncing, setSyncing] = _react.useState.call(void 0, false);
901
1279
  const isInImagesFolder = currentPath === "public/images" || currentPath.startsWith("public/images/");
902
1280
  const handleUpload = _react.useCallback.call(void 0, () => {
903
1281
  _optionalChain([fileInputRef, 'access', _2 => _2.current, 'optionalAccess', _3 => _3.click, 'call', _4 => _4()]);
@@ -1194,9 +1572,60 @@ function StudioToolbar() {
1194
1572
  });
1195
1573
  }
1196
1574
  }, [selectedItems, clearSelection, triggerRefresh]);
1197
- const handleSyncCdn = _react.useCallback.call(void 0, () => {
1198
- console.log("Sync CDN clicked", selectedItems);
1199
- }, [selectedItems]);
1575
+ const handleSyncCdn = _react.useCallback.call(void 0, async () => {
1576
+ if (selectedItems.size === 0) return;
1577
+ const imageKeys = Array.from(selectedItems).filter((p) => !p.endsWith("/")).map((p) => "/" + p.replace(/^public\//, ""));
1578
+ if (imageKeys.length === 0) {
1579
+ setAlertMessage({
1580
+ title: "No Images Selected",
1581
+ message: "Please select image files to sync to CDN."
1582
+ });
1583
+ return;
1584
+ }
1585
+ setSyncing(true);
1586
+ try {
1587
+ const response = await fetch("/api/studio/sync", {
1588
+ method: "POST",
1589
+ headers: { "Content-Type": "application/json" },
1590
+ body: JSON.stringify({ imageKeys })
1591
+ });
1592
+ const data = await response.json();
1593
+ if (response.ok) {
1594
+ const syncedCount = _optionalChain([data, 'access', _19 => _19.synced, 'optionalAccess', _20 => _20.length]) || 0;
1595
+ const errorCount = _optionalChain([data, 'access', _21 => _21.errors, 'optionalAccess', _22 => _22.length]) || 0;
1596
+ if (errorCount > 0) {
1597
+ setAlertMessage({
1598
+ title: "Sync Partially Complete",
1599
+ message: `Synced ${syncedCount} images. ${errorCount} failed.`
1600
+ });
1601
+ } else {
1602
+ setAlertMessage({
1603
+ title: "Sync Complete",
1604
+ message: `Successfully synced ${syncedCount} images to CDN.`
1605
+ });
1606
+ }
1607
+ clearSelection();
1608
+ triggerRefresh();
1609
+ } else {
1610
+ 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")])) {
1611
+ setShowR2SetupModal(true);
1612
+ } else {
1613
+ setAlertMessage({
1614
+ title: "Sync Failed",
1615
+ message: data.error || "Failed to sync to CDN."
1616
+ });
1617
+ }
1618
+ }
1619
+ } catch (error) {
1620
+ console.error("Sync error:", error);
1621
+ setAlertMessage({
1622
+ title: "Sync Failed",
1623
+ message: "Failed to sync to CDN. Check console for details."
1624
+ });
1625
+ } finally {
1626
+ setSyncing(false);
1627
+ }
1628
+ }, [selectedItems, clearSelection, triggerRefresh]);
1200
1629
  const handleCreateFolder = _react.useCallback.call(void 0, async (folderName) => {
1201
1630
  setShowNewFolderModal(false);
1202
1631
  try {
@@ -1375,7 +1804,14 @@ function StudioToolbar() {
1375
1804
  onClose: () => setAlertMessage(null)
1376
1805
  }
1377
1806
  ),
1378
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.toolbar, children: [
1807
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1808
+ R2SetupModal,
1809
+ {
1810
+ isOpen: showR2SetupModal,
1811
+ onClose: () => setShowR2SetupModal(false)
1812
+ }
1813
+ ),
1814
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.toolbar, children: [
1379
1815
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1380
1816
  "input",
1381
1817
  {
@@ -1387,11 +1823,11 @@ function StudioToolbar() {
1387
1823
  style: { display: "none" }
1388
1824
  }
1389
1825
  ),
1390
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.left, children: [
1826
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.left, children: [
1391
1827
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1392
1828
  "button",
1393
1829
  {
1394
- css: [styles3.btn, styles3.btnPrimary],
1830
+ css: [styles4.btn, styles4.btnPrimary],
1395
1831
  onClick: handleUpload,
1396
1832
  disabled: uploading || isInImagesFolder,
1397
1833
  children: [
@@ -1403,7 +1839,7 @@ function StudioToolbar() {
1403
1839
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1404
1840
  "button",
1405
1841
  {
1406
- css: styles3.btn,
1842
+ css: styles4.btn,
1407
1843
  onClick: () => singleFolderSelected ? setShowRenameFolderModal(true) : setShowNewFolderModal(true),
1408
1844
  disabled: isInImagesFolder && !singleFolderSelected,
1409
1845
  title: isInImagesFolder && !singleFolderSelected ? "Cannot create folders in protected images folder" : void 0,
@@ -1413,11 +1849,11 @@ function StudioToolbar() {
1413
1849
  ]
1414
1850
  }
1415
1851
  ),
1416
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles3.divider }),
1852
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles4.divider }),
1417
1853
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1418
1854
  "button",
1419
1855
  {
1420
- css: styles3.btn,
1856
+ css: styles4.btn,
1421
1857
  onClick: handleProcessImages,
1422
1858
  disabled: processing || isInImagesFolder,
1423
1859
  title: isInImagesFolder ? "Cannot process images folder" : void 0,
@@ -1430,7 +1866,7 @@ function StudioToolbar() {
1430
1866
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1431
1867
  "button",
1432
1868
  {
1433
- css: [styles3.btn, styles3.btnDanger],
1869
+ css: [styles4.btn, styles4.btnDanger],
1434
1870
  onClick: handleDeleteClick,
1435
1871
  disabled: !hasSelection,
1436
1872
  children: [
@@ -1442,7 +1878,7 @@ function StudioToolbar() {
1442
1878
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1443
1879
  "button",
1444
1880
  {
1445
- css: styles3.btn,
1881
+ css: styles4.btn,
1446
1882
  onClick: handleMoveClick,
1447
1883
  disabled: !hasSelection,
1448
1884
  children: [
@@ -1454,20 +1890,20 @@ function StudioToolbar() {
1454
1890
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1455
1891
  "button",
1456
1892
  {
1457
- css: styles3.btn,
1893
+ css: styles4.btn,
1458
1894
  onClick: handleSyncCdn,
1459
- disabled: !hasSelection,
1895
+ disabled: !hasSelection || syncing,
1460
1896
  children: [
1461
1897
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, CloudIcon, {}),
1462
- "Sync CDN"
1898
+ syncing ? "Syncing..." : "Sync CDN"
1463
1899
  ]
1464
1900
  }
1465
1901
  ),
1466
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.searchWrapper, children: [
1902
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.searchWrapper, children: [
1467
1903
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1468
1904
  "input",
1469
1905
  {
1470
- css: styles3.searchInput,
1906
+ css: styles4.searchInput,
1471
1907
  type: "text",
1472
1908
  placeholder: "Search images...",
1473
1909
  value: searchQuery,
@@ -1478,7 +1914,7 @@ function StudioToolbar() {
1478
1914
  searchQuery && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1479
1915
  "button",
1480
1916
  {
1481
- css: styles3.searchClearBtn,
1917
+ css: styles4.searchClearBtn,
1482
1918
  onClick: () => setSearchQuery(""),
1483
1919
  title: "Clear search",
1484
1920
  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 +1922,25 @@ function StudioToolbar() {
1486
1922
  )
1487
1923
  ] })
1488
1924
  ] }),
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: [
1925
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.right, children: [
1926
+ hasSelection && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles4.selectionCount, children: [
1491
1927
  selectedItems.size,
1492
1928
  " selected",
1493
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles3.clearBtn, onClick: clearSelection, children: "Clear" })
1929
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles4.clearBtn, onClick: clearSelection, children: "Clear" })
1494
1930
  ] }),
1495
1931
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1496
1932
  "button",
1497
1933
  {
1498
- css: [styles3.btn, styles3.btnIconOnly],
1934
+ css: [styles4.btn, styles4.btnIconOnly],
1499
1935
  onClick: handleRefresh,
1500
1936
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, RefreshIcon, { spinning: refreshing })
1501
1937
  }
1502
1938
  ),
1503
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.viewToggle, children: [
1939
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.viewToggle, children: [
1504
1940
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1505
1941
  "button",
1506
1942
  {
1507
- css: [styles3.viewBtn, viewMode === "grid" && styles3.viewBtnActive],
1943
+ css: [styles4.viewBtn, viewMode === "grid" && styles4.viewBtnActive],
1508
1944
  onClick: () => setViewMode("grid"),
1509
1945
  "aria-label": "Grid view",
1510
1946
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, GridIcon, {})
@@ -1513,7 +1949,7 @@ function StudioToolbar() {
1513
1949
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1514
1950
  "button",
1515
1951
  {
1516
- css: [styles3.viewBtn, viewMode === "list" && styles3.viewBtnActive],
1952
+ css: [styles4.viewBtn, viewMode === "list" && styles4.viewBtnActive],
1517
1953
  onClick: () => setViewMode("list"),
1518
1954
  "aria-label": "List view",
1519
1955
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ListIcon, {})
@@ -1525,34 +1961,34 @@ function StudioToolbar() {
1525
1961
  ] });
1526
1962
  }
1527
1963
  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" }) });
1964
+ 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
1965
  }
1530
1966
  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" }) });
1967
+ 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
1968
  }
1533
1969
  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" }) });
1970
+ 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
1971
  }
1536
1972
  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" }) });
1973
+ 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
1974
  }
1539
1975
  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" }) });
1976
+ 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
1977
  }
1542
1978
  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" }) });
1979
+ 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
1980
  }
1545
1981
  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" }) });
1982
+ 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
1983
  }
1548
1984
  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" }) });
1985
+ 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
1986
  }
1551
1987
  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" }) });
1988
+ 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
1989
  }
1554
1990
  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" }) });
1991
+ 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
1992
  }
1557
1993
 
1558
1994
  // src/components/StudioFileGrid.tsx
@@ -1750,7 +2186,7 @@ function useFileList() {
1750
2186
  var spin2 = _react3.keyframes`
1751
2187
  to { transform: rotate(360deg); }
1752
2188
  `;
1753
- var styles4 = {
2189
+ var styles5 = {
1754
2190
  loading: _react3.css`
1755
2191
  display: flex;
1756
2192
  align-items: center;
@@ -2083,22 +2519,22 @@ function StudioFileGrid() {
2083
2519
  handleSelectAll
2084
2520
  } = useFileList();
2085
2521
  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 }) });
2522
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.loading, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.spinner }) });
2087
2523
  }
2088
2524
  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" })
2525
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.empty, children: [
2526
+ /* @__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" }) }),
2527
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.emptyText, children: "No files in this folder" }),
2528
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.emptyText, children: "Upload images to get started" })
2093
2529
  ] });
2094
2530
  }
2095
2531
  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: [
2532
+ 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
2533
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2098
2534
  "input",
2099
2535
  {
2100
2536
  type: "checkbox",
2101
- css: styles4.selectAllCheckbox,
2537
+ css: styles5.selectAllCheckbox,
2102
2538
  checked: allItemsSelected,
2103
2539
  ref: (el) => {
2104
2540
  if (el) el.indeterminate = someItemsSelected && !allItemsSelected;
@@ -2110,17 +2546,17 @@ function StudioFileGrid() {
2110
2546
  sortedItems.length,
2111
2547
  ")"
2112
2548
  ] }) }),
2113
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.grid, children: [
2549
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.grid, children: [
2114
2550
  !isAtRoot && !isSearching && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2115
2551
  "div",
2116
2552
  {
2117
- css: [styles4.item, styles4.parentItem],
2553
+ css: [styles5.item, styles5.parentItem],
2118
2554
  onClick: navigateUp,
2119
2555
  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" })
2556
+ /* @__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" }) }) }),
2557
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.label, children: [
2558
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.name, children: ".." }),
2559
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.size, children: "Parent folder" })
2124
2560
  ] })
2125
2561
  ]
2126
2562
  }
@@ -2154,43 +2590,43 @@ function GridItem({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
2154
2590
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2155
2591
  "div",
2156
2592
  {
2157
- css: [styles4.item, isSelected && styles4.itemSelected],
2593
+ css: [styles5.item, isSelected && styles5.itemSelected],
2158
2594
  onClick,
2159
2595
  children: [
2160
2596
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2161
2597
  "div",
2162
2598
  {
2163
- css: styles4.checkboxWrapper,
2599
+ css: styles5.checkboxWrapper,
2164
2600
  onClick: (e) => e.stopPropagation(),
2165
2601
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2166
2602
  "input",
2167
2603
  {
2168
2604
  type: "checkbox",
2169
- css: styles4.checkbox,
2605
+ css: styles5.checkbox,
2170
2606
  checked: isSelected,
2171
2607
  onChange: () => onClick({})
2172
2608
  }
2173
2609
  )
2174
2610
  }
2175
2611
  ),
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: [
2612
+ item.cdnSynced && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles5.cdnBadge, children: "CDN" }),
2613
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.content, children: [
2178
2614
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2179
2615
  "button",
2180
2616
  {
2181
- css: styles4.copyBtn,
2617
+ css: styles5.copyBtn,
2182
2618
  onClick: handleCopyPath,
2183
2619
  title: "Copy file path",
2184
2620
  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" }) })
2621
+ showCopied && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles5.tooltip, children: "Copied!" }),
2622
+ /* @__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
2623
  ]
2188
2624
  }
2189
2625
  ),
2190
2626
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2191
2627
  "button",
2192
2628
  {
2193
- css: styles4.openBtn,
2629
+ css: styles5.openBtn,
2194
2630
  onClick: (e) => {
2195
2631
  e.stopPropagation();
2196
2632
  onOpen();
@@ -2198,13 +2634,13 @@ function GridItem({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
2198
2634
  children: "Open"
2199
2635
  }
2200
2636
  ),
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,
2637
+ isFolder ? isImagesFolder ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.imagesFolderWrapper, children: [
2638
+ /* @__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" }) }),
2639
+ /* @__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" }) })
2640
+ ] }) : /* @__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
2641
  "img",
2206
2642
  {
2207
- css: styles4.image,
2643
+ css: styles5.image,
2208
2644
  src: item.thumbnail,
2209
2645
  alt: item.name,
2210
2646
  loading: "lazy"
@@ -2212,26 +2648,26 @@ function GridItem({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
2212
2648
  ) : isImage && !item.hasThumbnail ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2213
2649
  "button",
2214
2650
  {
2215
- css: styles4.noThumbnail,
2651
+ css: styles5.noThumbnail,
2216
2652
  onClick: (e) => {
2217
2653
  e.stopPropagation();
2218
2654
  onGenerateThumbnail();
2219
2655
  },
2220
2656
  title: "Generate thumbnail",
2221
2657
  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" })
2658
+ /* @__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" }) }),
2659
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles5.noThumbnailText, children: "Generate" })
2224
2660
  ]
2225
2661
  }
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" }) })
2662
+ ) : /* @__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
2663
  ] }),
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: [
2664
+ /* @__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: [
2665
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.name, title: item.name, children: truncateMiddle(item.name) }),
2666
+ isFolder ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { css: styles5.size, children: [
2231
2667
  item.fileCount !== void 0 ? `${item.fileCount} files` : "",
2232
2668
  item.fileCount !== void 0 && item.totalSize !== void 0 ? " \xB7 " : "",
2233
2669
  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) })
2670
+ ] }) : item.size !== void 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.size, children: formatFileSize(item.size) })
2235
2671
  ] }) }) })
2236
2672
  ]
2237
2673
  }
@@ -2263,7 +2699,7 @@ function truncateMiddle(str, maxLength = 24) {
2263
2699
  var spin3 = _react3.keyframes`
2264
2700
  to { transform: rotate(360deg); }
2265
2701
  `;
2266
- var styles5 = {
2702
+ var styles6 = {
2267
2703
  loading: _react3.css`
2268
2704
  display: flex;
2269
2705
  align-items: center;
@@ -2584,18 +3020,18 @@ function StudioFileList() {
2584
3020
  handleSelectAll
2585
3021
  } = useFileList();
2586
3022
  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 }) });
3023
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.loading, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.spinner }) });
2588
3024
  }
2589
3025
  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" }) });
3026
+ 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
3027
  }
2592
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.tableWrapper, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "table", { css: styles5.table, children: [
3028
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.tableWrapper, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "table", { css: styles6.table, children: [
2593
3029
  /* @__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,
3030
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles6.th, styles6.thCheckbox], children: sortedItems.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2595
3031
  "input",
2596
3032
  {
2597
3033
  type: "checkbox",
2598
- css: styles5.checkbox,
3034
+ css: styles6.checkbox,
2599
3035
  checked: allItemsSelected,
2600
3036
  ref: (el) => {
2601
3037
  if (el) el.indeterminate = someItemsSelected && !allItemsSelected;
@@ -2603,21 +3039,21 @@ function StudioFileList() {
2603
3039
  onChange: handleSelectAll
2604
3040
  }
2605
3041
  ) }),
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" })
3042
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: styles6.th, children: "Name" }),
3043
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles6.th, styles6.thSize], children: "Size" }),
3044
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles6.th, styles6.thDimensions], children: "Dimensions" }),
3045
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles6.th, styles6.thCdn], children: "CDN" })
2610
3046
  ] }) }),
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: ".." })
3047
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tbody", { css: styles6.tbody, children: [
3048
+ !isAtRoot && !isSearching && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tr", { css: styles6.parentRow, onClick: navigateUp, children: [
3049
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles6.td }),
3050
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles6.td, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.nameCell, children: [
3051
+ /* @__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" }) }),
3052
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles6.name, children: ".." })
2617
3053
  ] }) }),
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: "--" })
3054
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles6.td, styles6.meta], children: "--" }),
3055
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles6.td, styles6.meta], children: "Parent folder" }),
3056
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles6.td, children: "--" })
2621
3057
  ] }),
2622
3058
  sortedItems.map((item) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2623
3059
  ListRow,
@@ -2648,59 +3084,59 @@ function ListRow({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
2648
3084
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2649
3085
  "tr",
2650
3086
  {
2651
- css: [styles5.row, isSelected && styles5.rowSelected],
3087
+ css: [styles6.row, isSelected && styles6.rowSelected],
2652
3088
  onClick,
2653
3089
  children: [
2654
3090
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2655
3091
  "td",
2656
3092
  {
2657
- css: [styles5.td, styles5.checkboxCell],
3093
+ css: [styles6.td, styles6.checkboxCell],
2658
3094
  onClick: (e) => e.stopPropagation(),
2659
3095
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2660
3096
  "input",
2661
3097
  {
2662
3098
  type: "checkbox",
2663
- css: styles5.checkbox,
3099
+ css: styles6.checkbox,
2664
3100
  checked: isSelected,
2665
3101
  onChange: () => onClick({})
2666
3102
  }
2667
3103
  )
2668
3104
  }
2669
3105
  ),
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,
3106
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles6.td, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.nameCell, children: [
3107
+ isFolder ? isImagesFolder ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.imagesFolderWrapper, children: [
3108
+ /* @__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" }) }),
3109
+ /* @__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" }) })
3110
+ ] }) : /* @__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
3111
  "button",
2676
3112
  {
2677
- css: styles5.noThumbnail,
3113
+ css: styles6.noThumbnail,
2678
3114
  onClick: (e) => {
2679
3115
  e.stopPropagation();
2680
3116
  onGenerateThumbnail();
2681
3117
  },
2682
3118
  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" }) })
3119
+ 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
3120
  }
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: [
3121
+ ) }) : /* @__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" }) }) }),
3122
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles6.name, title: item.name, children: truncateMiddle2(item.name) }),
3123
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.actionsCell, children: [
2688
3124
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2689
3125
  "button",
2690
3126
  {
2691
- css: styles5.copyBtn,
3127
+ css: styles6.copyBtn,
2692
3128
  onClick: handleCopyPath,
2693
3129
  title: "Copy file path",
2694
3130
  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" }) })
3131
+ showCopied && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles6.tooltip, children: "Copied!" }),
3132
+ /* @__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
3133
  ]
2698
3134
  }
2699
3135
  ),
2700
3136
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2701
3137
  "button",
2702
3138
  {
2703
- css: styles5.openBtn,
3139
+ css: styles6.openBtn,
2704
3140
  onClick: (e) => {
2705
3141
  e.stopPropagation();
2706
3142
  onOpen();
@@ -2710,12 +3146,12 @@ function ListRow({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
2710
3146
  )
2711
3147
  ] })
2712
3148
  ] }) }),
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" }) }),
3149
+ /* @__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) : "--" }),
3150
+ /* @__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}` : "--" }),
3151
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles6.td, children: item.cdnSynced ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles6.cdnBadge, children: [
3152
+ /* @__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
3153
  "Synced"
2718
- ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles5.cdnEmpty, children: "--" }) })
3154
+ ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles6.cdnEmpty, children: "--" }) })
2719
3155
  ]
2720
3156
  }
2721
3157
  );
@@ -2753,7 +3189,7 @@ function isVideoFile(filename) {
2753
3189
  const ext = filename.toLowerCase().substring(filename.lastIndexOf("."));
2754
3190
  return VIDEO_EXTENSIONS.includes(ext);
2755
3191
  }
2756
- var styles6 = {
3192
+ var styles7 = {
2757
3193
  overlay: _react3.css`
2758
3194
  position: absolute;
2759
3195
  top: 0;
@@ -3004,9 +3440,11 @@ function StudioDetailView() {
3004
3440
  const [showDeleteConfirm, setShowDeleteConfirm] = _react.useState.call(void 0, false);
3005
3441
  const [showRenameModal, setShowRenameModal] = _react.useState.call(void 0, false);
3006
3442
  const [showProcessConfirm, setShowProcessConfirm] = _react.useState.call(void 0, false);
3443
+ const [showR2SetupModal, setShowR2SetupModal] = _react.useState.call(void 0, false);
3007
3444
  const [processProgress, setProcessProgress] = _react.useState.call(void 0, null);
3008
3445
  const [alertMessage, setAlertMessage] = _react.useState.call(void 0, null);
3009
3446
  const [showCopied, setShowCopied] = _react.useState.call(void 0, false);
3447
+ const [syncing, setSyncing] = _react.useState.call(void 0, false);
3010
3448
  if (!focusedItem) return null;
3011
3449
  const isImage = isImageFile(focusedItem.name);
3012
3450
  const isVideo = isVideoFile(focusedItem.name);
@@ -3078,8 +3516,41 @@ function StudioDetailView() {
3078
3516
  });
3079
3517
  }
3080
3518
  };
3081
- const handleSync = () => {
3082
- console.log("Sync to CDN:", focusedItem.path);
3519
+ const handleSync = async () => {
3520
+ const imageKey = "/" + focusedItem.path.replace(/^public\//, "");
3521
+ setSyncing(true);
3522
+ try {
3523
+ const response = await fetch("/api/studio/sync", {
3524
+ method: "POST",
3525
+ headers: { "Content-Type": "application/json" },
3526
+ body: JSON.stringify({ imageKeys: [imageKey] })
3527
+ });
3528
+ const data = await response.json();
3529
+ if (response.ok) {
3530
+ setAlertMessage({
3531
+ title: "Sync Complete",
3532
+ message: "Successfully synced to CDN."
3533
+ });
3534
+ triggerRefresh();
3535
+ } else {
3536
+ 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")])) {
3537
+ setShowR2SetupModal(true);
3538
+ } else {
3539
+ setAlertMessage({
3540
+ title: "Sync Failed",
3541
+ message: data.error || "Failed to sync to CDN."
3542
+ });
3543
+ }
3544
+ }
3545
+ } catch (error) {
3546
+ console.error("Sync error:", error);
3547
+ setAlertMessage({
3548
+ title: "Sync Failed",
3549
+ message: "Failed to sync to CDN. Check console for details."
3550
+ });
3551
+ } finally {
3552
+ setSyncing(false);
3553
+ }
3083
3554
  };
3084
3555
  const handleProcessImage = async () => {
3085
3556
  setShowProcessConfirm(false);
@@ -3101,7 +3572,7 @@ function StudioDetailView() {
3101
3572
  if (!response.ok) {
3102
3573
  throw new Error("Processing failed");
3103
3574
  }
3104
- const reader = _optionalChain([response, 'access', _19 => _19.body, 'optionalAccess', _20 => _20.getReader, 'call', _21 => _21()]);
3575
+ const reader = _optionalChain([response, 'access', _35 => _35.body, 'optionalAccess', _36 => _36.getReader, 'call', _37 => _37()]);
3105
3576
  if (!reader) {
3106
3577
  throw new Error("No response body");
3107
3578
  }
@@ -3137,14 +3608,14 @@ function StudioDetailView() {
3137
3608
  };
3138
3609
  const renderMedia = () => {
3139
3610
  if (isImage) {
3140
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { css: styles6.image, src: imageSrc, alt: focusedItem.name });
3611
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { css: styles7.image, src: imageSrc, alt: focusedItem.name });
3141
3612
  }
3142
3613
  if (isVideo) {
3143
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "video", { css: styles6.video, src: imageSrc, controls: true });
3614
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "video", { css: styles7.video, src: imageSrc, controls: true });
3144
3615
  }
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 })
3616
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.filePlaceholder, children: [
3617
+ /* @__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" }) }),
3618
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles7.fileName, children: focusedItem.name })
3148
3619
  ] });
3149
3620
  };
3150
3621
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
@@ -3167,6 +3638,13 @@ function StudioDetailView() {
3167
3638
  onClose: () => setAlertMessage(null)
3168
3639
  }
3169
3640
  ),
3641
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3642
+ R2SetupModal,
3643
+ {
3644
+ isOpen: showR2SetupModal,
3645
+ onClose: () => setShowR2SetupModal(false)
3646
+ }
3647
+ ),
3170
3648
  showRenameModal && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3171
3649
  InputModal,
3172
3650
  {
@@ -3197,61 +3675,61 @@ function StudioDetailView() {
3197
3675
  onClose: () => setProcessProgress(null)
3198
3676
  }
3199
3677
  ),
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" }) })
3678
+ /* @__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: [
3679
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.main, children: [
3680
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.headerButtons, children: [
3681
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles7.copyBtn, onClick: handleCopyPath, title: "Copy file path", children: [
3682
+ showCopied && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.tooltip, children: "Copied!" }),
3683
+ /* @__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
3684
  ] }),
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" }) }) })
3685
+ /* @__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
3686
  ] }),
3209
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.mediaWrapper, children: renderMedia() })
3687
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles7.mediaWrapper, children: renderMedia() })
3210
3688
  ] }),
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 })
3689
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.sidebar, children: [
3690
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles7.sidebarHeader, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles7.sidebarTitle, children: "Details" }) }),
3691
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.sidebarContent, children: [
3692
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.info, children: [
3693
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.infoRow, children: [
3694
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoLabel, children: "Name" }),
3695
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoValueWrap, children: focusedItem.name })
3218
3696
  ] }),
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\//, "") })
3697
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.infoRow, children: [
3698
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoLabel, children: "Path" }),
3699
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoValueWrap, children: focusedItem.path.replace(/^public\//, "") })
3222
3700
  ] }),
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) })
3701
+ focusedItem.size !== void 0 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.infoRow, children: [
3702
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoLabel, children: "Size" }),
3703
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoValue, children: formatFileSize3(focusedItem.size) })
3226
3704
  ] }),
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: [
3705
+ focusedItem.dimensions && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.infoRow, children: [
3706
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoLabel, children: "Dimensions" }),
3707
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles7.infoValue, children: [
3230
3708
  focusedItem.dimensions.width,
3231
3709
  " \xD7 ",
3232
3710
  focusedItem.dimensions.height
3233
3711
  ] })
3234
3712
  ] }),
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" })
3713
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.infoRow, children: [
3714
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoLabel, children: "CDN Status" }),
3715
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoValue, children: focusedItem.cdnSynced ? "Synced" : "Not synced" })
3238
3716
  ] })
3239
3717
  ] }),
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" }) }),
3718
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.actions, children: [
3719
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles7.actionBtn, onClick: () => setShowRenameModal(true), children: [
3720
+ /* @__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
3721
  "Rename"
3244
3722
  ] }),
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"
3723
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles7.actionBtn, onClick: handleSync, disabled: syncing, children: [
3724
+ /* @__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" }) }),
3725
+ syncing ? "Syncing..." : "Sync to CDN"
3248
3726
  ] }),
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" }) }),
3727
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles7.actionBtn, onClick: () => setShowProcessConfirm(true), children: [
3728
+ /* @__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
3729
  "Process Image"
3252
3730
  ] }),
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" }) }),
3731
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: [styles7.actionBtn, styles7.actionBtnDanger], onClick: () => setShowDeleteConfirm(true), children: [
3732
+ /* @__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
3733
  "Delete"
3256
3734
  ] })
3257
3735
  ] })
@@ -3271,7 +3749,7 @@ function formatFileSize3(bytes) {
3271
3749
 
3272
3750
 
3273
3751
  var btnHeight2 = "36px";
3274
- var styles7 = {
3752
+ var styles8 = {
3275
3753
  btn: _react3.css`
3276
3754
  height: ${btnHeight2};
3277
3755
  padding: 0 12px;
@@ -3509,10 +3987,10 @@ var styles7 = {
3509
3987
  function StudioSettings() {
3510
3988
  const [isOpen, setIsOpen] = _react.useState.call(void 0, false);
3511
3989
  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,
3990
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles8.btn, onClick: () => setIsOpen(true), "aria-label": "Settings", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
3513
3991
  "svg",
3514
3992
  {
3515
- css: styles7.icon,
3993
+ css: styles8.icon,
3516
3994
  xmlns: "http://www.w3.org/2000/svg",
3517
3995
  viewBox: "0 0 24 24",
3518
3996
  fill: "none",
@@ -3541,50 +4019,50 @@ function SettingsPanel({ onClose }) {
3541
4019
  setCopied(true);
3542
4020
  setTimeout(() => setCopied(false), 2e3);
3543
4021
  };
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" }) }) })
4022
+ 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: [
4023
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.header, children: [
4024
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { css: styles8.title, children: "Settings" }),
4025
+ /* @__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
4026
  ] }),
3549
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.sections, children: [
4027
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.sections, children: [
3550
4028
  /* @__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" }) })
4029
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles8.sectionTitle, children: "Cloudflare R2" }),
4030
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles8.description, children: "Configure in .env.local file:" }),
4031
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.codeWrapper, children: [
4032
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles8.copyBtn, onClick: handleCopy, title: "Copy to clipboard", children: [
4033
+ copied && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles8.tooltip, children: "Copied!" }),
4034
+ /* @__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
4035
  ] }),
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" })
4036
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.code, children: [
4037
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles8.codeLine, children: "CLOUDFLARE_R2_ACCOUNT_ID=abc123def456ghi789" }),
4038
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles8.codeLine, children: "CLOUDFLARE_R2_ACCESS_KEY_ID=your_access_key_id_here" }),
4039
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles8.codeLine, children: "CLOUDFLARE_R2_SECRET_ACCESS_KEY=your_secret_access_key_here" }),
4040
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles8.codeLine, children: "CLOUDFLARE_R2_BUCKET_NAME=my-images-bucket" }),
4041
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles8.codeLine, children: "CLOUDFLARE_R2_PUBLIC_URL=https://cdn.yourdomain.com" })
3564
4042
  ] })
3565
4043
  ] })
3566
4044
  ] }),
3567
4045
  /* @__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: [
4046
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles8.sectionTitle, children: "Thumbnail Sizes" }),
4047
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.grid, children: [
3570
4048
  /* @__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 })
4049
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css: styles8.label, children: "Small" }),
4050
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles8.input, type: "number", defaultValue: 300 })
3573
4051
  ] }),
3574
4052
  /* @__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 })
4053
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css: styles8.label, children: "Medium" }),
4054
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles8.input, type: "number", defaultValue: 700 })
3577
4055
  ] }),
3578
4056
  /* @__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 })
4057
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css: styles8.label, children: "Large" }),
4058
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles8.input, type: "number", defaultValue: 1400 })
3581
4059
  ] })
3582
4060
  ] })
3583
4061
  ] })
3584
4062
  ] }),
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" })
4063
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.footer, children: [
4064
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles8.cancelBtn, onClick: onClose, children: "Cancel" }),
4065
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles8.saveBtn, children: "Save Changes" })
3588
4066
  ] })
3589
4067
  ] }) });
3590
4068
  }
@@ -3592,7 +4070,7 @@ function SettingsPanel({ onClose }) {
3592
4070
  // src/components/ErrorModal.tsx
3593
4071
 
3594
4072
 
3595
- var styles8 = {
4073
+ var styles9 = {
3596
4074
  overlay: _react3.css`
3597
4075
  position: fixed;
3598
4076
  inset: 0;
@@ -3654,20 +4132,20 @@ var styles8 = {
3654
4132
  function ErrorModal() {
3655
4133
  const { error, clearError } = useStudio();
3656
4134
  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 })
4135
+ 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: [
4136
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles9.header, children: [
4137
+ /* @__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" }) }),
4138
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles9.title, children: error.title })
3661
4139
  ] }),
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" })
4140
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles9.message, children: error.message }),
4141
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles9.button, onClick: clearError, children: "OK" })
3664
4142
  ] }) });
3665
4143
  }
3666
4144
 
3667
4145
  // src/components/StudioUI.tsx
3668
4146
 
3669
4147
  var btnHeight3 = "36px";
3670
- var styles9 = {
4148
+ var styles10 = {
3671
4149
  container: _react3.css`
3672
4150
  ${_chunkUFCWGUAGjs.baseReset}
3673
4151
  display: flex;
@@ -3961,16 +4439,16 @@ function StudioUI({ onClose, isVisible = true }) {
3961
4439
  showError,
3962
4440
  clearError
3963
4441
  };
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: [
4442
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioContext.Provider, { value: contextValue, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles10.container, children: [
4443
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles10.header, children: [
4444
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles10.headerLeft, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h1", { css: styles10.title, children: "Studio" }) }),
4445
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles10.headerCenter, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Breadcrumbs, { currentPath, onNavigate: setCurrentPath }) }),
4446
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles10.headerActions, children: [
3969
4447
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioSettings, {}),
3970
4448
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3971
4449
  "button",
3972
4450
  {
3973
- css: styles9.headerBtn,
4451
+ css: styles10.headerBtn,
3974
4452
  onClick: onClose,
3975
4453
  "aria-label": "Close Studio",
3976
4454
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, CloseIcon, {})
@@ -3982,16 +4460,16 @@ function StudioUI({ onClose, isVisible = true }) {
3982
4460
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
3983
4461
  "div",
3984
4462
  {
3985
- css: styles9.content,
4463
+ css: styles10.content,
3986
4464
  onDragOver: handleDragOver,
3987
4465
  onDragLeave: handleDragLeave,
3988
4466
  onDrop: handleDrop,
3989
4467
  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" }) }),
4468
+ isDragging && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles10.dropOverlay, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles10.dropMessage, children: [
4469
+ /* @__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
4470
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: "Drop files to upload" })
3993
4471
  ] }) }),
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, {}) })
4472
+ /* @__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
4473
  ]
3996
4474
  }
3997
4475
  ),
@@ -4005,12 +4483,12 @@ function Breadcrumbs({ currentPath, onNavigate }) {
4005
4483
  name: part,
4006
4484
  path: parts.slice(0, index + 1).join("/")
4007
4485
  }));
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,
4486
+ 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: [
4487
+ index > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles10.breadcrumbSeparator, children: "/" }),
4488
+ index === breadcrumbs.length - 1 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles10.breadcrumbCurrent, children: crumb.name }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
4011
4489
  "span",
4012
4490
  {
4013
- css: styles9.breadcrumbItem,
4491
+ css: styles10.breadcrumbItem,
4014
4492
  onClick: () => onNavigate(crumb.path),
4015
4493
  children: crumb.name
4016
4494
  }
@@ -4021,7 +4499,7 @@ function CloseIcon() {
4021
4499
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
4022
4500
  "svg",
4023
4501
  {
4024
- css: styles9.headerIcon,
4502
+ css: styles10.headerIcon,
4025
4503
  xmlns: "http://www.w3.org/2000/svg",
4026
4504
  viewBox: "0 0 24 24",
4027
4505
  fill: "none",
@@ -4041,4 +4519,4 @@ var StudioUI_default = StudioUI;
4041
4519
 
4042
4520
 
4043
4521
  exports.StudioUI = StudioUI; exports.default = StudioUI_default;
4044
- //# sourceMappingURL=StudioUI-YFDO5MGG.js.map
4522
+ //# sourceMappingURL=StudioUI-VNSW7JUI.js.map