@gallop.software/studio 0.1.7 → 0.1.9

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.
@@ -50,8 +50,147 @@ function useStudio() {
50
50
  // src/components/StudioToolbar.tsx
51
51
 
52
52
 
53
+
54
+ // src/components/StudioModal.tsx
55
+
53
56
  var _jsxruntime = require('@emotion/react/jsx-runtime');
57
+ var fadeIn = _react3.keyframes`
58
+ from { opacity: 0; }
59
+ to { opacity: 1; }
60
+ `;
61
+ var slideIn = _react3.keyframes`
62
+ from {
63
+ opacity: 0;
64
+ transform: scale(0.95);
65
+ }
66
+ to {
67
+ opacity: 1;
68
+ transform: scale(1);
69
+ }
70
+ `;
54
71
  var styles = {
72
+ overlay: _react3.css`
73
+ position: fixed;
74
+ inset: 0;
75
+ background-color: rgba(0, 0, 0, 0.5);
76
+ display: flex;
77
+ align-items: center;
78
+ justify-content: center;
79
+ z-index: 10000;
80
+ animation: ${fadeIn} 0.15s ease-out;
81
+ `,
82
+ modal: _react3.css`
83
+ background-color: white;
84
+ border-radius: 12px;
85
+ box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
86
+ max-width: 400px;
87
+ width: 90%;
88
+ animation: ${slideIn} 0.15s ease-out;
89
+ `,
90
+ header: _react3.css`
91
+ padding: 20px 24px 0;
92
+ `,
93
+ title: _react3.css`
94
+ font-size: 18px;
95
+ font-weight: 600;
96
+ color: #111827;
97
+ margin: 0;
98
+ `,
99
+ body: _react3.css`
100
+ padding: 12px 24px 24px;
101
+ `,
102
+ message: _react3.css`
103
+ font-size: 14px;
104
+ color: #6b7280;
105
+ margin: 0;
106
+ line-height: 1.5;
107
+ `,
108
+ footer: _react3.css`
109
+ display: flex;
110
+ justify-content: flex-end;
111
+ gap: 12px;
112
+ padding: 16px 24px;
113
+ border-top: 1px solid #e5e7eb;
114
+ background-color: #f9fafb;
115
+ border-radius: 0 0 12px 12px;
116
+ `,
117
+ btn: _react3.css`
118
+ padding: 8px 16px;
119
+ font-size: 14px;
120
+ font-weight: 500;
121
+ border-radius: 8px;
122
+ cursor: pointer;
123
+ transition: all 0.15s;
124
+ `,
125
+ btnCancel: _react3.css`
126
+ background-color: white;
127
+ border: 1px solid #d1d5db;
128
+ color: #374151;
129
+
130
+ &:hover {
131
+ background-color: #f9fafb;
132
+ }
133
+ `,
134
+ btnConfirm: _react3.css`
135
+ background-color: #9333ea;
136
+ border: 1px solid #9333ea;
137
+ color: white;
138
+
139
+ &:hover {
140
+ background-color: #7c3aed;
141
+ }
142
+ `,
143
+ btnDanger: _react3.css`
144
+ background-color: #dc2626;
145
+ border: 1px solid #dc2626;
146
+ color: white;
147
+
148
+ &:hover {
149
+ background-color: #b91c1c;
150
+ }
151
+ `
152
+ };
153
+ function ConfirmModal({
154
+ title,
155
+ message,
156
+ confirmLabel = "Confirm",
157
+ cancelLabel = "Cancel",
158
+ variant = "default",
159
+ onConfirm,
160
+ onCancel
161
+ }) {
162
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles.overlay, onClick: onCancel, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles.modal, onClick: (e) => e.stopPropagation(), children: [
163
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles.header, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles.title, children: title }) }),
164
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles.body, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles.message, children: message }) }),
165
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles.footer, children: [
166
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: [styles.btn, styles.btnCancel], onClick: onCancel, children: cancelLabel }),
167
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
168
+ "button",
169
+ {
170
+ css: [styles.btn, variant === "danger" ? styles.btnDanger : styles.btnConfirm],
171
+ onClick: onConfirm,
172
+ children: confirmLabel
173
+ }
174
+ )
175
+ ] })
176
+ ] }) });
177
+ }
178
+ function AlertModal({
179
+ title,
180
+ message,
181
+ buttonLabel = "OK",
182
+ onClose
183
+ }) {
184
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles.overlay, onClick: onClose, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles.modal, onClick: (e) => e.stopPropagation(), children: [
185
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles.header, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles.title, children: title }) }),
186
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles.body, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles.message, children: message }) }),
187
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles.footer, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: [styles.btn, styles.btnConfirm], onClick: onClose, children: buttonLabel }) })
188
+ ] }) });
189
+ }
190
+
191
+ // src/components/StudioToolbar.tsx
192
+
193
+ var styles2 = {
55
194
  toolbar: _react3.css`
56
195
  display: flex;
57
196
  align-items: center;
@@ -151,6 +290,8 @@ function StudioToolbar() {
151
290
  const { selectedItems, viewMode, setViewMode, clearSelection, currentPath, triggerRefresh } = useStudio();
152
291
  const fileInputRef = _react.useRef.call(void 0, null);
153
292
  const [uploading, setUploading] = _react.useState.call(void 0, false);
293
+ const [showDeleteConfirm, setShowDeleteConfirm] = _react.useState.call(void 0, false);
294
+ const [alertMessage, setAlertMessage] = _react.useState.call(void 0, null);
154
295
  const handleUpload = _react.useCallback.call(void 0, () => {
155
296
  _optionalChain([fileInputRef, 'access', _ => _.current, 'optionalAccess', _2 => _2.click, 'call', _3 => _3()]);
156
297
  }, []);
@@ -170,13 +311,19 @@ function StudioToolbar() {
170
311
  if (!response.ok) {
171
312
  const error = await response.json();
172
313
  console.error("Upload failed:", error);
173
- alert(`Failed to upload ${file.name}: ${error.error || "Unknown error"}`);
314
+ setAlertMessage({
315
+ title: "Upload Failed",
316
+ message: `Failed to upload ${file.name}: ${error.error || "Unknown error"}`
317
+ });
174
318
  }
175
319
  }
176
320
  triggerRefresh();
177
321
  } catch (error) {
178
322
  console.error("Upload error:", error);
179
- alert("Upload failed. Check console for details.");
323
+ setAlertMessage({
324
+ title: "Upload Failed",
325
+ message: "Upload failed. Check console for details."
326
+ });
180
327
  } finally {
181
328
  setUploading(false);
182
329
  if (fileInputRef.current) {
@@ -187,9 +334,12 @@ function StudioToolbar() {
187
334
  const handleReprocess = _react.useCallback.call(void 0, () => {
188
335
  console.log("Reprocess clicked", selectedItems);
189
336
  }, [selectedItems]);
190
- const handleDelete = _react.useCallback.call(void 0, async () => {
337
+ const handleDeleteClick = _react.useCallback.call(void 0, () => {
191
338
  if (selectedItems.size === 0) return;
192
- if (!confirm(`Delete ${selectedItems.size} item(s)?`)) return;
339
+ setShowDeleteConfirm(true);
340
+ }, [selectedItems]);
341
+ const handleDeleteConfirm = _react.useCallback.call(void 0, async () => {
342
+ setShowDeleteConfirm(false);
193
343
  try {
194
344
  const response = await fetch("/api/studio/delete", {
195
345
  method: "POST",
@@ -201,11 +351,17 @@ function StudioToolbar() {
201
351
  triggerRefresh();
202
352
  } else {
203
353
  const error = await response.json();
204
- alert(`Delete failed: ${error.error || "Unknown error"}`);
354
+ setAlertMessage({
355
+ title: "Delete Failed",
356
+ message: error.error || "Unknown error"
357
+ });
205
358
  }
206
359
  } catch (error) {
207
360
  console.error("Delete error:", error);
208
- alert("Delete failed. Check console for details.");
361
+ setAlertMessage({
362
+ title: "Delete Failed",
363
+ message: "Delete failed. Check console for details."
364
+ });
209
365
  }
210
366
  }, [selectedItems, clearSelection, triggerRefresh]);
211
367
  const handleSyncCdn = _react.useCallback.call(void 0, () => {
@@ -215,83 +371,104 @@ function StudioToolbar() {
215
371
  console.log("Scan clicked");
216
372
  }, []);
217
373
  const hasSelection = selectedItems.size > 0;
218
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles.toolbar, children: [
219
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
220
- "input",
374
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
375
+ showDeleteConfirm && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
376
+ ConfirmModal,
221
377
  {
222
- ref: fileInputRef,
223
- type: "file",
224
- multiple: true,
225
- accept: "image/*",
226
- onChange: handleFileChange,
227
- style: { display: "none" }
378
+ title: "Delete Items",
379
+ message: `Are you sure you want to delete ${selectedItems.size} item(s)? This action cannot be undone.`,
380
+ confirmLabel: "Delete",
381
+ variant: "danger",
382
+ onConfirm: handleDeleteConfirm,
383
+ onCancel: () => setShowDeleteConfirm(false)
228
384
  }
229
385
  ),
230
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles.left, children: [
231
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
232
- ToolbarButton,
233
- {
234
- onClick: handleUpload,
235
- icon: "upload",
236
- label: uploading ? "Uploading..." : "Upload",
237
- disabled: uploading
238
- }
239
- ),
240
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
241
- ToolbarButton,
242
- {
243
- onClick: handleReprocess,
244
- icon: "refresh",
245
- label: "Reprocess",
246
- disabled: !hasSelection
247
- }
248
- ),
249
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
250
- ToolbarButton,
251
- {
252
- onClick: handleDelete,
253
- icon: "trash",
254
- label: "Delete",
255
- disabled: !hasSelection,
256
- variant: "danger"
257
- }
258
- ),
386
+ alertMessage && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
387
+ AlertModal,
388
+ {
389
+ title: alertMessage.title,
390
+ message: alertMessage.message,
391
+ onClose: () => setAlertMessage(null)
392
+ }
393
+ ),
394
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles2.toolbar, children: [
259
395
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
260
- ToolbarButton,
396
+ "input",
261
397
  {
262
- onClick: handleSyncCdn,
263
- icon: "cloud",
264
- label: "Sync CDN",
265
- disabled: !hasSelection
398
+ ref: fileInputRef,
399
+ type: "file",
400
+ multiple: true,
401
+ accept: "image/*",
402
+ onChange: handleFileChange,
403
+ style: { display: "none" }
266
404
  }
267
405
  ),
268
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ToolbarButton, { onClick: handleScan, icon: "scan", label: "Scan" })
269
- ] }),
270
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles.right, children: [
271
- hasSelection && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles.selectionCount, children: [
272
- selectedItems.size,
273
- " selected",
274
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles.clearBtn, onClick: clearSelection, children: "Clear" })
275
- ] }),
276
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles.viewToggle, children: [
406
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles2.left, children: [
277
407
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
278
- "button",
408
+ ToolbarButton,
279
409
  {
280
- css: [styles.viewBtn, viewMode === "grid" && styles.viewBtnActive],
281
- onClick: () => setViewMode("grid"),
282
- "aria-label": "Grid view",
283
- children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, GridIcon, {})
410
+ onClick: handleUpload,
411
+ icon: "upload",
412
+ label: uploading ? "Uploading..." : "Upload",
413
+ disabled: uploading
284
414
  }
285
415
  ),
286
416
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
287
- "button",
417
+ ToolbarButton,
288
418
  {
289
- css: [styles.viewBtn, viewMode === "list" && styles.viewBtnActive],
290
- onClick: () => setViewMode("list"),
291
- "aria-label": "List view",
292
- children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ListIcon, {})
419
+ onClick: handleReprocess,
420
+ icon: "refresh",
421
+ label: "Reprocess",
422
+ disabled: !hasSelection
293
423
  }
294
- )
424
+ ),
425
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
426
+ ToolbarButton,
427
+ {
428
+ onClick: handleDeleteClick,
429
+ icon: "trash",
430
+ label: "Delete",
431
+ disabled: !hasSelection,
432
+ variant: "danger"
433
+ }
434
+ ),
435
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
436
+ ToolbarButton,
437
+ {
438
+ onClick: handleSyncCdn,
439
+ icon: "cloud",
440
+ label: "Sync CDN",
441
+ disabled: !hasSelection
442
+ }
443
+ ),
444
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ToolbarButton, { onClick: handleScan, icon: "scan", label: "Scan" })
445
+ ] }),
446
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles2.right, children: [
447
+ hasSelection && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles2.selectionCount, children: [
448
+ selectedItems.size,
449
+ " selected",
450
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles2.clearBtn, onClick: clearSelection, children: "Clear" })
451
+ ] }),
452
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles2.viewToggle, children: [
453
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
454
+ "button",
455
+ {
456
+ css: [styles2.viewBtn, viewMode === "grid" && styles2.viewBtnActive],
457
+ onClick: () => setViewMode("grid"),
458
+ "aria-label": "Grid view",
459
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, GridIcon, {})
460
+ }
461
+ ),
462
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
463
+ "button",
464
+ {
465
+ css: [styles2.viewBtn, viewMode === "list" && styles2.viewBtnActive],
466
+ onClick: () => setViewMode("list"),
467
+ "aria-label": "List view",
468
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ListIcon, {})
469
+ }
470
+ )
471
+ ] })
295
472
  ] })
296
473
  ] })
297
474
  ] });
@@ -306,7 +483,7 @@ function ToolbarButton({
306
483
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
307
484
  "button",
308
485
  {
309
- css: [styles.btn, variant === "danger" ? styles.btnDanger : styles.btnDefault],
486
+ css: [styles2.btn, variant === "danger" ? styles2.btnDanger : styles2.btnDefault],
310
487
  onClick,
311
488
  disabled,
312
489
  children: [
@@ -319,30 +496,30 @@ function ToolbarButton({
319
496
  function IconComponent({ icon }) {
320
497
  switch (icon) {
321
498
  case "upload":
322
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles.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: "M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" }) });
499
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles2.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: "M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" }) });
323
500
  case "refresh":
324
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles.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: "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" }) });
501
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles2.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: "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" }) });
325
502
  case "trash":
326
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles.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: "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" }) });
503
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles2.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: "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" }) });
327
504
  case "cloud":
328
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles.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: "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" }) });
505
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles2.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: "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" }) });
329
506
  case "scan":
330
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles.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: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) });
507
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles2.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: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) });
331
508
  default:
332
509
  return null;
333
510
  }
334
511
  }
335
512
  function GridIcon() {
336
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles.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: "M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z" }) });
513
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles2.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: "M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z" }) });
337
514
  }
338
515
  function ListIcon() {
339
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles.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: "M4 6h16M4 10h16M4 14h16M4 18h16" }) });
516
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles2.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: "M4 6h16M4 10h16M4 14h16M4 18h16" }) });
340
517
  }
341
518
 
342
519
  // src/components/StudioBreadcrumb.tsx
343
520
 
344
521
 
345
- var styles2 = {
522
+ var styles3 = {
346
523
  container: _react3.css`
347
524
  display: flex;
348
525
  align-items: center;
@@ -413,14 +590,14 @@ function StudioBreadcrumb() {
413
590
  const newPath = parts.slice(0, index + 1).join("/");
414
591
  setCurrentPath(newPath);
415
592
  };
416
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles2.container, children: [
417
- currentPath !== "public" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles2.backBtn, onClick: navigateUp, "aria-label": "Go back", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles2.backIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) }) }),
418
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "nav", { css: styles2.nav, children: parts.map((part, index) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles2.item, children: [
419
- index > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles2.separator, children: "/" }),
593
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.container, children: [
594
+ currentPath !== "public" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles3.backBtn, onClick: navigateUp, "aria-label": "Go back", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles3.backIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) }) }),
595
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "nav", { css: styles3.nav, children: parts.map((part, index) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles3.item, children: [
596
+ index > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.separator, children: "/" }),
420
597
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
421
598
  "button",
422
599
  {
423
- css: [styles2.btn, index === parts.length - 1 ? styles2.btnActive : styles2.btnInactive],
600
+ css: [styles3.btn, index === parts.length - 1 ? styles3.btnActive : styles3.btnInactive],
424
601
  onClick: () => handleClick(index),
425
602
  children: part
426
603
  }
@@ -436,7 +613,7 @@ function StudioBreadcrumb() {
436
613
  var spin = _react3.keyframes`
437
614
  to { transform: rotate(360deg); }
438
615
  `;
439
- var styles3 = {
616
+ var styles4 = {
440
617
  loading: _react3.css`
441
618
  display: flex;
442
619
  align-items: center;
@@ -494,6 +671,10 @@ var styles3 = {
494
671
  itemSelected: _react3.css`
495
672
  border-color: #a855f7;
496
673
  background-color: #faf5ff;
674
+
675
+ &:hover {
676
+ border-color: #a855f7;
677
+ }
497
678
  `,
498
679
  checkbox: _react3.css`
499
680
  position: absolute;
@@ -597,13 +778,13 @@ function StudioFileGrid() {
597
778
  loadItems();
598
779
  }, [currentPath, refreshKey]);
599
780
  if (loading) {
600
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles3.loading, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles3.spinner }) });
781
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles4.loading, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles4.spinner }) });
601
782
  }
602
783
  if (items.length === 0) {
603
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.empty, children: [
604
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles3.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" }) }),
605
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles3.emptyText, children: "No files in this folder" }),
606
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles3.emptyText, children: "Upload images to get started" })
784
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.empty, children: [
785
+ /* @__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" }) }),
786
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles4.emptyText, children: "No files in this folder" }),
787
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles4.emptyText, children: "Upload images to get started" })
607
788
  ] });
608
789
  }
609
790
  const sortedItems = [...items].sort((a, b) => {
@@ -633,12 +814,12 @@ function StudioFileGrid() {
633
814
  }
634
815
  };
635
816
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
636
- files.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles3.selectAllRow, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "label", { css: styles3.selectAllLabel, children: [
817
+ files.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles4.selectAllRow, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "label", { css: styles4.selectAllLabel, children: [
637
818
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
638
819
  "input",
639
820
  {
640
821
  type: "checkbox",
641
- css: styles3.selectAllCheckbox,
822
+ css: styles4.selectAllCheckbox,
642
823
  checked: allFilesSelected,
643
824
  ref: (el) => {
644
825
  if (el) el.indeterminate = someFilesSelected && !allFilesSelected;
@@ -650,7 +831,7 @@ function StudioFileGrid() {
650
831
  files.length,
651
832
  ")"
652
833
  ] }) }),
653
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles3.grid, children: sortedItems.map((item) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
834
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles4.grid, children: sortedItems.map((item) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
654
835
  GridItem,
655
836
  {
656
837
  item,
@@ -663,31 +844,31 @@ function StudioFileGrid() {
663
844
  }
664
845
  function GridItem({ item, isSelected, onClick }) {
665
846
  const isFolder = item.type === "folder";
666
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: [styles3.item, isSelected && styles3.itemSelected], onClick, children: [
847
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: [styles4.item, isSelected && styles4.itemSelected], onClick, children: [
667
848
  !isFolder && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
668
849
  "input",
669
850
  {
670
851
  type: "checkbox",
671
- css: styles3.checkbox,
852
+ css: styles4.checkbox,
672
853
  checked: isSelected,
673
854
  onChange: () => {
674
855
  },
675
856
  onClick: (e) => e.stopPropagation()
676
857
  }
677
858
  ),
678
- item.cdnSynced && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles3.cdnBadge, children: "CDN" }),
679
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles3.content, children: isFolder ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles3.folderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "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" }) }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
859
+ item.cdnSynced && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles4.cdnBadge, children: "CDN" }),
860
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles4.content, children: isFolder ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.folderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "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" }) }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
680
861
  "img",
681
862
  {
682
- css: styles3.image,
863
+ css: styles4.image,
683
864
  src: item.path.replace("public", ""),
684
865
  alt: item.name,
685
866
  loading: "lazy"
686
867
  }
687
868
  ) }),
688
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles3.label, children: [
689
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles3.name, title: item.name, children: item.name }),
690
- item.size && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles3.size, children: formatFileSize(item.size) })
869
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.label, children: [
870
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles4.name, title: item.name, children: item.name }),
871
+ item.size && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles4.size, children: formatFileSize(item.size) })
691
872
  ] })
692
873
  ] });
693
874
  }
@@ -704,7 +885,7 @@ function formatFileSize(bytes) {
704
885
  var spin2 = _react3.keyframes`
705
886
  to { transform: rotate(360deg); }
706
887
  `;
707
- var styles4 = {
888
+ var styles5 = {
708
889
  loading: _react3.css`
709
890
  display: flex;
710
891
  align-items: center;
@@ -765,6 +946,10 @@ var styles4 = {
765
946
  `,
766
947
  rowSelected: _react3.css`
767
948
  background-color: #faf5ff;
949
+
950
+ &:hover {
951
+ background-color: #faf5ff;
952
+ }
768
953
  `,
769
954
  td: _react3.css`
770
955
  padding: 8px 0;
@@ -835,10 +1020,10 @@ function StudioFileList() {
835
1020
  loadItems();
836
1021
  }, [currentPath, refreshKey]);
837
1022
  if (loading) {
838
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles4.loading, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles4.spinner }) });
1023
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.loading, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.spinner }) });
839
1024
  }
840
1025
  if (items.length === 0) {
841
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles4.empty, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { children: "No files in this folder" }) });
1026
+ 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" }) });
842
1027
  }
843
1028
  const sortedItems = [...items].sort((a, b) => {
844
1029
  if (a.type === "folder" && b.type !== "folder") return -1;
@@ -866,13 +1051,13 @@ function StudioFileList() {
866
1051
  toggleSelection(item.path);
867
1052
  }
868
1053
  };
869
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "table", { css: styles4.table, children: [
1054
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "table", { css: styles5.table, children: [
870
1055
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "thead", { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tr", { children: [
871
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles4.th, styles4.thCheckbox], children: files.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1056
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles5.th, styles5.thCheckbox], children: files.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
872
1057
  "input",
873
1058
  {
874
1059
  type: "checkbox",
875
- css: styles4.checkbox,
1060
+ css: styles5.checkbox,
876
1061
  checked: allFilesSelected,
877
1062
  ref: (el) => {
878
1063
  if (el) el.indeterminate = someFilesSelected && !allFilesSelected;
@@ -880,12 +1065,12 @@ function StudioFileList() {
880
1065
  onChange: handleSelectAll
881
1066
  }
882
1067
  ) }),
883
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: styles4.th, children: "Name" }),
884
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles4.th, styles4.thSize], children: "Size" }),
885
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles4.th, styles4.thDimensions], children: "Dimensions" }),
886
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles4.th, styles4.thCdn], children: "CDN" })
1068
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: styles5.th, children: "Name" }),
1069
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles5.th, styles5.thSize], children: "Size" }),
1070
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles5.th, styles5.thDimensions], children: "Dimensions" }),
1071
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { css: [styles5.th, styles5.thCdn], children: "CDN" })
887
1072
  ] }) }),
888
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "tbody", { css: styles4.tbody, children: sortedItems.map((item) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1073
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "tbody", { css: styles5.tbody, children: sortedItems.map((item) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
889
1074
  ListRow,
890
1075
  {
891
1076
  item,
@@ -898,28 +1083,28 @@ function StudioFileList() {
898
1083
  }
899
1084
  function ListRow({ item, isSelected, onClick }) {
900
1085
  const isFolder = item.type === "folder";
901
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tr", { css: [styles4.row, isSelected && styles4.rowSelected], onClick, children: [
902
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles4.td, children: !isFolder && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1086
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tr", { css: [styles5.row, isSelected && styles5.rowSelected], onClick, children: [
1087
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles5.td, children: !isFolder && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
903
1088
  "input",
904
1089
  {
905
1090
  type: "checkbox",
906
- css: styles4.checkbox,
1091
+ css: styles5.checkbox,
907
1092
  checked: isSelected,
908
1093
  onChange: () => {
909
1094
  },
910
1095
  onClick: (e) => e.stopPropagation()
911
1096
  }
912
1097
  ) }),
913
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles4.td, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles4.nameCell, children: [
914
- isFolder ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.folderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "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" }) }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.fileIcon, 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" }) }),
915
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles4.name, children: item.name })
1098
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles5.td, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.nameCell, children: [
1099
+ isFolder ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.folderIcon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "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" }) }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.fileIcon, 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" }) }),
1100
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles5.name, children: item.name })
916
1101
  ] }) }),
917
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles4.td, styles4.meta], children: item.size ? formatFileSize2(item.size) : "--" }),
918
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles4.td, styles4.meta], children: item.dimensions ? `${item.dimensions.width}x${item.dimensions.height}` : "--" }),
919
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles4.td, children: item.cdnSynced ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles4.cdnBadge, children: [
920
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles4.cdnIcon, fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }),
1102
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles5.td, styles5.meta], children: item.size ? formatFileSize2(item.size) : "--" }),
1103
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: [styles5.td, styles5.meta], children: item.dimensions ? `${item.dimensions.width}x${item.dimensions.height}` : "--" }),
1104
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { css: styles5.td, children: item.cdnSynced ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { css: styles5.cdnBadge, children: [
1105
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.cdnIcon, fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }),
921
1106
  "Synced"
922
- ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles4.cdnEmpty, children: "--" }) })
1107
+ ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles5.cdnEmpty, children: "--" }) })
923
1108
  ] });
924
1109
  }
925
1110
  function formatFileSize2(bytes) {
@@ -931,7 +1116,8 @@ function formatFileSize2(bytes) {
931
1116
  // src/components/StudioPreview.tsx
932
1117
 
933
1118
 
934
- var styles5 = {
1119
+
1120
+ var styles6 = {
935
1121
  panel: _react3.css`
936
1122
  width: 320px;
937
1123
  border-left: 1px solid #e5e7eb;
@@ -1062,9 +1248,14 @@ var styles5 = {
1062
1248
  };
1063
1249
  function StudioPreview() {
1064
1250
  const { selectedItems, meta, triggerRefresh, clearSelection } = useStudio();
1065
- const handleDelete = async () => {
1251
+ const [showDeleteConfirm, setShowDeleteConfirm] = _react.useState.call(void 0, false);
1252
+ const [alertMessage, setAlertMessage] = _react.useState.call(void 0, null);
1253
+ const handleDeleteClick = () => {
1066
1254
  if (selectedItems.size === 0) return;
1067
- if (!confirm(`Delete ${selectedItems.size} item(s)?`)) return;
1255
+ setShowDeleteConfirm(true);
1256
+ };
1257
+ const handleDeleteConfirm = async () => {
1258
+ setShowDeleteConfirm(false);
1068
1259
  try {
1069
1260
  const response = await fetch("/api/studio/delete", {
1070
1261
  method: "POST",
@@ -1076,106 +1267,142 @@ function StudioPreview() {
1076
1267
  triggerRefresh();
1077
1268
  } else {
1078
1269
  const error = await response.json();
1079
- alert(`Delete failed: ${error.error || "Unknown error"}`);
1270
+ setAlertMessage({
1271
+ title: "Delete Failed",
1272
+ message: error.error || "Unknown error"
1273
+ });
1080
1274
  }
1081
1275
  } catch (error) {
1082
1276
  console.error("Delete error:", error);
1083
- alert("Delete failed. Check console for details.");
1277
+ setAlertMessage({
1278
+ title: "Delete Failed",
1279
+ message: "Delete failed. Check console for details."
1280
+ });
1084
1281
  }
1085
1282
  };
1283
+ const modals = /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1284
+ showDeleteConfirm && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1285
+ ConfirmModal,
1286
+ {
1287
+ title: "Delete Items",
1288
+ message: `Are you sure you want to delete ${selectedItems.size} item(s)? This action cannot be undone.`,
1289
+ confirmLabel: "Delete",
1290
+ variant: "danger",
1291
+ onConfirm: handleDeleteConfirm,
1292
+ onCancel: () => setShowDeleteConfirm(false)
1293
+ }
1294
+ ),
1295
+ alertMessage && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1296
+ AlertModal,
1297
+ {
1298
+ title: alertMessage.title,
1299
+ message: alertMessage.message,
1300
+ onClose: () => setAlertMessage(null)
1301
+ }
1302
+ )
1303
+ ] });
1086
1304
  if (selectedItems.size === 0) {
1087
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.panel, children: [
1088
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles5.title, children: "Preview" }),
1089
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.emptyState, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.emptyText, children: "Select an image to preview" }) })
1305
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1306
+ modals,
1307
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.panel, children: [
1308
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles6.title, children: "Preview" }),
1309
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.emptyState, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.emptyText, children: "Select an image to preview" }) })
1310
+ ] })
1090
1311
  ] });
1091
1312
  }
1092
1313
  if (selectedItems.size > 1) {
1093
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.panel, children: [
1094
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "h3", { css: styles5.title, children: [
1095
- selectedItems.size,
1096
- " items selected"
1097
- ] }),
1098
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.actions, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: [styles5.actionBtn, styles5.actionBtnDanger], onClick: handleDelete, children: [
1099
- "Delete ",
1100
- selectedItems.size,
1101
- " items"
1102
- ] }) })
1314
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1315
+ modals,
1316
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.panel, children: [
1317
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "h3", { css: styles6.title, children: [
1318
+ selectedItems.size,
1319
+ " items selected"
1320
+ ] }),
1321
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.actions, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "button", { css: [styles6.actionBtn, styles6.actionBtnDanger], onClick: handleDeleteClick, children: [
1322
+ "Delete ",
1323
+ selectedItems.size,
1324
+ " items"
1325
+ ] }) })
1326
+ ] })
1103
1327
  ] });
1104
1328
  }
1105
1329
  const selectedPath = Array.from(selectedItems)[0];
1106
1330
  const imageKey = selectedPath.replace(/^public\/images\//, "").replace(/^public\/originals\//, "");
1107
1331
  const imageData = _optionalChain([meta, 'optionalAccess', _4 => _4.images, 'optionalAccess', _5 => _5[imageKey]]);
1108
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.panel, children: [
1109
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles5.title, children: "Preview" }),
1110
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles5.imageContainer, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1111
- "img",
1112
- {
1113
- css: styles5.image,
1114
- src: selectedPath.replace("public", ""),
1115
- alt: "Preview"
1116
- }
1117
- ) }),
1118
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.info, children: [
1119
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, InfoRow, { label: "Filename", value: selectedPath.split("/").pop() || "" }),
1120
- imageData && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1121
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1122
- InfoRow,
1123
- {
1124
- label: "Original",
1125
- value: `${imageData.original.width}x${imageData.original.height}`
1126
- }
1127
- ),
1128
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1129
- InfoRow,
1130
- {
1131
- label: "File size",
1132
- value: formatFileSize3(imageData.original.fileSize)
1133
- }
1134
- ),
1135
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.section, children: [
1136
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.sectionTitle, children: "Generated sizes" }),
1137
- Object.entries(imageData.sizes).map(([size, data]) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, InfoRow, { label: size, value: `${data.width}x${data.height}` }, size))
1138
- ] }),
1139
- _optionalChain([imageData, 'access', _6 => _6.cdn, 'optionalAccess', _7 => _7.synced]) && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.section, children: [
1140
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles5.sectionTitle, children: "CDN" }),
1141
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.cdnStatus, children: [
1142
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles5.cdnIcon, fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }),
1143
- "Synced to CDN"
1144
- ] }),
1332
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1333
+ modals,
1334
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.panel, children: [
1335
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles6.title, children: "Preview" }),
1336
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.imageContainer, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1337
+ "img",
1338
+ {
1339
+ css: styles6.image,
1340
+ src: selectedPath.replace("public", ""),
1341
+ alt: "Preview"
1342
+ }
1343
+ ) }),
1344
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.info, children: [
1345
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, InfoRow, { label: "Filename", value: selectedPath.split("/").pop() || "" }),
1346
+ imageData && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1145
1347
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1146
- "button",
1348
+ InfoRow,
1147
1349
  {
1148
- css: styles5.copyBtn,
1149
- onClick: () => {
1150
- navigator.clipboard.writeText(`${_optionalChain([imageData, 'access', _8 => _8.cdn, 'optionalAccess', _9 => _9.baseUrl])}${imageData.sizes.full.path}`);
1151
- },
1152
- children: "Copy CDN URL"
1350
+ label: "Original",
1351
+ value: `${imageData.original.width}x${imageData.original.height}`
1153
1352
  }
1154
- )
1155
- ] }),
1156
- imageData.blurhash && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.section, children: [
1157
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, InfoRow, { label: "Blurhash", value: imageData.blurhash, truncate: true }),
1353
+ ),
1158
1354
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1159
- "div",
1355
+ InfoRow,
1160
1356
  {
1161
- css: styles5.colorSwatch,
1162
- style: { backgroundColor: imageData.dominantColor },
1163
- title: `Dominant color: ${imageData.dominantColor}`
1357
+ label: "File size",
1358
+ value: formatFileSize3(imageData.original.fileSize)
1164
1359
  }
1165
- )
1360
+ ),
1361
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.section, children: [
1362
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.sectionTitle, children: "Generated sizes" }),
1363
+ Object.entries(imageData.sizes).map(([size, data]) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, InfoRow, { label: size, value: `${data.width}x${data.height}` }, size))
1364
+ ] }),
1365
+ _optionalChain([imageData, 'access', _6 => _6.cdn, 'optionalAccess', _7 => _7.synced]) && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.section, children: [
1366
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.sectionTitle, children: "CDN" }),
1367
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.cdnStatus, children: [
1368
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.cdnIcon, fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }),
1369
+ "Synced to CDN"
1370
+ ] }),
1371
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1372
+ "button",
1373
+ {
1374
+ css: styles6.copyBtn,
1375
+ onClick: () => {
1376
+ navigator.clipboard.writeText(`${_optionalChain([imageData, 'access', _8 => _8.cdn, 'optionalAccess', _9 => _9.baseUrl])}${imageData.sizes.full.path}`);
1377
+ },
1378
+ children: "Copy CDN URL"
1379
+ }
1380
+ )
1381
+ ] }),
1382
+ imageData.blurhash && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.section, children: [
1383
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, InfoRow, { label: "Blurhash", value: imageData.blurhash, truncate: true }),
1384
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1385
+ "div",
1386
+ {
1387
+ css: styles6.colorSwatch,
1388
+ style: { backgroundColor: imageData.dominantColor },
1389
+ title: `Dominant color: ${imageData.dominantColor}`
1390
+ }
1391
+ )
1392
+ ] })
1166
1393
  ] })
1394
+ ] }),
1395
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.actions, children: [
1396
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles6.actionBtn, children: "Rename" }),
1397
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: [styles6.actionBtn, styles6.actionBtnDanger], onClick: handleDeleteClick, children: "Delete" })
1167
1398
  ] })
1168
- ] }),
1169
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.actions, children: [
1170
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles5.actionBtn, children: "Rename" }),
1171
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: [styles5.actionBtn, styles5.actionBtnDanger], onClick: handleDelete, children: "Delete" })
1172
1399
  ] })
1173
1400
  ] });
1174
1401
  }
1175
1402
  function InfoRow({ label, value, truncate }) {
1176
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles5.row, children: [
1177
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles5.label, children: label }),
1178
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: [styles5.value, truncate && styles5.valueTruncate], title: truncate ? value : void 0, children: value })
1403
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.row, children: [
1404
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: styles6.label, children: label }),
1405
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { css: [styles6.value, truncate && styles6.valueTruncate], title: truncate ? value : void 0, children: value })
1179
1406
  ] });
1180
1407
  }
1181
1408
  function formatFileSize3(bytes) {
@@ -1188,7 +1415,7 @@ function formatFileSize3(bytes) {
1188
1415
 
1189
1416
 
1190
1417
 
1191
- var styles6 = {
1418
+ var styles7 = {
1192
1419
  btn: _react3.css`
1193
1420
  padding: 8px;
1194
1421
  background: none;
@@ -1346,10 +1573,10 @@ var styles6 = {
1346
1573
  function StudioSettings() {
1347
1574
  const [isOpen, setIsOpen] = _react.useState.call(void 0, false);
1348
1575
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1349
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles6.btn, onClick: () => setIsOpen(true), "aria-label": "Settings", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1576
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles7.btn, onClick: () => setIsOpen(true), "aria-label": "Settings", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1350
1577
  "svg",
1351
1578
  {
1352
- css: styles6.icon,
1579
+ css: styles7.icon,
1353
1580
  xmlns: "http://www.w3.org/2000/svg",
1354
1581
  viewBox: "0 0 24 24",
1355
1582
  fill: "none",
@@ -1367,51 +1594,51 @@ function StudioSettings() {
1367
1594
  ] });
1368
1595
  }
1369
1596
  function SettingsPanel({ onClose }) {
1370
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.overlay, children: [
1371
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles6.backdrop, onClick: onClose }),
1372
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.panel, children: [
1373
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.header, children: [
1374
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { css: styles6.title, children: "Settings" }),
1375
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles6.closeBtn, onClick: onClose, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles6.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: "M6 18L18 6M6 6l12 12" }) }) })
1597
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.overlay, children: [
1598
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles7.backdrop, onClick: onClose }),
1599
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.panel, children: [
1600
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.header, children: [
1601
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { css: styles7.title, children: "Settings" }),
1602
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles7.closeBtn, onClick: onClose, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { css: styles7.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: "M6 18L18 6M6 6l12 12" }) }) })
1376
1603
  ] }),
1377
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.sections, children: [
1604
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.sections, children: [
1378
1605
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "section", { children: [
1379
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles6.sectionTitle, children: "Cloudflare R2" }),
1380
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.description, children: "Configure in .env.local file:" }),
1381
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.code, children: [
1382
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.codeLine, children: "CLOUDFLARE_R2_ACCOUNT_ID" }),
1383
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.codeLine, children: "CLOUDFLARE_R2_ACCESS_KEY_ID" }),
1384
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.codeLine, children: "CLOUDFLARE_R2_SECRET_ACCESS_KEY" }),
1385
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.codeLine, children: "CLOUDFLARE_R2_BUCKET_NAME" }),
1386
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.codeLine, children: "CLOUDFLARE_R2_PUBLIC_URL" })
1606
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles7.sectionTitle, children: "Cloudflare R2" }),
1607
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles7.description, children: "Configure in .env.local file:" }),
1608
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.code, children: [
1609
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles7.codeLine, children: "CLOUDFLARE_R2_ACCOUNT_ID" }),
1610
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles7.codeLine, children: "CLOUDFLARE_R2_ACCESS_KEY_ID" }),
1611
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles7.codeLine, children: "CLOUDFLARE_R2_SECRET_ACCESS_KEY" }),
1612
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles7.codeLine, children: "CLOUDFLARE_R2_BUCKET_NAME" }),
1613
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles7.codeLine, children: "CLOUDFLARE_R2_PUBLIC_URL" })
1387
1614
  ] })
1388
1615
  ] }),
1389
1616
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "section", { children: [
1390
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles6.sectionTitle, children: "Custom CDN URL" }),
1391
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles6.description, children: "Override the default R2 URL with a custom domain:" }),
1392
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles6.input, type: "text", placeholder: "https://cdn.yourdomain.com" })
1617
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles7.sectionTitle, children: "Custom CDN URL" }),
1618
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { css: styles7.description, children: "Override the default R2 URL with a custom domain:" }),
1619
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles7.input, type: "text", placeholder: "https://cdn.yourdomain.com" })
1393
1620
  ] }),
1394
1621
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "section", { children: [
1395
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles6.sectionTitle, children: "Thumbnail Sizes" }),
1396
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.grid, children: [
1622
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { css: styles7.sectionTitle, children: "Thumbnail Sizes" }),
1623
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.grid, children: [
1397
1624
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
1398
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css: styles6.label, children: "Small" }),
1399
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles6.input, type: "number", defaultValue: 300 })
1625
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css: styles7.label, children: "Small" }),
1626
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles7.input, type: "number", defaultValue: 300 })
1400
1627
  ] }),
1401
1628
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
1402
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css: styles6.label, children: "Medium" }),
1403
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles6.input, type: "number", defaultValue: 700 })
1629
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css: styles7.label, children: "Medium" }),
1630
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles7.input, type: "number", defaultValue: 700 })
1404
1631
  ] }),
1405
1632
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
1406
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css: styles6.label, children: "Large" }),
1407
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles6.input, type: "number", defaultValue: 1400 })
1633
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { css: styles7.label, children: "Large" }),
1634
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "input", { css: styles7.input, type: "number", defaultValue: 1400 })
1408
1635
  ] })
1409
1636
  ] })
1410
1637
  ] })
1411
1638
  ] }),
1412
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles6.footer, children: [
1413
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles6.cancelBtn, onClick: onClose, children: "Cancel" }),
1414
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles6.saveBtn, children: "Save Changes" })
1639
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.footer, children: [
1640
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles7.cancelBtn, onClick: onClose, children: "Cancel" }),
1641
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { css: styles7.saveBtn, children: "Save Changes" })
1415
1642
  ] })
1416
1643
  ] })
1417
1644
  ] });
@@ -1419,7 +1646,7 @@ function SettingsPanel({ onClose }) {
1419
1646
 
1420
1647
  // src/components/StudioUI.tsx
1421
1648
 
1422
- var styles7 = {
1649
+ var styles8 = {
1423
1650
  container: _react3.css`
1424
1651
  display: flex;
1425
1652
  flex-direction: column;
@@ -1569,15 +1796,15 @@ function StudioUI({ onClose }) {
1569
1796
  refreshKey,
1570
1797
  triggerRefresh
1571
1798
  };
1572
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioContext.Provider, { value: contextValue, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.container, children: [
1573
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.header, children: [
1574
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h1", { css: styles7.title, children: "Studio" }),
1575
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.headerActions, children: [
1799
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioContext.Provider, { value: contextValue, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.container, children: [
1800
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.header, children: [
1801
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h1", { css: styles8.title, children: "Studio" }),
1802
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.headerActions, children: [
1576
1803
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioSettings, {}),
1577
1804
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1578
1805
  "button",
1579
1806
  {
1580
- css: styles7.closeBtn,
1807
+ css: styles8.closeBtn,
1581
1808
  onClick: onClose,
1582
1809
  "aria-label": "Close Studio",
1583
1810
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, CloseIcon, {})
@@ -1587,8 +1814,8 @@ function StudioUI({ onClose }) {
1587
1814
  ] }),
1588
1815
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioToolbar, {}),
1589
1816
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioBreadcrumb, {}),
1590
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles7.content, children: [
1591
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles7.fileBrowser, children: viewMode === "grid" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioFileGrid, {}) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioFileList, {}) }),
1817
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { css: styles8.content, children: [
1818
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { css: styles8.fileBrowser, children: viewMode === "grid" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioFileGrid, {}) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioFileList, {}) }),
1592
1819
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, StudioPreview, {})
1593
1820
  ] })
1594
1821
  ] }) });
@@ -1597,7 +1824,7 @@ function CloseIcon() {
1597
1824
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1598
1825
  "svg",
1599
1826
  {
1600
- css: styles7.closeIcon,
1827
+ css: styles8.closeIcon,
1601
1828
  xmlns: "http://www.w3.org/2000/svg",
1602
1829
  viewBox: "0 0 24 24",
1603
1830
  fill: "none",
@@ -1617,4 +1844,4 @@ var StudioUI_default = StudioUI;
1617
1844
 
1618
1845
 
1619
1846
  exports.StudioUI = StudioUI; exports.default = StudioUI_default;
1620
- //# sourceMappingURL=StudioUI-ZAD65UPD.js.map
1847
+ //# sourceMappingURL=StudioUI-QG2NJQTM.js.map