refactor: preview image modal

This commit is contained in:
Tristan Yang
2025-08-10 18:11:55 +08:00
parent 880ef4f2cc
commit db525ea222
7 changed files with 1603 additions and 1903 deletions
+2 -2
View File
@@ -12,8 +12,8 @@ const prices: Price[] = [
},
];
const official_dev = `https://dev.voce.chat`;
const local_dev = `http://localhost:3000`;
// const local_dev = `http://chat.jcdl369.top:3009`;
const local_dev = `http://localhost:3333`;
// const local_dev = `https://dev.voce.chat`;
const dev_origin = process.env.REACT_APP_OFFICIAL_DEMO ? official_dev : local_dev;
// const local_dev = `https://im.ttt.td`;
+31 -67
View File
@@ -1,10 +1,11 @@
import { FC, useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { Ring } from "@uiball/loaders";
import { useKey, useOutsideClick } from "rooks";
import Modal from "./Modal";
import { FC } from "react";
import { Lightbox } from "yet-another-react-lightbox";
import "yet-another-react-lightbox/styles.css";
import Fullscreen from "yet-another-react-lightbox/plugins/fullscreen";
import Download from "yet-another-react-lightbox/plugins/download";
import Captions from "yet-another-react-lightbox/plugins/captions";
import Zoom from "yet-another-react-lightbox/plugins/zoom";
import "yet-another-react-lightbox/plugins/captions.css";
export interface PreviewImageData {
originUrl: string;
thumbnail?: string;
@@ -20,69 +21,32 @@ interface Props {
}
const ImagePreviewModal: FC<Props> = ({ download = true, data, closeModal }) => {
const { t } = useTranslation();
const [url, setUrl] = useState(data?.thumbnail);
const [loading, setLoading] = useState(true);
const wrapperRef = useRef<HTMLDivElement>(null);
useOutsideClick(wrapperRef, closeModal);
useKey(
"Escape",
() => {
closeModal();
},
{ eventTypes: ["keyup"] }
);
useEffect(() => {
if (data) {
const { originUrl } = data;
if (!originUrl) setLoading(false);
const img = new Image();
img.src = originUrl;
img.onload = () => {
setUrl(originUrl);
setLoading(false);
};
img.onerror = () => {
setLoading(false);
};
}
}, [data]);
if (!data) return null;
const { originUrl, downloadLink, name, type } = data;
return (
<Modal>
<div className="w-screen h-screen flex-center bg-black/90">
<div className={`relative flex flex-col justify-start gap-3`} ref={wrapperRef}>
<div className="overflow-auto">
<img
className={`max-w-[70vw] max-h-[80vh] ${loading ? "blur-sm" : ""}`}
src={url}
alt="preview"
/>
</div>
{download && (
<a
// onClick={handleDownload}
className="font-semibold text-sm text-gray-600 hover:underline hover:text-white"
download={name}
type={type}
href={downloadLink || originUrl}
rel="noreferrer"
>
{t("action.download_origin")}
</a>
)}
{loading && (
<div className="absolute top-[40%] left-1/2 -translate-x-1/2">
<Ring />
</div>
)}
</div>
</div>
</Modal>
<Lightbox
open
close={closeModal}
styles={{
navigationNext: {
display: "none",
},
navigationPrev: {
display: "none",
},
}}
slides={[
{
src: originUrl,
alt: name,
title: name,
description: name,
download: downloadLink || originUrl,
},
]}
plugins={download ? [Captions, Fullscreen, Zoom, Download] : [Captions, Fullscreen, Zoom]}
captions={{ descriptionTextAlign: "center" }}
/>
);
};
@@ -1,17 +1,14 @@
import { forwardRef } from "react";
import { PlateElement, PlateElementProps } from "@udecode/plate-common";
import { cn } from "@/utils";
const ParagraphElement = forwardRef<React.ElementRef<typeof PlateElement>, PlateElementProps>(
({ className, children, ...props }: PlateElementProps, ref) => {
return (
<PlateElement ref={ref} className={cn("m-0 px-0 py-1", className)} {...props}>
{children}
</PlateElement>
);
}
);
const ParagraphElement = ({ className, children, ref, ...props }: PlateElementProps) => {
return (
<PlateElement ref={ref} className={cn("m-0 px-0 py-1", className)} {...props}>
{children}
</PlateElement>
);
};
ParagraphElement.displayName = "ParagraphElement";
export { ParagraphElement };
@@ -1,9 +1,7 @@
import { forwardRef } from "react";
// @ts-ignore
const CustomList = forwardRef(({ style, ...props }, ref) => {
const CustomList = ({ style, ref, ...props }) => {
// @ts-ignore
return <div style={{ ...style, width: `calc(100% - 2rem)` }} {...props} ref={ref} />;
});
};
export default CustomList;