@gallop.software/studio 0.1.77 → 0.1.79

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.
@@ -1263,9 +1263,6 @@ function StudioToolbar() {
1263
1263
  }
1264
1264
  }, [setSearchQuery]);
1265
1265
  const hasSelection = selectedItems.size > 0;
1266
- const hasImagesSelected = Array.from(selectedItems).some(
1267
- (path) => path === "public/images" || path.startsWith("public/images/")
1268
- );
1269
1266
  if (focusedItem) {
1270
1267
  return null;
1271
1268
  }
@@ -1383,8 +1380,8 @@ function StudioToolbar() {
1383
1380
  {
1384
1381
  css: styles3.btn,
1385
1382
  onClick: handleProcessImages,
1386
- disabled: processing || isInImagesFolder || hasImagesSelected,
1387
- title: isInImagesFolder || hasImagesSelected ? "Cannot process protected images folder" : void 0,
1383
+ disabled: processing || isInImagesFolder,
1384
+ title: isInImagesFolder ? "Cannot process images folder" : void 0,
1388
1385
  children: [
1389
1386
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ImageStackIcon, {}),
1390
1387
  processing ? "Processing..." : "Process Images"
@@ -1396,8 +1393,7 @@ function StudioToolbar() {
1396
1393
  {
1397
1394
  css: [styles3.btn, styles3.btnDanger],
1398
1395
  onClick: handleDeleteClick,
1399
- disabled: !hasSelection || hasImagesSelected,
1400
- title: hasImagesSelected ? "Cannot delete protected images folder items" : void 0,
1396
+ disabled: !hasSelection,
1401
1397
  children: [
1402
1398
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TrashIcon, {}),
1403
1399
  "Delete"
@@ -1409,8 +1405,7 @@ function StudioToolbar() {
1409
1405
  {
1410
1406
  css: styles3.btn,
1411
1407
  onClick: handleMoveClick,
1412
- disabled: !hasSelection || hasImagesSelected,
1413
- title: hasImagesSelected ? "Cannot move protected images folder items" : void 0,
1408
+ disabled: !hasSelection,
1414
1409
  children: [
1415
1410
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, MoveIcon, {}),
1416
1411
  "Move"
@@ -1724,11 +1719,15 @@ var styles4 = {
1724
1719
  flex: 1;
1725
1720
  min-width: 0;
1726
1721
  `,
1727
- copyBtn: _react3.css`
1722
+ actionBtns: _react3.css`
1728
1723
  position: absolute;
1729
1724
  top: 4px;
1730
1725
  right: 4px;
1731
1726
  z-index: 10;
1727
+ display: flex;
1728
+ gap: 2px;
1729
+ `,
1730
+ copyBtn: _react3.css`
1732
1731
  height: 28px;
1733
1732
  width: 28px;
1734
1733
  color: ${_chunkUFCWGUAGjs.colors.textMuted};
@@ -1741,6 +1740,7 @@ var styles4 = {
1741
1740
  display: flex;
1742
1741
  align-items: center;
1743
1742
  justify-content: center;
1743
+ position: relative;
1744
1744
 
1745
1745
  &:hover {
1746
1746
  color: ${_chunkUFCWGUAGjs.colors.text};
@@ -1846,6 +1846,7 @@ function StudioFileGrid() {
1846
1846
  const { currentPath, setCurrentPath, navigateUp, selectedItems, toggleSelection, selectRange, lastSelectedPath, selectAll, clearSelection, refreshKey, setFocusedItem, triggerRefresh, searchQuery } = useStudio();
1847
1847
  const [items, setItems] = _react.useState.call(void 0, []);
1848
1848
  const [loading, setLoading] = _react.useState.call(void 0, true);
1849
+ const [renameItem, setRenameItem] = _react.useState.call(void 0, null);
1849
1850
  const isInitialLoad = _react.useRef.call(void 0, true);
1850
1851
  const lastPath = _react.useRef.call(void 0, currentPath);
1851
1852
  _react.useEffect.call(void 0, () => {
@@ -1914,6 +1915,22 @@ function StudioFileGrid() {
1914
1915
  console.error("Failed to generate thumbnail:", error);
1915
1916
  }
1916
1917
  };
1918
+ const handleRename = async (newName) => {
1919
+ if (!renameItem) return;
1920
+ setRenameItem(null);
1921
+ try {
1922
+ const response = await fetch("/api/studio/rename", {
1923
+ method: "POST",
1924
+ headers: { "Content-Type": "application/json" },
1925
+ body: JSON.stringify({ oldPath: renameItem.path, newName })
1926
+ });
1927
+ if (response.ok) {
1928
+ triggerRefresh();
1929
+ }
1930
+ } catch (error) {
1931
+ console.error("Failed to rename:", error);
1932
+ }
1933
+ };
1917
1934
  const allItemsSelected = sortedItems.length > 0 && sortedItems.every((item) => selectedItems.has(item.path));
1918
1935
  const someItemsSelected = sortedItems.some((item) => selectedItems.has(item.path));
1919
1936
  const handleSelectAll = () => {
@@ -1924,6 +1941,18 @@ function StudioFileGrid() {
1924
1941
  }
1925
1942
  };
1926
1943
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
1944
+ renameItem && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1945
+ InputModal,
1946
+ {
1947
+ title: renameItem.type === "folder" ? "Rename Folder" : "Rename File",
1948
+ message: "Enter a new name:",
1949
+ placeholder: renameItem.name,
1950
+ defaultValue: renameItem.name,
1951
+ confirmLabel: "Rename",
1952
+ onConfirm: handleRename,
1953
+ onCancel: () => setRenameItem(null)
1954
+ }
1955
+ ),
1927
1956
  sortedItems.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles4.selectAllRow, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "label", { css: styles4.selectAllLabel, children: [
1928
1957
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1929
1958
  "input",
@@ -1963,14 +1992,15 @@ function StudioFileGrid() {
1963
1992
  isSelected: selectedItems.has(item.path),
1964
1993
  onClick: (e) => handleItemClick(item, e),
1965
1994
  onOpen: () => handleOpen(item),
1966
- onGenerateThumbnail: () => handleGenerateThumbnail(item)
1995
+ onGenerateThumbnail: () => handleGenerateThumbnail(item),
1996
+ onRename: () => setRenameItem(item)
1967
1997
  },
1968
1998
  item.path
1969
1999
  ))
1970
2000
  ] })
1971
2001
  ] });
1972
2002
  }
1973
- function GridItem({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
2003
+ function GridItem({ item, isSelected, onClick, onOpen, onGenerateThumbnail, onRename }) {
1974
2004
  const [showCopied, setShowCopied] = _react.useState.call(void 0, false);
1975
2005
  const isFolder = item.type === "folder";
1976
2006
  const isImage = !isFolder && item.thumbnail !== void 0;
@@ -2006,18 +2036,32 @@ function GridItem({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
2006
2036
  ),
2007
2037
  item.cdnSynced && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles4.cdnBadge, children: "CDN" }),
2008
2038
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.content, children: [
2009
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2010
- "button",
2011
- {
2012
- css: styles4.copyBtn,
2013
- onClick: handleCopyPath,
2014
- title: "Copy file path",
2015
- children: [
2016
- showCopied && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles4.tooltip, children: "Copied!" }),
2017
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" }) })
2018
- ]
2019
- }
2020
- ),
2039
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.actionBtns, children: [
2040
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2041
+ "button",
2042
+ {
2043
+ css: styles4.copyBtn,
2044
+ onClick: handleCopyPath,
2045
+ title: "Copy file path",
2046
+ children: [
2047
+ showCopied && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles4.tooltip, children: "Copied!" }),
2048
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" }) })
2049
+ ]
2050
+ }
2051
+ ),
2052
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2053
+ "button",
2054
+ {
2055
+ css: styles4.copyBtn,
2056
+ onClick: (e) => {
2057
+ e.stopPropagation();
2058
+ onRename();
2059
+ },
2060
+ title: "Rename",
2061
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "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" }) })
2062
+ }
2063
+ )
2064
+ ] }),
2021
2065
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2022
2066
  "button",
2023
2067
  {
@@ -2403,6 +2447,7 @@ function StudioFileList() {
2403
2447
  const { currentPath, setCurrentPath, navigateUp, selectedItems, toggleSelection, selectRange, lastSelectedPath, selectAll, clearSelection, refreshKey, setFocusedItem, triggerRefresh, searchQuery } = useStudio();
2404
2448
  const [items, setItems] = _react.useState.call(void 0, []);
2405
2449
  const [loading, setLoading] = _react.useState.call(void 0, true);
2450
+ const [renameItem, setRenameItem] = _react.useState.call(void 0, null);
2406
2451
  const isInitialLoad = _react.useRef.call(void 0, true);
2407
2452
  const lastPath = _react.useRef.call(void 0, currentPath);
2408
2453
  _react.useEffect.call(void 0, () => {
@@ -2467,6 +2512,22 @@ function StudioFileList() {
2467
2512
  console.error("Failed to generate thumbnail:", error);
2468
2513
  }
2469
2514
  };
2515
+ const handleRename = async (newName) => {
2516
+ if (!renameItem) return;
2517
+ setRenameItem(null);
2518
+ try {
2519
+ const response = await fetch("/api/studio/rename", {
2520
+ method: "POST",
2521
+ headers: { "Content-Type": "application/json" },
2522
+ body: JSON.stringify({ oldPath: renameItem.path, newName })
2523
+ });
2524
+ if (response.ok) {
2525
+ triggerRefresh();
2526
+ }
2527
+ } catch (error) {
2528
+ console.error("Failed to rename:", error);
2529
+ }
2530
+ };
2470
2531
  const allItemsSelected = sortedItems.length > 0 && sortedItems.every((item) => selectedItems.has(item.path));
2471
2532
  const someItemsSelected = sortedItems.some((item) => selectedItems.has(item.path));
2472
2533
  const handleSelectAll = () => {
@@ -2476,51 +2537,66 @@ function StudioFileList() {
2476
2537
  selectAll(sortedItems);
2477
2538
  }
2478
2539
  };
2479
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.tableWrapper, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "table", { css: styles5.table, children: [
2480
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "thead", { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tr", { children: [
2481
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles5.th, styles5.thCheckbox], children: sortedItems.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2482
- "input",
2483
- {
2484
- type: "checkbox",
2485
- css: styles5.checkbox,
2486
- checked: allItemsSelected,
2487
- ref: (el) => {
2488
- if (el) el.indeterminate = someItemsSelected && !allItemsSelected;
2540
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.tableWrapper, children: [
2541
+ renameItem && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2542
+ InputModal,
2543
+ {
2544
+ title: renameItem.type === "folder" ? "Rename Folder" : "Rename File",
2545
+ message: "Enter a new name:",
2546
+ placeholder: renameItem.name,
2547
+ defaultValue: renameItem.name,
2548
+ confirmLabel: "Rename",
2549
+ onConfirm: handleRename,
2550
+ onCancel: () => setRenameItem(null)
2551
+ }
2552
+ ),
2553
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "table", { css: styles5.table, children: [
2554
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "thead", { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tr", { children: [
2555
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles5.th, styles5.thCheckbox], children: sortedItems.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2556
+ "input",
2557
+ {
2558
+ type: "checkbox",
2559
+ css: styles5.checkbox,
2560
+ checked: allItemsSelected,
2561
+ ref: (el) => {
2562
+ if (el) el.indeterminate = someItemsSelected && !allItemsSelected;
2563
+ },
2564
+ onChange: handleSelectAll
2565
+ }
2566
+ ) }),
2567
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: styles5.th, children: "Name" }),
2568
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles5.th, styles5.thSize], children: "Size" }),
2569
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles5.th, styles5.thDimensions], children: "Dimensions" }),
2570
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles5.th, styles5.thCdn], children: "CDN" })
2571
+ ] }) }),
2572
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tbody", { css: styles5.tbody, children: [
2573
+ !isAtRoot && !isSearching && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tr", { css: styles5.parentRow, onClick: navigateUp, children: [
2574
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles5.td }),
2575
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles5.td, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.nameCell, children: [
2576
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.parentIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M3 10h10a8 8 0 018 8v2M3 10l6 6m-6-6l6-6" }) }),
2577
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles5.name, children: ".." })
2578
+ ] }) }),
2579
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles5.td, styles5.meta], children: "--" }),
2580
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles5.td, styles5.meta], children: "Parent folder" }),
2581
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles5.td, children: "--" })
2582
+ ] }),
2583
+ sortedItems.map((item) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2584
+ ListRow,
2585
+ {
2586
+ item,
2587
+ isSelected: selectedItems.has(item.path),
2588
+ onClick: (e) => handleItemClick(item, e),
2589
+ onOpen: () => handleOpen(item),
2590
+ onGenerateThumbnail: () => handleGenerateThumbnail(item),
2591
+ onRename: () => setRenameItem(item)
2489
2592
  },
2490
- onChange: handleSelectAll
2491
- }
2492
- ) }),
2493
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: styles5.th, children: "Name" }),
2494
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles5.th, styles5.thSize], children: "Size" }),
2495
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles5.th, styles5.thDimensions], children: "Dimensions" }),
2496
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles5.th, styles5.thCdn], children: "CDN" })
2497
- ] }) }),
2498
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tbody", { css: styles5.tbody, children: [
2499
- !isAtRoot && !isSearching && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tr", { css: styles5.parentRow, onClick: navigateUp, children: [
2500
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles5.td }),
2501
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles5.td, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.nameCell, children: [
2502
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.parentIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M3 10h10a8 8 0 018 8v2M3 10l6 6m-6-6l6-6" }) }),
2503
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles5.name, children: ".." })
2504
- ] }) }),
2505
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles5.td, styles5.meta], children: "--" }),
2506
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles5.td, styles5.meta], children: "Parent folder" }),
2507
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles5.td, children: "--" })
2508
- ] }),
2509
- sortedItems.map((item) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2510
- ListRow,
2511
- {
2512
- item,
2513
- isSelected: selectedItems.has(item.path),
2514
- onClick: (e) => handleItemClick(item, e),
2515
- onOpen: () => handleOpen(item),
2516
- onGenerateThumbnail: () => handleGenerateThumbnail(item)
2517
- },
2518
- item.path
2519
- ))
2593
+ item.path
2594
+ ))
2595
+ ] })
2520
2596
  ] })
2521
- ] }) });
2597
+ ] });
2522
2598
  }
2523
- function ListRow({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
2599
+ function ListRow({ item, isSelected, onClick, onOpen, onGenerateThumbnail, onRename }) {
2524
2600
  const [showCopied, setShowCopied] = _react.useState.call(void 0, false);
2525
2601
  const isFolder = item.type === "folder";
2526
2602
  const isImage = !isFolder && item.thumbnail !== void 0;
@@ -2584,6 +2660,18 @@ function ListRow({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
2584
2660
  ]
2585
2661
  }
2586
2662
  ),
2663
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2664
+ "button",
2665
+ {
2666
+ css: styles5.copyBtn,
2667
+ onClick: (e) => {
2668
+ e.stopPropagation();
2669
+ onRename();
2670
+ },
2671
+ title: "Rename",
2672
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "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" }) })
2673
+ }
2674
+ ),
2587
2675
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2588
2676
  "button",
2589
2677
  {
@@ -3842,4 +3930,4 @@ var StudioUI_default = StudioUI;
3842
3930
 
3843
3931
 
3844
3932
  exports.StudioUI = StudioUI; exports.default = StudioUI_default;
3845
- //# sourceMappingURL=StudioUI-3BYIEK6S.js.map
3933
+ //# sourceMappingURL=StudioUI-JGKWCQSR.js.map