@dust-tt/sparkle 0.2.490 → 0.2.491
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/Breadcrumbs.d.ts +2 -1
- package/dist/esm/components/Breadcrumbs.d.ts.map +1 -1
- package/dist/esm/components/Breadcrumbs.js +14 -14
- package/dist/esm/components/Breadcrumbs.js.map +1 -1
- package/dist/esm/components/InteractiveImageGrid.d.ts +14 -0
- package/dist/esm/components/InteractiveImageGrid.d.ts.map +1 -0
- package/dist/esm/components/InteractiveImageGrid.js +137 -0
- package/dist/esm/components/InteractiveImageGrid.js.map +1 -0
- package/dist/esm/components/index.d.ts +1 -1
- package/dist/esm/components/index.d.ts.map +1 -1
- package/dist/esm/components/index.js +1 -1
- package/dist/esm/components/index.js.map +1 -1
- package/dist/esm/stories/Breadcrumbs.stories.d.ts +11 -1
- package/dist/esm/stories/Breadcrumbs.stories.d.ts.map +1 -1
- package/dist/esm/stories/Breadcrumbs.stories.js +14 -6
- package/dist/esm/stories/Breadcrumbs.stories.js.map +1 -1
- package/dist/esm/stories/{InteractiveImage.stories.d.ts → InteractiveImageGrid.stories.d.ts} +1 -1
- package/dist/esm/stories/InteractiveImageGrid.stories.d.ts.map +1 -0
- package/dist/esm/stories/InteractiveImageGrid.stories.js +59 -0
- package/dist/esm/stories/InteractiveImageGrid.stories.js.map +1 -0
- package/dist/esm/styles/global.css +30 -0
- package/dist/sparkle.css +49 -28
- package/package.json +1 -1
- package/src/components/Breadcrumbs.tsx +35 -9
- package/src/components/InteractiveImageGrid.tsx +310 -0
- package/src/components/index.ts +1 -1
- package/src/stories/Breadcrumbs.stories.tsx +17 -6
- package/src/stories/InteractiveImageGrid.stories.tsx +70 -0
- package/src/styles/global.css +30 -0
- package/dist/esm/components/InteractiveImage.d.ts +0 -11
- package/dist/esm/components/InteractiveImage.d.ts.map +0 -1
- package/dist/esm/components/InteractiveImage.js +0 -73
- package/dist/esm/components/InteractiveImage.js.map +0 -1
- package/dist/esm/stories/InteractiveImage.stories.d.ts.map +0 -1
- package/dist/esm/stories/InteractiveImage.stories.js +0 -17
- package/dist/esm/stories/InteractiveImage.stories.js.map +0 -1
- package/src/components/InteractiveImage.tsx +0 -190
- package/src/stories/InteractiveImage.stories.tsx +0 -39
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { Meta } from "@storybook/react";
|
|
2
|
+
import React from "react";
|
|
3
|
+
|
|
4
|
+
import { InteractiveImageGrid } from "@sparkle/components/InteractiveImageGrid";
|
|
5
|
+
|
|
6
|
+
import { Citation } from "../index_with_tw_base";
|
|
7
|
+
|
|
8
|
+
const meta = {
|
|
9
|
+
title: "Components/Citation",
|
|
10
|
+
component: Citation,
|
|
11
|
+
} satisfies Meta<typeof Citation>;
|
|
12
|
+
|
|
13
|
+
export default meta;
|
|
14
|
+
|
|
15
|
+
const images = [
|
|
16
|
+
{
|
|
17
|
+
alt: "Example of a loading interactive image",
|
|
18
|
+
isLoading: true,
|
|
19
|
+
title: "Example of a loading interactive image",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
alt: "Example of an interactive image",
|
|
23
|
+
downloadUrl: "https://dust.tt/static/droidavatar/Droid_Lime_2.jpg",
|
|
24
|
+
imageUrl: "https://dust.tt/static/droidavatar/Droid_Lime_2.jpg",
|
|
25
|
+
title: "Example of an interactive image",
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
alt: "Example of an interactive image",
|
|
29
|
+
downloadUrl: "https://dust.tt/static/droidavatar/Droid_Lime_3.jpg",
|
|
30
|
+
imageUrl: "https://dust.tt/static/droidavatar/Droid_Lime_3.jpg",
|
|
31
|
+
title: "Example of an interactive image",
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
alt: "Example of an interactive image",
|
|
35
|
+
downloadUrl: "https://dust.tt/static/droidavatar/Droid_Lime_4.jpg",
|
|
36
|
+
imageUrl: "https://dust.tt/static/droidavatar/Droid_Lime_4.jpg",
|
|
37
|
+
title: "Example of an interactive image",
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
alt: "Example of an interactive image",
|
|
41
|
+
downloadUrl: "https://dust.tt/static/droidavatar/Droid_Lime_5.jpg",
|
|
42
|
+
imageUrl: "https://dust.tt/static/droidavatar/Droid_Lime_5.jpg",
|
|
43
|
+
title: "Example of an interactive image",
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
alt: "Example of an interactive image",
|
|
47
|
+
downloadUrl: "https://dust.tt/static/droidavatar/Droid_Lime_6.jpg",
|
|
48
|
+
imageUrl: "https://dust.tt/static/droidavatar/Droid_Lime_6.jpg",
|
|
49
|
+
title: "Example of an interactive image",
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
alt: "Example of an interactive PNG image",
|
|
53
|
+
downloadUrl: "https://dust.tt/static/DustHorizontalIcon.png",
|
|
54
|
+
imageUrl: "https://dust.tt/static/DustHorizontalIcon.png",
|
|
55
|
+
title: "Example of an interactive image",
|
|
56
|
+
},
|
|
57
|
+
];
|
|
58
|
+
|
|
59
|
+
export const InteractiveImageExample = () => (
|
|
60
|
+
<div className="s-flex s-flex-col s-gap-8">
|
|
61
|
+
<div className="s-w-[700px]">
|
|
62
|
+
<h2>Interactive Image Grid</h2>
|
|
63
|
+
<InteractiveImageGrid images={images} />
|
|
64
|
+
</div>
|
|
65
|
+
<div className="s-w-[700px]">
|
|
66
|
+
<h2>Interactive Image Grid with 1 image</h2>
|
|
67
|
+
<InteractiveImageGrid images={images.slice(1, 2)} />
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
);
|
package/src/styles/global.css
CHANGED
|
@@ -22,6 +22,36 @@
|
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
@layer utilities {
|
|
26
|
+
.s-checkerboard {
|
|
27
|
+
background-image: linear-gradient(
|
|
28
|
+
45deg,
|
|
29
|
+
var(--tw-checker-color) 25%,
|
|
30
|
+
transparent 25%,
|
|
31
|
+
transparent 75%,
|
|
32
|
+
var(--tw-checker-color) 75%
|
|
33
|
+
),
|
|
34
|
+
linear-gradient(
|
|
35
|
+
45deg,
|
|
36
|
+
var(--tw-checker-color) 25%,
|
|
37
|
+
transparent 25%,
|
|
38
|
+
transparent 75%,
|
|
39
|
+
var(--tw-checker-color) 75%
|
|
40
|
+
);
|
|
41
|
+
background-size: 40px 40px;
|
|
42
|
+
background-position:
|
|
43
|
+
0 0,
|
|
44
|
+
20px 20px;
|
|
45
|
+
background-color: theme("colors.white"); /* Base color */
|
|
46
|
+
--tw-checker-color: theme("colors.gray.50"); /* Pattern color */
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.s-dark .s-checkerboard {
|
|
50
|
+
background-color: theme("colors.black"); /* Dark mode base color */
|
|
51
|
+
--tw-checker-color: theme("colors.slate.950"); /* Dark mode pattern color */
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
25
55
|
.s-blinking-cursor > :not(pre):last-child::after {
|
|
26
56
|
content: "";
|
|
27
57
|
width: 8px;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
interface InteractiveImageProps {
|
|
3
|
-
alt: string;
|
|
4
|
-
downloadUrl?: string;
|
|
5
|
-
imageUrl?: string;
|
|
6
|
-
isLoading?: boolean;
|
|
7
|
-
title: string;
|
|
8
|
-
}
|
|
9
|
-
export declare function InteractiveImage({ alt, downloadUrl, imageUrl, isLoading, ...props }: InteractiveImageProps): React.JSX.Element;
|
|
10
|
-
export {};
|
|
11
|
-
//# sourceMappingURL=InteractiveImage.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
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,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,GAAG,EACH,WAAW,EACX,QAAQ,EACR,SAAiB,EACjB,GAAG,KAAK,EACT,EAAE,qBAAqB,qBA2DvB"}
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { __assign, __awaiter, __generator, __read, __rest } from "tslib";
|
|
2
|
-
import React from "react";
|
|
3
|
-
import { Dialog, DialogContent, DialogTrigger, IconButton, Spinner, } from "../components";
|
|
4
|
-
import { ArrowDownOnSquareIcon } from "../icons/app";
|
|
5
|
-
import { cn } from "../lib/utils";
|
|
6
|
-
function DownloadButton(_a) {
|
|
7
|
-
var _this = this;
|
|
8
|
-
var className = _a.className, downloadUrl = _a.downloadUrl, _b = _a.size, size = _b === void 0 ? "xs" : _b, 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 (!downloadUrl) {
|
|
13
|
-
return [2 /*return*/];
|
|
14
|
-
}
|
|
15
|
-
link = document.createElement("a");
|
|
16
|
-
link.href = downloadUrl;
|
|
17
|
-
link.download = title;
|
|
18
|
-
document.body.appendChild(link);
|
|
19
|
-
link.click();
|
|
20
|
-
document.body.removeChild(link);
|
|
21
|
-
return [2 /*return*/];
|
|
22
|
-
});
|
|
23
|
-
}); }, [downloadUrl, 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
|
-
}
|
|
37
|
-
export function InteractiveImage(_a) {
|
|
38
|
-
var alt = _a.alt, downloadUrl = _a.downloadUrl, imageUrl = _a.imageUrl, _b = _a.isLoading, isLoading = _b === void 0 ? false : _b, props = __rest(_a, ["alt", "downloadUrl", "imageUrl", "isLoading"]);
|
|
39
|
-
var _c = __read(React.useState(false), 2), isZoomed = _c[0], setIsZoomed = _c[1];
|
|
40
|
-
var _d = __read(React.useState(false), 2), imageLoaded = _d[0], setImageLoaded = _d[1];
|
|
41
|
-
var handleZoomToggle = React.useCallback(function () {
|
|
42
|
-
setIsZoomed(!isZoomed);
|
|
43
|
-
}, [isZoomed]);
|
|
44
|
-
return (React.createElement(Dialog, { open: isZoomed, onOpenChange: handleZoomToggle },
|
|
45
|
-
React.createElement(DialogTrigger, { asChild: true },
|
|
46
|
-
React.createElement("div", { className: "s-aspect-square s-h-80 s-w-80" },
|
|
47
|
-
React.createElement(ImagePreview, __assign({ alt: alt, downloadUrl: downloadUrl !== null && downloadUrl !== void 0 ? downloadUrl : imageUrl, isLoading: isLoading, onClick: function (e) {
|
|
48
|
-
if (isLoading) {
|
|
49
|
-
e.preventDefault();
|
|
50
|
-
e.stopPropagation();
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
handleZoomToggle();
|
|
54
|
-
}, imageUrl: imageUrl }, props)))),
|
|
55
|
-
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" },
|
|
56
|
-
React.createElement("div", { className: "s-flex s-flex-col" },
|
|
57
|
-
React.createElement("div", { className: "s-flex s-justify-end" }, imageLoaded && (React.createElement(DownloadButton, { downloadUrl: downloadUrl !== null && downloadUrl !== void 0 ? downloadUrl : imageUrl, title: props.title, size: "md" }))),
|
|
58
|
-
React.createElement("div", { className: "s-relative s-w-full" },
|
|
59
|
-
React.createElement("img", { src: imageUrl, alt: alt, className: "s-w-full s-object-contain", onLoad: function () { return setImageLoaded(true); } }))))));
|
|
60
|
-
}
|
|
61
|
-
function LoadingImage() {
|
|
62
|
-
return (React.createElement("div", { className: "s-flex s-h-full s-w-full s-items-center s-justify-center" },
|
|
63
|
-
React.createElement(Spinner, { variant: "dark", size: "md" })));
|
|
64
|
-
}
|
|
65
|
-
function ImagePreview(_a) {
|
|
66
|
-
var alt = _a.alt, downloadUrl = _a.downloadUrl, imageUrl = _a.imageUrl, isLoading = _a.isLoading, onClick = _a.onClick, 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,
|
|
68
|
-
React.createElement("img", { src: imageUrl, alt: alt, className: "s-h-full s-w-full s-rounded-2xl s-object-cover" }),
|
|
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, { downloadUrl: downloadUrl, title: title, size: "xs" }))))));
|
|
72
|
-
}
|
|
73
|
-
//# sourceMappingURL=InteractiveImage.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"InteractiveImage.js","sourceRoot":"","sources":["../../../src/components/InteractiveImage.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"InteractiveImage.stories.d.ts","sourceRoot":"","sources":["../../../src/stories/InteractiveImage.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAM1B,QAAA,MAAM,IAAI;;;;;;;CAGuB,CAAC;AAElC,eAAe,IAAI,CAAC;AAEpB,eAAO,MAAM,uBAAuB,yBAwBnC,CAAC"}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { InteractiveImage } from "../components/InteractiveImage";
|
|
3
|
-
import { Citation } from "../index_with_tw_base";
|
|
4
|
-
var meta = {
|
|
5
|
-
title: "Components/Citation",
|
|
6
|
-
component: Citation,
|
|
7
|
-
};
|
|
8
|
-
export default meta;
|
|
9
|
-
export var InteractiveImageExample = function () { return (React.createElement("div", { className: "s-flex s-flex-col s-gap-8" },
|
|
10
|
-
"Example of interactive image",
|
|
11
|
-
React.createElement("h2", null, "Loading"),
|
|
12
|
-
React.createElement(InteractiveImage, { alt: "Example of a loading interactive image", isLoading: true, title: "Example of a loading interactive image" }),
|
|
13
|
-
React.createElement("h2", null, "Loaded"),
|
|
14
|
-
React.createElement(InteractiveImage, { alt: "Example of an interactive image", downloadUrl: "https://dust.tt/static/droidavatar/Droid_Lime_3.jpg", imageUrl: "https://dust.tt/static/droidavatar/Droid_Lime_3.jpg", title: "Example of an interactive image" }),
|
|
15
|
-
React.createElement("h3", null, "With 4:3 aspect ratio"),
|
|
16
|
-
React.createElement(InteractiveImage, { alt: "Example of a 4:3 aspect ratio interactive image", downloadUrl: "https://upload.wikimedia.org/wikipedia/commons/d/de/Aspect-ratio-4x3.svg", imageUrl: "https://upload.wikimedia.org/wikipedia/commons/d/de/Aspect-ratio-4x3.svg", title: "Example of a 4:3 aspect ratio interactive image" }))); };
|
|
17
|
-
//# sourceMappingURL=InteractiveImage.stories.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"InteractiveImage.stories.js","sourceRoot":"","sources":["../../../src/stories/InteractiveImage.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAExE,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,IAAM,IAAI,GAAG;IACX,KAAK,EAAE,qBAAqB;IAC5B,SAAS,EAAE,QAAQ;CACY,CAAC;AAElC,eAAe,IAAI,CAAC;AAEpB,MAAM,CAAC,IAAM,uBAAuB,GAAG,cAAM,OAAA,CAC3C,6BAAK,SAAS,EAAC,2BAA2B;;IAExC,0CAAgB;IAChB,oBAAC,gBAAgB,IACf,GAAG,EAAC,wCAAwC,EAC5C,SAAS,EAAE,IAAI,EACf,KAAK,EAAC,wCAAwC,GAC9C;IACF,yCAAe;IACf,oBAAC,gBAAgB,IACf,GAAG,EAAC,iCAAiC,EACrC,WAAW,EAAC,qDAAqD,EACjE,QAAQ,EAAC,qDAAqD,EAC9D,KAAK,EAAC,iCAAiC,GACvC;IACF,wDAA8B;IAC9B,oBAAC,gBAAgB,IACf,GAAG,EAAC,iDAAiD,EACrD,WAAW,EAAC,0EAA0E,EACtF,QAAQ,EAAC,0EAA0E,EACnF,KAAK,EAAC,iDAAiD,GACvD,CACE,CACP,EAxB4C,CAwB5C,CAAC"}
|
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
Dialog,
|
|
5
|
-
DialogContent,
|
|
6
|
-
DialogTrigger,
|
|
7
|
-
IconButton,
|
|
8
|
-
Spinner,
|
|
9
|
-
} from "@sparkle/components/";
|
|
10
|
-
import { ArrowDownOnSquareIcon } from "@sparkle/icons/app";
|
|
11
|
-
import { cn } from "@sparkle/lib/utils";
|
|
12
|
-
|
|
13
|
-
interface DownloadButtonProps {
|
|
14
|
-
className?: string;
|
|
15
|
-
downloadUrl?: string;
|
|
16
|
-
size?: "xs" | "sm" | "md";
|
|
17
|
-
title: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function DownloadButton({
|
|
21
|
-
className,
|
|
22
|
-
downloadUrl,
|
|
23
|
-
size = "xs",
|
|
24
|
-
title,
|
|
25
|
-
}: DownloadButtonProps) {
|
|
26
|
-
const handleDownload = React.useCallback(async () => {
|
|
27
|
-
if (!downloadUrl) {
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Create a hidden link and click it.
|
|
32
|
-
const link = document.createElement("a");
|
|
33
|
-
link.href = downloadUrl;
|
|
34
|
-
link.download = title;
|
|
35
|
-
document.body.appendChild(link);
|
|
36
|
-
link.click();
|
|
37
|
-
document.body.removeChild(link);
|
|
38
|
-
}, [downloadUrl, 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
|
-
|
|
54
|
-
interface InteractiveImageProps {
|
|
55
|
-
alt: string;
|
|
56
|
-
downloadUrl?: string;
|
|
57
|
-
imageUrl?: string;
|
|
58
|
-
isLoading?: boolean;
|
|
59
|
-
title: string;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export function InteractiveImage({
|
|
63
|
-
alt,
|
|
64
|
-
downloadUrl,
|
|
65
|
-
imageUrl,
|
|
66
|
-
isLoading = false,
|
|
67
|
-
...props
|
|
68
|
-
}: InteractiveImageProps) {
|
|
69
|
-
const [isZoomed, setIsZoomed] = React.useState(false);
|
|
70
|
-
const [imageLoaded, setImageLoaded] = React.useState(false);
|
|
71
|
-
|
|
72
|
-
const handleZoomToggle = React.useCallback(() => {
|
|
73
|
-
setIsZoomed(!isZoomed);
|
|
74
|
-
}, [isZoomed]);
|
|
75
|
-
|
|
76
|
-
return (
|
|
77
|
-
<Dialog open={isZoomed} onOpenChange={handleZoomToggle}>
|
|
78
|
-
<DialogTrigger asChild>
|
|
79
|
-
<div className="s-aspect-square s-h-80 s-w-80">
|
|
80
|
-
<ImagePreview
|
|
81
|
-
alt={alt}
|
|
82
|
-
downloadUrl={downloadUrl ?? imageUrl}
|
|
83
|
-
isLoading={isLoading}
|
|
84
|
-
onClick={(e) => {
|
|
85
|
-
if (isLoading) {
|
|
86
|
-
e.preventDefault();
|
|
87
|
-
e.stopPropagation();
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
handleZoomToggle();
|
|
91
|
-
}}
|
|
92
|
-
imageUrl={imageUrl}
|
|
93
|
-
{...props}
|
|
94
|
-
/>
|
|
95
|
-
</div>
|
|
96
|
-
</DialogTrigger>
|
|
97
|
-
<DialogContent
|
|
98
|
-
className={cn(
|
|
99
|
-
"s-w-auto s-max-w-none s-border-0 s-outline-none s-ring-0",
|
|
100
|
-
"focus:s-outline-none focus:s-ring-0",
|
|
101
|
-
"s-rounded-none s-bg-transparent s-shadow-none"
|
|
102
|
-
)}
|
|
103
|
-
size="xl"
|
|
104
|
-
>
|
|
105
|
-
<div className="s-flex s-flex-col">
|
|
106
|
-
<div className="s-flex s-justify-end">
|
|
107
|
-
{imageLoaded && (
|
|
108
|
-
<DownloadButton
|
|
109
|
-
downloadUrl={downloadUrl ?? imageUrl}
|
|
110
|
-
title={props.title}
|
|
111
|
-
size="md"
|
|
112
|
-
/>
|
|
113
|
-
)}
|
|
114
|
-
</div>
|
|
115
|
-
<div className="s-relative s-w-full">
|
|
116
|
-
<img
|
|
117
|
-
src={imageUrl}
|
|
118
|
-
alt={alt}
|
|
119
|
-
className="s-w-full s-object-contain"
|
|
120
|
-
onLoad={() => setImageLoaded(true)}
|
|
121
|
-
/>
|
|
122
|
-
</div>
|
|
123
|
-
</div>
|
|
124
|
-
</DialogContent>
|
|
125
|
-
</Dialog>
|
|
126
|
-
);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function LoadingImage() {
|
|
130
|
-
return (
|
|
131
|
-
<div className="s-flex s-h-full s-w-full s-items-center s-justify-center">
|
|
132
|
-
<Spinner variant="dark" size="md" />
|
|
133
|
-
</div>
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
type ImagePreviewProps = InteractiveImageProps & {
|
|
138
|
-
onClick?: (e: React.MouseEvent) => void;
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
function ImagePreview({
|
|
142
|
-
alt,
|
|
143
|
-
downloadUrl,
|
|
144
|
-
imageUrl,
|
|
145
|
-
isLoading,
|
|
146
|
-
onClick,
|
|
147
|
-
title,
|
|
148
|
-
}: ImagePreviewProps) {
|
|
149
|
-
return (
|
|
150
|
-
<div
|
|
151
|
-
onClick={onClick}
|
|
152
|
-
className={cn(
|
|
153
|
-
"s-group/preview s-relative s-h-full s-w-full s-overflow-hidden s-rounded-2xl",
|
|
154
|
-
"s-bg-muted-background dark:s-bg-muted-background-night",
|
|
155
|
-
!isLoading && "s-cursor-pointer"
|
|
156
|
-
)}
|
|
157
|
-
>
|
|
158
|
-
{isLoading ? (
|
|
159
|
-
<LoadingImage />
|
|
160
|
-
) : (
|
|
161
|
-
<>
|
|
162
|
-
<img
|
|
163
|
-
src={imageUrl}
|
|
164
|
-
alt={alt}
|
|
165
|
-
className="s-h-full s-w-full s-rounded-2xl s-object-cover"
|
|
166
|
-
/>
|
|
167
|
-
{/* Dark overlay on hover */}
|
|
168
|
-
<div
|
|
169
|
-
className={cn(
|
|
170
|
-
"s-absolute s-inset-0 s-bg-gradient-to-b",
|
|
171
|
-
"s-from-black/40 s-via-transparent s-to-black/40",
|
|
172
|
-
"s-opacity-0 s-transition-opacity s-duration-200",
|
|
173
|
-
"group-hover/preview:s-opacity-100"
|
|
174
|
-
)}
|
|
175
|
-
/>
|
|
176
|
-
{/* Icon container - only visible on hover */}
|
|
177
|
-
<div
|
|
178
|
-
className={cn(
|
|
179
|
-
"s-absolute s-right-3 s-top-3 s-z-10 s-flex",
|
|
180
|
-
"s-opacity-0 s-transition-opacity s-duration-200",
|
|
181
|
-
"group-hover/preview:s-opacity-100"
|
|
182
|
-
)}
|
|
183
|
-
>
|
|
184
|
-
<DownloadButton downloadUrl={downloadUrl} title={title} size="xs" />
|
|
185
|
-
</div>
|
|
186
|
-
</>
|
|
187
|
-
)}
|
|
188
|
-
</div>
|
|
189
|
-
);
|
|
190
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import type { Meta } from "@storybook/react";
|
|
2
|
-
import React from "react";
|
|
3
|
-
|
|
4
|
-
import { InteractiveImage } from "@sparkle/components/InteractiveImage";
|
|
5
|
-
|
|
6
|
-
import { Citation } from "../index_with_tw_base";
|
|
7
|
-
|
|
8
|
-
const meta = {
|
|
9
|
-
title: "Components/Citation",
|
|
10
|
-
component: Citation,
|
|
11
|
-
} satisfies Meta<typeof Citation>;
|
|
12
|
-
|
|
13
|
-
export default meta;
|
|
14
|
-
|
|
15
|
-
export const InteractiveImageExample = () => (
|
|
16
|
-
<div className="s-flex s-flex-col s-gap-8">
|
|
17
|
-
Example of interactive image
|
|
18
|
-
<h2>Loading</h2>
|
|
19
|
-
<InteractiveImage
|
|
20
|
-
alt="Example of a loading interactive image"
|
|
21
|
-
isLoading={true}
|
|
22
|
-
title="Example of a loading interactive image"
|
|
23
|
-
/>
|
|
24
|
-
<h2>Loaded</h2>
|
|
25
|
-
<InteractiveImage
|
|
26
|
-
alt="Example of an interactive image"
|
|
27
|
-
downloadUrl="https://dust.tt/static/droidavatar/Droid_Lime_3.jpg"
|
|
28
|
-
imageUrl="https://dust.tt/static/droidavatar/Droid_Lime_3.jpg"
|
|
29
|
-
title="Example of an interactive image"
|
|
30
|
-
/>
|
|
31
|
-
<h3>With 4:3 aspect ratio</h3>
|
|
32
|
-
<InteractiveImage
|
|
33
|
-
alt="Example of a 4:3 aspect ratio interactive image"
|
|
34
|
-
downloadUrl="https://upload.wikimedia.org/wikipedia/commons/d/de/Aspect-ratio-4x3.svg"
|
|
35
|
-
imageUrl="https://upload.wikimedia.org/wikipedia/commons/d/de/Aspect-ratio-4x3.svg"
|
|
36
|
-
title="Example of a 4:3 aspect ratio interactive image"
|
|
37
|
-
/>
|
|
38
|
-
</div>
|
|
39
|
-
);
|