@gallop.software/studio 0.1.83 → 0.1.85

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.
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-HXE6XCG2.mjs";
8
8
 
9
9
  // src/components/StudioUI.tsx
10
- import { useEffect as useEffect3, useCallback as useCallback3, useState as useState8 } from "react";
10
+ import { useEffect as useEffect3, useCallback as useCallback3, useState as useState9 } from "react";
11
11
  import { css as css10 } from "@emotion/react";
12
12
 
13
13
  // src/components/StudioContext.tsx
@@ -65,7 +65,7 @@ function useStudio() {
65
65
  }
66
66
 
67
67
  // src/components/StudioToolbar.tsx
68
- import { useCallback, useRef, useState as useState2 } from "react";
68
+ import { useCallback, useRef, useState as useState3 } from "react";
69
69
  import { css as css4, keyframes as keyframes3 } from "@emotion/react";
70
70
 
71
71
  // src/components/StudioModal.tsx
@@ -675,8 +675,15 @@ function StudioFolderPicker({ selectedItems, currentPath, onMove, onCancel }) {
675
675
  }
676
676
 
677
677
  // src/components/R2SetupModal.tsx
678
+ import { useState as useState2 } from "react";
678
679
  import { css as css3 } from "@emotion/react";
679
680
  import { jsx as jsx3, jsxs as jsxs3 } from "@emotion/react/jsx-runtime";
681
+ var ENV_TEMPLATE = `CLOUDFLARE_R2_ACCOUNT_ID=your_account_id
682
+ CLOUDFLARE_R2_ACCESS_KEY_ID=your_access_key
683
+ CLOUDFLARE_R2_SECRET_ACCESS_KEY=your_secret_key
684
+ CLOUDFLARE_R2_BUCKET_NAME=your_bucket_name
685
+ CLOUDFLARE_R2_PUBLIC_URL=https://pub-xxx.r2.dev
686
+ NEXT_PUBLIC_CLOUDFLARE_R2_PUBLIC_URL=https://pub-xxx.r2.dev`;
680
687
  var styles3 = {
681
688
  overlay: css3`
682
689
  position: fixed;
@@ -793,12 +800,16 @@ var styles3 = {
793
800
  text-decoration: underline;
794
801
  }
795
802
  `,
803
+ envVarsWrapper: css3`
804
+ position: relative;
805
+ margin-top: 20px;
806
+ `,
796
807
  envVars: css3`
797
808
  background: ${colors.background};
798
809
  border: 1px solid ${colors.border};
799
810
  border-radius: 8px;
800
811
  padding: 16px;
801
- margin-top: 20px;
812
+ padding-right: 48px;
802
813
  font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;
803
814
  font-size: 13px;
804
815
  line-height: 1.8;
@@ -814,6 +825,57 @@ var styles3 = {
814
825
  envValue: css3`
815
826
  color: ${colors.textSecondary};
816
827
  `,
828
+ copyBtn: css3`
829
+ position: absolute;
830
+ top: 8px;
831
+ right: 8px;
832
+ width: 32px;
833
+ height: 32px;
834
+ display: flex;
835
+ align-items: center;
836
+ justify-content: center;
837
+ background: ${colors.surface};
838
+ border: 1px solid ${colors.border};
839
+ border-radius: 6px;
840
+ cursor: pointer;
841
+ color: ${colors.textMuted};
842
+ transition: all 0.15s ease;
843
+
844
+ &:hover {
845
+ background: ${colors.surfaceHover};
846
+ color: ${colors.text};
847
+ border-color: #d0d5dd;
848
+ }
849
+ `,
850
+ copyIcon: css3`
851
+ width: 16px;
852
+ height: 16px;
853
+ `,
854
+ copiedTooltip: css3`
855
+ position: absolute;
856
+ top: 50%;
857
+ right: 100%;
858
+ transform: translateY(-50%);
859
+ background: #1a1f36;
860
+ color: white;
861
+ padding: 4px 8px;
862
+ border-radius: 4px;
863
+ font-size: 12px;
864
+ white-space: nowrap;
865
+ margin-right: 6px;
866
+ pointer-events: none;
867
+
868
+ &::before {
869
+ content: '';
870
+ position: absolute;
871
+ right: -4px;
872
+ top: 50%;
873
+ transform: translateY(-50%);
874
+ border-left: 4px solid #1a1f36;
875
+ border-top: 4px solid transparent;
876
+ border-bottom: 4px solid transparent;
877
+ }
878
+ `,
817
879
  footer: css3`
818
880
  padding: 16px 24px;
819
881
  border-top: 1px solid ${colors.border};
@@ -862,6 +924,16 @@ var styles3 = {
862
924
  `
863
925
  };
864
926
  function R2SetupModal({ isOpen, onClose }) {
927
+ const [copied, setCopied] = useState2(false);
928
+ const handleCopy = async () => {
929
+ try {
930
+ await navigator.clipboard.writeText(ENV_TEMPLATE);
931
+ setCopied(true);
932
+ setTimeout(() => setCopied(false), 2e3);
933
+ } catch (error) {
934
+ console.error("Failed to copy:", error);
935
+ }
936
+ };
865
937
  if (!isOpen) return null;
866
938
  return /* @__PURE__ */ jsx3("div", { css: styles3.overlay, onClick: onClose, children: /* @__PURE__ */ jsxs3("div", { css: styles3.modal, onClick: (e) => e.stopPropagation(), children: [
867
939
  /* @__PURE__ */ jsxs3("div", { css: styles3.header, children: [
@@ -926,31 +998,42 @@ function R2SetupModal({ isOpen, onClose }) {
926
998
  ] })
927
999
  ] })
928
1000
  ] }),
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" })
1001
+ /* @__PURE__ */ jsxs3("div", { css: styles3.envVarsWrapper, children: [
1002
+ /* @__PURE__ */ jsxs3("div", { css: styles3.envVars, children: [
1003
+ /* @__PURE__ */ jsxs3("span", { css: styles3.envVar, children: [
1004
+ /* @__PURE__ */ jsx3("span", { css: styles3.envKey, children: "CLOUDFLARE_R2_ACCOUNT_ID" }),
1005
+ "=",
1006
+ /* @__PURE__ */ jsx3("span", { css: styles3.envValue, children: "your_account_id" })
1007
+ ] }),
1008
+ /* @__PURE__ */ jsxs3("span", { css: styles3.envVar, children: [
1009
+ /* @__PURE__ */ jsx3("span", { css: styles3.envKey, children: "CLOUDFLARE_R2_ACCESS_KEY_ID" }),
1010
+ "=",
1011
+ /* @__PURE__ */ jsx3("span", { css: styles3.envValue, children: "your_access_key" })
1012
+ ] }),
1013
+ /* @__PURE__ */ jsxs3("span", { css: styles3.envVar, children: [
1014
+ /* @__PURE__ */ jsx3("span", { css: styles3.envKey, children: "CLOUDFLARE_R2_SECRET_ACCESS_KEY" }),
1015
+ "=",
1016
+ /* @__PURE__ */ jsx3("span", { css: styles3.envValue, children: "your_secret_key" })
1017
+ ] }),
1018
+ /* @__PURE__ */ jsxs3("span", { css: styles3.envVar, children: [
1019
+ /* @__PURE__ */ jsx3("span", { css: styles3.envKey, children: "CLOUDFLARE_R2_BUCKET_NAME" }),
1020
+ "=",
1021
+ /* @__PURE__ */ jsx3("span", { css: styles3.envValue, children: "your_bucket_name" })
1022
+ ] }),
1023
+ /* @__PURE__ */ jsxs3("span", { css: styles3.envVar, children: [
1024
+ /* @__PURE__ */ jsx3("span", { css: styles3.envKey, children: "CLOUDFLARE_R2_PUBLIC_URL" }),
1025
+ "=",
1026
+ /* @__PURE__ */ jsx3("span", { css: styles3.envValue, children: "https://pub-xxx.r2.dev" })
1027
+ ] }),
1028
+ /* @__PURE__ */ jsxs3("span", { css: styles3.envVar, children: [
1029
+ /* @__PURE__ */ jsx3("span", { css: styles3.envKey, children: "NEXT_PUBLIC_CLOUDFLARE_R2_PUBLIC_URL" }),
1030
+ "=",
1031
+ /* @__PURE__ */ jsx3("span", { css: styles3.envValue, children: "https://pub-xxx.r2.dev" })
1032
+ ] })
949
1033
  ] }),
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" })
1034
+ /* @__PURE__ */ jsxs3("button", { css: styles3.copyBtn, onClick: handleCopy, title: "Copy to clipboard", children: [
1035
+ copied && /* @__PURE__ */ jsx3("span", { css: styles3.copiedTooltip, children: "Copied!" }),
1036
+ /* @__PURE__ */ jsx3("svg", { css: styles3.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx3("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" }) })
954
1037
  ] })
955
1038
  ] })
956
1039
  ] }),
@@ -1178,27 +1261,27 @@ function StudioToolbar() {
1178
1261
  const { selectedItems, viewMode, setViewMode, clearSelection, currentPath, triggerRefresh, focusedItem } = useStudio();
1179
1262
  const fileInputRef = useRef(null);
1180
1263
  const abortControllerRef = useRef(null);
1181
- const [uploading, setUploading] = useState2(false);
1182
- const [refreshing, setRefreshing] = useState2(false);
1183
- const [processing, setProcessing] = useState2(false);
1184
- const [showDeleteConfirm, setShowDeleteConfirm] = useState2(false);
1185
- const [showProcessConfirm, setShowProcessConfirm] = useState2(false);
1186
- const [showProgress, setShowProgress] = useState2(false);
1187
- const [progressState, setProgressState] = useState2({
1264
+ const [uploading, setUploading] = useState3(false);
1265
+ const [refreshing, setRefreshing] = useState3(false);
1266
+ const [processing, setProcessing] = useState3(false);
1267
+ const [showDeleteConfirm, setShowDeleteConfirm] = useState3(false);
1268
+ const [showProcessConfirm, setShowProcessConfirm] = useState3(false);
1269
+ const [showProgress, setShowProgress] = useState3(false);
1270
+ const [progressState, setProgressState] = useState3({
1188
1271
  current: 0,
1189
1272
  total: 0,
1190
1273
  percent: 0,
1191
1274
  status: "processing"
1192
1275
  });
1193
- const [processCount, setProcessCount] = useState2(0);
1194
- const [processMode, setProcessMode] = useState2("all");
1195
- const [imagesToProcess, setImagesToProcess] = useState2([]);
1196
- const [alertMessage, setAlertMessage] = useState2(null);
1197
- const [showNewFolderModal, setShowNewFolderModal] = useState2(false);
1198
- const [showRenameFolderModal, setShowRenameFolderModal] = useState2(false);
1199
- const [showMoveModal, setShowMoveModal] = useState2(false);
1200
- const [showR2SetupModal, setShowR2SetupModal] = useState2(false);
1201
- const [syncing, setSyncing] = useState2(false);
1276
+ const [processCount, setProcessCount] = useState3(0);
1277
+ const [processMode, setProcessMode] = useState3("all");
1278
+ const [imagesToProcess, setImagesToProcess] = useState3([]);
1279
+ const [alertMessage, setAlertMessage] = useState3(null);
1280
+ const [showNewFolderModal, setShowNewFolderModal] = useState3(false);
1281
+ const [showRenameFolderModal, setShowRenameFolderModal] = useState3(false);
1282
+ const [showMoveModal, setShowMoveModal] = useState3(false);
1283
+ const [showR2SetupModal, setShowR2SetupModal] = useState3(false);
1284
+ const [syncing, setSyncing] = useState3(false);
1202
1285
  const isInImagesFolder = currentPath === "public/images" || currentPath.startsWith("public/images/");
1203
1286
  const handleUpload = useCallback(() => {
1204
1287
  fileInputRef.current?.click();
@@ -1915,11 +1998,11 @@ function ImageStackIcon() {
1915
1998
  }
1916
1999
 
1917
2000
  // src/components/StudioFileGrid.tsx
1918
- import { useState as useState4 } from "react";
2001
+ import { useState as useState5 } from "react";
1919
2002
  import { css as css5, keyframes as keyframes4 } from "@emotion/react";
1920
2003
 
1921
2004
  // src/hooks/useFileList.ts
1922
- import { useEffect as useEffect2, useState as useState3, useRef as useRef2, useCallback as useCallback2 } from "react";
2005
+ import { useEffect as useEffect2, useState as useState4, useRef as useRef2, useCallback as useCallback2 } from "react";
1923
2006
 
1924
2007
  // src/lib/api.ts
1925
2008
  var StudioApiClient = class {
@@ -2018,8 +2101,8 @@ function useFileList() {
2018
2101
  searchQuery,
2019
2102
  showError
2020
2103
  } = useStudio();
2021
- const [items, setItems] = useState3([]);
2022
- const [loading, setLoading] = useState3(true);
2104
+ const [items, setItems] = useState4([]);
2105
+ const [loading, setLoading] = useState4(true);
2023
2106
  const isInitialLoad = useRef2(true);
2024
2107
  const lastPath = useRef2(currentPath);
2025
2108
  useEffect2(() => {
@@ -2499,7 +2582,7 @@ function StudioFileGrid() {
2499
2582
  ] });
2500
2583
  }
2501
2584
  function GridItem({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
2502
- const [showCopied, setShowCopied] = useState4(false);
2585
+ const [showCopied, setShowCopied] = useState5(false);
2503
2586
  const isFolder = item.type === "folder";
2504
2587
  const isImage = !isFolder && item.thumbnail !== void 0;
2505
2588
  const isImagesFolder = isFolder && (item.name === "images" || item.path.includes("/images/"));
@@ -2616,7 +2699,7 @@ function truncateMiddle(str, maxLength = 24) {
2616
2699
  }
2617
2700
 
2618
2701
  // src/components/StudioFileList.tsx
2619
- import { useState as useState5 } from "react";
2702
+ import { useState as useState6 } from "react";
2620
2703
  import { css as css6, keyframes as keyframes5 } from "@emotion/react";
2621
2704
  import { jsx as jsx6, jsxs as jsxs6 } from "@emotion/react/jsx-runtime";
2622
2705
  var spin3 = keyframes5`
@@ -2993,7 +3076,7 @@ function StudioFileList() {
2993
3076
  ] }) });
2994
3077
  }
2995
3078
  function ListRow({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
2996
- const [showCopied, setShowCopied] = useState5(false);
3079
+ const [showCopied, setShowCopied] = useState6(false);
2997
3080
  const isFolder = item.type === "folder";
2998
3081
  const isImage = !isFolder && item.thumbnail !== void 0;
2999
3082
  const isImagesFolder = isFolder && (item.name === "images" || item.path.includes("/images/"));
@@ -3099,7 +3182,7 @@ function truncateMiddle2(str, maxLength = 32) {
3099
3182
  }
3100
3183
 
3101
3184
  // src/components/StudioDetailView.tsx
3102
- import { useState as useState6 } from "react";
3185
+ import { useState as useState7 } from "react";
3103
3186
  import { css as css7 } from "@emotion/react";
3104
3187
  import { Fragment as Fragment3, jsx as jsx7, jsxs as jsxs7 } from "@emotion/react/jsx-runtime";
3105
3188
  var IMAGE_EXTENSIONS = [".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg", ".ico", ".bmp", ".tiff", ".tif"];
@@ -3360,14 +3443,14 @@ var styles7 = {
3360
3443
  };
3361
3444
  function StudioDetailView() {
3362
3445
  const { focusedItem, setFocusedItem, triggerRefresh, clearSelection } = useStudio();
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);
3446
+ const [showDeleteConfirm, setShowDeleteConfirm] = useState7(false);
3447
+ const [showRenameModal, setShowRenameModal] = useState7(false);
3448
+ const [showProcessConfirm, setShowProcessConfirm] = useState7(false);
3449
+ const [showR2SetupModal, setShowR2SetupModal] = useState7(false);
3450
+ const [processProgress, setProcessProgress] = useState7(null);
3451
+ const [alertMessage, setAlertMessage] = useState7(null);
3452
+ const [showCopied, setShowCopied] = useState7(false);
3453
+ const [syncing, setSyncing] = useState7(false);
3371
3454
  if (!focusedItem) return null;
3372
3455
  const isImage = isImageFile(focusedItem.name);
3373
3456
  const isVideo = isVideoFile(focusedItem.name);
@@ -3668,7 +3751,7 @@ function formatFileSize3(bytes) {
3668
3751
  }
3669
3752
 
3670
3753
  // src/components/StudioSettings.tsx
3671
- import { useState as useState7 } from "react";
3754
+ import { useState as useState8 } from "react";
3672
3755
  import { css as css8 } from "@emotion/react";
3673
3756
  import { Fragment as Fragment4, jsx as jsx8, jsxs as jsxs8 } from "@emotion/react/jsx-runtime";
3674
3757
  var btnHeight2 = "36px";
@@ -3908,7 +3991,7 @@ var styles8 = {
3908
3991
  `
3909
3992
  };
3910
3993
  function StudioSettings() {
3911
- const [isOpen, setIsOpen] = useState7(false);
3994
+ const [isOpen, setIsOpen] = useState8(false);
3912
3995
  return /* @__PURE__ */ jsxs8(Fragment4, { children: [
3913
3996
  /* @__PURE__ */ jsx8("button", { css: styles8.btn, onClick: () => setIsOpen(true), "aria-label": "Settings", children: /* @__PURE__ */ jsxs8(
3914
3997
  "svg",
@@ -3936,7 +4019,7 @@ CLOUDFLARE_R2_SECRET_ACCESS_KEY=your_secret_access_key_here
3936
4019
  CLOUDFLARE_R2_BUCKET_NAME=my-images-bucket
3937
4020
  CLOUDFLARE_R2_PUBLIC_URL=https://cdn.yourdomain.com`;
3938
4021
  function SettingsPanel({ onClose }) {
3939
- const [copied, setCopied] = useState7(false);
4022
+ const [copied, setCopied] = useState8(false);
3940
4023
  const handleCopy = () => {
3941
4024
  navigator.clipboard.writeText(envTemplate);
3942
4025
  setCopied(true);
@@ -4206,17 +4289,17 @@ var styles10 = {
4206
4289
  `
4207
4290
  };
4208
4291
  function StudioUI({ onClose, isVisible = true }) {
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);
4292
+ const [currentPath, setCurrentPathInternal] = useState9("public");
4293
+ const [selectedItems, setSelectedItems] = useState9(/* @__PURE__ */ new Set());
4294
+ const [lastSelectedPath, setLastSelectedPath] = useState9(null);
4295
+ const [viewMode, setViewMode] = useState9("grid");
4296
+ const [focusedItem, setFocusedItem] = useState9(null);
4297
+ const [meta, setMeta] = useState9(null);
4298
+ const [isLoading, setIsLoading] = useState9(false);
4299
+ const [refreshKey, setRefreshKey] = useState9(0);
4300
+ const [searchQuery, setSearchQuery] = useState9("");
4301
+ const [error, setError] = useState9(null);
4302
+ const [isDragging, setIsDragging] = useState9(false);
4220
4303
  const triggerRefresh = useCallback3(() => {
4221
4304
  setRefreshKey((k) => k + 1);
4222
4305
  }, []);
@@ -4442,4 +4525,4 @@ export {
4442
4525
  StudioUI,
4443
4526
  StudioUI_default as default
4444
4527
  };
4445
- //# sourceMappingURL=StudioUI-XV7HCEAF.mjs.map
4528
+ //# sourceMappingURL=StudioUI-PPX6VKNU.mjs.map