feat: 增加选中文本部分复制

This commit is contained in:
haorwen
2026-01-24 20:45:45 +08:00
parent f0a18ea170
commit f8eee70c17
4 changed files with 21 additions and 6 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "vocechat-web", "name": "vocechat-web",
"version": "0.9.56", "version": "0.9.57",
"homepage": "https://voce.chat", "homepage": "https://voce.chat",
"dependencies": { "dependencies": {
"@metamask/onboarding": "^1.0.1", "@metamask/onboarding": "^1.0.1",
+4 -2
View File
@@ -24,6 +24,7 @@ type Props = {
hide: () => void; hide: () => void;
editMessage: () => void; editMessage: () => void;
children: ReactElement; children: ReactElement;
selectedText?: string;
}; };
const MessageContextMenu: FC<Props> = ({ const MessageContextMenu: FC<Props> = ({
context, context,
@@ -32,7 +33,8 @@ const MessageContextMenu: FC<Props> = ({
visible, visible,
hide, hide,
editMessage, editMessage,
children children,
selectedText = ""
}) => { }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { const {
@@ -50,7 +52,7 @@ const MessageContextMenu: FC<Props> = ({
PinModal, PinModal,
ForwardModal, ForwardModal,
DeleteModal DeleteModal
} = useMessageOperation({ mid, contextId, context }); } = useMessageOperation({ mid, contextId, context, selectedText });
const dispatch = useDispatch(); const dispatch = useDispatch();
const { setReplying } = useSendMessage({ context, to: contextId }); const { setReplying } = useSendMessage({ context, to: contextId });
const handleSelect = () => { const handleSelect = () => {
+8 -1
View File
@@ -42,6 +42,7 @@ const Message: FC<IProps> = ({
const inViewRef = useInView<HTMLDivElement>(); const inViewRef = useInView<HTMLDivElement>();
const [edit, setEdit] = useState(false); const [edit, setEdit] = useState(false);
const avatarRef = useRef(null); const avatarRef = useRef(null);
const selectedTextRef = useRef<string>("");
const { getPinInfo } = usePinMessage(context == "channel" ? contextId : 0); const { getPinInfo } = usePinMessage(context == "channel" ? contextId : 0);
const message = useAppSelector((store) => store.message[mid], shallowEqual); const message = useAppSelector((store) => store.message[mid], shallowEqual);
const enableRightLayout = useAppSelector( const enableRightLayout = useAppSelector(
@@ -104,7 +105,12 @@ const Message: FC<IProps> = ({
return ( return (
<div <div
key={_key} key={_key}
onContextMenu={readOnly ? undefined : handleContextMenuEvent} onContextMenu={readOnly ? undefined : (evt) => {
// 在右键点击时保存选中的文本
const selection = window.getSelection();
selectedTextRef.current = selection?.toString().trim() || "";
handleContextMenuEvent(evt);
}}
data-msg-mid={mid} data-msg-mid={mid}
ref={inViewRef} ref={inViewRef}
className={clsx( className={clsx(
@@ -141,6 +147,7 @@ const Message: FC<IProps> = ({
mid={mid} mid={mid}
visible={contextMenuVisible && !failed} visible={contextMenuVisible && !failed}
hide={hideContextMenu} hide={hideContextMenu}
selectedText={selectedTextRef.current}
> >
<div <div
className={clsx( className={clsx(
@@ -15,9 +15,10 @@ interface Params {
mid: number; mid: number;
context: ChatContext; context: ChatContext;
contextId: number; contextId: number;
selectedText?: string;
} }
export default function useMessageOperation({ mid, context, contextId }: Params) { export default function useMessageOperation({ mid, context, contextId, selectedText = "" }: Params) {
const { copy } = useCopy(); const { copy } = useCopy();
const message = useAppSelector((store) => store.message[mid], shallowEqual); const message = useAppSelector((store) => store.message[mid], shallowEqual);
const loginUser = useAppSelector((store) => store.authData.user, shallowEqual); const loginUser = useAppSelector((store) => store.authData.user, shallowEqual);
@@ -46,7 +47,12 @@ export default function useMessageOperation({ mid, context, contextId }: Params)
setPinModalVisible((prev) => !prev); setPinModalVisible((prev) => !prev);
}; };
const copyContent = (image = false) => { const copyContent = (image = false) => {
copy(content, image); // 如果有选中的文本,复制选中的文本;否则复制整条消息
if (selectedText && !image) {
copy(selectedText, false);
} else {
copy(content, image);
}
}; };
useEffect(() => { useEffect(() => {
if (forwardModalVisible && content_type == ContentTypes.archive) { if (forwardModalVisible && content_type == ContentTypes.archive) {