@thetechfossil/upfiles 1.0.9 → 1.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -2
- package/dist/index.d.mts +54 -7
- package/dist/index.d.ts +54 -7
- package/dist/index.js +1100 -411
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1051 -347
- package/dist/index.mjs.map +1 -0
- package/package.json +7 -7
package/dist/index.mjs
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
|
+
import * as React4 from 'react';
|
|
2
|
+
import React4__default, { useRef, useMemo, useState, useCallback, useEffect } from 'react';
|
|
3
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
4
|
+
import * as Dialog2 from '@radix-ui/react-dialog';
|
|
5
|
+
|
|
1
6
|
// src/client.ts
|
|
2
7
|
var UpfilesClient = class {
|
|
3
8
|
constructor(opts) {
|
|
4
9
|
this.baseUrl = opts.baseUrl?.replace(/\/$/, "");
|
|
5
|
-
this.presignPath = opts.presignPath ?? "/api/plugin/upload
|
|
10
|
+
this.presignPath = opts.presignPath ?? "/api/plugin/upload";
|
|
6
11
|
this.presignUrl = opts.presignUrl;
|
|
7
12
|
this.headers = opts.headers;
|
|
8
13
|
this.withCredentials = opts.withCredentials;
|
|
9
14
|
this.apiKey = opts.apiKey;
|
|
10
15
|
this.apiKeyHeader = opts.apiKeyHeader ?? "authorization";
|
|
11
16
|
this.thumbnailsPath = opts.thumbnailsPath ?? "/api/plugin/thumbnails";
|
|
12
|
-
this.completionPath = opts.completionPath ?? "/api/plugin/
|
|
17
|
+
this.completionPath = opts.completionPath ?? "/api/plugin/files";
|
|
18
|
+
this.foldersPath = opts.foldersPath ?? "/api/plugin/folders";
|
|
13
19
|
this.callCompletionEndpoint = opts.callCompletionEndpoint ?? false;
|
|
14
20
|
}
|
|
15
21
|
async getPresignedUrl(params) {
|
|
@@ -132,6 +138,7 @@ var UpfilesClient = class {
|
|
|
132
138
|
}
|
|
133
139
|
throw new Error(msg);
|
|
134
140
|
}
|
|
141
|
+
return res.json();
|
|
135
142
|
}
|
|
136
143
|
async getThumbnails(fileKey) {
|
|
137
144
|
const target = this.baseUrl ? `${this.baseUrl}${this.thumbnailsPath}` : this.thumbnailsPath;
|
|
@@ -192,6 +199,65 @@ var UpfilesClient = class {
|
|
|
192
199
|
const data = await res.json();
|
|
193
200
|
return { masterWebp: data.masterWebp, thumbnails: data.thumbnails ?? [] };
|
|
194
201
|
}
|
|
202
|
+
async getFolders(parentId) {
|
|
203
|
+
const target = this.baseUrl ? `${this.baseUrl}${this.foldersPath}` : this.foldersPath;
|
|
204
|
+
const url = parentId ? `${target}?parentId=${encodeURIComponent(parentId)}` : target;
|
|
205
|
+
const headers = { ...this.headers || {} };
|
|
206
|
+
if (this.apiKey) {
|
|
207
|
+
if (this.apiKeyHeader === "authorization") {
|
|
208
|
+
headers["authorization"] = this.apiKey.startsWith("upk_") ? `Bearer ${this.apiKey}` : this.apiKey;
|
|
209
|
+
} else if (this.apiKeyHeader === "x-api-key") {
|
|
210
|
+
headers["x-api-key"] = this.apiKey;
|
|
211
|
+
} else {
|
|
212
|
+
headers["x-up-api-key"] = this.apiKey;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
const res = await fetch(url, { method: "GET", headers, credentials: this.withCredentials ? "include" : "same-origin" });
|
|
216
|
+
if (!res.ok) {
|
|
217
|
+
let msg = "Failed to fetch folders";
|
|
218
|
+
try {
|
|
219
|
+
const data2 = await res.json();
|
|
220
|
+
msg = data2.error || msg;
|
|
221
|
+
} catch {
|
|
222
|
+
}
|
|
223
|
+
throw new Error(msg);
|
|
224
|
+
}
|
|
225
|
+
const data = await res.json();
|
|
226
|
+
return data?.folders ?? [];
|
|
227
|
+
}
|
|
228
|
+
async createFolder(name, parentId) {
|
|
229
|
+
const target = this.baseUrl ? `${this.baseUrl}${this.foldersPath}` : this.foldersPath;
|
|
230
|
+
const headers = {
|
|
231
|
+
"content-type": "application/json",
|
|
232
|
+
...this.headers || {}
|
|
233
|
+
};
|
|
234
|
+
if (this.apiKey) {
|
|
235
|
+
if (this.apiKeyHeader === "authorization") {
|
|
236
|
+
headers["authorization"] = this.apiKey.startsWith("upk_") ? `Bearer ${this.apiKey}` : this.apiKey;
|
|
237
|
+
} else if (this.apiKeyHeader === "x-api-key") {
|
|
238
|
+
headers["x-api-key"] = this.apiKey;
|
|
239
|
+
} else {
|
|
240
|
+
headers["x-up-api-key"] = this.apiKey;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
const res = await fetch(target, {
|
|
244
|
+
method: "POST",
|
|
245
|
+
headers,
|
|
246
|
+
credentials: this.withCredentials ? "include" : "same-origin",
|
|
247
|
+
body: JSON.stringify({ name, parentId })
|
|
248
|
+
});
|
|
249
|
+
if (!res.ok) {
|
|
250
|
+
let msg = "Failed to create folder";
|
|
251
|
+
try {
|
|
252
|
+
const data2 = await res.json();
|
|
253
|
+
msg = data2.error || msg;
|
|
254
|
+
} catch {
|
|
255
|
+
}
|
|
256
|
+
throw new Error(msg);
|
|
257
|
+
}
|
|
258
|
+
const data = await res.json();
|
|
259
|
+
return data.folder;
|
|
260
|
+
}
|
|
195
261
|
async getProjectFiles(params) {
|
|
196
262
|
const basePath = this.thumbnailsPath.replace(/\/thumbnails$/, "");
|
|
197
263
|
const filesPath = `${basePath}/files`;
|
|
@@ -218,13 +284,24 @@ var UpfilesClient = class {
|
|
|
218
284
|
throw new Error(msg);
|
|
219
285
|
}
|
|
220
286
|
const data = await res.json();
|
|
221
|
-
return
|
|
287
|
+
return {
|
|
288
|
+
files: data?.files ?? [],
|
|
289
|
+
updatedAt: res.headers.get("X-Files-Updated-At")
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
getEventsUrl(projectId) {
|
|
293
|
+
this.thumbnailsPath.replace(/\/thumbnails$/, "");
|
|
294
|
+
const target = this.baseUrl ? `${this.baseUrl}/api/events` : "/api/events";
|
|
295
|
+
const url = new URL(target, window.location.href);
|
|
296
|
+
if (this.apiKey) {
|
|
297
|
+
url.searchParams.set("apiKey", this.apiKey);
|
|
298
|
+
}
|
|
299
|
+
if (projectId) {
|
|
300
|
+
url.searchParams.set("projectId", projectId);
|
|
301
|
+
}
|
|
302
|
+
return url.toString();
|
|
222
303
|
}
|
|
223
304
|
};
|
|
224
|
-
|
|
225
|
-
// src/Uploader.tsx
|
|
226
|
-
import React, { useCallback, useMemo, useRef, useState } from "react";
|
|
227
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
228
305
|
var Uploader = ({
|
|
229
306
|
clientOptions,
|
|
230
307
|
multiple = true,
|
|
@@ -243,7 +320,7 @@ var Uploader = ({
|
|
|
243
320
|
projectId,
|
|
244
321
|
folderPath,
|
|
245
322
|
fetchThumbnails,
|
|
246
|
-
autoRecordToDb =
|
|
323
|
+
autoRecordToDb = true,
|
|
247
324
|
recordUrl = "/api/files",
|
|
248
325
|
autoUpload = false
|
|
249
326
|
}) => {
|
|
@@ -317,9 +394,10 @@ var Uploader = ({
|
|
|
317
394
|
xhr.setRequestHeader("Content-Type", item.type || "application/octet-stream");
|
|
318
395
|
xhr.send(item.file);
|
|
319
396
|
});
|
|
397
|
+
let completionResult = null;
|
|
320
398
|
if (autoRecordToDb && projectId) {
|
|
321
399
|
try {
|
|
322
|
-
await client.completeUpload({
|
|
400
|
+
completionResult = await client.completeUpload({
|
|
323
401
|
fileKey: presign.fileKey,
|
|
324
402
|
originalName: item.name,
|
|
325
403
|
size: item.size,
|
|
@@ -333,15 +411,21 @@ var Uploader = ({
|
|
|
333
411
|
}
|
|
334
412
|
let thumbs;
|
|
335
413
|
let masterWebp;
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
414
|
+
if (completionResult?.thumbnails?.length > 0) {
|
|
415
|
+
thumbs = completionResult.thumbnails;
|
|
416
|
+
masterWebp = completionResult.masterWebp;
|
|
417
|
+
} else if (fetchThumbnails) {
|
|
418
|
+
const fileKeyToUse = completionResult?.file?.key || presign.fileKey;
|
|
419
|
+
try {
|
|
420
|
+
const result2 = await client.generateThumbnails(fileKeyToUse);
|
|
339
421
|
thumbs = result2.thumbnails;
|
|
340
422
|
masterWebp = result2.masterWebp;
|
|
423
|
+
} catch (e) {
|
|
424
|
+
console.warn("Failed to generate thumbnails:", e);
|
|
341
425
|
}
|
|
342
|
-
} catch (e) {
|
|
343
|
-
console.warn("Failed to generate thumbnails:", e);
|
|
344
426
|
}
|
|
427
|
+
const finalFileKey = completionResult?.file?.key || presign.fileKey;
|
|
428
|
+
const finalPublicUrl = completionResult?.file?.url || presign.publicUrl;
|
|
345
429
|
const result = {
|
|
346
430
|
...item,
|
|
347
431
|
status: "success",
|
|
@@ -384,7 +468,7 @@ var Uploader = ({
|
|
|
384
468
|
setIsUploading(false);
|
|
385
469
|
}
|
|
386
470
|
}, [files, onComplete, onError, uploadOne]);
|
|
387
|
-
|
|
471
|
+
React4__default.useEffect(() => {
|
|
388
472
|
if (autoUpload && files.some((f2) => f2.status === "pending") && !isUploading) {
|
|
389
473
|
const timer = setTimeout(() => {
|
|
390
474
|
uploadAll();
|
|
@@ -404,10 +488,10 @@ var Uploader = ({
|
|
|
404
488
|
onChange: onInputChange
|
|
405
489
|
}
|
|
406
490
|
),
|
|
407
|
-
/* @__PURE__ */
|
|
491
|
+
/* @__PURE__ */ jsxs(
|
|
408
492
|
"div",
|
|
409
493
|
{
|
|
410
|
-
className: dropzoneClassName
|
|
494
|
+
className: `${dropzoneClassName} border-2 border-dashed rounded-xl transition-all duration-200 cursor-pointer p-10 flex flex-col items-center justify-center gap-4 ${isDragOver ? "border-blue-500 bg-blue-50 dark:bg-blue-900/20" : "border-gray-200 dark:border-gray-800 hover:border-gray-300 dark:hover:border-gray-700 bg-gray-50/50 dark:bg-gray-900/50"}`,
|
|
411
495
|
onDragOver: (e) => {
|
|
412
496
|
e.preventDefault();
|
|
413
497
|
e.stopPropagation();
|
|
@@ -422,60 +506,126 @@ var Uploader = ({
|
|
|
422
506
|
onClick: () => inputRef.current?.click(),
|
|
423
507
|
role: "button",
|
|
424
508
|
"aria-label": "Upload files",
|
|
425
|
-
children:
|
|
426
|
-
/* @__PURE__ */ jsx("div", {
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
"
|
|
430
|
-
|
|
431
|
-
|
|
509
|
+
children: [
|
|
510
|
+
/* @__PURE__ */ jsx("div", { className: "w-16 h-16 rounded-full bg-blue-100 dark:bg-blue-900/30 flex items-center justify-center text-blue-600 dark:text-blue-400", children: /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "32", height: "32", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
511
|
+
/* @__PURE__ */ jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
|
|
512
|
+
/* @__PURE__ */ jsx("polyline", { points: "17 8 12 3 7 8" }),
|
|
513
|
+
/* @__PURE__ */ jsx("line", { x1: "12", y1: "3", x2: "12", y2: "15" })
|
|
514
|
+
] }) }),
|
|
515
|
+
children ?? /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
|
|
516
|
+
/* @__PURE__ */ jsx("div", { className: "text-lg font-semibold text-gray-900 dark:text-gray-100", children: "Drop files here or click to browse" }),
|
|
517
|
+
/* @__PURE__ */ jsxs("div", { className: "text-sm text-gray-500 dark:text-gray-400 mt-1", children: [
|
|
518
|
+
multiple ? `Up to ${maxFiles} files` : "Single file",
|
|
519
|
+
" \u2022 Max ",
|
|
520
|
+
(maxFileSize / (1024 * 1024)).toFixed(0),
|
|
521
|
+
"MB"
|
|
522
|
+
] })
|
|
432
523
|
] })
|
|
433
|
-
]
|
|
524
|
+
]
|
|
434
525
|
}
|
|
435
526
|
),
|
|
436
|
-
files.length > 0 && /* @__PURE__ */ jsxs("div", {
|
|
437
|
-
/* @__PURE__ */ jsxs("div", {
|
|
438
|
-
/* @__PURE__ */ jsx(
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
527
|
+
files.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mt-8 space-y-4", children: [
|
|
528
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-b border-gray-100 dark:border-gray-800 pb-4", children: [
|
|
529
|
+
/* @__PURE__ */ jsx("h4", { className: "font-semibold text-gray-900 dark:text-gray-100", children: "Selected Files" }),
|
|
530
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-3", children: [
|
|
531
|
+
/* @__PURE__ */ jsx(
|
|
532
|
+
"button",
|
|
533
|
+
{
|
|
534
|
+
className: "px-4 py-2 bg-blue-600 text-white text-sm font-semibold rounded-lg hover:bg-blue-500 disabled:opacity-50 disabled:cursor-not-allowed transition-colors shadow-sm",
|
|
535
|
+
disabled: isUploading || files.every((f2) => f2.status !== "pending"),
|
|
536
|
+
onClick: uploadAll,
|
|
537
|
+
children: isUploading ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
|
|
538
|
+
/* @__PURE__ */ jsxs("svg", { className: "animate-spin h-4 w-4 text-white", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [
|
|
539
|
+
/* @__PURE__ */ jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
540
|
+
/* @__PURE__ */ jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })
|
|
541
|
+
] }),
|
|
542
|
+
"Uploading..."
|
|
543
|
+
] }) : "Upload All"
|
|
544
|
+
}
|
|
545
|
+
),
|
|
546
|
+
/* @__PURE__ */ jsx(
|
|
547
|
+
"button",
|
|
548
|
+
{
|
|
549
|
+
className: "px-4 py-2 bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300 text-sm font-semibold rounded-lg hover:bg-gray-200 dark:hover:bg-gray-700 disabled:opacity-50 transition-colors",
|
|
550
|
+
disabled: isUploading,
|
|
551
|
+
onClick: () => setFiles([]),
|
|
552
|
+
children: "Clear"
|
|
553
|
+
}
|
|
554
|
+
)
|
|
555
|
+
] })
|
|
456
556
|
] }),
|
|
457
|
-
/* @__PURE__ */ jsx("
|
|
458
|
-
/* @__PURE__ */
|
|
459
|
-
/* @__PURE__ */ jsx("
|
|
460
|
-
/* @__PURE__ */
|
|
461
|
-
|
|
462
|
-
|
|
557
|
+
/* @__PURE__ */ jsx("div", { className: "grid gap-3", children: files.map((f2) => /* @__PURE__ */ jsx("div", { className: "group relative bg-white dark:bg-gray-900 border border-gray-100 dark:border-gray-800 rounded-xl p-4 transition-all hover:shadow-md", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
|
|
558
|
+
/* @__PURE__ */ jsx("div", { className: "w-10 h-10 rounded-lg bg-gray-50 dark:bg-gray-800 flex items-center justify-center flex-shrink-0", children: f2.type.startsWith("image/") ? /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "text-indigo-500", children: [
|
|
559
|
+
/* @__PURE__ */ jsx("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
|
|
560
|
+
/* @__PURE__ */ jsx("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
|
|
561
|
+
/* @__PURE__ */ jsx("polyline", { points: "21 15 16 10 5 21" })
|
|
562
|
+
] }) : /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "text-blue-500", children: [
|
|
563
|
+
/* @__PURE__ */ jsx("path", { d: "M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z" }),
|
|
564
|
+
/* @__PURE__ */ jsx("polyline", { points: "14 2 14 8 20 8" })
|
|
565
|
+
] }) }),
|
|
566
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
567
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-1", children: [
|
|
568
|
+
/* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-gray-900 dark:text-gray-100 truncate pr-4", children: f2.name }),
|
|
569
|
+
/* @__PURE__ */ jsxs("div", { className: "text-xs text-gray-500 font-medium whitespace-nowrap", children: [
|
|
570
|
+
(f2.size / (1024 * 1024)).toFixed(2),
|
|
571
|
+
" MB"
|
|
572
|
+
] })
|
|
463
573
|
] }),
|
|
464
|
-
f2.error
|
|
465
|
-
|
|
574
|
+
f2.status === "error" ? /* @__PURE__ */ jsx("div", { className: "text-xs text-red-500 font-medium mt-1", children: f2.error }) : /* @__PURE__ */ jsx("div", { className: "h-1.5 w-full bg-gray-100 dark:bg-gray-800 rounded-full overflow-hidden mt-2", children: /* @__PURE__ */ jsx(
|
|
575
|
+
"div",
|
|
576
|
+
{
|
|
577
|
+
className: `h-full transition-all duration-300 ${f2.status === "success" ? "bg-green-500" : "bg-blue-500"}`,
|
|
578
|
+
style: { width: `${f2.progress}%` }
|
|
579
|
+
}
|
|
580
|
+
) })
|
|
466
581
|
] }),
|
|
467
|
-
/* @__PURE__ */ jsxs("div", {
|
|
468
|
-
|
|
469
|
-
|
|
582
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-shrink-0 ml-4", children: [
|
|
583
|
+
f2.status === "success" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
584
|
+
/* @__PURE__ */ jsx("span", { className: "flex h-6 w-6 items-center justify-center rounded-full bg-green-100 dark:bg-green-900/30 text-green-600 dark:text-green-400", children: /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("polyline", { points: "20 6 9 17 4 12" }) }) }),
|
|
585
|
+
f2.publicUrl && /* @__PURE__ */ jsx(
|
|
586
|
+
"a",
|
|
587
|
+
{
|
|
588
|
+
href: f2.publicUrl,
|
|
589
|
+
target: "_blank",
|
|
590
|
+
rel: "noreferrer",
|
|
591
|
+
className: "p-1.5 text-blue-600 hover:bg-blue-50 dark:hover:bg-blue-900/20 rounded-md transition-colors",
|
|
592
|
+
title: "View online",
|
|
593
|
+
children: /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
594
|
+
/* @__PURE__ */ jsx("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }),
|
|
595
|
+
/* @__PURE__ */ jsx("polyline", { points: "15 3 21 3 21 9" }),
|
|
596
|
+
/* @__PURE__ */ jsx("line", { x1: "10", y1: "14", x2: "21", y2: "3" })
|
|
597
|
+
] })
|
|
598
|
+
}
|
|
599
|
+
)
|
|
600
|
+
] }),
|
|
601
|
+
f2.status === "error" && /* @__PURE__ */ jsx("span", { className: "flex h-6 w-6 items-center justify-center rounded-full bg-red-100 dark:bg-red-900/30 text-red-600 dark:text-red-400", children: /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
602
|
+
/* @__PURE__ */ jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
603
|
+
/* @__PURE__ */ jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
604
|
+
] }) }),
|
|
605
|
+
f2.status === "uploading" && /* @__PURE__ */ jsxs("span", { className: "text-xs font-semibold text-blue-600 dark:text-blue-400", children: [
|
|
606
|
+
f2.progress,
|
|
607
|
+
"%"
|
|
608
|
+
] }),
|
|
609
|
+
f2.status === "pending" && /* @__PURE__ */ jsx(
|
|
610
|
+
"button",
|
|
611
|
+
{
|
|
612
|
+
onClick: (e) => {
|
|
613
|
+
e.stopPropagation();
|
|
614
|
+
setFiles((prev) => prev.filter((file) => file.id !== f2.id));
|
|
615
|
+
},
|
|
616
|
+
className: "p-1.5 text-gray-400 hover:text-red-500 hover:bg-red-50 dark:hover:bg-red-900/20 rounded-md transition-colors",
|
|
617
|
+
title: "Remove",
|
|
618
|
+
children: /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
619
|
+
/* @__PURE__ */ jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
620
|
+
/* @__PURE__ */ jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
621
|
+
] })
|
|
622
|
+
}
|
|
623
|
+
)
|
|
470
624
|
] })
|
|
471
625
|
] }) }, f2.id)) })
|
|
472
626
|
] })
|
|
473
627
|
] });
|
|
474
628
|
};
|
|
475
|
-
|
|
476
|
-
// src/ProjectFilesWidget.tsx
|
|
477
|
-
import { useEffect, useMemo as useMemo2, useState as useState2 } from "react";
|
|
478
|
-
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
479
629
|
var ProjectFilesWidget = ({
|
|
480
630
|
clientOptions,
|
|
481
631
|
folderPath,
|
|
@@ -488,34 +638,47 @@ var ProjectFilesWidget = ({
|
|
|
488
638
|
onSaved,
|
|
489
639
|
onDelete,
|
|
490
640
|
deleteUrl = "/api/files",
|
|
491
|
-
showDelete = false
|
|
641
|
+
showDelete = false,
|
|
642
|
+
refreshInterval = 5e3
|
|
492
643
|
}) => {
|
|
493
|
-
const client =
|
|
494
|
-
const [files, setFiles] =
|
|
495
|
-
const [loading, setLoading] =
|
|
496
|
-
const [error, setError] =
|
|
497
|
-
const [query, setQuery] =
|
|
498
|
-
const [savingKey, setSavingKey] =
|
|
499
|
-
const [deletingKey, setDeletingKey] =
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
if (!cancelled) setLoading(false);
|
|
644
|
+
const client = useMemo(() => new UpfilesClient(clientOptions ?? {}), [clientOptions]);
|
|
645
|
+
const [files, setFiles] = useState([]);
|
|
646
|
+
const [loading, setLoading] = useState(false);
|
|
647
|
+
const [error, setError] = useState(null);
|
|
648
|
+
const [query, setQuery] = useState("");
|
|
649
|
+
const [savingKey, setSavingKey] = useState(null);
|
|
650
|
+
const [deletingKey, setDeletingKey] = useState(null);
|
|
651
|
+
const lastUpdatedRef = React4__default.useRef(null);
|
|
652
|
+
const isFetchingRef = React4__default.useRef(false);
|
|
653
|
+
const fetchFiles = React4__default.useCallback(async (isPolling = false) => {
|
|
654
|
+
if (isFetchingRef.current) return;
|
|
655
|
+
isFetchingRef.current = true;
|
|
656
|
+
if (!isPolling) setLoading(true);
|
|
657
|
+
setError(null);
|
|
658
|
+
try {
|
|
659
|
+
const { files: newFiles, updatedAt } = await client.getProjectFiles({ folderPath });
|
|
660
|
+
if (isPolling && updatedAt && updatedAt === lastUpdatedRef.current) {
|
|
661
|
+
return;
|
|
512
662
|
}
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
}
|
|
663
|
+
setFiles(newFiles);
|
|
664
|
+
lastUpdatedRef.current = updatedAt;
|
|
665
|
+
} catch (e) {
|
|
666
|
+
if (!isPolling) setError(e?.message || "Failed to load files");
|
|
667
|
+
} finally {
|
|
668
|
+
if (!isPolling) setLoading(false);
|
|
669
|
+
isFetchingRef.current = false;
|
|
670
|
+
}
|
|
518
671
|
}, [client, folderPath]);
|
|
672
|
+
useEffect(() => {
|
|
673
|
+
fetchFiles();
|
|
674
|
+
}, [fetchFiles]);
|
|
675
|
+
useEffect(() => {
|
|
676
|
+
if (!refreshInterval || refreshInterval <= 0) return;
|
|
677
|
+
const timer = setInterval(() => {
|
|
678
|
+
fetchFiles(true);
|
|
679
|
+
}, refreshInterval);
|
|
680
|
+
return () => clearInterval(timer);
|
|
681
|
+
}, [fetchFiles, refreshInterval]);
|
|
519
682
|
const visible = files.filter(
|
|
520
683
|
(f2) => !query ? true : (f2.originalName || "").toLowerCase().includes(query.toLowerCase())
|
|
521
684
|
);
|
|
@@ -555,9 +718,9 @@ var ProjectFilesWidget = ({
|
|
|
555
718
|
setDeletingKey(null);
|
|
556
719
|
}
|
|
557
720
|
};
|
|
558
|
-
return /* @__PURE__ */
|
|
559
|
-
/* @__PURE__ */
|
|
560
|
-
/* @__PURE__ */
|
|
721
|
+
return /* @__PURE__ */ jsxs("div", { className, children: [
|
|
722
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8, alignItems: "center", marginBottom: 8 }, children: [
|
|
723
|
+
/* @__PURE__ */ jsx(
|
|
561
724
|
"input",
|
|
562
725
|
{
|
|
563
726
|
type: "text",
|
|
@@ -567,49 +730,38 @@ var ProjectFilesWidget = ({
|
|
|
567
730
|
style: { flex: 1, padding: 8, border: "1px solid #e5e7eb", borderRadius: 6 }
|
|
568
731
|
}
|
|
569
732
|
),
|
|
570
|
-
/* @__PURE__ */
|
|
733
|
+
/* @__PURE__ */ jsx(
|
|
571
734
|
"button",
|
|
572
735
|
{
|
|
573
736
|
onClick: () => {
|
|
574
737
|
setQuery("");
|
|
575
|
-
(
|
|
576
|
-
setLoading(true);
|
|
577
|
-
setError(null);
|
|
578
|
-
try {
|
|
579
|
-
const data = await client.getProjectFiles({ folderPath });
|
|
580
|
-
setFiles(data);
|
|
581
|
-
} catch (e) {
|
|
582
|
-
setError(e?.message || "Failed to load files");
|
|
583
|
-
} finally {
|
|
584
|
-
setLoading(false);
|
|
585
|
-
}
|
|
586
|
-
})();
|
|
738
|
+
fetchFiles();
|
|
587
739
|
},
|
|
588
740
|
style: { padding: "8px 12px", border: "1px solid #e5e7eb", borderRadius: 6, background: "#fff" },
|
|
589
741
|
children: "Refresh"
|
|
590
742
|
}
|
|
591
743
|
)
|
|
592
744
|
] }),
|
|
593
|
-
loading && /* @__PURE__ */
|
|
594
|
-
error && /* @__PURE__ */
|
|
595
|
-
!loading && !error && /* @__PURE__ */
|
|
596
|
-
visible.map((f2) => /* @__PURE__ */
|
|
745
|
+
loading && /* @__PURE__ */ jsx("div", { style: { fontSize: 12, color: "#666" }, children: "Loading files\u2026" }),
|
|
746
|
+
error && /* @__PURE__ */ jsx("div", { style: { fontSize: 12, color: "#b91c1c" }, children: error }),
|
|
747
|
+
!loading && !error && /* @__PURE__ */ jsxs("ul", { className: listClassName, style: { listStyle: "none", padding: 0, margin: 0, display: "grid", gap: 8 }, children: [
|
|
748
|
+
visible.map((f2) => /* @__PURE__ */ jsxs(
|
|
597
749
|
"li",
|
|
598
750
|
{
|
|
599
751
|
className: itemClassName,
|
|
600
752
|
style: { border: "1px solid #e5e7eb", borderRadius: 8, padding: 10, display: "flex", justifyContent: "space-between", alignItems: "center" },
|
|
601
753
|
children: [
|
|
602
|
-
/* @__PURE__ */
|
|
603
|
-
/* @__PURE__ */
|
|
604
|
-
/* @__PURE__ */
|
|
754
|
+
/* @__PURE__ */ jsxs("div", { style: { minWidth: 0 }, children: [
|
|
755
|
+
/* @__PURE__ */ jsx("div", { style: { fontWeight: 500, overflow: "hidden", textOverflow: "ellipsis" }, children: f2.originalName }),
|
|
756
|
+
/* @__PURE__ */ jsxs("div", { style: { fontSize: 12, color: "#666" }, children: [
|
|
605
757
|
(f2.size / (1024 * 1024)).toFixed(2),
|
|
606
758
|
" MB \u2022 ",
|
|
607
759
|
f2.contentType
|
|
608
760
|
] })
|
|
609
761
|
] }),
|
|
610
|
-
/* @__PURE__ */
|
|
611
|
-
/* @__PURE__ */
|
|
612
|
-
/* @__PURE__ */
|
|
762
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
|
|
763
|
+
/* @__PURE__ */ jsx("a", { href: f2.url, target: "_blank", rel: "noreferrer", style: { fontSize: 12, color: "#2563eb" }, children: "View" }),
|
|
764
|
+
/* @__PURE__ */ jsx(
|
|
613
765
|
"button",
|
|
614
766
|
{
|
|
615
767
|
onClick: async () => {
|
|
@@ -646,7 +798,7 @@ var ProjectFilesWidget = ({
|
|
|
646
798
|
children: savingKey === f2.key ? "Saving\u2026" : "Use"
|
|
647
799
|
}
|
|
648
800
|
),
|
|
649
|
-
showDelete && /* @__PURE__ */
|
|
801
|
+
showDelete && /* @__PURE__ */ jsx(
|
|
650
802
|
"button",
|
|
651
803
|
{
|
|
652
804
|
onClick: () => handleDelete(f2.key),
|
|
@@ -660,15 +812,11 @@ var ProjectFilesWidget = ({
|
|
|
660
812
|
},
|
|
661
813
|
f2.key
|
|
662
814
|
)),
|
|
663
|
-
visible.length === 0 && /* @__PURE__ */
|
|
815
|
+
visible.length === 0 && /* @__PURE__ */ jsx("li", { style: { fontSize: 12, color: "#666" }, children: "No files found" })
|
|
664
816
|
] })
|
|
665
817
|
] });
|
|
666
818
|
};
|
|
667
819
|
|
|
668
|
-
// src/ConnectProjectDialog.tsx
|
|
669
|
-
import * as React3 from "react";
|
|
670
|
-
import * as Dialog from "@radix-ui/react-dialog";
|
|
671
|
-
|
|
672
820
|
// src/projectConnect.ts
|
|
673
821
|
var f = (globalThis.fetch || fetch).bind(globalThis);
|
|
674
822
|
async function httpJson(input, init, useFetch) {
|
|
@@ -758,19 +906,16 @@ function connectUsingApiKey(opts) {
|
|
|
758
906
|
const client = new UpfilesClient({ baseUrl, apiKey, apiKeyHeader: opts.apiKeyHeader ?? "authorization" });
|
|
759
907
|
return { apiKey, client };
|
|
760
908
|
}
|
|
761
|
-
|
|
762
|
-
// src/ConnectProjectDialog.tsx
|
|
763
|
-
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
764
909
|
function ConnectProjectDialog(props) {
|
|
765
910
|
const { baseUrl, open, onOpenChange, onConnected, fetchImpl, title, description, className } = props;
|
|
766
|
-
const [mode, setMode] =
|
|
767
|
-
const [loading, setLoading] =
|
|
768
|
-
const [error, setError] =
|
|
769
|
-
const [projects, setProjects] =
|
|
770
|
-
const [selectedProjectId, setSelectedProjectId] =
|
|
771
|
-
const [manualKey, setManualKey] =
|
|
772
|
-
const [newProjectName, setNewProjectName] =
|
|
773
|
-
const resetState =
|
|
911
|
+
const [mode, setMode] = React4.useState("existing");
|
|
912
|
+
const [loading, setLoading] = React4.useState(false);
|
|
913
|
+
const [error, setError] = React4.useState(null);
|
|
914
|
+
const [projects, setProjects] = React4.useState([]);
|
|
915
|
+
const [selectedProjectId, setSelectedProjectId] = React4.useState("");
|
|
916
|
+
const [manualKey, setManualKey] = React4.useState("");
|
|
917
|
+
const [newProjectName, setNewProjectName] = React4.useState("");
|
|
918
|
+
const resetState = React4.useCallback(() => {
|
|
774
919
|
setMode("existing");
|
|
775
920
|
setLoading(false);
|
|
776
921
|
setError(null);
|
|
@@ -779,7 +924,7 @@ function ConnectProjectDialog(props) {
|
|
|
779
924
|
setManualKey("");
|
|
780
925
|
setNewProjectName("");
|
|
781
926
|
}, []);
|
|
782
|
-
|
|
927
|
+
React4.useEffect(() => {
|
|
783
928
|
const run = async () => {
|
|
784
929
|
if (!open || mode !== "existing") return;
|
|
785
930
|
try {
|
|
@@ -841,8 +986,8 @@ function ConnectProjectDialog(props) {
|
|
|
841
986
|
setLoading(false);
|
|
842
987
|
}
|
|
843
988
|
};
|
|
844
|
-
const ModeSwitcher = /* @__PURE__ */
|
|
845
|
-
/* @__PURE__ */
|
|
989
|
+
const ModeSwitcher = /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-3 gap-2", children: [
|
|
990
|
+
/* @__PURE__ */ jsx(
|
|
846
991
|
"button",
|
|
847
992
|
{
|
|
848
993
|
type: "button",
|
|
@@ -851,7 +996,7 @@ function ConnectProjectDialog(props) {
|
|
|
851
996
|
children: "Connect existing"
|
|
852
997
|
}
|
|
853
998
|
),
|
|
854
|
-
/* @__PURE__ */
|
|
999
|
+
/* @__PURE__ */ jsx(
|
|
855
1000
|
"button",
|
|
856
1001
|
{
|
|
857
1002
|
type: "button",
|
|
@@ -860,7 +1005,7 @@ function ConnectProjectDialog(props) {
|
|
|
860
1005
|
children: "Add API key"
|
|
861
1006
|
}
|
|
862
1007
|
),
|
|
863
|
-
/* @__PURE__ */
|
|
1008
|
+
/* @__PURE__ */ jsx(
|
|
864
1009
|
"button",
|
|
865
1010
|
{
|
|
866
1011
|
type: "button",
|
|
@@ -870,19 +1015,19 @@ function ConnectProjectDialog(props) {
|
|
|
870
1015
|
}
|
|
871
1016
|
)
|
|
872
1017
|
] });
|
|
873
|
-
return /* @__PURE__ */
|
|
1018
|
+
return /* @__PURE__ */ jsx(Dialog2.Root, { open, onOpenChange: (o) => {
|
|
874
1019
|
if (!o) resetState();
|
|
875
1020
|
onOpenChange(o);
|
|
876
|
-
}, children: /* @__PURE__ */
|
|
877
|
-
/* @__PURE__ */
|
|
878
|
-
/* @__PURE__ */
|
|
879
|
-
/* @__PURE__ */
|
|
880
|
-
/* @__PURE__ */
|
|
1021
|
+
}, children: /* @__PURE__ */ jsxs(Dialog2.Portal, { children: [
|
|
1022
|
+
/* @__PURE__ */ jsx(Dialog2.Overlay, { className: "fixed inset-0 bg-black/40" }),
|
|
1023
|
+
/* @__PURE__ */ jsx(Dialog2.Content, { className: `fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-[95vw] max-w-md rounded-lg border bg-white p-4 shadow-lg ${className ?? ""}`, children: /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
1024
|
+
/* @__PURE__ */ jsx(Dialog2.Title, { className: "text-lg font-semibold", children: title ?? "Connect to Upfiles" }),
|
|
1025
|
+
/* @__PURE__ */ jsx(Dialog2.Description, { className: "text-sm text-muted-foreground", children: description ?? "Choose how to connect your project to retrieve an API key." }),
|
|
881
1026
|
ModeSwitcher,
|
|
882
|
-
error && /* @__PURE__ */
|
|
883
|
-
mode === "existing" && /* @__PURE__ */
|
|
884
|
-
/* @__PURE__ */
|
|
885
|
-
/* @__PURE__ */
|
|
1027
|
+
error && /* @__PURE__ */ jsx("div", { className: "rounded border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700", children: error }),
|
|
1028
|
+
mode === "existing" && /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
1029
|
+
/* @__PURE__ */ jsx("label", { className: "text-sm font-medium", children: "Project" }),
|
|
1030
|
+
/* @__PURE__ */ jsxs(
|
|
886
1031
|
"select",
|
|
887
1032
|
{
|
|
888
1033
|
className: "w-full rounded border px-3 py-2 text-sm",
|
|
@@ -890,14 +1035,14 @@ function ConnectProjectDialog(props) {
|
|
|
890
1035
|
onChange: (e) => setSelectedProjectId(e.target.value),
|
|
891
1036
|
disabled: loading,
|
|
892
1037
|
children: [
|
|
893
|
-
projects.length === 0 && /* @__PURE__ */
|
|
894
|
-
projects.map((p) => /* @__PURE__ */
|
|
1038
|
+
projects.length === 0 && /* @__PURE__ */ jsx("option", { value: "", children: loading ? "Loading..." : "No projects found" }),
|
|
1039
|
+
projects.map((p) => /* @__PURE__ */ jsx("option", { value: p.id, children: p.name }, p.id))
|
|
895
1040
|
]
|
|
896
1041
|
}
|
|
897
1042
|
),
|
|
898
|
-
/* @__PURE__ */
|
|
899
|
-
/* @__PURE__ */
|
|
900
|
-
/* @__PURE__ */
|
|
1043
|
+
/* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2 pt-2", children: [
|
|
1044
|
+
/* @__PURE__ */ jsx(Dialog2.Close, { asChild: true, children: /* @__PURE__ */ jsx("button", { type: "button", className: "px-3 py-2 text-sm rounded border", children: "Cancel" }) }),
|
|
1045
|
+
/* @__PURE__ */ jsx(
|
|
901
1046
|
"button",
|
|
902
1047
|
{
|
|
903
1048
|
type: "button",
|
|
@@ -909,9 +1054,9 @@ function ConnectProjectDialog(props) {
|
|
|
909
1054
|
)
|
|
910
1055
|
] })
|
|
911
1056
|
] }),
|
|
912
|
-
mode === "manual" && /* @__PURE__ */
|
|
913
|
-
/* @__PURE__ */
|
|
914
|
-
/* @__PURE__ */
|
|
1057
|
+
mode === "manual" && /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
1058
|
+
/* @__PURE__ */ jsx("label", { className: "text-sm font-medium", children: "API key" }),
|
|
1059
|
+
/* @__PURE__ */ jsx(
|
|
915
1060
|
"input",
|
|
916
1061
|
{
|
|
917
1062
|
className: "w-full rounded border px-3 py-2 text-sm",
|
|
@@ -921,9 +1066,9 @@ function ConnectProjectDialog(props) {
|
|
|
921
1066
|
disabled: loading
|
|
922
1067
|
}
|
|
923
1068
|
),
|
|
924
|
-
/* @__PURE__ */
|
|
925
|
-
/* @__PURE__ */
|
|
926
|
-
/* @__PURE__ */
|
|
1069
|
+
/* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2 pt-2", children: [
|
|
1070
|
+
/* @__PURE__ */ jsx(Dialog2.Close, { asChild: true, children: /* @__PURE__ */ jsx("button", { type: "button", className: "px-3 py-2 text-sm rounded border", children: "Cancel" }) }),
|
|
1071
|
+
/* @__PURE__ */ jsx(
|
|
927
1072
|
"button",
|
|
928
1073
|
{
|
|
929
1074
|
type: "button",
|
|
@@ -935,9 +1080,9 @@ function ConnectProjectDialog(props) {
|
|
|
935
1080
|
)
|
|
936
1081
|
] })
|
|
937
1082
|
] }),
|
|
938
|
-
mode === "new" && /* @__PURE__ */
|
|
939
|
-
/* @__PURE__ */
|
|
940
|
-
/* @__PURE__ */
|
|
1083
|
+
mode === "new" && /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
1084
|
+
/* @__PURE__ */ jsx("label", { className: "text-sm font-medium", children: "Project name" }),
|
|
1085
|
+
/* @__PURE__ */ jsx(
|
|
941
1086
|
"input",
|
|
942
1087
|
{
|
|
943
1088
|
className: "w-full rounded border px-3 py-2 text-sm",
|
|
@@ -947,10 +1092,10 @@ function ConnectProjectDialog(props) {
|
|
|
947
1092
|
disabled: loading
|
|
948
1093
|
}
|
|
949
1094
|
),
|
|
950
|
-
/* @__PURE__ */
|
|
951
|
-
/* @__PURE__ */
|
|
952
|
-
/* @__PURE__ */
|
|
953
|
-
/* @__PURE__ */
|
|
1095
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "A project will be created in your Upfiles account and an API key generated." }),
|
|
1096
|
+
/* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2 pt-2", children: [
|
|
1097
|
+
/* @__PURE__ */ jsx(Dialog2.Close, { asChild: true, children: /* @__PURE__ */ jsx("button", { type: "button", className: "px-3 py-2 text-sm rounded border", children: "Cancel" }) }),
|
|
1098
|
+
/* @__PURE__ */ jsx(
|
|
954
1099
|
"button",
|
|
955
1100
|
{
|
|
956
1101
|
type: "button",
|
|
@@ -976,7 +1121,7 @@ async function fetchFileThumbnails(clientOptions, fileKey) {
|
|
|
976
1121
|
return client.getThumbnails(fileKey);
|
|
977
1122
|
}
|
|
978
1123
|
async function fetchProjectImagesWithThumbs(clientOptions, opts) {
|
|
979
|
-
const files = await fetchProjectFiles(clientOptions, opts?.folderPath);
|
|
1124
|
+
const { files, updatedAt } = await fetchProjectFiles(clientOptions, opts?.folderPath);
|
|
980
1125
|
const limit = Math.max(1, Math.min(opts?.limitConcurrent ?? 6, 12));
|
|
981
1126
|
const queue = [...files];
|
|
982
1127
|
const results = [];
|
|
@@ -998,13 +1143,62 @@ async function fetchProjectImagesWithThumbs(clientOptions, opts) {
|
|
|
998
1143
|
await Promise.all(Array.from({ length: workers }, () => worker()));
|
|
999
1144
|
const keyToIndex = new Map(files.map((f2, i) => [f2.key, i]));
|
|
1000
1145
|
results.sort((a, b) => (keyToIndex.get(a.key) ?? 0) - (keyToIndex.get(b.key) ?? 0));
|
|
1001
|
-
return results;
|
|
1146
|
+
return { items: results, updatedAt };
|
|
1002
1147
|
}
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1148
|
+
var IconGrid = ({ className }) => /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
|
|
1149
|
+
/* @__PURE__ */ jsx("rect", { width: "7", height: "7", x: "3", y: "3", rx: "1" }),
|
|
1150
|
+
/* @__PURE__ */ jsx("rect", { width: "7", height: "7", x: "14", y: "3", rx: "1" }),
|
|
1151
|
+
/* @__PURE__ */ jsx("rect", { width: "7", height: "7", x: "14", y: "14", rx: "1" }),
|
|
1152
|
+
/* @__PURE__ */ jsx("rect", { width: "7", height: "7", x: "3", y: "14", rx: "1" })
|
|
1153
|
+
] });
|
|
1154
|
+
var IconUploadCloud = ({ className }) => /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
|
|
1155
|
+
/* @__PURE__ */ jsx("path", { d: "M4 14.899A7 7 0 1 1 15.71 8h1.79a4.5 4.5 0 0 1 2.5 8.242" }),
|
|
1156
|
+
/* @__PURE__ */ jsx("path", { d: "M12 12v9" }),
|
|
1157
|
+
/* @__PURE__ */ jsx("path", { d: "m16 16-4-4-4 4" })
|
|
1158
|
+
] });
|
|
1159
|
+
var IconFolder = ({ className }) => /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "currentColor", stroke: "currentColor", strokeWidth: "0", className, children: /* @__PURE__ */ jsx("path", { d: "M19.5 21a3 3 0 0 0 3-3v-4.5a3 3 0 0 0-3-3h-15a3 3 0 0 0-3 3V18a3 3 0 0 0 3 3h15ZM1.5 10.146V6a3 3 0 0 1 3-3h5.379a2.25 2.25 0 0 1 1.59.659l2.122 2.121c.14.141.331.22.53.22H19.5a3 3 0 0 1 3 3v1.146A4.483 4.483 0 0 0 19.5 9h-15a4.483 4.483 0 0 0-3 1.146Z" }) });
|
|
1160
|
+
var IconFolderPlus = ({ className }) => /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
|
|
1161
|
+
/* @__PURE__ */ jsx("path", { d: "M4 20h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.93a2 2 0 0 1-1.66-.9l-.82-1.2A2 2 0 0 0 7.93 2H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2Z" }),
|
|
1162
|
+
/* @__PURE__ */ jsx("line", { x1: "12", x2: "12", y1: "10", y2: "16" }),
|
|
1163
|
+
/* @__PURE__ */ jsx("line", { x1: "9", x2: "15", y1: "13", y2: "13" })
|
|
1164
|
+
] });
|
|
1165
|
+
var IconSearch = ({ className }) => /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
|
|
1166
|
+
/* @__PURE__ */ jsx("circle", { cx: "11", cy: "11", r: "8" }),
|
|
1167
|
+
/* @__PURE__ */ jsx("path", { d: "m21 21-4.3-4.3" })
|
|
1168
|
+
] });
|
|
1169
|
+
var IconRefresh = ({ className }) => /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
|
|
1170
|
+
/* @__PURE__ */ jsx("path", { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8" }),
|
|
1171
|
+
/* @__PURE__ */ jsx("path", { d: "M21 3v5h-5" }),
|
|
1172
|
+
/* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16" }),
|
|
1173
|
+
/* @__PURE__ */ jsx("path", { d: "M8 16H3v5" })
|
|
1174
|
+
] });
|
|
1175
|
+
var IconChevronRight = ({ className }) => /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: /* @__PURE__ */ jsx("path", { d: "m9 18 6-6-6-6" }) });
|
|
1176
|
+
var IconTrash = ({ className }) => /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
|
|
1177
|
+
/* @__PURE__ */ jsx("path", { d: "M3 6h18" }),
|
|
1178
|
+
/* @__PURE__ */ jsx("path", { d: "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" }),
|
|
1179
|
+
/* @__PURE__ */ jsx("path", { d: "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" }),
|
|
1180
|
+
/* @__PURE__ */ jsx("line", { x1: "10", x2: "10", y1: "11", y2: "17" }),
|
|
1181
|
+
/* @__PURE__ */ jsx("line", { x1: "14", x2: "14", y1: "11", y2: "17" })
|
|
1182
|
+
] });
|
|
1183
|
+
var IconX = ({ className }) => /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
|
|
1184
|
+
/* @__PURE__ */ jsx("path", { d: "M18 6 6 18" }),
|
|
1185
|
+
/* @__PURE__ */ jsx("path", { d: "m6 6 12 12" })
|
|
1186
|
+
] });
|
|
1187
|
+
var IconHome = ({ className }) => /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
|
|
1188
|
+
/* @__PURE__ */ jsx("path", { d: "m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" }),
|
|
1189
|
+
/* @__PURE__ */ jsx("polyline", { points: "9 22 9 12 15 12 15 22" })
|
|
1190
|
+
] });
|
|
1191
|
+
var IconImage = ({ className }) => /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
|
|
1192
|
+
/* @__PURE__ */ jsx("rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2" }),
|
|
1193
|
+
/* @__PURE__ */ jsx("circle", { cx: "9", cy: "9", r: "2" }),
|
|
1194
|
+
/* @__PURE__ */ jsx("path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21" })
|
|
1195
|
+
] });
|
|
1196
|
+
var IconLoader = ({ className }) => /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: /* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }) });
|
|
1197
|
+
var IconLayers = ({ className }) => /* @__PURE__ */ jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
|
|
1198
|
+
/* @__PURE__ */ jsx("polygon", { points: "12 2 2 7 12 12 22 7 12 2" }),
|
|
1199
|
+
/* @__PURE__ */ jsx("polyline", { points: "2 17 12 22 22 17" }),
|
|
1200
|
+
/* @__PURE__ */ jsx("polyline", { points: "2 12 12 17 22 12" })
|
|
1201
|
+
] });
|
|
1008
1202
|
function ImageManager(props) {
|
|
1009
1203
|
const {
|
|
1010
1204
|
open,
|
|
@@ -1024,223 +1218,733 @@ function ImageManager(props) {
|
|
|
1024
1218
|
maxFileSize = 100 * 1024 * 1024,
|
|
1025
1219
|
maxFiles = 10,
|
|
1026
1220
|
mode = "full",
|
|
1027
|
-
showDelete = true
|
|
1221
|
+
showDelete = true,
|
|
1222
|
+
refreshInterval = 5e3
|
|
1028
1223
|
} = props;
|
|
1029
|
-
const [
|
|
1224
|
+
const [activeView, setActiveView] = React4.useState(mode === "upload" ? "upload" : "browse");
|
|
1030
1225
|
const [loading, setLoading] = React4.useState(false);
|
|
1031
1226
|
const [error, setError] = React4.useState(null);
|
|
1032
|
-
const [
|
|
1227
|
+
const [currentFolderId, setCurrentFolderId] = React4.useState(void 0);
|
|
1228
|
+
const [breadcrumbs, setBreadcrumbs] = React4.useState([{ id: void 0, name: "Home" }]);
|
|
1229
|
+
const [files, setFiles] = React4.useState([]);
|
|
1230
|
+
const [folders, setFolders] = React4.useState([]);
|
|
1033
1231
|
const [query, setQuery] = React4.useState("");
|
|
1034
1232
|
const [deleting, setDeleting] = React4.useState(null);
|
|
1035
|
-
const
|
|
1233
|
+
const [showCreateFolder, setShowCreateFolder] = React4.useState(false);
|
|
1234
|
+
const [newFolderName, setNewFolderName] = React4.useState("");
|
|
1235
|
+
const [creatingFolder, setCreatingFolder] = React4.useState(false);
|
|
1236
|
+
const [fileToDelete, setFileToDelete] = React4.useState(null);
|
|
1237
|
+
const [thumbnailSelectorFile, setThumbnailSelectorFile] = React4.useState(null);
|
|
1238
|
+
const [selectedThumbnailForFile, setSelectedThumbnailForFile] = React4.useState(null);
|
|
1239
|
+
const [previewFile, setPreviewFile] = React4.useState(null);
|
|
1240
|
+
const lastUpdatedRef = React4.useRef(null);
|
|
1241
|
+
const isFetchingRef = React4.useRef(false);
|
|
1242
|
+
const deduplicateFiles = React4.useCallback((files2) => {
|
|
1243
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1244
|
+
return files2.filter((file) => {
|
|
1245
|
+
if (seen.has(file.key)) {
|
|
1246
|
+
return false;
|
|
1247
|
+
}
|
|
1248
|
+
seen.add(file.key);
|
|
1249
|
+
return true;
|
|
1250
|
+
});
|
|
1251
|
+
}, []);
|
|
1252
|
+
const load = React4.useCallback(async (isPolling = false) => {
|
|
1253
|
+
if (isFetchingRef.current) return;
|
|
1254
|
+
isFetchingRef.current = true;
|
|
1036
1255
|
try {
|
|
1037
|
-
setLoading(true);
|
|
1256
|
+
if (!isPolling) setLoading(true);
|
|
1038
1257
|
setError(null);
|
|
1039
|
-
const
|
|
1040
|
-
|
|
1258
|
+
const client = new UpfilesClient(clientOptions);
|
|
1259
|
+
const currentPathPrefix = breadcrumbs.length > 1 ? breadcrumbs.slice(1).map((b) => b.name).join("/") + "/" : void 0;
|
|
1260
|
+
const effectiveFolderPath = currentPathPrefix || folderPath;
|
|
1261
|
+
const [filesData, foldersData] = await Promise.all([
|
|
1262
|
+
fetchProjectImagesWithThumbs(clientOptions, { folderPath: effectiveFolderPath, limitConcurrent: 6 }),
|
|
1263
|
+
client.getFolders(currentFolderId)
|
|
1264
|
+
]);
|
|
1265
|
+
const { items: list, updatedAt } = filesData;
|
|
1266
|
+
if (isPolling && updatedAt && updatedAt === lastUpdatedRef.current) {
|
|
1267
|
+
}
|
|
1268
|
+
setFiles(deduplicateFiles(list));
|
|
1269
|
+
setFolders(foldersData);
|
|
1270
|
+
lastUpdatedRef.current = updatedAt;
|
|
1041
1271
|
} catch (e) {
|
|
1042
|
-
setError(e?.message || "Failed to load images");
|
|
1272
|
+
if (!isPolling) setError(e?.message || "Failed to load images");
|
|
1043
1273
|
} finally {
|
|
1044
|
-
setLoading(false);
|
|
1274
|
+
if (!isPolling) setLoading(false);
|
|
1275
|
+
isFetchingRef.current = false;
|
|
1045
1276
|
}
|
|
1046
|
-
}, [clientOptions, folderPath]);
|
|
1277
|
+
}, [clientOptions, folderPath, currentFolderId, breadcrumbs]);
|
|
1047
1278
|
React4.useEffect(() => {
|
|
1048
1279
|
if (!open) {
|
|
1049
|
-
|
|
1280
|
+
setFiles([]);
|
|
1281
|
+
setFolders([]);
|
|
1050
1282
|
setQuery("");
|
|
1051
1283
|
setError(null);
|
|
1284
|
+
lastUpdatedRef.current = null;
|
|
1052
1285
|
return;
|
|
1053
1286
|
}
|
|
1054
|
-
if (mode !== "upload" &&
|
|
1287
|
+
if (mode !== "upload" && activeView === "browse") {
|
|
1055
1288
|
load();
|
|
1056
1289
|
}
|
|
1057
|
-
}, [open,
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
if (!confirm("Delete this file?")) return;
|
|
1290
|
+
}, [open, activeView, load, mode]);
|
|
1291
|
+
React4.useEffect(() => {
|
|
1292
|
+
if (!open) return;
|
|
1293
|
+
const client = new UpfilesClient(clientOptions);
|
|
1294
|
+
const url = client.getEventsUrl(projectId);
|
|
1295
|
+
const eventSource = new EventSource(url);
|
|
1296
|
+
eventSource.onmessage = (event) => {
|
|
1065
1297
|
try {
|
|
1066
|
-
|
|
1067
|
-
if (
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
const headers = {
|
|
1073
|
-
"content-type": "application/json",
|
|
1074
|
-
...clientOptions?.headers || {}
|
|
1075
|
-
};
|
|
1076
|
-
if (clientOptions?.apiKey) {
|
|
1077
|
-
const keyHeader = clientOptions.apiKeyHeader || "authorization";
|
|
1078
|
-
if (keyHeader === "authorization") {
|
|
1079
|
-
headers["authorization"] = clientOptions.apiKey.startsWith("upk_") ? `Bearer ${clientOptions.apiKey}` : clientOptions.apiKey;
|
|
1080
|
-
} else {
|
|
1081
|
-
headers[keyHeader] = clientOptions.apiKey;
|
|
1082
|
-
}
|
|
1083
|
-
}
|
|
1084
|
-
const res = await fetch(url, {
|
|
1085
|
-
method: "DELETE",
|
|
1086
|
-
headers,
|
|
1087
|
-
credentials: clientOptions?.withCredentials ? "include" : "same-origin",
|
|
1088
|
-
body: JSON.stringify({ fileKey: key })
|
|
1298
|
+
const payload = JSON.parse(event.data);
|
|
1299
|
+
if (payload.type === "file:uploaded") {
|
|
1300
|
+
const newFile = payload.data.file;
|
|
1301
|
+
setFiles((prev) => {
|
|
1302
|
+
if (prev.find((f2) => f2.key === newFile.key)) return prev;
|
|
1303
|
+
return deduplicateFiles([newFile, ...prev]);
|
|
1089
1304
|
});
|
|
1090
|
-
|
|
1305
|
+
} else if (payload.type === "file:deleted") {
|
|
1306
|
+
const deletedKey = payload.data.fileKey || payload.data.file?.key;
|
|
1307
|
+
setFiles((prev) => prev.filter((f2) => f2.key !== deletedKey));
|
|
1091
1308
|
}
|
|
1092
|
-
setItems((prev) => prev.filter((f2) => f2.key !== key));
|
|
1093
1309
|
} catch (e) {
|
|
1094
|
-
|
|
1095
|
-
} finally {
|
|
1096
|
-
setDeleting(null);
|
|
1310
|
+
console.error("SSE Error parsing message", e);
|
|
1097
1311
|
}
|
|
1098
|
-
}
|
|
1099
|
-
|
|
1100
|
-
);
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1312
|
+
};
|
|
1313
|
+
return () => eventSource.close();
|
|
1314
|
+
}, [open, clientOptions, projectId]);
|
|
1315
|
+
const visibleFiles = React4.useMemo(() => {
|
|
1316
|
+
const q = query.trim().toLowerCase();
|
|
1317
|
+
return !q ? files : files.filter((i) => (i.originalName || "").toLowerCase().includes(q));
|
|
1318
|
+
}, [files, query]);
|
|
1319
|
+
const visibleFolders = React4.useMemo(() => {
|
|
1320
|
+
const q = query.trim().toLowerCase();
|
|
1321
|
+
return !q ? folders : folders.filter((f2) => (f2.name || "").toLowerCase().includes(q));
|
|
1322
|
+
}, [folders, query]);
|
|
1323
|
+
const handleDelete = async () => {
|
|
1324
|
+
if (!fileToDelete) return;
|
|
1325
|
+
const key = fileToDelete.key;
|
|
1326
|
+
try {
|
|
1327
|
+
setDeleting(key);
|
|
1328
|
+
if (onDelete) {
|
|
1329
|
+
await onDelete(key);
|
|
1330
|
+
} else {
|
|
1331
|
+
const client = new UpfilesClient(clientOptions);
|
|
1332
|
+
const baseUrl = clientOptions?.baseUrl || "";
|
|
1333
|
+
const url = baseUrl ? `${baseUrl}${deleteUrl}` : deleteUrl;
|
|
1334
|
+
const headers = {
|
|
1335
|
+
"content-type": "application/json",
|
|
1336
|
+
...clientOptions?.headers || {}
|
|
1337
|
+
};
|
|
1338
|
+
if (clientOptions?.apiKey) {
|
|
1339
|
+
const keyHeader = clientOptions.apiKeyHeader || "authorization";
|
|
1340
|
+
if (keyHeader === "authorization") {
|
|
1341
|
+
headers["authorization"] = clientOptions.apiKey.startsWith("upk_") ? `Bearer ${clientOptions.apiKey}` : clientOptions.apiKey;
|
|
1342
|
+
} else {
|
|
1343
|
+
headers[keyHeader] = clientOptions.apiKey;
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
const res = await fetch(url, {
|
|
1347
|
+
method: "DELETE",
|
|
1348
|
+
headers,
|
|
1349
|
+
credentials: clientOptions?.withCredentials ? "include" : "same-origin",
|
|
1350
|
+
body: JSON.stringify({ fileKey: key })
|
|
1351
|
+
});
|
|
1352
|
+
if (!res.ok) throw new Error("Delete failed");
|
|
1353
|
+
}
|
|
1354
|
+
setFiles((prev) => prev.filter((f2) => f2.key !== key));
|
|
1355
|
+
setFileToDelete(null);
|
|
1356
|
+
} catch (e) {
|
|
1357
|
+
alert(e?.message || "Failed to delete");
|
|
1358
|
+
} finally {
|
|
1359
|
+
setDeleting(null);
|
|
1360
|
+
}
|
|
1361
|
+
};
|
|
1362
|
+
const handleCreateFolder = async () => {
|
|
1363
|
+
if (!newFolderName.trim()) return;
|
|
1364
|
+
setCreatingFolder(true);
|
|
1365
|
+
try {
|
|
1366
|
+
const client = new UpfilesClient(clientOptions);
|
|
1367
|
+
await client.createFolder(newFolderName, currentFolderId);
|
|
1368
|
+
setNewFolderName("");
|
|
1369
|
+
setShowCreateFolder(false);
|
|
1370
|
+
load();
|
|
1371
|
+
} catch (e) {
|
|
1372
|
+
alert(e.message || "Failed to create folder");
|
|
1373
|
+
} finally {
|
|
1374
|
+
setCreatingFolder(false);
|
|
1375
|
+
}
|
|
1376
|
+
};
|
|
1377
|
+
const handleNavigate = (folder) => {
|
|
1378
|
+
setCurrentFolderId(folder.id);
|
|
1379
|
+
setBreadcrumbs((prev) => [...prev, { id: folder.id, name: folder.name }]);
|
|
1380
|
+
setQuery("");
|
|
1381
|
+
};
|
|
1382
|
+
const handleBreadcrumbClick = (index) => {
|
|
1383
|
+
const target = breadcrumbs[index];
|
|
1384
|
+
setBreadcrumbs(breadcrumbs.slice(0, index + 1));
|
|
1385
|
+
setCurrentFolderId(target.id);
|
|
1386
|
+
setQuery("");
|
|
1387
|
+
};
|
|
1388
|
+
const uploadFoldersList = React4.useMemo(() => {
|
|
1389
|
+
const options = [];
|
|
1390
|
+
options.push({ id: "root", name: "Root ( / )", path: void 0 });
|
|
1391
|
+
if (currentFolderId) {
|
|
1392
|
+
const currentPath = breadcrumbs.slice(1).map((b) => b.name).join("/") + "/";
|
|
1393
|
+
options.push({ id: "current", name: `Current ( ${breadcrumbs[breadcrumbs.length - 1].name} )`, path: currentPath });
|
|
1394
|
+
}
|
|
1395
|
+
folders.forEach((f2) => {
|
|
1396
|
+
const parentPath = breadcrumbs.length > 1 ? breadcrumbs.slice(1).map((b) => b.name).join("/") + "/" : "";
|
|
1397
|
+
options.push({ id: f2.id, name: f2.name, path: parentPath + f2.name + "/" });
|
|
1398
|
+
});
|
|
1399
|
+
return options;
|
|
1400
|
+
}, [breadcrumbs, currentFolderId, folders]);
|
|
1401
|
+
const [selectedUploadFolder, setSelectedUploadFolder] = React4.useState("current");
|
|
1402
|
+
const activeBreadcrumbPath = React4.useMemo(() => {
|
|
1403
|
+
return breadcrumbs.length > 1 ? breadcrumbs.slice(1).map((b) => b.name).join("/") + "/" : void 0;
|
|
1404
|
+
}, [breadcrumbs]);
|
|
1405
|
+
return /* @__PURE__ */ jsxs(Dialog2.Root, { open, onOpenChange, children: [
|
|
1406
|
+
/* @__PURE__ */ jsxs(Dialog2.Portal, { children: [
|
|
1407
|
+
/* @__PURE__ */ jsx(Dialog2.Overlay, { className: "fixed inset-0 bg-black/60 backdrop-blur-sm z-50 transition-all duration-300 flex items-center justify-center" }),
|
|
1408
|
+
/* @__PURE__ */ jsxs(
|
|
1409
|
+
Dialog2.Content,
|
|
1410
|
+
{
|
|
1411
|
+
className: `fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-[95vw] h-[90vh] max-w-7xl min-w-[800px] min-h-[600px] rounded-2xl bg-white dark:bg-gray-950 shadow-2xl z-[51] overflow-hidden flex flex-row ${className ?? ""}`,
|
|
1412
|
+
children: [
|
|
1413
|
+
/* @__PURE__ */ jsx(
|
|
1414
|
+
Dialog2.Title,
|
|
1113
1415
|
{
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1416
|
+
style: {
|
|
1417
|
+
position: "absolute",
|
|
1418
|
+
width: "1px",
|
|
1419
|
+
height: "1px",
|
|
1420
|
+
padding: "0",
|
|
1421
|
+
margin: "-1px",
|
|
1422
|
+
overflow: "hidden",
|
|
1423
|
+
clip: "rect(0, 0, 0, 0)",
|
|
1424
|
+
whiteSpace: "nowrap",
|
|
1425
|
+
border: "0"
|
|
1426
|
+
},
|
|
1427
|
+
children: title ?? "Media Library"
|
|
1118
1428
|
}
|
|
1119
1429
|
),
|
|
1120
|
-
/* @__PURE__ */
|
|
1121
|
-
"
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
children: "
|
|
1127
|
-
}
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1430
|
+
/* @__PURE__ */ jsxs("div", { className: "w-64 min-w-[256px] bg-gray-50 dark:bg-gray-900 border-r border-gray-200 dark:border-gray-800 flex flex-col flex-shrink-0", children: [
|
|
1431
|
+
/* @__PURE__ */ jsxs("div", { className: "p-6", children: [
|
|
1432
|
+
/* @__PURE__ */ jsxs("h2", { className: "text-lg font-bold text-gray-900 dark:text-white flex items-center gap-2", children: [
|
|
1433
|
+
/* @__PURE__ */ jsx(IconImage, { className: "text-blue-600" }),
|
|
1434
|
+
title ?? "Media Library"
|
|
1435
|
+
] }),
|
|
1436
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 mt-1", children: description ?? "Manage your assets" })
|
|
1437
|
+
] }),
|
|
1438
|
+
/* @__PURE__ */ jsxs("nav", { className: "flex-1 px-3 space-y-1", children: [
|
|
1439
|
+
/* @__PURE__ */ jsxs(
|
|
1440
|
+
"button",
|
|
1441
|
+
{
|
|
1442
|
+
onClick: () => setActiveView("browse"),
|
|
1443
|
+
className: `w-full flex items-center gap-3 px-3 py-2.5 text-sm font-medium rounded-lg transition-colors ${activeView === "browse" ? "bg-white dark:bg-gray-800 text-blue-600 dark:text-blue-400 shadow-sm" : "text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800"}`,
|
|
1444
|
+
children: [
|
|
1445
|
+
/* @__PURE__ */ jsx(IconGrid, { className: "w-4 h-4" }),
|
|
1446
|
+
"All Files"
|
|
1447
|
+
]
|
|
1448
|
+
}
|
|
1449
|
+
),
|
|
1450
|
+
mode === "full" && /* @__PURE__ */ jsxs(
|
|
1451
|
+
"button",
|
|
1452
|
+
{
|
|
1453
|
+
onClick: () => setActiveView("upload"),
|
|
1454
|
+
className: `w-full flex items-center gap-3 px-3 py-2.5 text-sm font-medium rounded-lg transition-colors ${activeView === "upload" ? "bg-white dark:bg-gray-800 text-blue-600 dark:text-blue-400 shadow-sm" : "text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800"}`,
|
|
1455
|
+
children: [
|
|
1456
|
+
/* @__PURE__ */ jsx(IconUploadCloud, { className: "w-4 h-4" }),
|
|
1457
|
+
"Upload New"
|
|
1458
|
+
]
|
|
1459
|
+
}
|
|
1460
|
+
)
|
|
1461
|
+
] }),
|
|
1462
|
+
/* @__PURE__ */ jsx("div", { className: "p-4 border-t border-gray-200 dark:border-gray-800", children: /* @__PURE__ */ jsxs("div", { className: "text-xs text-center text-gray-400", children: [
|
|
1463
|
+
files.length,
|
|
1464
|
+
" files \u2022 ",
|
|
1465
|
+
folders.length,
|
|
1466
|
+
" folders"
|
|
1467
|
+
] }) })
|
|
1142
1468
|
] }),
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1469
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col bg-white dark:bg-gray-950 relative", children: [
|
|
1470
|
+
/* @__PURE__ */ jsxs("div", { className: "h-16 border-b border-gray-100 dark:border-gray-800 flex items-center justify-between px-6 gap-4", children: [
|
|
1471
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-4 flex-1", children: activeView === "browse" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1472
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center text-sm text-gray-500 overflow-hidden whitespace-nowrap", children: [
|
|
1473
|
+
/* @__PURE__ */ jsx("button", { onClick: () => handleBreadcrumbClick(0), className: "hover:text-blue-600 transition-colors", children: /* @__PURE__ */ jsx(IconHome, { className: "w-4 h-4" }) }),
|
|
1474
|
+
breadcrumbs.slice(1).map((b, i) => /* @__PURE__ */ jsxs(React4.Fragment, { children: [
|
|
1475
|
+
/* @__PURE__ */ jsx(IconChevronRight, { className: "w-4 h-4 text-gray-300 mx-1" }),
|
|
1476
|
+
/* @__PURE__ */ jsx(
|
|
1477
|
+
"button",
|
|
1478
|
+
{
|
|
1479
|
+
onClick: () => handleBreadcrumbClick(i + 1),
|
|
1480
|
+
className: `hover:text-blue-600 transition-colors truncate max-w-[100px] ${i === breadcrumbs.length - 2 ? "font-semibold text-gray-900 dark:text-white" : ""}`,
|
|
1481
|
+
children: b.name
|
|
1482
|
+
}
|
|
1483
|
+
)
|
|
1484
|
+
] }, `${b.id || "breadcrumb"}-${i}`))
|
|
1485
|
+
] }),
|
|
1486
|
+
/* @__PURE__ */ jsx("div", { className: "h-4 w-px bg-gray-200 dark:bg-gray-700 mx-2" }),
|
|
1487
|
+
/* @__PURE__ */ jsx(
|
|
1488
|
+
"button",
|
|
1489
|
+
{
|
|
1490
|
+
onClick: () => load(),
|
|
1491
|
+
disabled: loading,
|
|
1492
|
+
className: "p-1.5 text-gray-400 hover:text-blue-600 hover:bg-blue-50 dark:hover:bg-blue-900/20 rounded-md transition-all disabled:opacity-50",
|
|
1493
|
+
title: "Refresh",
|
|
1494
|
+
children: /* @__PURE__ */ jsx(IconRefresh, { className: `w-4 h-4 ${loading ? "animate-spin" : ""}` })
|
|
1495
|
+
}
|
|
1496
|
+
),
|
|
1497
|
+
/* @__PURE__ */ jsx("div", { className: "h-4 w-px bg-gray-200 dark:bg-gray-700 mx-2" }),
|
|
1498
|
+
/* @__PURE__ */ jsxs("div", { className: "relative flex-1 max-w-sm group", children: [
|
|
1499
|
+
/* @__PURE__ */ jsx(IconSearch, { className: "absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400 group-focus-within:text-blue-500 transition-colors" }),
|
|
1500
|
+
/* @__PURE__ */ jsx(
|
|
1501
|
+
"input",
|
|
1171
1502
|
{
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
className: "
|
|
1176
|
-
children: deleting === f2.key ? "..." : "Delete"
|
|
1503
|
+
value: query,
|
|
1504
|
+
onChange: (e) => setQuery(e.target.value),
|
|
1505
|
+
placeholder: "Search files...",
|
|
1506
|
+
className: "w-full pl-9 pr-4 py-1.5 bg-gray-50 dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-all"
|
|
1177
1507
|
}
|
|
1178
1508
|
)
|
|
1509
|
+
] })
|
|
1510
|
+
] }) }),
|
|
1511
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1512
|
+
activeView === "browse" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1513
|
+
/* @__PURE__ */ jsx("button", { onClick: () => setShowCreateFolder(true), className: "p-2 text-gray-400 hover:text-blue-600 hover:bg-blue-50 dark:hover:bg-blue-900/10 rounded-lg transition-colors", title: "New Folder", children: /* @__PURE__ */ jsx(IconFolderPlus, { className: "w-5 h-5" }) }),
|
|
1514
|
+
/* @__PURE__ */ jsx("button", { onClick: () => load(), className: `p-2 text-gray-400 hover:text-blue-600 hover:bg-blue-50 dark:hover:bg-blue-900/10 rounded-lg transition-colors ${loading ? "animate-spin text-blue-600" : ""}`, title: "Refresh", children: /* @__PURE__ */ jsx(IconLoader, { className: "w-5 h-5" }) })
|
|
1515
|
+
] }),
|
|
1516
|
+
/* @__PURE__ */ jsx(Dialog2.Close, { asChild: true, children: /* @__PURE__ */ jsx("button", { className: "ml-2 p-2 text-gray-400 hover:text-red-500 hover:bg-red-50 dark:hover:bg-red-900/10 rounded-lg transition-colors", children: /* @__PURE__ */ jsx(IconX, { className: "w-5 h-5" }) }) })
|
|
1517
|
+
] })
|
|
1518
|
+
] }),
|
|
1519
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto p-6 bg-gray-50/30 dark:bg-gray-900/30", children: [
|
|
1520
|
+
activeView === "browse" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1521
|
+
error && /* @__PURE__ */ jsx("div", { className: "mb-6 bg-red-50 text-red-600 p-4 rounded-lg text-sm border border-red-100 flex items-center gap-2", children: /* @__PURE__ */ jsx("span", { children: error }) }),
|
|
1522
|
+
/* @__PURE__ */ jsxs("div", { className: gridClassName ?? "grid grid-cols-2 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 gap-6", children: [
|
|
1523
|
+
visibleFolders.map((folder) => /* @__PURE__ */ jsxs(
|
|
1524
|
+
"div",
|
|
1525
|
+
{
|
|
1526
|
+
onClick: () => handleNavigate(folder),
|
|
1527
|
+
className: "group flex flex-col items-center gap-3 p-4 rounded-xl border border-gray-200/60 bg-white hover:border-blue-200 hover:shadow-lg hover:shadow-blue-500/5 hover:-translate-y-1 transition-all cursor-pointer",
|
|
1528
|
+
children: [
|
|
1529
|
+
/* @__PURE__ */ jsx("div", { className: "w-16 h-12 bg-blue-50 rounded-lg flex items-center justify-center text-blue-500 group-hover:scale-110 transition-transform", children: /* @__PURE__ */ jsx(IconFolder, { className: "w-8 h-8 drop-shadow-sm" }) }),
|
|
1530
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-gray-700 truncate w-full text-center", children: folder.name })
|
|
1531
|
+
]
|
|
1532
|
+
},
|
|
1533
|
+
folder.id
|
|
1534
|
+
)),
|
|
1535
|
+
visibleFiles.map((f2) => {
|
|
1536
|
+
const fWithThumbs = f2;
|
|
1537
|
+
const bestThumb = fWithThumbs.thumbnails?.sort((a, b) => a.size - b.size).find((t) => t.size >= 300) || fWithThumbs.thumbnails?.[fWithThumbs.thumbnails?.length - 1];
|
|
1538
|
+
const thumbUrl = bestThumb?.url || f2.url;
|
|
1539
|
+
return /* @__PURE__ */ jsxs(
|
|
1540
|
+
"div",
|
|
1541
|
+
{
|
|
1542
|
+
onClick: () => setPreviewFile(f2),
|
|
1543
|
+
className: "group relative aspect-[4/3] bg-white rounded-xl border border-gray-200 overflow-hidden shadow-sm hover:shadow-xl hover:shadow-gray-200/50 hover:border-blue-300 transition-all duration-300 cursor-pointer",
|
|
1544
|
+
children: [
|
|
1545
|
+
/* @__PURE__ */ jsx("img", { src: thumbUrl, alt: f2.originalName, className: "w-full h-full object-cover transition-transform duration-700 group-hover:scale-105" }),
|
|
1546
|
+
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-black/40 opacity-0 group-hover:opacity-100 transition-opacity duration-200 flex flex-col justify-end p-3", children: /* @__PURE__ */ jsxs("div", { className: "flex gap-2 justify-center transform translate-y-2 group-hover:translate-y-0 transition-transform duration-300", children: [
|
|
1547
|
+
/* @__PURE__ */ jsx(
|
|
1548
|
+
"button",
|
|
1549
|
+
{
|
|
1550
|
+
onClick: (e) => {
|
|
1551
|
+
e.stopPropagation();
|
|
1552
|
+
onSelect({
|
|
1553
|
+
url: f2.url,
|
|
1554
|
+
key: f2.key,
|
|
1555
|
+
originalName: f2.originalName,
|
|
1556
|
+
size: f2.size,
|
|
1557
|
+
contentType: f2.contentType,
|
|
1558
|
+
thumbnails: f2.thumbnails
|
|
1559
|
+
});
|
|
1560
|
+
onOpenChange(false);
|
|
1561
|
+
},
|
|
1562
|
+
className: "px-3 py-1.5 bg-blue-600 text-white text-xs font-semibold rounded-md hover:bg-blue-500 shadow-lg",
|
|
1563
|
+
children: "Select"
|
|
1564
|
+
}
|
|
1565
|
+
),
|
|
1566
|
+
fWithThumbs.thumbnails && fWithThumbs.thumbnails.length > 0 && /* @__PURE__ */ jsx(
|
|
1567
|
+
"button",
|
|
1568
|
+
{
|
|
1569
|
+
onClick: (e) => {
|
|
1570
|
+
e.stopPropagation();
|
|
1571
|
+
setThumbnailSelectorFile(f2);
|
|
1572
|
+
setSelectedThumbnailForFile(null);
|
|
1573
|
+
},
|
|
1574
|
+
className: "p-1.5 bg-white/20 text-white text-xs font-semibold rounded-md hover:bg-purple-500 backdrop-blur-md transition-colors",
|
|
1575
|
+
title: "Select Thumbnail",
|
|
1576
|
+
children: /* @__PURE__ */ jsx(IconLayers, { className: "w-4 h-4" })
|
|
1577
|
+
}
|
|
1578
|
+
),
|
|
1579
|
+
showDelete && /* @__PURE__ */ jsx(
|
|
1580
|
+
"button",
|
|
1581
|
+
{
|
|
1582
|
+
onClick: (e) => {
|
|
1583
|
+
e.stopPropagation();
|
|
1584
|
+
setFileToDelete(f2);
|
|
1585
|
+
},
|
|
1586
|
+
className: "p-1.5 bg-white/20 text-white text-xs font-semibold rounded-md hover:bg-red-500 backdrop-blur-md transition-colors",
|
|
1587
|
+
children: /* @__PURE__ */ jsx(IconTrash, { className: "w-4 h-4" })
|
|
1588
|
+
}
|
|
1589
|
+
)
|
|
1590
|
+
] }) }),
|
|
1591
|
+
/* @__PURE__ */ jsx("div", { className: "absolute top-2 right-2 bg-black/50 backdrop-blur-md text-white text-[10px] px-1.5 py-0.5 rounded opacity-0 group-hover:opacity-100 transition-opacity", children: f2.originalName.split(".").pop()?.toUpperCase() })
|
|
1592
|
+
]
|
|
1593
|
+
},
|
|
1594
|
+
f2.key
|
|
1595
|
+
);
|
|
1596
|
+
})
|
|
1597
|
+
] }),
|
|
1598
|
+
!loading && visibleFolders.length === 0 && visibleFiles.length === 0 && /* @__PURE__ */ jsxs("div", { className: "h-full flex flex-col items-center justify-center text-gray-400", children: [
|
|
1599
|
+
/* @__PURE__ */ jsx("div", { className: "w-16 h-16 bg-gray-100 rounded-2xl flex items-center justify-center mb-4", children: /* @__PURE__ */ jsx(IconSearch, { className: "w-8 h-8 opacity-40" }) }),
|
|
1600
|
+
/* @__PURE__ */ jsx("h3", { className: "text-gray-900 font-medium mb-1", children: "No Assets Found" }),
|
|
1601
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm", children: "Try uploading a file or creating a new folder." })
|
|
1602
|
+
] })
|
|
1603
|
+
] }),
|
|
1604
|
+
activeView === "upload" && /* @__PURE__ */ jsx("div", { className: "h-full flex flex-col items-center justify-center max-w-2xl mx-auto", children: /* @__PURE__ */ jsxs("div", { className: "w-full bg-white rounded-2xl border border-gray-200 p-8 shadow-sm", children: [
|
|
1605
|
+
/* @__PURE__ */ jsxs("h3", { className: "text-lg font-semibold text-gray-900 mb-6 flex items-center gap-2", children: [
|
|
1606
|
+
/* @__PURE__ */ jsx(IconUploadCloud, { className: "text-blue-500" }),
|
|
1607
|
+
"Upload Files"
|
|
1179
1608
|
] }),
|
|
1180
|
-
/* @__PURE__ */
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1609
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-6", children: [
|
|
1610
|
+
/* @__PURE__ */ jsx("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: "Target Folder" }),
|
|
1611
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
1612
|
+
/* @__PURE__ */ jsx(
|
|
1613
|
+
"select",
|
|
1614
|
+
{
|
|
1615
|
+
value: selectedUploadFolder,
|
|
1616
|
+
onChange: (e) => setSelectedUploadFolder(e.target.value),
|
|
1617
|
+
className: "block w-full rounded-lg border-gray-200 bg-gray-50 text-gray-900 text-sm focus:ring-blue-500 focus:border-blue-500 p-2.5",
|
|
1618
|
+
children: uploadFoldersList.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.id, children: opt.name }, opt.id))
|
|
1619
|
+
}
|
|
1620
|
+
),
|
|
1621
|
+
/* @__PURE__ */ jsx("button", { onClick: () => setShowCreateFolder(true), className: "px-3 bg-gray-100 hover:bg-gray-200 rounded-lg text-gray-600 transition-colors", children: /* @__PURE__ */ jsx(IconFolderPlus, { className: "w-5 h-5" }) })
|
|
1622
|
+
] })
|
|
1623
|
+
] }),
|
|
1624
|
+
/* @__PURE__ */ jsx(
|
|
1625
|
+
Uploader,
|
|
1626
|
+
{
|
|
1627
|
+
clientOptions,
|
|
1628
|
+
projectId,
|
|
1629
|
+
folderPath: uploadFoldersList.find((o) => o.id === selectedUploadFolder)?.path || activeBreadcrumbPath || folderPath,
|
|
1630
|
+
accept: ["image/*"],
|
|
1631
|
+
maxFileSize,
|
|
1632
|
+
maxFiles,
|
|
1633
|
+
autoRecordToDb,
|
|
1634
|
+
fetchThumbnails,
|
|
1635
|
+
autoUpload: true,
|
|
1636
|
+
onClientUploadComplete: (file) => {
|
|
1637
|
+
if (file.status === "success" && file.publicUrl && file.fileKey) {
|
|
1638
|
+
const newItem = {
|
|
1639
|
+
key: file.fileKey,
|
|
1640
|
+
originalName: file.name,
|
|
1641
|
+
size: file.size,
|
|
1642
|
+
contentType: file.type,
|
|
1643
|
+
uploadedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1644
|
+
url: file.publicUrl,
|
|
1645
|
+
thumbnails: file.thumbnails
|
|
1646
|
+
};
|
|
1647
|
+
setFiles((prev) => {
|
|
1648
|
+
if (prev.find((f2) => f2.key === newItem.key)) return prev;
|
|
1649
|
+
return deduplicateFiles([newItem, ...prev]);
|
|
1650
|
+
});
|
|
1651
|
+
}
|
|
1652
|
+
},
|
|
1653
|
+
onComplete: () => {
|
|
1654
|
+
if (mode === "full") {
|
|
1655
|
+
setTimeout(() => {
|
|
1656
|
+
setActiveView("browse");
|
|
1657
|
+
load();
|
|
1658
|
+
}, 1e3);
|
|
1659
|
+
}
|
|
1660
|
+
},
|
|
1661
|
+
dropzoneClassName: "border-2 border-dashed border-gray-300 bg-gray-50 rounded-xl p-12 text-center cursor-pointer hover:border-blue-500 hover:bg-blue-50/50 transition-all",
|
|
1662
|
+
buttonClassName: "hidden",
|
|
1663
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-4", children: [
|
|
1664
|
+
/* @__PURE__ */ jsx("div", { className: "w-12 h-12 bg-blue-100 text-blue-600 rounded-full flex items-center justify-center", children: /* @__PURE__ */ jsx(IconUploadCloud, { className: "w-6 h-6" }) }),
|
|
1665
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1666
|
+
/* @__PURE__ */ jsx("p", { className: "text-gray-900 font-medium", children: "Click to upload or drag and drop" }),
|
|
1667
|
+
/* @__PURE__ */ jsxs("p", { className: "text-xs text-gray-500 mt-1", children: [
|
|
1668
|
+
"Supports PNG, JPG, GIF up to ",
|
|
1669
|
+
Math.round(maxFileSize / 1024 / 1024),
|
|
1670
|
+
"MB"
|
|
1671
|
+
] })
|
|
1672
|
+
] })
|
|
1673
|
+
] })
|
|
1674
|
+
}
|
|
1675
|
+
)
|
|
1676
|
+
] }) })
|
|
1677
|
+
] })
|
|
1185
1678
|
] })
|
|
1679
|
+
]
|
|
1680
|
+
}
|
|
1681
|
+
)
|
|
1682
|
+
] }),
|
|
1683
|
+
/* @__PURE__ */ jsx(Dialog2.Root, { open: showCreateFolder, onOpenChange: setShowCreateFolder, children: /* @__PURE__ */ jsxs(Dialog2.Portal, { children: [
|
|
1684
|
+
/* @__PURE__ */ jsx(Dialog2.Overlay, { className: "fixed inset-0 bg-black/40 z-[60]" }),
|
|
1685
|
+
/* @__PURE__ */ jsxs(Dialog2.Content, { className: "fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-full max-w-sm rounded-xl bg-white p-6 shadow-2xl z-[61] outline-none", "aria-describedby": "new-folder-description", children: [
|
|
1686
|
+
/* @__PURE__ */ jsx(Dialog2.Title, { className: "text-lg font-semibold text-gray-900 mb-4", children: "New Folder" }),
|
|
1687
|
+
/* @__PURE__ */ jsx(Dialog2.Description, { id: "new-folder-description", className: "sr-only", children: "Create a new folder to organize your files" }),
|
|
1688
|
+
/* @__PURE__ */ jsx(
|
|
1689
|
+
"input",
|
|
1690
|
+
{
|
|
1691
|
+
autoFocus: true,
|
|
1692
|
+
className: "w-full rounded-lg border border-gray-200 bg-gray-50 px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 outline-none mb-6",
|
|
1693
|
+
placeholder: "Folder Name",
|
|
1694
|
+
value: newFolderName,
|
|
1695
|
+
onChange: (e) => setNewFolderName(e.target.value),
|
|
1696
|
+
onKeyDown: (e) => e.key === "Enter" && handleCreateFolder()
|
|
1697
|
+
}
|
|
1698
|
+
),
|
|
1699
|
+
/* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-3", children: [
|
|
1700
|
+
/* @__PURE__ */ jsx("button", { onClick: () => setShowCreateFolder(false), className: "px-4 py-2 text-sm font-medium text-gray-600 hover:bg-gray-100 rounded-lg", children: "Cancel" }),
|
|
1701
|
+
/* @__PURE__ */ jsx(
|
|
1702
|
+
"button",
|
|
1703
|
+
{
|
|
1704
|
+
onClick: handleCreateFolder,
|
|
1705
|
+
disabled: creatingFolder || !newFolderName.trim(),
|
|
1706
|
+
className: "px-4 py-2 text-sm font-medium rounded-lg bg-blue-600 text-white hover:bg-blue-700 disabled:opacity-50",
|
|
1707
|
+
children: "Create"
|
|
1708
|
+
}
|
|
1709
|
+
)
|
|
1710
|
+
] })
|
|
1711
|
+
] })
|
|
1712
|
+
] }) }),
|
|
1713
|
+
/* @__PURE__ */ jsx(Dialog2.Root, { open: !!fileToDelete, onOpenChange: (open2) => !open2 && setFileToDelete(null), children: /* @__PURE__ */ jsxs(Dialog2.Portal, { children: [
|
|
1714
|
+
/* @__PURE__ */ jsx(Dialog2.Overlay, { className: "fixed inset-0 bg-black/40 z-[80]" }),
|
|
1715
|
+
/* @__PURE__ */ jsxs(Dialog2.Content, { className: "fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-full max-w-md rounded-xl bg-white p-6 shadow-2xl z-[81]", "aria-describedby": "delete-file-description", children: [
|
|
1716
|
+
/* @__PURE__ */ jsx(Dialog2.Title, { className: "text-xl font-semibold text-gray-900 mb-2", children: "Delete File" }),
|
|
1717
|
+
/* @__PURE__ */ jsxs(Dialog2.Description, { id: "delete-file-description", className: "text-gray-600 mb-6", children: [
|
|
1718
|
+
"Are you sure you want to delete ",
|
|
1719
|
+
/* @__PURE__ */ jsxs("span", { className: "font-semibold text-gray-900", children: [
|
|
1720
|
+
'"',
|
|
1721
|
+
fileToDelete?.originalName,
|
|
1722
|
+
'"'
|
|
1186
1723
|
] }),
|
|
1187
|
-
|
|
1188
|
-
|
|
1724
|
+
"?"
|
|
1725
|
+
] }),
|
|
1726
|
+
/* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-3", children: [
|
|
1727
|
+
/* @__PURE__ */ jsx(
|
|
1728
|
+
"button",
|
|
1729
|
+
{
|
|
1730
|
+
onClick: () => setFileToDelete(null),
|
|
1731
|
+
className: "px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-100 rounded-lg",
|
|
1732
|
+
children: "Cancel"
|
|
1733
|
+
}
|
|
1734
|
+
),
|
|
1735
|
+
/* @__PURE__ */ jsx(
|
|
1736
|
+
"button",
|
|
1737
|
+
{
|
|
1738
|
+
onClick: handleDelete,
|
|
1739
|
+
disabled: !!deleting,
|
|
1740
|
+
className: "px-4 py-2 text-sm font-medium rounded-lg bg-red-600 text-white hover:bg-red-700 disabled:opacity-70",
|
|
1741
|
+
children: deleting ? "Deleting..." : "Delete"
|
|
1742
|
+
}
|
|
1743
|
+
)
|
|
1744
|
+
] })
|
|
1745
|
+
] })
|
|
1746
|
+
] }) }),
|
|
1747
|
+
/* @__PURE__ */ jsx(Dialog2.Root, { open: !!thumbnailSelectorFile, onOpenChange: (open2) => !open2 && setThumbnailSelectorFile(null), children: /* @__PURE__ */ jsxs(Dialog2.Portal, { children: [
|
|
1748
|
+
/* @__PURE__ */ jsx(Dialog2.Overlay, { className: "fixed inset-0 bg-black/50 z-[90]" }),
|
|
1749
|
+
/* @__PURE__ */ jsxs(Dialog2.Content, { className: "fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-full max-w-4xl max-h-[80vh] rounded-xl bg-white shadow-2xl z-[91] overflow-hidden", "aria-describedby": "thumbnail-selector-description", children: [
|
|
1750
|
+
/* @__PURE__ */ jsxs("div", { className: "p-6 border-b border-gray-200", children: [
|
|
1751
|
+
/* @__PURE__ */ jsx(Dialog2.Title, { className: "text-xl font-semibold text-gray-900 mb-2", children: "Select Thumbnail" }),
|
|
1752
|
+
/* @__PURE__ */ jsxs(Dialog2.Description, { id: "thumbnail-selector-description", className: "text-gray-600", children: [
|
|
1753
|
+
"Choose a thumbnail size for ",
|
|
1754
|
+
/* @__PURE__ */ jsxs("span", { className: "font-semibold text-gray-900", children: [
|
|
1755
|
+
'"',
|
|
1756
|
+
thumbnailSelectorFile?.originalName,
|
|
1757
|
+
'"'
|
|
1758
|
+
] })
|
|
1759
|
+
] })
|
|
1760
|
+
] }),
|
|
1761
|
+
/* @__PURE__ */ jsx("div", { className: "p-6 overflow-y-auto max-h-[60vh]", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4", children: [
|
|
1762
|
+
/* @__PURE__ */ jsxs(
|
|
1763
|
+
"div",
|
|
1764
|
+
{
|
|
1765
|
+
onClick: () => setSelectedThumbnailForFile(null),
|
|
1766
|
+
className: `group cursor-pointer rounded-lg border-2 overflow-hidden transition-all ${selectedThumbnailForFile === null ? "border-blue-500 ring-2 ring-blue-200" : "border-gray-200 hover:border-blue-300"}`,
|
|
1767
|
+
children: [
|
|
1768
|
+
/* @__PURE__ */ jsxs("div", { className: "aspect-square bg-gray-100 flex items-center justify-center relative", children: [
|
|
1769
|
+
/* @__PURE__ */ jsx(
|
|
1770
|
+
"img",
|
|
1771
|
+
{
|
|
1772
|
+
src: thumbnailSelectorFile?.url,
|
|
1773
|
+
alt: "Original",
|
|
1774
|
+
className: "w-full h-full object-cover"
|
|
1775
|
+
}
|
|
1776
|
+
),
|
|
1777
|
+
selectedThumbnailForFile === null && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-blue-500/20 flex items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: "w-6 h-6 bg-blue-500 rounded-full flex items-center justify-center", children: /* @__PURE__ */ jsx("svg", { className: "w-4 h-4 text-white", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx("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" }) }) }) })
|
|
1778
|
+
] }),
|
|
1779
|
+
/* @__PURE__ */ jsxs("div", { className: "p-3 bg-white", children: [
|
|
1780
|
+
/* @__PURE__ */ jsx("div", { className: "font-medium text-sm text-gray-900", children: "Original" }),
|
|
1781
|
+
/* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500", children: "Full size" })
|
|
1782
|
+
] })
|
|
1783
|
+
]
|
|
1784
|
+
}
|
|
1785
|
+
),
|
|
1786
|
+
thumbnailSelectorFile?.thumbnails?.map((thumbnail) => /* @__PURE__ */ jsxs(
|
|
1787
|
+
"div",
|
|
1788
|
+
{
|
|
1789
|
+
onClick: () => setSelectedThumbnailForFile(thumbnail),
|
|
1790
|
+
className: `group cursor-pointer rounded-lg border-2 overflow-hidden transition-all ${selectedThumbnailForFile?.id === thumbnail.id ? "border-blue-500 ring-2 ring-blue-200" : "border-gray-200 hover:border-blue-300"}`,
|
|
1791
|
+
children: [
|
|
1792
|
+
/* @__PURE__ */ jsxs("div", { className: "aspect-square bg-gray-100 flex items-center justify-center relative", children: [
|
|
1793
|
+
/* @__PURE__ */ jsx(
|
|
1794
|
+
"img",
|
|
1795
|
+
{
|
|
1796
|
+
src: thumbnail.url,
|
|
1797
|
+
alt: `${thumbnail.size}px thumbnail`,
|
|
1798
|
+
className: "w-full h-full object-cover"
|
|
1799
|
+
}
|
|
1800
|
+
),
|
|
1801
|
+
selectedThumbnailForFile?.id === thumbnail.id && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-blue-500/20 flex items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: "w-6 h-6 bg-blue-500 rounded-full flex items-center justify-center", children: /* @__PURE__ */ jsx("svg", { className: "w-4 h-4 text-white", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx("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" }) }) }) })
|
|
1802
|
+
] }),
|
|
1803
|
+
/* @__PURE__ */ jsxs("div", { className: "p-3 bg-white", children: [
|
|
1804
|
+
/* @__PURE__ */ jsxs("div", { className: "font-medium text-sm text-gray-900", children: [
|
|
1805
|
+
thumbnail.size,
|
|
1806
|
+
"px"
|
|
1807
|
+
] }),
|
|
1808
|
+
/* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500", children: thumbnail.sizeType || "Thumbnail" })
|
|
1809
|
+
] })
|
|
1810
|
+
]
|
|
1811
|
+
},
|
|
1812
|
+
thumbnail.id
|
|
1813
|
+
))
|
|
1814
|
+
] }) }),
|
|
1815
|
+
/* @__PURE__ */ jsxs("div", { className: "p-6 border-t border-gray-200 flex justify-end gap-3", children: [
|
|
1816
|
+
/* @__PURE__ */ jsx(
|
|
1817
|
+
"button",
|
|
1818
|
+
{
|
|
1819
|
+
onClick: () => setThumbnailSelectorFile(null),
|
|
1820
|
+
className: "px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-100 rounded-lg",
|
|
1821
|
+
children: "Cancel"
|
|
1822
|
+
}
|
|
1823
|
+
),
|
|
1824
|
+
/* @__PURE__ */ jsxs(
|
|
1825
|
+
"button",
|
|
1189
1826
|
{
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
originalName: file.name,
|
|
1204
|
-
size: file.size,
|
|
1205
|
-
contentType: file.type,
|
|
1206
|
-
uploadedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1207
|
-
url: file.publicUrl,
|
|
1208
|
-
thumbnails: file.thumbnails
|
|
1209
|
-
};
|
|
1210
|
-
setItems((prev) => [newItem, ...prev]);
|
|
1827
|
+
onClick: () => {
|
|
1828
|
+
if (thumbnailSelectorFile) {
|
|
1829
|
+
onSelect({
|
|
1830
|
+
url: selectedThumbnailForFile?.url || thumbnailSelectorFile.url,
|
|
1831
|
+
key: thumbnailSelectorFile.key,
|
|
1832
|
+
originalName: thumbnailSelectorFile.originalName,
|
|
1833
|
+
size: thumbnailSelectorFile.size,
|
|
1834
|
+
contentType: thumbnailSelectorFile.contentType,
|
|
1835
|
+
thumbnails: thumbnailSelectorFile.thumbnails,
|
|
1836
|
+
selectedThumbnail: selectedThumbnailForFile || void 0
|
|
1837
|
+
});
|
|
1838
|
+
onOpenChange(false);
|
|
1839
|
+
setThumbnailSelectorFile(null);
|
|
1211
1840
|
}
|
|
1212
1841
|
},
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1842
|
+
className: "px-4 py-2 text-sm font-medium rounded-lg bg-blue-600 text-white hover:bg-blue-700",
|
|
1843
|
+
children: [
|
|
1844
|
+
"Select ",
|
|
1845
|
+
selectedThumbnailForFile ? `${selectedThumbnailForFile.size}px Thumbnail` : "Original"
|
|
1846
|
+
]
|
|
1847
|
+
}
|
|
1848
|
+
)
|
|
1849
|
+
] })
|
|
1850
|
+
] })
|
|
1851
|
+
] }) }),
|
|
1852
|
+
/* @__PURE__ */ jsx(Dialog2.Root, { open: !!previewFile, onOpenChange: (open2) => !open2 && setPreviewFile(null), children: /* @__PURE__ */ jsxs(Dialog2.Portal, { children: [
|
|
1853
|
+
/* @__PURE__ */ jsx(Dialog2.Overlay, { className: "fixed inset-0 bg-black/90 z-[100]", onClick: () => setPreviewFile(null) }),
|
|
1854
|
+
/* @__PURE__ */ jsx(Dialog2.Content, { className: "fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-[90vw] h-[90vh] z-[101] outline-none", "aria-describedby": "image-preview-description", children: /* @__PURE__ */ jsxs("div", { className: "relative w-full h-full flex flex-col", children: [
|
|
1855
|
+
/* @__PURE__ */ jsx("div", { className: "absolute top-0 left-0 right-0 z-10 bg-gradient-to-b from-black/70 to-transparent p-6", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between", children: [
|
|
1856
|
+
/* @__PURE__ */ jsxs("div", { className: "text-white", children: [
|
|
1857
|
+
/* @__PURE__ */ jsx(Dialog2.Title, { className: "text-xl font-semibold mb-1", children: previewFile?.originalName }),
|
|
1858
|
+
/* @__PURE__ */ jsxs(Dialog2.Description, { id: "image-preview-description", className: "text-sm text-gray-300", children: [
|
|
1859
|
+
previewFile?.size ? `${(previewFile.size / 1024).toFixed(1)} KB` : "",
|
|
1860
|
+
" \u2022 ",
|
|
1861
|
+
previewFile?.contentType
|
|
1862
|
+
] })
|
|
1863
|
+
] }),
|
|
1864
|
+
/* @__PURE__ */ jsx(
|
|
1865
|
+
"button",
|
|
1866
|
+
{
|
|
1867
|
+
onClick: () => setPreviewFile(null),
|
|
1868
|
+
className: "p-2 bg-white/10 hover:bg-white/20 rounded-lg backdrop-blur-md transition-colors",
|
|
1869
|
+
children: /* @__PURE__ */ jsx(IconX, { className: "w-6 h-6 text-white" })
|
|
1870
|
+
}
|
|
1871
|
+
)
|
|
1872
|
+
] }) }),
|
|
1873
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 flex items-center justify-center p-6", children: /* @__PURE__ */ jsx(
|
|
1874
|
+
"img",
|
|
1875
|
+
{
|
|
1876
|
+
src: previewFile?.url,
|
|
1877
|
+
alt: previewFile?.originalName,
|
|
1878
|
+
className: "max-w-full max-h-full object-contain",
|
|
1879
|
+
onError: (e) => {
|
|
1880
|
+
const target = e.target;
|
|
1881
|
+
target.style.display = "none";
|
|
1882
|
+
const errorDiv = document.createElement("div");
|
|
1883
|
+
errorDiv.className = "text-white text-center";
|
|
1884
|
+
errorDiv.innerHTML = `
|
|
1885
|
+
<div class="text-red-400 mb-2">Failed to load image</div>
|
|
1886
|
+
<div class="text-sm text-gray-400">URL: ${previewFile?.url}</div>
|
|
1887
|
+
`;
|
|
1888
|
+
target.parentElement?.appendChild(errorDiv);
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
) }),
|
|
1892
|
+
/* @__PURE__ */ jsx("div", { className: "absolute bottom-0 left-0 right-0 z-10 bg-gradient-to-t from-black/70 to-transparent p-6", children: /* @__PURE__ */ jsxs("div", { className: "flex gap-3 justify-center", children: [
|
|
1893
|
+
/* @__PURE__ */ jsx(
|
|
1894
|
+
"button",
|
|
1895
|
+
{
|
|
1896
|
+
onClick: (e) => {
|
|
1897
|
+
e.stopPropagation();
|
|
1898
|
+
if (previewFile) {
|
|
1899
|
+
onSelect({
|
|
1900
|
+
url: previewFile.url,
|
|
1901
|
+
key: previewFile.key,
|
|
1902
|
+
originalName: previewFile.originalName,
|
|
1903
|
+
size: previewFile.size,
|
|
1904
|
+
contentType: previewFile.contentType,
|
|
1905
|
+
thumbnails: previewFile.thumbnails
|
|
1906
|
+
});
|
|
1907
|
+
onOpenChange(false);
|
|
1908
|
+
setPreviewFile(null);
|
|
1219
1909
|
}
|
|
1220
1910
|
},
|
|
1221
|
-
|
|
1222
|
-
|
|
1911
|
+
className: "px-6 py-2.5 bg-blue-600 text-white font-semibold rounded-lg hover:bg-blue-500 shadow-lg",
|
|
1912
|
+
children: "Select Image"
|
|
1223
1913
|
}
|
|
1224
1914
|
),
|
|
1225
|
-
/* @__PURE__ */
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1915
|
+
/* @__PURE__ */ jsx(
|
|
1916
|
+
"a",
|
|
1917
|
+
{
|
|
1918
|
+
href: previewFile?.url,
|
|
1919
|
+
target: "_blank",
|
|
1920
|
+
rel: "noopener noreferrer",
|
|
1921
|
+
onClick: (e) => e.stopPropagation(),
|
|
1922
|
+
className: "px-6 py-2.5 bg-white/10 text-white font-semibold rounded-lg hover:bg-white/20 backdrop-blur-md transition-colors",
|
|
1923
|
+
children: "Open in New Tab"
|
|
1924
|
+
}
|
|
1925
|
+
),
|
|
1926
|
+
previewFile?.thumbnails && previewFile.thumbnails.length > 0 && /* @__PURE__ */ jsxs(
|
|
1927
|
+
"button",
|
|
1928
|
+
{
|
|
1929
|
+
onClick: (e) => {
|
|
1930
|
+
e.stopPropagation();
|
|
1931
|
+
setThumbnailSelectorFile(previewFile);
|
|
1932
|
+
setSelectedThumbnailForFile(null);
|
|
1933
|
+
setPreviewFile(null);
|
|
1934
|
+
},
|
|
1935
|
+
className: "px-6 py-2.5 bg-purple-600 text-white font-semibold rounded-lg hover:bg-purple-500 shadow-lg flex items-center gap-2",
|
|
1936
|
+
children: [
|
|
1937
|
+
/* @__PURE__ */ jsx(IconLayers, { className: "w-5 h-5" }),
|
|
1938
|
+
"Select Thumbnail"
|
|
1939
|
+
]
|
|
1940
|
+
}
|
|
1941
|
+
)
|
|
1942
|
+
] }) })
|
|
1943
|
+
] }) })
|
|
1944
|
+
] }) })
|
|
1945
|
+
] });
|
|
1230
1946
|
}
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
UpfilesClient,
|
|
1236
|
-
Uploader,
|
|
1237
|
-
addApiKeyManually,
|
|
1238
|
-
connectProject,
|
|
1239
|
-
connectUsingApiKey,
|
|
1240
|
-
createClientWithKey,
|
|
1241
|
-
createProject,
|
|
1242
|
-
fetchFileThumbnails,
|
|
1243
|
-
fetchProjectFiles,
|
|
1244
|
-
fetchProjectImagesWithThumbs,
|
|
1245
|
-
listProjects
|
|
1246
|
-
};
|
|
1947
|
+
|
|
1948
|
+
export { ConnectProjectDialog, ImageManager, ProjectFilesWidget, UpfilesClient, Uploader, addApiKeyManually, connectProject, connectUsingApiKey, createClientWithKey, createProject, fetchFileThumbnails, fetchProjectFiles, fetchProjectImagesWithThumbs, listProjects };
|
|
1949
|
+
//# sourceMappingURL=index.mjs.map
|
|
1950
|
+
//# sourceMappingURL=index.mjs.map
|