@plugable-io/react 0.0.7 → 0.0.8
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 +111 -0
- package/dist/index.d.mts +32 -3
- package/dist/index.d.ts +32 -3
- package/dist/index.js +353 -81
- package/dist/index.mjs +359 -90
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,112 @@
|
|
|
1
1
|
// src/PlugableProvider.tsx
|
|
2
|
-
import { createContext, useContext, useMemo, useCallback, useRef, useState } from "react";
|
|
2
|
+
import { createContext, useContext, useMemo, useCallback, useRef, useState, useEffect } from "react";
|
|
3
3
|
import { BucketClient } from "@plugable-io/js";
|
|
4
|
+
|
|
5
|
+
// src/utils/theme.ts
|
|
6
|
+
var defaultLightTheme = {
|
|
7
|
+
// Purple to blue accent gradient
|
|
8
|
+
accentPrimary: "#9333ea",
|
|
9
|
+
// purple-600
|
|
10
|
+
accentSecondary: "#2563eb",
|
|
11
|
+
// blue-600
|
|
12
|
+
accentHover: "#7c3aed",
|
|
13
|
+
// purple-700
|
|
14
|
+
// Light backgrounds
|
|
15
|
+
baseBg: "#ffffff",
|
|
16
|
+
baseSurface: "#f8fafc",
|
|
17
|
+
// slate-50
|
|
18
|
+
baseBorder: "#e2e8f0",
|
|
19
|
+
// slate-200
|
|
20
|
+
// Dark text on light
|
|
21
|
+
textPrimary: "#0f172a",
|
|
22
|
+
// slate-900
|
|
23
|
+
textSecondary: "#475569",
|
|
24
|
+
// slate-600
|
|
25
|
+
textMuted: "#94a3b8",
|
|
26
|
+
// slate-400
|
|
27
|
+
// State colors
|
|
28
|
+
success: "#10b981",
|
|
29
|
+
// green-500
|
|
30
|
+
error: "#ef4444",
|
|
31
|
+
// red-500
|
|
32
|
+
warning: "#f59e0b",
|
|
33
|
+
// amber-500
|
|
34
|
+
// Overlay
|
|
35
|
+
overlay: "rgba(0, 0, 0, 0.05)",
|
|
36
|
+
backdropBlur: "blur(12px)"
|
|
37
|
+
};
|
|
38
|
+
var defaultDarkTheme = {
|
|
39
|
+
// Purple to blue accent gradient (same as light)
|
|
40
|
+
accentPrimary: "#9333ea",
|
|
41
|
+
accentSecondary: "#2563eb",
|
|
42
|
+
accentHover: "#a855f7",
|
|
43
|
+
// purple-500 (lighter for dark mode)
|
|
44
|
+
// Dark backgrounds
|
|
45
|
+
baseBg: "#0f172a",
|
|
46
|
+
// slate-900
|
|
47
|
+
baseSurface: "rgba(30, 41, 59, 0.5)",
|
|
48
|
+
// slate-800/50 with transparency
|
|
49
|
+
baseBorder: "rgba(255, 255, 255, 0.1)",
|
|
50
|
+
// Light text on dark
|
|
51
|
+
textPrimary: "#f1f5f9",
|
|
52
|
+
// slate-100
|
|
53
|
+
textSecondary: "#cbd5e1",
|
|
54
|
+
// slate-300
|
|
55
|
+
textMuted: "#64748b",
|
|
56
|
+
// slate-500
|
|
57
|
+
// State colors (slightly adjusted for dark mode)
|
|
58
|
+
success: "#34d399",
|
|
59
|
+
// green-400
|
|
60
|
+
error: "#f87171",
|
|
61
|
+
// red-400
|
|
62
|
+
warning: "#fbbf24",
|
|
63
|
+
// amber-400
|
|
64
|
+
// Overlay
|
|
65
|
+
overlay: "rgba(0, 0, 0, 0.3)",
|
|
66
|
+
backdropBlur: "blur(24px)"
|
|
67
|
+
};
|
|
68
|
+
function getThemeColors(config = {}) {
|
|
69
|
+
const { theme = "dark", accentColor, baseColor } = config;
|
|
70
|
+
const isDark = theme === "dark" || theme === "auto" && window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
71
|
+
const colors = isDark ? { ...defaultDarkTheme } : { ...defaultLightTheme };
|
|
72
|
+
if (accentColor) {
|
|
73
|
+
colors.accentPrimary = accentColor;
|
|
74
|
+
colors.accentSecondary = accentColor;
|
|
75
|
+
colors.accentHover = accentColor;
|
|
76
|
+
}
|
|
77
|
+
if (baseColor) {
|
|
78
|
+
colors.baseBg = baseColor;
|
|
79
|
+
colors.baseSurface = baseColor;
|
|
80
|
+
}
|
|
81
|
+
return colors;
|
|
82
|
+
}
|
|
83
|
+
function generateCSSVariables(colors) {
|
|
84
|
+
return {
|
|
85
|
+
"--plugable-accent-primary": colors.accentPrimary,
|
|
86
|
+
"--plugable-accent-secondary": colors.accentSecondary,
|
|
87
|
+
"--plugable-accent-hover": colors.accentHover,
|
|
88
|
+
"--plugable-base-bg": colors.baseBg,
|
|
89
|
+
"--plugable-base-surface": colors.baseSurface,
|
|
90
|
+
"--plugable-base-border": colors.baseBorder,
|
|
91
|
+
"--plugable-text-primary": colors.textPrimary,
|
|
92
|
+
"--plugable-text-secondary": colors.textSecondary,
|
|
93
|
+
"--plugable-text-muted": colors.textMuted,
|
|
94
|
+
"--plugable-success": colors.success,
|
|
95
|
+
"--plugable-error": colors.error,
|
|
96
|
+
"--plugable-warning": colors.warning,
|
|
97
|
+
"--plugable-overlay": colors.overlay,
|
|
98
|
+
"--plugable-backdrop-blur": colors.backdropBlur
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function applyCSSVariables(element, config = {}) {
|
|
102
|
+
const colors = getThemeColors(config);
|
|
103
|
+
const variables = generateCSSVariables(colors);
|
|
104
|
+
Object.entries(variables).forEach(([key, value]) => {
|
|
105
|
+
element.style.setProperty(key, value);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// src/PlugableProvider.tsx
|
|
4
110
|
import { jsx } from "react/jsx-runtime";
|
|
5
111
|
var PlugableContext = createContext(null);
|
|
6
112
|
function createAuthTokenGetter(authProvider, clerkJWTTemplate) {
|
|
@@ -45,6 +151,13 @@ function createAuthTokenGetter(authProvider, clerkJWTTemplate) {
|
|
|
45
151
|
"Firebase not found. Please ensure firebase is installed and initialized, or provide a custom getToken function."
|
|
46
152
|
);
|
|
47
153
|
};
|
|
154
|
+
case "generic_jwks":
|
|
155
|
+
case "generic_jwt":
|
|
156
|
+
return async () => {
|
|
157
|
+
throw new Error(
|
|
158
|
+
`Manual token required for ${authProvider}. Please provide a custom getToken function.`
|
|
159
|
+
);
|
|
160
|
+
};
|
|
48
161
|
default:
|
|
49
162
|
throw new Error(
|
|
50
163
|
`Unknown auth provider: ${authProvider}. Please provide either a valid authProvider or a custom getToken function.`
|
|
@@ -58,11 +171,15 @@ function PlugableProvider({
|
|
|
58
171
|
authProvider,
|
|
59
172
|
clerkJWTTemplate,
|
|
60
173
|
baseUrl,
|
|
61
|
-
staleTime = 5 * 60 * 1e3
|
|
174
|
+
staleTime = 5 * 60 * 1e3,
|
|
62
175
|
// Default 5 minutes
|
|
176
|
+
accentColor,
|
|
177
|
+
baseColor,
|
|
178
|
+
theme = "dark"
|
|
63
179
|
}) {
|
|
64
180
|
const listenersRef = useRef({});
|
|
65
181
|
const [cache, setCacheState] = useState(/* @__PURE__ */ new Map());
|
|
182
|
+
const containerRef = useRef(null);
|
|
66
183
|
const client = useMemo(() => {
|
|
67
184
|
if (!getToken && !authProvider) {
|
|
68
185
|
throw new Error(
|
|
@@ -132,7 +249,12 @@ function PlugableProvider({
|
|
|
132
249
|
}),
|
|
133
250
|
[client, bucketId, on, emit, baseUrl, staleTime, getCache, setCache, invalidateCache]
|
|
134
251
|
);
|
|
135
|
-
|
|
252
|
+
useEffect(() => {
|
|
253
|
+
if (containerRef.current) {
|
|
254
|
+
applyCSSVariables(containerRef.current, { accentColor, baseColor, theme });
|
|
255
|
+
}
|
|
256
|
+
}, [accentColor, baseColor, theme]);
|
|
257
|
+
return /* @__PURE__ */ jsx(PlugableContext.Provider, { value, children: /* @__PURE__ */ jsx("div", { ref: containerRef, className: "plugable-root", children }) });
|
|
136
258
|
}
|
|
137
259
|
function usePlugable() {
|
|
138
260
|
const context = useContext(PlugableContext);
|
|
@@ -277,6 +399,74 @@ function Dropzone({
|
|
|
277
399
|
}
|
|
278
400
|
);
|
|
279
401
|
}
|
|
402
|
+
const containerStyle = {
|
|
403
|
+
position: "relative",
|
|
404
|
+
border: `2px dashed ${isDragActive ? "var(--plugable-accent-primary)" : "var(--plugable-base-border)"}`,
|
|
405
|
+
borderRadius: "12px",
|
|
406
|
+
padding: "48px 24px",
|
|
407
|
+
textAlign: "center",
|
|
408
|
+
cursor: "pointer",
|
|
409
|
+
background: isDragActive ? "var(--plugable-accent-primary)10" : "var(--plugable-base-surface)",
|
|
410
|
+
backdropFilter: "var(--plugable-backdrop-blur)",
|
|
411
|
+
transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)",
|
|
412
|
+
...style
|
|
413
|
+
};
|
|
414
|
+
const iconContainerStyle = {
|
|
415
|
+
width: "48px",
|
|
416
|
+
height: "48px",
|
|
417
|
+
margin: "0 auto 16px",
|
|
418
|
+
borderRadius: "50%",
|
|
419
|
+
display: "flex",
|
|
420
|
+
alignItems: "center",
|
|
421
|
+
justifyContent: "center",
|
|
422
|
+
background: isDragActive ? `linear-gradient(135deg, var(--plugable-accent-primary), var(--plugable-accent-secondary))` : "var(--plugable-overlay)",
|
|
423
|
+
transition: "all 0.3s ease",
|
|
424
|
+
transform: isDragActive ? "scale(1.1)" : "scale(1)"
|
|
425
|
+
};
|
|
426
|
+
const cloudIconStyle = {
|
|
427
|
+
width: "24px",
|
|
428
|
+
height: "24px",
|
|
429
|
+
color: isDragActive ? "#fff" : "var(--plugable-accent-primary)"
|
|
430
|
+
};
|
|
431
|
+
const titleStyle = {
|
|
432
|
+
margin: 0,
|
|
433
|
+
fontWeight: 600,
|
|
434
|
+
fontSize: "16px",
|
|
435
|
+
color: "var(--plugable-text-primary)",
|
|
436
|
+
marginBottom: "8px"
|
|
437
|
+
};
|
|
438
|
+
const subtitleStyle = {
|
|
439
|
+
margin: 0,
|
|
440
|
+
fontSize: "14px",
|
|
441
|
+
color: "var(--plugable-text-secondary)"
|
|
442
|
+
};
|
|
443
|
+
const maxFilesStyle = {
|
|
444
|
+
margin: "4px 0 0 0",
|
|
445
|
+
fontSize: "12px",
|
|
446
|
+
color: "var(--plugable-text-muted)"
|
|
447
|
+
};
|
|
448
|
+
const progressContainerStyle = {
|
|
449
|
+
marginTop: "16px"
|
|
450
|
+
};
|
|
451
|
+
const progressItemStyle = {
|
|
452
|
+
marginBottom: "12px",
|
|
453
|
+
textAlign: "left"
|
|
454
|
+
};
|
|
455
|
+
const progressLabelStyle = {
|
|
456
|
+
fontSize: "14px",
|
|
457
|
+
color: "var(--plugable-text-secondary)",
|
|
458
|
+
marginBottom: "6px",
|
|
459
|
+
display: "flex",
|
|
460
|
+
justifyContent: "space-between",
|
|
461
|
+
alignItems: "center"
|
|
462
|
+
};
|
|
463
|
+
const progressBarBgStyle = {
|
|
464
|
+
width: "100%",
|
|
465
|
+
height: "6px",
|
|
466
|
+
backgroundColor: "var(--plugable-overlay)",
|
|
467
|
+
borderRadius: "3px",
|
|
468
|
+
overflow: "hidden"
|
|
469
|
+
};
|
|
280
470
|
return /* @__PURE__ */ jsxs(
|
|
281
471
|
"div",
|
|
282
472
|
{
|
|
@@ -285,16 +475,7 @@ function Dropzone({
|
|
|
285
475
|
onDragLeave: handleDragLeave,
|
|
286
476
|
onClick: openFileDialog,
|
|
287
477
|
className,
|
|
288
|
-
style:
|
|
289
|
-
border: `2px dashed ${isDragActive ? "#0070f3" : "#ccc"}`,
|
|
290
|
-
borderRadius: "8px",
|
|
291
|
-
padding: "40px 20px",
|
|
292
|
-
textAlign: "center",
|
|
293
|
-
cursor: "pointer",
|
|
294
|
-
backgroundColor: isDragActive ? "#f0f8ff" : "#fafafa",
|
|
295
|
-
transition: "all 0.2s ease",
|
|
296
|
-
...style
|
|
297
|
-
},
|
|
478
|
+
style: containerStyle,
|
|
298
479
|
children: [
|
|
299
480
|
/* @__PURE__ */ jsx2(
|
|
300
481
|
"input",
|
|
@@ -308,42 +489,34 @@ function Dropzone({
|
|
|
308
489
|
}
|
|
309
490
|
),
|
|
310
491
|
isUploading ? /* @__PURE__ */ jsxs("div", { children: [
|
|
311
|
-
/* @__PURE__ */ jsx2("
|
|
312
|
-
/* @__PURE__ */ jsx2("
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
":
|
|
316
|
-
|
|
317
|
-
|
|
492
|
+
/* @__PURE__ */ jsx2("div", { style: iconContainerStyle, children: /* @__PURE__ */ jsx2("svg", { style: cloudIconStyle, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx2("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" }) }) }),
|
|
493
|
+
/* @__PURE__ */ jsx2("p", { style: titleStyle, children: "Uploading..." }),
|
|
494
|
+
/* @__PURE__ */ jsx2("div", { style: progressContainerStyle, children: Object.entries(uploadProgress).map(([fileName, progress]) => /* @__PURE__ */ jsxs("div", { style: progressItemStyle, children: [
|
|
495
|
+
/* @__PURE__ */ jsxs("div", { style: progressLabelStyle, children: [
|
|
496
|
+
/* @__PURE__ */ jsx2("span", { children: fileName }),
|
|
497
|
+
/* @__PURE__ */ jsxs("span", { style: { fontWeight: 600 }, children: [
|
|
498
|
+
progress,
|
|
499
|
+
"%"
|
|
500
|
+
] })
|
|
318
501
|
] }),
|
|
319
|
-
/* @__PURE__ */ jsx2(
|
|
502
|
+
/* @__PURE__ */ jsx2("div", { style: progressBarBgStyle, children: /* @__PURE__ */ jsx2(
|
|
320
503
|
"div",
|
|
321
504
|
{
|
|
322
505
|
style: {
|
|
323
|
-
width:
|
|
324
|
-
height: "
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
}
|
|
329
|
-
children: /* @__PURE__ */ jsx2(
|
|
330
|
-
"div",
|
|
331
|
-
{
|
|
332
|
-
style: {
|
|
333
|
-
width: `${progress}%`,
|
|
334
|
-
height: "100%",
|
|
335
|
-
backgroundColor: "#0070f3",
|
|
336
|
-
transition: "width 0.3s ease"
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
)
|
|
506
|
+
width: `${progress}%`,
|
|
507
|
+
height: "100%",
|
|
508
|
+
background: `linear-gradient(90deg, var(--plugable-accent-primary), var(--plugable-accent-secondary))`,
|
|
509
|
+
transition: "width 0.3s ease",
|
|
510
|
+
borderRadius: "3px"
|
|
511
|
+
}
|
|
340
512
|
}
|
|
341
|
-
)
|
|
513
|
+
) })
|
|
342
514
|
] }, fileName)) })
|
|
343
515
|
] }) : /* @__PURE__ */ jsxs("div", { children: [
|
|
344
|
-
/* @__PURE__ */ jsx2("
|
|
345
|
-
/* @__PURE__ */ jsx2("p", { style:
|
|
346
|
-
|
|
516
|
+
/* @__PURE__ */ jsx2("div", { style: iconContainerStyle, children: /* @__PURE__ */ jsx2("svg", { style: cloudIconStyle, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx2("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" }) }) }),
|
|
517
|
+
/* @__PURE__ */ jsx2("p", { style: titleStyle, children: isDragActive ? "Drop files here" : "Click to upload or drag and drop" }),
|
|
518
|
+
/* @__PURE__ */ jsx2("p", { style: subtitleStyle, children: accept ? `Accepted: ${accept}` : "Any file type" }),
|
|
519
|
+
maxFiles && maxFiles > 1 && /* @__PURE__ */ jsxs("p", { style: maxFilesStyle, children: [
|
|
347
520
|
"(Maximum ",
|
|
348
521
|
maxFiles,
|
|
349
522
|
" files)"
|
|
@@ -355,7 +528,7 @@ function Dropzone({
|
|
|
355
528
|
}
|
|
356
529
|
|
|
357
530
|
// src/hooks/useFiles.ts
|
|
358
|
-
import { useState as useState3, useCallback as useCallback3, useEffect, useMemo as useMemo2, useRef as useRef2 } from "react";
|
|
531
|
+
import { useState as useState3, useCallback as useCallback3, useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2 } from "react";
|
|
359
532
|
function useFiles({
|
|
360
533
|
metadata,
|
|
361
534
|
startPage = 1,
|
|
@@ -440,7 +613,7 @@ function useFiles({
|
|
|
440
613
|
setIsLoading(false);
|
|
441
614
|
}
|
|
442
615
|
}, [client, stableMetadata, mediaType, perPage, orderBy, orderDirection, getCache, setCache, effectiveStaleTime]);
|
|
443
|
-
|
|
616
|
+
useEffect2(() => {
|
|
444
617
|
const paramsChanged = previousParamsRef.current !== null && previousParamsRef.current !== paramsKeyWithPage;
|
|
445
618
|
const isInitialMount = isInitialMountRef.current;
|
|
446
619
|
previousParamsRef.current = paramsKeyWithPage;
|
|
@@ -461,7 +634,7 @@ function useFiles({
|
|
|
461
634
|
fetchFiles(page, true);
|
|
462
635
|
}
|
|
463
636
|
}, [paramsKeyWithPage, autoLoad, getCache, effectiveStaleTime, fetchFiles, page]);
|
|
464
|
-
|
|
637
|
+
useEffect2(() => {
|
|
465
638
|
const unsubscribe = on("file.uploaded", () => {
|
|
466
639
|
fetchFiles(page, true);
|
|
467
640
|
});
|
|
@@ -523,7 +696,7 @@ function FileList({
|
|
|
523
696
|
}
|
|
524
697
|
|
|
525
698
|
// src/components/FileImage.tsx
|
|
526
|
-
import { useEffect as
|
|
699
|
+
import { useEffect as useEffect3, useState as useState4, useRef as useRef3 } from "react";
|
|
527
700
|
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
528
701
|
var imageCache = /* @__PURE__ */ new Map();
|
|
529
702
|
function FileImage({
|
|
@@ -543,7 +716,7 @@ function FileImage({
|
|
|
543
716
|
const [isLoading, setIsLoading] = useState4(true);
|
|
544
717
|
const [error, setError] = useState4(null);
|
|
545
718
|
const refetchAttemptedRef = useRef3(null);
|
|
546
|
-
|
|
719
|
+
useEffect3(() => {
|
|
547
720
|
let isMounted = true;
|
|
548
721
|
let objectUrl = null;
|
|
549
722
|
const loadImage = async () => {
|
|
@@ -636,20 +809,25 @@ function FileImage({
|
|
|
636
809
|
...style
|
|
637
810
|
};
|
|
638
811
|
if (error) {
|
|
639
|
-
return /* @__PURE__ */
|
|
812
|
+
return /* @__PURE__ */ jsxs2(
|
|
640
813
|
"div",
|
|
641
814
|
{
|
|
642
815
|
className,
|
|
643
816
|
style: {
|
|
644
817
|
...imageStyle,
|
|
645
818
|
display: "flex",
|
|
819
|
+
flexDirection: "column",
|
|
646
820
|
alignItems: "center",
|
|
647
821
|
justifyContent: "center",
|
|
648
|
-
backgroundColor: "
|
|
649
|
-
color: "
|
|
650
|
-
fontSize: "14px"
|
|
822
|
+
backgroundColor: "var(--plugable-base-surface)",
|
|
823
|
+
color: "var(--plugable-text-muted)",
|
|
824
|
+
fontSize: "14px",
|
|
825
|
+
gap: "8px"
|
|
651
826
|
},
|
|
652
|
-
children:
|
|
827
|
+
children: [
|
|
828
|
+
/* @__PURE__ */ jsx4("svg", { style: { width: "32px", height: "32px" }, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx4("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" }) }),
|
|
829
|
+
/* @__PURE__ */ jsx4("span", { children: "Failed to load" })
|
|
830
|
+
]
|
|
653
831
|
}
|
|
654
832
|
);
|
|
655
833
|
}
|
|
@@ -660,29 +838,29 @@ function FileImage({
|
|
|
660
838
|
className,
|
|
661
839
|
style: {
|
|
662
840
|
...imageStyle,
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
backgroundColor: "#f0f0f0"
|
|
841
|
+
position: "relative",
|
|
842
|
+
overflow: "hidden",
|
|
843
|
+
backgroundColor: "var(--plugable-base-surface)"
|
|
667
844
|
},
|
|
668
845
|
children: [
|
|
669
846
|
/* @__PURE__ */ jsx4(
|
|
670
847
|
"div",
|
|
671
848
|
{
|
|
672
849
|
style: {
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
850
|
+
position: "absolute",
|
|
851
|
+
top: 0,
|
|
852
|
+
left: "-100%",
|
|
853
|
+
width: "100%",
|
|
854
|
+
height: "100%",
|
|
855
|
+
background: "linear-gradient(90deg, transparent, var(--plugable-overlay), transparent)",
|
|
856
|
+
animation: "shimmer 1.5s infinite"
|
|
679
857
|
}
|
|
680
858
|
}
|
|
681
859
|
),
|
|
682
860
|
/* @__PURE__ */ jsx4("style", { children: `
|
|
683
|
-
@keyframes
|
|
684
|
-
0% {
|
|
685
|
-
100% {
|
|
861
|
+
@keyframes shimmer {
|
|
862
|
+
0% { left: -100%; }
|
|
863
|
+
100% { left: 100%; }
|
|
686
864
|
}
|
|
687
865
|
` })
|
|
688
866
|
]
|
|
@@ -695,7 +873,11 @@ function FileImage({
|
|
|
695
873
|
src: imageSrc,
|
|
696
874
|
alt: alt || file.name,
|
|
697
875
|
className,
|
|
698
|
-
style:
|
|
876
|
+
style: {
|
|
877
|
+
...imageStyle,
|
|
878
|
+
opacity: isLoading ? 0 : 1,
|
|
879
|
+
transition: "opacity 0.3s ease-in"
|
|
880
|
+
},
|
|
699
881
|
onLoad: handleLoad,
|
|
700
882
|
onError: handleError
|
|
701
883
|
}
|
|
@@ -707,12 +889,35 @@ function clearImageCache() {
|
|
|
707
889
|
}
|
|
708
890
|
|
|
709
891
|
// src/components/FilePreview.tsx
|
|
710
|
-
import { useState as useState5, useCallback as useCallback4, useEffect as
|
|
711
|
-
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
892
|
+
import { useState as useState5, useCallback as useCallback4, useEffect as useEffect4 } from "react";
|
|
893
|
+
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
894
|
+
var fileTypeColors = {
|
|
895
|
+
pdf: { bg: "transparent", text: "#94a3b8" },
|
|
896
|
+
// Slate-400
|
|
897
|
+
doc: { bg: "transparent", text: "#94a3b8" },
|
|
898
|
+
docx: { bg: "transparent", text: "#94a3b8" },
|
|
899
|
+
xls: { bg: "transparent", text: "#94a3b8" },
|
|
900
|
+
xlsx: { bg: "transparent", text: "#94a3b8" },
|
|
901
|
+
csv: { bg: "transparent", text: "#94a3b8" },
|
|
902
|
+
txt: { bg: "transparent", text: "#94a3b8" },
|
|
903
|
+
zip: { bg: "transparent", text: "#94a3b8" },
|
|
904
|
+
rar: { bg: "transparent", text: "#94a3b8" },
|
|
905
|
+
mp4: { bg: "transparent", text: "#94a3b8" },
|
|
906
|
+
mov: { bg: "transparent", text: "#94a3b8" },
|
|
907
|
+
avi: { bg: "transparent", text: "#94a3b8" },
|
|
908
|
+
mp3: { bg: "transparent", text: "#94a3b8" },
|
|
909
|
+
wav: { bg: "transparent", text: "#94a3b8" },
|
|
910
|
+
default: { bg: "transparent", text: "#64748b" }
|
|
911
|
+
// Slate-500
|
|
912
|
+
};
|
|
913
|
+
function getFileTypeColor(filename) {
|
|
914
|
+
const ext = filename.split(".").pop()?.toLowerCase() || "";
|
|
915
|
+
return fileTypeColors[ext] || fileTypeColors.default;
|
|
916
|
+
}
|
|
712
917
|
function FilePreview({
|
|
713
918
|
file: initialFile,
|
|
714
|
-
width =
|
|
715
|
-
height =
|
|
919
|
+
width = 120,
|
|
920
|
+
height = 120,
|
|
716
921
|
className,
|
|
717
922
|
style,
|
|
718
923
|
objectFit = "cover",
|
|
@@ -722,7 +927,8 @@ function FilePreview({
|
|
|
722
927
|
const { client } = usePlugable();
|
|
723
928
|
const [file, setFile] = useState5(initialFile);
|
|
724
929
|
const [isRefetching, setIsRefetching] = useState5(false);
|
|
725
|
-
|
|
930
|
+
const [isHovered, setIsHovered] = useState5(false);
|
|
931
|
+
useEffect4(() => {
|
|
726
932
|
setFile(initialFile);
|
|
727
933
|
}, [initialFile.id, initialFile.download_url]);
|
|
728
934
|
const handleRefetch = useCallback4(async () => {
|
|
@@ -736,45 +942,105 @@ function FilePreview({
|
|
|
736
942
|
} finally {
|
|
737
943
|
setIsRefetching(false);
|
|
738
944
|
}
|
|
739
|
-
}, [file.id, client]);
|
|
945
|
+
}, [file.id, client, isRefetching]);
|
|
740
946
|
const isImage = file.content_type.startsWith("image/");
|
|
741
947
|
const containerStyle = {
|
|
742
948
|
width,
|
|
743
949
|
height,
|
|
744
|
-
borderRadius:
|
|
950
|
+
borderRadius: "8px",
|
|
745
951
|
overflow: "hidden",
|
|
746
|
-
|
|
952
|
+
position: "relative",
|
|
747
953
|
display: "flex",
|
|
748
954
|
alignItems: "center",
|
|
749
955
|
justifyContent: "center",
|
|
750
|
-
border: "1px solid
|
|
956
|
+
border: isHovered ? "1px solid var(--plugable-accent-primary)" : "1px solid var(--plugable-base-border)",
|
|
957
|
+
background: "var(--plugable-base-surface)",
|
|
958
|
+
transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)",
|
|
959
|
+
boxShadow: "0 2px 4px rgba(0, 0, 0, 0.05)",
|
|
960
|
+
cursor: "pointer",
|
|
751
961
|
...style
|
|
752
962
|
};
|
|
753
963
|
if (isImage) {
|
|
754
964
|
return /* @__PURE__ */ jsx5(
|
|
755
|
-
|
|
965
|
+
"div",
|
|
756
966
|
{
|
|
757
|
-
|
|
758
|
-
width,
|
|
759
|
-
height,
|
|
760
|
-
objectFit,
|
|
967
|
+
style: containerStyle,
|
|
761
968
|
className,
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
969
|
+
onMouseEnter: () => setIsHovered(true),
|
|
970
|
+
onMouseLeave: () => setIsHovered(false),
|
|
971
|
+
children: /* @__PURE__ */ jsx5(
|
|
972
|
+
FileImage,
|
|
973
|
+
{
|
|
974
|
+
file,
|
|
975
|
+
width,
|
|
976
|
+
height,
|
|
977
|
+
objectFit,
|
|
978
|
+
style: { borderRadius: "8px" },
|
|
979
|
+
onRefetchNeeded: handleRefetch
|
|
980
|
+
}
|
|
981
|
+
)
|
|
765
982
|
}
|
|
766
983
|
);
|
|
767
984
|
}
|
|
768
985
|
if (renderNonImage) {
|
|
769
|
-
return /* @__PURE__ */ jsx5(
|
|
986
|
+
return /* @__PURE__ */ jsx5(
|
|
987
|
+
"div",
|
|
988
|
+
{
|
|
989
|
+
className,
|
|
990
|
+
style: containerStyle,
|
|
991
|
+
onMouseEnter: () => setIsHovered(true),
|
|
992
|
+
onMouseLeave: () => setIsHovered(false),
|
|
993
|
+
children: renderNonImage(file)
|
|
994
|
+
}
|
|
995
|
+
);
|
|
770
996
|
}
|
|
771
997
|
const extension = file.name.split(".").pop()?.toUpperCase() || "FILE";
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
998
|
+
const colors = getFileTypeColor(file.name);
|
|
999
|
+
const badgeStyle = {
|
|
1000
|
+
padding: "2px 8px",
|
|
1001
|
+
borderRadius: "4px",
|
|
1002
|
+
border: "1px solid var(--plugable-base-border)",
|
|
1003
|
+
backgroundColor: "var(--plugable-overlay)",
|
|
1004
|
+
display: "inline-flex",
|
|
1005
|
+
alignItems: "center",
|
|
1006
|
+
justifyContent: "center"
|
|
1007
|
+
};
|
|
1008
|
+
const extensionStyle = {
|
|
1009
|
+
fontSize: "11px",
|
|
1010
|
+
fontWeight: 600,
|
|
1011
|
+
color: "var(--plugable-text-secondary)",
|
|
1012
|
+
textTransform: "uppercase",
|
|
1013
|
+
letterSpacing: "0.05em"
|
|
1014
|
+
};
|
|
1015
|
+
const iconStyle = {
|
|
1016
|
+
width: "28px",
|
|
1017
|
+
height: "28px",
|
|
1018
|
+
marginBottom: "6px",
|
|
1019
|
+
color: colors.text
|
|
1020
|
+
};
|
|
1021
|
+
const wrapperStyle = {
|
|
1022
|
+
textAlign: "center",
|
|
1023
|
+
padding: "12px",
|
|
1024
|
+
display: "flex",
|
|
1025
|
+
flexDirection: "column",
|
|
1026
|
+
alignItems: "center",
|
|
1027
|
+
justifyContent: "center",
|
|
1028
|
+
width: "100%",
|
|
1029
|
+
height: "100%"
|
|
1030
|
+
};
|
|
1031
|
+
return /* @__PURE__ */ jsx5(
|
|
1032
|
+
"div",
|
|
1033
|
+
{
|
|
1034
|
+
className,
|
|
1035
|
+
style: containerStyle,
|
|
1036
|
+
onMouseEnter: () => setIsHovered(true),
|
|
1037
|
+
onMouseLeave: () => setIsHovered(false),
|
|
1038
|
+
children: /* @__PURE__ */ jsxs3("div", { style: wrapperStyle, children: [
|
|
1039
|
+
/* @__PURE__ */ jsx5("svg", { style: iconStyle, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx5("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" }) }),
|
|
1040
|
+
showExtension && /* @__PURE__ */ jsx5("div", { style: badgeStyle, children: /* @__PURE__ */ jsx5("span", { style: extensionStyle, children: extension }) })
|
|
1041
|
+
] })
|
|
1042
|
+
}
|
|
1043
|
+
);
|
|
778
1044
|
}
|
|
779
1045
|
export {
|
|
780
1046
|
Dropzone,
|
|
@@ -782,7 +1048,10 @@ export {
|
|
|
782
1048
|
FileList,
|
|
783
1049
|
FilePreview,
|
|
784
1050
|
PlugableProvider,
|
|
1051
|
+
applyCSSVariables,
|
|
785
1052
|
clearImageCache,
|
|
1053
|
+
generateCSSVariables,
|
|
1054
|
+
getThemeColors,
|
|
786
1055
|
useFiles,
|
|
787
1056
|
usePlugable
|
|
788
1057
|
};
|