forked from XiaoMo/ChatGPT-Next-Web
Merge pull request #1679 from Yidadaa/export
chore: mobile export image style
This commit is contained in:
commit
f0b4ef5917
@ -3,7 +3,7 @@ import Locale from "../locales";
|
|||||||
import styles from "./exporter.module.scss";
|
import styles from "./exporter.module.scss";
|
||||||
import { List, ListItem, Modal, showToast } from "./ui-lib";
|
import { List, ListItem, Modal, showToast } from "./ui-lib";
|
||||||
import { IconButton } from "./button";
|
import { IconButton } from "./button";
|
||||||
import { copyToClipboard, downloadAs } from "../utils";
|
import { copyToClipboard, downloadAs, useMobileScreen } from "../utils";
|
||||||
|
|
||||||
import CopyIcon from "../icons/copy.svg";
|
import CopyIcon from "../icons/copy.svg";
|
||||||
import LoadingIcon from "../icons/three-dots.svg";
|
import LoadingIcon from "../icons/three-dots.svg";
|
||||||
@ -222,16 +222,19 @@ export function MessageExporter() {
|
|||||||
export function PreviewActions(props: {
|
export function PreviewActions(props: {
|
||||||
download: () => void;
|
download: () => void;
|
||||||
copy: () => void;
|
copy: () => void;
|
||||||
|
showCopy?: boolean;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className={styles["preview-actions"]}>
|
<div className={styles["preview-actions"]}>
|
||||||
<IconButton
|
{props.showCopy && (
|
||||||
text={Locale.Export.Copy}
|
<IconButton
|
||||||
bordered
|
text={Locale.Export.Copy}
|
||||||
shadow
|
bordered
|
||||||
icon={<CopyIcon />}
|
shadow
|
||||||
onClick={props.copy}
|
icon={<CopyIcon />}
|
||||||
></IconButton>
|
onClick={props.copy}
|
||||||
|
></IconButton>
|
||||||
|
)}
|
||||||
<IconButton
|
<IconButton
|
||||||
text={Locale.Export.Download}
|
text={Locale.Export.Download}
|
||||||
bordered
|
bordered
|
||||||
@ -282,23 +285,34 @@ export function ImagePreviewer(props: {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isMobile = useMobileScreen();
|
||||||
|
|
||||||
const download = () => {
|
const download = () => {
|
||||||
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;
|
||||||
const link = document.createElement("a");
|
|
||||||
link.download = `${props.topic}.png`;
|
if (isMobile) {
|
||||||
link.href = blob;
|
const image = new Image();
|
||||||
link.click();
|
image.src = blob;
|
||||||
|
const win = window.open("");
|
||||||
|
win?.document.write(image.outerHTML);
|
||||||
|
} else {
|
||||||
|
const link = document.createElement("a");
|
||||||
|
link.download = `${props.topic}.png`;
|
||||||
|
link.href = blob;
|
||||||
|
link.click();
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch((e) => console.log("[Export Image] ", e));
|
.catch((e) => console.log("[Export Image] ", e));
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles["image-previewer"]}>
|
<div className={styles["image-previewer"]}>
|
||||||
<PreviewActions copy={copy} download={download} />
|
<PreviewActions copy={copy} download={download} showCopy={!isMobile} />
|
||||||
<div
|
<div
|
||||||
className={`${styles["preview-body"]} ${styles["default-theme"]}`}
|
className={`${styles["preview-body"]} ${styles["default-theme"]}`}
|
||||||
ref={previewRef}
|
ref={previewRef}
|
||||||
|
@ -5,10 +5,31 @@
|
|||||||
.search-bar {
|
.search-bar {
|
||||||
max-width: unset;
|
max-width: unset;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filter-item:not(:last-child) {
|
.actions {
|
||||||
margin-right: 10px;
|
display: flex;
|
||||||
|
|
||||||
|
button:not(:last-child) {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 600px) {
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.search-bar {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
margin-top: 20px;
|
||||||
|
|
||||||
|
button {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,33 +140,35 @@ export function MessageSelector(props: {
|
|||||||
}}
|
}}
|
||||||
></input>
|
></input>
|
||||||
|
|
||||||
<IconButton
|
<div className={styles["actions"]}>
|
||||||
text={Locale.Select.All}
|
<IconButton
|
||||||
bordered
|
text={Locale.Select.All}
|
||||||
className={styles["filter-item"]}
|
bordered
|
||||||
onClick={selectAll}
|
className={styles["filter-item"]}
|
||||||
/>
|
onClick={selectAll}
|
||||||
<IconButton
|
/>
|
||||||
text={Locale.Select.Latest}
|
<IconButton
|
||||||
bordered
|
text={Locale.Select.Latest}
|
||||||
className={styles["filter-item"]}
|
bordered
|
||||||
onClick={() =>
|
className={styles["filter-item"]}
|
||||||
props.updateSelection((selection) => {
|
onClick={() =>
|
||||||
selection.clear();
|
props.updateSelection((selection) => {
|
||||||
messages
|
selection.clear();
|
||||||
.slice(messageCount - 10)
|
messages
|
||||||
.forEach((m) => selection.add(m.id!));
|
.slice(messageCount - 10)
|
||||||
})
|
.forEach((m) => selection.add(m.id!));
|
||||||
}
|
})
|
||||||
/>
|
}
|
||||||
<IconButton
|
/>
|
||||||
text={Locale.Select.Clear}
|
<IconButton
|
||||||
bordered
|
text={Locale.Select.Clear}
|
||||||
className={styles["filter-item"]}
|
bordered
|
||||||
onClick={() =>
|
className={styles["filter-item"]}
|
||||||
props.updateSelection((selection) => selection.clear())
|
onClick={() =>
|
||||||
}
|
props.updateSelection((selection) => selection.clear())
|
||||||
/>
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles["messages"]}>
|
<div className={styles["messages"]}>
|
||||||
|
Loading…
Reference in New Issue
Block a user