forked from XiaoMo/ChatGPT-Next-Web
feat: close #2267 display a modal to export image
This commit is contained in:
parent
9e6617e3ca
commit
6c6a2d08db
@ -1,7 +1,8 @@
|
|||||||
|
/* eslint-disable @next/next/no-img-element */
|
||||||
import { ChatMessage, useAppConfig, useChatStore } from "../store";
|
import { ChatMessage, useAppConfig, useChatStore } from "../store";
|
||||||
import Locale from "../locales";
|
import Locale from "../locales";
|
||||||
import styles from "./exporter.module.scss";
|
import styles from "./exporter.module.scss";
|
||||||
import { List, ListItem, Modal, Select, showToast } from "./ui-lib";
|
import { List, ListItem, Modal, Select, showModal, showToast } from "./ui-lib";
|
||||||
import { IconButton } from "./button";
|
import { IconButton } from "./button";
|
||||||
import { copyToClipboard, downloadAs, useMobileScreen } from "../utils";
|
import { copyToClipboard, downloadAs, useMobileScreen } from "../utils";
|
||||||
|
|
||||||
@ -23,6 +24,7 @@ import { DEFAULT_MASK_AVATAR } from "../store/mask";
|
|||||||
import { api } from "../client/api";
|
import { api } from "../client/api";
|
||||||
import { prettyObject } from "../utils/format";
|
import { prettyObject } from "../utils/format";
|
||||||
import { EXPORT_MESSAGE_CLASS_NAME } from "../constant";
|
import { EXPORT_MESSAGE_CLASS_NAME } from "../constant";
|
||||||
|
import { getClientConfig } from "../config/client";
|
||||||
|
|
||||||
const Markdown = dynamic(async () => (await import("./markdown")).Markdown, {
|
const Markdown = dynamic(async () => (await import("./markdown")).Markdown, {
|
||||||
loading: () => <LoadingIcon />,
|
loading: () => <LoadingIcon />,
|
||||||
@ -357,6 +359,24 @@ function ExportAvatar(props: { avatar: string }) {
|
|||||||
return <Avatar avatar={props.avatar}></Avatar>;
|
return <Avatar avatar={props.avatar}></Avatar>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function showImageModal(img: string) {
|
||||||
|
showModal({
|
||||||
|
title: Locale.Export.Image.Modal,
|
||||||
|
children: (
|
||||||
|
<div>
|
||||||
|
<img
|
||||||
|
src={img}
|
||||||
|
alt="preview"
|
||||||
|
style={{
|
||||||
|
maxWidth: "100%",
|
||||||
|
}}
|
||||||
|
></img>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
defaultMax: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function ImagePreviewer(props: {
|
export function ImagePreviewer(props: {
|
||||||
messages: ChatMessage[];
|
messages: ChatMessage[];
|
||||||
topic: string;
|
topic: string;
|
||||||
@ -369,6 +389,7 @@ export function ImagePreviewer(props: {
|
|||||||
const previewRef = useRef<HTMLDivElement>(null);
|
const previewRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const copy = () => {
|
const copy = () => {
|
||||||
|
showToast(Locale.Export.Image.Toast);
|
||||||
const dom = previewRef.current;
|
const dom = previewRef.current;
|
||||||
if (!dom) return;
|
if (!dom) return;
|
||||||
toBlob(dom).then((blob) => {
|
toBlob(dom).then((blob) => {
|
||||||
@ -393,17 +414,15 @@ export function ImagePreviewer(props: {
|
|||||||
const isMobile = useMobileScreen();
|
const isMobile = useMobileScreen();
|
||||||
|
|
||||||
const download = () => {
|
const download = () => {
|
||||||
|
showToast(Locale.Export.Image.Toast);
|
||||||
const dom = previewRef.current;
|
const dom = previewRef.current;
|
||||||
if (!dom) return;
|
if (!dom) return;
|
||||||
toPng(dom)
|
toPng(dom)
|
||||||
.then((blob) => {
|
.then((blob) => {
|
||||||
if (!blob) return;
|
if (!blob) return;
|
||||||
|
|
||||||
if (isMobile) {
|
if (isMobile || getClientConfig()?.isApp) {
|
||||||
const image = new Image();
|
showImageModal(blob);
|
||||||
image.src = blob;
|
|
||||||
const win = window.open("");
|
|
||||||
win?.document.write(image.outerHTML);
|
|
||||||
} else {
|
} else {
|
||||||
const link = document.createElement("a");
|
const link = document.createElement("a");
|
||||||
link.download = `${props.topic}.png`;
|
link.download = `${props.topic}.png`;
|
||||||
|
@ -95,6 +95,7 @@ interface ModalProps {
|
|||||||
title: string;
|
title: string;
|
||||||
children?: any;
|
children?: any;
|
||||||
actions?: JSX.Element[];
|
actions?: JSX.Element[];
|
||||||
|
defaultMax?: boolean;
|
||||||
onClose?: () => void;
|
onClose?: () => void;
|
||||||
}
|
}
|
||||||
export function Modal(props: ModalProps) {
|
export function Modal(props: ModalProps) {
|
||||||
@ -113,7 +114,7 @@ export function Modal(props: ModalProps) {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const [isMax, setMax] = useState(false);
|
const [isMax, setMax] = useState(!!props.defaultMax);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
@ -86,6 +86,10 @@ const cn = {
|
|||||||
Select: "选取",
|
Select: "选取",
|
||||||
Preview: "预览",
|
Preview: "预览",
|
||||||
},
|
},
|
||||||
|
Image: {
|
||||||
|
Toast: "正在生成截图",
|
||||||
|
Modal: "长按或右键保存图片",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Select: {
|
Select: {
|
||||||
Search: "搜索消息",
|
Search: "搜索消息",
|
||||||
|
@ -87,6 +87,10 @@ const en: LocaleType = {
|
|||||||
Select: "Select",
|
Select: "Select",
|
||||||
Preview: "Preview",
|
Preview: "Preview",
|
||||||
},
|
},
|
||||||
|
Image: {
|
||||||
|
Toast: "Capturing Image...",
|
||||||
|
Modal: "Long press or right click to save image",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Select: {
|
Select: {
|
||||||
Search: "Search",
|
Search: "Search",
|
||||||
|
Loading…
Reference in New Issue
Block a user