@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
|
@@ -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 = _react.createContext.call(void 0, defaultState);
|
|
@@ -1554,6 +1559,194 @@ function ImageStackIcon() {
|
|
|
1554
1559
|
|
|
1555
1560
|
|
|
1556
1561
|
|
|
1562
|
+
// src/hooks/useFileList.ts
|
|
1563
|
+
|
|
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] = _react.useState.call(void 0, []);
|
|
1663
|
+
const [loading, setLoading] = _react.useState.call(void 0, true);
|
|
1664
|
+
const isInitialLoad = _react.useRef.call(void 0, true);
|
|
1665
|
+
const lastPath = _react.useRef.call(void 0, currentPath);
|
|
1666
|
+
_react.useEffect.call(void 0, () => {
|
|
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 = _react.useCallback.call(void 0, (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 = _react.useCallback.call(void 0, (item) => {
|
|
1703
|
+
if (item.type === "folder") {
|
|
1704
|
+
setCurrentPath(item.path);
|
|
1705
|
+
} else {
|
|
1706
|
+
setFocusedItem(item);
|
|
1707
|
+
}
|
|
1708
|
+
}, [setCurrentPath, setFocusedItem]);
|
|
1709
|
+
const handleGenerateThumbnail = _react.useCallback.call(void 0, 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 = _react.useCallback.call(void 0, () => {
|
|
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
|
|
1749
|
+
|
|
1557
1750
|
var spin2 = _react3.keyframes`
|
|
1558
1751
|
to { transform: rotate(360deg); }
|
|
1559
1752
|
`;
|
|
@@ -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__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles4.loading, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles4.spinner }) });
|
|
1907
2087
|
}
|
|
1908
|
-
|
|
1909
|
-
if (items.length === 0 && isAtRoot) {
|
|
2088
|
+
if (sortedItems.length === 0 && isAtRoot) {
|
|
1910
2089
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.empty, children: [
|
|
1911
2090
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.emptyIcon, 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: "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__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles4.emptyText, children: "No files in this folder" }),
|
|
1913
2092
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "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__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
|
|
1959
2096
|
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: [
|
|
1960
2097
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
@@ -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__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.loading, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.spinner }) });
|
|
2464
2588
|
}
|
|
2465
|
-
|
|
2466
|
-
if (items.length === 0 && isAtRoot) {
|
|
2589
|
+
if (sortedItems.length === 0 && isAtRoot) {
|
|
2467
2590
|
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.empty, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "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__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.tableWrapper, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "table", { css: styles5.table, children: [
|
|
2512
2593
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "thead", { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tr", { children: [
|
|
2513
2594
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles5.th, styles5.thCheckbox], children: sortedItems.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
@@ -3508,10 +3589,85 @@ function SettingsPanel({ onClose }) {
|
|
|
3508
3589
|
] }) });
|
|
3509
3590
|
}
|
|
3510
3591
|
|
|
3592
|
+
// src/components/ErrorModal.tsx
|
|
3593
|
+
|
|
3594
|
+
|
|
3595
|
+
var styles8 = {
|
|
3596
|
+
overlay: _react3.css`
|
|
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: _react3.css`
|
|
3606
|
+
background: ${_chunkUFCWGUAGjs.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: _react3.css`
|
|
3614
|
+
display: flex;
|
|
3615
|
+
align-items: center;
|
|
3616
|
+
gap: 12px;
|
|
3617
|
+
margin-bottom: 12px;
|
|
3618
|
+
`,
|
|
3619
|
+
icon: _react3.css`
|
|
3620
|
+
width: 24px;
|
|
3621
|
+
height: 24px;
|
|
3622
|
+
color: ${_chunkUFCWGUAGjs.colors.danger};
|
|
3623
|
+
flex-shrink: 0;
|
|
3624
|
+
`,
|
|
3625
|
+
title: _react3.css`
|
|
3626
|
+
font-size: ${_chunkUFCWGUAGjs.fontSize.lg};
|
|
3627
|
+
font-weight: 600;
|
|
3628
|
+
color: ${_chunkUFCWGUAGjs.colors.text};
|
|
3629
|
+
margin: 0;
|
|
3630
|
+
`,
|
|
3631
|
+
message: _react3.css`
|
|
3632
|
+
font-size: ${_chunkUFCWGUAGjs.fontSize.base};
|
|
3633
|
+
color: ${_chunkUFCWGUAGjs.colors.textSecondary};
|
|
3634
|
+
margin: 0 0 20px 0;
|
|
3635
|
+
line-height: 1.5;
|
|
3636
|
+
`,
|
|
3637
|
+
button: _react3.css`
|
|
3638
|
+
width: 100%;
|
|
3639
|
+
padding: 10px 16px;
|
|
3640
|
+
border-radius: 6px;
|
|
3641
|
+
font-size: ${_chunkUFCWGUAGjs.fontSize.base};
|
|
3642
|
+
font-weight: 500;
|
|
3643
|
+
border: none;
|
|
3644
|
+
background: ${_chunkUFCWGUAGjs.colors.primary};
|
|
3645
|
+
color: white;
|
|
3646
|
+
cursor: pointer;
|
|
3647
|
+
transition: background 0.15s ease;
|
|
3648
|
+
|
|
3649
|
+
&:hover {
|
|
3650
|
+
background: ${_chunkUFCWGUAGjs.colors.primaryHover};
|
|
3651
|
+
}
|
|
3652
|
+
`
|
|
3653
|
+
};
|
|
3654
|
+
function ErrorModal() {
|
|
3655
|
+
const { error, clearError } = useStudio();
|
|
3656
|
+
if (!error) return null;
|
|
3657
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles8.overlay, onClick: clearError, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.modal, onClick: (e) => e.stopPropagation(), children: [
|
|
3658
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.header, children: [
|
|
3659
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles8.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "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__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles8.title, children: error.title })
|
|
3661
|
+
] }),
|
|
3662
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles8.message, children: error.message }),
|
|
3663
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles8.button, onClick: clearError, children: "OK" })
|
|
3664
|
+
] }) });
|
|
3665
|
+
}
|
|
3666
|
+
|
|
3511
3667
|
// src/components/StudioUI.tsx
|
|
3512
3668
|
|
|
3513
3669
|
var btnHeight3 = "36px";
|
|
3514
|
-
var
|
|
3670
|
+
var styles9 = {
|
|
3515
3671
|
container: _react3.css`
|
|
3516
3672
|
${_chunkUFCWGUAGjs.baseReset}
|
|
3517
3673
|
display: flex;
|
|
@@ -3658,10 +3814,17 @@ function StudioUI({ onClose, isVisible = true }) {
|
|
|
3658
3814
|
const [isLoading, setIsLoading] = _react.useState.call(void 0, false);
|
|
3659
3815
|
const [refreshKey, setRefreshKey] = _react.useState.call(void 0, 0);
|
|
3660
3816
|
const [searchQuery, setSearchQuery] = _react.useState.call(void 0, "");
|
|
3817
|
+
const [error, setError] = _react.useState.call(void 0, null);
|
|
3661
3818
|
const [isDragging, setIsDragging] = _react.useState.call(void 0, false);
|
|
3662
3819
|
const triggerRefresh = _react.useCallback.call(void 0, () => {
|
|
3663
3820
|
setRefreshKey((k) => k + 1);
|
|
3664
3821
|
}, []);
|
|
3822
|
+
const showError = _react.useCallback.call(void 0, (title, message) => {
|
|
3823
|
+
setError({ title, message });
|
|
3824
|
+
}, []);
|
|
3825
|
+
const clearError = _react.useCallback.call(void 0, () => {
|
|
3826
|
+
setError(null);
|
|
3827
|
+
}, []);
|
|
3665
3828
|
const handleDragOver = _react.useCallback.call(void 0, (e) => {
|
|
3666
3829
|
e.preventDefault();
|
|
3667
3830
|
e.stopPropagation();
|
|
@@ -3690,8 +3853,8 @@ 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();
|
|
@@ -3793,18 +3956,21 @@ 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__ */ _jsxruntime.jsx.call(void 0, StudioContext.Provider, { value: contextValue, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
3799
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
3800
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css:
|
|
3801
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css:
|
|
3802
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css:
|
|
3964
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioContext.Provider, { value: contextValue, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles9.container, children: [
|
|
3965
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles9.header, children: [
|
|
3966
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles9.headerLeft, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h1", { css: styles9.title, children: "Studio" }) }),
|
|
3967
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles9.headerCenter, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Breadcrumbs, { currentPath, onNavigate: setCurrentPath }) }),
|
|
3968
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles9.headerActions, children: [
|
|
3803
3969
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioSettings, {}),
|
|
3804
3970
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3805
3971
|
"button",
|
|
3806
3972
|
{
|
|
3807
|
-
css:
|
|
3973
|
+
css: styles9.headerBtn,
|
|
3808
3974
|
onClick: onClose,
|
|
3809
3975
|
"aria-label": "Close Studio",
|
|
3810
3976
|
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, CloseIcon, {})
|
|
@@ -3816,20 +3982,21 @@ function StudioUI({ onClose, isVisible = true }) {
|
|
|
3816
3982
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
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__ */ _jsxruntime.jsx.call(void 0, "div", { css:
|
|
3825
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css:
|
|
3990
|
+
isDragging && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles9.dropOverlay, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles9.dropMessage, children: [
|
|
3991
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles9.dropIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "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" }) }),
|
|
3826
3992
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: "Drop files to upload" })
|
|
3827
3993
|
] }) }),
|
|
3828
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css:
|
|
3994
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles9.fileBrowser, children: viewMode === "grid" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioFileGrid, {}) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioFileList, {}) })
|
|
3829
3995
|
]
|
|
3830
3996
|
}
|
|
3831
3997
|
),
|
|
3832
|
-
focusedItem && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioDetailView, {})
|
|
3998
|
+
focusedItem && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioDetailView, {}),
|
|
3999
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, 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__ */ _jsxruntime.jsx.call(void 0, "div", { css:
|
|
3842
|
-
index > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css:
|
|
3843
|
-
index === breadcrumbs.length - 1 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css:
|
|
4008
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles9.breadcrumbs, children: breadcrumbs.map((crumb, index) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
|
|
4009
|
+
index > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles9.breadcrumbSeparator, children: "/" }),
|
|
4010
|
+
index === breadcrumbs.length - 1 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles9.breadcrumbCurrent, children: crumb.name }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
3844
4011
|
"span",
|
|
3845
4012
|
{
|
|
3846
|
-
css:
|
|
4013
|
+
css: styles9.breadcrumbItem,
|
|
3847
4014
|
onClick: () => onNavigate(crumb.path),
|
|
3848
4015
|
children: crumb.name
|
|
3849
4016
|
}
|
|
@@ -3854,7 +4021,7 @@ function CloseIcon() {
|
|
|
3854
4021
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
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",
|
|
@@ -3874,4 +4041,4 @@ var StudioUI_default = StudioUI;
|
|
|
3874
4041
|
|
|
3875
4042
|
|
|
3876
4043
|
exports.StudioUI = StudioUI; exports.default = StudioUI_default;
|
|
3877
|
-
//# sourceMappingURL=StudioUI-
|
|
4044
|
+
//# sourceMappingURL=StudioUI-YFDO5MGG.js.map
|