@gallop.software/studio 0.1.78 → 0.1.80

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.
@@ -1582,6 +1582,10 @@ var styles4 = {
1582
1582
  &:hover {
1583
1583
  border-color: #d0d5dd;
1584
1584
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.06);
1585
+
1586
+ button[title="Rename"] {
1587
+ opacity: 1;
1588
+ }
1585
1589
  }
1586
1590
  `,
1587
1591
  itemSelected: css4`
@@ -1741,6 +1745,35 @@ var styles4 = {
1741
1745
  color: ${colors.text};
1742
1746
  }
1743
1747
  `,
1748
+ nameRow: css4`
1749
+ display: flex;
1750
+ align-items: center;
1751
+ gap: 4px;
1752
+ `,
1753
+ renameBtn: css4`
1754
+ flex-shrink: 0;
1755
+ height: 20px;
1756
+ width: 20px;
1757
+ color: ${colors.textMuted};
1758
+ background: transparent;
1759
+ border: none;
1760
+ padding: 0;
1761
+ cursor: pointer;
1762
+ border-radius: 4px;
1763
+ transition: all 0.15s ease;
1764
+ display: flex;
1765
+ align-items: center;
1766
+ justify-content: center;
1767
+ opacity: 0;
1768
+
1769
+ &:hover {
1770
+ color: ${colors.text};
1771
+ }
1772
+ `,
1773
+ renameIcon: css4`
1774
+ width: 14px;
1775
+ height: 14px;
1776
+ `,
1744
1777
  copyIcon: css4`
1745
1778
  width: 18px;
1746
1779
  height: 18px;
@@ -1841,6 +1874,7 @@ function StudioFileGrid() {
1841
1874
  const { currentPath, setCurrentPath, navigateUp, selectedItems, toggleSelection, selectRange, lastSelectedPath, selectAll, clearSelection, refreshKey, setFocusedItem, triggerRefresh, searchQuery } = useStudio();
1842
1875
  const [items, setItems] = useState3([]);
1843
1876
  const [loading, setLoading] = useState3(true);
1877
+ const [renameItem, setRenameItem] = useState3(null);
1844
1878
  const isInitialLoad = useRef2(true);
1845
1879
  const lastPath = useRef2(currentPath);
1846
1880
  useEffect2(() => {
@@ -1909,6 +1943,22 @@ function StudioFileGrid() {
1909
1943
  console.error("Failed to generate thumbnail:", error);
1910
1944
  }
1911
1945
  };
1946
+ const handleRename = async (newName) => {
1947
+ if (!renameItem) return;
1948
+ setRenameItem(null);
1949
+ try {
1950
+ const response = await fetch("/api/studio/rename", {
1951
+ method: "POST",
1952
+ headers: { "Content-Type": "application/json" },
1953
+ body: JSON.stringify({ oldPath: renameItem.path, newName })
1954
+ });
1955
+ if (response.ok) {
1956
+ triggerRefresh();
1957
+ }
1958
+ } catch (error) {
1959
+ console.error("Failed to rename:", error);
1960
+ }
1961
+ };
1912
1962
  const allItemsSelected = sortedItems.length > 0 && sortedItems.every((item) => selectedItems.has(item.path));
1913
1963
  const someItemsSelected = sortedItems.some((item) => selectedItems.has(item.path));
1914
1964
  const handleSelectAll = () => {
@@ -1919,6 +1969,18 @@ function StudioFileGrid() {
1919
1969
  }
1920
1970
  };
1921
1971
  return /* @__PURE__ */ jsxs4("div", { children: [
1972
+ renameItem && /* @__PURE__ */ jsx4(
1973
+ InputModal,
1974
+ {
1975
+ title: renameItem.type === "folder" ? "Rename Folder" : "Rename File",
1976
+ message: "Enter a new name:",
1977
+ placeholder: renameItem.name,
1978
+ defaultValue: renameItem.name,
1979
+ confirmLabel: "Rename",
1980
+ onConfirm: handleRename,
1981
+ onCancel: () => setRenameItem(null)
1982
+ }
1983
+ ),
1922
1984
  sortedItems.length > 0 && /* @__PURE__ */ jsx4("div", { css: styles4.selectAllRow, children: /* @__PURE__ */ jsxs4("label", { css: styles4.selectAllLabel, children: [
1923
1985
  /* @__PURE__ */ jsx4(
1924
1986
  "input",
@@ -1958,14 +2020,15 @@ function StudioFileGrid() {
1958
2020
  isSelected: selectedItems.has(item.path),
1959
2021
  onClick: (e) => handleItemClick(item, e),
1960
2022
  onOpen: () => handleOpen(item),
1961
- onGenerateThumbnail: () => handleGenerateThumbnail(item)
2023
+ onGenerateThumbnail: () => handleGenerateThumbnail(item),
2024
+ onRename: () => setRenameItem(item)
1962
2025
  },
1963
2026
  item.path
1964
2027
  ))
1965
2028
  ] })
1966
2029
  ] });
1967
2030
  }
1968
- function GridItem({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
2031
+ function GridItem({ item, isSelected, onClick, onOpen, onGenerateThumbnail, onRename }) {
1969
2032
  const [showCopied, setShowCopied] = useState3(false);
1970
2033
  const isFolder = item.type === "folder";
1971
2034
  const isImage = !isFolder && item.thumbnail !== void 0;
@@ -2052,7 +2115,21 @@ function GridItem({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
2052
2115
  ) : /* @__PURE__ */ jsx4("svg", { css: styles4.fileIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4("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" }) })
2053
2116
  ] }),
2054
2117
  /* @__PURE__ */ jsx4("div", { css: styles4.label, children: /* @__PURE__ */ jsx4("div", { css: styles4.labelRow, children: /* @__PURE__ */ jsxs4("div", { css: styles4.labelText, children: [
2055
- /* @__PURE__ */ jsx4("p", { css: styles4.name, title: item.name, children: truncateMiddle(item.name) }),
2118
+ /* @__PURE__ */ jsxs4("div", { css: styles4.nameRow, children: [
2119
+ /* @__PURE__ */ jsx4("p", { css: styles4.name, title: item.name, children: truncateMiddle(item.name) }),
2120
+ /* @__PURE__ */ jsx4(
2121
+ "button",
2122
+ {
2123
+ css: styles4.renameBtn,
2124
+ onClick: (e) => {
2125
+ e.stopPropagation();
2126
+ onRename();
2127
+ },
2128
+ title: "Rename",
2129
+ children: /* @__PURE__ */ jsx4("svg", { css: styles4.renameIcon, 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" }) })
2130
+ }
2131
+ )
2132
+ ] }),
2056
2133
  isFolder ? /* @__PURE__ */ jsxs4("p", { css: styles4.size, children: [
2057
2134
  item.fileCount !== void 0 ? `${item.fileCount} files` : "",
2058
2135
  item.fileCount !== void 0 && item.totalSize !== void 0 ? " \xB7 " : "",
@@ -2398,6 +2475,7 @@ function StudioFileList() {
2398
2475
  const { currentPath, setCurrentPath, navigateUp, selectedItems, toggleSelection, selectRange, lastSelectedPath, selectAll, clearSelection, refreshKey, setFocusedItem, triggerRefresh, searchQuery } = useStudio();
2399
2476
  const [items, setItems] = useState4([]);
2400
2477
  const [loading, setLoading] = useState4(true);
2478
+ const [renameItem, setRenameItem] = useState4(null);
2401
2479
  const isInitialLoad = useRef3(true);
2402
2480
  const lastPath = useRef3(currentPath);
2403
2481
  useEffect3(() => {
@@ -2462,6 +2540,22 @@ function StudioFileList() {
2462
2540
  console.error("Failed to generate thumbnail:", error);
2463
2541
  }
2464
2542
  };
2543
+ const handleRename = async (newName) => {
2544
+ if (!renameItem) return;
2545
+ setRenameItem(null);
2546
+ try {
2547
+ const response = await fetch("/api/studio/rename", {
2548
+ method: "POST",
2549
+ headers: { "Content-Type": "application/json" },
2550
+ body: JSON.stringify({ oldPath: renameItem.path, newName })
2551
+ });
2552
+ if (response.ok) {
2553
+ triggerRefresh();
2554
+ }
2555
+ } catch (error) {
2556
+ console.error("Failed to rename:", error);
2557
+ }
2558
+ };
2465
2559
  const allItemsSelected = sortedItems.length > 0 && sortedItems.every((item) => selectedItems.has(item.path));
2466
2560
  const someItemsSelected = sortedItems.some((item) => selectedItems.has(item.path));
2467
2561
  const handleSelectAll = () => {
@@ -2471,51 +2565,66 @@ function StudioFileList() {
2471
2565
  selectAll(sortedItems);
2472
2566
  }
2473
2567
  };
2474
- return /* @__PURE__ */ jsx5("div", { css: styles5.tableWrapper, children: /* @__PURE__ */ jsxs5("table", { css: styles5.table, children: [
2475
- /* @__PURE__ */ jsx5("thead", { children: /* @__PURE__ */ jsxs5("tr", { children: [
2476
- /* @__PURE__ */ jsx5("th", { css: [styles5.th, styles5.thCheckbox], children: sortedItems.length > 0 && /* @__PURE__ */ jsx5(
2477
- "input",
2478
- {
2479
- type: "checkbox",
2480
- css: styles5.checkbox,
2481
- checked: allItemsSelected,
2482
- ref: (el) => {
2483
- if (el) el.indeterminate = someItemsSelected && !allItemsSelected;
2568
+ return /* @__PURE__ */ jsxs5("div", { css: styles5.tableWrapper, children: [
2569
+ renameItem && /* @__PURE__ */ jsx5(
2570
+ InputModal,
2571
+ {
2572
+ title: renameItem.type === "folder" ? "Rename Folder" : "Rename File",
2573
+ message: "Enter a new name:",
2574
+ placeholder: renameItem.name,
2575
+ defaultValue: renameItem.name,
2576
+ confirmLabel: "Rename",
2577
+ onConfirm: handleRename,
2578
+ onCancel: () => setRenameItem(null)
2579
+ }
2580
+ ),
2581
+ /* @__PURE__ */ jsxs5("table", { css: styles5.table, children: [
2582
+ /* @__PURE__ */ jsx5("thead", { children: /* @__PURE__ */ jsxs5("tr", { children: [
2583
+ /* @__PURE__ */ jsx5("th", { css: [styles5.th, styles5.thCheckbox], children: sortedItems.length > 0 && /* @__PURE__ */ jsx5(
2584
+ "input",
2585
+ {
2586
+ type: "checkbox",
2587
+ css: styles5.checkbox,
2588
+ checked: allItemsSelected,
2589
+ ref: (el) => {
2590
+ if (el) el.indeterminate = someItemsSelected && !allItemsSelected;
2591
+ },
2592
+ onChange: handleSelectAll
2593
+ }
2594
+ ) }),
2595
+ /* @__PURE__ */ jsx5("th", { css: styles5.th, children: "Name" }),
2596
+ /* @__PURE__ */ jsx5("th", { css: [styles5.th, styles5.thSize], children: "Size" }),
2597
+ /* @__PURE__ */ jsx5("th", { css: [styles5.th, styles5.thDimensions], children: "Dimensions" }),
2598
+ /* @__PURE__ */ jsx5("th", { css: [styles5.th, styles5.thCdn], children: "CDN" })
2599
+ ] }) }),
2600
+ /* @__PURE__ */ jsxs5("tbody", { css: styles5.tbody, children: [
2601
+ !isAtRoot && !isSearching && /* @__PURE__ */ jsxs5("tr", { css: styles5.parentRow, onClick: navigateUp, children: [
2602
+ /* @__PURE__ */ jsx5("td", { css: styles5.td }),
2603
+ /* @__PURE__ */ jsx5("td", { css: styles5.td, children: /* @__PURE__ */ jsxs5("div", { css: styles5.nameCell, children: [
2604
+ /* @__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" }) }),
2605
+ /* @__PURE__ */ jsx5("span", { css: styles5.name, children: ".." })
2606
+ ] }) }),
2607
+ /* @__PURE__ */ jsx5("td", { css: [styles5.td, styles5.meta], children: "--" }),
2608
+ /* @__PURE__ */ jsx5("td", { css: [styles5.td, styles5.meta], children: "Parent folder" }),
2609
+ /* @__PURE__ */ jsx5("td", { css: styles5.td, children: "--" })
2610
+ ] }),
2611
+ sortedItems.map((item) => /* @__PURE__ */ jsx5(
2612
+ ListRow,
2613
+ {
2614
+ item,
2615
+ isSelected: selectedItems.has(item.path),
2616
+ onClick: (e) => handleItemClick(item, e),
2617
+ onOpen: () => handleOpen(item),
2618
+ onGenerateThumbnail: () => handleGenerateThumbnail(item),
2619
+ onRename: () => setRenameItem(item)
2484
2620
  },
2485
- onChange: handleSelectAll
2486
- }
2487
- ) }),
2488
- /* @__PURE__ */ jsx5("th", { css: styles5.th, children: "Name" }),
2489
- /* @__PURE__ */ jsx5("th", { css: [styles5.th, styles5.thSize], children: "Size" }),
2490
- /* @__PURE__ */ jsx5("th", { css: [styles5.th, styles5.thDimensions], children: "Dimensions" }),
2491
- /* @__PURE__ */ jsx5("th", { css: [styles5.th, styles5.thCdn], children: "CDN" })
2492
- ] }) }),
2493
- /* @__PURE__ */ jsxs5("tbody", { css: styles5.tbody, children: [
2494
- !isAtRoot && !isSearching && /* @__PURE__ */ jsxs5("tr", { css: styles5.parentRow, onClick: navigateUp, children: [
2495
- /* @__PURE__ */ jsx5("td", { css: styles5.td }),
2496
- /* @__PURE__ */ jsx5("td", { css: styles5.td, children: /* @__PURE__ */ jsxs5("div", { css: styles5.nameCell, children: [
2497
- /* @__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" }) }),
2498
- /* @__PURE__ */ jsx5("span", { css: styles5.name, children: ".." })
2499
- ] }) }),
2500
- /* @__PURE__ */ jsx5("td", { css: [styles5.td, styles5.meta], children: "--" }),
2501
- /* @__PURE__ */ jsx5("td", { css: [styles5.td, styles5.meta], children: "Parent folder" }),
2502
- /* @__PURE__ */ jsx5("td", { css: styles5.td, children: "--" })
2503
- ] }),
2504
- sortedItems.map((item) => /* @__PURE__ */ jsx5(
2505
- ListRow,
2506
- {
2507
- item,
2508
- isSelected: selectedItems.has(item.path),
2509
- onClick: (e) => handleItemClick(item, e),
2510
- onOpen: () => handleOpen(item),
2511
- onGenerateThumbnail: () => handleGenerateThumbnail(item)
2512
- },
2513
- item.path
2514
- ))
2621
+ item.path
2622
+ ))
2623
+ ] })
2515
2624
  ] })
2516
- ] }) });
2625
+ ] });
2517
2626
  }
2518
- function ListRow({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
2627
+ function ListRow({ item, isSelected, onClick, onOpen, onGenerateThumbnail, onRename }) {
2519
2628
  const [showCopied, setShowCopied] = useState4(false);
2520
2629
  const isFolder = item.type === "folder";
2521
2630
  const isImage = !isFolder && item.thumbnail !== void 0;
@@ -2579,6 +2688,18 @@ function ListRow({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
2579
2688
  ]
2580
2689
  }
2581
2690
  ),
2691
+ /* @__PURE__ */ jsx5(
2692
+ "button",
2693
+ {
2694
+ css: styles5.copyBtn,
2695
+ onClick: (e) => {
2696
+ e.stopPropagation();
2697
+ onRename();
2698
+ },
2699
+ title: "Rename",
2700
+ children: /* @__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: "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" }) })
2701
+ }
2702
+ ),
2582
2703
  /* @__PURE__ */ jsx5(
2583
2704
  "button",
2584
2705
  {
@@ -3837,4 +3958,4 @@ export {
3837
3958
  StudioUI,
3838
3959
  StudioUI_default as default
3839
3960
  };
3840
- //# sourceMappingURL=StudioUI-PMJDMXUP.mjs.map
3961
+ //# sourceMappingURL=StudioUI-VPNL5NMI.mjs.map