diff --git a/src/common/component/ImagePreview.tsx b/src/common/component/ImagePreview.tsx new file mode 100644 index 00000000..62a83b1c --- /dev/null +++ b/src/common/component/ImagePreview.tsx @@ -0,0 +1,52 @@ +import { useEffect, useState } from 'react'; +import ImagePreviewModal, { PreviewImageData } from "../../common/component/ImagePreviewModal"; +type Props = { + context?: "chat" | "markdown", + container: HTMLElement | null +} + +const ImagePreview = ({ container, context = "chat" }: Props) => { + const [previewImage, setPreviewImage] = useState(null); + const closePreviewModal = () => { + setPreviewImage(null); + }; + useEffect(() => { + if (!container) return; + const chatHandler = (evt: MouseEvent) => { + const target = evt.target as HTMLImageElement; + if (!target) return; + if (target.nodeName == "IMG" && target.classList.contains("preview")) { + const thumbnail = target.src; + const originUrl = target.dataset.origin || target.src; + const downloadLink = target.dataset.download || target.src; + const meta = JSON.parse(target.dataset.meta || "{}"); + setPreviewImage({ thumbnail, originUrl, downloadLink, ...meta }); + } + }; + const markdownHandler = (evt: MouseEvent) => { + evt.stopPropagation(); + const target = evt.target as HTMLImageElement; + if (!target) return; + // 图片 + if (target.nodeName == "IMG") { + const urlObj = new URL(target.src); + const originUrl = `${urlObj.origin}${urlObj.pathname}?file_path=${urlObj.searchParams.get( + "file_path" + )}`; + const data = { originUrl }; + setPreviewImage(data); + } + }; + + const handler = context == 'chat' ? chatHandler : markdownHandler; + // 点击查看大图 + container.addEventListener("click", handler, true); + return () => { + container.removeEventListener("click", handler, true); + }; + }, [container, context]); + return previewImage ? : null; + +}; + +export default ImagePreview; \ No newline at end of file diff --git a/src/common/component/MarkdownRender.tsx b/src/common/component/MarkdownRender.tsx index 02a4b141..a9bf1196 100644 --- a/src/common/component/MarkdownRender.tsx +++ b/src/common/component/MarkdownRender.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState, useRef, FC } from "react"; +import { useRef, FC } from "react"; import "prismjs/themes/prism.css"; import '@toast-ui/editor/dist/theme/toastui-editor-dark.css'; import "@toast-ui/editor-plugin-code-syntax-highlight/dist/toastui-editor-plugin-code-syntax-highlight.css"; @@ -6,8 +6,8 @@ import "@toast-ui/editor-plugin-code-syntax-highlight/dist/toastui-editor-plugin import codeSyntaxHighlight from "@toast-ui/editor-plugin-code-syntax-highlight/dist/toastui-editor-plugin-code-syntax-highlight-all.js"; import { Viewer } from "@toast-ui/react-editor"; -import ImagePreviewModal, { PreviewImageData } from "./ImagePreviewModal"; import { isDarkMode } from "../utils"; +import ImagePreview from "./ImagePreview"; interface IProps { @@ -15,42 +15,9 @@ interface IProps { } const MarkdownRender: FC = ({ content }) => { const mdContainer = useRef(null); - const [previewImage, setPreviewImage] = useState(null); - - useEffect(() => { - const container = mdContainer?.current; - if (!container) return; - // 点击查看大图 - // todo: 事件代理 - container.addEventListener( - "click", - (evt) => { - evt.stopPropagation(); - const target = evt.target as HTMLImageElement; - if (!target) return; - // 图片 - if (target.nodeName == "IMG") { - const urlObj = new URL(target.src); - const originUrl = `${urlObj.origin}${urlObj.pathname}?file_path=${urlObj.searchParams.get( - "file_path" - )}`; - const data = { originUrl }; - setPreviewImage(data); - } - }, - true - ); - }, []); - - const closePreviewModal = () => { - setPreviewImage(null); - }; - return ( <> - {previewImage && ( - - )} +
diff --git a/src/routes/chat/Layout/index.tsx b/src/routes/chat/Layout/index.tsx index 1fc0a7d2..66f4bc9f 100644 --- a/src/routes/chat/Layout/index.tsx +++ b/src/routes/chat/Layout/index.tsx @@ -1,10 +1,10 @@ -import { useState, useRef, useEffect, FC, ReactElement } from "react"; +import { useRef, useEffect, FC, ReactElement } from "react"; import { useDrop } from "react-dnd"; import { NativeTypes } from "react-dnd-html5-backend"; import clsx from "clsx"; import { toast } from "react-hot-toast"; -import ImagePreviewModal from "../../../common/component/ImagePreviewModal"; + import Send from "../../../common/component/Send"; import Operations from "./Operations"; import useUploadFile from "../../../common/hook/useUploadFile"; @@ -14,6 +14,7 @@ import useLicense from "../../../common/hook/useLicense"; import LicenseUpgradeTip from "./LicenseOutdatedTip"; import DnDTip from "./DnDTip"; import IconWarning from '../../../assets/icons/warning.svg'; +import ImagePreview from "../../../common/component/ImagePreview"; interface Props { readonly?: boolean; @@ -40,7 +41,7 @@ const Layout: FC = ({ const { reachLimit } = useLicense(); const { addStageFile } = useUploadFile({ context, id: to }); const messagesContainer = useRef(null); - const [previewImage, setPreviewImage] = useState(null); + const { selects, channelsData, usersData, inputMode } = useAppSelector((store) => { return { inputMode: store.ui.inputMode, @@ -86,46 +87,21 @@ const Layout: FC = ({ addStageFile(filesData); } }, [dropFiles]); - - const closePreviewModal = () => { - setPreviewImage(null); - }; - - useEffect(() => { - const container = messagesContainer?.current; - if (!container) return; - // 点击查看大图 - container.addEventListener( - "click", - (evt) => { - const target = evt.target as HTMLImageElement; - if (!target) return; - if (target.nodeName == "IMG" && target.classList.contains("preview")) { - const thumbnail = target.src; - const originUrl = target.dataset.origin || target.src; - const downloadLink = target.dataset.download || target.src; - const meta = JSON.parse(target.dataset.meta || "{}"); - setPreviewImage({ thumbnail, originUrl, downloadLink, ...meta }); - } - }, - true - ); - }, []); const name = context == "channel" ? channelsData[to]?.name : usersData[to]?.name; return ( <> - {previewImage && } +
{header} -
-
+
+
{/* 消息流 */}
{children}
{/* 发送框 */} -
+
{readonly ? ( ) : reachLimit ? (