@dust-tt/sparkle 0.2.481-rc1 → 0.2.481-rc3
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/dist/cjs/index.js +1 -1
- package/dist/esm/components/InteractiveImage.d.ts +0 -2
- package/dist/esm/components/InteractiveImage.d.ts.map +1 -1
- package/dist/esm/components/InteractiveImage.js +44 -102
- package/dist/esm/components/InteractiveImage.js.map +1 -1
- package/dist/sparkle.css +33 -9
- package/package.json +1 -1
- package/src/components/InteractiveImage.tsx +77 -89
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InteractiveImage.d.ts","sourceRoot":"","sources":["../../../src/components/InteractiveImage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"InteractiveImage.d.ts","sourceRoot":"","sources":["../../../src/components/InteractiveImage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAqD1B,UAAU,qBAAqB;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,GAAG,EACH,SAAiB,EACjB,GAAG,EACH,GAAG,KAAK,EACT,EAAE,qBAAqB,qBA8CvB"}
|
|
@@ -1,9 +1,39 @@
|
|
|
1
1
|
import { __assign, __awaiter, __generator, __read, __rest } from "tslib";
|
|
2
2
|
import React from "react";
|
|
3
3
|
import { Dialog, DialogContent, DialogTrigger, IconButton, Spinner, } from "../components";
|
|
4
|
-
import {
|
|
5
|
-
import { ArrowDownOnSquareIcon, ClipboardCheckIcon, ClipboardIcon, } from "../icons/app";
|
|
4
|
+
import { ArrowDownOnSquareIcon } from "../icons/app";
|
|
6
5
|
import { cn } from "../lib/utils";
|
|
6
|
+
function DownloadButton(_a) {
|
|
7
|
+
var _this = this;
|
|
8
|
+
var className = _a.className, _b = _a.size, size = _b === void 0 ? "xs" : _b, src = _a.src, title = _a.title;
|
|
9
|
+
var handleDownload = React.useCallback(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
10
|
+
var link;
|
|
11
|
+
return __generator(this, function (_a) {
|
|
12
|
+
if (!src) {
|
|
13
|
+
return [2 /*return*/];
|
|
14
|
+
}
|
|
15
|
+
link = document.createElement("a");
|
|
16
|
+
link.href = src;
|
|
17
|
+
link.download = title;
|
|
18
|
+
document.body.appendChild(link);
|
|
19
|
+
link.click();
|
|
20
|
+
document.body.removeChild(link);
|
|
21
|
+
return [2 /*return*/];
|
|
22
|
+
});
|
|
23
|
+
}); }, [src, title]);
|
|
24
|
+
return (React.createElement(IconButton, { icon: ArrowDownOnSquareIcon, className: cn("s-text-white", className), tooltip: "Download", size: size, onClick: function (e) { return __awaiter(_this, void 0, void 0, function () {
|
|
25
|
+
return __generator(this, function (_a) {
|
|
26
|
+
switch (_a.label) {
|
|
27
|
+
case 0:
|
|
28
|
+
e.stopPropagation(); // Prevent image zoom.
|
|
29
|
+
return [4 /*yield*/, handleDownload()];
|
|
30
|
+
case 1:
|
|
31
|
+
_a.sent();
|
|
32
|
+
return [2 /*return*/];
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}); } }));
|
|
36
|
+
}
|
|
7
37
|
export function InteractiveImage(_a) {
|
|
8
38
|
var alt = _a.alt, _b = _a.isLoading, isLoading = _b === void 0 ? false : _b, src = _a.src, props = __rest(_a, ["alt", "isLoading", "src"]);
|
|
9
39
|
var _c = __read(React.useState(false), 2), isZoomed = _c[0], setIsZoomed = _c[1];
|
|
@@ -21,111 +51,23 @@ export function InteractiveImage(_a) {
|
|
|
21
51
|
}
|
|
22
52
|
handleZoomToggle();
|
|
23
53
|
}, src: src }, props)))),
|
|
24
|
-
React.createElement(DialogContent, { className: "s-w-auto s-max-w-none s-border-0 s-outline-none s-ring-0 focus:s-outline-none focus:s-ring-0" },
|
|
25
|
-
React.createElement("
|
|
54
|
+
React.createElement(DialogContent, { className: cn("s-w-auto s-max-w-none s-border-0 s-outline-none s-ring-0", "focus:s-outline-none focus:s-ring-0", "s-rounded-none s-bg-transparent s-shadow-none"), size: "xl" },
|
|
55
|
+
React.createElement("div", { className: "s-flex s-flex-col" },
|
|
56
|
+
React.createElement("div", { className: "s-flex s-justify-end s-pb-2 s-pr-1 s-pt-1" },
|
|
57
|
+
React.createElement(DownloadButton, { src: src, title: props.title, size: "sm" })),
|
|
58
|
+
React.createElement("div", { className: "s-relative s-w-full" },
|
|
59
|
+
React.createElement("img", { src: src, alt: alt, className: "s-w-full s-object-contain" }))))));
|
|
26
60
|
}
|
|
27
61
|
function LoadingImage() {
|
|
28
62
|
return (React.createElement("div", { className: "s-flex s-h-full s-w-full s-items-center s-justify-center" },
|
|
29
|
-
React.createElement(Spinner, { variant: "dark", size: "
|
|
63
|
+
React.createElement(Spinner, { variant: "dark", size: "md" })));
|
|
30
64
|
}
|
|
31
65
|
function ImagePreview(_a) {
|
|
32
|
-
var
|
|
33
|
-
|
|
34
|
-
var _b = __read(useCopyToClipboard(), 2), isCopied = _b[0], copyToClipboard = _b[1];
|
|
35
|
-
var handleCopy = function () { return __awaiter(_this, void 0, void 0, function () {
|
|
36
|
-
var response, blob, error_1;
|
|
37
|
-
var _a;
|
|
38
|
-
return __generator(this, function (_b) {
|
|
39
|
-
switch (_b.label) {
|
|
40
|
-
case 0:
|
|
41
|
-
_b.trys.push([0, 4, , 5]);
|
|
42
|
-
if (!src) {
|
|
43
|
-
return [2 /*return*/];
|
|
44
|
-
}
|
|
45
|
-
return [4 /*yield*/, fetch(src)];
|
|
46
|
-
case 1:
|
|
47
|
-
response = _b.sent();
|
|
48
|
-
return [4 /*yield*/, response.blob()];
|
|
49
|
-
case 2:
|
|
50
|
-
blob = _b.sent();
|
|
51
|
-
// Copy to clipboard.
|
|
52
|
-
return [4 /*yield*/, copyToClipboard(new ClipboardItem((_a = {},
|
|
53
|
-
_a[blob.type] = blob,
|
|
54
|
-
_a)))];
|
|
55
|
-
case 3:
|
|
56
|
-
// Copy to clipboard.
|
|
57
|
-
_b.sent();
|
|
58
|
-
return [3 /*break*/, 5];
|
|
59
|
-
case 4:
|
|
60
|
-
error_1 = _b.sent();
|
|
61
|
-
onCopyError === null || onCopyError === void 0 ? void 0 : onCopyError(error_1);
|
|
62
|
-
return [3 /*break*/, 5];
|
|
63
|
-
case 5: return [2 /*return*/];
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
}); };
|
|
67
|
-
var handleDownload = function () { return __awaiter(_this, void 0, void 0, function () {
|
|
68
|
-
var response, blob, url, link, error_2;
|
|
69
|
-
return __generator(this, function (_a) {
|
|
70
|
-
switch (_a.label) {
|
|
71
|
-
case 0:
|
|
72
|
-
_a.trys.push([0, 3, , 4]);
|
|
73
|
-
if (!src) {
|
|
74
|
-
return [2 /*return*/];
|
|
75
|
-
}
|
|
76
|
-
return [4 /*yield*/, fetch(src)];
|
|
77
|
-
case 1:
|
|
78
|
-
response = _a.sent();
|
|
79
|
-
return [4 /*yield*/, response.blob()];
|
|
80
|
-
case 2:
|
|
81
|
-
blob = _a.sent();
|
|
82
|
-
url = window.URL.createObjectURL(blob);
|
|
83
|
-
link = document.createElement("a");
|
|
84
|
-
link.href = url;
|
|
85
|
-
// Extract filename from URL or use a default.
|
|
86
|
-
link.download = title;
|
|
87
|
-
// Trigger download.
|
|
88
|
-
document.body.appendChild(link);
|
|
89
|
-
link.click();
|
|
90
|
-
// Cleanup.
|
|
91
|
-
document.body.removeChild(link);
|
|
92
|
-
window.URL.revokeObjectURL(url);
|
|
93
|
-
return [3 /*break*/, 4];
|
|
94
|
-
case 3:
|
|
95
|
-
error_2 = _a.sent();
|
|
96
|
-
onDownloadError === null || onDownloadError === void 0 ? void 0 : onDownloadError(error_2);
|
|
97
|
-
return [3 /*break*/, 4];
|
|
98
|
-
case 4: return [2 /*return*/];
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
}); };
|
|
102
|
-
return (React.createElement("div", { onClick: onClick, className: cn("s-group/preview s-relative s-h-full s-w-full s-overflow-hidden s-rounded-2xl s-bg-muted-background dark:s-bg-muted-background-night", !isLoading && "s-cursor-pointer") }, isLoading ? (React.createElement(LoadingImage, null)) : (React.createElement(React.Fragment, null,
|
|
66
|
+
var isLoading = _a.isLoading, onClick = _a.onClick, alt = _a.alt, src = _a.src, title = _a.title;
|
|
67
|
+
return (React.createElement("div", { onClick: onClick, className: cn("s-group/preview s-relative s-h-full s-w-full s-overflow-hidden s-rounded-2xl", "s-bg-muted-background dark:s-bg-muted-background-night", !isLoading && "s-cursor-pointer") }, isLoading ? (React.createElement(LoadingImage, null)) : (React.createElement(React.Fragment, null,
|
|
103
68
|
React.createElement("img", { src: src, alt: alt, className: "s-h-full s-w-full s-rounded-2xl s-object-cover" }),
|
|
104
|
-
React.createElement("div", { className: "s-absolute s-inset-0 s-bg-black s-opacity-0 s-transition-opacity s-duration-200 group-hover/preview:s-opacity-
|
|
105
|
-
React.createElement("div", { className: "s-absolute s-right-3 s-top-3 s-z-10 s-flex s-opacity-0 s-transition-opacity s-duration-200 group-hover/preview:s-opacity-100" },
|
|
106
|
-
React.createElement(
|
|
107
|
-
return __generator(this, function (_a) {
|
|
108
|
-
switch (_a.label) {
|
|
109
|
-
case 0:
|
|
110
|
-
e.stopPropagation(); // Prevent image zoom.
|
|
111
|
-
return [4 /*yield*/, handleCopy()];
|
|
112
|
-
case 1:
|
|
113
|
-
_a.sent();
|
|
114
|
-
return [2 /*return*/];
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
}); } }),
|
|
118
|
-
React.createElement(IconButton, { icon: ArrowDownOnSquareIcon, className: "s-text-white", tooltip: "Download", size: "xs", onClick: function (e) { return __awaiter(_this, void 0, void 0, function () {
|
|
119
|
-
return __generator(this, function (_a) {
|
|
120
|
-
switch (_a.label) {
|
|
121
|
-
case 0:
|
|
122
|
-
e.stopPropagation(); // Prevent image zoom.
|
|
123
|
-
return [4 /*yield*/, handleDownload()];
|
|
124
|
-
case 1:
|
|
125
|
-
_a.sent();
|
|
126
|
-
return [2 /*return*/];
|
|
127
|
-
}
|
|
128
|
-
});
|
|
129
|
-
}); } }))))));
|
|
69
|
+
React.createElement("div", { className: cn("s-absolute s-inset-0 s-bg-gradient-to-b", "s-from-black/40 s-via-transparent s-to-black/40", "s-opacity-0 s-transition-opacity s-duration-200", "group-hover/preview:s-opacity-100") }),
|
|
70
|
+
React.createElement("div", { className: cn("s-absolute s-right-3 s-top-3 s-z-10 s-flex", "s-opacity-0 s-transition-opacity s-duration-200", "group-hover/preview:s-opacity-100") },
|
|
71
|
+
React.createElement(DownloadButton, { src: src, title: title, size: "xs" }))))));
|
|
130
72
|
}
|
|
131
73
|
//# sourceMappingURL=InteractiveImage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InteractiveImage.js","sourceRoot":"","sources":["../../../src/components/InteractiveImage.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EACL,MAAM,EACN,aAAa,EACb,aAAa,EACb,UAAU,EACV,OAAO,GACR,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"InteractiveImage.js","sourceRoot":"","sources":["../../../src/components/InteractiveImage.tsx"],"names":[],"mappings":"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"}
|
package/dist/sparkle.css
CHANGED
|
@@ -2311,6 +2311,10 @@ select {
|
|
|
2311
2311
|
border-radius: 0.375rem;
|
|
2312
2312
|
}
|
|
2313
2313
|
|
|
2314
|
+
.s-rounded-none {
|
|
2315
|
+
border-radius: 0px;
|
|
2316
|
+
}
|
|
2317
|
+
|
|
2314
2318
|
.s-rounded-sm {
|
|
2315
2319
|
border-radius: 0.125rem;
|
|
2316
2320
|
}
|
|
@@ -2674,11 +2678,6 @@ select {
|
|
|
2674
2678
|
background-color: rgb(255 255 255 / 0.8);
|
|
2675
2679
|
}
|
|
2676
2680
|
|
|
2677
|
-
.s-bg-black {
|
|
2678
|
-
--tw-bg-opacity: 1;
|
|
2679
|
-
background-color: rgb(0 0 0 / var(--tw-bg-opacity));
|
|
2680
|
-
}
|
|
2681
|
-
|
|
2682
2681
|
.s-bg-blue-100 {
|
|
2683
2682
|
--tw-bg-opacity: 1;
|
|
2684
2683
|
background-color: rgb(202 235 255 / var(--tw-bg-opacity));
|
|
@@ -3563,6 +3562,10 @@ select {
|
|
|
3563
3562
|
background-color: rgb(169 184 169 / var(--tw-bg-opacity));
|
|
3564
3563
|
}
|
|
3565
3564
|
|
|
3565
|
+
.s-bg-transparent {
|
|
3566
|
+
background-color: transparent;
|
|
3567
|
+
}
|
|
3568
|
+
|
|
3566
3569
|
.s-bg-violet-100 {
|
|
3567
3570
|
--tw-bg-opacity: 1;
|
|
3568
3571
|
background-color: rgb(237 233 254 / var(--tw-bg-opacity));
|
|
@@ -3697,6 +3700,10 @@ select {
|
|
|
3697
3700
|
background-color: rgb(254 240 138 / var(--tw-bg-opacity));
|
|
3698
3701
|
}
|
|
3699
3702
|
|
|
3703
|
+
.s-bg-gradient-to-b {
|
|
3704
|
+
background-image: linear-gradient(to bottom, var(--tw-gradient-stops));
|
|
3705
|
+
}
|
|
3706
|
+
|
|
3700
3707
|
.s-bg-gradient-to-r {
|
|
3701
3708
|
background-image: linear-gradient(to right, var(--tw-gradient-stops));
|
|
3702
3709
|
}
|
|
@@ -3709,6 +3716,12 @@ select {
|
|
|
3709
3716
|
background-image: linear-gradient(90deg, #7AC6FF, #1C91FF, #a855f7, #4BABFF, #0A6CC6);
|
|
3710
3717
|
}
|
|
3711
3718
|
|
|
3719
|
+
.s-from-black\/40 {
|
|
3720
|
+
--tw-gradient-from: rgb(0 0 0 / 0.4) var(--tw-gradient-from-position);
|
|
3721
|
+
--tw-gradient-to: rgb(0 0 0 / 0) var(--tw-gradient-to-position);
|
|
3722
|
+
--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
|
|
3723
|
+
}
|
|
3724
|
+
|
|
3712
3725
|
.s-from-cyan-500 {
|
|
3713
3726
|
--tw-gradient-from: #06b6d4 var(--tw-gradient-from-position);
|
|
3714
3727
|
--tw-gradient-to: rgb(6 182 212 / 0) var(--tw-gradient-to-position);
|
|
@@ -3826,6 +3839,11 @@ select {
|
|
|
3826
3839
|
--tw-gradient-stops: var(--tw-gradient-from), #04140A var(--tw-gradient-via-position), var(--tw-gradient-to);
|
|
3827
3840
|
}
|
|
3828
3841
|
|
|
3842
|
+
.s-via-transparent {
|
|
3843
|
+
--tw-gradient-to: rgb(0 0 0 / 0) var(--tw-gradient-to-position);
|
|
3844
|
+
--tw-gradient-stops: var(--tw-gradient-from), transparent var(--tw-gradient-via-position), var(--tw-gradient-to);
|
|
3845
|
+
}
|
|
3846
|
+
|
|
3829
3847
|
.s-via-warning-950 {
|
|
3830
3848
|
--tw-gradient-to: rgb(34 10 4 / 0) var(--tw-gradient-to-position);
|
|
3831
3849
|
--tw-gradient-stops: var(--tw-gradient-from), #220A04 var(--tw-gradient-via-position), var(--tw-gradient-to);
|
|
@@ -3835,6 +3853,10 @@ select {
|
|
|
3835
3853
|
--tw-gradient-via-position: 50%;
|
|
3836
3854
|
}
|
|
3837
3855
|
|
|
3856
|
+
.s-to-black\/40 {
|
|
3857
|
+
--tw-gradient-to: rgb(0 0 0 / 0.4) var(--tw-gradient-to-position);
|
|
3858
|
+
}
|
|
3859
|
+
|
|
3838
3860
|
.s-to-blue-500 {
|
|
3839
3861
|
--tw-gradient-to: #1C91FF var(--tw-gradient-to-position);
|
|
3840
3862
|
}
|
|
@@ -4899,6 +4921,12 @@ select {
|
|
|
4899
4921
|
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
|
4900
4922
|
}
|
|
4901
4923
|
|
|
4924
|
+
.s-shadow-none {
|
|
4925
|
+
--tw-shadow: 0 0 #0000;
|
|
4926
|
+
--tw-shadow-colored: 0 0 #0000;
|
|
4927
|
+
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
|
4928
|
+
}
|
|
4929
|
+
|
|
4902
4930
|
.s-shadow-sm {
|
|
4903
4931
|
--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
|
4904
4932
|
--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);
|
|
@@ -5811,10 +5839,6 @@ select {
|
|
|
5811
5839
|
opacity: 1;
|
|
5812
5840
|
}
|
|
5813
5841
|
|
|
5814
|
-
.s-group\/preview:hover .group-hover\/preview\:s-opacity-40 {
|
|
5815
|
-
opacity: 0.4;
|
|
5816
|
-
}
|
|
5817
|
-
|
|
5818
5842
|
.s-group\/tree:hover .group-hover\/tree\:s-opacity-100 {
|
|
5819
5843
|
opacity: 1;
|
|
5820
5844
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dust-tt/sparkle",
|
|
3
|
-
"version": "0.2.481-
|
|
3
|
+
"version": "0.2.481-rc3",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"build": "rm -rf dist && npm run tailwind && npm run build:esm && npm run build:cjs",
|
|
6
6
|
"tailwind": "tailwindcss -i ./src/styles/tailwind.css -o dist/sparkle.css",
|
|
@@ -7,19 +7,53 @@ import {
|
|
|
7
7
|
IconButton,
|
|
8
8
|
Spinner,
|
|
9
9
|
} from "@sparkle/components/";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
ArrowDownOnSquareIcon,
|
|
13
|
-
ClipboardCheckIcon,
|
|
14
|
-
ClipboardIcon,
|
|
15
|
-
} from "@sparkle/icons/app";
|
|
10
|
+
import { ArrowDownOnSquareIcon } from "@sparkle/icons/app";
|
|
16
11
|
import { cn } from "@sparkle/lib/utils";
|
|
17
12
|
|
|
13
|
+
interface DownloadButtonProps {
|
|
14
|
+
className?: string;
|
|
15
|
+
size?: "xs" | "sm";
|
|
16
|
+
src?: string;
|
|
17
|
+
title: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function DownloadButton({
|
|
21
|
+
className,
|
|
22
|
+
size = "xs",
|
|
23
|
+
src,
|
|
24
|
+
title,
|
|
25
|
+
}: DownloadButtonProps) {
|
|
26
|
+
const handleDownload = React.useCallback(async () => {
|
|
27
|
+
if (!src) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Create a hidden link and click it.
|
|
32
|
+
const link = document.createElement("a");
|
|
33
|
+
link.href = src;
|
|
34
|
+
link.download = title;
|
|
35
|
+
document.body.appendChild(link);
|
|
36
|
+
link.click();
|
|
37
|
+
document.body.removeChild(link);
|
|
38
|
+
}, [src, title]);
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<IconButton
|
|
42
|
+
icon={ArrowDownOnSquareIcon}
|
|
43
|
+
className={cn("s-text-white", className)}
|
|
44
|
+
tooltip="Download"
|
|
45
|
+
size={size}
|
|
46
|
+
onClick={async (e) => {
|
|
47
|
+
e.stopPropagation(); // Prevent image zoom.
|
|
48
|
+
await handleDownload();
|
|
49
|
+
}}
|
|
50
|
+
/>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
18
54
|
interface InteractiveImageProps {
|
|
19
55
|
alt: string;
|
|
20
56
|
isLoading?: boolean;
|
|
21
|
-
onCopyError?: (error: unknown) => void;
|
|
22
|
-
onDownloadError?: (error: unknown) => void;
|
|
23
57
|
src?: string;
|
|
24
58
|
title: string;
|
|
25
59
|
}
|
|
@@ -56,8 +90,22 @@ export function InteractiveImage({
|
|
|
56
90
|
/>
|
|
57
91
|
</div>
|
|
58
92
|
</DialogTrigger>
|
|
59
|
-
<DialogContent
|
|
60
|
-
|
|
93
|
+
<DialogContent
|
|
94
|
+
className={cn(
|
|
95
|
+
"s-w-auto s-max-w-none s-border-0 s-outline-none s-ring-0",
|
|
96
|
+
"focus:s-outline-none focus:s-ring-0",
|
|
97
|
+
"s-rounded-none s-bg-transparent s-shadow-none"
|
|
98
|
+
)}
|
|
99
|
+
size="xl"
|
|
100
|
+
>
|
|
101
|
+
<div className="s-flex s-flex-col">
|
|
102
|
+
<div className="s-flex s-justify-end s-pb-2 s-pr-1 s-pt-1">
|
|
103
|
+
<DownloadButton src={src} title={props.title} size="sm" />
|
|
104
|
+
</div>
|
|
105
|
+
<div className="s-relative s-w-full">
|
|
106
|
+
<img src={src} alt={alt} className="s-w-full s-object-contain" />
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
61
109
|
</DialogContent>
|
|
62
110
|
</Dialog>
|
|
63
111
|
);
|
|
@@ -66,7 +114,7 @@ export function InteractiveImage({
|
|
|
66
114
|
function LoadingImage() {
|
|
67
115
|
return (
|
|
68
116
|
<div className="s-flex s-h-full s-w-full s-items-center s-justify-center">
|
|
69
|
-
<Spinner variant="dark" size="
|
|
117
|
+
<Spinner variant="dark" size="md" />
|
|
70
118
|
</div>
|
|
71
119
|
);
|
|
72
120
|
}
|
|
@@ -81,67 +129,13 @@ function ImagePreview({
|
|
|
81
129
|
alt,
|
|
82
130
|
src,
|
|
83
131
|
title,
|
|
84
|
-
onCopyError,
|
|
85
|
-
onDownloadError,
|
|
86
132
|
}: ImagePreviewProps) {
|
|
87
|
-
const [isCopied, copyToClipboard] = useCopyToClipboard();
|
|
88
|
-
|
|
89
|
-
const handleCopy = async () => {
|
|
90
|
-
try {
|
|
91
|
-
if (!src) {
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Fetch the image as a blob.
|
|
96
|
-
const response = await fetch(src);
|
|
97
|
-
const blob = await response.blob();
|
|
98
|
-
|
|
99
|
-
// Copy to clipboard.
|
|
100
|
-
await copyToClipboard(
|
|
101
|
-
new ClipboardItem({
|
|
102
|
-
[blob.type]: blob,
|
|
103
|
-
})
|
|
104
|
-
);
|
|
105
|
-
} catch (error) {
|
|
106
|
-
onCopyError?.(error);
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
const handleDownload = async () => {
|
|
111
|
-
try {
|
|
112
|
-
if (!src) {
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// Fetch the image.
|
|
117
|
-
const response = await fetch(src);
|
|
118
|
-
const blob = await response.blob();
|
|
119
|
-
|
|
120
|
-
// Create a download link.
|
|
121
|
-
const url = window.URL.createObjectURL(blob);
|
|
122
|
-
const link = document.createElement("a");
|
|
123
|
-
link.href = url;
|
|
124
|
-
|
|
125
|
-
// Extract filename from URL or use a default.
|
|
126
|
-
link.download = title;
|
|
127
|
-
|
|
128
|
-
// Trigger download.
|
|
129
|
-
document.body.appendChild(link);
|
|
130
|
-
link.click();
|
|
131
|
-
|
|
132
|
-
// Cleanup.
|
|
133
|
-
document.body.removeChild(link);
|
|
134
|
-
window.URL.revokeObjectURL(url);
|
|
135
|
-
} catch (error) {
|
|
136
|
-
onDownloadError?.(error);
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
|
|
140
133
|
return (
|
|
141
134
|
<div
|
|
142
135
|
onClick={onClick}
|
|
143
136
|
className={cn(
|
|
144
|
-
"s-group/preview s-relative s-h-full s-w-full s-overflow-hidden s-rounded-2xl
|
|
137
|
+
"s-group/preview s-relative s-h-full s-w-full s-overflow-hidden s-rounded-2xl",
|
|
138
|
+
"s-bg-muted-background dark:s-bg-muted-background-night",
|
|
145
139
|
!isLoading && "s-cursor-pointer"
|
|
146
140
|
)}
|
|
147
141
|
>
|
|
@@ -155,29 +149,23 @@ function ImagePreview({
|
|
|
155
149
|
className="s-h-full s-w-full s-rounded-2xl s-object-cover"
|
|
156
150
|
/>
|
|
157
151
|
{/* Dark overlay on hover */}
|
|
158
|
-
<div
|
|
152
|
+
<div
|
|
153
|
+
className={cn(
|
|
154
|
+
"s-absolute s-inset-0 s-bg-gradient-to-b",
|
|
155
|
+
"s-from-black/40 s-via-transparent s-to-black/40",
|
|
156
|
+
"s-opacity-0 s-transition-opacity s-duration-200",
|
|
157
|
+
"group-hover/preview:s-opacity-100"
|
|
158
|
+
)}
|
|
159
|
+
/>
|
|
159
160
|
{/* Icon container - only visible on hover */}
|
|
160
|
-
<div
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
await handleCopy();
|
|
169
|
-
}}
|
|
170
|
-
/>
|
|
171
|
-
<IconButton
|
|
172
|
-
icon={ArrowDownOnSquareIcon}
|
|
173
|
-
className="s-text-white"
|
|
174
|
-
tooltip="Download"
|
|
175
|
-
size="xs"
|
|
176
|
-
onClick={async (e) => {
|
|
177
|
-
e.stopPropagation(); // Prevent image zoom.
|
|
178
|
-
await handleDownload();
|
|
179
|
-
}}
|
|
180
|
-
/>
|
|
161
|
+
<div
|
|
162
|
+
className={cn(
|
|
163
|
+
"s-absolute s-right-3 s-top-3 s-z-10 s-flex",
|
|
164
|
+
"s-opacity-0 s-transition-opacity s-duration-200",
|
|
165
|
+
"group-hover/preview:s-opacity-100"
|
|
166
|
+
)}
|
|
167
|
+
>
|
|
168
|
+
<DownloadButton src={src} title={title} size="xs" />
|
|
181
169
|
</div>
|
|
182
170
|
</>
|
|
183
171
|
)}
|