refactor: Enhance message context menu with improved text selection and copying
This commit is contained in:
parent
4ca2d61ccc
commit
59c69e065c
@ -35,14 +35,6 @@ interface Props {
|
|||||||
onDeleteMessage?: (message: Message) => Promise<void>
|
onDeleteMessage?: (message: Message) => Promise<void>
|
||||||
}
|
}
|
||||||
|
|
||||||
const getMessageBackground = (isBubbleStyle: boolean, isAssistantMessage: boolean) => {
|
|
||||||
return isBubbleStyle
|
|
||||||
? isAssistantMessage
|
|
||||||
? 'var(--chat-background-assistant)'
|
|
||||||
: 'var(--chat-background-user)'
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
const MessageItem: FC<Props> = ({
|
const MessageItem: FC<Props> = ({
|
||||||
message: _message,
|
message: _message,
|
||||||
topic: _topic,
|
topic: _topic,
|
||||||
@ -64,6 +56,7 @@ const MessageItem: FC<Props> = ({
|
|||||||
const topic = useTopic(assistant, _topic?.id)
|
const topic = useTopic(assistant, _topic?.id)
|
||||||
const [contextMenuPosition, setContextMenuPosition] = useState<{ x: number; y: number } | null>(null)
|
const [contextMenuPosition, setContextMenuPosition] = useState<{ x: number; y: number } | null>(null)
|
||||||
const [selectedQuoteText, setSelectedQuoteText] = useState<string>('')
|
const [selectedQuoteText, setSelectedQuoteText] = useState<string>('')
|
||||||
|
const [selectedText, setSelectedText] = useState<string>('')
|
||||||
|
|
||||||
const isLastMessage = index === 0
|
const isLastMessage = index === 0
|
||||||
const isAssistantMessage = message.role === 'assistant'
|
const isAssistantMessage = message.role === 'assistant'
|
||||||
@ -79,15 +72,16 @@ const MessageItem: FC<Props> = ({
|
|||||||
|
|
||||||
const handleContextMenu = useCallback((e: React.MouseEvent) => {
|
const handleContextMenu = useCallback((e: React.MouseEvent) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
const selectedText = window.getSelection()?.toString()
|
const _selectedText = window.getSelection()?.toString()
|
||||||
if (selectedText) {
|
if (_selectedText) {
|
||||||
const quotedText =
|
const quotedText =
|
||||||
selectedText
|
_selectedText
|
||||||
.split('\n')
|
.split('\n')
|
||||||
.map((line) => `> ${line}`)
|
.map((line) => `> ${line}`)
|
||||||
.join('\n') + '\n-------------'
|
.join('\n') + '\n-------------'
|
||||||
setSelectedQuoteText(quotedText)
|
setSelectedQuoteText(quotedText)
|
||||||
setContextMenuPosition({ x: e.clientX, y: e.clientY })
|
setContextMenuPosition({ x: e.clientX, y: e.clientY })
|
||||||
|
setSelectedText(_selectedText)
|
||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
@ -214,35 +208,9 @@ const MessageItem: FC<Props> = ({
|
|||||||
onContextMenu={handleContextMenu}
|
onContextMenu={handleContextMenu}
|
||||||
style={{ ...style, alignItems: isBubbleStyle ? (isAssistantMessage ? 'start' : 'end') : undefined }}>
|
style={{ ...style, alignItems: isBubbleStyle ? (isAssistantMessage ? 'start' : 'end') : undefined }}>
|
||||||
{contextMenuPosition && (
|
{contextMenuPosition && (
|
||||||
<ContextMenuOverlay
|
<ContextMenuOverlay style={{ left: contextMenuPosition.x, top: contextMenuPosition.y, zIndex: 1000 }}>
|
||||||
style={{
|
|
||||||
position: 'fixed',
|
|
||||||
left: contextMenuPosition.x,
|
|
||||||
top: contextMenuPosition.y,
|
|
||||||
zIndex: 1000
|
|
||||||
}}>
|
|
||||||
<Dropdown
|
<Dropdown
|
||||||
menu={{
|
menu={{ items: getContextMenuItems(t, selectedQuoteText, selectedText) }}
|
||||||
items: [
|
|
||||||
{
|
|
||||||
key: 'copy',
|
|
||||||
label: t('common.copy'),
|
|
||||||
onClick: () => {
|
|
||||||
navigator.clipboard.writeText(
|
|
||||||
selectedQuoteText.replace(/^> /gm, '').replace(/\n-------------$/, '')
|
|
||||||
)
|
|
||||||
window.message.success({ content: t('message.copied'), key: 'copy-message' })
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'quote',
|
|
||||||
label: t('chat.message.quote'),
|
|
||||||
onClick: () => {
|
|
||||||
EventEmitter.emit(EVENT_NAMES.QUOTE_TEXT, selectedQuoteText)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}}
|
|
||||||
open={true}
|
open={true}
|
||||||
trigger={['contextMenu']}>
|
trigger={['contextMenu']}>
|
||||||
<div />
|
<div />
|
||||||
@ -284,6 +252,32 @@ const MessageItem: FC<Props> = ({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getMessageBackground = (isBubbleStyle: boolean, isAssistantMessage: boolean) => {
|
||||||
|
return isBubbleStyle
|
||||||
|
? isAssistantMessage
|
||||||
|
? 'var(--chat-background-assistant)'
|
||||||
|
: 'var(--chat-background-user)'
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
const getContextMenuItems = (t: (key: string) => string, selectedQuoteText: string, selectedText: string) => [
|
||||||
|
{
|
||||||
|
key: 'copy',
|
||||||
|
label: t('common.copy'),
|
||||||
|
onClick: () => {
|
||||||
|
navigator.clipboard.writeText(selectedText)
|
||||||
|
window.message.success({ content: t('message.copied'), key: 'copy-message' })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'quote',
|
||||||
|
label: t('chat.message.quote'),
|
||||||
|
onClick: () => {
|
||||||
|
EventEmitter.emit(EVENT_NAMES.QUOTE_TEXT, selectedQuoteText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
const MessageContainer = styled.div`
|
const MessageContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user