feat: copy image message
This commit is contained in:
+6
-5
@@ -4,7 +4,7 @@
|
||||
"private": true,
|
||||
"homepage": "https://privoce.rustchat.com",
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.17.10",
|
||||
"@babel/core": "^7.17.12",
|
||||
"@emoji-mart/data": "^1.0.1",
|
||||
"@metamask/onboarding": "^1.0.1",
|
||||
"@microsoft/fetch-event-source": "^2.0.1",
|
||||
@@ -15,7 +15,7 @@
|
||||
"@toast-ui/editor": "^3.1.6",
|
||||
"@toast-ui/editor-plugin-code-syntax-highlight": "^3.0.0",
|
||||
"@toast-ui/react-editor": "^3.1.6",
|
||||
"@udecode/plate": "^11.0.5",
|
||||
"@udecode/plate": "^11.0.6",
|
||||
"@uiball/loaders": "^1.2.6",
|
||||
"animate.css": "^4.1.1",
|
||||
"babel-loader": "^8.2.5",
|
||||
@@ -25,6 +25,7 @@
|
||||
"browserslist": "^4.20.3",
|
||||
"camelcase": "^6.3.0",
|
||||
"case-sensitive-paths-webpack-plugin": "^2.4.0",
|
||||
"copy-image-clipboard": "^2.1.2",
|
||||
"css-loader": "^6.7.1",
|
||||
"css-minimizer-webpack-plugin": "^3.4.1",
|
||||
"dayjs": "^1.11.2",
|
||||
@@ -74,7 +75,7 @@
|
||||
"source-map-loader": "^3.0.1",
|
||||
"style-loader": "^3.3.1",
|
||||
"styled-components": "^5.3.5",
|
||||
"styled-reset": "^4.3.4",
|
||||
"styled-reset": "^4.4.0",
|
||||
"terser-webpack-plugin": "^5.3.1",
|
||||
"tippy.js": "^6.3.7",
|
||||
"webpack": "^5.72.1",
|
||||
@@ -123,8 +124,8 @@
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^16.3.0",
|
||||
"@commitlint/config-conventional": "^16.2.4",
|
||||
"@commitlint/cli": "^17.0.0",
|
||||
"@commitlint/config-conventional": "^17.0.0",
|
||||
"autoprefixer": "^10.4.7",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
|
||||
@@ -165,7 +165,6 @@ export default function Commands({
|
||||
onShow={handleTippyVisible.bind(null, true)}
|
||||
onHide={handleTippyVisible.bind(null, false)}
|
||||
interactive
|
||||
popperOptions={{ strategy: "fixed" }}
|
||||
placement="left-start"
|
||||
trigger="click"
|
||||
content={
|
||||
|
||||
@@ -74,7 +74,7 @@ export default function MessageContextMenu({
|
||||
handler: handleReply,
|
||||
},
|
||||
canCopy && {
|
||||
title: isMarkdown ? "Copy Markdown" : "Copy Text",
|
||||
title: "Copy",
|
||||
icon: <IconCopy className="icon" />,
|
||||
handler: copyContent,
|
||||
},
|
||||
|
||||
@@ -87,35 +87,35 @@ function Message({
|
||||
console.log("render message");
|
||||
// return null;
|
||||
return (
|
||||
<ContextMenu
|
||||
editMessage={toggleEditMessage}
|
||||
context={context}
|
||||
contextId={contextId}
|
||||
mid={mid}
|
||||
visible={contextMenuVisible}
|
||||
hide={hideContextMenu}
|
||||
offset={offset}
|
||||
<StyledWrapper
|
||||
onContextMenu={handleContextMenuEvent}
|
||||
data-msg-mid={mid}
|
||||
ref={inviewRef}
|
||||
className={`message ${readOnly ? "readonly" : ""} ${
|
||||
contextMenuVisible ? "contextVisible" : ""
|
||||
} `}
|
||||
>
|
||||
<StyledWrapper
|
||||
onContextMenu={handleContextMenuEvent}
|
||||
data-msg-mid={mid}
|
||||
ref={inviewRef}
|
||||
className={`message ${readOnly ? "readonly" : ""} ${
|
||||
contextMenuVisible ? "contextVisible" : ""
|
||||
} `}
|
||||
<Tippy
|
||||
disabled={readOnly}
|
||||
duration={0}
|
||||
interactive
|
||||
placement="left"
|
||||
trigger="click"
|
||||
content={<Profile uid={fromUid} type="card" />}
|
||||
>
|
||||
<div className="avatar" data-uid={fromUid} ref={avatarRef}>
|
||||
<Avatar url={currUser.avatar} name={currUser.name} />
|
||||
</div>
|
||||
</Tippy>
|
||||
<ContextMenu
|
||||
editMessage={toggleEditMessage}
|
||||
context={context}
|
||||
contextId={contextId}
|
||||
mid={mid}
|
||||
visible={contextMenuVisible}
|
||||
hide={hideContextMenu}
|
||||
offset={offset}
|
||||
>
|
||||
<Tippy
|
||||
disabled={readOnly}
|
||||
duration={0}
|
||||
interactive
|
||||
placement="left"
|
||||
trigger="click"
|
||||
content={<Profile uid={fromUid} type="card" />}
|
||||
>
|
||||
<div className="avatar" data-uid={fromUid} ref={avatarRef}>
|
||||
<Avatar url={currUser.avatar} name={currUser.name} />
|
||||
</div>
|
||||
</Tippy>
|
||||
<div className="details">
|
||||
<div className="up">
|
||||
<span className="name">{currUser.name}</span>
|
||||
@@ -153,18 +153,19 @@ function Message({
|
||||
{reactions && <Reaction mid={mid} reactions={reactions} />}
|
||||
</div>
|
||||
</div>
|
||||
{!edit && !readOnly && (
|
||||
<Commands
|
||||
content_type={content_type}
|
||||
context={context}
|
||||
contextId={contextId}
|
||||
mid={mid}
|
||||
from_uid={fromUid}
|
||||
toggleEditMessage={toggleEditMessage}
|
||||
/>
|
||||
)}
|
||||
</StyledWrapper>
|
||||
</ContextMenu>
|
||||
</ContextMenu>
|
||||
|
||||
{!edit && !readOnly && (
|
||||
<Commands
|
||||
content_type={content_type}
|
||||
context={context}
|
||||
contextId={contextId}
|
||||
mid={mid}
|
||||
from_uid={fromUid}
|
||||
toggleEditMessage={toggleEditMessage}
|
||||
/>
|
||||
)}
|
||||
</StyledWrapper>
|
||||
);
|
||||
}
|
||||
export default React.memo(Message, (prevs, nexts) => {
|
||||
|
||||
@@ -78,7 +78,6 @@ const renderContent = ({
|
||||
// const { size, name, file_type } = properties;
|
||||
ctn = (
|
||||
<FileMessage
|
||||
content_type={""}
|
||||
properties={properties}
|
||||
context={context}
|
||||
to={to}
|
||||
|
||||
@@ -7,19 +7,19 @@ const StyledMsg = styled.div`
|
||||
padding: 4px 8px;
|
||||
margin: 8px 0;
|
||||
border-radius: 8px;
|
||||
content-visibility: auto;
|
||||
contain-intrinsic-size: auto 150px;
|
||||
&.in_view {
|
||||
/* content-visibility: auto;
|
||||
contain-intrinsic-size: auto 150px; */
|
||||
/* &.in_view {
|
||||
content-visibility: visible;
|
||||
}
|
||||
} */
|
||||
&[data-highlight="true"] {
|
||||
background: #f5f6f7;
|
||||
}
|
||||
&:hover,
|
||||
&.contextVisible,
|
||||
&.preview {
|
||||
content-visibility: inherit;
|
||||
contain-intrinsic-size: inherit;
|
||||
/* content-visibility: inherit;
|
||||
contain-intrinsic-size: inherit; */
|
||||
background: #f5f6f7;
|
||||
.cmds {
|
||||
visibility: visible;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import { copyImageToClipboard } from "copy-image-clipboard";
|
||||
import DeleteMessageConfirm from "../DeleteMessageConfirm";
|
||||
import ForwardModal from "../ForwardModal";
|
||||
import PinMessageModal from "./PinMessageModal";
|
||||
@@ -6,18 +8,20 @@ import { ContentTypes } from "../../../app/config";
|
||||
import { useSelector } from "react-redux";
|
||||
import useCopy from "../../hook/useCopy";
|
||||
import usePinMessage from "../../hook/usePinMessage";
|
||||
import toast from "react-hot-toast";
|
||||
|
||||
export default function useMessageOperation({ mid, context, contextId }) {
|
||||
const [copied, copy] = useCopy();
|
||||
const { content_type, currUid, from_uid, content } = useSelector((store) => {
|
||||
return {
|
||||
content: store.message[mid]?.content,
|
||||
from_uid: store.message[mid]?.from_uid,
|
||||
content_type: store.message[mid]?.content_type,
|
||||
currUid: store.authData.uid,
|
||||
};
|
||||
});
|
||||
const { content_type, properties, currUid, from_uid, content } = useSelector(
|
||||
(store) => {
|
||||
return {
|
||||
content: store.message[mid]?.content,
|
||||
from_uid: store.message[mid]?.from_uid,
|
||||
content_type: store.message[mid]?.content_type,
|
||||
properties: store.message[mid]?.properties,
|
||||
currUid: store.authData.uid,
|
||||
};
|
||||
}
|
||||
);
|
||||
const { canPin, pins, unpinMessage, isUnpinSuccess } = usePinMessage(
|
||||
context == "channel" ? contextId : undefined
|
||||
);
|
||||
@@ -38,8 +42,12 @@ export default function useMessageOperation({ mid, context, contextId }) {
|
||||
// hideAll();
|
||||
setPinModalVisible((prev) => !prev);
|
||||
};
|
||||
const copyContent = () => {
|
||||
copy(content);
|
||||
const copyContent = (image = false) => {
|
||||
if (image) {
|
||||
copyImageToClipboard(content);
|
||||
} else {
|
||||
copy(content);
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
if (content_type == ContentTypes.archive) {
|
||||
@@ -66,24 +74,28 @@ export default function useMessageOperation({ mid, context, contextId }) {
|
||||
}
|
||||
}, [copied]);
|
||||
const enablePin = context == "channel" && canPin;
|
||||
const enableReply = currUid != from_uid;
|
||||
|
||||
// const enableReply = currUid != from_uid;
|
||||
const isImage =
|
||||
content_type == ContentTypes.file &&
|
||||
properties?.content_type &&
|
||||
properties?.content_type.startsWith("image");
|
||||
const enableEdit =
|
||||
currUid == from_uid &&
|
||||
[ContentTypes.text, ContentTypes.markdown].includes(content_type);
|
||||
const canDelete = currUid == from_uid;
|
||||
const canCopy = [ContentTypes.text, ContentTypes.markdown].includes(
|
||||
content_type
|
||||
);
|
||||
const canCopy =
|
||||
[ContentTypes.text, ContentTypes.markdown].includes(content_type) ||
|
||||
isImage;
|
||||
return {
|
||||
copyContent,
|
||||
copyContent: isImage ? copyContent.bind(null, true) : copyContent,
|
||||
canCopy,
|
||||
isImage,
|
||||
isMarkdown: content_type == ContentTypes.markdown,
|
||||
canDelete,
|
||||
canPin: context == "channel" && canPin,
|
||||
pinned: enablePin ? pins.findIndex((p) => p.mid == mid) > -1 : false,
|
||||
unPin: unpinMessage,
|
||||
canReply: enableReply,
|
||||
canReply: true,
|
||||
canEdit: enableEdit,
|
||||
toggleDeleteModal,
|
||||
toggleForwardModal,
|
||||
|
||||
Reference in New Issue
Block a user