@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
|
@@ -7,8 +7,8 @@ import {
|
|
|
7
7
|
} from "./chunk-HXE6XCG2.mjs";
|
|
8
8
|
|
|
9
9
|
// src/components/StudioUI.tsx
|
|
10
|
-
import { useEffect as
|
|
11
|
-
import { css as
|
|
10
|
+
import { useEffect as useEffect3, useCallback as useCallback3, useState as useState8 } from "react";
|
|
11
|
+
import { css as css10 } from "@emotion/react";
|
|
12
12
|
|
|
13
13
|
// src/components/StudioContext.tsx
|
|
14
14
|
import { createContext, useContext } from "react";
|
|
@@ -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 = createContext(defaultState);
|
|
@@ -61,7 +66,7 @@ function useStudio() {
|
|
|
61
66
|
|
|
62
67
|
// src/components/StudioToolbar.tsx
|
|
63
68
|
import { useCallback, useRef, useState as useState2 } from "react";
|
|
64
|
-
import { css as
|
|
69
|
+
import { css as css4, keyframes as keyframes3 } from "@emotion/react";
|
|
65
70
|
|
|
66
71
|
// src/components/StudioModal.tsx
|
|
67
72
|
import React from "react";
|
|
@@ -669,14 +674,313 @@ function StudioFolderPicker({ selectedItems, currentPath, onMove, onCancel }) {
|
|
|
669
674
|
] }) });
|
|
670
675
|
}
|
|
671
676
|
|
|
677
|
+
// src/components/R2SetupModal.tsx
|
|
678
|
+
import { css as css3 } from "@emotion/react";
|
|
679
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "@emotion/react/jsx-runtime";
|
|
680
|
+
var styles3 = {
|
|
681
|
+
overlay: css3`
|
|
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: css3`
|
|
692
|
+
background: ${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: css3`
|
|
701
|
+
display: flex;
|
|
702
|
+
align-items: center;
|
|
703
|
+
gap: 12px;
|
|
704
|
+
padding: 20px 24px;
|
|
705
|
+
border-bottom: 1px solid ${colors.border};
|
|
706
|
+
`,
|
|
707
|
+
icon: css3`
|
|
708
|
+
width: 32px;
|
|
709
|
+
height: 32px;
|
|
710
|
+
color: ${colors.primary};
|
|
711
|
+
flex-shrink: 0;
|
|
712
|
+
`,
|
|
713
|
+
title: css3`
|
|
714
|
+
font-size: ${fontSize.xl};
|
|
715
|
+
font-weight: 600;
|
|
716
|
+
color: ${colors.text};
|
|
717
|
+
margin: 0;
|
|
718
|
+
`,
|
|
719
|
+
closeBtn: css3`
|
|
720
|
+
margin-left: auto;
|
|
721
|
+
background: none;
|
|
722
|
+
border: none;
|
|
723
|
+
padding: 4px;
|
|
724
|
+
cursor: pointer;
|
|
725
|
+
color: ${colors.textMuted};
|
|
726
|
+
border-radius: 4px;
|
|
727
|
+
|
|
728
|
+
&:hover {
|
|
729
|
+
color: ${colors.text};
|
|
730
|
+
background: ${colors.surfaceHover};
|
|
731
|
+
}
|
|
732
|
+
`,
|
|
733
|
+
closeIcon: css3`
|
|
734
|
+
width: 20px;
|
|
735
|
+
height: 20px;
|
|
736
|
+
`,
|
|
737
|
+
content: css3`
|
|
738
|
+
padding: 24px;
|
|
739
|
+
`,
|
|
740
|
+
intro: css3`
|
|
741
|
+
font-size: ${fontSize.base};
|
|
742
|
+
color: ${colors.textSecondary};
|
|
743
|
+
margin: 0 0 20px 0;
|
|
744
|
+
line-height: 1.6;
|
|
745
|
+
`,
|
|
746
|
+
steps: css3`
|
|
747
|
+
list-style: none;
|
|
748
|
+
padding: 0;
|
|
749
|
+
margin: 0;
|
|
750
|
+
display: flex;
|
|
751
|
+
flex-direction: column;
|
|
752
|
+
gap: 16px;
|
|
753
|
+
`,
|
|
754
|
+
step: css3`
|
|
755
|
+
display: flex;
|
|
756
|
+
gap: 12px;
|
|
757
|
+
`,
|
|
758
|
+
stepNumber: css3`
|
|
759
|
+
width: 28px;
|
|
760
|
+
height: 28px;
|
|
761
|
+
border-radius: 50%;
|
|
762
|
+
background: ${colors.primaryLight};
|
|
763
|
+
color: ${colors.primary};
|
|
764
|
+
font-size: ${fontSize.sm};
|
|
765
|
+
font-weight: 600;
|
|
766
|
+
display: flex;
|
|
767
|
+
align-items: center;
|
|
768
|
+
justify-content: center;
|
|
769
|
+
flex-shrink: 0;
|
|
770
|
+
`,
|
|
771
|
+
stepContent: css3`
|
|
772
|
+
flex: 1;
|
|
773
|
+
padding-top: 3px;
|
|
774
|
+
`,
|
|
775
|
+
stepTitle: css3`
|
|
776
|
+
font-size: ${fontSize.base};
|
|
777
|
+
font-weight: 500;
|
|
778
|
+
color: ${colors.text};
|
|
779
|
+
margin: 0 0 4px 0;
|
|
780
|
+
`,
|
|
781
|
+
stepDesc: css3`
|
|
782
|
+
font-size: ${fontSize.sm};
|
|
783
|
+
color: ${colors.textSecondary};
|
|
784
|
+
margin: 0;
|
|
785
|
+
line-height: 1.5;
|
|
786
|
+
`,
|
|
787
|
+
link: css3`
|
|
788
|
+
color: ${colors.primary};
|
|
789
|
+
text-decoration: none;
|
|
790
|
+
font-weight: 500;
|
|
791
|
+
|
|
792
|
+
&:hover {
|
|
793
|
+
text-decoration: underline;
|
|
794
|
+
}
|
|
795
|
+
`,
|
|
796
|
+
envVars: css3`
|
|
797
|
+
background: ${colors.background};
|
|
798
|
+
border: 1px solid ${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: ${colors.text};
|
|
806
|
+
overflow-x: auto;
|
|
807
|
+
`,
|
|
808
|
+
envVar: css3`
|
|
809
|
+
display: block;
|
|
810
|
+
`,
|
|
811
|
+
envKey: css3`
|
|
812
|
+
color: ${colors.primary};
|
|
813
|
+
`,
|
|
814
|
+
envValue: css3`
|
|
815
|
+
color: ${colors.textSecondary};
|
|
816
|
+
`,
|
|
817
|
+
footer: css3`
|
|
818
|
+
padding: 16px 24px;
|
|
819
|
+
border-top: 1px solid ${colors.border};
|
|
820
|
+
display: flex;
|
|
821
|
+
justify-content: flex-end;
|
|
822
|
+
gap: 12px;
|
|
823
|
+
`,
|
|
824
|
+
docsBtn: css3`
|
|
825
|
+
padding: 10px 16px;
|
|
826
|
+
border-radius: 6px;
|
|
827
|
+
font-size: ${fontSize.base};
|
|
828
|
+
font-weight: 500;
|
|
829
|
+
border: 1px solid ${colors.border};
|
|
830
|
+
background: ${colors.surface};
|
|
831
|
+
color: ${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: ${colors.surfaceHover};
|
|
841
|
+
border-color: #d0d5dd;
|
|
842
|
+
}
|
|
843
|
+
`,
|
|
844
|
+
doneBtn: css3`
|
|
845
|
+
padding: 10px 20px;
|
|
846
|
+
border-radius: 6px;
|
|
847
|
+
font-size: ${fontSize.base};
|
|
848
|
+
font-weight: 500;
|
|
849
|
+
border: none;
|
|
850
|
+
background: ${colors.primary};
|
|
851
|
+
color: white;
|
|
852
|
+
cursor: pointer;
|
|
853
|
+
transition: background 0.15s ease;
|
|
854
|
+
|
|
855
|
+
&:hover {
|
|
856
|
+
background: ${colors.primaryHover};
|
|
857
|
+
}
|
|
858
|
+
`,
|
|
859
|
+
externalIcon: css3`
|
|
860
|
+
width: 14px;
|
|
861
|
+
height: 14px;
|
|
862
|
+
`
|
|
863
|
+
};
|
|
864
|
+
function R2SetupModal({ isOpen, onClose }) {
|
|
865
|
+
if (!isOpen) return null;
|
|
866
|
+
return /* @__PURE__ */ jsx3("div", { css: styles3.overlay, onClick: onClose, children: /* @__PURE__ */ jsxs3("div", { css: styles3.modal, onClick: (e) => e.stopPropagation(), children: [
|
|
867
|
+
/* @__PURE__ */ jsxs3("div", { css: styles3.header, children: [
|
|
868
|
+
/* @__PURE__ */ jsx3("svg", { css: styles3.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx3("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__ */ jsx3("h2", { css: styles3.title, children: "Set Up CDN Storage" }),
|
|
870
|
+
/* @__PURE__ */ jsx3("button", { css: styles3.closeBtn, onClick: onClose, children: /* @__PURE__ */ jsx3("svg", { css: styles3.closeIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx3("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })
|
|
871
|
+
] }),
|
|
872
|
+
/* @__PURE__ */ jsxs3("div", { css: styles3.content, children: [
|
|
873
|
+
/* @__PURE__ */ jsx3("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__ */ jsxs3("ol", { css: styles3.steps, children: [
|
|
875
|
+
/* @__PURE__ */ jsxs3("li", { css: styles3.step, children: [
|
|
876
|
+
/* @__PURE__ */ jsx3("span", { css: styles3.stepNumber, children: "1" }),
|
|
877
|
+
/* @__PURE__ */ jsxs3("div", { css: styles3.stepContent, children: [
|
|
878
|
+
/* @__PURE__ */ jsx3("h4", { css: styles3.stepTitle, children: "Create a Cloudflare account" }),
|
|
879
|
+
/* @__PURE__ */ jsxs3("p", { css: styles3.stepDesc, children: [
|
|
880
|
+
"Sign up at",
|
|
881
|
+
" ",
|
|
882
|
+
/* @__PURE__ */ jsx3("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__ */ jsxs3("li", { css: styles3.step, children: [
|
|
889
|
+
/* @__PURE__ */ jsx3("span", { css: styles3.stepNumber, children: "2" }),
|
|
890
|
+
/* @__PURE__ */ jsxs3("div", { css: styles3.stepContent, children: [
|
|
891
|
+
/* @__PURE__ */ jsx3("h4", { css: styles3.stepTitle, children: "Create an R2 bucket" }),
|
|
892
|
+
/* @__PURE__ */ jsxs3("p", { css: styles3.stepDesc, children: [
|
|
893
|
+
"Go to R2 in your Cloudflare dashboard and create a new bucket. Choose a name like ",
|
|
894
|
+
/* @__PURE__ */ jsx3("code", { children: "my-images" }),
|
|
895
|
+
"."
|
|
896
|
+
] })
|
|
897
|
+
] })
|
|
898
|
+
] }),
|
|
899
|
+
/* @__PURE__ */ jsxs3("li", { css: styles3.step, children: [
|
|
900
|
+
/* @__PURE__ */ jsx3("span", { css: styles3.stepNumber, children: "3" }),
|
|
901
|
+
/* @__PURE__ */ jsxs3("div", { css: styles3.stepContent, children: [
|
|
902
|
+
/* @__PURE__ */ jsx3("h4", { css: styles3.stepTitle, children: "Enable public access" }),
|
|
903
|
+
/* @__PURE__ */ jsxs3("p", { css: styles3.stepDesc, children: [
|
|
904
|
+
'In bucket settings, enable "Public Access" and copy the public URL (e.g., ',
|
|
905
|
+
/* @__PURE__ */ jsx3("code", { children: "https://pub-xxx.r2.dev" }),
|
|
906
|
+
")."
|
|
907
|
+
] })
|
|
908
|
+
] })
|
|
909
|
+
] }),
|
|
910
|
+
/* @__PURE__ */ jsxs3("li", { css: styles3.step, children: [
|
|
911
|
+
/* @__PURE__ */ jsx3("span", { css: styles3.stepNumber, children: "4" }),
|
|
912
|
+
/* @__PURE__ */ jsxs3("div", { css: styles3.stepContent, children: [
|
|
913
|
+
/* @__PURE__ */ jsx3("h4", { css: styles3.stepTitle, children: "Create API token" }),
|
|
914
|
+
/* @__PURE__ */ jsx3("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__ */ jsxs3("li", { css: styles3.step, children: [
|
|
918
|
+
/* @__PURE__ */ jsx3("span", { css: styles3.stepNumber, children: "5" }),
|
|
919
|
+
/* @__PURE__ */ jsxs3("div", { css: styles3.stepContent, children: [
|
|
920
|
+
/* @__PURE__ */ jsx3("h4", { css: styles3.stepTitle, children: "Add environment variables" }),
|
|
921
|
+
/* @__PURE__ */ jsxs3("p", { css: styles3.stepDesc, children: [
|
|
922
|
+
"Add these to your ",
|
|
923
|
+
/* @__PURE__ */ jsx3("code", { children: ".env.local" }),
|
|
924
|
+
" file:"
|
|
925
|
+
] })
|
|
926
|
+
] })
|
|
927
|
+
] })
|
|
928
|
+
] }),
|
|
929
|
+
/* @__PURE__ */ jsxs3("div", { css: styles3.envVars, children: [
|
|
930
|
+
/* @__PURE__ */ jsxs3("span", { css: styles3.envVar, children: [
|
|
931
|
+
/* @__PURE__ */ jsx3("span", { css: styles3.envKey, children: "CLOUDFLARE_R2_ACCOUNT_ID" }),
|
|
932
|
+
"=",
|
|
933
|
+
/* @__PURE__ */ jsx3("span", { css: styles3.envValue, children: "your_account_id" })
|
|
934
|
+
] }),
|
|
935
|
+
/* @__PURE__ */ jsxs3("span", { css: styles3.envVar, children: [
|
|
936
|
+
/* @__PURE__ */ jsx3("span", { css: styles3.envKey, children: "CLOUDFLARE_R2_ACCESS_KEY_ID" }),
|
|
937
|
+
"=",
|
|
938
|
+
/* @__PURE__ */ jsx3("span", { css: styles3.envValue, children: "your_access_key" })
|
|
939
|
+
] }),
|
|
940
|
+
/* @__PURE__ */ jsxs3("span", { css: styles3.envVar, children: [
|
|
941
|
+
/* @__PURE__ */ jsx3("span", { css: styles3.envKey, children: "CLOUDFLARE_R2_SECRET_ACCESS_KEY" }),
|
|
942
|
+
"=",
|
|
943
|
+
/* @__PURE__ */ jsx3("span", { css: styles3.envValue, children: "your_secret_key" })
|
|
944
|
+
] }),
|
|
945
|
+
/* @__PURE__ */ jsxs3("span", { css: styles3.envVar, children: [
|
|
946
|
+
/* @__PURE__ */ jsx3("span", { css: styles3.envKey, children: "CLOUDFLARE_R2_BUCKET_NAME" }),
|
|
947
|
+
"=",
|
|
948
|
+
/* @__PURE__ */ jsx3("span", { css: styles3.envValue, children: "your_bucket_name" })
|
|
949
|
+
] }),
|
|
950
|
+
/* @__PURE__ */ jsxs3("span", { css: styles3.envVar, children: [
|
|
951
|
+
/* @__PURE__ */ jsx3("span", { css: styles3.envKey, children: "CLOUDFLARE_R2_PUBLIC_URL" }),
|
|
952
|
+
"=",
|
|
953
|
+
/* @__PURE__ */ jsx3("span", { css: styles3.envValue, children: "https://pub-xxx.r2.dev" })
|
|
954
|
+
] })
|
|
955
|
+
] })
|
|
956
|
+
] }),
|
|
957
|
+
/* @__PURE__ */ jsxs3("div", { css: styles3.footer, children: [
|
|
958
|
+
/* @__PURE__ */ jsxs3(
|
|
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__ */ jsx3("svg", { css: styles3.externalIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx3("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__ */ jsx3("button", { css: styles3.doneBtn, onClick: onClose, children: "Got it" })
|
|
972
|
+
] })
|
|
973
|
+
] }) });
|
|
974
|
+
}
|
|
975
|
+
|
|
672
976
|
// src/components/StudioToolbar.tsx
|
|
673
|
-
import { Fragment as Fragment2, jsx as
|
|
977
|
+
import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "@emotion/react/jsx-runtime";
|
|
674
978
|
var btnHeight = "36px";
|
|
675
979
|
var spin = keyframes3`
|
|
676
980
|
to { transform: rotate(360deg); }
|
|
677
981
|
`;
|
|
678
|
-
var
|
|
679
|
-
toolbar:
|
|
982
|
+
var styles4 = {
|
|
983
|
+
toolbar: css4`
|
|
680
984
|
display: flex;
|
|
681
985
|
flex-wrap: nowrap;
|
|
682
986
|
align-items: center;
|
|
@@ -692,21 +996,21 @@ var styles3 = {
|
|
|
692
996
|
padding: 12px 24px;
|
|
693
997
|
}
|
|
694
998
|
`,
|
|
695
|
-
left:
|
|
999
|
+
left: css4`
|
|
696
1000
|
display: flex;
|
|
697
1001
|
flex-wrap: nowrap;
|
|
698
1002
|
flex-shrink: 0;
|
|
699
1003
|
align-items: center;
|
|
700
1004
|
gap: 8px;
|
|
701
1005
|
`,
|
|
702
|
-
right:
|
|
1006
|
+
right: css4`
|
|
703
1007
|
display: flex;
|
|
704
1008
|
flex-wrap: nowrap;
|
|
705
1009
|
flex-shrink: 0;
|
|
706
1010
|
align-items: center;
|
|
707
1011
|
gap: 8px;
|
|
708
1012
|
`,
|
|
709
|
-
btn:
|
|
1013
|
+
btn: css4`
|
|
710
1014
|
display: inline-flex;
|
|
711
1015
|
align-items: center;
|
|
712
1016
|
justify-content: center;
|
|
@@ -733,10 +1037,10 @@ var styles3 = {
|
|
|
733
1037
|
opacity: 0.5;
|
|
734
1038
|
}
|
|
735
1039
|
`,
|
|
736
|
-
btnIconOnly:
|
|
1040
|
+
btnIconOnly: css4`
|
|
737
1041
|
padding: 0 10px;
|
|
738
1042
|
`,
|
|
739
|
-
btnPrimary:
|
|
1043
|
+
btnPrimary: css4`
|
|
740
1044
|
background: ${colors.primary};
|
|
741
1045
|
border-color: ${colors.primary};
|
|
742
1046
|
color: white;
|
|
@@ -746,7 +1050,7 @@ var styles3 = {
|
|
|
746
1050
|
border-color: ${colors.primaryHover};
|
|
747
1051
|
}
|
|
748
1052
|
`,
|
|
749
|
-
btnDanger:
|
|
1053
|
+
btnDanger: css4`
|
|
750
1054
|
color: ${colors.danger};
|
|
751
1055
|
|
|
752
1056
|
&:hover:not(:disabled) {
|
|
@@ -754,14 +1058,14 @@ var styles3 = {
|
|
|
754
1058
|
border-color: ${colors.danger};
|
|
755
1059
|
}
|
|
756
1060
|
`,
|
|
757
|
-
icon:
|
|
1061
|
+
icon: css4`
|
|
758
1062
|
width: 16px;
|
|
759
1063
|
height: 16px;
|
|
760
1064
|
`,
|
|
761
|
-
iconSpin:
|
|
1065
|
+
iconSpin: css4`
|
|
762
1066
|
animation: ${spin} 1s linear infinite;
|
|
763
1067
|
`,
|
|
764
|
-
selectionCount:
|
|
1068
|
+
selectionCount: css4`
|
|
765
1069
|
font-size: ${fontSize.base};
|
|
766
1070
|
color: ${colors.textSecondary};
|
|
767
1071
|
display: flex;
|
|
@@ -769,7 +1073,7 @@ var styles3 = {
|
|
|
769
1073
|
gap: 8px;
|
|
770
1074
|
margin-right: 8px;
|
|
771
1075
|
`,
|
|
772
|
-
clearBtn:
|
|
1076
|
+
clearBtn: css4`
|
|
773
1077
|
color: ${colors.primary};
|
|
774
1078
|
background: none;
|
|
775
1079
|
border: none;
|
|
@@ -782,13 +1086,13 @@ var styles3 = {
|
|
|
782
1086
|
text-decoration: underline;
|
|
783
1087
|
}
|
|
784
1088
|
`,
|
|
785
|
-
divider:
|
|
1089
|
+
divider: css4`
|
|
786
1090
|
width: 1px;
|
|
787
1091
|
height: 24px;
|
|
788
1092
|
background: ${colors.border};
|
|
789
1093
|
margin: 0 4px;
|
|
790
1094
|
`,
|
|
791
|
-
viewToggle:
|
|
1095
|
+
viewToggle: css4`
|
|
792
1096
|
display: flex;
|
|
793
1097
|
align-items: center;
|
|
794
1098
|
height: ${btnHeight};
|
|
@@ -797,12 +1101,12 @@ var styles3 = {
|
|
|
797
1101
|
border-radius: 6px;
|
|
798
1102
|
overflow: hidden;
|
|
799
1103
|
`,
|
|
800
|
-
searchWrapper:
|
|
1104
|
+
searchWrapper: css4`
|
|
801
1105
|
position: relative;
|
|
802
1106
|
display: flex;
|
|
803
1107
|
align-items: center;
|
|
804
1108
|
`,
|
|
805
|
-
searchInput:
|
|
1109
|
+
searchInput: css4`
|
|
806
1110
|
height: ${btnHeight};
|
|
807
1111
|
padding: 0 32px 0 12px;
|
|
808
1112
|
border: 1px solid ${colors.border};
|
|
@@ -823,7 +1127,7 @@ var styles3 = {
|
|
|
823
1127
|
color: ${colors.textMuted};
|
|
824
1128
|
}
|
|
825
1129
|
`,
|
|
826
|
-
searchClearBtn:
|
|
1130
|
+
searchClearBtn: css4`
|
|
827
1131
|
position: absolute;
|
|
828
1132
|
right: 5px;
|
|
829
1133
|
top: 5px;
|
|
@@ -843,7 +1147,7 @@ var styles3 = {
|
|
|
843
1147
|
background: ${colors.primaryHover};
|
|
844
1148
|
}
|
|
845
1149
|
`,
|
|
846
|
-
viewBtn:
|
|
1150
|
+
viewBtn: css4`
|
|
847
1151
|
height: 100%;
|
|
848
1152
|
padding: 0 10px;
|
|
849
1153
|
background: transparent;
|
|
@@ -860,7 +1164,7 @@ var styles3 = {
|
|
|
860
1164
|
background-color: ${colors.surfaceHover};
|
|
861
1165
|
}
|
|
862
1166
|
`,
|
|
863
|
-
viewBtnActive:
|
|
1167
|
+
viewBtnActive: css4`
|
|
864
1168
|
background-color: ${colors.primaryLight};
|
|
865
1169
|
color: ${colors.primary};
|
|
866
1170
|
|
|
@@ -893,6 +1197,8 @@ function StudioToolbar() {
|
|
|
893
1197
|
const [showNewFolderModal, setShowNewFolderModal] = useState2(false);
|
|
894
1198
|
const [showRenameFolderModal, setShowRenameFolderModal] = useState2(false);
|
|
895
1199
|
const [showMoveModal, setShowMoveModal] = useState2(false);
|
|
1200
|
+
const [showR2SetupModal, setShowR2SetupModal] = useState2(false);
|
|
1201
|
+
const [syncing, setSyncing] = useState2(false);
|
|
896
1202
|
const isInImagesFolder = currentPath === "public/images" || currentPath.startsWith("public/images/");
|
|
897
1203
|
const handleUpload = useCallback(() => {
|
|
898
1204
|
fileInputRef.current?.click();
|
|
@@ -1189,9 +1495,60 @@ function StudioToolbar() {
|
|
|
1189
1495
|
});
|
|
1190
1496
|
}
|
|
1191
1497
|
}, [selectedItems, clearSelection, triggerRefresh]);
|
|
1192
|
-
const handleSyncCdn = useCallback(() => {
|
|
1193
|
-
|
|
1194
|
-
|
|
1498
|
+
const handleSyncCdn = useCallback(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 = data.synced?.length || 0;
|
|
1518
|
+
const errorCount = data.errors?.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 (data.error?.includes("R2 not configured") || data.error?.includes("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 = useCallback(async (folderName) => {
|
|
1196
1553
|
setShowNewFolderModal(false);
|
|
1197
1554
|
try {
|
|
@@ -1288,8 +1645,8 @@ function StudioToolbar() {
|
|
|
1288
1645
|
if (focusedItem) {
|
|
1289
1646
|
return null;
|
|
1290
1647
|
}
|
|
1291
|
-
return /* @__PURE__ */
|
|
1292
|
-
showDeleteConfirm && /* @__PURE__ */
|
|
1648
|
+
return /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
1649
|
+
showDeleteConfirm && /* @__PURE__ */ jsx4(
|
|
1293
1650
|
ConfirmModal,
|
|
1294
1651
|
{
|
|
1295
1652
|
title: "Delete Items",
|
|
@@ -1300,7 +1657,7 @@ function StudioToolbar() {
|
|
|
1300
1657
|
onCancel: () => setShowDeleteConfirm(false)
|
|
1301
1658
|
}
|
|
1302
1659
|
),
|
|
1303
|
-
showProcessConfirm && /* @__PURE__ */
|
|
1660
|
+
showProcessConfirm && /* @__PURE__ */ jsx4(
|
|
1304
1661
|
ConfirmModal,
|
|
1305
1662
|
{
|
|
1306
1663
|
title: "Process Images",
|
|
@@ -1310,7 +1667,7 @@ function StudioToolbar() {
|
|
|
1310
1667
|
onCancel: () => setShowProcessConfirm(false)
|
|
1311
1668
|
}
|
|
1312
1669
|
),
|
|
1313
|
-
showProgress && /* @__PURE__ */
|
|
1670
|
+
showProgress && /* @__PURE__ */ jsx4(
|
|
1314
1671
|
ProgressModal,
|
|
1315
1672
|
{
|
|
1316
1673
|
title: "Processing Images",
|
|
@@ -1327,7 +1684,7 @@ function StudioToolbar() {
|
|
|
1327
1684
|
}
|
|
1328
1685
|
}
|
|
1329
1686
|
),
|
|
1330
|
-
showNewFolderModal && /* @__PURE__ */
|
|
1687
|
+
showNewFolderModal && /* @__PURE__ */ jsx4(
|
|
1331
1688
|
InputModal,
|
|
1332
1689
|
{
|
|
1333
1690
|
title: "New Folder",
|
|
@@ -1338,7 +1695,7 @@ function StudioToolbar() {
|
|
|
1338
1695
|
onCancel: () => setShowNewFolderModal(false)
|
|
1339
1696
|
}
|
|
1340
1697
|
),
|
|
1341
|
-
showMoveModal && /* @__PURE__ */
|
|
1698
|
+
showMoveModal && /* @__PURE__ */ jsx4(
|
|
1342
1699
|
StudioFolderPicker,
|
|
1343
1700
|
{
|
|
1344
1701
|
selectedItems,
|
|
@@ -1350,7 +1707,7 @@ function StudioToolbar() {
|
|
|
1350
1707
|
onCancel: () => setShowMoveModal(false)
|
|
1351
1708
|
}
|
|
1352
1709
|
),
|
|
1353
|
-
showRenameFolderModal && selectedFolderPath && /* @__PURE__ */
|
|
1710
|
+
showRenameFolderModal && selectedFolderPath && /* @__PURE__ */ jsx4(
|
|
1354
1711
|
InputModal,
|
|
1355
1712
|
{
|
|
1356
1713
|
title: "Rename Folder",
|
|
@@ -1362,7 +1719,7 @@ function StudioToolbar() {
|
|
|
1362
1719
|
onCancel: () => setShowRenameFolderModal(false)
|
|
1363
1720
|
}
|
|
1364
1721
|
),
|
|
1365
|
-
alertMessage && /* @__PURE__ */
|
|
1722
|
+
alertMessage && /* @__PURE__ */ jsx4(
|
|
1366
1723
|
AlertModal,
|
|
1367
1724
|
{
|
|
1368
1725
|
title: alertMessage.title,
|
|
@@ -1370,8 +1727,15 @@ function StudioToolbar() {
|
|
|
1370
1727
|
onClose: () => setAlertMessage(null)
|
|
1371
1728
|
}
|
|
1372
1729
|
),
|
|
1373
|
-
/* @__PURE__ */
|
|
1374
|
-
|
|
1730
|
+
/* @__PURE__ */ jsx4(
|
|
1731
|
+
R2SetupModal,
|
|
1732
|
+
{
|
|
1733
|
+
isOpen: showR2SetupModal,
|
|
1734
|
+
onClose: () => setShowR2SetupModal(false)
|
|
1735
|
+
}
|
|
1736
|
+
),
|
|
1737
|
+
/* @__PURE__ */ jsxs4("div", { css: styles4.toolbar, children: [
|
|
1738
|
+
/* @__PURE__ */ jsx4(
|
|
1375
1739
|
"input",
|
|
1376
1740
|
{
|
|
1377
1741
|
ref: fileInputRef,
|
|
@@ -1382,87 +1746,87 @@ function StudioToolbar() {
|
|
|
1382
1746
|
style: { display: "none" }
|
|
1383
1747
|
}
|
|
1384
1748
|
),
|
|
1385
|
-
/* @__PURE__ */
|
|
1386
|
-
/* @__PURE__ */
|
|
1749
|
+
/* @__PURE__ */ jsxs4("div", { css: styles4.left, children: [
|
|
1750
|
+
/* @__PURE__ */ jsxs4(
|
|
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: [
|
|
1393
|
-
/* @__PURE__ */
|
|
1757
|
+
/* @__PURE__ */ jsx4(UploadIcon, {}),
|
|
1394
1758
|
uploading ? "Uploading..." : "Upload"
|
|
1395
1759
|
]
|
|
1396
1760
|
}
|
|
1397
1761
|
),
|
|
1398
|
-
/* @__PURE__ */
|
|
1762
|
+
/* @__PURE__ */ jsxs4(
|
|
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,
|
|
1405
1769
|
children: [
|
|
1406
|
-
singleFolderSelected ? /* @__PURE__ */
|
|
1770
|
+
singleFolderSelected ? /* @__PURE__ */ jsx4(RenameIcon, {}) : /* @__PURE__ */ jsx4(FolderPlusIcon, {}),
|
|
1407
1771
|
singleFolderSelected ? "Rename Folder" : "New Folder"
|
|
1408
1772
|
]
|
|
1409
1773
|
}
|
|
1410
1774
|
),
|
|
1411
|
-
/* @__PURE__ */
|
|
1412
|
-
/* @__PURE__ */
|
|
1775
|
+
/* @__PURE__ */ jsx4("div", { css: styles4.divider }),
|
|
1776
|
+
/* @__PURE__ */ jsxs4(
|
|
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,
|
|
1419
1783
|
children: [
|
|
1420
|
-
/* @__PURE__ */
|
|
1784
|
+
/* @__PURE__ */ jsx4(ImageStackIcon, {}),
|
|
1421
1785
|
processing ? "Processing..." : "Process Images"
|
|
1422
1786
|
]
|
|
1423
1787
|
}
|
|
1424
1788
|
),
|
|
1425
|
-
/* @__PURE__ */
|
|
1789
|
+
/* @__PURE__ */ jsxs4(
|
|
1426
1790
|
"button",
|
|
1427
1791
|
{
|
|
1428
|
-
css: [
|
|
1792
|
+
css: [styles4.btn, styles4.btnDanger],
|
|
1429
1793
|
onClick: handleDeleteClick,
|
|
1430
1794
|
disabled: !hasSelection,
|
|
1431
1795
|
children: [
|
|
1432
|
-
/* @__PURE__ */
|
|
1796
|
+
/* @__PURE__ */ jsx4(TrashIcon, {}),
|
|
1433
1797
|
"Delete"
|
|
1434
1798
|
]
|
|
1435
1799
|
}
|
|
1436
1800
|
),
|
|
1437
|
-
/* @__PURE__ */
|
|
1801
|
+
/* @__PURE__ */ jsxs4(
|
|
1438
1802
|
"button",
|
|
1439
1803
|
{
|
|
1440
|
-
css:
|
|
1804
|
+
css: styles4.btn,
|
|
1441
1805
|
onClick: handleMoveClick,
|
|
1442
1806
|
disabled: !hasSelection,
|
|
1443
1807
|
children: [
|
|
1444
|
-
/* @__PURE__ */
|
|
1808
|
+
/* @__PURE__ */ jsx4(MoveIcon, {}),
|
|
1445
1809
|
"Move"
|
|
1446
1810
|
]
|
|
1447
1811
|
}
|
|
1448
1812
|
),
|
|
1449
|
-
/* @__PURE__ */
|
|
1813
|
+
/* @__PURE__ */ jsxs4(
|
|
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
|
-
/* @__PURE__ */
|
|
1457
|
-
"Sync CDN"
|
|
1820
|
+
/* @__PURE__ */ jsx4(CloudIcon, {}),
|
|
1821
|
+
syncing ? "Syncing..." : "Sync CDN"
|
|
1458
1822
|
]
|
|
1459
1823
|
}
|
|
1460
1824
|
),
|
|
1461
|
-
/* @__PURE__ */
|
|
1462
|
-
/* @__PURE__ */
|
|
1825
|
+
/* @__PURE__ */ jsxs4("div", { css: styles4.searchWrapper, children: [
|
|
1826
|
+
/* @__PURE__ */ jsx4(
|
|
1463
1827
|
"input",
|
|
1464
1828
|
{
|
|
1465
|
-
css:
|
|
1829
|
+
css: styles4.searchInput,
|
|
1466
1830
|
type: "text",
|
|
1467
1831
|
placeholder: "Search images...",
|
|
1468
1832
|
value: searchQuery,
|
|
@@ -1470,48 +1834,48 @@ function StudioToolbar() {
|
|
|
1470
1834
|
onKeyDown: handleSearchKeyDown
|
|
1471
1835
|
}
|
|
1472
1836
|
),
|
|
1473
|
-
searchQuery && /* @__PURE__ */
|
|
1837
|
+
searchQuery && /* @__PURE__ */ jsx4(
|
|
1474
1838
|
"button",
|
|
1475
1839
|
{
|
|
1476
|
-
css:
|
|
1840
|
+
css: styles4.searchClearBtn,
|
|
1477
1841
|
onClick: () => setSearchQuery(""),
|
|
1478
1842
|
title: "Clear search",
|
|
1479
|
-
children: /* @__PURE__ */
|
|
1843
|
+
children: /* @__PURE__ */ jsx4("svg", { width: "14", height: "14", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
|
|
1480
1844
|
}
|
|
1481
1845
|
)
|
|
1482
1846
|
] })
|
|
1483
1847
|
] }),
|
|
1484
|
-
/* @__PURE__ */
|
|
1485
|
-
hasSelection && /* @__PURE__ */
|
|
1848
|
+
/* @__PURE__ */ jsxs4("div", { css: styles4.right, children: [
|
|
1849
|
+
hasSelection && /* @__PURE__ */ jsxs4("span", { css: styles4.selectionCount, children: [
|
|
1486
1850
|
selectedItems.size,
|
|
1487
1851
|
" selected",
|
|
1488
|
-
/* @__PURE__ */
|
|
1852
|
+
/* @__PURE__ */ jsx4("button", { css: styles4.clearBtn, onClick: clearSelection, children: "Clear" })
|
|
1489
1853
|
] }),
|
|
1490
|
-
/* @__PURE__ */
|
|
1854
|
+
/* @__PURE__ */ jsx4(
|
|
1491
1855
|
"button",
|
|
1492
1856
|
{
|
|
1493
|
-
css: [
|
|
1857
|
+
css: [styles4.btn, styles4.btnIconOnly],
|
|
1494
1858
|
onClick: handleRefresh,
|
|
1495
|
-
children: /* @__PURE__ */
|
|
1859
|
+
children: /* @__PURE__ */ jsx4(RefreshIcon, { spinning: refreshing })
|
|
1496
1860
|
}
|
|
1497
1861
|
),
|
|
1498
|
-
/* @__PURE__ */
|
|
1499
|
-
/* @__PURE__ */
|
|
1862
|
+
/* @__PURE__ */ jsxs4("div", { css: styles4.viewToggle, children: [
|
|
1863
|
+
/* @__PURE__ */ jsx4(
|
|
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
|
-
children: /* @__PURE__ */
|
|
1869
|
+
children: /* @__PURE__ */ jsx4(GridIcon, {})
|
|
1506
1870
|
}
|
|
1507
1871
|
),
|
|
1508
|
-
/* @__PURE__ */
|
|
1872
|
+
/* @__PURE__ */ jsx4(
|
|
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
|
-
children: /* @__PURE__ */
|
|
1878
|
+
children: /* @__PURE__ */ jsx4(ListIcon, {})
|
|
1515
1879
|
}
|
|
1516
1880
|
)
|
|
1517
1881
|
] })
|
|
@@ -1520,82 +1884,270 @@ function StudioToolbar() {
|
|
|
1520
1884
|
] });
|
|
1521
1885
|
}
|
|
1522
1886
|
function UploadIcon() {
|
|
1523
|
-
return /* @__PURE__ */
|
|
1887
|
+
return /* @__PURE__ */ jsx4("svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4("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__ */
|
|
1890
|
+
return /* @__PURE__ */ jsx4("svg", { css: [styles4.icon, spinning && styles4.iconSpin], fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4("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__ */
|
|
1893
|
+
return /* @__PURE__ */ jsx4("svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4("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__ */
|
|
1896
|
+
return /* @__PURE__ */ jsx4("svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4("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__ */
|
|
1899
|
+
return /* @__PURE__ */ jsx4("svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4("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__ */
|
|
1902
|
+
return /* @__PURE__ */ jsx4("svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4("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__ */
|
|
1905
|
+
return /* @__PURE__ */ jsx4("svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4("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__ */
|
|
1908
|
+
return /* @__PURE__ */ jsx4("svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4("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__ */
|
|
1911
|
+
return /* @__PURE__ */ jsx4("svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6h16M4 10h16M4 14h16M4 18h16" }) });
|
|
1548
1912
|
}
|
|
1549
1913
|
function ImageStackIcon() {
|
|
1550
|
-
return /* @__PURE__ */
|
|
1914
|
+
return /* @__PURE__ */ jsx4("svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4("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" }) });
|
|
1551
1915
|
}
|
|
1552
1916
|
|
|
1553
1917
|
// src/components/StudioFileGrid.tsx
|
|
1554
|
-
import {
|
|
1555
|
-
import { css as
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1918
|
+
import { useState as useState4 } from "react";
|
|
1919
|
+
import { css as css5, keyframes as keyframes4 } from "@emotion/react";
|
|
1920
|
+
|
|
1921
|
+
// src/hooks/useFileList.ts
|
|
1922
|
+
import { useEffect as useEffect2, useState as useState3, useRef as useRef2, useCallback as useCallback2 } from "react";
|
|
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] = useState3([]);
|
|
2022
|
+
const [loading, setLoading] = useState3(true);
|
|
2023
|
+
const isInitialLoad = useRef2(true);
|
|
2024
|
+
const lastPath = useRef2(currentPath);
|
|
2025
|
+
useEffect2(() => {
|
|
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;
|
|
1596
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 = useCallback2((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 = useCallback2((item) => {
|
|
2062
|
+
if (item.type === "folder") {
|
|
2063
|
+
setCurrentPath(item.path);
|
|
2064
|
+
} else {
|
|
2065
|
+
setFocusedItem(item);
|
|
2066
|
+
}
|
|
2067
|
+
}, [setCurrentPath, setFocusedItem]);
|
|
2068
|
+
const handleGenerateThumbnail = useCallback2(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 = useCallback2(() => {
|
|
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
|
+
};
|
|
2105
|
+
}
|
|
2106
|
+
|
|
2107
|
+
// src/components/StudioFileGrid.tsx
|
|
2108
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "@emotion/react/jsx-runtime";
|
|
2109
|
+
var spin2 = keyframes4`
|
|
2110
|
+
to { transform: rotate(360deg); }
|
|
2111
|
+
`;
|
|
2112
|
+
var styles5 = {
|
|
2113
|
+
loading: css5`
|
|
2114
|
+
display: flex;
|
|
2115
|
+
align-items: center;
|
|
2116
|
+
justify-content: center;
|
|
2117
|
+
height: 256px;
|
|
1597
2118
|
`,
|
|
1598
|
-
|
|
2119
|
+
spinner: css5`
|
|
2120
|
+
width: 32px;
|
|
2121
|
+
height: 32px;
|
|
2122
|
+
border-radius: 50%;
|
|
2123
|
+
border: 3px solid ${colors.border};
|
|
2124
|
+
border-top-color: ${colors.primary};
|
|
2125
|
+
animation: ${spin2} 0.8s linear infinite;
|
|
2126
|
+
`,
|
|
2127
|
+
empty: css5`
|
|
2128
|
+
display: flex;
|
|
2129
|
+
flex-direction: column;
|
|
2130
|
+
align-items: center;
|
|
2131
|
+
justify-content: center;
|
|
2132
|
+
height: 256px;
|
|
2133
|
+
color: ${colors.textSecondary};
|
|
2134
|
+
`,
|
|
2135
|
+
emptyIcon: css5`
|
|
2136
|
+
width: 48px;
|
|
2137
|
+
height: 48px;
|
|
2138
|
+
margin-bottom: 16px;
|
|
2139
|
+
opacity: 0.5;
|
|
2140
|
+
`,
|
|
2141
|
+
emptyText: css5`
|
|
2142
|
+
font-size: ${fontSize.base};
|
|
2143
|
+
margin: 0 0 4px 0;
|
|
2144
|
+
|
|
2145
|
+
&:last-child {
|
|
2146
|
+
color: ${colors.textMuted};
|
|
2147
|
+
font-size: ${fontSize.sm};
|
|
2148
|
+
}
|
|
2149
|
+
`,
|
|
2150
|
+
grid: css5`
|
|
1599
2151
|
display: grid;
|
|
1600
2152
|
grid-template-columns: 1fr;
|
|
1601
2153
|
gap: 12px;
|
|
@@ -1605,7 +2157,7 @@ var styles4 = {
|
|
|
1605
2157
|
@media (min-width: 1024px) { grid-template-columns: repeat(4, 1fr); }
|
|
1606
2158
|
@media (min-width: 1280px) { grid-template-columns: repeat(5, 1fr); }
|
|
1607
2159
|
`,
|
|
1608
|
-
item:
|
|
2160
|
+
item: css5`
|
|
1609
2161
|
position: relative;
|
|
1610
2162
|
border-radius: 8px;
|
|
1611
2163
|
border: 1px solid ${colors.border};
|
|
@@ -1621,7 +2173,7 @@ var styles4 = {
|
|
|
1621
2173
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.06);
|
|
1622
2174
|
}
|
|
1623
2175
|
`,
|
|
1624
|
-
itemSelected:
|
|
2176
|
+
itemSelected: css5`
|
|
1625
2177
|
border-color: ${colors.primary};
|
|
1626
2178
|
box-shadow: 0 0 0 1px ${colors.primary};
|
|
1627
2179
|
|
|
@@ -1630,14 +2182,14 @@ var styles4 = {
|
|
|
1630
2182
|
box-shadow: 0 0 0 1px ${colors.primary};
|
|
1631
2183
|
}
|
|
1632
2184
|
`,
|
|
1633
|
-
parentItem:
|
|
2185
|
+
parentItem: css5`
|
|
1634
2186
|
cursor: pointer;
|
|
1635
2187
|
|
|
1636
2188
|
&:hover {
|
|
1637
2189
|
border-color: ${colors.primary};
|
|
1638
2190
|
}
|
|
1639
2191
|
`,
|
|
1640
|
-
checkboxWrapper:
|
|
2192
|
+
checkboxWrapper: css5`
|
|
1641
2193
|
position: absolute;
|
|
1642
2194
|
top: 0;
|
|
1643
2195
|
left: 0;
|
|
@@ -1645,13 +2197,13 @@ var styles4 = {
|
|
|
1645
2197
|
padding: 8px;
|
|
1646
2198
|
cursor: pointer;
|
|
1647
2199
|
`,
|
|
1648
|
-
checkbox:
|
|
2200
|
+
checkbox: css5`
|
|
1649
2201
|
width: 18px;
|
|
1650
2202
|
height: 18px;
|
|
1651
2203
|
accent-color: ${colors.primary};
|
|
1652
2204
|
cursor: pointer;
|
|
1653
2205
|
`,
|
|
1654
|
-
cdnBadge:
|
|
2206
|
+
cdnBadge: css5`
|
|
1655
2207
|
position: absolute;
|
|
1656
2208
|
top: 8px;
|
|
1657
2209
|
right: 8px;
|
|
@@ -1663,7 +2215,7 @@ var styles4 = {
|
|
|
1663
2215
|
padding: 2px 8px;
|
|
1664
2216
|
border-radius: 4px;
|
|
1665
2217
|
`,
|
|
1666
|
-
content:
|
|
2218
|
+
content: css5`
|
|
1667
2219
|
position: relative;
|
|
1668
2220
|
aspect-ratio: 1;
|
|
1669
2221
|
display: flex;
|
|
@@ -1672,20 +2224,20 @@ var styles4 = {
|
|
|
1672
2224
|
padding: 16px;
|
|
1673
2225
|
background: ${colors.background};
|
|
1674
2226
|
`,
|
|
1675
|
-
folderIcon:
|
|
2227
|
+
folderIcon: css5`
|
|
1676
2228
|
width: 56px;
|
|
1677
2229
|
height: 56px;
|
|
1678
2230
|
color: #f9935e;
|
|
1679
2231
|
`,
|
|
1680
|
-
imagesFolderIcon:
|
|
2232
|
+
imagesFolderIcon: css5`
|
|
1681
2233
|
width: 56px;
|
|
1682
2234
|
height: 56px;
|
|
1683
2235
|
color: ${colors.imagesFolder};
|
|
1684
2236
|
`,
|
|
1685
|
-
imagesFolderWrapper:
|
|
2237
|
+
imagesFolderWrapper: css5`
|
|
1686
2238
|
position: relative;
|
|
1687
2239
|
`,
|
|
1688
|
-
lockIcon:
|
|
2240
|
+
lockIcon: css5`
|
|
1689
2241
|
position: absolute;
|
|
1690
2242
|
bottom: 4px;
|
|
1691
2243
|
right: 4px;
|
|
@@ -1696,23 +2248,23 @@ var styles4 = {
|
|
|
1696
2248
|
border-radius: 50%;
|
|
1697
2249
|
padding: 2px;
|
|
1698
2250
|
`,
|
|
1699
|
-
parentIcon:
|
|
2251
|
+
parentIcon: css5`
|
|
1700
2252
|
width: 56px;
|
|
1701
2253
|
height: 56px;
|
|
1702
2254
|
color: ${colors.textMuted};
|
|
1703
2255
|
`,
|
|
1704
|
-
fileIcon:
|
|
2256
|
+
fileIcon: css5`
|
|
1705
2257
|
width: 40px;
|
|
1706
2258
|
height: 40px;
|
|
1707
2259
|
color: ${colors.textMuted};
|
|
1708
2260
|
`,
|
|
1709
|
-
image:
|
|
2261
|
+
image: css5`
|
|
1710
2262
|
max-width: 100%;
|
|
1711
2263
|
max-height: 100%;
|
|
1712
2264
|
object-fit: contain;
|
|
1713
2265
|
border-radius: 4px;
|
|
1714
2266
|
`,
|
|
1715
|
-
noThumbnail:
|
|
2267
|
+
noThumbnail: css5`
|
|
1716
2268
|
display: flex;
|
|
1717
2269
|
flex-direction: column;
|
|
1718
2270
|
align-items: center;
|
|
@@ -1732,31 +2284,31 @@ var styles4 = {
|
|
|
1732
2284
|
background: ${colors.surfaceHover};
|
|
1733
2285
|
}
|
|
1734
2286
|
`,
|
|
1735
|
-
noThumbnailIcon:
|
|
2287
|
+
noThumbnailIcon: css5`
|
|
1736
2288
|
width: 32px;
|
|
1737
2289
|
height: 32px;
|
|
1738
2290
|
color: ${colors.textMuted};
|
|
1739
2291
|
`,
|
|
1740
|
-
noThumbnailText:
|
|
2292
|
+
noThumbnailText: css5`
|
|
1741
2293
|
font-size: ${fontSize.xs};
|
|
1742
2294
|
color: ${colors.textMuted};
|
|
1743
2295
|
text-align: center;
|
|
1744
2296
|
`,
|
|
1745
|
-
label:
|
|
2297
|
+
label: css5`
|
|
1746
2298
|
padding: 10px 12px;
|
|
1747
2299
|
background-color: ${colors.surface};
|
|
1748
2300
|
border-top: 1px solid ${colors.borderLight};
|
|
1749
2301
|
`,
|
|
1750
|
-
labelRow:
|
|
2302
|
+
labelRow: css5`
|
|
1751
2303
|
display: flex;
|
|
1752
2304
|
flex-direction: column;
|
|
1753
2305
|
gap: 2px;
|
|
1754
2306
|
`,
|
|
1755
|
-
labelText:
|
|
2307
|
+
labelText: css5`
|
|
1756
2308
|
flex: 1;
|
|
1757
2309
|
min-width: 0;
|
|
1758
2310
|
`,
|
|
1759
|
-
copyBtn:
|
|
2311
|
+
copyBtn: css5`
|
|
1760
2312
|
position: absolute;
|
|
1761
2313
|
top: 4px;
|
|
1762
2314
|
right: 4px;
|
|
@@ -1778,11 +2330,11 @@ var styles4 = {
|
|
|
1778
2330
|
color: ${colors.text};
|
|
1779
2331
|
}
|
|
1780
2332
|
`,
|
|
1781
|
-
copyIcon:
|
|
2333
|
+
copyIcon: css5`
|
|
1782
2334
|
width: 18px;
|
|
1783
2335
|
height: 18px;
|
|
1784
2336
|
`,
|
|
1785
|
-
tooltip:
|
|
2337
|
+
tooltip: css5`
|
|
1786
2338
|
position: absolute;
|
|
1787
2339
|
top: 50%;
|
|
1788
2340
|
right: 100%;
|
|
@@ -1807,7 +2359,7 @@ var styles4 = {
|
|
|
1807
2359
|
border-left-color: #1a1f36;
|
|
1808
2360
|
}
|
|
1809
2361
|
`,
|
|
1810
|
-
openBtn:
|
|
2362
|
+
openBtn: css5`
|
|
1811
2363
|
position: absolute;
|
|
1812
2364
|
bottom: 8px;
|
|
1813
2365
|
right: 8px;
|
|
@@ -1831,7 +2383,7 @@ var styles4 = {
|
|
|
1831
2383
|
border-color: ${colors.primary};
|
|
1832
2384
|
}
|
|
1833
2385
|
`,
|
|
1834
|
-
name:
|
|
2386
|
+
name: css5`
|
|
1835
2387
|
font-size: ${fontSize.sm};
|
|
1836
2388
|
font-weight: 500;
|
|
1837
2389
|
color: ${colors.text};
|
|
@@ -1841,12 +2393,12 @@ var styles4 = {
|
|
|
1841
2393
|
margin: 0;
|
|
1842
2394
|
letter-spacing: -0.01em;
|
|
1843
2395
|
`,
|
|
1844
|
-
size:
|
|
2396
|
+
size: css5`
|
|
1845
2397
|
font-size: ${fontSize.xs};
|
|
1846
2398
|
color: ${colors.textMuted};
|
|
1847
2399
|
margin: 2px 0 0 0;
|
|
1848
2400
|
`,
|
|
1849
|
-
selectAllRow:
|
|
2401
|
+
selectAllRow: css5`
|
|
1850
2402
|
display: flex;
|
|
1851
2403
|
align-items: center;
|
|
1852
2404
|
margin-bottom: 16px;
|
|
@@ -1855,7 +2407,7 @@ var styles4 = {
|
|
|
1855
2407
|
border-radius: 8px;
|
|
1856
2408
|
border: 1px solid ${colors.border};
|
|
1857
2409
|
`,
|
|
1858
|
-
selectAllLabel:
|
|
2410
|
+
selectAllLabel: css5`
|
|
1859
2411
|
display: flex;
|
|
1860
2412
|
align-items: center;
|
|
1861
2413
|
gap: 10px;
|
|
@@ -1868,100 +2420,44 @@ var styles4 = {
|
|
|
1868
2420
|
color: ${colors.text};
|
|
1869
2421
|
}
|
|
1870
2422
|
`,
|
|
1871
|
-
selectAllCheckbox:
|
|
2423
|
+
selectAllCheckbox: css5`
|
|
1872
2424
|
width: 16px;
|
|
1873
2425
|
height: 16px;
|
|
1874
2426
|
accent-color: ${colors.primary};
|
|
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__ */
|
|
2445
|
+
return /* @__PURE__ */ jsx5("div", { css: styles5.loading, children: /* @__PURE__ */ jsx5("div", { css: styles5.spinner }) });
|
|
1907
2446
|
}
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
/* @__PURE__ */
|
|
1912
|
-
/* @__PURE__ */
|
|
1913
|
-
/* @__PURE__ */ jsx4("p", { css: styles4.emptyText, children: "Upload images to get started" })
|
|
2447
|
+
if (sortedItems.length === 0 && isAtRoot) {
|
|
2448
|
+
return /* @__PURE__ */ jsxs5("div", { css: styles5.empty, children: [
|
|
2449
|
+
/* @__PURE__ */ jsx5("svg", { css: styles5.emptyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5("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__ */ jsx5("p", { css: styles5.emptyText, children: "No files in this folder" }),
|
|
2451
|
+
/* @__PURE__ */ jsx5("p", { css: styles5.emptyText, children: "Upload images to get started" })
|
|
1914
2452
|
] });
|
|
1915
2453
|
}
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
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
|
-
return /* @__PURE__ */ jsxs4("div", { children: [
|
|
1959
|
-
sortedItems.length > 0 && /* @__PURE__ */ jsx4("div", { css: styles4.selectAllRow, children: /* @__PURE__ */ jsxs4("label", { css: styles4.selectAllLabel, children: [
|
|
1960
|
-
/* @__PURE__ */ jsx4(
|
|
2454
|
+
return /* @__PURE__ */ jsxs5("div", { children: [
|
|
2455
|
+
sortedItems.length > 0 && /* @__PURE__ */ jsx5("div", { css: styles5.selectAllRow, children: /* @__PURE__ */ jsxs5("label", { css: styles5.selectAllLabel, children: [
|
|
2456
|
+
/* @__PURE__ */ jsx5(
|
|
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,22 +2469,22 @@ function StudioFileGrid() {
|
|
|
1973
2469
|
sortedItems.length,
|
|
1974
2470
|
")"
|
|
1975
2471
|
] }) }),
|
|
1976
|
-
/* @__PURE__ */
|
|
1977
|
-
!isAtRoot && !isSearching && /* @__PURE__ */
|
|
2472
|
+
/* @__PURE__ */ jsxs5("div", { css: styles5.grid, children: [
|
|
2473
|
+
!isAtRoot && !isSearching && /* @__PURE__ */ jsxs5(
|
|
1978
2474
|
"div",
|
|
1979
2475
|
{
|
|
1980
|
-
css: [
|
|
2476
|
+
css: [styles5.item, styles5.parentItem],
|
|
1981
2477
|
onClick: navigateUp,
|
|
1982
2478
|
children: [
|
|
1983
|
-
/* @__PURE__ */
|
|
1984
|
-
/* @__PURE__ */
|
|
1985
|
-
/* @__PURE__ */
|
|
1986
|
-
/* @__PURE__ */
|
|
2479
|
+
/* @__PURE__ */ jsx5("div", { css: styles5.content, children: /* @__PURE__ */ jsx5("svg", { css: styles5.parentIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M3 10h10a8 8 0 018 8v2M3 10l6 6m-6-6l6-6" }) }) }),
|
|
2480
|
+
/* @__PURE__ */ jsxs5("div", { css: styles5.label, children: [
|
|
2481
|
+
/* @__PURE__ */ jsx5("p", { css: styles5.name, children: ".." }),
|
|
2482
|
+
/* @__PURE__ */ jsx5("p", { css: styles5.size, children: "Parent folder" })
|
|
1987
2483
|
] })
|
|
1988
2484
|
]
|
|
1989
2485
|
}
|
|
1990
2486
|
),
|
|
1991
|
-
sortedItems.map((item) => /* @__PURE__ */
|
|
2487
|
+
sortedItems.map((item) => /* @__PURE__ */ jsx5(
|
|
1992
2488
|
GridItem,
|
|
1993
2489
|
{
|
|
1994
2490
|
item,
|
|
@@ -2003,7 +2499,7 @@ function StudioFileGrid() {
|
|
|
2003
2499
|
] });
|
|
2004
2500
|
}
|
|
2005
2501
|
function GridItem({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
|
|
2006
|
-
const [showCopied, setShowCopied] =
|
|
2502
|
+
const [showCopied, setShowCopied] = useState4(false);
|
|
2007
2503
|
const isFolder = item.type === "folder";
|
|
2008
2504
|
const isImage = !isFolder && item.thumbnail !== void 0;
|
|
2009
2505
|
const isImagesFolder = isFolder && (item.name === "images" || item.path.includes("/images/"));
|
|
@@ -2014,46 +2510,46 @@ function GridItem({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
|
|
|
2014
2510
|
setShowCopied(true);
|
|
2015
2511
|
setTimeout(() => setShowCopied(false), 1500);
|
|
2016
2512
|
};
|
|
2017
|
-
return /* @__PURE__ */
|
|
2513
|
+
return /* @__PURE__ */ jsxs5(
|
|
2018
2514
|
"div",
|
|
2019
2515
|
{
|
|
2020
|
-
css: [
|
|
2516
|
+
css: [styles5.item, isSelected && styles5.itemSelected],
|
|
2021
2517
|
onClick,
|
|
2022
2518
|
children: [
|
|
2023
|
-
/* @__PURE__ */
|
|
2519
|
+
/* @__PURE__ */ jsx5(
|
|
2024
2520
|
"div",
|
|
2025
2521
|
{
|
|
2026
|
-
css:
|
|
2522
|
+
css: styles5.checkboxWrapper,
|
|
2027
2523
|
onClick: (e) => e.stopPropagation(),
|
|
2028
|
-
children: /* @__PURE__ */
|
|
2524
|
+
children: /* @__PURE__ */ jsx5(
|
|
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__ */
|
|
2040
|
-
/* @__PURE__ */
|
|
2041
|
-
/* @__PURE__ */
|
|
2535
|
+
item.cdnSynced && /* @__PURE__ */ jsx5("span", { css: styles5.cdnBadge, children: "CDN" }),
|
|
2536
|
+
/* @__PURE__ */ jsxs5("div", { css: styles5.content, children: [
|
|
2537
|
+
/* @__PURE__ */ jsxs5(
|
|
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__ */
|
|
2049
|
-
/* @__PURE__ */
|
|
2544
|
+
showCopied && /* @__PURE__ */ jsx5("span", { css: styles5.tooltip, children: "Copied!" }),
|
|
2545
|
+
/* @__PURE__ */ jsx5("svg", { css: styles5.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5("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
|
-
/* @__PURE__ */
|
|
2549
|
+
/* @__PURE__ */ jsx5(
|
|
2054
2550
|
"button",
|
|
2055
2551
|
{
|
|
2056
|
-
css:
|
|
2552
|
+
css: styles5.openBtn,
|
|
2057
2553
|
onClick: (e) => {
|
|
2058
2554
|
e.stopPropagation();
|
|
2059
2555
|
onOpen();
|
|
@@ -2061,40 +2557,40 @@ function GridItem({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
|
|
|
2061
2557
|
children: "Open"
|
|
2062
2558
|
}
|
|
2063
2559
|
),
|
|
2064
|
-
isFolder ? isImagesFolder ? /* @__PURE__ */
|
|
2065
|
-
/* @__PURE__ */
|
|
2066
|
-
/* @__PURE__ */
|
|
2067
|
-
] }) : /* @__PURE__ */
|
|
2560
|
+
isFolder ? isImagesFolder ? /* @__PURE__ */ jsxs5("div", { css: styles5.imagesFolderWrapper, children: [
|
|
2561
|
+
/* @__PURE__ */ jsx5("svg", { css: styles5.imagesFolderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5("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__ */ jsx5("svg", { css: styles5.lockIcon, fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx5("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__ */ jsx5("svg", { css: styles5.folderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5("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__ */ jsx5(
|
|
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"
|
|
2074
2570
|
}
|
|
2075
|
-
) : isImage && !item.hasThumbnail ? /* @__PURE__ */
|
|
2571
|
+
) : isImage && !item.hasThumbnail ? /* @__PURE__ */ jsxs5(
|
|
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__ */
|
|
2086
|
-
/* @__PURE__ */
|
|
2581
|
+
/* @__PURE__ */ jsx5("svg", { css: styles5.noThumbnailIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5("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__ */ jsx5("span", { css: styles5.noThumbnailText, children: "Generate" })
|
|
2087
2583
|
]
|
|
2088
2584
|
}
|
|
2089
|
-
) : /* @__PURE__ */
|
|
2585
|
+
) : /* @__PURE__ */ jsx5("svg", { css: styles5.fileIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" }) })
|
|
2090
2586
|
] }),
|
|
2091
|
-
/* @__PURE__ */
|
|
2092
|
-
/* @__PURE__ */
|
|
2093
|
-
isFolder ? /* @__PURE__ */
|
|
2587
|
+
/* @__PURE__ */ jsx5("div", { css: styles5.label, children: /* @__PURE__ */ jsx5("div", { css: styles5.labelRow, children: /* @__PURE__ */ jsxs5("div", { css: styles5.labelText, children: [
|
|
2588
|
+
/* @__PURE__ */ jsx5("p", { css: styles5.name, title: item.name, children: truncateMiddle(item.name) }),
|
|
2589
|
+
isFolder ? /* @__PURE__ */ jsxs5("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__ */
|
|
2593
|
+
] }) : item.size !== void 0 && /* @__PURE__ */ jsx5("p", { css: styles5.size, children: formatFileSize(item.size) })
|
|
2098
2594
|
] }) }) })
|
|
2099
2595
|
]
|
|
2100
2596
|
}
|
|
@@ -2120,20 +2616,20 @@ function truncateMiddle(str, maxLength = 24) {
|
|
|
2120
2616
|
}
|
|
2121
2617
|
|
|
2122
2618
|
// src/components/StudioFileList.tsx
|
|
2123
|
-
import {
|
|
2124
|
-
import { css as
|
|
2125
|
-
import { jsx as
|
|
2619
|
+
import { useState as useState5 } from "react";
|
|
2620
|
+
import { css as css6, keyframes as keyframes5 } from "@emotion/react";
|
|
2621
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "@emotion/react/jsx-runtime";
|
|
2126
2622
|
var spin3 = keyframes5`
|
|
2127
2623
|
to { transform: rotate(360deg); }
|
|
2128
2624
|
`;
|
|
2129
|
-
var
|
|
2130
|
-
loading:
|
|
2625
|
+
var styles6 = {
|
|
2626
|
+
loading: css6`
|
|
2131
2627
|
display: flex;
|
|
2132
2628
|
align-items: center;
|
|
2133
2629
|
justify-content: center;
|
|
2134
2630
|
height: 256px;
|
|
2135
2631
|
`,
|
|
2136
|
-
spinner:
|
|
2632
|
+
spinner: css6`
|
|
2137
2633
|
width: 32px;
|
|
2138
2634
|
height: 32px;
|
|
2139
2635
|
border-radius: 50%;
|
|
@@ -2141,7 +2637,7 @@ var styles5 = {
|
|
|
2141
2637
|
border-top-color: ${colors.primary};
|
|
2142
2638
|
animation: ${spin3} 0.8s linear infinite;
|
|
2143
2639
|
`,
|
|
2144
|
-
empty:
|
|
2640
|
+
empty: css6`
|
|
2145
2641
|
display: flex;
|
|
2146
2642
|
flex-direction: column;
|
|
2147
2643
|
align-items: center;
|
|
@@ -2149,19 +2645,19 @@ var styles5 = {
|
|
|
2149
2645
|
height: 256px;
|
|
2150
2646
|
color: ${colors.textSecondary};
|
|
2151
2647
|
`,
|
|
2152
|
-
tableWrapper:
|
|
2648
|
+
tableWrapper: css6`
|
|
2153
2649
|
background: ${colors.surface};
|
|
2154
2650
|
border-radius: 8px;
|
|
2155
2651
|
border: 1px solid ${colors.border};
|
|
2156
2652
|
overflow-x: auto;
|
|
2157
2653
|
`,
|
|
2158
|
-
table:
|
|
2654
|
+
table: css6`
|
|
2159
2655
|
width: 100%;
|
|
2160
2656
|
min-width: 600px;
|
|
2161
2657
|
border-collapse: collapse;
|
|
2162
2658
|
white-space: nowrap;
|
|
2163
2659
|
`,
|
|
2164
|
-
th:
|
|
2660
|
+
th: css6`
|
|
2165
2661
|
text-align: left;
|
|
2166
2662
|
font-size: 11px;
|
|
2167
2663
|
color: ${colors.textMuted};
|
|
@@ -2172,20 +2668,20 @@ var styles5 = {
|
|
|
2172
2668
|
background: ${colors.background};
|
|
2173
2669
|
border-bottom: 1px solid ${colors.border};
|
|
2174
2670
|
`,
|
|
2175
|
-
thCheckbox:
|
|
2671
|
+
thCheckbox: css6`
|
|
2176
2672
|
width: 48px;
|
|
2177
2673
|
`,
|
|
2178
|
-
thSize:
|
|
2674
|
+
thSize: css6`
|
|
2179
2675
|
width: 96px;
|
|
2180
2676
|
`,
|
|
2181
|
-
thDimensions:
|
|
2677
|
+
thDimensions: css6`
|
|
2182
2678
|
width: 128px;
|
|
2183
2679
|
`,
|
|
2184
|
-
thCdn:
|
|
2680
|
+
thCdn: css6`
|
|
2185
2681
|
width: 96px;
|
|
2186
2682
|
`,
|
|
2187
|
-
tbody:
|
|
2188
|
-
row:
|
|
2683
|
+
tbody: css6``,
|
|
2684
|
+
row: css6`
|
|
2189
2685
|
cursor: pointer;
|
|
2190
2686
|
transition: background-color 0.15s ease;
|
|
2191
2687
|
user-select: none;
|
|
@@ -2198,14 +2694,14 @@ var styles5 = {
|
|
|
2198
2694
|
border-bottom: 1px solid ${colors.borderLight};
|
|
2199
2695
|
}
|
|
2200
2696
|
`,
|
|
2201
|
-
rowSelected:
|
|
2697
|
+
rowSelected: css6`
|
|
2202
2698
|
background-color: ${colors.primaryLight};
|
|
2203
2699
|
|
|
2204
2700
|
&:hover {
|
|
2205
2701
|
background-color: ${colors.primaryLight};
|
|
2206
2702
|
}
|
|
2207
2703
|
`,
|
|
2208
|
-
parentRow:
|
|
2704
|
+
parentRow: css6`
|
|
2209
2705
|
cursor: pointer;
|
|
2210
2706
|
border-bottom: 1px solid ${colors.border};
|
|
2211
2707
|
|
|
@@ -2213,22 +2709,22 @@ var styles5 = {
|
|
|
2213
2709
|
background-color: ${colors.surfaceHover};
|
|
2214
2710
|
}
|
|
2215
2711
|
`,
|
|
2216
|
-
td:
|
|
2712
|
+
td: css6`
|
|
2217
2713
|
padding: 12px 16px;
|
|
2218
2714
|
`,
|
|
2219
|
-
checkboxCell:
|
|
2715
|
+
checkboxCell: css6`
|
|
2220
2716
|
padding: 12px 16px;
|
|
2221
2717
|
cursor: pointer;
|
|
2222
2718
|
vertical-align: middle;
|
|
2223
2719
|
`,
|
|
2224
|
-
checkbox:
|
|
2720
|
+
checkbox: css6`
|
|
2225
2721
|
width: 18px;
|
|
2226
2722
|
height: 18px;
|
|
2227
2723
|
accent-color: ${colors.primary};
|
|
2228
2724
|
cursor: pointer;
|
|
2229
2725
|
display: block;
|
|
2230
2726
|
`,
|
|
2231
|
-
actionsCell:
|
|
2727
|
+
actionsCell: css6`
|
|
2232
2728
|
display: flex;
|
|
2233
2729
|
align-items: center;
|
|
2234
2730
|
justify-content: flex-end;
|
|
@@ -2236,7 +2732,7 @@ var styles5 = {
|
|
|
2236
2732
|
margin-left: auto;
|
|
2237
2733
|
flex-shrink: 0;
|
|
2238
2734
|
`,
|
|
2239
|
-
copyBtn:
|
|
2735
|
+
copyBtn: css6`
|
|
2240
2736
|
position: relative;
|
|
2241
2737
|
flex-shrink: 0;
|
|
2242
2738
|
height: 32px;
|
|
@@ -2259,11 +2755,11 @@ var styles5 = {
|
|
|
2259
2755
|
color: ${colors.text};
|
|
2260
2756
|
}
|
|
2261
2757
|
`,
|
|
2262
|
-
copyIcon:
|
|
2758
|
+
copyIcon: css6`
|
|
2263
2759
|
width: 16px;
|
|
2264
2760
|
height: 16px;
|
|
2265
2761
|
`,
|
|
2266
|
-
tooltip:
|
|
2762
|
+
tooltip: css6`
|
|
2267
2763
|
position: absolute;
|
|
2268
2764
|
top: 50%;
|
|
2269
2765
|
right: 100%;
|
|
@@ -2288,13 +2784,13 @@ var styles5 = {
|
|
|
2288
2784
|
border-left-color: #1a1f36;
|
|
2289
2785
|
}
|
|
2290
2786
|
`,
|
|
2291
|
-
nameCell:
|
|
2787
|
+
nameCell: css6`
|
|
2292
2788
|
display: flex;
|
|
2293
2789
|
align-items: center;
|
|
2294
2790
|
gap: 12px;
|
|
2295
2791
|
flex: 1;
|
|
2296
2792
|
`,
|
|
2297
|
-
thumbnailWrapper:
|
|
2793
|
+
thumbnailWrapper: css6`
|
|
2298
2794
|
width: 48px;
|
|
2299
2795
|
height: 36px;
|
|
2300
2796
|
display: flex;
|
|
@@ -2302,7 +2798,7 @@ var styles5 = {
|
|
|
2302
2798
|
justify-content: center;
|
|
2303
2799
|
flex-shrink: 0;
|
|
2304
2800
|
`,
|
|
2305
|
-
folderIconWrapper:
|
|
2801
|
+
folderIconWrapper: css6`
|
|
2306
2802
|
width: 48px;
|
|
2307
2803
|
height: 36px;
|
|
2308
2804
|
display: flex;
|
|
@@ -2310,12 +2806,12 @@ var styles5 = {
|
|
|
2310
2806
|
justify-content: center;
|
|
2311
2807
|
flex-shrink: 0;
|
|
2312
2808
|
`,
|
|
2313
|
-
folderIcon:
|
|
2809
|
+
folderIcon: css6`
|
|
2314
2810
|
width: 24px;
|
|
2315
2811
|
height: 24px;
|
|
2316
2812
|
color: #f9935e;
|
|
2317
2813
|
`,
|
|
2318
|
-
imagesFolderWrapper:
|
|
2814
|
+
imagesFolderWrapper: css6`
|
|
2319
2815
|
width: 48px;
|
|
2320
2816
|
height: 36px;
|
|
2321
2817
|
display: flex;
|
|
@@ -2325,31 +2821,31 @@ var styles5 = {
|
|
|
2325
2821
|
position: relative;
|
|
2326
2822
|
align-items: center;
|
|
2327
2823
|
`,
|
|
2328
|
-
imagesFolderIcon:
|
|
2824
|
+
imagesFolderIcon: css6`
|
|
2329
2825
|
width: 24px;
|
|
2330
2826
|
height: 24px;
|
|
2331
2827
|
color: ${colors.imagesFolder};
|
|
2332
2828
|
`,
|
|
2333
|
-
lockIcon:
|
|
2829
|
+
lockIcon: css6`
|
|
2334
2830
|
width: 10px;
|
|
2335
2831
|
height: 10px;
|
|
2336
2832
|
color: ${colors.imagesFolder};
|
|
2337
2833
|
margin-left: -6px;
|
|
2338
2834
|
margin-top: 8px;
|
|
2339
2835
|
`,
|
|
2340
|
-
parentIcon:
|
|
2836
|
+
parentIcon: css6`
|
|
2341
2837
|
width: 20px;
|
|
2342
2838
|
height: 20px;
|
|
2343
2839
|
color: ${colors.textMuted};
|
|
2344
2840
|
flex-shrink: 0;
|
|
2345
2841
|
`,
|
|
2346
|
-
fileIcon:
|
|
2842
|
+
fileIcon: css6`
|
|
2347
2843
|
width: 20px;
|
|
2348
2844
|
height: 20px;
|
|
2349
2845
|
color: ${colors.textMuted};
|
|
2350
2846
|
flex-shrink: 0;
|
|
2351
2847
|
`,
|
|
2352
|
-
thumbnail:
|
|
2848
|
+
thumbnail: css6`
|
|
2353
2849
|
max-width: 100%;
|
|
2354
2850
|
max-height: 100%;
|
|
2355
2851
|
width: auto;
|
|
@@ -2358,7 +2854,7 @@ var styles5 = {
|
|
|
2358
2854
|
border-radius: 4px;
|
|
2359
2855
|
border: 1px solid ${colors.borderLight};
|
|
2360
2856
|
`,
|
|
2361
|
-
noThumbnail:
|
|
2857
|
+
noThumbnail: css6`
|
|
2362
2858
|
width: 36px;
|
|
2363
2859
|
height: 36px;
|
|
2364
2860
|
display: flex;
|
|
@@ -2376,12 +2872,12 @@ var styles5 = {
|
|
|
2376
2872
|
background: ${colors.surfaceHover};
|
|
2377
2873
|
}
|
|
2378
2874
|
`,
|
|
2379
|
-
noThumbnailIcon:
|
|
2875
|
+
noThumbnailIcon: css6`
|
|
2380
2876
|
width: 16px;
|
|
2381
2877
|
height: 16px;
|
|
2382
2878
|
color: ${colors.textMuted};
|
|
2383
2879
|
`,
|
|
2384
|
-
name:
|
|
2880
|
+
name: css6`
|
|
2385
2881
|
font-size: ${fontSize.base};
|
|
2386
2882
|
font-weight: 500;
|
|
2387
2883
|
color: ${colors.text};
|
|
@@ -2391,11 +2887,11 @@ var styles5 = {
|
|
|
2391
2887
|
white-space: nowrap;
|
|
2392
2888
|
max-width: 300px;
|
|
2393
2889
|
`,
|
|
2394
|
-
meta:
|
|
2890
|
+
meta: css6`
|
|
2395
2891
|
font-size: ${fontSize.sm};
|
|
2396
2892
|
color: ${colors.textSecondary};
|
|
2397
2893
|
`,
|
|
2398
|
-
cdnBadge:
|
|
2894
|
+
cdnBadge: css6`
|
|
2399
2895
|
display: inline-flex;
|
|
2400
2896
|
align-items: center;
|
|
2401
2897
|
gap: 4px;
|
|
@@ -2403,15 +2899,15 @@ var styles5 = {
|
|
|
2403
2899
|
font-weight: 500;
|
|
2404
2900
|
color: ${colors.success};
|
|
2405
2901
|
`,
|
|
2406
|
-
cdnIcon:
|
|
2902
|
+
cdnIcon: css6`
|
|
2407
2903
|
width: 12px;
|
|
2408
2904
|
height: 12px;
|
|
2409
2905
|
`,
|
|
2410
|
-
cdnEmpty:
|
|
2906
|
+
cdnEmpty: css6`
|
|
2411
2907
|
font-size: ${fontSize.sm};
|
|
2412
2908
|
color: ${colors.textMuted};
|
|
2413
2909
|
`,
|
|
2414
|
-
openBtn:
|
|
2910
|
+
openBtn: css6`
|
|
2415
2911
|
height: 32px;
|
|
2416
2912
|
font-size: ${fontSize.sm};
|
|
2417
2913
|
font-weight: 500;
|
|
@@ -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__ */
|
|
2946
|
+
return /* @__PURE__ */ jsx6("div", { css: styles6.loading, children: /* @__PURE__ */ jsx6("div", { css: styles6.spinner }) });
|
|
2464
2947
|
}
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
return /* @__PURE__ */ jsx5("div", { css: styles5.empty, children: /* @__PURE__ */ jsx5("p", { children: "No files in this folder" }) });
|
|
2948
|
+
if (sortedItems.length === 0 && isAtRoot) {
|
|
2949
|
+
return /* @__PURE__ */ jsx6("div", { css: styles6.empty, children: /* @__PURE__ */ jsx6("p", { children: "No files in this folder" }) });
|
|
2468
2950
|
}
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
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__ */ jsx5("div", { css: styles5.tableWrapper, children: /* @__PURE__ */ jsxs5("table", { css: styles5.table, children: [
|
|
2512
|
-
/* @__PURE__ */ jsx5("thead", { children: /* @__PURE__ */ jsxs5("tr", { children: [
|
|
2513
|
-
/* @__PURE__ */ jsx5("th", { css: [styles5.th, styles5.thCheckbox], children: sortedItems.length > 0 && /* @__PURE__ */ jsx5(
|
|
2951
|
+
return /* @__PURE__ */ jsx6("div", { css: styles6.tableWrapper, children: /* @__PURE__ */ jsxs6("table", { css: styles6.table, children: [
|
|
2952
|
+
/* @__PURE__ */ jsx6("thead", { children: /* @__PURE__ */ jsxs6("tr", { children: [
|
|
2953
|
+
/* @__PURE__ */ jsx6("th", { css: [styles6.th, styles6.thCheckbox], children: sortedItems.length > 0 && /* @__PURE__ */ jsx6(
|
|
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,23 +2962,23 @@ function StudioFileList() {
|
|
|
2522
2962
|
onChange: handleSelectAll
|
|
2523
2963
|
}
|
|
2524
2964
|
) }),
|
|
2525
|
-
/* @__PURE__ */
|
|
2526
|
-
/* @__PURE__ */
|
|
2527
|
-
/* @__PURE__ */
|
|
2528
|
-
/* @__PURE__ */
|
|
2965
|
+
/* @__PURE__ */ jsx6("th", { css: styles6.th, children: "Name" }),
|
|
2966
|
+
/* @__PURE__ */ jsx6("th", { css: [styles6.th, styles6.thSize], children: "Size" }),
|
|
2967
|
+
/* @__PURE__ */ jsx6("th", { css: [styles6.th, styles6.thDimensions], children: "Dimensions" }),
|
|
2968
|
+
/* @__PURE__ */ jsx6("th", { css: [styles6.th, styles6.thCdn], children: "CDN" })
|
|
2529
2969
|
] }) }),
|
|
2530
|
-
/* @__PURE__ */
|
|
2531
|
-
!isAtRoot && !isSearching && /* @__PURE__ */
|
|
2532
|
-
/* @__PURE__ */
|
|
2533
|
-
/* @__PURE__ */
|
|
2534
|
-
/* @__PURE__ */
|
|
2535
|
-
/* @__PURE__ */
|
|
2970
|
+
/* @__PURE__ */ jsxs6("tbody", { css: styles6.tbody, children: [
|
|
2971
|
+
!isAtRoot && !isSearching && /* @__PURE__ */ jsxs6("tr", { css: styles6.parentRow, onClick: navigateUp, children: [
|
|
2972
|
+
/* @__PURE__ */ jsx6("td", { css: styles6.td }),
|
|
2973
|
+
/* @__PURE__ */ jsx6("td", { css: styles6.td, children: /* @__PURE__ */ jsxs6("div", { css: styles6.nameCell, children: [
|
|
2974
|
+
/* @__PURE__ */ jsx6("svg", { css: styles6.parentIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx6("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M3 10h10a8 8 0 018 8v2M3 10l6 6m-6-6l6-6" }) }),
|
|
2975
|
+
/* @__PURE__ */ jsx6("span", { css: styles6.name, children: ".." })
|
|
2536
2976
|
] }) }),
|
|
2537
|
-
/* @__PURE__ */
|
|
2538
|
-
/* @__PURE__ */
|
|
2539
|
-
/* @__PURE__ */
|
|
2977
|
+
/* @__PURE__ */ jsx6("td", { css: [styles6.td, styles6.meta], children: "--" }),
|
|
2978
|
+
/* @__PURE__ */ jsx6("td", { css: [styles6.td, styles6.meta], children: "Parent folder" }),
|
|
2979
|
+
/* @__PURE__ */ jsx6("td", { css: styles6.td, children: "--" })
|
|
2540
2980
|
] }),
|
|
2541
|
-
sortedItems.map((item) => /* @__PURE__ */
|
|
2981
|
+
sortedItems.map((item) => /* @__PURE__ */ jsx6(
|
|
2542
2982
|
ListRow,
|
|
2543
2983
|
{
|
|
2544
2984
|
item,
|
|
@@ -2553,7 +2993,7 @@ function StudioFileList() {
|
|
|
2553
2993
|
] }) });
|
|
2554
2994
|
}
|
|
2555
2995
|
function ListRow({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
|
|
2556
|
-
const [showCopied, setShowCopied] =
|
|
2996
|
+
const [showCopied, setShowCopied] = useState5(false);
|
|
2557
2997
|
const isFolder = item.type === "folder";
|
|
2558
2998
|
const isImage = !isFolder && item.thumbnail !== void 0;
|
|
2559
2999
|
const isImagesFolder = isFolder && (item.name === "images" || item.path.includes("/images/"));
|
|
@@ -2564,62 +3004,62 @@ function ListRow({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
|
|
|
2564
3004
|
setShowCopied(true);
|
|
2565
3005
|
setTimeout(() => setShowCopied(false), 1500);
|
|
2566
3006
|
};
|
|
2567
|
-
return /* @__PURE__ */
|
|
3007
|
+
return /* @__PURE__ */ jsxs6(
|
|
2568
3008
|
"tr",
|
|
2569
3009
|
{
|
|
2570
|
-
css: [
|
|
3010
|
+
css: [styles6.row, isSelected && styles6.rowSelected],
|
|
2571
3011
|
onClick,
|
|
2572
3012
|
children: [
|
|
2573
|
-
/* @__PURE__ */
|
|
3013
|
+
/* @__PURE__ */ jsx6(
|
|
2574
3014
|
"td",
|
|
2575
3015
|
{
|
|
2576
|
-
css: [
|
|
3016
|
+
css: [styles6.td, styles6.checkboxCell],
|
|
2577
3017
|
onClick: (e) => e.stopPropagation(),
|
|
2578
|
-
children: /* @__PURE__ */
|
|
3018
|
+
children: /* @__PURE__ */ jsx6(
|
|
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__ */
|
|
2590
|
-
isFolder ? isImagesFolder ? /* @__PURE__ */
|
|
2591
|
-
/* @__PURE__ */
|
|
2592
|
-
/* @__PURE__ */
|
|
2593
|
-
] }) : /* @__PURE__ */
|
|
3029
|
+
/* @__PURE__ */ jsx6("td", { css: styles6.td, children: /* @__PURE__ */ jsxs6("div", { css: styles6.nameCell, children: [
|
|
3030
|
+
isFolder ? isImagesFolder ? /* @__PURE__ */ jsxs6("div", { css: styles6.imagesFolderWrapper, children: [
|
|
3031
|
+
/* @__PURE__ */ jsx6("svg", { css: styles6.imagesFolderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx6("path", { d: "M10 4H4a2 2 0 00-2 2v12a2 2 0 002 2h16a2 2 0 002-2V8a2 2 0 00-2-2h-8l-2-2z" }) }),
|
|
3032
|
+
/* @__PURE__ */ jsx6("svg", { css: styles6.lockIcon, fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx6("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__ */ jsx6("div", { css: styles6.folderIconWrapper, children: /* @__PURE__ */ jsx6("svg", { css: styles6.folderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx6("path", { d: "M10 4H4a2 2 0 00-2 2v12a2 2 0 002 2h16a2 2 0 002-2V8a2 2 0 00-2-2h-8l-2-2z" }) }) }) : isImage && item.hasThumbnail ? /* @__PURE__ */ jsx6("div", { css: styles6.thumbnailWrapper, children: /* @__PURE__ */ jsx6("img", { css: styles6.thumbnail, src: item.thumbnail, alt: item.name, loading: "lazy" }) }) : isImage && !item.hasThumbnail ? /* @__PURE__ */ jsx6("div", { css: styles6.thumbnailWrapper, children: /* @__PURE__ */ jsx6(
|
|
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__ */
|
|
3042
|
+
children: /* @__PURE__ */ jsx6("svg", { css: styles6.noThumbnailIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx6("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__ */
|
|
2605
|
-
/* @__PURE__ */
|
|
2606
|
-
/* @__PURE__ */
|
|
2607
|
-
/* @__PURE__ */
|
|
3044
|
+
) }) : /* @__PURE__ */ jsx6("div", { css: styles6.thumbnailWrapper, children: /* @__PURE__ */ jsx6("svg", { css: styles6.fileIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx6("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" }) }) }),
|
|
3045
|
+
/* @__PURE__ */ jsx6("span", { css: styles6.name, title: item.name, children: truncateMiddle2(item.name) }),
|
|
3046
|
+
/* @__PURE__ */ jsxs6("div", { css: styles6.actionsCell, children: [
|
|
3047
|
+
/* @__PURE__ */ jsxs6(
|
|
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__ */
|
|
2615
|
-
/* @__PURE__ */
|
|
3054
|
+
showCopied && /* @__PURE__ */ jsx6("span", { css: styles6.tooltip, children: "Copied!" }),
|
|
3055
|
+
/* @__PURE__ */ jsx6("svg", { css: styles6.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx6("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
|
-
/* @__PURE__ */
|
|
3059
|
+
/* @__PURE__ */ jsx6(
|
|
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__ */
|
|
2633
|
-
/* @__PURE__ */
|
|
2634
|
-
/* @__PURE__ */
|
|
2635
|
-
/* @__PURE__ */
|
|
3072
|
+
/* @__PURE__ */ jsx6("td", { css: [styles6.td, styles6.meta], children: isFolder ? item.fileCount !== void 0 ? `${item.fileCount} files` : "--" : item.size !== void 0 ? formatFileSize2(item.size) : "--" }),
|
|
3073
|
+
/* @__PURE__ */ jsx6("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__ */ jsx6("td", { css: styles6.td, children: item.cdnSynced ? /* @__PURE__ */ jsxs6("span", { css: styles6.cdnBadge, children: [
|
|
3075
|
+
/* @__PURE__ */ jsx6("svg", { css: styles6.cdnIcon, fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx6("path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }),
|
|
2636
3076
|
"Synced"
|
|
2637
|
-
] }) : /* @__PURE__ */
|
|
3077
|
+
] }) : /* @__PURE__ */ jsx6("span", { css: styles6.cdnEmpty, children: "--" }) })
|
|
2638
3078
|
]
|
|
2639
3079
|
}
|
|
2640
3080
|
);
|
|
@@ -2659,9 +3099,9 @@ function truncateMiddle2(str, maxLength = 32) {
|
|
|
2659
3099
|
}
|
|
2660
3100
|
|
|
2661
3101
|
// src/components/StudioDetailView.tsx
|
|
2662
|
-
import { useState as
|
|
2663
|
-
import { css as
|
|
2664
|
-
import { Fragment as Fragment3, jsx as
|
|
3102
|
+
import { useState as useState6 } from "react";
|
|
3103
|
+
import { css as css7 } from "@emotion/react";
|
|
3104
|
+
import { Fragment as Fragment3, jsx as jsx7, jsxs as jsxs7 } from "@emotion/react/jsx-runtime";
|
|
2665
3105
|
var IMAGE_EXTENSIONS = [".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg", ".ico", ".bmp", ".tiff", ".tif"];
|
|
2666
3106
|
var VIDEO_EXTENSIONS = [".mp4", ".webm", ".mov", ".avi", ".mkv", ".m4v"];
|
|
2667
3107
|
function isImageFile(filename) {
|
|
@@ -2672,8 +3112,8 @@ function isVideoFile(filename) {
|
|
|
2672
3112
|
const ext = filename.toLowerCase().substring(filename.lastIndexOf("."));
|
|
2673
3113
|
return VIDEO_EXTENSIONS.includes(ext);
|
|
2674
3114
|
}
|
|
2675
|
-
var
|
|
2676
|
-
overlay:
|
|
3115
|
+
var styles7 = {
|
|
3116
|
+
overlay: css7`
|
|
2677
3117
|
position: absolute;
|
|
2678
3118
|
top: 0;
|
|
2679
3119
|
left: 0;
|
|
@@ -2683,7 +3123,7 @@ var styles6 = {
|
|
|
2683
3123
|
display: flex;
|
|
2684
3124
|
background: transparent;
|
|
2685
3125
|
`,
|
|
2686
|
-
container:
|
|
3126
|
+
container: css7`
|
|
2687
3127
|
display: flex;
|
|
2688
3128
|
flex: 1;
|
|
2689
3129
|
margin: 24px;
|
|
@@ -2693,7 +3133,7 @@ var styles6 = {
|
|
|
2693
3133
|
overflow: hidden;
|
|
2694
3134
|
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
|
|
2695
3135
|
`,
|
|
2696
|
-
main:
|
|
3136
|
+
main: css7`
|
|
2697
3137
|
position: relative;
|
|
2698
3138
|
flex: 1;
|
|
2699
3139
|
display: flex;
|
|
@@ -2704,7 +3144,7 @@ var styles6 = {
|
|
|
2704
3144
|
background: ${colors.background};
|
|
2705
3145
|
overflow: auto;
|
|
2706
3146
|
`,
|
|
2707
|
-
headerButtons:
|
|
3147
|
+
headerButtons: css7`
|
|
2708
3148
|
position: absolute;
|
|
2709
3149
|
top: 16px;
|
|
2710
3150
|
right: 16px;
|
|
@@ -2712,7 +3152,7 @@ var styles6 = {
|
|
|
2712
3152
|
gap: 8px;
|
|
2713
3153
|
z-index: 10;
|
|
2714
3154
|
`,
|
|
2715
|
-
copyBtn:
|
|
3155
|
+
copyBtn: css7`
|
|
2716
3156
|
position: relative;
|
|
2717
3157
|
padding: 8px;
|
|
2718
3158
|
background: ${colors.surface};
|
|
@@ -2730,12 +3170,12 @@ var styles6 = {
|
|
|
2730
3170
|
border-color: ${colors.borderHover};
|
|
2731
3171
|
}
|
|
2732
3172
|
`,
|
|
2733
|
-
copyIcon:
|
|
3173
|
+
copyIcon: css7`
|
|
2734
3174
|
width: 20px;
|
|
2735
3175
|
height: 20px;
|
|
2736
3176
|
color: ${colors.textSecondary};
|
|
2737
3177
|
`,
|
|
2738
|
-
tooltip:
|
|
3178
|
+
tooltip: css7`
|
|
2739
3179
|
position: absolute;
|
|
2740
3180
|
right: 100%;
|
|
2741
3181
|
top: 50%;
|
|
@@ -2760,7 +3200,7 @@ var styles6 = {
|
|
|
2760
3200
|
border-left-color: #1a1f36;
|
|
2761
3201
|
}
|
|
2762
3202
|
`,
|
|
2763
|
-
mainCloseBtn:
|
|
3203
|
+
mainCloseBtn: css7`
|
|
2764
3204
|
padding: 8px;
|
|
2765
3205
|
background: ${colors.surface};
|
|
2766
3206
|
border: 1px solid ${colors.border};
|
|
@@ -2777,32 +3217,32 @@ var styles6 = {
|
|
|
2777
3217
|
border-color: ${colors.borderHover};
|
|
2778
3218
|
}
|
|
2779
3219
|
`,
|
|
2780
|
-
mainCloseIcon:
|
|
3220
|
+
mainCloseIcon: css7`
|
|
2781
3221
|
width: 20px;
|
|
2782
3222
|
height: 20px;
|
|
2783
3223
|
color: ${colors.textSecondary};
|
|
2784
3224
|
`,
|
|
2785
|
-
mediaWrapper:
|
|
3225
|
+
mediaWrapper: css7`
|
|
2786
3226
|
max-width: 100%;
|
|
2787
3227
|
max-height: 100%;
|
|
2788
3228
|
display: flex;
|
|
2789
3229
|
align-items: center;
|
|
2790
3230
|
justify-content: center;
|
|
2791
3231
|
`,
|
|
2792
|
-
image:
|
|
3232
|
+
image: css7`
|
|
2793
3233
|
max-width: 100%;
|
|
2794
3234
|
max-height: calc(100vh - 200px);
|
|
2795
3235
|
object-fit: contain;
|
|
2796
3236
|
border-radius: 8px;
|
|
2797
3237
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
2798
3238
|
`,
|
|
2799
|
-
video:
|
|
3239
|
+
video: css7`
|
|
2800
3240
|
max-width: 100%;
|
|
2801
3241
|
max-height: calc(100vh - 200px);
|
|
2802
3242
|
border-radius: 8px;
|
|
2803
3243
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
2804
3244
|
`,
|
|
2805
|
-
filePlaceholder:
|
|
3245
|
+
filePlaceholder: css7`
|
|
2806
3246
|
display: flex;
|
|
2807
3247
|
flex-direction: column;
|
|
2808
3248
|
align-items: center;
|
|
@@ -2812,19 +3252,19 @@ var styles6 = {
|
|
|
2812
3252
|
border-radius: 12px;
|
|
2813
3253
|
border: 1px solid ${colors.border};
|
|
2814
3254
|
`,
|
|
2815
|
-
fileIcon:
|
|
3255
|
+
fileIcon: css7`
|
|
2816
3256
|
width: 80px;
|
|
2817
3257
|
height: 80px;
|
|
2818
3258
|
color: ${colors.textMuted};
|
|
2819
3259
|
margin-bottom: 16px;
|
|
2820
3260
|
`,
|
|
2821
|
-
fileName:
|
|
3261
|
+
fileName: css7`
|
|
2822
3262
|
font-size: ${fontSize.lg};
|
|
2823
3263
|
font-weight: 600;
|
|
2824
3264
|
color: ${colors.text};
|
|
2825
3265
|
margin: 0;
|
|
2826
3266
|
`,
|
|
2827
|
-
sidebar:
|
|
3267
|
+
sidebar: css7`
|
|
2828
3268
|
width: 280px;
|
|
2829
3269
|
background: ${colors.surface};
|
|
2830
3270
|
border-left: 1px solid ${colors.border};
|
|
@@ -2832,36 +3272,36 @@ var styles6 = {
|
|
|
2832
3272
|
flex-direction: column;
|
|
2833
3273
|
overflow: hidden;
|
|
2834
3274
|
`,
|
|
2835
|
-
sidebarHeader:
|
|
3275
|
+
sidebarHeader: css7`
|
|
2836
3276
|
padding: 16px 20px;
|
|
2837
3277
|
border-bottom: 1px solid ${colors.border};
|
|
2838
3278
|
`,
|
|
2839
|
-
sidebarTitle:
|
|
3279
|
+
sidebarTitle: css7`
|
|
2840
3280
|
font-size: ${fontSize.base};
|
|
2841
3281
|
font-weight: 600;
|
|
2842
3282
|
color: ${colors.text};
|
|
2843
3283
|
margin: 0;
|
|
2844
3284
|
`,
|
|
2845
|
-
sidebarContent:
|
|
3285
|
+
sidebarContent: css7`
|
|
2846
3286
|
flex: 1;
|
|
2847
3287
|
padding: 20px;
|
|
2848
3288
|
overflow: auto;
|
|
2849
3289
|
`,
|
|
2850
|
-
info:
|
|
3290
|
+
info: css7`
|
|
2851
3291
|
display: flex;
|
|
2852
3292
|
flex-direction: column;
|
|
2853
3293
|
gap: 12px;
|
|
2854
3294
|
margin-bottom: 24px;
|
|
2855
3295
|
`,
|
|
2856
|
-
infoRow:
|
|
3296
|
+
infoRow: css7`
|
|
2857
3297
|
display: flex;
|
|
2858
3298
|
justify-content: space-between;
|
|
2859
3299
|
font-size: ${fontSize.sm};
|
|
2860
3300
|
`,
|
|
2861
|
-
infoLabel:
|
|
3301
|
+
infoLabel: css7`
|
|
2862
3302
|
color: ${colors.textSecondary};
|
|
2863
3303
|
`,
|
|
2864
|
-
infoValue:
|
|
3304
|
+
infoValue: css7`
|
|
2865
3305
|
color: ${colors.text};
|
|
2866
3306
|
font-weight: 500;
|
|
2867
3307
|
text-align: right;
|
|
@@ -2870,7 +3310,7 @@ var styles6 = {
|
|
|
2870
3310
|
text-overflow: ellipsis;
|
|
2871
3311
|
white-space: nowrap;
|
|
2872
3312
|
`,
|
|
2873
|
-
infoValueWrap:
|
|
3313
|
+
infoValueWrap: css7`
|
|
2874
3314
|
color: ${colors.text};
|
|
2875
3315
|
font-weight: 500;
|
|
2876
3316
|
text-align: right;
|
|
@@ -2878,12 +3318,12 @@ var styles6 = {
|
|
|
2878
3318
|
word-break: break-all;
|
|
2879
3319
|
white-space: normal;
|
|
2880
3320
|
`,
|
|
2881
|
-
actions:
|
|
3321
|
+
actions: css7`
|
|
2882
3322
|
display: flex;
|
|
2883
3323
|
flex-direction: column;
|
|
2884
3324
|
gap: 8px;
|
|
2885
3325
|
`,
|
|
2886
|
-
actionBtn:
|
|
3326
|
+
actionBtn: css7`
|
|
2887
3327
|
display: flex;
|
|
2888
3328
|
align-items: center;
|
|
2889
3329
|
gap: 10px;
|
|
@@ -2904,7 +3344,7 @@ var styles6 = {
|
|
|
2904
3344
|
border-color: ${colors.borderHover};
|
|
2905
3345
|
}
|
|
2906
3346
|
`,
|
|
2907
|
-
actionBtnDanger:
|
|
3347
|
+
actionBtnDanger: css7`
|
|
2908
3348
|
color: ${colors.danger};
|
|
2909
3349
|
|
|
2910
3350
|
&:hover {
|
|
@@ -2912,7 +3352,7 @@ var styles6 = {
|
|
|
2912
3352
|
border-color: ${colors.danger};
|
|
2913
3353
|
}
|
|
2914
3354
|
`,
|
|
2915
|
-
actionIcon:
|
|
3355
|
+
actionIcon: css7`
|
|
2916
3356
|
width: 16px;
|
|
2917
3357
|
height: 16px;
|
|
2918
3358
|
flex-shrink: 0;
|
|
@@ -2920,12 +3360,14 @@ var styles6 = {
|
|
|
2920
3360
|
};
|
|
2921
3361
|
function StudioDetailView() {
|
|
2922
3362
|
const { focusedItem, setFocusedItem, triggerRefresh, clearSelection } = useStudio();
|
|
2923
|
-
const [showDeleteConfirm, setShowDeleteConfirm] =
|
|
2924
|
-
const [showRenameModal, setShowRenameModal] =
|
|
2925
|
-
const [showProcessConfirm, setShowProcessConfirm] =
|
|
2926
|
-
const [
|
|
2927
|
-
const [
|
|
2928
|
-
const [
|
|
3363
|
+
const [showDeleteConfirm, setShowDeleteConfirm] = useState6(false);
|
|
3364
|
+
const [showRenameModal, setShowRenameModal] = useState6(false);
|
|
3365
|
+
const [showProcessConfirm, setShowProcessConfirm] = useState6(false);
|
|
3366
|
+
const [showR2SetupModal, setShowR2SetupModal] = useState6(false);
|
|
3367
|
+
const [processProgress, setProcessProgress] = useState6(null);
|
|
3368
|
+
const [alertMessage, setAlertMessage] = useState6(null);
|
|
3369
|
+
const [showCopied, setShowCopied] = useState6(false);
|
|
3370
|
+
const [syncing, setSyncing] = useState6(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 (data.error?.includes("R2 not configured") || data.error?.includes("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);
|
|
@@ -3056,18 +3531,18 @@ function StudioDetailView() {
|
|
|
3056
3531
|
};
|
|
3057
3532
|
const renderMedia = () => {
|
|
3058
3533
|
if (isImage) {
|
|
3059
|
-
return /* @__PURE__ */
|
|
3534
|
+
return /* @__PURE__ */ jsx7("img", { css: styles7.image, src: imageSrc, alt: focusedItem.name });
|
|
3060
3535
|
}
|
|
3061
3536
|
if (isVideo) {
|
|
3062
|
-
return /* @__PURE__ */
|
|
3537
|
+
return /* @__PURE__ */ jsx7("video", { css: styles7.video, src: imageSrc, controls: true });
|
|
3063
3538
|
}
|
|
3064
|
-
return /* @__PURE__ */
|
|
3065
|
-
/* @__PURE__ */
|
|
3066
|
-
/* @__PURE__ */
|
|
3539
|
+
return /* @__PURE__ */ jsxs7("div", { css: styles7.filePlaceholder, children: [
|
|
3540
|
+
/* @__PURE__ */ jsx7("svg", { css: styles7.fileIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx7("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__ */ jsx7("p", { css: styles7.fileName, children: focusedItem.name })
|
|
3067
3542
|
] });
|
|
3068
3543
|
};
|
|
3069
|
-
return /* @__PURE__ */
|
|
3070
|
-
showDeleteConfirm && /* @__PURE__ */
|
|
3544
|
+
return /* @__PURE__ */ jsxs7(Fragment3, { children: [
|
|
3545
|
+
showDeleteConfirm && /* @__PURE__ */ jsx7(
|
|
3071
3546
|
ConfirmModal,
|
|
3072
3547
|
{
|
|
3073
3548
|
title: "Delete File",
|
|
@@ -3078,7 +3553,7 @@ function StudioDetailView() {
|
|
|
3078
3553
|
onCancel: () => setShowDeleteConfirm(false)
|
|
3079
3554
|
}
|
|
3080
3555
|
),
|
|
3081
|
-
alertMessage && /* @__PURE__ */
|
|
3556
|
+
alertMessage && /* @__PURE__ */ jsx7(
|
|
3082
3557
|
AlertModal,
|
|
3083
3558
|
{
|
|
3084
3559
|
title: alertMessage.title,
|
|
@@ -3086,7 +3561,14 @@ function StudioDetailView() {
|
|
|
3086
3561
|
onClose: () => setAlertMessage(null)
|
|
3087
3562
|
}
|
|
3088
3563
|
),
|
|
3089
|
-
|
|
3564
|
+
/* @__PURE__ */ jsx7(
|
|
3565
|
+
R2SetupModal,
|
|
3566
|
+
{
|
|
3567
|
+
isOpen: showR2SetupModal,
|
|
3568
|
+
onClose: () => setShowR2SetupModal(false)
|
|
3569
|
+
}
|
|
3570
|
+
),
|
|
3571
|
+
showRenameModal && /* @__PURE__ */ jsx7(
|
|
3090
3572
|
InputModal,
|
|
3091
3573
|
{
|
|
3092
3574
|
title: "Rename File",
|
|
@@ -3098,7 +3580,7 @@ function StudioDetailView() {
|
|
|
3098
3580
|
onCancel: () => setShowRenameModal(false)
|
|
3099
3581
|
}
|
|
3100
3582
|
),
|
|
3101
|
-
showProcessConfirm && /* @__PURE__ */
|
|
3583
|
+
showProcessConfirm && /* @__PURE__ */ jsx7(
|
|
3102
3584
|
ConfirmModal,
|
|
3103
3585
|
{
|
|
3104
3586
|
title: "Process Image",
|
|
@@ -3108,7 +3590,7 @@ function StudioDetailView() {
|
|
|
3108
3590
|
onCancel: () => setShowProcessConfirm(false)
|
|
3109
3591
|
}
|
|
3110
3592
|
),
|
|
3111
|
-
processProgress && /* @__PURE__ */
|
|
3593
|
+
processProgress && /* @__PURE__ */ jsx7(
|
|
3112
3594
|
ProgressModal,
|
|
3113
3595
|
{
|
|
3114
3596
|
title: "Processing Image",
|
|
@@ -3116,61 +3598,61 @@ function StudioDetailView() {
|
|
|
3116
3598
|
onClose: () => setProcessProgress(null)
|
|
3117
3599
|
}
|
|
3118
3600
|
),
|
|
3119
|
-
/* @__PURE__ */
|
|
3120
|
-
/* @__PURE__ */
|
|
3121
|
-
/* @__PURE__ */
|
|
3122
|
-
/* @__PURE__ */
|
|
3123
|
-
showCopied && /* @__PURE__ */
|
|
3124
|
-
/* @__PURE__ */
|
|
3601
|
+
/* @__PURE__ */ jsx7("div", { css: styles7.overlay, onClick: handleClose, children: /* @__PURE__ */ jsxs7("div", { css: styles7.container, onClick: (e) => e.stopPropagation(), children: [
|
|
3602
|
+
/* @__PURE__ */ jsxs7("div", { css: styles7.main, children: [
|
|
3603
|
+
/* @__PURE__ */ jsxs7("div", { css: styles7.headerButtons, children: [
|
|
3604
|
+
/* @__PURE__ */ jsxs7("button", { css: styles7.copyBtn, onClick: handleCopyPath, title: "Copy file path", children: [
|
|
3605
|
+
showCopied && /* @__PURE__ */ jsx7("span", { css: styles7.tooltip, children: "Copied!" }),
|
|
3606
|
+
/* @__PURE__ */ jsx7("svg", { css: styles7.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx7("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__ */
|
|
3608
|
+
/* @__PURE__ */ jsx7("button", { css: styles7.mainCloseBtn, onClick: handleClose, "aria-label": "Close", children: /* @__PURE__ */ jsx7("svg", { css: styles7.mainCloseIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx7("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })
|
|
3127
3609
|
] }),
|
|
3128
|
-
/* @__PURE__ */
|
|
3610
|
+
/* @__PURE__ */ jsx7("div", { css: styles7.mediaWrapper, children: renderMedia() })
|
|
3129
3611
|
] }),
|
|
3130
|
-
/* @__PURE__ */
|
|
3131
|
-
/* @__PURE__ */
|
|
3132
|
-
/* @__PURE__ */
|
|
3133
|
-
/* @__PURE__ */
|
|
3134
|
-
/* @__PURE__ */
|
|
3135
|
-
/* @__PURE__ */
|
|
3136
|
-
/* @__PURE__ */
|
|
3612
|
+
/* @__PURE__ */ jsxs7("div", { css: styles7.sidebar, children: [
|
|
3613
|
+
/* @__PURE__ */ jsx7("div", { css: styles7.sidebarHeader, children: /* @__PURE__ */ jsx7("h3", { css: styles7.sidebarTitle, children: "Details" }) }),
|
|
3614
|
+
/* @__PURE__ */ jsxs7("div", { css: styles7.sidebarContent, children: [
|
|
3615
|
+
/* @__PURE__ */ jsxs7("div", { css: styles7.info, children: [
|
|
3616
|
+
/* @__PURE__ */ jsxs7("div", { css: styles7.infoRow, children: [
|
|
3617
|
+
/* @__PURE__ */ jsx7("span", { css: styles7.infoLabel, children: "Name" }),
|
|
3618
|
+
/* @__PURE__ */ jsx7("span", { css: styles7.infoValueWrap, children: focusedItem.name })
|
|
3137
3619
|
] }),
|
|
3138
|
-
/* @__PURE__ */
|
|
3139
|
-
/* @__PURE__ */
|
|
3140
|
-
/* @__PURE__ */
|
|
3620
|
+
/* @__PURE__ */ jsxs7("div", { css: styles7.infoRow, children: [
|
|
3621
|
+
/* @__PURE__ */ jsx7("span", { css: styles7.infoLabel, children: "Path" }),
|
|
3622
|
+
/* @__PURE__ */ jsx7("span", { css: styles7.infoValueWrap, children: focusedItem.path.replace(/^public\//, "") })
|
|
3141
3623
|
] }),
|
|
3142
|
-
focusedItem.size !== void 0 && /* @__PURE__ */
|
|
3143
|
-
/* @__PURE__ */
|
|
3144
|
-
/* @__PURE__ */
|
|
3624
|
+
focusedItem.size !== void 0 && /* @__PURE__ */ jsxs7("div", { css: styles7.infoRow, children: [
|
|
3625
|
+
/* @__PURE__ */ jsx7("span", { css: styles7.infoLabel, children: "Size" }),
|
|
3626
|
+
/* @__PURE__ */ jsx7("span", { css: styles7.infoValue, children: formatFileSize3(focusedItem.size) })
|
|
3145
3627
|
] }),
|
|
3146
|
-
focusedItem.dimensions && /* @__PURE__ */
|
|
3147
|
-
/* @__PURE__ */
|
|
3148
|
-
/* @__PURE__ */
|
|
3628
|
+
focusedItem.dimensions && /* @__PURE__ */ jsxs7("div", { css: styles7.infoRow, children: [
|
|
3629
|
+
/* @__PURE__ */ jsx7("span", { css: styles7.infoLabel, children: "Dimensions" }),
|
|
3630
|
+
/* @__PURE__ */ jsxs7("span", { css: styles7.infoValue, children: [
|
|
3149
3631
|
focusedItem.dimensions.width,
|
|
3150
3632
|
" \xD7 ",
|
|
3151
3633
|
focusedItem.dimensions.height
|
|
3152
3634
|
] })
|
|
3153
3635
|
] }),
|
|
3154
|
-
/* @__PURE__ */
|
|
3155
|
-
/* @__PURE__ */
|
|
3156
|
-
/* @__PURE__ */
|
|
3636
|
+
/* @__PURE__ */ jsxs7("div", { css: styles7.infoRow, children: [
|
|
3637
|
+
/* @__PURE__ */ jsx7("span", { css: styles7.infoLabel, children: "CDN Status" }),
|
|
3638
|
+
/* @__PURE__ */ jsx7("span", { css: styles7.infoValue, children: focusedItem.cdnSynced ? "Synced" : "Not synced" })
|
|
3157
3639
|
] })
|
|
3158
3640
|
] }),
|
|
3159
|
-
/* @__PURE__ */
|
|
3160
|
-
/* @__PURE__ */
|
|
3161
|
-
/* @__PURE__ */
|
|
3641
|
+
/* @__PURE__ */ jsxs7("div", { css: styles7.actions, children: [
|
|
3642
|
+
/* @__PURE__ */ jsxs7("button", { css: styles7.actionBtn, onClick: () => setShowRenameModal(true), children: [
|
|
3643
|
+
/* @__PURE__ */ jsx7("svg", { css: styles7.actionIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx7("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__ */
|
|
3165
|
-
/* @__PURE__ */
|
|
3166
|
-
"Sync to CDN"
|
|
3646
|
+
/* @__PURE__ */ jsxs7("button", { css: styles7.actionBtn, onClick: handleSync, disabled: syncing, children: [
|
|
3647
|
+
/* @__PURE__ */ jsx7("svg", { css: styles7.actionIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx7("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__ */
|
|
3169
|
-
/* @__PURE__ */
|
|
3650
|
+
/* @__PURE__ */ jsxs7("button", { css: styles7.actionBtn, onClick: () => setShowProcessConfirm(true), children: [
|
|
3651
|
+
/* @__PURE__ */ jsx7("svg", { css: styles7.actionIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx7("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__ */
|
|
3173
|
-
/* @__PURE__ */
|
|
3654
|
+
/* @__PURE__ */ jsxs7("button", { css: [styles7.actionBtn, styles7.actionBtnDanger], onClick: () => setShowDeleteConfirm(true), children: [
|
|
3655
|
+
/* @__PURE__ */ jsx7("svg", { css: styles7.actionIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx7("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
|
] })
|
|
@@ -3186,12 +3668,12 @@ function formatFileSize3(bytes) {
|
|
|
3186
3668
|
}
|
|
3187
3669
|
|
|
3188
3670
|
// src/components/StudioSettings.tsx
|
|
3189
|
-
import { useState as
|
|
3190
|
-
import { css as
|
|
3191
|
-
import { Fragment as Fragment4, jsx as
|
|
3671
|
+
import { useState as useState7 } from "react";
|
|
3672
|
+
import { css as css8 } from "@emotion/react";
|
|
3673
|
+
import { Fragment as Fragment4, jsx as jsx8, jsxs as jsxs8 } from "@emotion/react/jsx-runtime";
|
|
3192
3674
|
var btnHeight2 = "36px";
|
|
3193
|
-
var
|
|
3194
|
-
btn:
|
|
3675
|
+
var styles8 = {
|
|
3676
|
+
btn: css8`
|
|
3195
3677
|
height: ${btnHeight2};
|
|
3196
3678
|
padding: 0 12px;
|
|
3197
3679
|
background: ${colors.surface};
|
|
@@ -3208,12 +3690,12 @@ var styles7 = {
|
|
|
3208
3690
|
border-color: ${colors.borderHover};
|
|
3209
3691
|
}
|
|
3210
3692
|
`,
|
|
3211
|
-
icon:
|
|
3693
|
+
icon: css8`
|
|
3212
3694
|
width: 16px;
|
|
3213
3695
|
height: 16px;
|
|
3214
3696
|
color: ${colors.textSecondary};
|
|
3215
3697
|
`,
|
|
3216
|
-
overlay:
|
|
3698
|
+
overlay: css8`
|
|
3217
3699
|
position: fixed;
|
|
3218
3700
|
top: 0;
|
|
3219
3701
|
right: 0;
|
|
@@ -3226,7 +3708,7 @@ var styles7 = {
|
|
|
3226
3708
|
background-color: rgba(26, 31, 54, 0.4);
|
|
3227
3709
|
backdrop-filter: blur(4px);
|
|
3228
3710
|
`,
|
|
3229
|
-
panel:
|
|
3711
|
+
panel: css8`
|
|
3230
3712
|
${baseReset}
|
|
3231
3713
|
position: relative;
|
|
3232
3714
|
background-color: ${colors.surface};
|
|
@@ -3236,20 +3718,20 @@ var styles7 = {
|
|
|
3236
3718
|
max-width: 512px;
|
|
3237
3719
|
padding: 24px;
|
|
3238
3720
|
`,
|
|
3239
|
-
header:
|
|
3721
|
+
header: css8`
|
|
3240
3722
|
display: flex;
|
|
3241
3723
|
align-items: center;
|
|
3242
3724
|
justify-content: space-between;
|
|
3243
3725
|
margin-bottom: 24px;
|
|
3244
3726
|
`,
|
|
3245
|
-
title:
|
|
3727
|
+
title: css8`
|
|
3246
3728
|
font-size: ${fontSize.xl};
|
|
3247
3729
|
font-weight: 600;
|
|
3248
3730
|
color: ${colors.text};
|
|
3249
3731
|
margin: 0;
|
|
3250
3732
|
letter-spacing: -0.02em;
|
|
3251
3733
|
`,
|
|
3252
|
-
closeBtn:
|
|
3734
|
+
closeBtn: css8`
|
|
3253
3735
|
padding: 6px;
|
|
3254
3736
|
background: ${colors.surface};
|
|
3255
3737
|
border: 1px solid ${colors.border};
|
|
@@ -3265,26 +3747,26 @@ var styles7 = {
|
|
|
3265
3747
|
border-color: ${colors.borderHover};
|
|
3266
3748
|
}
|
|
3267
3749
|
`,
|
|
3268
|
-
sections:
|
|
3750
|
+
sections: css8`
|
|
3269
3751
|
display: flex;
|
|
3270
3752
|
flex-direction: column;
|
|
3271
3753
|
gap: 24px;
|
|
3272
3754
|
`,
|
|
3273
|
-
sectionTitle:
|
|
3755
|
+
sectionTitle: css8`
|
|
3274
3756
|
font-size: ${fontSize.base};
|
|
3275
3757
|
font-weight: 600;
|
|
3276
3758
|
color: ${colors.text};
|
|
3277
3759
|
margin: 0 0 12px 0;
|
|
3278
3760
|
`,
|
|
3279
|
-
description:
|
|
3761
|
+
description: css8`
|
|
3280
3762
|
font-size: ${fontSize.sm};
|
|
3281
3763
|
color: ${colors.textSecondary};
|
|
3282
3764
|
margin: 0 0 12px 0;
|
|
3283
3765
|
`,
|
|
3284
|
-
codeWrapper:
|
|
3766
|
+
codeWrapper: css8`
|
|
3285
3767
|
position: relative;
|
|
3286
3768
|
`,
|
|
3287
|
-
code:
|
|
3769
|
+
code: css8`
|
|
3288
3770
|
background-color: ${colors.background};
|
|
3289
3771
|
border-radius: 8px;
|
|
3290
3772
|
padding: 12px;
|
|
@@ -3296,7 +3778,7 @@ var styles7 = {
|
|
|
3296
3778
|
overflow-x: auto;
|
|
3297
3779
|
white-space: nowrap;
|
|
3298
3780
|
`,
|
|
3299
|
-
copyBtn:
|
|
3781
|
+
copyBtn: css8`
|
|
3300
3782
|
position: absolute;
|
|
3301
3783
|
top: 8px;
|
|
3302
3784
|
right: 8px;
|
|
@@ -3315,7 +3797,7 @@ var styles7 = {
|
|
|
3315
3797
|
border-color: ${colors.borderHover};
|
|
3316
3798
|
}
|
|
3317
3799
|
`,
|
|
3318
|
-
tooltip:
|
|
3800
|
+
tooltip: css8`
|
|
3319
3801
|
position: absolute;
|
|
3320
3802
|
bottom: 100%;
|
|
3321
3803
|
left: 50%;
|
|
@@ -3340,19 +3822,19 @@ var styles7 = {
|
|
|
3340
3822
|
border-top-color: #1a1f36;
|
|
3341
3823
|
}
|
|
3342
3824
|
`,
|
|
3343
|
-
copyIcon:
|
|
3825
|
+
copyIcon: css8`
|
|
3344
3826
|
width: 14px;
|
|
3345
3827
|
height: 14px;
|
|
3346
3828
|
color: ${colors.textSecondary};
|
|
3347
3829
|
`,
|
|
3348
|
-
codeLine:
|
|
3830
|
+
codeLine: css8`
|
|
3349
3831
|
margin: 0 0 4px 0;
|
|
3350
3832
|
|
|
3351
3833
|
&:last-child {
|
|
3352
3834
|
margin: 0;
|
|
3353
3835
|
}
|
|
3354
3836
|
`,
|
|
3355
|
-
input:
|
|
3837
|
+
input: css8`
|
|
3356
3838
|
width: 100%;
|
|
3357
3839
|
padding: 10px 14px;
|
|
3358
3840
|
border: 1px solid ${colors.border};
|
|
@@ -3372,19 +3854,19 @@ var styles7 = {
|
|
|
3372
3854
|
color: ${colors.textMuted};
|
|
3373
3855
|
}
|
|
3374
3856
|
`,
|
|
3375
|
-
grid:
|
|
3857
|
+
grid: css8`
|
|
3376
3858
|
display: grid;
|
|
3377
3859
|
grid-template-columns: repeat(3, 1fr);
|
|
3378
3860
|
gap: 12px;
|
|
3379
3861
|
`,
|
|
3380
|
-
label:
|
|
3862
|
+
label: css8`
|
|
3381
3863
|
font-size: ${fontSize.xs};
|
|
3382
3864
|
font-weight: 500;
|
|
3383
3865
|
color: ${colors.textSecondary};
|
|
3384
3866
|
display: block;
|
|
3385
3867
|
margin-bottom: 6px;
|
|
3386
3868
|
`,
|
|
3387
|
-
footer:
|
|
3869
|
+
footer: css8`
|
|
3388
3870
|
margin-top: 24px;
|
|
3389
3871
|
padding-top: 20px;
|
|
3390
3872
|
border-top: 1px solid ${colors.border};
|
|
@@ -3392,7 +3874,7 @@ var styles7 = {
|
|
|
3392
3874
|
justify-content: flex-end;
|
|
3393
3875
|
gap: 12px;
|
|
3394
3876
|
`,
|
|
3395
|
-
cancelBtn:
|
|
3877
|
+
cancelBtn: css8`
|
|
3396
3878
|
padding: 10px 18px;
|
|
3397
3879
|
font-size: ${fontSize.base};
|
|
3398
3880
|
font-weight: 500;
|
|
@@ -3408,7 +3890,7 @@ var styles7 = {
|
|
|
3408
3890
|
border-color: ${colors.borderHover};
|
|
3409
3891
|
}
|
|
3410
3892
|
`,
|
|
3411
|
-
saveBtn:
|
|
3893
|
+
saveBtn: css8`
|
|
3412
3894
|
padding: 10px 18px;
|
|
3413
3895
|
font-size: ${fontSize.base};
|
|
3414
3896
|
font-weight: 500;
|
|
@@ -3426,12 +3908,12 @@ var styles7 = {
|
|
|
3426
3908
|
`
|
|
3427
3909
|
};
|
|
3428
3910
|
function StudioSettings() {
|
|
3429
|
-
const [isOpen, setIsOpen] =
|
|
3430
|
-
return /* @__PURE__ */
|
|
3431
|
-
/* @__PURE__ */
|
|
3911
|
+
const [isOpen, setIsOpen] = useState7(false);
|
|
3912
|
+
return /* @__PURE__ */ jsxs8(Fragment4, { children: [
|
|
3913
|
+
/* @__PURE__ */ jsx8("button", { css: styles8.btn, onClick: () => setIsOpen(true), "aria-label": "Settings", children: /* @__PURE__ */ jsxs8(
|
|
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",
|
|
@@ -3440,12 +3922,12 @@ function StudioSettings() {
|
|
|
3440
3922
|
strokeLinecap: "round",
|
|
3441
3923
|
strokeLinejoin: "round",
|
|
3442
3924
|
children: [
|
|
3443
|
-
/* @__PURE__ */
|
|
3444
|
-
/* @__PURE__ */
|
|
3925
|
+
/* @__PURE__ */ jsx8("circle", { cx: "12", cy: "12", r: "3" }),
|
|
3926
|
+
/* @__PURE__ */ jsx8("path", { d: "M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-2 2 2 2 0 01-2-2v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83 0 2 2 0 010-2.83l.06-.06a1.65 1.65 0 00.33-1.82 1.65 1.65 0 00-1.51-1H3a2 2 0 01-2-2 2 2 0 012-2h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 010-2.83 2 2 0 012.83 0l.06.06a1.65 1.65 0 001.82.33H9a1.65 1.65 0 001-1.51V3a2 2 0 012-2 2 2 0 012 2v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 0 2 2 0 010 2.83l-.06.06a1.65 1.65 0 00-.33 1.82V9a1.65 1.65 0 001.51 1H21a2 2 0 012 2 2 2 0 01-2 2h-.09a1.65 1.65 0 00-1.51 1z" })
|
|
3445
3927
|
]
|
|
3446
3928
|
}
|
|
3447
3929
|
) }),
|
|
3448
|
-
isOpen && /* @__PURE__ */
|
|
3930
|
+
isOpen && /* @__PURE__ */ jsx8(SettingsPanel, { onClose: () => setIsOpen(false) })
|
|
3449
3931
|
] });
|
|
3450
3932
|
}
|
|
3451
3933
|
var envTemplate = `CLOUDFLARE_R2_ACCOUNT_ID=abc123def456ghi789
|
|
@@ -3454,72 +3936,147 @@ CLOUDFLARE_R2_SECRET_ACCESS_KEY=your_secret_access_key_here
|
|
|
3454
3936
|
CLOUDFLARE_R2_BUCKET_NAME=my-images-bucket
|
|
3455
3937
|
CLOUDFLARE_R2_PUBLIC_URL=https://cdn.yourdomain.com`;
|
|
3456
3938
|
function SettingsPanel({ onClose }) {
|
|
3457
|
-
const [copied, setCopied] =
|
|
3939
|
+
const [copied, setCopied] = useState7(false);
|
|
3458
3940
|
const handleCopy = () => {
|
|
3459
3941
|
navigator.clipboard.writeText(envTemplate);
|
|
3460
3942
|
setCopied(true);
|
|
3461
3943
|
setTimeout(() => setCopied(false), 2e3);
|
|
3462
3944
|
};
|
|
3463
|
-
return /* @__PURE__ */
|
|
3464
|
-
/* @__PURE__ */
|
|
3465
|
-
/* @__PURE__ */
|
|
3466
|
-
/* @__PURE__ */
|
|
3945
|
+
return /* @__PURE__ */ jsx8("div", { css: styles8.overlay, onClick: onClose, children: /* @__PURE__ */ jsxs8("div", { css: styles8.panel, onClick: (e) => e.stopPropagation(), children: [
|
|
3946
|
+
/* @__PURE__ */ jsxs8("div", { css: styles8.header, children: [
|
|
3947
|
+
/* @__PURE__ */ jsx8("h2", { css: styles8.title, children: "Settings" }),
|
|
3948
|
+
/* @__PURE__ */ jsx8("button", { css: styles8.closeBtn, onClick: onClose, children: /* @__PURE__ */ jsx8("svg", { css: styles8.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx8("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })
|
|
3467
3949
|
] }),
|
|
3468
|
-
/* @__PURE__ */
|
|
3469
|
-
/* @__PURE__ */
|
|
3470
|
-
/* @__PURE__ */
|
|
3471
|
-
/* @__PURE__ */
|
|
3472
|
-
/* @__PURE__ */
|
|
3473
|
-
/* @__PURE__ */
|
|
3474
|
-
copied && /* @__PURE__ */
|
|
3475
|
-
/* @__PURE__ */
|
|
3950
|
+
/* @__PURE__ */ jsxs8("div", { css: styles8.sections, children: [
|
|
3951
|
+
/* @__PURE__ */ jsxs8("section", { children: [
|
|
3952
|
+
/* @__PURE__ */ jsx8("h3", { css: styles8.sectionTitle, children: "Cloudflare R2" }),
|
|
3953
|
+
/* @__PURE__ */ jsx8("p", { css: styles8.description, children: "Configure in .env.local file:" }),
|
|
3954
|
+
/* @__PURE__ */ jsxs8("div", { css: styles8.codeWrapper, children: [
|
|
3955
|
+
/* @__PURE__ */ jsxs8("button", { css: styles8.copyBtn, onClick: handleCopy, title: "Copy to clipboard", children: [
|
|
3956
|
+
copied && /* @__PURE__ */ jsx8("span", { css: styles8.tooltip, children: "Copied!" }),
|
|
3957
|
+
/* @__PURE__ */ jsx8("svg", { css: styles8.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx8("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__ */
|
|
3478
|
-
/* @__PURE__ */
|
|
3479
|
-
/* @__PURE__ */
|
|
3480
|
-
/* @__PURE__ */
|
|
3481
|
-
/* @__PURE__ */
|
|
3482
|
-
/* @__PURE__ */
|
|
3959
|
+
/* @__PURE__ */ jsxs8("div", { css: styles8.code, children: [
|
|
3960
|
+
/* @__PURE__ */ jsx8("p", { css: styles8.codeLine, children: "CLOUDFLARE_R2_ACCOUNT_ID=abc123def456ghi789" }),
|
|
3961
|
+
/* @__PURE__ */ jsx8("p", { css: styles8.codeLine, children: "CLOUDFLARE_R2_ACCESS_KEY_ID=your_access_key_id_here" }),
|
|
3962
|
+
/* @__PURE__ */ jsx8("p", { css: styles8.codeLine, children: "CLOUDFLARE_R2_SECRET_ACCESS_KEY=your_secret_access_key_here" }),
|
|
3963
|
+
/* @__PURE__ */ jsx8("p", { css: styles8.codeLine, children: "CLOUDFLARE_R2_BUCKET_NAME=my-images-bucket" }),
|
|
3964
|
+
/* @__PURE__ */ jsx8("p", { css: styles8.codeLine, children: "CLOUDFLARE_R2_PUBLIC_URL=https://cdn.yourdomain.com" })
|
|
3483
3965
|
] })
|
|
3484
3966
|
] })
|
|
3485
3967
|
] }),
|
|
3486
|
-
/* @__PURE__ */
|
|
3487
|
-
/* @__PURE__ */
|
|
3488
|
-
/* @__PURE__ */
|
|
3489
|
-
/* @__PURE__ */
|
|
3490
|
-
/* @__PURE__ */
|
|
3491
|
-
/* @__PURE__ */
|
|
3968
|
+
/* @__PURE__ */ jsxs8("section", { children: [
|
|
3969
|
+
/* @__PURE__ */ jsx8("h3", { css: styles8.sectionTitle, children: "Thumbnail Sizes" }),
|
|
3970
|
+
/* @__PURE__ */ jsxs8("div", { css: styles8.grid, children: [
|
|
3971
|
+
/* @__PURE__ */ jsxs8("div", { children: [
|
|
3972
|
+
/* @__PURE__ */ jsx8("label", { css: styles8.label, children: "Small" }),
|
|
3973
|
+
/* @__PURE__ */ jsx8("input", { css: styles8.input, type: "number", defaultValue: 300 })
|
|
3492
3974
|
] }),
|
|
3493
|
-
/* @__PURE__ */
|
|
3494
|
-
/* @__PURE__ */
|
|
3495
|
-
/* @__PURE__ */
|
|
3975
|
+
/* @__PURE__ */ jsxs8("div", { children: [
|
|
3976
|
+
/* @__PURE__ */ jsx8("label", { css: styles8.label, children: "Medium" }),
|
|
3977
|
+
/* @__PURE__ */ jsx8("input", { css: styles8.input, type: "number", defaultValue: 700 })
|
|
3496
3978
|
] }),
|
|
3497
|
-
/* @__PURE__ */
|
|
3498
|
-
/* @__PURE__ */
|
|
3499
|
-
/* @__PURE__ */
|
|
3979
|
+
/* @__PURE__ */ jsxs8("div", { children: [
|
|
3980
|
+
/* @__PURE__ */ jsx8("label", { css: styles8.label, children: "Large" }),
|
|
3981
|
+
/* @__PURE__ */ jsx8("input", { css: styles8.input, type: "number", defaultValue: 1400 })
|
|
3500
3982
|
] })
|
|
3501
3983
|
] })
|
|
3502
3984
|
] })
|
|
3503
3985
|
] }),
|
|
3504
|
-
/* @__PURE__ */
|
|
3505
|
-
/* @__PURE__ */
|
|
3506
|
-
/* @__PURE__ */
|
|
3986
|
+
/* @__PURE__ */ jsxs8("div", { css: styles8.footer, children: [
|
|
3987
|
+
/* @__PURE__ */ jsx8("button", { css: styles8.cancelBtn, onClick: onClose, children: "Cancel" }),
|
|
3988
|
+
/* @__PURE__ */ jsx8("button", { css: styles8.saveBtn, children: "Save Changes" })
|
|
3507
3989
|
] })
|
|
3508
3990
|
] }) });
|
|
3509
3991
|
}
|
|
3510
3992
|
|
|
3993
|
+
// src/components/ErrorModal.tsx
|
|
3994
|
+
import { css as css9 } from "@emotion/react";
|
|
3995
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "@emotion/react/jsx-runtime";
|
|
3996
|
+
var styles9 = {
|
|
3997
|
+
overlay: css9`
|
|
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: css9`
|
|
4007
|
+
background: ${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: css9`
|
|
4015
|
+
display: flex;
|
|
4016
|
+
align-items: center;
|
|
4017
|
+
gap: 12px;
|
|
4018
|
+
margin-bottom: 12px;
|
|
4019
|
+
`,
|
|
4020
|
+
icon: css9`
|
|
4021
|
+
width: 24px;
|
|
4022
|
+
height: 24px;
|
|
4023
|
+
color: ${colors.danger};
|
|
4024
|
+
flex-shrink: 0;
|
|
4025
|
+
`,
|
|
4026
|
+
title: css9`
|
|
4027
|
+
font-size: ${fontSize.lg};
|
|
4028
|
+
font-weight: 600;
|
|
4029
|
+
color: ${colors.text};
|
|
4030
|
+
margin: 0;
|
|
4031
|
+
`,
|
|
4032
|
+
message: css9`
|
|
4033
|
+
font-size: ${fontSize.base};
|
|
4034
|
+
color: ${colors.textSecondary};
|
|
4035
|
+
margin: 0 0 20px 0;
|
|
4036
|
+
line-height: 1.5;
|
|
4037
|
+
`,
|
|
4038
|
+
button: css9`
|
|
4039
|
+
width: 100%;
|
|
4040
|
+
padding: 10px 16px;
|
|
4041
|
+
border-radius: 6px;
|
|
4042
|
+
font-size: ${fontSize.base};
|
|
4043
|
+
font-weight: 500;
|
|
4044
|
+
border: none;
|
|
4045
|
+
background: ${colors.primary};
|
|
4046
|
+
color: white;
|
|
4047
|
+
cursor: pointer;
|
|
4048
|
+
transition: background 0.15s ease;
|
|
4049
|
+
|
|
4050
|
+
&:hover {
|
|
4051
|
+
background: ${colors.primaryHover};
|
|
4052
|
+
}
|
|
4053
|
+
`
|
|
4054
|
+
};
|
|
4055
|
+
function ErrorModal() {
|
|
4056
|
+
const { error, clearError } = useStudio();
|
|
4057
|
+
if (!error) return null;
|
|
4058
|
+
return /* @__PURE__ */ jsx9("div", { css: styles9.overlay, onClick: clearError, children: /* @__PURE__ */ jsxs9("div", { css: styles9.modal, onClick: (e) => e.stopPropagation(), children: [
|
|
4059
|
+
/* @__PURE__ */ jsxs9("div", { css: styles9.header, children: [
|
|
4060
|
+
/* @__PURE__ */ jsx9("svg", { css: styles9.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx9("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__ */ jsx9("h3", { css: styles9.title, children: error.title })
|
|
4062
|
+
] }),
|
|
4063
|
+
/* @__PURE__ */ jsx9("p", { css: styles9.message, children: error.message }),
|
|
4064
|
+
/* @__PURE__ */ jsx9("button", { css: styles9.button, onClick: clearError, children: "OK" })
|
|
4065
|
+
] }) });
|
|
4066
|
+
}
|
|
4067
|
+
|
|
3511
4068
|
// src/components/StudioUI.tsx
|
|
3512
|
-
import { jsx as
|
|
4069
|
+
import { jsx as jsx10, jsxs as jsxs10 } from "@emotion/react/jsx-runtime";
|
|
3513
4070
|
var btnHeight3 = "36px";
|
|
3514
|
-
var
|
|
3515
|
-
container:
|
|
4071
|
+
var styles10 = {
|
|
4072
|
+
container: css10`
|
|
3516
4073
|
${baseReset}
|
|
3517
4074
|
display: flex;
|
|
3518
4075
|
flex-direction: column;
|
|
3519
4076
|
height: 100%;
|
|
3520
4077
|
background: ${colors.background};
|
|
3521
4078
|
`,
|
|
3522
|
-
header:
|
|
4079
|
+
header: css10`
|
|
3523
4080
|
display: flex;
|
|
3524
4081
|
align-items: center;
|
|
3525
4082
|
justify-content: space-between;
|
|
@@ -3528,7 +4085,7 @@ var styles8 = {
|
|
|
3528
4085
|
border-bottom: 1px solid ${colors.border};
|
|
3529
4086
|
position: relative;
|
|
3530
4087
|
`,
|
|
3531
|
-
title:
|
|
4088
|
+
title: css10`
|
|
3532
4089
|
font-size: ${fontSize.lg};
|
|
3533
4090
|
font-weight: 600;
|
|
3534
4091
|
color: ${colors.text};
|
|
@@ -3536,14 +4093,14 @@ var styles8 = {
|
|
|
3536
4093
|
letter-spacing: -0.02em;
|
|
3537
4094
|
flex-shrink: 0;
|
|
3538
4095
|
`,
|
|
3539
|
-
headerLeft:
|
|
4096
|
+
headerLeft: css10`
|
|
3540
4097
|
display: flex;
|
|
3541
4098
|
align-items: center;
|
|
3542
4099
|
gap: 12px;
|
|
3543
4100
|
flex: 1;
|
|
3544
4101
|
min-width: 0;
|
|
3545
4102
|
`,
|
|
3546
|
-
headerCenter:
|
|
4103
|
+
headerCenter: css10`
|
|
3547
4104
|
position: absolute;
|
|
3548
4105
|
left: 50%;
|
|
3549
4106
|
transform: translateX(-50%);
|
|
@@ -3551,7 +4108,7 @@ var styles8 = {
|
|
|
3551
4108
|
align-items: center;
|
|
3552
4109
|
max-width: 50%;
|
|
3553
4110
|
`,
|
|
3554
|
-
breadcrumbs:
|
|
4111
|
+
breadcrumbs: css10`
|
|
3555
4112
|
display: flex;
|
|
3556
4113
|
align-items: center;
|
|
3557
4114
|
gap: 6px;
|
|
@@ -3559,11 +4116,11 @@ var styles8 = {
|
|
|
3559
4116
|
color: ${colors.textSecondary};
|
|
3560
4117
|
overflow: hidden;
|
|
3561
4118
|
`,
|
|
3562
|
-
breadcrumbSeparator:
|
|
4119
|
+
breadcrumbSeparator: css10`
|
|
3563
4120
|
color: ${colors.border};
|
|
3564
4121
|
flex-shrink: 0;
|
|
3565
4122
|
`,
|
|
3566
|
-
breadcrumbItem:
|
|
4123
|
+
breadcrumbItem: css10`
|
|
3567
4124
|
color: ${colors.textSecondary};
|
|
3568
4125
|
text-decoration: none;
|
|
3569
4126
|
cursor: pointer;
|
|
@@ -3574,19 +4131,19 @@ var styles8 = {
|
|
|
3574
4131
|
color: ${colors.primary};
|
|
3575
4132
|
}
|
|
3576
4133
|
`,
|
|
3577
|
-
breadcrumbCurrent:
|
|
4134
|
+
breadcrumbCurrent: css10`
|
|
3578
4135
|
color: ${colors.text};
|
|
3579
4136
|
font-weight: 500;
|
|
3580
4137
|
white-space: nowrap;
|
|
3581
4138
|
overflow: hidden;
|
|
3582
4139
|
text-overflow: ellipsis;
|
|
3583
4140
|
`,
|
|
3584
|
-
headerActions:
|
|
4141
|
+
headerActions: css10`
|
|
3585
4142
|
display: flex;
|
|
3586
4143
|
align-items: center;
|
|
3587
4144
|
gap: 8px;
|
|
3588
4145
|
`,
|
|
3589
|
-
headerBtn:
|
|
4146
|
+
headerBtn: css10`
|
|
3590
4147
|
height: ${btnHeight3};
|
|
3591
4148
|
padding: 0 12px;
|
|
3592
4149
|
background: ${colors.surface};
|
|
@@ -3603,23 +4160,23 @@ var styles8 = {
|
|
|
3603
4160
|
border-color: ${colors.borderHover};
|
|
3604
4161
|
}
|
|
3605
4162
|
`,
|
|
3606
|
-
headerIcon:
|
|
4163
|
+
headerIcon: css10`
|
|
3607
4164
|
width: 16px;
|
|
3608
4165
|
height: 16px;
|
|
3609
4166
|
color: ${colors.textSecondary};
|
|
3610
4167
|
`,
|
|
3611
|
-
content:
|
|
4168
|
+
content: css10`
|
|
3612
4169
|
flex: 1;
|
|
3613
4170
|
display: flex;
|
|
3614
4171
|
overflow: hidden;
|
|
3615
4172
|
`,
|
|
3616
|
-
fileBrowser:
|
|
4173
|
+
fileBrowser: css10`
|
|
3617
4174
|
flex: 1;
|
|
3618
4175
|
min-width: 0;
|
|
3619
4176
|
overflow: auto;
|
|
3620
4177
|
padding: 20px 24px;
|
|
3621
4178
|
`,
|
|
3622
|
-
dropOverlay:
|
|
4179
|
+
dropOverlay: css10`
|
|
3623
4180
|
position: absolute;
|
|
3624
4181
|
top: 0;
|
|
3625
4182
|
left: 0;
|
|
@@ -3634,7 +4191,7 @@ var styles8 = {
|
|
|
3634
4191
|
z-index: 50;
|
|
3635
4192
|
pointer-events: none;
|
|
3636
4193
|
`,
|
|
3637
|
-
dropMessage:
|
|
4194
|
+
dropMessage: css10`
|
|
3638
4195
|
display: flex;
|
|
3639
4196
|
flex-direction: column;
|
|
3640
4197
|
align-items: center;
|
|
@@ -3643,36 +4200,43 @@ var styles8 = {
|
|
|
3643
4200
|
font-size: ${fontSize.lg};
|
|
3644
4201
|
font-weight: 600;
|
|
3645
4202
|
`,
|
|
3646
|
-
dropIcon:
|
|
4203
|
+
dropIcon: css10`
|
|
3647
4204
|
width: 48px;
|
|
3648
4205
|
height: 48px;
|
|
3649
4206
|
`
|
|
3650
4207
|
};
|
|
3651
4208
|
function StudioUI({ onClose, isVisible = true }) {
|
|
3652
|
-
const [currentPath, setCurrentPathInternal] =
|
|
3653
|
-
const [selectedItems, setSelectedItems] =
|
|
3654
|
-
const [lastSelectedPath, setLastSelectedPath] =
|
|
3655
|
-
const [viewMode, setViewMode] =
|
|
3656
|
-
const [focusedItem, setFocusedItem] =
|
|
3657
|
-
const [meta, setMeta] =
|
|
3658
|
-
const [isLoading, setIsLoading] =
|
|
3659
|
-
const [refreshKey, setRefreshKey] =
|
|
3660
|
-
const [searchQuery, setSearchQuery] =
|
|
3661
|
-
const [
|
|
3662
|
-
const
|
|
4209
|
+
const [currentPath, setCurrentPathInternal] = useState8("public");
|
|
4210
|
+
const [selectedItems, setSelectedItems] = useState8(/* @__PURE__ */ new Set());
|
|
4211
|
+
const [lastSelectedPath, setLastSelectedPath] = useState8(null);
|
|
4212
|
+
const [viewMode, setViewMode] = useState8("grid");
|
|
4213
|
+
const [focusedItem, setFocusedItem] = useState8(null);
|
|
4214
|
+
const [meta, setMeta] = useState8(null);
|
|
4215
|
+
const [isLoading, setIsLoading] = useState8(false);
|
|
4216
|
+
const [refreshKey, setRefreshKey] = useState8(0);
|
|
4217
|
+
const [searchQuery, setSearchQuery] = useState8("");
|
|
4218
|
+
const [error, setError] = useState8(null);
|
|
4219
|
+
const [isDragging, setIsDragging] = useState8(false);
|
|
4220
|
+
const triggerRefresh = useCallback3(() => {
|
|
3663
4221
|
setRefreshKey((k) => k + 1);
|
|
3664
4222
|
}, []);
|
|
3665
|
-
const
|
|
4223
|
+
const showError = useCallback3((title, message) => {
|
|
4224
|
+
setError({ title, message });
|
|
4225
|
+
}, []);
|
|
4226
|
+
const clearError = useCallback3(() => {
|
|
4227
|
+
setError(null);
|
|
4228
|
+
}, []);
|
|
4229
|
+
const handleDragOver = useCallback3((e) => {
|
|
3666
4230
|
e.preventDefault();
|
|
3667
4231
|
e.stopPropagation();
|
|
3668
4232
|
setIsDragging(true);
|
|
3669
4233
|
}, []);
|
|
3670
|
-
const handleDragLeave =
|
|
4234
|
+
const handleDragLeave = useCallback3((e) => {
|
|
3671
4235
|
e.preventDefault();
|
|
3672
4236
|
e.stopPropagation();
|
|
3673
4237
|
setIsDragging(false);
|
|
3674
4238
|
}, []);
|
|
3675
|
-
const handleDrop =
|
|
4239
|
+
const handleDrop = useCallback3(async (e) => {
|
|
3676
4240
|
e.preventDefault();
|
|
3677
4241
|
e.stopPropagation();
|
|
3678
4242
|
setIsDragging(false);
|
|
@@ -3690,25 +4254,25 @@ 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();
|
|
3698
4262
|
}, [currentPath, triggerRefresh]);
|
|
3699
|
-
const navigateUp =
|
|
4263
|
+
const navigateUp = useCallback3(() => {
|
|
3700
4264
|
if (currentPath === "public") return;
|
|
3701
4265
|
const parts = currentPath.split("/");
|
|
3702
4266
|
parts.pop();
|
|
3703
4267
|
setCurrentPathInternal(parts.join("/") || "public");
|
|
3704
4268
|
setSelectedItems(/* @__PURE__ */ new Set());
|
|
3705
4269
|
}, [currentPath]);
|
|
3706
|
-
const setCurrentPath =
|
|
4270
|
+
const setCurrentPath = useCallback3((path) => {
|
|
3707
4271
|
setCurrentPathInternal(path);
|
|
3708
4272
|
setSelectedItems(/* @__PURE__ */ new Set());
|
|
3709
4273
|
setFocusedItem(null);
|
|
3710
4274
|
}, []);
|
|
3711
|
-
const toggleSelection =
|
|
4275
|
+
const toggleSelection = useCallback3((path) => {
|
|
3712
4276
|
setSelectedItems((prev) => {
|
|
3713
4277
|
const next = new Set(prev);
|
|
3714
4278
|
if (next.has(path)) {
|
|
@@ -3720,7 +4284,7 @@ function StudioUI({ onClose, isVisible = true }) {
|
|
|
3720
4284
|
});
|
|
3721
4285
|
setLastSelectedPath(path);
|
|
3722
4286
|
}, []);
|
|
3723
|
-
const selectRange =
|
|
4287
|
+
const selectRange = useCallback3((fromPath, toPath, allItems) => {
|
|
3724
4288
|
const fromIndex = allItems.findIndex((item) => item.path === fromPath);
|
|
3725
4289
|
const toIndex = allItems.findIndex((item) => item.path === toPath);
|
|
3726
4290
|
if (fromIndex === -1 || toIndex === -1) return;
|
|
@@ -3735,13 +4299,13 @@ function StudioUI({ onClose, isVisible = true }) {
|
|
|
3735
4299
|
});
|
|
3736
4300
|
setLastSelectedPath(toPath);
|
|
3737
4301
|
}, []);
|
|
3738
|
-
const selectAll =
|
|
4302
|
+
const selectAll = useCallback3((items) => {
|
|
3739
4303
|
setSelectedItems(new Set(items.map((item) => item.path)));
|
|
3740
4304
|
}, []);
|
|
3741
|
-
const clearSelection =
|
|
4305
|
+
const clearSelection = useCallback3(() => {
|
|
3742
4306
|
setSelectedItems(/* @__PURE__ */ new Set());
|
|
3743
4307
|
}, []);
|
|
3744
|
-
const handleKeyDown =
|
|
4308
|
+
const handleKeyDown = useCallback3(
|
|
3745
4309
|
(e) => {
|
|
3746
4310
|
if (e.key === "Escape") {
|
|
3747
4311
|
const target = e.target;
|
|
@@ -3757,7 +4321,7 @@ function StudioUI({ onClose, isVisible = true }) {
|
|
|
3757
4321
|
},
|
|
3758
4322
|
[onClose, focusedItem]
|
|
3759
4323
|
);
|
|
3760
|
-
|
|
4324
|
+
useEffect3(() => {
|
|
3761
4325
|
if (isVisible) {
|
|
3762
4326
|
document.addEventListener("keydown", handleKeyDown);
|
|
3763
4327
|
document.body.style.overflow = "hidden";
|
|
@@ -3793,43 +4357,47 @@ 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__ */
|
|
3799
|
-
/* @__PURE__ */
|
|
3800
|
-
/* @__PURE__ */
|
|
3801
|
-
/* @__PURE__ */
|
|
3802
|
-
/* @__PURE__ */
|
|
3803
|
-
/* @__PURE__ */
|
|
3804
|
-
/* @__PURE__ */
|
|
4365
|
+
return /* @__PURE__ */ jsx10(StudioContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs10("div", { css: styles10.container, children: [
|
|
4366
|
+
/* @__PURE__ */ jsxs10("div", { css: styles10.header, children: [
|
|
4367
|
+
/* @__PURE__ */ jsx10("div", { css: styles10.headerLeft, children: /* @__PURE__ */ jsx10("h1", { css: styles10.title, children: "Studio" }) }),
|
|
4368
|
+
/* @__PURE__ */ jsx10("div", { css: styles10.headerCenter, children: /* @__PURE__ */ jsx10(Breadcrumbs, { currentPath, onNavigate: setCurrentPath }) }),
|
|
4369
|
+
/* @__PURE__ */ jsxs10("div", { css: styles10.headerActions, children: [
|
|
4370
|
+
/* @__PURE__ */ jsx10(StudioSettings, {}),
|
|
4371
|
+
/* @__PURE__ */ jsx10(
|
|
3805
4372
|
"button",
|
|
3806
4373
|
{
|
|
3807
|
-
css:
|
|
4374
|
+
css: styles10.headerBtn,
|
|
3808
4375
|
onClick: onClose,
|
|
3809
4376
|
"aria-label": "Close Studio",
|
|
3810
|
-
children: /* @__PURE__ */
|
|
4377
|
+
children: /* @__PURE__ */ jsx10(CloseIcon, {})
|
|
3811
4378
|
}
|
|
3812
4379
|
)
|
|
3813
4380
|
] })
|
|
3814
4381
|
] }),
|
|
3815
|
-
/* @__PURE__ */
|
|
3816
|
-
/* @__PURE__ */
|
|
4382
|
+
/* @__PURE__ */ jsx10(StudioToolbar, {}),
|
|
4383
|
+
/* @__PURE__ */ jsxs10(
|
|
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__ */
|
|
3825
|
-
/* @__PURE__ */
|
|
3826
|
-
/* @__PURE__ */
|
|
4391
|
+
isDragging && /* @__PURE__ */ jsx10("div", { css: styles10.dropOverlay, children: /* @__PURE__ */ jsxs10("div", { css: styles10.dropMessage, children: [
|
|
4392
|
+
/* @__PURE__ */ jsx10("svg", { css: styles10.dropIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx10("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" }) }),
|
|
4393
|
+
/* @__PURE__ */ jsx10("span", { children: "Drop files to upload" })
|
|
3827
4394
|
] }) }),
|
|
3828
|
-
/* @__PURE__ */
|
|
4395
|
+
/* @__PURE__ */ jsx10("div", { css: styles10.fileBrowser, children: viewMode === "grid" ? /* @__PURE__ */ jsx10(StudioFileGrid, {}) : /* @__PURE__ */ jsx10(StudioFileList, {}) })
|
|
3829
4396
|
]
|
|
3830
4397
|
}
|
|
3831
4398
|
),
|
|
3832
|
-
focusedItem && /* @__PURE__ */
|
|
4399
|
+
focusedItem && /* @__PURE__ */ jsx10(StudioDetailView, {}),
|
|
4400
|
+
/* @__PURE__ */ jsx10(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__ */
|
|
3842
|
-
index > 0 && /* @__PURE__ */
|
|
3843
|
-
index === breadcrumbs.length - 1 ? /* @__PURE__ */
|
|
4409
|
+
return /* @__PURE__ */ jsx10("div", { css: styles10.breadcrumbs, children: breadcrumbs.map((crumb, index) => /* @__PURE__ */ jsxs10("span", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
|
|
4410
|
+
index > 0 && /* @__PURE__ */ jsx10("span", { css: styles10.breadcrumbSeparator, children: "/" }),
|
|
4411
|
+
index === breadcrumbs.length - 1 ? /* @__PURE__ */ jsx10("span", { css: styles10.breadcrumbCurrent, children: crumb.name }) : /* @__PURE__ */ jsx10(
|
|
3844
4412
|
"span",
|
|
3845
4413
|
{
|
|
3846
|
-
css:
|
|
4414
|
+
css: styles10.breadcrumbItem,
|
|
3847
4415
|
onClick: () => onNavigate(crumb.path),
|
|
3848
4416
|
children: crumb.name
|
|
3849
4417
|
}
|
|
@@ -3851,10 +4419,10 @@ function Breadcrumbs({ currentPath, onNavigate }) {
|
|
|
3851
4419
|
] }, crumb.path)) });
|
|
3852
4420
|
}
|
|
3853
4421
|
function CloseIcon() {
|
|
3854
|
-
return /* @__PURE__ */
|
|
4422
|
+
return /* @__PURE__ */ jsxs10(
|
|
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",
|
|
@@ -3863,8 +4431,8 @@ function CloseIcon() {
|
|
|
3863
4431
|
strokeLinecap: "round",
|
|
3864
4432
|
strokeLinejoin: "round",
|
|
3865
4433
|
children: [
|
|
3866
|
-
/* @__PURE__ */
|
|
3867
|
-
/* @__PURE__ */
|
|
4434
|
+
/* @__PURE__ */ jsx10("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
4435
|
+
/* @__PURE__ */ jsx10("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
3868
4436
|
]
|
|
3869
4437
|
}
|
|
3870
4438
|
);
|
|
@@ -3874,4 +4442,4 @@ export {
|
|
|
3874
4442
|
StudioUI,
|
|
3875
4443
|
StudioUI_default as default
|
|
3876
4444
|
};
|
|
3877
|
-
//# sourceMappingURL=StudioUI-
|
|
4445
|
+
//# sourceMappingURL=StudioUI-XV7HCEAF.mjs.map
|