mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-23 18:10:26 +08:00
feat: Drop file improvements (#6089)
* feat: enhance file drag-and-drop functionality and global paste handling in Inputbar - Added support for file dragging with visual feedback. - Implemented global paste event handling to allow pasting outside the text area. - Improved file drop handling to notify users of unsupported file types. * refactor(Inputbar): simplify global paste handling logic - Removed unnecessary checks for active element in global paste event handling. - Streamlined the paste event processing for improved clarity and maintainability. * style(Inputbar): clean up comments and maintain visual feedback for file dragging - Removed unnecessary comments related to the styling of the file dragging state. - Ensured the visual feedback for file dragging remains intact with updated background color.
This commit is contained in:
parent
3c2e8e2f1d
commit
c2465c33b7
@ -117,6 +117,7 @@ const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic, topic }) =
|
|||||||
const [selectedKnowledgeBases, setSelectedKnowledgeBases] = useState<KnowledgeBase[]>([])
|
const [selectedKnowledgeBases, setSelectedKnowledgeBases] = useState<KnowledgeBase[]>([])
|
||||||
const [mentionModels, setMentionModels] = useState<Model[]>([])
|
const [mentionModels, setMentionModels] = useState<Model[]>([])
|
||||||
const [isDragging, setIsDragging] = useState(false)
|
const [isDragging, setIsDragging] = useState(false)
|
||||||
|
const [isFileDragging, setIsFileDragging] = useState(false)
|
||||||
const [textareaHeight, setTextareaHeight] = useState<number>()
|
const [textareaHeight, setTextareaHeight] = useState<number>()
|
||||||
const startDragY = useRef<number>(0)
|
const startDragY = useRef<number>(0)
|
||||||
const startHeight = useRef<number>(0)
|
const startHeight = useRef<number>(0)
|
||||||
@ -646,14 +647,44 @@ const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic, topic }) =
|
|||||||
[model, pasteLongTextAsFile, pasteLongTextThreshold, resizeTextArea, supportExts, t, text]
|
[model, pasteLongTextAsFile, pasteLongTextThreshold, resizeTextArea, supportExts, t, text]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 添加全局粘贴事件处理
|
||||||
|
useEffect(() => {
|
||||||
|
const handleGlobalPaste = (event: ClipboardEvent) => {
|
||||||
|
if (document.activeElement === textareaRef.current?.resizableTextArea?.textArea) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
onPaste(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('paste', handleGlobalPaste)
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener('paste', handleGlobalPaste)
|
||||||
|
}
|
||||||
|
}, [onPaste])
|
||||||
|
|
||||||
const handleDragOver = (e: React.DragEvent<HTMLDivElement>) => {
|
const handleDragOver = (e: React.DragEvent<HTMLDivElement>) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
setIsFileDragging(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDragEnter = (e: React.DragEvent<HTMLDivElement>) => {
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
setIsFileDragging(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDragLeave = (e: React.DragEvent<HTMLDivElement>) => {
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
setIsFileDragging(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleDrop = async (e: React.DragEvent<HTMLDivElement>) => {
|
const handleDrop = async (e: React.DragEvent<HTMLDivElement>) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
setIsFileDragging(false)
|
||||||
|
|
||||||
const files = await getFilesFromDropEvent(e).catch((err) => {
|
const files = await getFilesFromDropEvent(e).catch((err) => {
|
||||||
Logger.error('[src/renderer/src/pages/home/Inputbar/Inputbar.tsx] handleDrop:', err)
|
Logger.error('[src/renderer/src/pages/home/Inputbar/Inputbar.tsx] handleDrop:', err)
|
||||||
@ -661,11 +692,22 @@ const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic, topic }) =
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (files) {
|
if (files) {
|
||||||
|
let supportedFiles = 0
|
||||||
|
|
||||||
files.forEach((file) => {
|
files.forEach((file) => {
|
||||||
if (supportExts.includes(getFileExtension(file.path))) {
|
if (supportExts.includes(getFileExtension(file.path))) {
|
||||||
setFiles((prevFiles) => [...prevFiles, file])
|
setFiles((prevFiles) => [...prevFiles, file])
|
||||||
|
supportedFiles++
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 如果有文件,但都不支持
|
||||||
|
if (files.length > 0 && supportedFiles === 0) {
|
||||||
|
window.message.info({
|
||||||
|
key: 'file_not_supported',
|
||||||
|
content: t('chat.input.file_not_supported')
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -881,12 +923,17 @@ const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic, topic }) =
|
|||||||
const showThinkingButton = isSupportedThinkingTokenModel(model) || isSupportedReasoningEffortModel(model)
|
const showThinkingButton = isSupportedThinkingTokenModel(model) || isSupportedReasoningEffortModel(model)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container onDragOver={handleDragOver} onDrop={handleDrop} className="inputbar">
|
<Container
|
||||||
|
onDragOver={handleDragOver}
|
||||||
|
onDrop={handleDrop}
|
||||||
|
onDragEnter={handleDragEnter}
|
||||||
|
onDragLeave={handleDragLeave}
|
||||||
|
className="inputbar">
|
||||||
<NarrowLayout style={{ width: '100%' }}>
|
<NarrowLayout style={{ width: '100%' }}>
|
||||||
<QuickPanelView setInputText={setText} />
|
<QuickPanelView setInputText={setText} />
|
||||||
<InputBarContainer
|
<InputBarContainer
|
||||||
id="inputbar"
|
id="inputbar"
|
||||||
className={classNames('inputbar-container', inputFocus && 'focus')}
|
className={classNames('inputbar-container', inputFocus && 'focus', isFileDragging && 'file-dragging')}
|
||||||
ref={containerRef}>
|
ref={containerRef}>
|
||||||
{files.length > 0 && <AttachmentPreview files={files} setFiles={setFiles} />}
|
{files.length > 0 && <AttachmentPreview files={files} setFiles={setFiles} />}
|
||||||
{selectedKnowledgeBases.length > 0 && (
|
{selectedKnowledgeBases.length > 0 && (
|
||||||
@ -1067,6 +1114,23 @@ const InputBarContainer = styled.div`
|
|||||||
border-radius: 15px;
|
border-radius: 15px;
|
||||||
padding-top: 6px; // 为拖动手柄留出空间
|
padding-top: 6px; // 为拖动手柄留出空间
|
||||||
background-color: var(--color-background-opacity);
|
background-color: var(--color-background-opacity);
|
||||||
|
|
||||||
|
&.file-dragging {
|
||||||
|
border: 2px dashed #2ecc71;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: rgba(46, 204, 113, 0.03);
|
||||||
|
border-radius: 14px;
|
||||||
|
z-index: 5;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const TextareaStyle: CSSProperties = {
|
const TextareaStyle: CSSProperties = {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user