cherry-studio/src/renderer/src/components/ContextMenu/index.tsx
kangfenmao f5c87af480 chore: update release notes and fix various issues
- Updated release notes to include new DMXAPI service and fixed knowledge base search results issue.
- Enhanced drag-and-drop functionality for message selection and resolved memory exceptions in translation replies.
- Added styling adjustments for context menu and improved layout in CodeBlockView and MessageGroup components.
2025-05-26 15:07:53 +08:00

95 lines
2.9 KiB
TypeScript

import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService'
import { Dropdown } from 'antd'
import { useCallback, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
interface ContextMenuProps {
children: React.ReactNode
onContextMenu?: (e: React.MouseEvent) => void
}
const ContextMenu: React.FC<ContextMenuProps> = ({ children, onContextMenu }) => {
const { t } = useTranslation()
const [contextMenuPosition, setContextMenuPosition] = useState<{ x: number; y: number } | null>(null)
const [selectedQuoteText, setSelectedQuoteText] = useState<string>('')
const [selectedText, setSelectedText] = useState<string>('')
const handleContextMenu = useCallback(
(e: React.MouseEvent) => {
e.preventDefault()
const _selectedText = window.getSelection()?.toString()
if (_selectedText) {
const quotedText =
_selectedText
.split('\n')
.map((line) => `> ${line}`)
.join('\n') + '\n-------------'
setSelectedQuoteText(quotedText)
setContextMenuPosition({ x: e.clientX, y: e.clientY })
setSelectedText(_selectedText)
}
onContextMenu?.(e)
},
[onContextMenu]
)
useEffect(() => {
const handleClick = () => {
setContextMenuPosition(null)
}
document.addEventListener('click', handleClick)
return () => {
document.removeEventListener('click', handleClick)
}
}, [])
// 获取右键菜单项
const getContextMenuItems = (t: (key: string) => string, selectedQuoteText: string, selectedText: string) => [
{
key: 'copy',
label: t('common.copy'),
onClick: () => {
if (selectedText) {
navigator.clipboard
.writeText(selectedText)
.then(() => {
window.message.success({ content: t('message.copied'), key: 'copy-message' })
})
.catch(() => {
window.message.error({ content: t('message.copy.failed'), key: 'copy-message-failed' })
})
}
}
},
{
key: 'quote',
label: t('chat.message.quote'),
onClick: () => {
if (selectedQuoteText) {
EventEmitter.emit(EVENT_NAMES.QUOTE_TEXT, selectedQuoteText)
}
}
}
]
return (
<ContextContainer onContextMenu={handleContextMenu} className="context-menu-container">
{contextMenuPosition && (
<Dropdown
overlayStyle={{ position: 'fixed', left: contextMenuPosition.x, top: contextMenuPosition.y, zIndex: 1000 }}
menu={{ items: getContextMenuItems(t, selectedQuoteText, selectedText) }}
open={true}
trigger={['contextMenu']}>
<div />
</Dropdown>
)}
{children}
</ContextContainer>
)
}
const ContextContainer = styled.div``
export default ContextMenu