@gallop.software/studio 0.1.81 → 0.1.83
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{StudioUI-RH4ZXWKP.js → StudioUI-MVIOZTZH.js} +922 -354
- package/dist/StudioUI-MVIOZTZH.js.map +1 -0
- package/dist/{StudioUI-SS3YMS53.mjs → StudioUI-XV7HCEAF.mjs} +1231 -663
- package/dist/StudioUI-XV7HCEAF.mjs.map +1 -0
- package/dist/{handlers.d.ts → handlers/index.d.mts} +1 -1
- package/dist/{handlers.d.mts → handlers/index.d.ts} +1 -1
- package/dist/{handlers.js → handlers/index.js} +611 -579
- package/dist/handlers/index.js.map +1 -0
- package/dist/{handlers.mjs → handlers/index.mjs} +620 -588
- package/dist/handlers/index.mjs.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +4 -4
- package/dist/StudioUI-RH4ZXWKP.js.map +0 -1
- package/dist/StudioUI-SS3YMS53.mjs.map +0 -1
- package/dist/handlers.js.map +0 -1
- package/dist/handlers.mjs.map +0 -1
|
@@ -52,6 +52,11 @@ var defaultState = {
|
|
|
52
52
|
},
|
|
53
53
|
searchQuery: "",
|
|
54
54
|
setSearchQuery: () => {
|
|
55
|
+
},
|
|
56
|
+
error: null,
|
|
57
|
+
showError: () => {
|
|
58
|
+
},
|
|
59
|
+
clearError: () => {
|
|
55
60
|
}
|
|
56
61
|
};
|
|
57
62
|
var StudioContext = _react.createContext.call(void 0, defaultState);
|
|
@@ -669,13 +674,312 @@ function StudioFolderPicker({ selectedItems, currentPath, onMove, onCancel }) {
|
|
|
669
674
|
] }) });
|
|
670
675
|
}
|
|
671
676
|
|
|
677
|
+
// src/components/R2SetupModal.tsx
|
|
678
|
+
|
|
679
|
+
|
|
680
|
+
var styles3 = {
|
|
681
|
+
overlay: _react3.css`
|
|
682
|
+
position: fixed;
|
|
683
|
+
inset: 0;
|
|
684
|
+
background: rgba(0, 0, 0, 0.6);
|
|
685
|
+
display: flex;
|
|
686
|
+
align-items: center;
|
|
687
|
+
justify-content: center;
|
|
688
|
+
z-index: 1100;
|
|
689
|
+
padding: 20px;
|
|
690
|
+
`,
|
|
691
|
+
modal: _react3.css`
|
|
692
|
+
background: ${_chunkUFCWGUAGjs.colors.surface};
|
|
693
|
+
border-radius: 12px;
|
|
694
|
+
max-width: 560px;
|
|
695
|
+
width: 100%;
|
|
696
|
+
max-height: 90vh;
|
|
697
|
+
overflow-y: auto;
|
|
698
|
+
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
|
|
699
|
+
`,
|
|
700
|
+
header: _react3.css`
|
|
701
|
+
display: flex;
|
|
702
|
+
align-items: center;
|
|
703
|
+
gap: 12px;
|
|
704
|
+
padding: 20px 24px;
|
|
705
|
+
border-bottom: 1px solid ${_chunkUFCWGUAGjs.colors.border};
|
|
706
|
+
`,
|
|
707
|
+
icon: _react3.css`
|
|
708
|
+
width: 32px;
|
|
709
|
+
height: 32px;
|
|
710
|
+
color: ${_chunkUFCWGUAGjs.colors.primary};
|
|
711
|
+
flex-shrink: 0;
|
|
712
|
+
`,
|
|
713
|
+
title: _react3.css`
|
|
714
|
+
font-size: ${_chunkUFCWGUAGjs.fontSize.xl};
|
|
715
|
+
font-weight: 600;
|
|
716
|
+
color: ${_chunkUFCWGUAGjs.colors.text};
|
|
717
|
+
margin: 0;
|
|
718
|
+
`,
|
|
719
|
+
closeBtn: _react3.css`
|
|
720
|
+
margin-left: auto;
|
|
721
|
+
background: none;
|
|
722
|
+
border: none;
|
|
723
|
+
padding: 4px;
|
|
724
|
+
cursor: pointer;
|
|
725
|
+
color: ${_chunkUFCWGUAGjs.colors.textMuted};
|
|
726
|
+
border-radius: 4px;
|
|
727
|
+
|
|
728
|
+
&:hover {
|
|
729
|
+
color: ${_chunkUFCWGUAGjs.colors.text};
|
|
730
|
+
background: ${_chunkUFCWGUAGjs.colors.surfaceHover};
|
|
731
|
+
}
|
|
732
|
+
`,
|
|
733
|
+
closeIcon: _react3.css`
|
|
734
|
+
width: 20px;
|
|
735
|
+
height: 20px;
|
|
736
|
+
`,
|
|
737
|
+
content: _react3.css`
|
|
738
|
+
padding: 24px;
|
|
739
|
+
`,
|
|
740
|
+
intro: _react3.css`
|
|
741
|
+
font-size: ${_chunkUFCWGUAGjs.fontSize.base};
|
|
742
|
+
color: ${_chunkUFCWGUAGjs.colors.textSecondary};
|
|
743
|
+
margin: 0 0 20px 0;
|
|
744
|
+
line-height: 1.6;
|
|
745
|
+
`,
|
|
746
|
+
steps: _react3.css`
|
|
747
|
+
list-style: none;
|
|
748
|
+
padding: 0;
|
|
749
|
+
margin: 0;
|
|
750
|
+
display: flex;
|
|
751
|
+
flex-direction: column;
|
|
752
|
+
gap: 16px;
|
|
753
|
+
`,
|
|
754
|
+
step: _react3.css`
|
|
755
|
+
display: flex;
|
|
756
|
+
gap: 12px;
|
|
757
|
+
`,
|
|
758
|
+
stepNumber: _react3.css`
|
|
759
|
+
width: 28px;
|
|
760
|
+
height: 28px;
|
|
761
|
+
border-radius: 50%;
|
|
762
|
+
background: ${_chunkUFCWGUAGjs.colors.primaryLight};
|
|
763
|
+
color: ${_chunkUFCWGUAGjs.colors.primary};
|
|
764
|
+
font-size: ${_chunkUFCWGUAGjs.fontSize.sm};
|
|
765
|
+
font-weight: 600;
|
|
766
|
+
display: flex;
|
|
767
|
+
align-items: center;
|
|
768
|
+
justify-content: center;
|
|
769
|
+
flex-shrink: 0;
|
|
770
|
+
`,
|
|
771
|
+
stepContent: _react3.css`
|
|
772
|
+
flex: 1;
|
|
773
|
+
padding-top: 3px;
|
|
774
|
+
`,
|
|
775
|
+
stepTitle: _react3.css`
|
|
776
|
+
font-size: ${_chunkUFCWGUAGjs.fontSize.base};
|
|
777
|
+
font-weight: 500;
|
|
778
|
+
color: ${_chunkUFCWGUAGjs.colors.text};
|
|
779
|
+
margin: 0 0 4px 0;
|
|
780
|
+
`,
|
|
781
|
+
stepDesc: _react3.css`
|
|
782
|
+
font-size: ${_chunkUFCWGUAGjs.fontSize.sm};
|
|
783
|
+
color: ${_chunkUFCWGUAGjs.colors.textSecondary};
|
|
784
|
+
margin: 0;
|
|
785
|
+
line-height: 1.5;
|
|
786
|
+
`,
|
|
787
|
+
link: _react3.css`
|
|
788
|
+
color: ${_chunkUFCWGUAGjs.colors.primary};
|
|
789
|
+
text-decoration: none;
|
|
790
|
+
font-weight: 500;
|
|
791
|
+
|
|
792
|
+
&:hover {
|
|
793
|
+
text-decoration: underline;
|
|
794
|
+
}
|
|
795
|
+
`,
|
|
796
|
+
envVars: _react3.css`
|
|
797
|
+
background: ${_chunkUFCWGUAGjs.colors.background};
|
|
798
|
+
border: 1px solid ${_chunkUFCWGUAGjs.colors.border};
|
|
799
|
+
border-radius: 8px;
|
|
800
|
+
padding: 16px;
|
|
801
|
+
margin-top: 20px;
|
|
802
|
+
font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;
|
|
803
|
+
font-size: 13px;
|
|
804
|
+
line-height: 1.8;
|
|
805
|
+
color: ${_chunkUFCWGUAGjs.colors.text};
|
|
806
|
+
overflow-x: auto;
|
|
807
|
+
`,
|
|
808
|
+
envVar: _react3.css`
|
|
809
|
+
display: block;
|
|
810
|
+
`,
|
|
811
|
+
envKey: _react3.css`
|
|
812
|
+
color: ${_chunkUFCWGUAGjs.colors.primary};
|
|
813
|
+
`,
|
|
814
|
+
envValue: _react3.css`
|
|
815
|
+
color: ${_chunkUFCWGUAGjs.colors.textSecondary};
|
|
816
|
+
`,
|
|
817
|
+
footer: _react3.css`
|
|
818
|
+
padding: 16px 24px;
|
|
819
|
+
border-top: 1px solid ${_chunkUFCWGUAGjs.colors.border};
|
|
820
|
+
display: flex;
|
|
821
|
+
justify-content: flex-end;
|
|
822
|
+
gap: 12px;
|
|
823
|
+
`,
|
|
824
|
+
docsBtn: _react3.css`
|
|
825
|
+
padding: 10px 16px;
|
|
826
|
+
border-radius: 6px;
|
|
827
|
+
font-size: ${_chunkUFCWGUAGjs.fontSize.base};
|
|
828
|
+
font-weight: 500;
|
|
829
|
+
border: 1px solid ${_chunkUFCWGUAGjs.colors.border};
|
|
830
|
+
background: ${_chunkUFCWGUAGjs.colors.surface};
|
|
831
|
+
color: ${_chunkUFCWGUAGjs.colors.text};
|
|
832
|
+
cursor: pointer;
|
|
833
|
+
text-decoration: none;
|
|
834
|
+
display: inline-flex;
|
|
835
|
+
align-items: center;
|
|
836
|
+
gap: 6px;
|
|
837
|
+
transition: all 0.15s ease;
|
|
838
|
+
|
|
839
|
+
&:hover {
|
|
840
|
+
background: ${_chunkUFCWGUAGjs.colors.surfaceHover};
|
|
841
|
+
border-color: #d0d5dd;
|
|
842
|
+
}
|
|
843
|
+
`,
|
|
844
|
+
doneBtn: _react3.css`
|
|
845
|
+
padding: 10px 20px;
|
|
846
|
+
border-radius: 6px;
|
|
847
|
+
font-size: ${_chunkUFCWGUAGjs.fontSize.base};
|
|
848
|
+
font-weight: 500;
|
|
849
|
+
border: none;
|
|
850
|
+
background: ${_chunkUFCWGUAGjs.colors.primary};
|
|
851
|
+
color: white;
|
|
852
|
+
cursor: pointer;
|
|
853
|
+
transition: background 0.15s ease;
|
|
854
|
+
|
|
855
|
+
&:hover {
|
|
856
|
+
background: ${_chunkUFCWGUAGjs.colors.primaryHover};
|
|
857
|
+
}
|
|
858
|
+
`,
|
|
859
|
+
externalIcon: _react3.css`
|
|
860
|
+
width: 14px;
|
|
861
|
+
height: 14px;
|
|
862
|
+
`
|
|
863
|
+
};
|
|
864
|
+
function R2SetupModal({ isOpen, onClose }) {
|
|
865
|
+
if (!isOpen) return null;
|
|
866
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles3.overlay, onClick: onClose, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.modal, onClick: (e) => e.stopPropagation(), children: [
|
|
867
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.header, children: [
|
|
868
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles3.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M3 15a4 4 0 004 4h9a5 5 0 10-.1-9.999 5.002 5.002 0 10-9.78 2.096A4.001 4.001 0 003 15z" }) }),
|
|
869
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { css: styles3.title, children: "Set Up CDN Storage" }),
|
|
870
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles3.closeBtn, onClick: onClose, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles3.closeIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })
|
|
871
|
+
] }),
|
|
872
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.content, children: [
|
|
873
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles3.intro, children: "Sync your images to Cloudflare R2 for faster global delivery. R2 offers generous free tier with no egress fees." }),
|
|
874
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "ol", { css: styles3.steps, children: [
|
|
875
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "li", { css: styles3.step, children: [
|
|
876
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.stepNumber, children: "1" }),
|
|
877
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.stepContent, children: [
|
|
878
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h4", { css: styles3.stepTitle, children: "Create a Cloudflare account" }),
|
|
879
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { css: styles3.stepDesc, children: [
|
|
880
|
+
"Sign up at",
|
|
881
|
+
" ",
|
|
882
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "a", { css: styles3.link, href: "https://dash.cloudflare.com/sign-up", target: "_blank", rel: "noopener noreferrer", children: "dash.cloudflare.com" }),
|
|
883
|
+
" ",
|
|
884
|
+
"if you don't have one already."
|
|
885
|
+
] })
|
|
886
|
+
] })
|
|
887
|
+
] }),
|
|
888
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "li", { css: styles3.step, children: [
|
|
889
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.stepNumber, children: "2" }),
|
|
890
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.stepContent, children: [
|
|
891
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h4", { css: styles3.stepTitle, children: "Create an R2 bucket" }),
|
|
892
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { css: styles3.stepDesc, children: [
|
|
893
|
+
"Go to R2 in your Cloudflare dashboard and create a new bucket. Choose a name like ",
|
|
894
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "code", { children: "my-images" }),
|
|
895
|
+
"."
|
|
896
|
+
] })
|
|
897
|
+
] })
|
|
898
|
+
] }),
|
|
899
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "li", { css: styles3.step, children: [
|
|
900
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.stepNumber, children: "3" }),
|
|
901
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.stepContent, children: [
|
|
902
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h4", { css: styles3.stepTitle, children: "Enable public access" }),
|
|
903
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { css: styles3.stepDesc, children: [
|
|
904
|
+
'In bucket settings, enable "Public Access" and copy the public URL (e.g., ',
|
|
905
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "code", { children: "https://pub-xxx.r2.dev" }),
|
|
906
|
+
")."
|
|
907
|
+
] })
|
|
908
|
+
] })
|
|
909
|
+
] }),
|
|
910
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "li", { css: styles3.step, children: [
|
|
911
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.stepNumber, children: "4" }),
|
|
912
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.stepContent, children: [
|
|
913
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h4", { css: styles3.stepTitle, children: "Create API token" }),
|
|
914
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles3.stepDesc, children: 'Go to R2 \u2192 Manage R2 API Tokens \u2192 Create API Token. Select "Object Read & Write" permissions for your bucket.' })
|
|
915
|
+
] })
|
|
916
|
+
] }),
|
|
917
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "li", { css: styles3.step, children: [
|
|
918
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.stepNumber, children: "5" }),
|
|
919
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.stepContent, children: [
|
|
920
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h4", { css: styles3.stepTitle, children: "Add environment variables" }),
|
|
921
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { css: styles3.stepDesc, children: [
|
|
922
|
+
"Add these to your ",
|
|
923
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "code", { children: ".env.local" }),
|
|
924
|
+
" file:"
|
|
925
|
+
] })
|
|
926
|
+
] })
|
|
927
|
+
] })
|
|
928
|
+
] }),
|
|
929
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.envVars, children: [
|
|
930
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles3.envVar, children: [
|
|
931
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.envKey, children: "CLOUDFLARE_R2_ACCOUNT_ID" }),
|
|
932
|
+
"=",
|
|
933
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.envValue, children: "your_account_id" })
|
|
934
|
+
] }),
|
|
935
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles3.envVar, children: [
|
|
936
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.envKey, children: "CLOUDFLARE_R2_ACCESS_KEY_ID" }),
|
|
937
|
+
"=",
|
|
938
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.envValue, children: "your_access_key" })
|
|
939
|
+
] }),
|
|
940
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles3.envVar, children: [
|
|
941
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.envKey, children: "CLOUDFLARE_R2_SECRET_ACCESS_KEY" }),
|
|
942
|
+
"=",
|
|
943
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.envValue, children: "your_secret_key" })
|
|
944
|
+
] }),
|
|
945
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles3.envVar, children: [
|
|
946
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.envKey, children: "CLOUDFLARE_R2_BUCKET_NAME" }),
|
|
947
|
+
"=",
|
|
948
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.envValue, children: "your_bucket_name" })
|
|
949
|
+
] }),
|
|
950
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles3.envVar, children: [
|
|
951
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.envKey, children: "CLOUDFLARE_R2_PUBLIC_URL" }),
|
|
952
|
+
"=",
|
|
953
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.envValue, children: "https://pub-xxx.r2.dev" })
|
|
954
|
+
] })
|
|
955
|
+
] })
|
|
956
|
+
] }),
|
|
957
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.footer, children: [
|
|
958
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
959
|
+
"a",
|
|
960
|
+
{
|
|
961
|
+
css: styles3.docsBtn,
|
|
962
|
+
href: "https://developers.cloudflare.com/r2/get-started/",
|
|
963
|
+
target: "_blank",
|
|
964
|
+
rel: "noopener noreferrer",
|
|
965
|
+
children: [
|
|
966
|
+
"R2 Documentation",
|
|
967
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles3.externalIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" }) })
|
|
968
|
+
]
|
|
969
|
+
}
|
|
970
|
+
),
|
|
971
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles3.doneBtn, onClick: onClose, children: "Got it" })
|
|
972
|
+
] })
|
|
973
|
+
] }) });
|
|
974
|
+
}
|
|
975
|
+
|
|
672
976
|
// src/components/StudioToolbar.tsx
|
|
673
977
|
|
|
674
978
|
var btnHeight = "36px";
|
|
675
979
|
var spin = _react3.keyframes`
|
|
676
980
|
to { transform: rotate(360deg); }
|
|
677
981
|
`;
|
|
678
|
-
var
|
|
982
|
+
var styles4 = {
|
|
679
983
|
toolbar: _react3.css`
|
|
680
984
|
display: flex;
|
|
681
985
|
flex-wrap: nowrap;
|
|
@@ -893,6 +1197,8 @@ function StudioToolbar() {
|
|
|
893
1197
|
const [showNewFolderModal, setShowNewFolderModal] = _react.useState.call(void 0, false);
|
|
894
1198
|
const [showRenameFolderModal, setShowRenameFolderModal] = _react.useState.call(void 0, false);
|
|
895
1199
|
const [showMoveModal, setShowMoveModal] = _react.useState.call(void 0, false);
|
|
1200
|
+
const [showR2SetupModal, setShowR2SetupModal] = _react.useState.call(void 0, false);
|
|
1201
|
+
const [syncing, setSyncing] = _react.useState.call(void 0, false);
|
|
896
1202
|
const isInImagesFolder = currentPath === "public/images" || currentPath.startsWith("public/images/");
|
|
897
1203
|
const handleUpload = _react.useCallback.call(void 0, () => {
|
|
898
1204
|
_optionalChain([fileInputRef, 'access', _2 => _2.current, 'optionalAccess', _3 => _3.click, 'call', _4 => _4()]);
|
|
@@ -1189,9 +1495,60 @@ function StudioToolbar() {
|
|
|
1189
1495
|
});
|
|
1190
1496
|
}
|
|
1191
1497
|
}, [selectedItems, clearSelection, triggerRefresh]);
|
|
1192
|
-
const handleSyncCdn = _react.useCallback.call(void 0, () => {
|
|
1193
|
-
|
|
1194
|
-
|
|
1498
|
+
const handleSyncCdn = _react.useCallback.call(void 0, async () => {
|
|
1499
|
+
if (selectedItems.size === 0) return;
|
|
1500
|
+
const imageKeys = Array.from(selectedItems).filter((p) => !p.endsWith("/")).map((p) => "/" + p.replace(/^public\//, ""));
|
|
1501
|
+
if (imageKeys.length === 0) {
|
|
1502
|
+
setAlertMessage({
|
|
1503
|
+
title: "No Images Selected",
|
|
1504
|
+
message: "Please select image files to sync to CDN."
|
|
1505
|
+
});
|
|
1506
|
+
return;
|
|
1507
|
+
}
|
|
1508
|
+
setSyncing(true);
|
|
1509
|
+
try {
|
|
1510
|
+
const response = await fetch("/api/studio/sync", {
|
|
1511
|
+
method: "POST",
|
|
1512
|
+
headers: { "Content-Type": "application/json" },
|
|
1513
|
+
body: JSON.stringify({ imageKeys })
|
|
1514
|
+
});
|
|
1515
|
+
const data = await response.json();
|
|
1516
|
+
if (response.ok) {
|
|
1517
|
+
const syncedCount = _optionalChain([data, 'access', _19 => _19.synced, 'optionalAccess', _20 => _20.length]) || 0;
|
|
1518
|
+
const errorCount = _optionalChain([data, 'access', _21 => _21.errors, 'optionalAccess', _22 => _22.length]) || 0;
|
|
1519
|
+
if (errorCount > 0) {
|
|
1520
|
+
setAlertMessage({
|
|
1521
|
+
title: "Sync Partially Complete",
|
|
1522
|
+
message: `Synced ${syncedCount} images. ${errorCount} failed.`
|
|
1523
|
+
});
|
|
1524
|
+
} else {
|
|
1525
|
+
setAlertMessage({
|
|
1526
|
+
title: "Sync Complete",
|
|
1527
|
+
message: `Successfully synced ${syncedCount} images to CDN.`
|
|
1528
|
+
});
|
|
1529
|
+
}
|
|
1530
|
+
clearSelection();
|
|
1531
|
+
triggerRefresh();
|
|
1532
|
+
} else {
|
|
1533
|
+
if (_optionalChain([data, 'access', _23 => _23.error, 'optionalAccess', _24 => _24.includes, 'call', _25 => _25("R2 not configured")]) || _optionalChain([data, 'access', _26 => _26.error, 'optionalAccess', _27 => _27.includes, 'call', _28 => _28("CLOUDFLARE_R2")])) {
|
|
1534
|
+
setShowR2SetupModal(true);
|
|
1535
|
+
} else {
|
|
1536
|
+
setAlertMessage({
|
|
1537
|
+
title: "Sync Failed",
|
|
1538
|
+
message: data.error || "Failed to sync to CDN."
|
|
1539
|
+
});
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
} catch (error) {
|
|
1543
|
+
console.error("Sync error:", error);
|
|
1544
|
+
setAlertMessage({
|
|
1545
|
+
title: "Sync Failed",
|
|
1546
|
+
message: "Failed to sync to CDN. Check console for details."
|
|
1547
|
+
});
|
|
1548
|
+
} finally {
|
|
1549
|
+
setSyncing(false);
|
|
1550
|
+
}
|
|
1551
|
+
}, [selectedItems, clearSelection, triggerRefresh]);
|
|
1195
1552
|
const handleCreateFolder = _react.useCallback.call(void 0, async (folderName) => {
|
|
1196
1553
|
setShowNewFolderModal(false);
|
|
1197
1554
|
try {
|
|
@@ -1370,7 +1727,14 @@ function StudioToolbar() {
|
|
|
1370
1727
|
onClose: () => setAlertMessage(null)
|
|
1371
1728
|
}
|
|
1372
1729
|
),
|
|
1373
|
-
/* @__PURE__ */ _jsxruntime.
|
|
1730
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1731
|
+
R2SetupModal,
|
|
1732
|
+
{
|
|
1733
|
+
isOpen: showR2SetupModal,
|
|
1734
|
+
onClose: () => setShowR2SetupModal(false)
|
|
1735
|
+
}
|
|
1736
|
+
),
|
|
1737
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.toolbar, children: [
|
|
1374
1738
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1375
1739
|
"input",
|
|
1376
1740
|
{
|
|
@@ -1382,11 +1746,11 @@ function StudioToolbar() {
|
|
|
1382
1746
|
style: { display: "none" }
|
|
1383
1747
|
}
|
|
1384
1748
|
),
|
|
1385
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
1749
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.left, children: [
|
|
1386
1750
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1387
1751
|
"button",
|
|
1388
1752
|
{
|
|
1389
|
-
css: [
|
|
1753
|
+
css: [styles4.btn, styles4.btnPrimary],
|
|
1390
1754
|
onClick: handleUpload,
|
|
1391
1755
|
disabled: uploading || isInImagesFolder,
|
|
1392
1756
|
children: [
|
|
@@ -1398,7 +1762,7 @@ function StudioToolbar() {
|
|
|
1398
1762
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1399
1763
|
"button",
|
|
1400
1764
|
{
|
|
1401
|
-
css:
|
|
1765
|
+
css: styles4.btn,
|
|
1402
1766
|
onClick: () => singleFolderSelected ? setShowRenameFolderModal(true) : setShowNewFolderModal(true),
|
|
1403
1767
|
disabled: isInImagesFolder && !singleFolderSelected,
|
|
1404
1768
|
title: isInImagesFolder && !singleFolderSelected ? "Cannot create folders in protected images folder" : void 0,
|
|
@@ -1408,11 +1772,11 @@ function StudioToolbar() {
|
|
|
1408
1772
|
]
|
|
1409
1773
|
}
|
|
1410
1774
|
),
|
|
1411
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css:
|
|
1775
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles4.divider }),
|
|
1412
1776
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1413
1777
|
"button",
|
|
1414
1778
|
{
|
|
1415
|
-
css:
|
|
1779
|
+
css: styles4.btn,
|
|
1416
1780
|
onClick: handleProcessImages,
|
|
1417
1781
|
disabled: processing || isInImagesFolder,
|
|
1418
1782
|
title: isInImagesFolder ? "Cannot process images folder" : void 0,
|
|
@@ -1425,7 +1789,7 @@ function StudioToolbar() {
|
|
|
1425
1789
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1426
1790
|
"button",
|
|
1427
1791
|
{
|
|
1428
|
-
css: [
|
|
1792
|
+
css: [styles4.btn, styles4.btnDanger],
|
|
1429
1793
|
onClick: handleDeleteClick,
|
|
1430
1794
|
disabled: !hasSelection,
|
|
1431
1795
|
children: [
|
|
@@ -1437,7 +1801,7 @@ function StudioToolbar() {
|
|
|
1437
1801
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1438
1802
|
"button",
|
|
1439
1803
|
{
|
|
1440
|
-
css:
|
|
1804
|
+
css: styles4.btn,
|
|
1441
1805
|
onClick: handleMoveClick,
|
|
1442
1806
|
disabled: !hasSelection,
|
|
1443
1807
|
children: [
|
|
@@ -1449,20 +1813,20 @@ function StudioToolbar() {
|
|
|
1449
1813
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1450
1814
|
"button",
|
|
1451
1815
|
{
|
|
1452
|
-
css:
|
|
1816
|
+
css: styles4.btn,
|
|
1453
1817
|
onClick: handleSyncCdn,
|
|
1454
|
-
disabled: !hasSelection,
|
|
1818
|
+
disabled: !hasSelection || syncing,
|
|
1455
1819
|
children: [
|
|
1456
1820
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, CloudIcon, {}),
|
|
1457
|
-
"Sync CDN"
|
|
1821
|
+
syncing ? "Syncing..." : "Sync CDN"
|
|
1458
1822
|
]
|
|
1459
1823
|
}
|
|
1460
1824
|
),
|
|
1461
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
1825
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.searchWrapper, children: [
|
|
1462
1826
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1463
1827
|
"input",
|
|
1464
1828
|
{
|
|
1465
|
-
css:
|
|
1829
|
+
css: styles4.searchInput,
|
|
1466
1830
|
type: "text",
|
|
1467
1831
|
placeholder: "Search images...",
|
|
1468
1832
|
value: searchQuery,
|
|
@@ -1473,7 +1837,7 @@ function StudioToolbar() {
|
|
|
1473
1837
|
searchQuery && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1474
1838
|
"button",
|
|
1475
1839
|
{
|
|
1476
|
-
css:
|
|
1840
|
+
css: styles4.searchClearBtn,
|
|
1477
1841
|
onClick: () => setSearchQuery(""),
|
|
1478
1842
|
title: "Clear search",
|
|
1479
1843
|
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { width: "14", height: "14", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
|
|
@@ -1481,25 +1845,25 @@ function StudioToolbar() {
|
|
|
1481
1845
|
)
|
|
1482
1846
|
] })
|
|
1483
1847
|
] }),
|
|
1484
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
1485
|
-
hasSelection && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css:
|
|
1848
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.right, children: [
|
|
1849
|
+
hasSelection && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles4.selectionCount, children: [
|
|
1486
1850
|
selectedItems.size,
|
|
1487
1851
|
" selected",
|
|
1488
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css:
|
|
1852
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles4.clearBtn, onClick: clearSelection, children: "Clear" })
|
|
1489
1853
|
] }),
|
|
1490
1854
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1491
1855
|
"button",
|
|
1492
1856
|
{
|
|
1493
|
-
css: [
|
|
1857
|
+
css: [styles4.btn, styles4.btnIconOnly],
|
|
1494
1858
|
onClick: handleRefresh,
|
|
1495
1859
|
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, RefreshIcon, { spinning: refreshing })
|
|
1496
1860
|
}
|
|
1497
1861
|
),
|
|
1498
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
1862
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.viewToggle, children: [
|
|
1499
1863
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1500
1864
|
"button",
|
|
1501
1865
|
{
|
|
1502
|
-
css: [
|
|
1866
|
+
css: [styles4.viewBtn, viewMode === "grid" && styles4.viewBtnActive],
|
|
1503
1867
|
onClick: () => setViewMode("grid"),
|
|
1504
1868
|
"aria-label": "Grid view",
|
|
1505
1869
|
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, GridIcon, {})
|
|
@@ -1508,7 +1872,7 @@ function StudioToolbar() {
|
|
|
1508
1872
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1509
1873
|
"button",
|
|
1510
1874
|
{
|
|
1511
|
-
css: [
|
|
1875
|
+
css: [styles4.viewBtn, viewMode === "list" && styles4.viewBtnActive],
|
|
1512
1876
|
onClick: () => setViewMode("list"),
|
|
1513
1877
|
"aria-label": "List view",
|
|
1514
1878
|
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ListIcon, {})
|
|
@@ -1520,44 +1884,232 @@ function StudioToolbar() {
|
|
|
1520
1884
|
] });
|
|
1521
1885
|
}
|
|
1522
1886
|
function UploadIcon() {
|
|
1523
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
1887
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" }) });
|
|
1524
1888
|
}
|
|
1525
1889
|
function RefreshIcon({ spinning }) {
|
|
1526
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: [
|
|
1890
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: [styles4.icon, spinning && styles4.iconSpin], fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" }) });
|
|
1527
1891
|
}
|
|
1528
1892
|
function TrashIcon() {
|
|
1529
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
1893
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" }) });
|
|
1530
1894
|
}
|
|
1531
1895
|
function FolderPlusIcon() {
|
|
1532
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
1896
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 13h6m-3-3v6m-9 1V7a2 2 0 012-2h6l2 2h6a2 2 0 012 2v8a2 2 0 01-2 2H5a2 2 0 01-2-2z" }) });
|
|
1533
1897
|
}
|
|
1534
1898
|
function RenameIcon() {
|
|
1535
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
1899
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" }) });
|
|
1536
1900
|
}
|
|
1537
1901
|
function MoveIcon() {
|
|
1538
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
1902
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4" }) });
|
|
1539
1903
|
}
|
|
1540
1904
|
function CloudIcon() {
|
|
1541
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
1905
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" }) });
|
|
1542
1906
|
}
|
|
1543
1907
|
function GridIcon() {
|
|
1544
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
1908
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z" }) });
|
|
1545
1909
|
}
|
|
1546
1910
|
function ListIcon() {
|
|
1547
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
1911
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6h16M4 10h16M4 14h16M4 18h16" }) });
|
|
1548
1912
|
}
|
|
1549
1913
|
function ImageStackIcon() {
|
|
1550
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
1914
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) });
|
|
1915
|
+
}
|
|
1916
|
+
|
|
1917
|
+
// src/components/StudioFileGrid.tsx
|
|
1918
|
+
|
|
1919
|
+
|
|
1920
|
+
|
|
1921
|
+
// src/hooks/useFileList.ts
|
|
1922
|
+
|
|
1923
|
+
|
|
1924
|
+
// src/lib/api.ts
|
|
1925
|
+
var StudioApiClient = class {
|
|
1926
|
+
async get(url) {
|
|
1927
|
+
const response = await fetch(url);
|
|
1928
|
+
if (!response.ok) {
|
|
1929
|
+
const data = await response.json().catch(() => ({}));
|
|
1930
|
+
throw new Error(data.error || `Request failed: ${response.status}`);
|
|
1931
|
+
}
|
|
1932
|
+
return response.json();
|
|
1933
|
+
}
|
|
1934
|
+
async post(url, body) {
|
|
1935
|
+
const response = await fetch(url, {
|
|
1936
|
+
method: "POST",
|
|
1937
|
+
headers: body ? { "Content-Type": "application/json" } : void 0,
|
|
1938
|
+
body: body ? JSON.stringify(body) : void 0
|
|
1939
|
+
});
|
|
1940
|
+
if (!response.ok) {
|
|
1941
|
+
const data = await response.json().catch(() => ({}));
|
|
1942
|
+
throw new Error(data.error || `Request failed: ${response.status}`);
|
|
1943
|
+
}
|
|
1944
|
+
return response.json();
|
|
1945
|
+
}
|
|
1946
|
+
// List handlers
|
|
1947
|
+
async list(path = "public") {
|
|
1948
|
+
return this.get(`/api/studio/list?path=${encodeURIComponent(path)}`);
|
|
1949
|
+
}
|
|
1950
|
+
async search(query) {
|
|
1951
|
+
return this.get(`/api/studio/search?q=${encodeURIComponent(query)}`);
|
|
1952
|
+
}
|
|
1953
|
+
async listFolders() {
|
|
1954
|
+
return this.get("/api/studio/list-folders");
|
|
1955
|
+
}
|
|
1956
|
+
async countImages() {
|
|
1957
|
+
return this.get("/api/studio/count-images");
|
|
1958
|
+
}
|
|
1959
|
+
async folderImages(folders) {
|
|
1960
|
+
return this.get(`/api/studio/folder-images?folders=${encodeURIComponent(folders.join(","))}`);
|
|
1961
|
+
}
|
|
1962
|
+
// File handlers
|
|
1963
|
+
async upload(file, targetPath = "public") {
|
|
1964
|
+
const formData = new FormData();
|
|
1965
|
+
formData.append("file", file);
|
|
1966
|
+
formData.append("path", targetPath);
|
|
1967
|
+
const response = await fetch("/api/studio/upload", {
|
|
1968
|
+
method: "POST",
|
|
1969
|
+
body: formData
|
|
1970
|
+
});
|
|
1971
|
+
if (!response.ok) {
|
|
1972
|
+
const data = await response.json().catch(() => ({}));
|
|
1973
|
+
throw new Error(data.error || `Upload failed: ${response.status}`);
|
|
1974
|
+
}
|
|
1975
|
+
return response.json();
|
|
1976
|
+
}
|
|
1977
|
+
async delete(paths) {
|
|
1978
|
+
return this.post("/api/studio/delete", { paths });
|
|
1979
|
+
}
|
|
1980
|
+
async createFolder(parentPath, name) {
|
|
1981
|
+
return this.post("/api/studio/create-folder", { parentPath, name });
|
|
1982
|
+
}
|
|
1983
|
+
async rename(oldPath, newName) {
|
|
1984
|
+
return this.post("/api/studio/rename", { oldPath, newName });
|
|
1985
|
+
}
|
|
1986
|
+
async move(paths, destination) {
|
|
1987
|
+
return this.post("/api/studio/move", { paths, destination });
|
|
1988
|
+
}
|
|
1989
|
+
// Image handlers
|
|
1990
|
+
async sync(imageKeys) {
|
|
1991
|
+
return this.post("/api/studio/sync", { imageKeys });
|
|
1992
|
+
}
|
|
1993
|
+
async reprocess(imageKeys) {
|
|
1994
|
+
return this.post("/api/studio/reprocess", { imageKeys });
|
|
1995
|
+
}
|
|
1996
|
+
// Process all returns a stream, handle separately
|
|
1997
|
+
processAllStream() {
|
|
1998
|
+
return new EventSource("/api/studio/process-all");
|
|
1999
|
+
}
|
|
2000
|
+
};
|
|
2001
|
+
var studioApi = new StudioApiClient();
|
|
2002
|
+
|
|
2003
|
+
// src/hooks/useFileList.ts
|
|
2004
|
+
function useFileList() {
|
|
2005
|
+
const {
|
|
2006
|
+
currentPath,
|
|
2007
|
+
setCurrentPath,
|
|
2008
|
+
navigateUp,
|
|
2009
|
+
selectedItems,
|
|
2010
|
+
toggleSelection,
|
|
2011
|
+
selectRange,
|
|
2012
|
+
lastSelectedPath,
|
|
2013
|
+
selectAll,
|
|
2014
|
+
clearSelection,
|
|
2015
|
+
refreshKey,
|
|
2016
|
+
setFocusedItem,
|
|
2017
|
+
triggerRefresh,
|
|
2018
|
+
searchQuery,
|
|
2019
|
+
showError
|
|
2020
|
+
} = useStudio();
|
|
2021
|
+
const [items, setItems] = _react.useState.call(void 0, []);
|
|
2022
|
+
const [loading, setLoading] = _react.useState.call(void 0, true);
|
|
2023
|
+
const isInitialLoad = _react.useRef.call(void 0, true);
|
|
2024
|
+
const lastPath = _react.useRef.call(void 0, currentPath);
|
|
2025
|
+
_react.useEffect.call(void 0, () => {
|
|
2026
|
+
async function loadItems() {
|
|
2027
|
+
const isPathChange = lastPath.current !== currentPath;
|
|
2028
|
+
if (isInitialLoad.current || isPathChange) {
|
|
2029
|
+
setLoading(true);
|
|
2030
|
+
}
|
|
2031
|
+
lastPath.current = currentPath;
|
|
2032
|
+
try {
|
|
2033
|
+
const data = searchQuery && searchQuery.length >= 2 ? await studioApi.search(searchQuery) : await studioApi.list(currentPath);
|
|
2034
|
+
setItems(data.items || []);
|
|
2035
|
+
} catch (error) {
|
|
2036
|
+
const message = error instanceof Error ? error.message : "Failed to load items";
|
|
2037
|
+
showError("Load Error", message);
|
|
2038
|
+
setItems([]);
|
|
2039
|
+
}
|
|
2040
|
+
setLoading(false);
|
|
2041
|
+
isInitialLoad.current = false;
|
|
2042
|
+
}
|
|
2043
|
+
loadItems();
|
|
2044
|
+
}, [currentPath, refreshKey, searchQuery, showError]);
|
|
2045
|
+
const isAtRoot = currentPath === "public";
|
|
2046
|
+
const isSearching = searchQuery && searchQuery.length >= 2;
|
|
2047
|
+
const sortedItems = [...items].sort((a, b) => {
|
|
2048
|
+
if (a.type === "folder" && b.type !== "folder") return -1;
|
|
2049
|
+
if (a.type !== "folder" && b.type === "folder") return 1;
|
|
2050
|
+
return a.name.localeCompare(b.name);
|
|
2051
|
+
});
|
|
2052
|
+
const allItemsSelected = sortedItems.length > 0 && sortedItems.every((item) => selectedItems.has(item.path));
|
|
2053
|
+
const someItemsSelected = sortedItems.some((item) => selectedItems.has(item.path));
|
|
2054
|
+
const handleItemClick = _react.useCallback.call(void 0, (item, e) => {
|
|
2055
|
+
if (e.shiftKey && lastSelectedPath) {
|
|
2056
|
+
selectRange(lastSelectedPath, item.path, sortedItems);
|
|
2057
|
+
} else {
|
|
2058
|
+
toggleSelection(item.path);
|
|
2059
|
+
}
|
|
2060
|
+
}, [lastSelectedPath, selectRange, sortedItems, toggleSelection]);
|
|
2061
|
+
const handleOpen = _react.useCallback.call(void 0, (item) => {
|
|
2062
|
+
if (item.type === "folder") {
|
|
2063
|
+
setCurrentPath(item.path);
|
|
2064
|
+
} else {
|
|
2065
|
+
setFocusedItem(item);
|
|
2066
|
+
}
|
|
2067
|
+
}, [setCurrentPath, setFocusedItem]);
|
|
2068
|
+
const handleGenerateThumbnail = _react.useCallback.call(void 0, async (item) => {
|
|
2069
|
+
try {
|
|
2070
|
+
const imageKey = "/" + item.path.replace(/^public\//, "");
|
|
2071
|
+
await studioApi.reprocess([imageKey]);
|
|
2072
|
+
triggerRefresh();
|
|
2073
|
+
} catch (error) {
|
|
2074
|
+
const message = error instanceof Error ? error.message : "Failed to generate thumbnail";
|
|
2075
|
+
showError("Processing Error", message);
|
|
2076
|
+
}
|
|
2077
|
+
}, [triggerRefresh, showError]);
|
|
2078
|
+
const handleSelectAll = _react.useCallback.call(void 0, () => {
|
|
2079
|
+
if (allItemsSelected) {
|
|
2080
|
+
clearSelection();
|
|
2081
|
+
} else {
|
|
2082
|
+
selectAll(sortedItems);
|
|
2083
|
+
}
|
|
2084
|
+
}, [allItemsSelected, clearSelection, selectAll, sortedItems]);
|
|
2085
|
+
return {
|
|
2086
|
+
// State
|
|
2087
|
+
items,
|
|
2088
|
+
loading,
|
|
2089
|
+
sortedItems,
|
|
2090
|
+
// Computed
|
|
2091
|
+
isAtRoot,
|
|
2092
|
+
isSearching,
|
|
2093
|
+
allItemsSelected,
|
|
2094
|
+
someItemsSelected,
|
|
2095
|
+
// Context values
|
|
2096
|
+
currentPath,
|
|
2097
|
+
selectedItems,
|
|
2098
|
+
navigateUp,
|
|
2099
|
+
// Handlers
|
|
2100
|
+
handleItemClick,
|
|
2101
|
+
handleOpen,
|
|
2102
|
+
handleGenerateThumbnail,
|
|
2103
|
+
handleSelectAll
|
|
2104
|
+
};
|
|
1551
2105
|
}
|
|
1552
2106
|
|
|
1553
2107
|
// src/components/StudioFileGrid.tsx
|
|
1554
2108
|
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
2109
|
var spin2 = _react3.keyframes`
|
|
1558
2110
|
to { transform: rotate(360deg); }
|
|
1559
2111
|
`;
|
|
1560
|
-
var
|
|
2112
|
+
var styles5 = {
|
|
1561
2113
|
loading: _react3.css`
|
|
1562
2114
|
display: flex;
|
|
1563
2115
|
align-items: center;
|
|
@@ -1875,93 +2427,37 @@ var styles4 = {
|
|
|
1875
2427
|
`
|
|
1876
2428
|
};
|
|
1877
2429
|
function StudioFileGrid() {
|
|
1878
|
-
const {
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
const response = await fetch(url);
|
|
1893
|
-
if (response.ok) {
|
|
1894
|
-
const data = await response.json();
|
|
1895
|
-
setItems(data.items || []);
|
|
1896
|
-
}
|
|
1897
|
-
} catch (error) {
|
|
1898
|
-
console.error("Failed to load items:", error);
|
|
1899
|
-
}
|
|
1900
|
-
setLoading(false);
|
|
1901
|
-
isInitialLoad.current = false;
|
|
1902
|
-
}
|
|
1903
|
-
loadItems();
|
|
1904
|
-
}, [currentPath, refreshKey, searchQuery]);
|
|
2430
|
+
const {
|
|
2431
|
+
loading,
|
|
2432
|
+
sortedItems,
|
|
2433
|
+
isAtRoot,
|
|
2434
|
+
isSearching,
|
|
2435
|
+
allItemsSelected,
|
|
2436
|
+
someItemsSelected,
|
|
2437
|
+
selectedItems,
|
|
2438
|
+
navigateUp,
|
|
2439
|
+
handleItemClick,
|
|
2440
|
+
handleOpen,
|
|
2441
|
+
handleGenerateThumbnail,
|
|
2442
|
+
handleSelectAll
|
|
2443
|
+
} = useFileList();
|
|
1905
2444
|
if (loading) {
|
|
1906
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css:
|
|
2445
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.loading, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.spinner }) });
|
|
1907
2446
|
}
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "
|
|
1912
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css:
|
|
1913
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles4.emptyText, children: "Upload images to get started" })
|
|
2447
|
+
if (sortedItems.length === 0 && isAtRoot) {
|
|
2448
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.empty, children: [
|
|
2449
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.emptyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) }),
|
|
2450
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.emptyText, children: "No files in this folder" }),
|
|
2451
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.emptyText, children: "Upload images to get started" })
|
|
1914
2452
|
] });
|
|
1915
2453
|
}
|
|
1916
|
-
const isSearching = searchQuery && searchQuery.length >= 2;
|
|
1917
|
-
const sortedItems = [...items].sort((a, b) => {
|
|
1918
|
-
if (a.type === "folder" && b.type !== "folder") return -1;
|
|
1919
|
-
if (a.type !== "folder" && b.type === "folder") return 1;
|
|
1920
|
-
return a.name.localeCompare(b.name);
|
|
1921
|
-
});
|
|
1922
|
-
const handleItemClick = (item, e) => {
|
|
1923
|
-
if (e.shiftKey && lastSelectedPath) {
|
|
1924
|
-
selectRange(lastSelectedPath, item.path, sortedItems);
|
|
1925
|
-
} else {
|
|
1926
|
-
toggleSelection(item.path);
|
|
1927
|
-
}
|
|
1928
|
-
};
|
|
1929
|
-
const handleOpen = (item) => {
|
|
1930
|
-
if (item.type === "folder") {
|
|
1931
|
-
setCurrentPath(item.path);
|
|
1932
|
-
} else {
|
|
1933
|
-
setFocusedItem(item);
|
|
1934
|
-
}
|
|
1935
|
-
};
|
|
1936
|
-
const handleGenerateThumbnail = async (item) => {
|
|
1937
|
-
try {
|
|
1938
|
-
const imageKey = item.path.replace(/^public\//, "");
|
|
1939
|
-
await fetch("/api/studio/reprocess", {
|
|
1940
|
-
method: "POST",
|
|
1941
|
-
headers: { "Content-Type": "application/json" },
|
|
1942
|
-
body: JSON.stringify({ imageKeys: [imageKey] })
|
|
1943
|
-
});
|
|
1944
|
-
triggerRefresh();
|
|
1945
|
-
} catch (error) {
|
|
1946
|
-
console.error("Failed to generate thumbnail:", error);
|
|
1947
|
-
}
|
|
1948
|
-
};
|
|
1949
|
-
const allItemsSelected = sortedItems.length > 0 && sortedItems.every((item) => selectedItems.has(item.path));
|
|
1950
|
-
const someItemsSelected = sortedItems.some((item) => selectedItems.has(item.path));
|
|
1951
|
-
const handleSelectAll = () => {
|
|
1952
|
-
if (allItemsSelected) {
|
|
1953
|
-
clearSelection();
|
|
1954
|
-
} else {
|
|
1955
|
-
selectAll(sortedItems);
|
|
1956
|
-
}
|
|
1957
|
-
};
|
|
1958
2454
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
|
|
1959
|
-
sortedItems.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css:
|
|
2455
|
+
sortedItems.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.selectAllRow, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "label", { css: styles5.selectAllLabel, children: [
|
|
1960
2456
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1961
2457
|
"input",
|
|
1962
2458
|
{
|
|
1963
2459
|
type: "checkbox",
|
|
1964
|
-
css:
|
|
2460
|
+
css: styles5.selectAllCheckbox,
|
|
1965
2461
|
checked: allItemsSelected,
|
|
1966
2462
|
ref: (el) => {
|
|
1967
2463
|
if (el) el.indeterminate = someItemsSelected && !allItemsSelected;
|
|
@@ -1973,17 +2469,17 @@ function StudioFileGrid() {
|
|
|
1973
2469
|
sortedItems.length,
|
|
1974
2470
|
")"
|
|
1975
2471
|
] }) }),
|
|
1976
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
2472
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.grid, children: [
|
|
1977
2473
|
!isAtRoot && !isSearching && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
1978
2474
|
"div",
|
|
1979
2475
|
{
|
|
1980
|
-
css: [
|
|
2476
|
+
css: [styles5.item, styles5.parentItem],
|
|
1981
2477
|
onClick: navigateUp,
|
|
1982
2478
|
children: [
|
|
1983
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css:
|
|
1984
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
1985
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css:
|
|
1986
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css:
|
|
2479
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.content, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.parentIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M3 10h10a8 8 0 018 8v2M3 10l6 6m-6-6l6-6" }) }) }),
|
|
2480
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.label, children: [
|
|
2481
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.name, children: ".." }),
|
|
2482
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.size, children: "Parent folder" })
|
|
1987
2483
|
] })
|
|
1988
2484
|
]
|
|
1989
2485
|
}
|
|
@@ -2017,43 +2513,43 @@ function GridItem({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
|
|
|
2017
2513
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
2018
2514
|
"div",
|
|
2019
2515
|
{
|
|
2020
|
-
css: [
|
|
2516
|
+
css: [styles5.item, isSelected && styles5.itemSelected],
|
|
2021
2517
|
onClick,
|
|
2022
2518
|
children: [
|
|
2023
2519
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2024
2520
|
"div",
|
|
2025
2521
|
{
|
|
2026
|
-
css:
|
|
2522
|
+
css: styles5.checkboxWrapper,
|
|
2027
2523
|
onClick: (e) => e.stopPropagation(),
|
|
2028
2524
|
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2029
2525
|
"input",
|
|
2030
2526
|
{
|
|
2031
2527
|
type: "checkbox",
|
|
2032
|
-
css:
|
|
2528
|
+
css: styles5.checkbox,
|
|
2033
2529
|
checked: isSelected,
|
|
2034
2530
|
onChange: () => onClick({})
|
|
2035
2531
|
}
|
|
2036
2532
|
)
|
|
2037
2533
|
}
|
|
2038
2534
|
),
|
|
2039
|
-
item.cdnSynced && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css:
|
|
2040
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
2535
|
+
item.cdnSynced && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles5.cdnBadge, children: "CDN" }),
|
|
2536
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.content, children: [
|
|
2041
2537
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
2042
2538
|
"button",
|
|
2043
2539
|
{
|
|
2044
|
-
css:
|
|
2540
|
+
css: styles5.copyBtn,
|
|
2045
2541
|
onClick: handleCopyPath,
|
|
2046
2542
|
title: "Copy file path",
|
|
2047
2543
|
children: [
|
|
2048
|
-
showCopied && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css:
|
|
2049
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
2544
|
+
showCopied && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles5.tooltip, children: "Copied!" }),
|
|
2545
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" }) })
|
|
2050
2546
|
]
|
|
2051
2547
|
}
|
|
2052
2548
|
),
|
|
2053
2549
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2054
2550
|
"button",
|
|
2055
2551
|
{
|
|
2056
|
-
css:
|
|
2552
|
+
css: styles5.openBtn,
|
|
2057
2553
|
onClick: (e) => {
|
|
2058
2554
|
e.stopPropagation();
|
|
2059
2555
|
onOpen();
|
|
@@ -2061,13 +2557,13 @@ function GridItem({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
|
|
|
2061
2557
|
children: "Open"
|
|
2062
2558
|
}
|
|
2063
2559
|
),
|
|
2064
|
-
isFolder ? isImagesFolder ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
2065
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
2066
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
2067
|
-
] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
2560
|
+
isFolder ? isImagesFolder ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.imagesFolderWrapper, children: [
|
|
2561
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.imagesFolderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M10 4H4a2 2 0 00-2 2v12a2 2 0 002 2h16a2 2 0 002-2V8a2 2 0 00-2-2h-8l-2-2z" }) }),
|
|
2562
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.lockIcon, fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { fillRule: "evenodd", d: "M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z", clipRule: "evenodd" }) })
|
|
2563
|
+
] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.folderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M10 4H4a2 2 0 00-2 2v12a2 2 0 002 2h16a2 2 0 002-2V8a2 2 0 00-2-2h-8l-2-2z" }) }) : isImage && item.hasThumbnail ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2068
2564
|
"img",
|
|
2069
2565
|
{
|
|
2070
|
-
css:
|
|
2566
|
+
css: styles5.image,
|
|
2071
2567
|
src: item.thumbnail,
|
|
2072
2568
|
alt: item.name,
|
|
2073
2569
|
loading: "lazy"
|
|
@@ -2075,26 +2571,26 @@ function GridItem({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
|
|
|
2075
2571
|
) : isImage && !item.hasThumbnail ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
2076
2572
|
"button",
|
|
2077
2573
|
{
|
|
2078
|
-
css:
|
|
2574
|
+
css: styles5.noThumbnail,
|
|
2079
2575
|
onClick: (e) => {
|
|
2080
2576
|
e.stopPropagation();
|
|
2081
2577
|
onGenerateThumbnail();
|
|
2082
2578
|
},
|
|
2083
2579
|
title: "Generate thumbnail",
|
|
2084
2580
|
children: [
|
|
2085
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
2086
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css:
|
|
2581
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.noThumbnailIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) }),
|
|
2582
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles5.noThumbnailText, children: "Generate" })
|
|
2087
2583
|
]
|
|
2088
2584
|
}
|
|
2089
|
-
) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
2585
|
+
) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.fileIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" }) })
|
|
2090
2586
|
] }),
|
|
2091
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css:
|
|
2092
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css:
|
|
2093
|
-
isFolder ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { css:
|
|
2587
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.label, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.labelRow, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.labelText, children: [
|
|
2588
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.name, title: item.name, children: truncateMiddle(item.name) }),
|
|
2589
|
+
isFolder ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { css: styles5.size, children: [
|
|
2094
2590
|
item.fileCount !== void 0 ? `${item.fileCount} files` : "",
|
|
2095
2591
|
item.fileCount !== void 0 && item.totalSize !== void 0 ? " \xB7 " : "",
|
|
2096
2592
|
item.totalSize !== void 0 ? formatFileSize(item.totalSize) : ""
|
|
2097
|
-
] }) : item.size !== void 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css:
|
|
2593
|
+
] }) : item.size !== void 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.size, children: formatFileSize(item.size) })
|
|
2098
2594
|
] }) }) })
|
|
2099
2595
|
]
|
|
2100
2596
|
}
|
|
@@ -2126,7 +2622,7 @@ function truncateMiddle(str, maxLength = 24) {
|
|
|
2126
2622
|
var spin3 = _react3.keyframes`
|
|
2127
2623
|
to { transform: rotate(360deg); }
|
|
2128
2624
|
`;
|
|
2129
|
-
var
|
|
2625
|
+
var styles6 = {
|
|
2130
2626
|
loading: _react3.css`
|
|
2131
2627
|
display: flex;
|
|
2132
2628
|
align-items: center;
|
|
@@ -2432,89 +2928,33 @@ var styles5 = {
|
|
|
2432
2928
|
`
|
|
2433
2929
|
};
|
|
2434
2930
|
function StudioFileList() {
|
|
2435
|
-
const {
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
const response = await fetch(url);
|
|
2450
|
-
if (response.ok) {
|
|
2451
|
-
const data = await response.json();
|
|
2452
|
-
setItems(data.items || []);
|
|
2453
|
-
}
|
|
2454
|
-
} catch (error) {
|
|
2455
|
-
console.error("Failed to load items:", error);
|
|
2456
|
-
}
|
|
2457
|
-
setLoading(false);
|
|
2458
|
-
isInitialLoad.current = false;
|
|
2459
|
-
}
|
|
2460
|
-
loadItems();
|
|
2461
|
-
}, [currentPath, refreshKey, searchQuery]);
|
|
2931
|
+
const {
|
|
2932
|
+
loading,
|
|
2933
|
+
sortedItems,
|
|
2934
|
+
isAtRoot,
|
|
2935
|
+
isSearching,
|
|
2936
|
+
allItemsSelected,
|
|
2937
|
+
someItemsSelected,
|
|
2938
|
+
selectedItems,
|
|
2939
|
+
navigateUp,
|
|
2940
|
+
handleItemClick,
|
|
2941
|
+
handleOpen,
|
|
2942
|
+
handleGenerateThumbnail,
|
|
2943
|
+
handleSelectAll
|
|
2944
|
+
} = useFileList();
|
|
2462
2945
|
if (loading) {
|
|
2463
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css:
|
|
2946
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.loading, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.spinner }) });
|
|
2464
2947
|
}
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
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" }) });
|
|
2948
|
+
if (sortedItems.length === 0 && isAtRoot) {
|
|
2949
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.empty, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { children: "No files in this folder" }) });
|
|
2468
2950
|
}
|
|
2469
|
-
|
|
2470
|
-
const sortedItems = [...items].sort((a, b) => {
|
|
2471
|
-
if (a.type === "folder" && b.type !== "folder") return -1;
|
|
2472
|
-
if (a.type !== "folder" && b.type === "folder") return 1;
|
|
2473
|
-
return a.name.localeCompare(b.name);
|
|
2474
|
-
});
|
|
2475
|
-
const handleItemClick = (item, e) => {
|
|
2476
|
-
if (e.shiftKey && lastSelectedPath) {
|
|
2477
|
-
selectRange(lastSelectedPath, item.path, sortedItems);
|
|
2478
|
-
} else {
|
|
2479
|
-
toggleSelection(item.path);
|
|
2480
|
-
}
|
|
2481
|
-
};
|
|
2482
|
-
const handleOpen = (item) => {
|
|
2483
|
-
if (item.type === "folder") {
|
|
2484
|
-
setCurrentPath(item.path);
|
|
2485
|
-
} else {
|
|
2486
|
-
setFocusedItem(item);
|
|
2487
|
-
}
|
|
2488
|
-
};
|
|
2489
|
-
const handleGenerateThumbnail = async (item) => {
|
|
2490
|
-
try {
|
|
2491
|
-
const imageKey = item.path.replace(/^public\//, "");
|
|
2492
|
-
await fetch("/api/studio/reprocess", {
|
|
2493
|
-
method: "POST",
|
|
2494
|
-
headers: { "Content-Type": "application/json" },
|
|
2495
|
-
body: JSON.stringify({ imageKeys: [imageKey] })
|
|
2496
|
-
});
|
|
2497
|
-
triggerRefresh();
|
|
2498
|
-
} catch (error) {
|
|
2499
|
-
console.error("Failed to generate thumbnail:", error);
|
|
2500
|
-
}
|
|
2501
|
-
};
|
|
2502
|
-
const allItemsSelected = sortedItems.length > 0 && sortedItems.every((item) => selectedItems.has(item.path));
|
|
2503
|
-
const someItemsSelected = sortedItems.some((item) => selectedItems.has(item.path));
|
|
2504
|
-
const handleSelectAll = () => {
|
|
2505
|
-
if (allItemsSelected) {
|
|
2506
|
-
clearSelection();
|
|
2507
|
-
} else {
|
|
2508
|
-
selectAll(sortedItems);
|
|
2509
|
-
}
|
|
2510
|
-
};
|
|
2511
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.tableWrapper, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "table", { css: styles5.table, children: [
|
|
2951
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.tableWrapper, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "table", { css: styles6.table, children: [
|
|
2512
2952
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "thead", { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tr", { children: [
|
|
2513
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [
|
|
2953
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles6.th, styles6.thCheckbox], children: sortedItems.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2514
2954
|
"input",
|
|
2515
2955
|
{
|
|
2516
2956
|
type: "checkbox",
|
|
2517
|
-
css:
|
|
2957
|
+
css: styles6.checkbox,
|
|
2518
2958
|
checked: allItemsSelected,
|
|
2519
2959
|
ref: (el) => {
|
|
2520
2960
|
if (el) el.indeterminate = someItemsSelected && !allItemsSelected;
|
|
@@ -2522,21 +2962,21 @@ function StudioFileList() {
|
|
|
2522
2962
|
onChange: handleSelectAll
|
|
2523
2963
|
}
|
|
2524
2964
|
) }),
|
|
2525
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css:
|
|
2526
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [
|
|
2527
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [
|
|
2528
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [
|
|
2965
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: styles6.th, children: "Name" }),
|
|
2966
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles6.th, styles6.thSize], children: "Size" }),
|
|
2967
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles6.th, styles6.thDimensions], children: "Dimensions" }),
|
|
2968
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles6.th, styles6.thCdn], children: "CDN" })
|
|
2529
2969
|
] }) }),
|
|
2530
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tbody", { css:
|
|
2531
|
-
!isAtRoot && !isSearching && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tr", { css:
|
|
2532
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css:
|
|
2533
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css:
|
|
2534
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
2535
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css:
|
|
2970
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tbody", { css: styles6.tbody, children: [
|
|
2971
|
+
!isAtRoot && !isSearching && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tr", { css: styles6.parentRow, onClick: navigateUp, children: [
|
|
2972
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles6.td }),
|
|
2973
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles6.td, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.nameCell, children: [
|
|
2974
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.parentIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M3 10h10a8 8 0 018 8v2M3 10l6 6m-6-6l6-6" }) }),
|
|
2975
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles6.name, children: ".." })
|
|
2536
2976
|
] }) }),
|
|
2537
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [
|
|
2538
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [
|
|
2539
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css:
|
|
2977
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles6.td, styles6.meta], children: "--" }),
|
|
2978
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles6.td, styles6.meta], children: "Parent folder" }),
|
|
2979
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles6.td, children: "--" })
|
|
2540
2980
|
] }),
|
|
2541
2981
|
sortedItems.map((item) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2542
2982
|
ListRow,
|
|
@@ -2567,59 +3007,59 @@ function ListRow({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
|
|
|
2567
3007
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
2568
3008
|
"tr",
|
|
2569
3009
|
{
|
|
2570
|
-
css: [
|
|
3010
|
+
css: [styles6.row, isSelected && styles6.rowSelected],
|
|
2571
3011
|
onClick,
|
|
2572
3012
|
children: [
|
|
2573
3013
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2574
3014
|
"td",
|
|
2575
3015
|
{
|
|
2576
|
-
css: [
|
|
3016
|
+
css: [styles6.td, styles6.checkboxCell],
|
|
2577
3017
|
onClick: (e) => e.stopPropagation(),
|
|
2578
3018
|
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2579
3019
|
"input",
|
|
2580
3020
|
{
|
|
2581
3021
|
type: "checkbox",
|
|
2582
|
-
css:
|
|
3022
|
+
css: styles6.checkbox,
|
|
2583
3023
|
checked: isSelected,
|
|
2584
3024
|
onChange: () => onClick({})
|
|
2585
3025
|
}
|
|
2586
3026
|
)
|
|
2587
3027
|
}
|
|
2588
3028
|
),
|
|
2589
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css:
|
|
2590
|
-
isFolder ? isImagesFolder ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
2591
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
2592
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
2593
|
-
] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css:
|
|
3029
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles6.td, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.nameCell, children: [
|
|
3030
|
+
isFolder ? isImagesFolder ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.imagesFolderWrapper, children: [
|
|
3031
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.imagesFolderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M10 4H4a2 2 0 00-2 2v12a2 2 0 002 2h16a2 2 0 002-2V8a2 2 0 00-2-2h-8l-2-2z" }) }),
|
|
3032
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.lockIcon, fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { fillRule: "evenodd", d: "M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z", clipRule: "evenodd" }) })
|
|
3033
|
+
] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.folderIconWrapper, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.folderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M10 4H4a2 2 0 00-2 2v12a2 2 0 002 2h16a2 2 0 002-2V8a2 2 0 00-2-2h-8l-2-2z" }) }) }) : isImage && item.hasThumbnail ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.thumbnailWrapper, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { css: styles6.thumbnail, src: item.thumbnail, alt: item.name, loading: "lazy" }) }) : isImage && !item.hasThumbnail ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.thumbnailWrapper, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2594
3034
|
"button",
|
|
2595
3035
|
{
|
|
2596
|
-
css:
|
|
3036
|
+
css: styles6.noThumbnail,
|
|
2597
3037
|
onClick: (e) => {
|
|
2598
3038
|
e.stopPropagation();
|
|
2599
3039
|
onGenerateThumbnail();
|
|
2600
3040
|
},
|
|
2601
3041
|
title: "Generate thumbnail",
|
|
2602
|
-
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
3042
|
+
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.noThumbnailIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) })
|
|
2603
3043
|
}
|
|
2604
|
-
) }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css:
|
|
2605
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css:
|
|
2606
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
3044
|
+
) }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.thumbnailWrapper, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.fileIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" }) }) }),
|
|
3045
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles6.name, title: item.name, children: truncateMiddle2(item.name) }),
|
|
3046
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.actionsCell, children: [
|
|
2607
3047
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
2608
3048
|
"button",
|
|
2609
3049
|
{
|
|
2610
|
-
css:
|
|
3050
|
+
css: styles6.copyBtn,
|
|
2611
3051
|
onClick: handleCopyPath,
|
|
2612
3052
|
title: "Copy file path",
|
|
2613
3053
|
children: [
|
|
2614
|
-
showCopied && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css:
|
|
2615
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
3054
|
+
showCopied && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles6.tooltip, children: "Copied!" }),
|
|
3055
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" }) })
|
|
2616
3056
|
]
|
|
2617
3057
|
}
|
|
2618
3058
|
),
|
|
2619
3059
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
2620
3060
|
"button",
|
|
2621
3061
|
{
|
|
2622
|
-
css:
|
|
3062
|
+
css: styles6.openBtn,
|
|
2623
3063
|
onClick: (e) => {
|
|
2624
3064
|
e.stopPropagation();
|
|
2625
3065
|
onOpen();
|
|
@@ -2629,12 +3069,12 @@ function ListRow({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
|
|
|
2629
3069
|
)
|
|
2630
3070
|
] })
|
|
2631
3071
|
] }) }),
|
|
2632
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [
|
|
2633
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [
|
|
2634
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css:
|
|
2635
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
3072
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles6.td, styles6.meta], children: isFolder ? item.fileCount !== void 0 ? `${item.fileCount} files` : "--" : item.size !== void 0 ? formatFileSize2(item.size) : "--" }),
|
|
3073
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles6.td, styles6.meta], children: isFolder ? item.totalSize !== void 0 ? formatFileSize2(item.totalSize) : "--" : item.dimensions ? `${item.dimensions.width}x${item.dimensions.height}` : "--" }),
|
|
3074
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles6.td, children: item.cdnSynced ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles6.cdnBadge, children: [
|
|
3075
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.cdnIcon, fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }),
|
|
2636
3076
|
"Synced"
|
|
2637
|
-
] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css:
|
|
3077
|
+
] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles6.cdnEmpty, children: "--" }) })
|
|
2638
3078
|
]
|
|
2639
3079
|
}
|
|
2640
3080
|
);
|
|
@@ -2672,7 +3112,7 @@ function isVideoFile(filename) {
|
|
|
2672
3112
|
const ext = filename.toLowerCase().substring(filename.lastIndexOf("."));
|
|
2673
3113
|
return VIDEO_EXTENSIONS.includes(ext);
|
|
2674
3114
|
}
|
|
2675
|
-
var
|
|
3115
|
+
var styles7 = {
|
|
2676
3116
|
overlay: _react3.css`
|
|
2677
3117
|
position: absolute;
|
|
2678
3118
|
top: 0;
|
|
@@ -2923,9 +3363,11 @@ function StudioDetailView() {
|
|
|
2923
3363
|
const [showDeleteConfirm, setShowDeleteConfirm] = _react.useState.call(void 0, false);
|
|
2924
3364
|
const [showRenameModal, setShowRenameModal] = _react.useState.call(void 0, false);
|
|
2925
3365
|
const [showProcessConfirm, setShowProcessConfirm] = _react.useState.call(void 0, false);
|
|
3366
|
+
const [showR2SetupModal, setShowR2SetupModal] = _react.useState.call(void 0, false);
|
|
2926
3367
|
const [processProgress, setProcessProgress] = _react.useState.call(void 0, null);
|
|
2927
3368
|
const [alertMessage, setAlertMessage] = _react.useState.call(void 0, null);
|
|
2928
3369
|
const [showCopied, setShowCopied] = _react.useState.call(void 0, false);
|
|
3370
|
+
const [syncing, setSyncing] = _react.useState.call(void 0, false);
|
|
2929
3371
|
if (!focusedItem) return null;
|
|
2930
3372
|
const isImage = isImageFile(focusedItem.name);
|
|
2931
3373
|
const isVideo = isVideoFile(focusedItem.name);
|
|
@@ -2997,8 +3439,41 @@ function StudioDetailView() {
|
|
|
2997
3439
|
});
|
|
2998
3440
|
}
|
|
2999
3441
|
};
|
|
3000
|
-
const handleSync = () => {
|
|
3001
|
-
|
|
3442
|
+
const handleSync = async () => {
|
|
3443
|
+
const imageKey = "/" + focusedItem.path.replace(/^public\//, "");
|
|
3444
|
+
setSyncing(true);
|
|
3445
|
+
try {
|
|
3446
|
+
const response = await fetch("/api/studio/sync", {
|
|
3447
|
+
method: "POST",
|
|
3448
|
+
headers: { "Content-Type": "application/json" },
|
|
3449
|
+
body: JSON.stringify({ imageKeys: [imageKey] })
|
|
3450
|
+
});
|
|
3451
|
+
const data = await response.json();
|
|
3452
|
+
if (response.ok) {
|
|
3453
|
+
setAlertMessage({
|
|
3454
|
+
title: "Sync Complete",
|
|
3455
|
+
message: "Successfully synced to CDN."
|
|
3456
|
+
});
|
|
3457
|
+
triggerRefresh();
|
|
3458
|
+
} else {
|
|
3459
|
+
if (_optionalChain([data, 'access', _29 => _29.error, 'optionalAccess', _30 => _30.includes, 'call', _31 => _31("R2 not configured")]) || _optionalChain([data, 'access', _32 => _32.error, 'optionalAccess', _33 => _33.includes, 'call', _34 => _34("CLOUDFLARE_R2")])) {
|
|
3460
|
+
setShowR2SetupModal(true);
|
|
3461
|
+
} else {
|
|
3462
|
+
setAlertMessage({
|
|
3463
|
+
title: "Sync Failed",
|
|
3464
|
+
message: data.error || "Failed to sync to CDN."
|
|
3465
|
+
});
|
|
3466
|
+
}
|
|
3467
|
+
}
|
|
3468
|
+
} catch (error) {
|
|
3469
|
+
console.error("Sync error:", error);
|
|
3470
|
+
setAlertMessage({
|
|
3471
|
+
title: "Sync Failed",
|
|
3472
|
+
message: "Failed to sync to CDN. Check console for details."
|
|
3473
|
+
});
|
|
3474
|
+
} finally {
|
|
3475
|
+
setSyncing(false);
|
|
3476
|
+
}
|
|
3002
3477
|
};
|
|
3003
3478
|
const handleProcessImage = async () => {
|
|
3004
3479
|
setShowProcessConfirm(false);
|
|
@@ -3020,7 +3495,7 @@ function StudioDetailView() {
|
|
|
3020
3495
|
if (!response.ok) {
|
|
3021
3496
|
throw new Error("Processing failed");
|
|
3022
3497
|
}
|
|
3023
|
-
const reader = _optionalChain([response, 'access',
|
|
3498
|
+
const reader = _optionalChain([response, 'access', _35 => _35.body, 'optionalAccess', _36 => _36.getReader, 'call', _37 => _37()]);
|
|
3024
3499
|
if (!reader) {
|
|
3025
3500
|
throw new Error("No response body");
|
|
3026
3501
|
}
|
|
@@ -3056,14 +3531,14 @@ function StudioDetailView() {
|
|
|
3056
3531
|
};
|
|
3057
3532
|
const renderMedia = () => {
|
|
3058
3533
|
if (isImage) {
|
|
3059
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { css:
|
|
3534
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { css: styles7.image, src: imageSrc, alt: focusedItem.name });
|
|
3060
3535
|
}
|
|
3061
3536
|
if (isVideo) {
|
|
3062
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "video", { css:
|
|
3537
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "video", { css: styles7.video, src: imageSrc, controls: true });
|
|
3063
3538
|
}
|
|
3064
|
-
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
3065
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
3066
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css:
|
|
3539
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.filePlaceholder, children: [
|
|
3540
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles7.fileIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" }) }),
|
|
3541
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles7.fileName, children: focusedItem.name })
|
|
3067
3542
|
] });
|
|
3068
3543
|
};
|
|
3069
3544
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
@@ -3086,6 +3561,13 @@ function StudioDetailView() {
|
|
|
3086
3561
|
onClose: () => setAlertMessage(null)
|
|
3087
3562
|
}
|
|
3088
3563
|
),
|
|
3564
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3565
|
+
R2SetupModal,
|
|
3566
|
+
{
|
|
3567
|
+
isOpen: showR2SetupModal,
|
|
3568
|
+
onClose: () => setShowR2SetupModal(false)
|
|
3569
|
+
}
|
|
3570
|
+
),
|
|
3089
3571
|
showRenameModal && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3090
3572
|
InputModal,
|
|
3091
3573
|
{
|
|
@@ -3116,61 +3598,61 @@ function StudioDetailView() {
|
|
|
3116
3598
|
onClose: () => setProcessProgress(null)
|
|
3117
3599
|
}
|
|
3118
3600
|
),
|
|
3119
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css:
|
|
3120
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
3121
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
3122
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css:
|
|
3123
|
-
showCopied && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css:
|
|
3124
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
3601
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles7.overlay, onClick: handleClose, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.container, onClick: (e) => e.stopPropagation(), children: [
|
|
3602
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.main, children: [
|
|
3603
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.headerButtons, children: [
|
|
3604
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles7.copyBtn, onClick: handleCopyPath, title: "Copy file path", children: [
|
|
3605
|
+
showCopied && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.tooltip, children: "Copied!" }),
|
|
3606
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles7.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" }) })
|
|
3125
3607
|
] }),
|
|
3126
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css:
|
|
3608
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles7.mainCloseBtn, onClick: handleClose, "aria-label": "Close", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles7.mainCloseIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })
|
|
3127
3609
|
] }),
|
|
3128
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css:
|
|
3610
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles7.mediaWrapper, children: renderMedia() })
|
|
3129
3611
|
] }),
|
|
3130
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
3131
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css:
|
|
3132
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
3133
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
3134
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
3135
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css:
|
|
3136
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css:
|
|
3612
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.sidebar, children: [
|
|
3613
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles7.sidebarHeader, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles7.sidebarTitle, children: "Details" }) }),
|
|
3614
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.sidebarContent, children: [
|
|
3615
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.info, children: [
|
|
3616
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.infoRow, children: [
|
|
3617
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoLabel, children: "Name" }),
|
|
3618
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoValueWrap, children: focusedItem.name })
|
|
3137
3619
|
] }),
|
|
3138
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
3139
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css:
|
|
3140
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css:
|
|
3620
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.infoRow, children: [
|
|
3621
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoLabel, children: "Path" }),
|
|
3622
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoValueWrap, children: focusedItem.path.replace(/^public\//, "") })
|
|
3141
3623
|
] }),
|
|
3142
|
-
focusedItem.size !== void 0 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
3143
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css:
|
|
3144
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css:
|
|
3624
|
+
focusedItem.size !== void 0 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.infoRow, children: [
|
|
3625
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoLabel, children: "Size" }),
|
|
3626
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoValue, children: formatFileSize3(focusedItem.size) })
|
|
3145
3627
|
] }),
|
|
3146
|
-
focusedItem.dimensions && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
3147
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css:
|
|
3148
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css:
|
|
3628
|
+
focusedItem.dimensions && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.infoRow, children: [
|
|
3629
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoLabel, children: "Dimensions" }),
|
|
3630
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles7.infoValue, children: [
|
|
3149
3631
|
focusedItem.dimensions.width,
|
|
3150
3632
|
" \xD7 ",
|
|
3151
3633
|
focusedItem.dimensions.height
|
|
3152
3634
|
] })
|
|
3153
3635
|
] }),
|
|
3154
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
3155
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css:
|
|
3156
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css:
|
|
3636
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.infoRow, children: [
|
|
3637
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoLabel, children: "CDN Status" }),
|
|
3638
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles7.infoValue, children: focusedItem.cdnSynced ? "Synced" : "Not synced" })
|
|
3157
3639
|
] })
|
|
3158
3640
|
] }),
|
|
3159
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
3160
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css:
|
|
3161
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
3641
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.actions, children: [
|
|
3642
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles7.actionBtn, onClick: () => setShowRenameModal(true), children: [
|
|
3643
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles7.actionIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" }) }),
|
|
3162
3644
|
"Rename"
|
|
3163
3645
|
] }),
|
|
3164
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css:
|
|
3165
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
3166
|
-
"Sync to CDN"
|
|
3646
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles7.actionBtn, onClick: handleSync, disabled: syncing, children: [
|
|
3647
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles7.actionIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" }) }),
|
|
3648
|
+
syncing ? "Syncing..." : "Sync to CDN"
|
|
3167
3649
|
] }),
|
|
3168
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css:
|
|
3169
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
3650
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles7.actionBtn, onClick: () => setShowProcessConfirm(true), children: [
|
|
3651
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles7.actionIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) }),
|
|
3170
3652
|
"Process Image"
|
|
3171
3653
|
] }),
|
|
3172
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: [
|
|
3173
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
3654
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: [styles7.actionBtn, styles7.actionBtnDanger], onClick: () => setShowDeleteConfirm(true), children: [
|
|
3655
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles7.actionIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" }) }),
|
|
3174
3656
|
"Delete"
|
|
3175
3657
|
] })
|
|
3176
3658
|
] })
|
|
@@ -3190,7 +3672,7 @@ function formatFileSize3(bytes) {
|
|
|
3190
3672
|
|
|
3191
3673
|
|
|
3192
3674
|
var btnHeight2 = "36px";
|
|
3193
|
-
var
|
|
3675
|
+
var styles8 = {
|
|
3194
3676
|
btn: _react3.css`
|
|
3195
3677
|
height: ${btnHeight2};
|
|
3196
3678
|
padding: 0 12px;
|
|
@@ -3428,10 +3910,10 @@ var styles7 = {
|
|
|
3428
3910
|
function StudioSettings() {
|
|
3429
3911
|
const [isOpen, setIsOpen] = _react.useState.call(void 0, false);
|
|
3430
3912
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
3431
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css:
|
|
3913
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles8.btn, onClick: () => setIsOpen(true), "aria-label": "Settings", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
3432
3914
|
"svg",
|
|
3433
3915
|
{
|
|
3434
|
-
css:
|
|
3916
|
+
css: styles8.icon,
|
|
3435
3917
|
xmlns: "http://www.w3.org/2000/svg",
|
|
3436
3918
|
viewBox: "0 0 24 24",
|
|
3437
3919
|
fill: "none",
|
|
@@ -3460,58 +3942,133 @@ function SettingsPanel({ onClose }) {
|
|
|
3460
3942
|
setCopied(true);
|
|
3461
3943
|
setTimeout(() => setCopied(false), 2e3);
|
|
3462
3944
|
};
|
|
3463
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css:
|
|
3464
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
3465
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { css:
|
|
3466
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css:
|
|
3945
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles8.overlay, onClick: onClose, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.panel, onClick: (e) => e.stopPropagation(), children: [
|
|
3946
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.header, children: [
|
|
3947
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { css: styles8.title, children: "Settings" }),
|
|
3948
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles8.closeBtn, onClick: onClose, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles8.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })
|
|
3467
3949
|
] }),
|
|
3468
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
3950
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.sections, children: [
|
|
3469
3951
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "section", { children: [
|
|
3470
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css:
|
|
3471
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css:
|
|
3472
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
3473
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css:
|
|
3474
|
-
copied && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css:
|
|
3475
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
3952
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles8.sectionTitle, children: "Cloudflare R2" }),
|
|
3953
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles8.description, children: "Configure in .env.local file:" }),
|
|
3954
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.codeWrapper, children: [
|
|
3955
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles8.copyBtn, onClick: handleCopy, title: "Copy to clipboard", children: [
|
|
3956
|
+
copied && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles8.tooltip, children: "Copied!" }),
|
|
3957
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles8.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" }) })
|
|
3476
3958
|
] }),
|
|
3477
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
3478
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css:
|
|
3479
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css:
|
|
3480
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css:
|
|
3481
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css:
|
|
3482
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css:
|
|
3959
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.code, children: [
|
|
3960
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles8.codeLine, children: "CLOUDFLARE_R2_ACCOUNT_ID=abc123def456ghi789" }),
|
|
3961
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles8.codeLine, children: "CLOUDFLARE_R2_ACCESS_KEY_ID=your_access_key_id_here" }),
|
|
3962
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles8.codeLine, children: "CLOUDFLARE_R2_SECRET_ACCESS_KEY=your_secret_access_key_here" }),
|
|
3963
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles8.codeLine, children: "CLOUDFLARE_R2_BUCKET_NAME=my-images-bucket" }),
|
|
3964
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles8.codeLine, children: "CLOUDFLARE_R2_PUBLIC_URL=https://cdn.yourdomain.com" })
|
|
3483
3965
|
] })
|
|
3484
3966
|
] })
|
|
3485
3967
|
] }),
|
|
3486
3968
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "section", { children: [
|
|
3487
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css:
|
|
3488
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
3969
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles8.sectionTitle, children: "Thumbnail Sizes" }),
|
|
3970
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.grid, children: [
|
|
3489
3971
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
|
|
3490
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css:
|
|
3491
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css:
|
|
3972
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css: styles8.label, children: "Small" }),
|
|
3973
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles8.input, type: "number", defaultValue: 300 })
|
|
3492
3974
|
] }),
|
|
3493
3975
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
|
|
3494
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css:
|
|
3495
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css:
|
|
3976
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css: styles8.label, children: "Medium" }),
|
|
3977
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles8.input, type: "number", defaultValue: 700 })
|
|
3496
3978
|
] }),
|
|
3497
3979
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
|
|
3498
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css:
|
|
3499
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css:
|
|
3980
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css: styles8.label, children: "Large" }),
|
|
3981
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles8.input, type: "number", defaultValue: 1400 })
|
|
3500
3982
|
] })
|
|
3501
3983
|
] })
|
|
3502
3984
|
] })
|
|
3503
3985
|
] }),
|
|
3504
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
3505
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css:
|
|
3506
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css:
|
|
3986
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.footer, children: [
|
|
3987
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles8.cancelBtn, onClick: onClose, children: "Cancel" }),
|
|
3988
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles8.saveBtn, children: "Save Changes" })
|
|
3507
3989
|
] })
|
|
3508
3990
|
] }) });
|
|
3509
3991
|
}
|
|
3510
3992
|
|
|
3993
|
+
// src/components/ErrorModal.tsx
|
|
3994
|
+
|
|
3995
|
+
|
|
3996
|
+
var styles9 = {
|
|
3997
|
+
overlay: _react3.css`
|
|
3998
|
+
position: fixed;
|
|
3999
|
+
inset: 0;
|
|
4000
|
+
background: rgba(0, 0, 0, 0.5);
|
|
4001
|
+
display: flex;
|
|
4002
|
+
align-items: center;
|
|
4003
|
+
justify-content: center;
|
|
4004
|
+
z-index: 1100;
|
|
4005
|
+
`,
|
|
4006
|
+
modal: _react3.css`
|
|
4007
|
+
background: ${_chunkUFCWGUAGjs.colors.surface};
|
|
4008
|
+
border-radius: 12px;
|
|
4009
|
+
padding: 24px;
|
|
4010
|
+
max-width: 400px;
|
|
4011
|
+
width: 90%;
|
|
4012
|
+
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
|
|
4013
|
+
`,
|
|
4014
|
+
header: _react3.css`
|
|
4015
|
+
display: flex;
|
|
4016
|
+
align-items: center;
|
|
4017
|
+
gap: 12px;
|
|
4018
|
+
margin-bottom: 12px;
|
|
4019
|
+
`,
|
|
4020
|
+
icon: _react3.css`
|
|
4021
|
+
width: 24px;
|
|
4022
|
+
height: 24px;
|
|
4023
|
+
color: ${_chunkUFCWGUAGjs.colors.danger};
|
|
4024
|
+
flex-shrink: 0;
|
|
4025
|
+
`,
|
|
4026
|
+
title: _react3.css`
|
|
4027
|
+
font-size: ${_chunkUFCWGUAGjs.fontSize.lg};
|
|
4028
|
+
font-weight: 600;
|
|
4029
|
+
color: ${_chunkUFCWGUAGjs.colors.text};
|
|
4030
|
+
margin: 0;
|
|
4031
|
+
`,
|
|
4032
|
+
message: _react3.css`
|
|
4033
|
+
font-size: ${_chunkUFCWGUAGjs.fontSize.base};
|
|
4034
|
+
color: ${_chunkUFCWGUAGjs.colors.textSecondary};
|
|
4035
|
+
margin: 0 0 20px 0;
|
|
4036
|
+
line-height: 1.5;
|
|
4037
|
+
`,
|
|
4038
|
+
button: _react3.css`
|
|
4039
|
+
width: 100%;
|
|
4040
|
+
padding: 10px 16px;
|
|
4041
|
+
border-radius: 6px;
|
|
4042
|
+
font-size: ${_chunkUFCWGUAGjs.fontSize.base};
|
|
4043
|
+
font-weight: 500;
|
|
4044
|
+
border: none;
|
|
4045
|
+
background: ${_chunkUFCWGUAGjs.colors.primary};
|
|
4046
|
+
color: white;
|
|
4047
|
+
cursor: pointer;
|
|
4048
|
+
transition: background 0.15s ease;
|
|
4049
|
+
|
|
4050
|
+
&:hover {
|
|
4051
|
+
background: ${_chunkUFCWGUAGjs.colors.primaryHover};
|
|
4052
|
+
}
|
|
4053
|
+
`
|
|
4054
|
+
};
|
|
4055
|
+
function ErrorModal() {
|
|
4056
|
+
const { error, clearError } = useStudio();
|
|
4057
|
+
if (!error) return null;
|
|
4058
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles9.overlay, onClick: clearError, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles9.modal, onClick: (e) => e.stopPropagation(), children: [
|
|
4059
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles9.header, children: [
|
|
4060
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles9.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" }) }),
|
|
4061
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles9.title, children: error.title })
|
|
4062
|
+
] }),
|
|
4063
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles9.message, children: error.message }),
|
|
4064
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles9.button, onClick: clearError, children: "OK" })
|
|
4065
|
+
] }) });
|
|
4066
|
+
}
|
|
4067
|
+
|
|
3511
4068
|
// src/components/StudioUI.tsx
|
|
3512
4069
|
|
|
3513
4070
|
var btnHeight3 = "36px";
|
|
3514
|
-
var
|
|
4071
|
+
var styles10 = {
|
|
3515
4072
|
container: _react3.css`
|
|
3516
4073
|
${_chunkUFCWGUAGjs.baseReset}
|
|
3517
4074
|
display: flex;
|
|
@@ -3658,10 +4215,17 @@ function StudioUI({ onClose, isVisible = true }) {
|
|
|
3658
4215
|
const [isLoading, setIsLoading] = _react.useState.call(void 0, false);
|
|
3659
4216
|
const [refreshKey, setRefreshKey] = _react.useState.call(void 0, 0);
|
|
3660
4217
|
const [searchQuery, setSearchQuery] = _react.useState.call(void 0, "");
|
|
4218
|
+
const [error, setError] = _react.useState.call(void 0, null);
|
|
3661
4219
|
const [isDragging, setIsDragging] = _react.useState.call(void 0, false);
|
|
3662
4220
|
const triggerRefresh = _react.useCallback.call(void 0, () => {
|
|
3663
4221
|
setRefreshKey((k) => k + 1);
|
|
3664
4222
|
}, []);
|
|
4223
|
+
const showError = _react.useCallback.call(void 0, (title, message) => {
|
|
4224
|
+
setError({ title, message });
|
|
4225
|
+
}, []);
|
|
4226
|
+
const clearError = _react.useCallback.call(void 0, () => {
|
|
4227
|
+
setError(null);
|
|
4228
|
+
}, []);
|
|
3665
4229
|
const handleDragOver = _react.useCallback.call(void 0, (e) => {
|
|
3666
4230
|
e.preventDefault();
|
|
3667
4231
|
e.stopPropagation();
|
|
@@ -3690,8 +4254,8 @@ function StudioUI({ onClose, isVisible = true }) {
|
|
|
3690
4254
|
method: "POST",
|
|
3691
4255
|
body: formData
|
|
3692
4256
|
});
|
|
3693
|
-
} catch (
|
|
3694
|
-
console.error("Upload error:",
|
|
4257
|
+
} catch (error2) {
|
|
4258
|
+
console.error("Upload error:", error2);
|
|
3695
4259
|
}
|
|
3696
4260
|
}
|
|
3697
4261
|
triggerRefresh();
|
|
@@ -3793,18 +4357,21 @@ function StudioUI({ onClose, isVisible = true }) {
|
|
|
3793
4357
|
refreshKey,
|
|
3794
4358
|
triggerRefresh,
|
|
3795
4359
|
searchQuery,
|
|
3796
|
-
setSearchQuery
|
|
4360
|
+
setSearchQuery,
|
|
4361
|
+
error,
|
|
4362
|
+
showError,
|
|
4363
|
+
clearError
|
|
3797
4364
|
};
|
|
3798
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioContext.Provider, { value: contextValue, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
3799
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
3800
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css:
|
|
3801
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css:
|
|
3802
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
4365
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioContext.Provider, { value: contextValue, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles10.container, children: [
|
|
4366
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles10.header, children: [
|
|
4367
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles10.headerLeft, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h1", { css: styles10.title, children: "Studio" }) }),
|
|
4368
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles10.headerCenter, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Breadcrumbs, { currentPath, onNavigate: setCurrentPath }) }),
|
|
4369
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles10.headerActions, children: [
|
|
3803
4370
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioSettings, {}),
|
|
3804
4371
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3805
4372
|
"button",
|
|
3806
4373
|
{
|
|
3807
|
-
css:
|
|
4374
|
+
css: styles10.headerBtn,
|
|
3808
4375
|
onClick: onClose,
|
|
3809
4376
|
"aria-label": "Close Studio",
|
|
3810
4377
|
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, CloseIcon, {})
|
|
@@ -3816,20 +4383,21 @@ function StudioUI({ onClose, isVisible = true }) {
|
|
|
3816
4383
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
3817
4384
|
"div",
|
|
3818
4385
|
{
|
|
3819
|
-
css:
|
|
4386
|
+
css: styles10.content,
|
|
3820
4387
|
onDragOver: handleDragOver,
|
|
3821
4388
|
onDragLeave: handleDragLeave,
|
|
3822
4389
|
onDrop: handleDrop,
|
|
3823
4390
|
children: [
|
|
3824
|
-
isDragging && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css:
|
|
3825
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
4391
|
+
isDragging && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles10.dropOverlay, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles10.dropMessage, children: [
|
|
4392
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles10.dropIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" }) }),
|
|
3826
4393
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: "Drop files to upload" })
|
|
3827
4394
|
] }) }),
|
|
3828
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css:
|
|
4395
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles10.fileBrowser, children: viewMode === "grid" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioFileGrid, {}) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioFileList, {}) })
|
|
3829
4396
|
]
|
|
3830
4397
|
}
|
|
3831
4398
|
),
|
|
3832
|
-
focusedItem && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioDetailView, {})
|
|
4399
|
+
focusedItem && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioDetailView, {}),
|
|
4400
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, ErrorModal, {})
|
|
3833
4401
|
] }) });
|
|
3834
4402
|
}
|
|
3835
4403
|
function Breadcrumbs({ currentPath, onNavigate }) {
|
|
@@ -3838,12 +4406,12 @@ function Breadcrumbs({ currentPath, onNavigate }) {
|
|
|
3838
4406
|
name: part,
|
|
3839
4407
|
path: parts.slice(0, index + 1).join("/")
|
|
3840
4408
|
}));
|
|
3841
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css:
|
|
3842
|
-
index > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css:
|
|
3843
|
-
index === breadcrumbs.length - 1 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css:
|
|
4409
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles10.breadcrumbs, children: breadcrumbs.map((crumb, index) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
|
|
4410
|
+
index > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles10.breadcrumbSeparator, children: "/" }),
|
|
4411
|
+
index === breadcrumbs.length - 1 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles10.breadcrumbCurrent, children: crumb.name }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3844
4412
|
"span",
|
|
3845
4413
|
{
|
|
3846
|
-
css:
|
|
4414
|
+
css: styles10.breadcrumbItem,
|
|
3847
4415
|
onClick: () => onNavigate(crumb.path),
|
|
3848
4416
|
children: crumb.name
|
|
3849
4417
|
}
|
|
@@ -3854,7 +4422,7 @@ function CloseIcon() {
|
|
|
3854
4422
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
3855
4423
|
"svg",
|
|
3856
4424
|
{
|
|
3857
|
-
css:
|
|
4425
|
+
css: styles10.headerIcon,
|
|
3858
4426
|
xmlns: "http://www.w3.org/2000/svg",
|
|
3859
4427
|
viewBox: "0 0 24 24",
|
|
3860
4428
|
fill: "none",
|
|
@@ -3874,4 +4442,4 @@ var StudioUI_default = StudioUI;
|
|
|
3874
4442
|
|
|
3875
4443
|
|
|
3876
4444
|
exports.StudioUI = StudioUI; exports.default = StudioUI_default;
|
|
3877
|
-
//# sourceMappingURL=StudioUI-
|
|
4445
|
+
//# sourceMappingURL=StudioUI-MVIOZTZH.js.map
|