@gallop.software/studio 0.1.52 → 0.1.54

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.
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }"use client";
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }"use client";
2
2
 
3
3
 
4
4
 
@@ -7,7 +7,7 @@
7
7
  var _chunkUFCWGUAGjs = require('./chunk-UFCWGUAG.js');
8
8
 
9
9
  // src/components/StudioUI.tsx
10
- var _react = require('react');
10
+ var _react = require('react'); var _react2 = _interopRequireDefault(_react);
11
11
  var _react3 = require('@emotion/react');
12
12
 
13
13
  // src/components/StudioContext.tsx
@@ -65,6 +65,7 @@ function useStudio() {
65
65
 
66
66
  // src/components/StudioModal.tsx
67
67
 
68
+
68
69
  var _jsxruntime = require('@emotion/react/jsx-runtime');
69
70
  var fadeIn = _react3.keyframes`
70
71
  from { opacity: 0; }
@@ -195,6 +196,70 @@ function ConfirmModal({
195
196
  ] })
196
197
  ] }) });
197
198
  }
199
+ var inputStyles = {
200
+ input: _react3.css`
201
+ width: 100%;
202
+ padding: 10px 12px;
203
+ font-size: ${_chunkUFCWGUAGjs.fontSize.base};
204
+ border: 1px solid ${_chunkUFCWGUAGjs.colors.border};
205
+ border-radius: 6px;
206
+ background: ${_chunkUFCWGUAGjs.colors.surface};
207
+ color: ${_chunkUFCWGUAGjs.colors.text};
208
+ margin-top: 12px;
209
+ transition: all 0.15s ease;
210
+
211
+ &:focus {
212
+ outline: none;
213
+ border-color: ${_chunkUFCWGUAGjs.colors.primary};
214
+ box-shadow: 0 0 0 2px ${_chunkUFCWGUAGjs.colors.primaryLight};
215
+ }
216
+
217
+ &::placeholder {
218
+ color: ${_chunkUFCWGUAGjs.colors.textMuted};
219
+ }
220
+ `
221
+ };
222
+ function InputModal({
223
+ title,
224
+ message,
225
+ inputLabel,
226
+ defaultValue = "",
227
+ placeholder,
228
+ confirmLabel = "Confirm",
229
+ cancelLabel = "Cancel",
230
+ onConfirm,
231
+ onCancel
232
+ }) {
233
+ const [value, setValue] = _react2.default.useState(defaultValue);
234
+ const handleSubmit = (e) => {
235
+ e.preventDefault();
236
+ if (value.trim()) {
237
+ onConfirm(value.trim());
238
+ }
239
+ };
240
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles.overlay, onClick: onCancel, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles.modal, onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "form", { onSubmit: handleSubmit, children: [
241
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles.header, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles.title, children: title }) }),
242
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles.body, children: [
243
+ message && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles.message, children: message }),
244
+ inputLabel && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css: styles.message, children: inputLabel }),
245
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
246
+ "input",
247
+ {
248
+ css: inputStyles.input,
249
+ type: "text",
250
+ value,
251
+ onChange: (e) => setValue(e.target.value),
252
+ placeholder,
253
+ autoFocus: true
254
+ }
255
+ )
256
+ ] }),
257
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles.footer, children: [
258
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button", css: [styles.btn, styles.btnCancel], onClick: onCancel, children: cancelLabel }),
259
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "submit", css: [styles.btn, styles.btnConfirm], disabled: !value.trim(), children: confirmLabel })
260
+ ] })
261
+ ] }) }) });
262
+ }
198
263
  function AlertModal({
199
264
  title,
200
265
  message,
@@ -440,9 +505,14 @@ var styles2 = {
440
505
  border-radius: 6px;
441
506
  overflow: hidden;
442
507
  `,
508
+ searchWrapper: _react3.css`
509
+ position: relative;
510
+ display: flex;
511
+ align-items: center;
512
+ `,
443
513
  searchInput: _react3.css`
444
514
  height: ${btnHeight};
445
- padding: 0 12px;
515
+ padding: 0 32px 0 12px;
446
516
  border: 1px solid ${_chunkUFCWGUAGjs.colors.border};
447
517
  border-radius: 6px;
448
518
  font-size: ${_chunkUFCWGUAGjs.fontSize.base};
@@ -461,6 +531,27 @@ var styles2 = {
461
531
  color: ${_chunkUFCWGUAGjs.colors.textMuted};
462
532
  }
463
533
  `,
534
+ searchClearBtn: _react3.css`
535
+ position: absolute;
536
+ right: 8px;
537
+ top: 50%;
538
+ transform: translateY(-50%);
539
+ background: none;
540
+ border: none;
541
+ padding: 4px;
542
+ cursor: pointer;
543
+ color: ${_chunkUFCWGUAGjs.colors.textMuted};
544
+ display: flex;
545
+ align-items: center;
546
+ justify-content: center;
547
+ border-radius: 4px;
548
+ transition: all 0.15s ease;
549
+
550
+ &:hover {
551
+ color: ${_chunkUFCWGUAGjs.colors.text};
552
+ background: ${_chunkUFCWGUAGjs.colors.surfaceHover};
553
+ }
554
+ `,
464
555
  viewBtn: _react3.css`
465
556
  height: 100%;
466
557
  padding: 0 10px;
@@ -929,16 +1020,27 @@ function StudioToolbar() {
929
1020
  ]
930
1021
  }
931
1022
  ),
932
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
933
- "input",
934
- {
935
- css: styles2.searchInput,
936
- type: "text",
937
- placeholder: "Search images...",
938
- value: searchQuery,
939
- onChange: handleSearch
940
- }
941
- )
1023
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles2.searchWrapper, children: [
1024
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1025
+ "input",
1026
+ {
1027
+ css: styles2.searchInput,
1028
+ type: "text",
1029
+ placeholder: "Search images...",
1030
+ value: searchQuery,
1031
+ onChange: handleSearch
1032
+ }
1033
+ ),
1034
+ searchQuery && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1035
+ "button",
1036
+ {
1037
+ css: styles2.searchClearBtn,
1038
+ onClick: () => setSearchQuery(""),
1039
+ title: "Clear search",
1040
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { width: "14", height: "14", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
1041
+ }
1042
+ )
1043
+ ] })
942
1044
  ] }),
943
1045
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles2.right, children: [
944
1046
  hasSelection && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles2.selectionCount, children: [
@@ -1685,6 +1787,7 @@ var styles4 = {
1685
1787
  flex-shrink: 0;
1686
1788
  `,
1687
1789
  copyBtn: _react3.css`
1790
+ position: relative;
1688
1791
  flex-shrink: 0;
1689
1792
  height: 32px;
1690
1793
  width: 32px;
@@ -2364,6 +2467,9 @@ var styles5 = {
2364
2467
  function StudioDetailView() {
2365
2468
  const { focusedItem, setFocusedItem, triggerRefresh, clearSelection } = useStudio();
2366
2469
  const [showDeleteConfirm, setShowDeleteConfirm] = _react.useState.call(void 0, false);
2470
+ const [showRenameModal, setShowRenameModal] = _react.useState.call(void 0, false);
2471
+ const [showProcessConfirm, setShowProcessConfirm] = _react.useState.call(void 0, false);
2472
+ const [processProgress, setProcessProgress] = _react.useState.call(void 0, null);
2367
2473
  const [alertMessage, setAlertMessage] = _react.useState.call(void 0, null);
2368
2474
  const [showCopied, setShowCopied] = _react.useState.call(void 0, false);
2369
2475
  if (!focusedItem) return null;
@@ -2379,10 +2485,35 @@ function StudioDetailView() {
2379
2485
  setShowCopied(true);
2380
2486
  setTimeout(() => setShowCopied(false), 1500);
2381
2487
  };
2382
- const handleRename = () => {
2383
- const newName = prompt("Enter new name:", focusedItem.name);
2488
+ const handleRename = async (newName) => {
2489
+ setShowRenameModal(false);
2384
2490
  if (newName && newName !== focusedItem.name) {
2385
- console.log("Rename to:", newName);
2491
+ try {
2492
+ const response = await fetch("/api/studio/rename", {
2493
+ method: "POST",
2494
+ headers: { "Content-Type": "application/json" },
2495
+ body: JSON.stringify({
2496
+ oldPath: focusedItem.path,
2497
+ newName
2498
+ })
2499
+ });
2500
+ if (response.ok) {
2501
+ triggerRefresh();
2502
+ setFocusedItem(null);
2503
+ } else {
2504
+ const data = await response.json();
2505
+ setAlertMessage({
2506
+ title: "Rename Failed",
2507
+ message: data.error || "Failed to rename file"
2508
+ });
2509
+ }
2510
+ } catch (error) {
2511
+ console.error("Rename error:", error);
2512
+ setAlertMessage({
2513
+ title: "Rename Failed",
2514
+ message: "An error occurred while renaming the file"
2515
+ });
2516
+ }
2386
2517
  }
2387
2518
  };
2388
2519
  const handleDelete = async () => {
@@ -2415,8 +2546,59 @@ function StudioDetailView() {
2415
2546
  const handleSync = () => {
2416
2547
  console.log("Sync to CDN:", focusedItem.path);
2417
2548
  };
2418
- const handleRegenerate = () => {
2419
- console.log("Regenerate:", focusedItem.path);
2549
+ const handleProcessImage = async () => {
2550
+ setShowProcessConfirm(false);
2551
+ setProcessProgress({
2552
+ current: 0,
2553
+ total: 1,
2554
+ percent: 0,
2555
+ status: "processing",
2556
+ currentFile: focusedItem.name
2557
+ });
2558
+ try {
2559
+ const response = await fetch("/api/studio/reprocess", {
2560
+ method: "POST",
2561
+ headers: { "Content-Type": "application/json" },
2562
+ body: JSON.stringify({
2563
+ paths: [focusedItem.path]
2564
+ })
2565
+ });
2566
+ if (!response.ok) {
2567
+ throw new Error("Processing failed");
2568
+ }
2569
+ const reader = _optionalChain([response, 'access', _18 => _18.body, 'optionalAccess', _19 => _19.getReader, 'call', _20 => _20()]);
2570
+ if (!reader) {
2571
+ throw new Error("No response body");
2572
+ }
2573
+ const decoder = new TextDecoder();
2574
+ let buffer = "";
2575
+ while (true) {
2576
+ const { done, value } = await reader.read();
2577
+ if (done) break;
2578
+ buffer += decoder.decode(value, { stream: true });
2579
+ const lines = buffer.split("\n");
2580
+ buffer = lines.pop() || "";
2581
+ for (const line of lines) {
2582
+ if (line.startsWith("data: ")) {
2583
+ try {
2584
+ const data = JSON.parse(line.slice(6));
2585
+ setProcessProgress(data);
2586
+ } catch (e3) {
2587
+ }
2588
+ }
2589
+ }
2590
+ }
2591
+ triggerRefresh();
2592
+ } catch (error) {
2593
+ console.error("Process error:", error);
2594
+ setProcessProgress({
2595
+ current: 0,
2596
+ total: 1,
2597
+ percent: 0,
2598
+ status: "error",
2599
+ message: "Failed to process image"
2600
+ });
2601
+ }
2420
2602
  };
2421
2603
  const renderMedia = () => {
2422
2604
  if (isImage) {
@@ -2450,6 +2632,36 @@ function StudioDetailView() {
2450
2632
  onClose: () => setAlertMessage(null)
2451
2633
  }
2452
2634
  ),
2635
+ showRenameModal && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2636
+ InputModal,
2637
+ {
2638
+ title: "Rename File",
2639
+ message: "Enter a new name for the file:",
2640
+ defaultValue: focusedItem.name,
2641
+ placeholder: "Enter new filename",
2642
+ confirmLabel: "Rename",
2643
+ onConfirm: handleRename,
2644
+ onCancel: () => setShowRenameModal(false)
2645
+ }
2646
+ ),
2647
+ showProcessConfirm && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2648
+ ConfirmModal,
2649
+ {
2650
+ title: "Process Image",
2651
+ message: `Generate thumbnails for "${focusedItem.name}"?`,
2652
+ confirmLabel: "Process",
2653
+ onConfirm: handleProcessImage,
2654
+ onCancel: () => setShowProcessConfirm(false)
2655
+ }
2656
+ ),
2657
+ processProgress && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2658
+ ProgressModal,
2659
+ {
2660
+ title: "Processing Image",
2661
+ progress: processProgress,
2662
+ onClose: () => setProcessProgress(null)
2663
+ }
2664
+ ),
2453
2665
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.overlay, onClick: handleClose, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.container, onClick: (e) => e.stopPropagation(), children: [
2454
2666
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.main, children: [
2455
2667
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.headerButtons, children: [
@@ -2491,7 +2703,7 @@ function StudioDetailView() {
2491
2703
  ] })
2492
2704
  ] }),
2493
2705
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.actions, children: [
2494
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles5.actionBtn, onClick: handleRename, children: [
2706
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles5.actionBtn, onClick: () => setShowRenameModal(true), children: [
2495
2707
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.actionIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" }) }),
2496
2708
  "Rename"
2497
2709
  ] }),
@@ -2499,9 +2711,9 @@ function StudioDetailView() {
2499
2711
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.actionIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" }) }),
2500
2712
  "Sync to CDN"
2501
2713
  ] }),
2502
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles5.actionBtn, onClick: handleRegenerate, children: [
2503
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.actionIcon, 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 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" }) }),
2504
- "Regenerate"
2714
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: styles5.actionBtn, onClick: () => setShowProcessConfirm(true), children: [
2715
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.actionIcon, 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 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" }) }),
2716
+ "Process Image"
2505
2717
  ] }),
2506
2718
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: [styles5.actionBtn, styles5.actionBtnDanger], onClick: () => setShowDeleteConfirm(true), children: [
2507
2719
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.actionIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" }) }),
@@ -3138,4 +3350,4 @@ var StudioUI_default = StudioUI;
3138
3350
 
3139
3351
 
3140
3352
  exports.StudioUI = StudioUI; exports.default = StudioUI_default;
3141
- //# sourceMappingURL=StudioUI-5SYZCU5P.js.map
3353
+ //# sourceMappingURL=StudioUI-22FP5AJL.js.map