From 088ab7ab73017531482f7453dd39f8b6d1ab4e51 Mon Sep 17 00:00:00 2001 From: sp mac bookpro 2605 Date: Fri, 5 Jun 2026 23:23:56 +0800 Subject: [PATCH] chat: improve copy with icon and plain/markdown modes --- src/components/icons.tsx | 33 ++++++++++ src/pages/chat/ChatPage.tsx | 7 ++- src/pages/chat/components/ChatBody.tsx | 3 +- .../chat/components/messages/MessageItem.tsx | 26 +++++--- src/pages/chat/utils/copy.ts | 63 +++++++++++++++++++ src/styles.css | 14 +++++ 6 files changed, 136 insertions(+), 10 deletions(-) create mode 100644 src/components/icons.tsx create mode 100644 src/pages/chat/utils/copy.ts diff --git a/src/components/icons.tsx b/src/components/icons.tsx new file mode 100644 index 0000000..d25400b --- /dev/null +++ b/src/components/icons.tsx @@ -0,0 +1,33 @@ +import type { SVGProps } from 'react'; + +export function ProductCopyIcon(props: SVGProps) { + const { width = 20, height = 20, ...rest } = props; + return ( + + + + + ); +} + diff --git a/src/pages/chat/ChatPage.tsx b/src/pages/chat/ChatPage.tsx index 6fd57b5..5acac87 100644 --- a/src/pages/chat/ChatPage.tsx +++ b/src/pages/chat/ChatPage.tsx @@ -10,6 +10,7 @@ import ChatDrawers from './components/ChatDrawers'; import { useChatScroll } from './hooks/useChatScroll'; import { useChatData } from './hooks/useChatData'; import { useChatSender } from './hooks/useChatSender'; +import { markdownToPlainText } from './utils/copy'; export default function ChatPage() { const { id } = useParams(); @@ -106,7 +107,10 @@ export default function ChatPage() { streaming={sender.streaming} onRegenerate={sender.handleRegenerate} onSwitchBranch={sender.handleSwitchBranch} - onCopy={(text) => navigator.clipboard?.writeText(text).then(() => message.success('已复制'))} + onCopy={(text, mode) => { + const content = mode === 'markdown' ? text : markdownToPlainText(text); + return navigator.clipboard?.writeText(content).then(() => message.success(mode === 'markdown' ? '已复制(Markdown)' : '已复制(纯文本)')); + }} /> ); } - diff --git a/src/pages/chat/components/ChatBody.tsx b/src/pages/chat/components/ChatBody.tsx index 012b1b3..b8f7725 100644 --- a/src/pages/chat/components/ChatBody.tsx +++ b/src/pages/chat/components/ChatBody.tsx @@ -2,6 +2,7 @@ import { Divider, Tag } from 'antd'; import type { Agent, BranchInfo, ChatMessage } from '../../../api'; import Markdown from '../../../components/Markdown'; import type { StreamingState } from '../hooks/useChatSender'; +import type { CopyMode } from '../utils/copy'; import MessageItem from './messages/MessageItem'; import { RetrievedView, ToolCallView } from './messages/MetaViews'; @@ -17,7 +18,7 @@ export default function ChatBody(props: { streaming: StreamingState; onRegenerate: (assistantId: string) => void; onSwitchBranch: (userMsgId: string, branchId: string) => void; - onCopy: (text: string) => void; + onCopy: (text: string, mode: CopyMode) => void; }) { const { bodyRef, agent, messages, branches, highlightId, sending, streaming, onRegenerate, onSwitchBranch, onCopy } = props; diff --git a/src/pages/chat/components/messages/MessageItem.tsx b/src/pages/chat/components/messages/MessageItem.tsx index 01332b4..5dfad1b 100644 --- a/src/pages/chat/components/messages/MessageItem.tsx +++ b/src/pages/chat/components/messages/MessageItem.tsx @@ -1,6 +1,8 @@ -import { Button, Space, Tag, Tooltip } from 'antd'; +import { Button, Dropdown, Space, Tag, Tooltip } from 'antd'; import type { BranchInfo, ChatMessage } from '../../../../api'; import Markdown from '../../../../components/Markdown'; +import { ProductCopyIcon } from '../../../../components/icons'; +import type { CopyMode } from '../../utils/copy'; import { ReasoningView, RetrievedView, ToolCallView } from './MetaViews'; export default function MessageItem(props: { @@ -10,7 +12,7 @@ export default function MessageItem(props: { busy?: boolean; onRegenerate?: (id: string) => void; onSwitchBranch?: (userMsgId: string, branchId: string) => void; - onCopy?: (text: string) => void; + onCopy?: (text: string, mode: CopyMode) => void; }) { const { message, highlighted, branch, busy, onRegenerate, onSwitchBranch, onCopy } = props; const hasBranches = !!branch && branch.total > 1; @@ -66,11 +68,21 @@ export default function MessageItem(props: { )} {message.meta?.aborted && 已停止} - - - + onCopy?.(message.content, 'plain') }, + { key: 'markdown', label: '复制 Markdown', onClick: () => onCopy?.(message.content, 'markdown') } + ] + }} + > + + + + + +