@gallop.software/studio 0.1.39 → 0.1.41

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.
@@ -4,7 +4,7 @@ import {
4
4
  colors,
5
5
  fontSize,
6
6
  fontStack
7
- } from "./chunk-DIJR5Y6S.mjs";
7
+ } from "./chunk-HXE6XCG2.mjs";
8
8
 
9
9
  // src/components/StudioUI.tsx
10
10
  import { useEffect as useEffect3, useCallback as useCallback2, useState as useState6 } from "react";
@@ -321,13 +321,15 @@ var spin = keyframes2`
321
321
  var styles2 = {
322
322
  toolbar: css2`
323
323
  display: flex;
324
- flex-wrap: wrap;
324
+ flex-wrap: nowrap;
325
325
  align-items: center;
326
326
  justify-content: space-between;
327
327
  gap: 8px;
328
328
  padding: 12px 16px;
329
329
  background-color: ${colors.surface};
330
330
  border-bottom: 1px solid ${colors.border};
331
+ overflow-x: auto;
332
+ min-width: 0;
331
333
 
332
334
  @media (min-width: 768px) {
333
335
  padding: 12px 24px;
@@ -335,13 +337,15 @@ var styles2 = {
335
337
  `,
336
338
  left: css2`
337
339
  display: flex;
338
- flex-wrap: wrap;
340
+ flex-wrap: nowrap;
341
+ flex-shrink: 0;
339
342
  align-items: center;
340
343
  gap: 8px;
341
344
  `,
342
345
  right: css2`
343
346
  display: flex;
344
- flex-wrap: wrap;
347
+ flex-wrap: nowrap;
348
+ flex-shrink: 0;
345
349
  align-items: center;
346
350
  gap: 8px;
347
351
  `,
@@ -475,8 +479,13 @@ var styles2 = {
475
479
  }
476
480
  `,
477
481
  viewBtnActive: css2`
478
- background-color: ${colors.background};
479
- color: ${colors.text};
482
+ background-color: ${colors.primaryLight};
483
+ color: ${colors.primary};
484
+
485
+ &:hover {
486
+ background-color: ${colors.primaryLight};
487
+ color: ${colors.primary};
488
+ }
480
489
  `
481
490
  };
482
491
  function StudioToolbar() {
@@ -803,6 +812,9 @@ function StudioToolbar() {
803
812
  setSearchQuery(e.target.value);
804
813
  }, [setSearchQuery]);
805
814
  const hasSelection = selectedItems.size > 0;
815
+ const hasImagesSelected = Array.from(selectedItems).some(
816
+ (path) => path === "public/images" || path.startsWith("public/images/")
817
+ );
806
818
  if (focusedItem) {
807
819
  return null;
808
820
  }
@@ -884,8 +896,8 @@ function StudioToolbar() {
884
896
  {
885
897
  css: styles2.btn,
886
898
  onClick: handleProcessImages,
887
- disabled: processing || isInImagesFolder,
888
- title: isInImagesFolder ? "Cannot process images from within the images folder" : void 0,
899
+ disabled: processing || isInImagesFolder || hasImagesSelected,
900
+ title: isInImagesFolder || hasImagesSelected ? "Cannot process protected images folder" : void 0,
889
901
  children: [
890
902
  /* @__PURE__ */ jsx2(ImageStackIcon, {}),
891
903
  processing ? "Processing..." : "Process Images"
@@ -897,7 +909,8 @@ function StudioToolbar() {
897
909
  {
898
910
  css: [styles2.btn, styles2.btnDanger],
899
911
  onClick: handleDeleteClick,
900
- disabled: !hasSelection,
912
+ disabled: !hasSelection || hasImagesSelected,
913
+ title: hasImagesSelected ? "Cannot delete protected images folder items" : void 0,
901
914
  children: [
902
915
  /* @__PURE__ */ jsx2(TrashIcon, {}),
903
916
  "Delete"
@@ -1034,13 +1047,13 @@ var styles3 = {
1034
1047
  `,
1035
1048
  grid: css3`
1036
1049
  display: grid;
1037
- grid-template-columns: repeat(2, 1fr);
1050
+ grid-template-columns: 1fr;
1038
1051
  gap: 12px;
1039
1052
 
1040
- @media (min-width: 640px) { grid-template-columns: repeat(3, 1fr); }
1041
- @media (min-width: 768px) { grid-template-columns: repeat(4, 1fr); }
1042
- @media (min-width: 1024px) { grid-template-columns: repeat(5, 1fr); }
1043
- @media (min-width: 1280px) { grid-template-columns: repeat(6, 1fr); }
1053
+ @media (min-width: 480px) { grid-template-columns: repeat(2, 1fr); }
1054
+ @media (min-width: 768px) { grid-template-columns: repeat(3, 1fr); }
1055
+ @media (min-width: 1024px) { grid-template-columns: repeat(4, 1fr); }
1056
+ @media (min-width: 1280px) { grid-template-columns: repeat(5, 1fr); }
1044
1057
  `,
1045
1058
  item: css3`
1046
1059
  position: relative;
@@ -1184,14 +1197,69 @@ var styles3 = {
1184
1197
  `,
1185
1198
  labelRow: css3`
1186
1199
  display: flex;
1187
- align-items: center;
1188
- justify-content: space-between;
1189
- gap: 8px;
1200
+ flex-direction: column;
1201
+ gap: 6px;
1190
1202
  `,
1191
1203
  labelText: css3`
1192
1204
  flex: 1;
1193
1205
  min-width: 0;
1194
1206
  `,
1207
+ buttonRow: css3`
1208
+ display: flex;
1209
+ gap: 6px;
1210
+ `,
1211
+ copyBtn: css3`
1212
+ position: relative;
1213
+ flex-shrink: 0;
1214
+ height: 28px;
1215
+ width: 28px;
1216
+ font-size: ${fontSize.xs};
1217
+ color: ${colors.textSecondary};
1218
+ background: ${colors.surface};
1219
+ border: 1px solid ${colors.border};
1220
+ padding: 0;
1221
+ cursor: pointer;
1222
+ border-radius: 4px;
1223
+ transition: all 0.15s ease;
1224
+ display: inline-flex;
1225
+ align-items: center;
1226
+ justify-content: center;
1227
+
1228
+ &:hover {
1229
+ background: ${colors.surfaceHover};
1230
+ border-color: ${colors.borderHover};
1231
+ color: ${colors.text};
1232
+ }
1233
+ `,
1234
+ copyIcon: css3`
1235
+ width: 14px;
1236
+ height: 14px;
1237
+ `,
1238
+ tooltip: css3`
1239
+ position: absolute;
1240
+ bottom: 100%;
1241
+ left: 50%;
1242
+ transform: translateX(-50%);
1243
+ background: #1a1f36;
1244
+ color: white;
1245
+ padding: 4px 8px;
1246
+ border-radius: 4px;
1247
+ font-size: 12px;
1248
+ white-space: nowrap;
1249
+ margin-bottom: 6px;
1250
+ pointer-events: none;
1251
+ z-index: 100;
1252
+
1253
+ &::after {
1254
+ content: '';
1255
+ position: absolute;
1256
+ top: 100%;
1257
+ left: 50%;
1258
+ transform: translateX(-50%);
1259
+ border: 4px solid transparent;
1260
+ border-top-color: #1a1f36;
1261
+ }
1262
+ `,
1195
1263
  name: css3`
1196
1264
  font-size: ${fontSize.sm};
1197
1265
  font-weight: 500;
@@ -1387,9 +1455,17 @@ function StudioFileGrid() {
1387
1455
  ] });
1388
1456
  }
1389
1457
  function GridItem({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
1458
+ const [showCopied, setShowCopied] = useState2(false);
1390
1459
  const isFolder = item.type === "folder";
1391
1460
  const isImage = !isFolder && item.thumbnail !== void 0;
1392
1461
  const isImagesFolder = isFolder && (item.name === "images" || item.path.includes("/images/"));
1462
+ const handleCopyPath = (e) => {
1463
+ e.stopPropagation();
1464
+ const pathToCopy = "/" + item.path;
1465
+ navigator.clipboard.writeText(pathToCopy);
1466
+ setShowCopied(true);
1467
+ setTimeout(() => setShowCopied(false), 1500);
1468
+ };
1393
1469
  return /* @__PURE__ */ jsxs3(
1394
1470
  "div",
1395
1471
  {
@@ -1448,17 +1524,31 @@ function GridItem({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
1448
1524
  item.totalSize !== void 0 ? formatFileSize(item.totalSize) : ""
1449
1525
  ] }) : item.size !== void 0 && /* @__PURE__ */ jsx3("p", { css: styles3.size, children: formatFileSize(item.size) })
1450
1526
  ] }),
1451
- /* @__PURE__ */ jsx3(
1452
- "button",
1453
- {
1454
- css: styles3.openBtn,
1455
- onClick: (e) => {
1456
- e.stopPropagation();
1457
- onOpen();
1458
- },
1459
- children: "Open"
1460
- }
1461
- )
1527
+ /* @__PURE__ */ jsxs3("div", { css: styles3.buttonRow, children: [
1528
+ /* @__PURE__ */ jsxs3(
1529
+ "button",
1530
+ {
1531
+ css: styles3.copyBtn,
1532
+ onClick: handleCopyPath,
1533
+ title: "Copy file path",
1534
+ children: [
1535
+ showCopied && /* @__PURE__ */ jsx3("span", { css: styles3.tooltip, children: "Copied!" }),
1536
+ /* @__PURE__ */ jsx3("svg", { css: styles3.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx3("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" }) })
1537
+ ]
1538
+ }
1539
+ ),
1540
+ /* @__PURE__ */ jsx3(
1541
+ "button",
1542
+ {
1543
+ css: styles3.openBtn,
1544
+ onClick: (e) => {
1545
+ e.stopPropagation();
1546
+ onOpen();
1547
+ },
1548
+ children: "Open"
1549
+ }
1550
+ )
1551
+ ] })
1462
1552
  ] }) })
1463
1553
  ]
1464
1554
  }
@@ -1581,34 +1671,107 @@ var styles4 = {
1581
1671
  checkboxCell: css4`
1582
1672
  padding: 12px 16px;
1583
1673
  cursor: pointer;
1674
+ vertical-align: middle;
1584
1675
  `,
1585
1676
  checkbox: css4`
1586
1677
  width: 16px;
1587
1678
  height: 16px;
1588
1679
  accent-color: ${colors.primary};
1589
1680
  cursor: pointer;
1681
+ display: block;
1682
+ `,
1683
+ copyBtn: css4`
1684
+ position: relative;
1685
+ flex-shrink: 0;
1686
+ height: 28px;
1687
+ width: 28px;
1688
+ font-size: ${fontSize.xs};
1689
+ color: ${colors.textSecondary};
1690
+ background: ${colors.surface};
1691
+ border: 1px solid ${colors.border};
1692
+ padding: 0;
1693
+ cursor: pointer;
1694
+ border-radius: 4px;
1695
+ transition: all 0.15s ease;
1696
+ display: inline-flex;
1697
+ align-items: center;
1698
+ justify-content: center;
1699
+
1700
+ &:hover {
1701
+ background: ${colors.surfaceHover};
1702
+ border-color: ${colors.borderHover};
1703
+ color: ${colors.text};
1704
+ }
1705
+ `,
1706
+ copyIcon: css4`
1707
+ width: 14px;
1708
+ height: 14px;
1709
+ `,
1710
+ tooltip: css4`
1711
+ position: absolute;
1712
+ bottom: 100%;
1713
+ left: 50%;
1714
+ transform: translateX(-50%);
1715
+ background: #1a1f36;
1716
+ color: white;
1717
+ padding: 4px 8px;
1718
+ border-radius: 4px;
1719
+ font-size: 12px;
1720
+ white-space: nowrap;
1721
+ margin-bottom: 6px;
1722
+ pointer-events: none;
1723
+ z-index: 100;
1724
+
1725
+ &::after {
1726
+ content: '';
1727
+ position: absolute;
1728
+ top: 100%;
1729
+ left: 50%;
1730
+ transform: translateX(-50%);
1731
+ border: 4px solid transparent;
1732
+ border-top-color: #1a1f36;
1733
+ }
1590
1734
  `,
1591
1735
  nameCell: css4`
1592
1736
  display: flex;
1593
1737
  align-items: center;
1594
1738
  gap: 12px;
1595
1739
  `,
1740
+ thumbnailWrapper: css4`
1741
+ width: 48px;
1742
+ height: 36px;
1743
+ display: flex;
1744
+ align-items: center;
1745
+ justify-content: center;
1746
+ flex-shrink: 0;
1747
+ `,
1748
+ folderIconWrapper: css4`
1749
+ width: 48px;
1750
+ height: 36px;
1751
+ display: flex;
1752
+ align-items: center;
1753
+ justify-content: center;
1754
+ flex-shrink: 0;
1755
+ `,
1596
1756
  folderIcon: css4`
1597
- width: 20px;
1598
- height: 20px;
1757
+ width: 24px;
1758
+ height: 24px;
1599
1759
  color: #f5a623;
1600
- flex-shrink: 0;
1601
1760
  `,
1602
1761
  imagesFolderWrapper: css4`
1603
- position: relative;
1762
+ width: 48px;
1763
+ height: 36px;
1604
1764
  display: flex;
1605
1765
  align-items: center;
1766
+ justify-content: center;
1767
+ flex-shrink: 0;
1768
+ position: relative;
1769
+ align-items: center;
1606
1770
  `,
1607
1771
  imagesFolderIcon: css4`
1608
- width: 20px;
1609
- height: 20px;
1772
+ width: 24px;
1773
+ height: 24px;
1610
1774
  color: ${colors.imagesFolder};
1611
- flex-shrink: 0;
1612
1775
  `,
1613
1776
  lockIcon: css4`
1614
1777
  width: 10px;
@@ -1630,13 +1793,12 @@ var styles4 = {
1630
1793
  flex-shrink: 0;
1631
1794
  `,
1632
1795
  thumbnail: css4`
1633
- max-width: 48px;
1634
- max-height: 36px;
1796
+ max-width: 100%;
1797
+ max-height: 100%;
1635
1798
  width: auto;
1636
1799
  height: auto;
1637
1800
  object-fit: contain;
1638
1801
  border-radius: 4px;
1639
- flex-shrink: 0;
1640
1802
  border: 1px solid ${colors.borderLight};
1641
1803
  `,
1642
1804
  noThumbnail: css4`
@@ -1834,9 +1996,17 @@ function StudioFileList() {
1834
1996
  ] }) });
1835
1997
  }
1836
1998
  function ListRow({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
1999
+ const [showCopied, setShowCopied] = useState3(false);
1837
2000
  const isFolder = item.type === "folder";
1838
2001
  const isImage = !isFolder && item.thumbnail !== void 0;
1839
2002
  const isImagesFolder = isFolder && (item.name === "images" || item.path.includes("/images/"));
2003
+ const handleCopyPath = (e) => {
2004
+ e.stopPropagation();
2005
+ const pathToCopy = "/" + item.path;
2006
+ navigator.clipboard.writeText(pathToCopy);
2007
+ setShowCopied(true);
2008
+ setTimeout(() => setShowCopied(false), 1500);
2009
+ };
1840
2010
  return /* @__PURE__ */ jsxs4(
1841
2011
  "tr",
1842
2012
  {
@@ -1863,7 +2033,7 @@ function ListRow({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
1863
2033
  isFolder ? isImagesFolder ? /* @__PURE__ */ jsxs4("div", { css: styles4.imagesFolderWrapper, children: [
1864
2034
  /* @__PURE__ */ jsx4("svg", { css: styles4.imagesFolderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4("path", { d: "M10 4H4a2 2 0 00-2 2v12a2 2 0 002 2h16a2 2 0 002-2V8a2 2 0 00-2-2h-8l-2-2z" }) }),
1865
2035
  /* @__PURE__ */ jsx4("svg", { css: styles4.lockIcon, fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx4("path", { fillRule: "evenodd", d: "M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z", clipRule: "evenodd" }) })
1866
- ] }) : /* @__PURE__ */ jsx4("svg", { css: styles4.folderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4("path", { d: "M10 4H4a2 2 0 00-2 2v12a2 2 0 002 2h16a2 2 0 002-2V8a2 2 0 00-2-2h-8l-2-2z" }) }) : isImage && item.hasThumbnail ? /* @__PURE__ */ jsx4("img", { css: styles4.thumbnail, src: item.thumbnail, alt: item.name, loading: "lazy" }) : isImage && !item.hasThumbnail ? /* @__PURE__ */ jsx4(
2036
+ ] }) : /* @__PURE__ */ jsx4("div", { css: styles4.folderIconWrapper, children: /* @__PURE__ */ jsx4("svg", { css: styles4.folderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4("path", { d: "M10 4H4a2 2 0 00-2 2v12a2 2 0 002 2h16a2 2 0 002-2V8a2 2 0 00-2-2h-8l-2-2z" }) }) }) : isImage && item.hasThumbnail ? /* @__PURE__ */ jsx4("div", { css: styles4.thumbnailWrapper, children: /* @__PURE__ */ jsx4("img", { css: styles4.thumbnail, src: item.thumbnail, alt: item.name, loading: "lazy" }) }) : isImage && !item.hasThumbnail ? /* @__PURE__ */ jsx4("div", { css: styles4.thumbnailWrapper, children: /* @__PURE__ */ jsx4(
1867
2037
  "button",
1868
2038
  {
1869
2039
  css: styles4.noThumbnail,
@@ -1874,8 +2044,20 @@ function ListRow({ item, isSelected, onClick, onOpen, onGenerateThumbnail }) {
1874
2044
  title: "Generate thumbnail",
1875
2045
  children: /* @__PURE__ */ jsx4("svg", { css: styles4.noThumbnailIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, 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" }) })
1876
2046
  }
1877
- ) : /* @__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" }) }),
2047
+ ) }) : /* @__PURE__ */ jsx4("div", { css: styles4.thumbnailWrapper, children: /* @__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" }) }) }),
1878
2048
  /* @__PURE__ */ jsx4("span", { css: styles4.name, title: item.name, children: truncateMiddle2(item.name) }),
2049
+ /* @__PURE__ */ jsxs4(
2050
+ "button",
2051
+ {
2052
+ css: styles4.copyBtn,
2053
+ onClick: handleCopyPath,
2054
+ title: "Copy file path",
2055
+ children: [
2056
+ showCopied && /* @__PURE__ */ jsx4("span", { css: styles4.tooltip, children: "Copied!" }),
2057
+ /* @__PURE__ */ jsx4("svg", { css: styles4.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" }) })
2058
+ ]
2059
+ }
2060
+ ),
1879
2061
  /* @__PURE__ */ jsx4(
1880
2062
  "button",
1881
2063
  {
@@ -1963,10 +2145,16 @@ var styles5 = {
1963
2145
  background: ${colors.background};
1964
2146
  overflow: auto;
1965
2147
  `,
1966
- mainCloseBtn: css5`
2148
+ headerButtons: css5`
1967
2149
  position: absolute;
1968
2150
  top: 16px;
1969
2151
  right: 16px;
2152
+ display: flex;
2153
+ gap: 8px;
2154
+ z-index: 10;
2155
+ `,
2156
+ copyBtn: css5`
2157
+ position: relative;
1970
2158
  padding: 8px;
1971
2159
  background: ${colors.surface};
1972
2160
  border: 1px solid ${colors.border};
@@ -1976,7 +2164,6 @@ var styles5 = {
1976
2164
  display: flex;
1977
2165
  align-items: center;
1978
2166
  justify-content: center;
1979
- z-index: 10;
1980
2167
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
1981
2168
 
1982
2169
  &:hover {
@@ -1984,11 +2171,58 @@ var styles5 = {
1984
2171
  border-color: ${colors.borderHover};
1985
2172
  }
1986
2173
  `,
1987
- mainCloseIcon: css5`
2174
+ copyIcon: css5`
1988
2175
  width: 20px;
1989
2176
  height: 20px;
1990
2177
  color: ${colors.textSecondary};
1991
2178
  `,
2179
+ tooltip: css5`
2180
+ position: absolute;
2181
+ bottom: 100%;
2182
+ left: 50%;
2183
+ transform: translateX(-50%);
2184
+ background: #1a1f36;
2185
+ color: white;
2186
+ padding: 4px 8px;
2187
+ border-radius: 4px;
2188
+ font-size: 12px;
2189
+ white-space: nowrap;
2190
+ margin-bottom: 6px;
2191
+ pointer-events: none;
2192
+ z-index: 100;
2193
+
2194
+ &::after {
2195
+ content: '';
2196
+ position: absolute;
2197
+ top: 100%;
2198
+ left: 50%;
2199
+ transform: translateX(-50%);
2200
+ border: 4px solid transparent;
2201
+ border-top-color: #1a1f36;
2202
+ }
2203
+ `,
2204
+ mainCloseBtn: css5`
2205
+ padding: 8px;
2206
+ background: ${colors.danger};
2207
+ border: 1px solid ${colors.danger};
2208
+ border-radius: 8px;
2209
+ cursor: pointer;
2210
+ transition: all 0.15s ease;
2211
+ display: flex;
2212
+ align-items: center;
2213
+ justify-content: center;
2214
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
2215
+
2216
+ &:hover {
2217
+ background-color: ${colors.dangerHover};
2218
+ border-color: ${colors.dangerHover};
2219
+ }
2220
+ `,
2221
+ mainCloseIcon: css5`
2222
+ width: 20px;
2223
+ height: 20px;
2224
+ color: white;
2225
+ `,
1992
2226
  mediaWrapper: css5`
1993
2227
  max-width: 100%;
1994
2228
  max-height: 100%;
@@ -2129,6 +2363,7 @@ function StudioDetailView() {
2129
2363
  const { focusedItem, setFocusedItem, triggerRefresh, clearSelection } = useStudio();
2130
2364
  const [showDeleteConfirm, setShowDeleteConfirm] = useState4(false);
2131
2365
  const [alertMessage, setAlertMessage] = useState4(null);
2366
+ const [showCopied, setShowCopied] = useState4(false);
2132
2367
  if (!focusedItem) return null;
2133
2368
  const isImage = isImageFile(focusedItem.name);
2134
2369
  const isVideo = isVideoFile(focusedItem.name);
@@ -2136,6 +2371,12 @@ function StudioDetailView() {
2136
2371
  const handleClose = () => {
2137
2372
  setFocusedItem(null);
2138
2373
  };
2374
+ const handleCopyPath = () => {
2375
+ const pathToCopy = "/" + focusedItem.path;
2376
+ navigator.clipboard.writeText(pathToCopy);
2377
+ setShowCopied(true);
2378
+ setTimeout(() => setShowCopied(false), 1500);
2379
+ };
2139
2380
  const handleRename = () => {
2140
2381
  const newName = prompt("Enter new name:", focusedItem.name);
2141
2382
  if (newName && newName !== focusedItem.name) {
@@ -2209,7 +2450,13 @@ function StudioDetailView() {
2209
2450
  ),
2210
2451
  /* @__PURE__ */ jsx5("div", { css: styles5.overlay, onClick: handleClose, children: /* @__PURE__ */ jsxs5("div", { css: styles5.container, onClick: (e) => e.stopPropagation(), children: [
2211
2452
  /* @__PURE__ */ jsxs5("div", { css: styles5.main, children: [
2212
- /* @__PURE__ */ jsx5("button", { css: styles5.mainCloseBtn, onClick: handleClose, "aria-label": "Close", children: /* @__PURE__ */ jsx5("svg", { css: styles5.mainCloseIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) }),
2453
+ /* @__PURE__ */ jsxs5("div", { css: styles5.headerButtons, children: [
2454
+ /* @__PURE__ */ jsxs5("button", { css: styles5.copyBtn, onClick: handleCopyPath, title: "Copy file path", children: [
2455
+ showCopied && /* @__PURE__ */ jsx5("span", { css: styles5.tooltip, children: "Copied!" }),
2456
+ /* @__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: "M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" }) })
2457
+ ] }),
2458
+ /* @__PURE__ */ jsx5("button", { css: styles5.mainCloseBtn, onClick: handleClose, "aria-label": "Close", children: /* @__PURE__ */ jsx5("svg", { css: styles5.mainCloseIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })
2459
+ ] }),
2213
2460
  /* @__PURE__ */ jsx5("div", { css: styles5.mediaWrapper, children: renderMedia() })
2214
2461
  ] }),
2215
2462
  /* @__PURE__ */ jsxs5("div", { css: styles5.sidebar, children: [
@@ -2378,6 +2625,8 @@ var styles6 = {
2378
2625
  font-size: ${fontSize.xs};
2379
2626
  color: ${colors.textSecondary};
2380
2627
  border: 1px solid ${colors.border};
2628
+ overflow-x: auto;
2629
+ white-space: nowrap;
2381
2630
  `,
2382
2631
  copyBtn: css6`
2383
2632
  position: absolute;
@@ -2398,6 +2647,31 @@ var styles6 = {
2398
2647
  border-color: ${colors.borderHover};
2399
2648
  }
2400
2649
  `,
2650
+ tooltip: css6`
2651
+ position: absolute;
2652
+ bottom: 100%;
2653
+ left: 50%;
2654
+ transform: translateX(-50%);
2655
+ background: #1a1f36;
2656
+ color: white;
2657
+ padding: 4px 8px;
2658
+ border-radius: 4px;
2659
+ font-size: 12px;
2660
+ white-space: nowrap;
2661
+ margin-bottom: 6px;
2662
+ pointer-events: none;
2663
+ z-index: 100;
2664
+
2665
+ &::after {
2666
+ content: '';
2667
+ position: absolute;
2668
+ top: 100%;
2669
+ left: 50%;
2670
+ transform: translateX(-50%);
2671
+ border: 4px solid transparent;
2672
+ border-top-color: #1a1f36;
2673
+ }
2674
+ `,
2401
2675
  copyIcon: css6`
2402
2676
  width: 14px;
2403
2677
  height: 14px;
@@ -2528,7 +2802,10 @@ function SettingsPanel({ onClose }) {
2528
2802
  /* @__PURE__ */ jsx6("h3", { css: styles6.sectionTitle, children: "Cloudflare R2" }),
2529
2803
  /* @__PURE__ */ jsx6("p", { css: styles6.description, children: "Configure in .env.local file:" }),
2530
2804
  /* @__PURE__ */ jsxs6("div", { css: styles6.codeWrapper, children: [
2531
- /* @__PURE__ */ jsx6("button", { css: styles6.copyBtn, onClick: handleCopy, title: copied ? "Copied!" : "Copy to clipboard", children: copied ? /* @__PURE__ */ jsx6("svg", { css: styles6.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx6("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" }) }) : /* @__PURE__ */ jsx6("svg", { css: styles6.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx6("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" }) }) }),
2805
+ /* @__PURE__ */ jsxs6("button", { css: styles6.copyBtn, onClick: handleCopy, title: "Copy to clipboard", children: [
2806
+ copied && /* @__PURE__ */ jsx6("span", { css: styles6.tooltip, children: "Copied!" }),
2807
+ copied ? /* @__PURE__ */ jsx6("svg", { css: styles6.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx6("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" }) }) : /* @__PURE__ */ jsx6("svg", { css: styles6.copyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx6("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" }) })
2808
+ ] }),
2532
2809
  /* @__PURE__ */ jsxs6("div", { css: styles6.code, children: [
2533
2810
  /* @__PURE__ */ jsx6("p", { css: styles6.codeLine, children: "CLOUDFLARE_R2_ACCOUNT_ID=abc123def456ghi789" }),
2534
2811
  /* @__PURE__ */ jsx6("p", { css: styles6.codeLine, children: "CLOUDFLARE_R2_ACCESS_KEY_ID=your_access_key_id_here" }),
@@ -2538,11 +2815,6 @@ function SettingsPanel({ onClose }) {
2538
2815
  ] })
2539
2816
  ] })
2540
2817
  ] }),
2541
- /* @__PURE__ */ jsxs6("section", { children: [
2542
- /* @__PURE__ */ jsx6("h3", { css: styles6.sectionTitle, children: "Custom CDN URL" }),
2543
- /* @__PURE__ */ jsx6("p", { css: styles6.description, children: "Override the default R2 URL with a custom domain:" }),
2544
- /* @__PURE__ */ jsx6("input", { css: styles6.input, type: "text", placeholder: "https://cdn.yourdomain.com" })
2545
- ] }),
2546
2818
  /* @__PURE__ */ jsxs6("section", { children: [
2547
2819
  /* @__PURE__ */ jsx6("h3", { css: styles6.sectionTitle, children: "Thumbnail Sizes" }),
2548
2820
  /* @__PURE__ */ jsxs6("div", { css: styles6.grid, children: [
@@ -2864,4 +3136,4 @@ export {
2864
3136
  StudioUI,
2865
3137
  StudioUI_default as default
2866
3138
  };
2867
- //# sourceMappingURL=StudioUI-RHBJ6LVY.mjs.map
3139
+ //# sourceMappingURL=StudioUI-ENDN62RA.mjs.map