@gallop.software/studio 0.1.81 → 0.1.82
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-SS3YMS53.mjs → StudioUI-VJVOSOPD.mjs} +395 -228
- package/dist/StudioUI-VJVOSOPD.mjs.map +1 -0
- package/dist/{StudioUI-RH4ZXWKP.js → StudioUI-YFDO5MGG.js} +330 -163
- package/dist/StudioUI-YFDO5MGG.js.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 css9 } 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);
|
|
@@ -1551,8 +1556,196 @@ function ImageStackIcon() {
|
|
|
1551
1556
|
}
|
|
1552
1557
|
|
|
1553
1558
|
// src/components/StudioFileGrid.tsx
|
|
1554
|
-
import {
|
|
1559
|
+
import { useState as useState4 } from "react";
|
|
1555
1560
|
import { css as css4, keyframes as keyframes4 } from "@emotion/react";
|
|
1561
|
+
|
|
1562
|
+
// src/hooks/useFileList.ts
|
|
1563
|
+
import { useEffect as useEffect2, useState as useState3, useRef as useRef2, useCallback as useCallback2 } from "react";
|
|
1564
|
+
|
|
1565
|
+
// src/lib/api.ts
|
|
1566
|
+
var StudioApiClient = class {
|
|
1567
|
+
async get(url) {
|
|
1568
|
+
const response = await fetch(url);
|
|
1569
|
+
if (!response.ok) {
|
|
1570
|
+
const data = await response.json().catch(() => ({}));
|
|
1571
|
+
throw new Error(data.error || `Request failed: ${response.status}`);
|
|
1572
|
+
}
|
|
1573
|
+
return response.json();
|
|
1574
|
+
}
|
|
1575
|
+
async post(url, body) {
|
|
1576
|
+
const response = await fetch(url, {
|
|
1577
|
+
method: "POST",
|
|
1578
|
+
headers: body ? { "Content-Type": "application/json" } : void 0,
|
|
1579
|
+
body: body ? JSON.stringify(body) : void 0
|
|
1580
|
+
});
|
|
1581
|
+
if (!response.ok) {
|
|
1582
|
+
const data = await response.json().catch(() => ({}));
|
|
1583
|
+
throw new Error(data.error || `Request failed: ${response.status}`);
|
|
1584
|
+
}
|
|
1585
|
+
return response.json();
|
|
1586
|
+
}
|
|
1587
|
+
// List handlers
|
|
1588
|
+
async list(path = "public") {
|
|
1589
|
+
return this.get(`/api/studio/list?path=${encodeURIComponent(path)}`);
|
|
1590
|
+
}
|
|
1591
|
+
async search(query) {
|
|
1592
|
+
return this.get(`/api/studio/search?q=${encodeURIComponent(query)}`);
|
|
1593
|
+
}
|
|
1594
|
+
async listFolders() {
|
|
1595
|
+
return this.get("/api/studio/list-folders");
|
|
1596
|
+
}
|
|
1597
|
+
async countImages() {
|
|
1598
|
+
return this.get("/api/studio/count-images");
|
|
1599
|
+
}
|
|
1600
|
+
async folderImages(folders) {
|
|
1601
|
+
return this.get(`/api/studio/folder-images?folders=${encodeURIComponent(folders.join(","))}`);
|
|
1602
|
+
}
|
|
1603
|
+
// File handlers
|
|
1604
|
+
async upload(file, targetPath = "public") {
|
|
1605
|
+
const formData = new FormData();
|
|
1606
|
+
formData.append("file", file);
|
|
1607
|
+
formData.append("path", targetPath);
|
|
1608
|
+
const response = await fetch("/api/studio/upload", {
|
|
1609
|
+
method: "POST",
|
|
1610
|
+
body: formData
|
|
1611
|
+
});
|
|
1612
|
+
if (!response.ok) {
|
|
1613
|
+
const data = await response.json().catch(() => ({}));
|
|
1614
|
+
throw new Error(data.error || `Upload failed: ${response.status}`);
|
|
1615
|
+
}
|
|
1616
|
+
return response.json();
|
|
1617
|
+
}
|
|
1618
|
+
async delete(paths) {
|
|
1619
|
+
return this.post("/api/studio/delete", { paths });
|
|
1620
|
+
}
|
|
1621
|
+
async createFolder(parentPath, name) {
|
|
1622
|
+
return this.post("/api/studio/create-folder", { parentPath, name });
|
|
1623
|
+
}
|
|
1624
|
+
async rename(oldPath, newName) {
|
|
1625
|
+
return this.post("/api/studio/rename", { oldPath, newName });
|
|
1626
|
+
}
|
|
1627
|
+
async move(paths, destination) {
|
|
1628
|
+
return this.post("/api/studio/move", { paths, destination });
|
|
1629
|
+
}
|
|
1630
|
+
// Image handlers
|
|
1631
|
+
async sync(imageKeys) {
|
|
1632
|
+
return this.post("/api/studio/sync", { imageKeys });
|
|
1633
|
+
}
|
|
1634
|
+
async reprocess(imageKeys) {
|
|
1635
|
+
return this.post("/api/studio/reprocess", { imageKeys });
|
|
1636
|
+
}
|
|
1637
|
+
// Process all returns a stream, handle separately
|
|
1638
|
+
processAllStream() {
|
|
1639
|
+
return new EventSource("/api/studio/process-all");
|
|
1640
|
+
}
|
|
1641
|
+
};
|
|
1642
|
+
var studioApi = new StudioApiClient();
|
|
1643
|
+
|
|
1644
|
+
// src/hooks/useFileList.ts
|
|
1645
|
+
function useFileList() {
|
|
1646
|
+
const {
|
|
1647
|
+
currentPath,
|
|
1648
|
+
setCurrentPath,
|
|
1649
|
+
navigateUp,
|
|
1650
|
+
selectedItems,
|
|
1651
|
+
toggleSelection,
|
|
1652
|
+
selectRange,
|
|
1653
|
+
lastSelectedPath,
|
|
1654
|
+
selectAll,
|
|
1655
|
+
clearSelection,
|
|
1656
|
+
refreshKey,
|
|
1657
|
+
setFocusedItem,
|
|
1658
|
+
triggerRefresh,
|
|
1659
|
+
searchQuery,
|
|
1660
|
+
showError
|
|
1661
|
+
} = useStudio();
|
|
1662
|
+
const [items, setItems] = useState3([]);
|
|
1663
|
+
const [loading, setLoading] = useState3(true);
|
|
1664
|
+
const isInitialLoad = useRef2(true);
|
|
1665
|
+
const lastPath = useRef2(currentPath);
|
|
1666
|
+
useEffect2(() => {
|
|
1667
|
+
async function loadItems() {
|
|
1668
|
+
const isPathChange = lastPath.current !== currentPath;
|
|
1669
|
+
if (isInitialLoad.current || isPathChange) {
|
|
1670
|
+
setLoading(true);
|
|
1671
|
+
}
|
|
1672
|
+
lastPath.current = currentPath;
|
|
1673
|
+
try {
|
|
1674
|
+
const data = searchQuery && searchQuery.length >= 2 ? await studioApi.search(searchQuery) : await studioApi.list(currentPath);
|
|
1675
|
+
setItems(data.items || []);
|
|
1676
|
+
} catch (error) {
|
|
1677
|
+
const message = error instanceof Error ? error.message : "Failed to load items";
|
|
1678
|
+
showError("Load Error", message);
|
|
1679
|
+
setItems([]);
|
|
1680
|
+
}
|
|
1681
|
+
setLoading(false);
|
|
1682
|
+
isInitialLoad.current = false;
|
|
1683
|
+
}
|
|
1684
|
+
loadItems();
|
|
1685
|
+
}, [currentPath, refreshKey, searchQuery, showError]);
|
|
1686
|
+
const isAtRoot = currentPath === "public";
|
|
1687
|
+
const isSearching = searchQuery && searchQuery.length >= 2;
|
|
1688
|
+
const sortedItems = [...items].sort((a, b) => {
|
|
1689
|
+
if (a.type === "folder" && b.type !== "folder") return -1;
|
|
1690
|
+
if (a.type !== "folder" && b.type === "folder") return 1;
|
|
1691
|
+
return a.name.localeCompare(b.name);
|
|
1692
|
+
});
|
|
1693
|
+
const allItemsSelected = sortedItems.length > 0 && sortedItems.every((item) => selectedItems.has(item.path));
|
|
1694
|
+
const someItemsSelected = sortedItems.some((item) => selectedItems.has(item.path));
|
|
1695
|
+
const handleItemClick = useCallback2((item, e) => {
|
|
1696
|
+
if (e.shiftKey && lastSelectedPath) {
|
|
1697
|
+
selectRange(lastSelectedPath, item.path, sortedItems);
|
|
1698
|
+
} else {
|
|
1699
|
+
toggleSelection(item.path);
|
|
1700
|
+
}
|
|
1701
|
+
}, [lastSelectedPath, selectRange, sortedItems, toggleSelection]);
|
|
1702
|
+
const handleOpen = useCallback2((item) => {
|
|
1703
|
+
if (item.type === "folder") {
|
|
1704
|
+
setCurrentPath(item.path);
|
|
1705
|
+
} else {
|
|
1706
|
+
setFocusedItem(item);
|
|
1707
|
+
}
|
|
1708
|
+
}, [setCurrentPath, setFocusedItem]);
|
|
1709
|
+
const handleGenerateThumbnail = useCallback2(async (item) => {
|
|
1710
|
+
try {
|
|
1711
|
+
const imageKey = "/" + item.path.replace(/^public\//, "");
|
|
1712
|
+
await studioApi.reprocess([imageKey]);
|
|
1713
|
+
triggerRefresh();
|
|
1714
|
+
} catch (error) {
|
|
1715
|
+
const message = error instanceof Error ? error.message : "Failed to generate thumbnail";
|
|
1716
|
+
showError("Processing Error", message);
|
|
1717
|
+
}
|
|
1718
|
+
}, [triggerRefresh, showError]);
|
|
1719
|
+
const handleSelectAll = useCallback2(() => {
|
|
1720
|
+
if (allItemsSelected) {
|
|
1721
|
+
clearSelection();
|
|
1722
|
+
} else {
|
|
1723
|
+
selectAll(sortedItems);
|
|
1724
|
+
}
|
|
1725
|
+
}, [allItemsSelected, clearSelection, selectAll, sortedItems]);
|
|
1726
|
+
return {
|
|
1727
|
+
// State
|
|
1728
|
+
items,
|
|
1729
|
+
loading,
|
|
1730
|
+
sortedItems,
|
|
1731
|
+
// Computed
|
|
1732
|
+
isAtRoot,
|
|
1733
|
+
isSearching,
|
|
1734
|
+
allItemsSelected,
|
|
1735
|
+
someItemsSelected,
|
|
1736
|
+
// Context values
|
|
1737
|
+
currentPath,
|
|
1738
|
+
selectedItems,
|
|
1739
|
+
navigateUp,
|
|
1740
|
+
// Handlers
|
|
1741
|
+
handleItemClick,
|
|
1742
|
+
handleOpen,
|
|
1743
|
+
handleGenerateThumbnail,
|
|
1744
|
+
handleSelectAll
|
|
1745
|
+
};
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
// src/components/StudioFileGrid.tsx
|
|
1556
1749
|
import { jsx as jsx4, jsxs as jsxs4 } from "@emotion/react/jsx-runtime";
|
|
1557
1750
|
var spin2 = keyframes4`
|
|
1558
1751
|
to { transform: rotate(360deg); }
|
|
@@ -1875,86 +2068,30 @@ var styles4 = {
|
|
|
1875
2068
|
`
|
|
1876
2069
|
};
|
|
1877
2070
|
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]);
|
|
2071
|
+
const {
|
|
2072
|
+
loading,
|
|
2073
|
+
sortedItems,
|
|
2074
|
+
isAtRoot,
|
|
2075
|
+
isSearching,
|
|
2076
|
+
allItemsSelected,
|
|
2077
|
+
someItemsSelected,
|
|
2078
|
+
selectedItems,
|
|
2079
|
+
navigateUp,
|
|
2080
|
+
handleItemClick,
|
|
2081
|
+
handleOpen,
|
|
2082
|
+
handleGenerateThumbnail,
|
|
2083
|
+
handleSelectAll
|
|
2084
|
+
} = useFileList();
|
|
1905
2085
|
if (loading) {
|
|
1906
2086
|
return /* @__PURE__ */ jsx4("div", { css: styles4.loading, children: /* @__PURE__ */ jsx4("div", { css: styles4.spinner }) });
|
|
1907
2087
|
}
|
|
1908
|
-
|
|
1909
|
-
if (items.length === 0 && isAtRoot) {
|
|
2088
|
+
if (sortedItems.length === 0 && isAtRoot) {
|
|
1910
2089
|
return /* @__PURE__ */ jsxs4("div", { css: styles4.empty, children: [
|
|
1911
2090
|
/* @__PURE__ */ jsx4("svg", { css: styles4.emptyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4("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" }) }),
|
|
1912
2091
|
/* @__PURE__ */ jsx4("p", { css: styles4.emptyText, children: "No files in this folder" }),
|
|
1913
2092
|
/* @__PURE__ */ jsx4("p", { css: styles4.emptyText, children: "Upload images to get started" })
|
|
1914
2093
|
] });
|
|
1915
2094
|
}
|
|
1916
|
-
const isSearching = searchQuery && searchQuery.length >= 2;
|
|
1917
|
-
const sortedItems = [...items].sort((a, b) => {
|
|
1918
|
-
if (a.type === "folder" && b.type !== "folder") return -1;
|
|
1919
|
-
if (a.type !== "folder" && b.type === "folder") return 1;
|
|
1920
|
-
return a.name.localeCompare(b.name);
|
|
1921
|
-
});
|
|
1922
|
-
const handleItemClick = (item, e) => {
|
|
1923
|
-
if (e.shiftKey && lastSelectedPath) {
|
|
1924
|
-
selectRange(lastSelectedPath, item.path, sortedItems);
|
|
1925
|
-
} else {
|
|
1926
|
-
toggleSelection(item.path);
|
|
1927
|
-
}
|
|
1928
|
-
};
|
|
1929
|
-
const handleOpen = (item) => {
|
|
1930
|
-
if (item.type === "folder") {
|
|
1931
|
-
setCurrentPath(item.path);
|
|
1932
|
-
} else {
|
|
1933
|
-
setFocusedItem(item);
|
|
1934
|
-
}
|
|
1935
|
-
};
|
|
1936
|
-
const handleGenerateThumbnail = async (item) => {
|
|
1937
|
-
try {
|
|
1938
|
-
const imageKey = item.path.replace(/^public\//, "");
|
|
1939
|
-
await fetch("/api/studio/reprocess", {
|
|
1940
|
-
method: "POST",
|
|
1941
|
-
headers: { "Content-Type": "application/json" },
|
|
1942
|
-
body: JSON.stringify({ imageKeys: [imageKey] })
|
|
1943
|
-
});
|
|
1944
|
-
triggerRefresh();
|
|
1945
|
-
} catch (error) {
|
|
1946
|
-
console.error("Failed to generate thumbnail:", error);
|
|
1947
|
-
}
|
|
1948
|
-
};
|
|
1949
|
-
const allItemsSelected = sortedItems.length > 0 && sortedItems.every((item) => selectedItems.has(item.path));
|
|
1950
|
-
const someItemsSelected = sortedItems.some((item) => selectedItems.has(item.path));
|
|
1951
|
-
const handleSelectAll = () => {
|
|
1952
|
-
if (allItemsSelected) {
|
|
1953
|
-
clearSelection();
|
|
1954
|
-
} else {
|
|
1955
|
-
selectAll(sortedItems);
|
|
1956
|
-
}
|
|
1957
|
-
};
|
|
1958
2095
|
return /* @__PURE__ */ jsxs4("div", { children: [
|
|
1959
2096
|
sortedItems.length > 0 && /* @__PURE__ */ jsx4("div", { css: styles4.selectAllRow, children: /* @__PURE__ */ jsxs4("label", { css: styles4.selectAllLabel, children: [
|
|
1960
2097
|
/* @__PURE__ */ jsx4(
|
|
@@ -2003,7 +2140,7 @@ function StudioFileGrid() {
|
|
|
2003
2140
|
] });
|
|
2004
2141
|
}
|
|
2005
2142
|
function GridItem({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
|
|
2006
|
-
const [showCopied, setShowCopied] =
|
|
2143
|
+
const [showCopied, setShowCopied] = useState4(false);
|
|
2007
2144
|
const isFolder = item.type === "folder";
|
|
2008
2145
|
const isImage = !isFolder && item.thumbnail !== void 0;
|
|
2009
2146
|
const isImagesFolder = isFolder && (item.name === "images" || item.path.includes("/images/"));
|
|
@@ -2120,7 +2257,7 @@ function truncateMiddle(str, maxLength = 24) {
|
|
|
2120
2257
|
}
|
|
2121
2258
|
|
|
2122
2259
|
// src/components/StudioFileList.tsx
|
|
2123
|
-
import {
|
|
2260
|
+
import { useState as useState5 } from "react";
|
|
2124
2261
|
import { css as css5, keyframes as keyframes5 } from "@emotion/react";
|
|
2125
2262
|
import { jsx as jsx5, jsxs as jsxs5 } from "@emotion/react/jsx-runtime";
|
|
2126
2263
|
var spin3 = keyframes5`
|
|
@@ -2432,82 +2569,26 @@ var styles5 = {
|
|
|
2432
2569
|
`
|
|
2433
2570
|
};
|
|
2434
2571
|
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]);
|
|
2572
|
+
const {
|
|
2573
|
+
loading,
|
|
2574
|
+
sortedItems,
|
|
2575
|
+
isAtRoot,
|
|
2576
|
+
isSearching,
|
|
2577
|
+
allItemsSelected,
|
|
2578
|
+
someItemsSelected,
|
|
2579
|
+
selectedItems,
|
|
2580
|
+
navigateUp,
|
|
2581
|
+
handleItemClick,
|
|
2582
|
+
handleOpen,
|
|
2583
|
+
handleGenerateThumbnail,
|
|
2584
|
+
handleSelectAll
|
|
2585
|
+
} = useFileList();
|
|
2462
2586
|
if (loading) {
|
|
2463
2587
|
return /* @__PURE__ */ jsx5("div", { css: styles5.loading, children: /* @__PURE__ */ jsx5("div", { css: styles5.spinner }) });
|
|
2464
2588
|
}
|
|
2465
|
-
|
|
2466
|
-
if (items.length === 0 && isAtRoot) {
|
|
2589
|
+
if (sortedItems.length === 0 && isAtRoot) {
|
|
2467
2590
|
return /* @__PURE__ */ jsx5("div", { css: styles5.empty, children: /* @__PURE__ */ jsx5("p", { children: "No files in this folder" }) });
|
|
2468
2591
|
}
|
|
2469
|
-
const isSearching = searchQuery && searchQuery.length >= 2;
|
|
2470
|
-
const sortedItems = [...items].sort((a, b) => {
|
|
2471
|
-
if (a.type === "folder" && b.type !== "folder") return -1;
|
|
2472
|
-
if (a.type !== "folder" && b.type === "folder") return 1;
|
|
2473
|
-
return a.name.localeCompare(b.name);
|
|
2474
|
-
});
|
|
2475
|
-
const handleItemClick = (item, e) => {
|
|
2476
|
-
if (e.shiftKey && lastSelectedPath) {
|
|
2477
|
-
selectRange(lastSelectedPath, item.path, sortedItems);
|
|
2478
|
-
} else {
|
|
2479
|
-
toggleSelection(item.path);
|
|
2480
|
-
}
|
|
2481
|
-
};
|
|
2482
|
-
const handleOpen = (item) => {
|
|
2483
|
-
if (item.type === "folder") {
|
|
2484
|
-
setCurrentPath(item.path);
|
|
2485
|
-
} else {
|
|
2486
|
-
setFocusedItem(item);
|
|
2487
|
-
}
|
|
2488
|
-
};
|
|
2489
|
-
const handleGenerateThumbnail = async (item) => {
|
|
2490
|
-
try {
|
|
2491
|
-
const imageKey = item.path.replace(/^public\//, "");
|
|
2492
|
-
await fetch("/api/studio/reprocess", {
|
|
2493
|
-
method: "POST",
|
|
2494
|
-
headers: { "Content-Type": "application/json" },
|
|
2495
|
-
body: JSON.stringify({ imageKeys: [imageKey] })
|
|
2496
|
-
});
|
|
2497
|
-
triggerRefresh();
|
|
2498
|
-
} catch (error) {
|
|
2499
|
-
console.error("Failed to generate thumbnail:", error);
|
|
2500
|
-
}
|
|
2501
|
-
};
|
|
2502
|
-
const allItemsSelected = sortedItems.length > 0 && sortedItems.every((item) => selectedItems.has(item.path));
|
|
2503
|
-
const someItemsSelected = sortedItems.some((item) => selectedItems.has(item.path));
|
|
2504
|
-
const handleSelectAll = () => {
|
|
2505
|
-
if (allItemsSelected) {
|
|
2506
|
-
clearSelection();
|
|
2507
|
-
} else {
|
|
2508
|
-
selectAll(sortedItems);
|
|
2509
|
-
}
|
|
2510
|
-
};
|
|
2511
2592
|
return /* @__PURE__ */ jsx5("div", { css: styles5.tableWrapper, children: /* @__PURE__ */ jsxs5("table", { css: styles5.table, children: [
|
|
2512
2593
|
/* @__PURE__ */ jsx5("thead", { children: /* @__PURE__ */ jsxs5("tr", { children: [
|
|
2513
2594
|
/* @__PURE__ */ jsx5("th", { css: [styles5.th, styles5.thCheckbox], children: sortedItems.length > 0 && /* @__PURE__ */ jsx5(
|
|
@@ -2553,7 +2634,7 @@ function StudioFileList() {
|
|
|
2553
2634
|
] }) });
|
|
2554
2635
|
}
|
|
2555
2636
|
function ListRow({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
|
|
2556
|
-
const [showCopied, setShowCopied] =
|
|
2637
|
+
const [showCopied, setShowCopied] = useState5(false);
|
|
2557
2638
|
const isFolder = item.type === "folder";
|
|
2558
2639
|
const isImage = !isFolder && item.thumbnail !== void 0;
|
|
2559
2640
|
const isImagesFolder = isFolder && (item.name === "images" || item.path.includes("/images/"));
|
|
@@ -2659,7 +2740,7 @@ function truncateMiddle2(str, maxLength = 32) {
|
|
|
2659
2740
|
}
|
|
2660
2741
|
|
|
2661
2742
|
// src/components/StudioDetailView.tsx
|
|
2662
|
-
import { useState as
|
|
2743
|
+
import { useState as useState6 } from "react";
|
|
2663
2744
|
import { css as css6 } from "@emotion/react";
|
|
2664
2745
|
import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs6 } from "@emotion/react/jsx-runtime";
|
|
2665
2746
|
var IMAGE_EXTENSIONS = [".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg", ".ico", ".bmp", ".tiff", ".tif"];
|
|
@@ -2920,12 +3001,12 @@ var styles6 = {
|
|
|
2920
3001
|
};
|
|
2921
3002
|
function StudioDetailView() {
|
|
2922
3003
|
const { focusedItem, setFocusedItem, triggerRefresh, clearSelection } = useStudio();
|
|
2923
|
-
const [showDeleteConfirm, setShowDeleteConfirm] =
|
|
2924
|
-
const [showRenameModal, setShowRenameModal] =
|
|
2925
|
-
const [showProcessConfirm, setShowProcessConfirm] =
|
|
2926
|
-
const [processProgress, setProcessProgress] =
|
|
2927
|
-
const [alertMessage, setAlertMessage] =
|
|
2928
|
-
const [showCopied, setShowCopied] =
|
|
3004
|
+
const [showDeleteConfirm, setShowDeleteConfirm] = useState6(false);
|
|
3005
|
+
const [showRenameModal, setShowRenameModal] = useState6(false);
|
|
3006
|
+
const [showProcessConfirm, setShowProcessConfirm] = useState6(false);
|
|
3007
|
+
const [processProgress, setProcessProgress] = useState6(null);
|
|
3008
|
+
const [alertMessage, setAlertMessage] = useState6(null);
|
|
3009
|
+
const [showCopied, setShowCopied] = useState6(false);
|
|
2929
3010
|
if (!focusedItem) return null;
|
|
2930
3011
|
const isImage = isImageFile(focusedItem.name);
|
|
2931
3012
|
const isVideo = isVideoFile(focusedItem.name);
|
|
@@ -3186,7 +3267,7 @@ function formatFileSize3(bytes) {
|
|
|
3186
3267
|
}
|
|
3187
3268
|
|
|
3188
3269
|
// src/components/StudioSettings.tsx
|
|
3189
|
-
import { useState as
|
|
3270
|
+
import { useState as useState7 } from "react";
|
|
3190
3271
|
import { css as css7 } from "@emotion/react";
|
|
3191
3272
|
import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs7 } from "@emotion/react/jsx-runtime";
|
|
3192
3273
|
var btnHeight2 = "36px";
|
|
@@ -3426,7 +3507,7 @@ var styles7 = {
|
|
|
3426
3507
|
`
|
|
3427
3508
|
};
|
|
3428
3509
|
function StudioSettings() {
|
|
3429
|
-
const [isOpen, setIsOpen] =
|
|
3510
|
+
const [isOpen, setIsOpen] = useState7(false);
|
|
3430
3511
|
return /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
3431
3512
|
/* @__PURE__ */ jsx7("button", { css: styles7.btn, onClick: () => setIsOpen(true), "aria-label": "Settings", children: /* @__PURE__ */ jsxs7(
|
|
3432
3513
|
"svg",
|
|
@@ -3454,7 +3535,7 @@ CLOUDFLARE_R2_SECRET_ACCESS_KEY=your_secret_access_key_here
|
|
|
3454
3535
|
CLOUDFLARE_R2_BUCKET_NAME=my-images-bucket
|
|
3455
3536
|
CLOUDFLARE_R2_PUBLIC_URL=https://cdn.yourdomain.com`;
|
|
3456
3537
|
function SettingsPanel({ onClose }) {
|
|
3457
|
-
const [copied, setCopied] =
|
|
3538
|
+
const [copied, setCopied] = useState7(false);
|
|
3458
3539
|
const handleCopy = () => {
|
|
3459
3540
|
navigator.clipboard.writeText(envTemplate);
|
|
3460
3541
|
setCopied(true);
|
|
@@ -3508,18 +3589,93 @@ function SettingsPanel({ onClose }) {
|
|
|
3508
3589
|
] }) });
|
|
3509
3590
|
}
|
|
3510
3591
|
|
|
3511
|
-
// src/components/
|
|
3592
|
+
// src/components/ErrorModal.tsx
|
|
3593
|
+
import { css as css8 } from "@emotion/react";
|
|
3512
3594
|
import { jsx as jsx8, jsxs as jsxs8 } from "@emotion/react/jsx-runtime";
|
|
3513
|
-
var btnHeight3 = "36px";
|
|
3514
3595
|
var styles8 = {
|
|
3515
|
-
|
|
3596
|
+
overlay: css8`
|
|
3597
|
+
position: fixed;
|
|
3598
|
+
inset: 0;
|
|
3599
|
+
background: rgba(0, 0, 0, 0.5);
|
|
3600
|
+
display: flex;
|
|
3601
|
+
align-items: center;
|
|
3602
|
+
justify-content: center;
|
|
3603
|
+
z-index: 1100;
|
|
3604
|
+
`,
|
|
3605
|
+
modal: css8`
|
|
3606
|
+
background: ${colors.surface};
|
|
3607
|
+
border-radius: 12px;
|
|
3608
|
+
padding: 24px;
|
|
3609
|
+
max-width: 400px;
|
|
3610
|
+
width: 90%;
|
|
3611
|
+
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
|
|
3612
|
+
`,
|
|
3613
|
+
header: css8`
|
|
3614
|
+
display: flex;
|
|
3615
|
+
align-items: center;
|
|
3616
|
+
gap: 12px;
|
|
3617
|
+
margin-bottom: 12px;
|
|
3618
|
+
`,
|
|
3619
|
+
icon: css8`
|
|
3620
|
+
width: 24px;
|
|
3621
|
+
height: 24px;
|
|
3622
|
+
color: ${colors.danger};
|
|
3623
|
+
flex-shrink: 0;
|
|
3624
|
+
`,
|
|
3625
|
+
title: css8`
|
|
3626
|
+
font-size: ${fontSize.lg};
|
|
3627
|
+
font-weight: 600;
|
|
3628
|
+
color: ${colors.text};
|
|
3629
|
+
margin: 0;
|
|
3630
|
+
`,
|
|
3631
|
+
message: css8`
|
|
3632
|
+
font-size: ${fontSize.base};
|
|
3633
|
+
color: ${colors.textSecondary};
|
|
3634
|
+
margin: 0 0 20px 0;
|
|
3635
|
+
line-height: 1.5;
|
|
3636
|
+
`,
|
|
3637
|
+
button: css8`
|
|
3638
|
+
width: 100%;
|
|
3639
|
+
padding: 10px 16px;
|
|
3640
|
+
border-radius: 6px;
|
|
3641
|
+
font-size: ${fontSize.base};
|
|
3642
|
+
font-weight: 500;
|
|
3643
|
+
border: none;
|
|
3644
|
+
background: ${colors.primary};
|
|
3645
|
+
color: white;
|
|
3646
|
+
cursor: pointer;
|
|
3647
|
+
transition: background 0.15s ease;
|
|
3648
|
+
|
|
3649
|
+
&:hover {
|
|
3650
|
+
background: ${colors.primaryHover};
|
|
3651
|
+
}
|
|
3652
|
+
`
|
|
3653
|
+
};
|
|
3654
|
+
function ErrorModal() {
|
|
3655
|
+
const { error, clearError } = useStudio();
|
|
3656
|
+
if (!error) return null;
|
|
3657
|
+
return /* @__PURE__ */ jsx8("div", { css: styles8.overlay, onClick: clearError, children: /* @__PURE__ */ jsxs8("div", { css: styles8.modal, onClick: (e) => e.stopPropagation(), children: [
|
|
3658
|
+
/* @__PURE__ */ jsxs8("div", { css: styles8.header, children: [
|
|
3659
|
+
/* @__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: "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" }) }),
|
|
3660
|
+
/* @__PURE__ */ jsx8("h3", { css: styles8.title, children: error.title })
|
|
3661
|
+
] }),
|
|
3662
|
+
/* @__PURE__ */ jsx8("p", { css: styles8.message, children: error.message }),
|
|
3663
|
+
/* @__PURE__ */ jsx8("button", { css: styles8.button, onClick: clearError, children: "OK" })
|
|
3664
|
+
] }) });
|
|
3665
|
+
}
|
|
3666
|
+
|
|
3667
|
+
// src/components/StudioUI.tsx
|
|
3668
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "@emotion/react/jsx-runtime";
|
|
3669
|
+
var btnHeight3 = "36px";
|
|
3670
|
+
var styles9 = {
|
|
3671
|
+
container: css9`
|
|
3516
3672
|
${baseReset}
|
|
3517
3673
|
display: flex;
|
|
3518
3674
|
flex-direction: column;
|
|
3519
3675
|
height: 100%;
|
|
3520
3676
|
background: ${colors.background};
|
|
3521
3677
|
`,
|
|
3522
|
-
header:
|
|
3678
|
+
header: css9`
|
|
3523
3679
|
display: flex;
|
|
3524
3680
|
align-items: center;
|
|
3525
3681
|
justify-content: space-between;
|
|
@@ -3528,7 +3684,7 @@ var styles8 = {
|
|
|
3528
3684
|
border-bottom: 1px solid ${colors.border};
|
|
3529
3685
|
position: relative;
|
|
3530
3686
|
`,
|
|
3531
|
-
title:
|
|
3687
|
+
title: css9`
|
|
3532
3688
|
font-size: ${fontSize.lg};
|
|
3533
3689
|
font-weight: 600;
|
|
3534
3690
|
color: ${colors.text};
|
|
@@ -3536,14 +3692,14 @@ var styles8 = {
|
|
|
3536
3692
|
letter-spacing: -0.02em;
|
|
3537
3693
|
flex-shrink: 0;
|
|
3538
3694
|
`,
|
|
3539
|
-
headerLeft:
|
|
3695
|
+
headerLeft: css9`
|
|
3540
3696
|
display: flex;
|
|
3541
3697
|
align-items: center;
|
|
3542
3698
|
gap: 12px;
|
|
3543
3699
|
flex: 1;
|
|
3544
3700
|
min-width: 0;
|
|
3545
3701
|
`,
|
|
3546
|
-
headerCenter:
|
|
3702
|
+
headerCenter: css9`
|
|
3547
3703
|
position: absolute;
|
|
3548
3704
|
left: 50%;
|
|
3549
3705
|
transform: translateX(-50%);
|
|
@@ -3551,7 +3707,7 @@ var styles8 = {
|
|
|
3551
3707
|
align-items: center;
|
|
3552
3708
|
max-width: 50%;
|
|
3553
3709
|
`,
|
|
3554
|
-
breadcrumbs:
|
|
3710
|
+
breadcrumbs: css9`
|
|
3555
3711
|
display: flex;
|
|
3556
3712
|
align-items: center;
|
|
3557
3713
|
gap: 6px;
|
|
@@ -3559,11 +3715,11 @@ var styles8 = {
|
|
|
3559
3715
|
color: ${colors.textSecondary};
|
|
3560
3716
|
overflow: hidden;
|
|
3561
3717
|
`,
|
|
3562
|
-
breadcrumbSeparator:
|
|
3718
|
+
breadcrumbSeparator: css9`
|
|
3563
3719
|
color: ${colors.border};
|
|
3564
3720
|
flex-shrink: 0;
|
|
3565
3721
|
`,
|
|
3566
|
-
breadcrumbItem:
|
|
3722
|
+
breadcrumbItem: css9`
|
|
3567
3723
|
color: ${colors.textSecondary};
|
|
3568
3724
|
text-decoration: none;
|
|
3569
3725
|
cursor: pointer;
|
|
@@ -3574,19 +3730,19 @@ var styles8 = {
|
|
|
3574
3730
|
color: ${colors.primary};
|
|
3575
3731
|
}
|
|
3576
3732
|
`,
|
|
3577
|
-
breadcrumbCurrent:
|
|
3733
|
+
breadcrumbCurrent: css9`
|
|
3578
3734
|
color: ${colors.text};
|
|
3579
3735
|
font-weight: 500;
|
|
3580
3736
|
white-space: nowrap;
|
|
3581
3737
|
overflow: hidden;
|
|
3582
3738
|
text-overflow: ellipsis;
|
|
3583
3739
|
`,
|
|
3584
|
-
headerActions:
|
|
3740
|
+
headerActions: css9`
|
|
3585
3741
|
display: flex;
|
|
3586
3742
|
align-items: center;
|
|
3587
3743
|
gap: 8px;
|
|
3588
3744
|
`,
|
|
3589
|
-
headerBtn:
|
|
3745
|
+
headerBtn: css9`
|
|
3590
3746
|
height: ${btnHeight3};
|
|
3591
3747
|
padding: 0 12px;
|
|
3592
3748
|
background: ${colors.surface};
|
|
@@ -3603,23 +3759,23 @@ var styles8 = {
|
|
|
3603
3759
|
border-color: ${colors.borderHover};
|
|
3604
3760
|
}
|
|
3605
3761
|
`,
|
|
3606
|
-
headerIcon:
|
|
3762
|
+
headerIcon: css9`
|
|
3607
3763
|
width: 16px;
|
|
3608
3764
|
height: 16px;
|
|
3609
3765
|
color: ${colors.textSecondary};
|
|
3610
3766
|
`,
|
|
3611
|
-
content:
|
|
3767
|
+
content: css9`
|
|
3612
3768
|
flex: 1;
|
|
3613
3769
|
display: flex;
|
|
3614
3770
|
overflow: hidden;
|
|
3615
3771
|
`,
|
|
3616
|
-
fileBrowser:
|
|
3772
|
+
fileBrowser: css9`
|
|
3617
3773
|
flex: 1;
|
|
3618
3774
|
min-width: 0;
|
|
3619
3775
|
overflow: auto;
|
|
3620
3776
|
padding: 20px 24px;
|
|
3621
3777
|
`,
|
|
3622
|
-
dropOverlay:
|
|
3778
|
+
dropOverlay: css9`
|
|
3623
3779
|
position: absolute;
|
|
3624
3780
|
top: 0;
|
|
3625
3781
|
left: 0;
|
|
@@ -3634,7 +3790,7 @@ var styles8 = {
|
|
|
3634
3790
|
z-index: 50;
|
|
3635
3791
|
pointer-events: none;
|
|
3636
3792
|
`,
|
|
3637
|
-
dropMessage:
|
|
3793
|
+
dropMessage: css9`
|
|
3638
3794
|
display: flex;
|
|
3639
3795
|
flex-direction: column;
|
|
3640
3796
|
align-items: center;
|
|
@@ -3643,36 +3799,43 @@ var styles8 = {
|
|
|
3643
3799
|
font-size: ${fontSize.lg};
|
|
3644
3800
|
font-weight: 600;
|
|
3645
3801
|
`,
|
|
3646
|
-
dropIcon:
|
|
3802
|
+
dropIcon: css9`
|
|
3647
3803
|
width: 48px;
|
|
3648
3804
|
height: 48px;
|
|
3649
3805
|
`
|
|
3650
3806
|
};
|
|
3651
3807
|
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
|
|
3808
|
+
const [currentPath, setCurrentPathInternal] = useState8("public");
|
|
3809
|
+
const [selectedItems, setSelectedItems] = useState8(/* @__PURE__ */ new Set());
|
|
3810
|
+
const [lastSelectedPath, setLastSelectedPath] = useState8(null);
|
|
3811
|
+
const [viewMode, setViewMode] = useState8("grid");
|
|
3812
|
+
const [focusedItem, setFocusedItem] = useState8(null);
|
|
3813
|
+
const [meta, setMeta] = useState8(null);
|
|
3814
|
+
const [isLoading, setIsLoading] = useState8(false);
|
|
3815
|
+
const [refreshKey, setRefreshKey] = useState8(0);
|
|
3816
|
+
const [searchQuery, setSearchQuery] = useState8("");
|
|
3817
|
+
const [error, setError] = useState8(null);
|
|
3818
|
+
const [isDragging, setIsDragging] = useState8(false);
|
|
3819
|
+
const triggerRefresh = useCallback3(() => {
|
|
3663
3820
|
setRefreshKey((k) => k + 1);
|
|
3664
3821
|
}, []);
|
|
3665
|
-
const
|
|
3822
|
+
const showError = useCallback3((title, message) => {
|
|
3823
|
+
setError({ title, message });
|
|
3824
|
+
}, []);
|
|
3825
|
+
const clearError = useCallback3(() => {
|
|
3826
|
+
setError(null);
|
|
3827
|
+
}, []);
|
|
3828
|
+
const handleDragOver = useCallback3((e) => {
|
|
3666
3829
|
e.preventDefault();
|
|
3667
3830
|
e.stopPropagation();
|
|
3668
3831
|
setIsDragging(true);
|
|
3669
3832
|
}, []);
|
|
3670
|
-
const handleDragLeave =
|
|
3833
|
+
const handleDragLeave = useCallback3((e) => {
|
|
3671
3834
|
e.preventDefault();
|
|
3672
3835
|
e.stopPropagation();
|
|
3673
3836
|
setIsDragging(false);
|
|
3674
3837
|
}, []);
|
|
3675
|
-
const handleDrop =
|
|
3838
|
+
const handleDrop = useCallback3(async (e) => {
|
|
3676
3839
|
e.preventDefault();
|
|
3677
3840
|
e.stopPropagation();
|
|
3678
3841
|
setIsDragging(false);
|
|
@@ -3690,25 +3853,25 @@ function StudioUI({ onClose, isVisible = true }) {
|
|
|
3690
3853
|
method: "POST",
|
|
3691
3854
|
body: formData
|
|
3692
3855
|
});
|
|
3693
|
-
} catch (
|
|
3694
|
-
console.error("Upload error:",
|
|
3856
|
+
} catch (error2) {
|
|
3857
|
+
console.error("Upload error:", error2);
|
|
3695
3858
|
}
|
|
3696
3859
|
}
|
|
3697
3860
|
triggerRefresh();
|
|
3698
3861
|
}, [currentPath, triggerRefresh]);
|
|
3699
|
-
const navigateUp =
|
|
3862
|
+
const navigateUp = useCallback3(() => {
|
|
3700
3863
|
if (currentPath === "public") return;
|
|
3701
3864
|
const parts = currentPath.split("/");
|
|
3702
3865
|
parts.pop();
|
|
3703
3866
|
setCurrentPathInternal(parts.join("/") || "public");
|
|
3704
3867
|
setSelectedItems(/* @__PURE__ */ new Set());
|
|
3705
3868
|
}, [currentPath]);
|
|
3706
|
-
const setCurrentPath =
|
|
3869
|
+
const setCurrentPath = useCallback3((path) => {
|
|
3707
3870
|
setCurrentPathInternal(path);
|
|
3708
3871
|
setSelectedItems(/* @__PURE__ */ new Set());
|
|
3709
3872
|
setFocusedItem(null);
|
|
3710
3873
|
}, []);
|
|
3711
|
-
const toggleSelection =
|
|
3874
|
+
const toggleSelection = useCallback3((path) => {
|
|
3712
3875
|
setSelectedItems((prev) => {
|
|
3713
3876
|
const next = new Set(prev);
|
|
3714
3877
|
if (next.has(path)) {
|
|
@@ -3720,7 +3883,7 @@ function StudioUI({ onClose, isVisible = true }) {
|
|
|
3720
3883
|
});
|
|
3721
3884
|
setLastSelectedPath(path);
|
|
3722
3885
|
}, []);
|
|
3723
|
-
const selectRange =
|
|
3886
|
+
const selectRange = useCallback3((fromPath, toPath, allItems) => {
|
|
3724
3887
|
const fromIndex = allItems.findIndex((item) => item.path === fromPath);
|
|
3725
3888
|
const toIndex = allItems.findIndex((item) => item.path === toPath);
|
|
3726
3889
|
if (fromIndex === -1 || toIndex === -1) return;
|
|
@@ -3735,13 +3898,13 @@ function StudioUI({ onClose, isVisible = true }) {
|
|
|
3735
3898
|
});
|
|
3736
3899
|
setLastSelectedPath(toPath);
|
|
3737
3900
|
}, []);
|
|
3738
|
-
const selectAll =
|
|
3901
|
+
const selectAll = useCallback3((items) => {
|
|
3739
3902
|
setSelectedItems(new Set(items.map((item) => item.path)));
|
|
3740
3903
|
}, []);
|
|
3741
|
-
const clearSelection =
|
|
3904
|
+
const clearSelection = useCallback3(() => {
|
|
3742
3905
|
setSelectedItems(/* @__PURE__ */ new Set());
|
|
3743
3906
|
}, []);
|
|
3744
|
-
const handleKeyDown =
|
|
3907
|
+
const handleKeyDown = useCallback3(
|
|
3745
3908
|
(e) => {
|
|
3746
3909
|
if (e.key === "Escape") {
|
|
3747
3910
|
const target = e.target;
|
|
@@ -3757,7 +3920,7 @@ function StudioUI({ onClose, isVisible = true }) {
|
|
|
3757
3920
|
},
|
|
3758
3921
|
[onClose, focusedItem]
|
|
3759
3922
|
);
|
|
3760
|
-
|
|
3923
|
+
useEffect3(() => {
|
|
3761
3924
|
if (isVisible) {
|
|
3762
3925
|
document.addEventListener("keydown", handleKeyDown);
|
|
3763
3926
|
document.body.style.overflow = "hidden";
|
|
@@ -3793,43 +3956,47 @@ function StudioUI({ onClose, isVisible = true }) {
|
|
|
3793
3956
|
refreshKey,
|
|
3794
3957
|
triggerRefresh,
|
|
3795
3958
|
searchQuery,
|
|
3796
|
-
setSearchQuery
|
|
3959
|
+
setSearchQuery,
|
|
3960
|
+
error,
|
|
3961
|
+
showError,
|
|
3962
|
+
clearError
|
|
3797
3963
|
};
|
|
3798
|
-
return /* @__PURE__ */
|
|
3799
|
-
/* @__PURE__ */
|
|
3800
|
-
/* @__PURE__ */
|
|
3801
|
-
/* @__PURE__ */
|
|
3802
|
-
/* @__PURE__ */
|
|
3803
|
-
/* @__PURE__ */
|
|
3804
|
-
/* @__PURE__ */
|
|
3964
|
+
return /* @__PURE__ */ jsx9(StudioContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs9("div", { css: styles9.container, children: [
|
|
3965
|
+
/* @__PURE__ */ jsxs9("div", { css: styles9.header, children: [
|
|
3966
|
+
/* @__PURE__ */ jsx9("div", { css: styles9.headerLeft, children: /* @__PURE__ */ jsx9("h1", { css: styles9.title, children: "Studio" }) }),
|
|
3967
|
+
/* @__PURE__ */ jsx9("div", { css: styles9.headerCenter, children: /* @__PURE__ */ jsx9(Breadcrumbs, { currentPath, onNavigate: setCurrentPath }) }),
|
|
3968
|
+
/* @__PURE__ */ jsxs9("div", { css: styles9.headerActions, children: [
|
|
3969
|
+
/* @__PURE__ */ jsx9(StudioSettings, {}),
|
|
3970
|
+
/* @__PURE__ */ jsx9(
|
|
3805
3971
|
"button",
|
|
3806
3972
|
{
|
|
3807
|
-
css:
|
|
3973
|
+
css: styles9.headerBtn,
|
|
3808
3974
|
onClick: onClose,
|
|
3809
3975
|
"aria-label": "Close Studio",
|
|
3810
|
-
children: /* @__PURE__ */
|
|
3976
|
+
children: /* @__PURE__ */ jsx9(CloseIcon, {})
|
|
3811
3977
|
}
|
|
3812
3978
|
)
|
|
3813
3979
|
] })
|
|
3814
3980
|
] }),
|
|
3815
|
-
/* @__PURE__ */
|
|
3816
|
-
/* @__PURE__ */
|
|
3981
|
+
/* @__PURE__ */ jsx9(StudioToolbar, {}),
|
|
3982
|
+
/* @__PURE__ */ jsxs9(
|
|
3817
3983
|
"div",
|
|
3818
3984
|
{
|
|
3819
|
-
css:
|
|
3985
|
+
css: styles9.content,
|
|
3820
3986
|
onDragOver: handleDragOver,
|
|
3821
3987
|
onDragLeave: handleDragLeave,
|
|
3822
3988
|
onDrop: handleDrop,
|
|
3823
3989
|
children: [
|
|
3824
|
-
isDragging && /* @__PURE__ */
|
|
3825
|
-
/* @__PURE__ */
|
|
3826
|
-
/* @__PURE__ */
|
|
3990
|
+
isDragging && /* @__PURE__ */ jsx9("div", { css: styles9.dropOverlay, children: /* @__PURE__ */ jsxs9("div", { css: styles9.dropMessage, children: [
|
|
3991
|
+
/* @__PURE__ */ jsx9("svg", { css: styles9.dropIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx9("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" }) }),
|
|
3992
|
+
/* @__PURE__ */ jsx9("span", { children: "Drop files to upload" })
|
|
3827
3993
|
] }) }),
|
|
3828
|
-
/* @__PURE__ */
|
|
3994
|
+
/* @__PURE__ */ jsx9("div", { css: styles9.fileBrowser, children: viewMode === "grid" ? /* @__PURE__ */ jsx9(StudioFileGrid, {}) : /* @__PURE__ */ jsx9(StudioFileList, {}) })
|
|
3829
3995
|
]
|
|
3830
3996
|
}
|
|
3831
3997
|
),
|
|
3832
|
-
focusedItem && /* @__PURE__ */
|
|
3998
|
+
focusedItem && /* @__PURE__ */ jsx9(StudioDetailView, {}),
|
|
3999
|
+
/* @__PURE__ */ jsx9(ErrorModal, {})
|
|
3833
4000
|
] }) });
|
|
3834
4001
|
}
|
|
3835
4002
|
function Breadcrumbs({ currentPath, onNavigate }) {
|
|
@@ -3838,12 +4005,12 @@ function Breadcrumbs({ currentPath, onNavigate }) {
|
|
|
3838
4005
|
name: part,
|
|
3839
4006
|
path: parts.slice(0, index + 1).join("/")
|
|
3840
4007
|
}));
|
|
3841
|
-
return /* @__PURE__ */
|
|
3842
|
-
index > 0 && /* @__PURE__ */
|
|
3843
|
-
index === breadcrumbs.length - 1 ? /* @__PURE__ */
|
|
4008
|
+
return /* @__PURE__ */ jsx9("div", { css: styles9.breadcrumbs, children: breadcrumbs.map((crumb, index) => /* @__PURE__ */ jsxs9("span", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
|
|
4009
|
+
index > 0 && /* @__PURE__ */ jsx9("span", { css: styles9.breadcrumbSeparator, children: "/" }),
|
|
4010
|
+
index === breadcrumbs.length - 1 ? /* @__PURE__ */ jsx9("span", { css: styles9.breadcrumbCurrent, children: crumb.name }) : /* @__PURE__ */ jsx9(
|
|
3844
4011
|
"span",
|
|
3845
4012
|
{
|
|
3846
|
-
css:
|
|
4013
|
+
css: styles9.breadcrumbItem,
|
|
3847
4014
|
onClick: () => onNavigate(crumb.path),
|
|
3848
4015
|
children: crumb.name
|
|
3849
4016
|
}
|
|
@@ -3851,10 +4018,10 @@ function Breadcrumbs({ currentPath, onNavigate }) {
|
|
|
3851
4018
|
] }, crumb.path)) });
|
|
3852
4019
|
}
|
|
3853
4020
|
function CloseIcon() {
|
|
3854
|
-
return /* @__PURE__ */
|
|
4021
|
+
return /* @__PURE__ */ jsxs9(
|
|
3855
4022
|
"svg",
|
|
3856
4023
|
{
|
|
3857
|
-
css:
|
|
4024
|
+
css: styles9.headerIcon,
|
|
3858
4025
|
xmlns: "http://www.w3.org/2000/svg",
|
|
3859
4026
|
viewBox: "0 0 24 24",
|
|
3860
4027
|
fill: "none",
|
|
@@ -3863,8 +4030,8 @@ function CloseIcon() {
|
|
|
3863
4030
|
strokeLinecap: "round",
|
|
3864
4031
|
strokeLinejoin: "round",
|
|
3865
4032
|
children: [
|
|
3866
|
-
/* @__PURE__ */
|
|
3867
|
-
/* @__PURE__ */
|
|
4033
|
+
/* @__PURE__ */ jsx9("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
4034
|
+
/* @__PURE__ */ jsx9("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
3868
4035
|
]
|
|
3869
4036
|
}
|
|
3870
4037
|
);
|
|
@@ -3874,4 +4041,4 @@ export {
|
|
|
3874
4041
|
StudioUI,
|
|
3875
4042
|
StudioUI_default as default
|
|
3876
4043
|
};
|
|
3877
|
-
//# sourceMappingURL=StudioUI-
|
|
4044
|
+
//# sourceMappingURL=StudioUI-VJVOSOPD.mjs.map
|