chore: prevent drag image to replace the window, and enable shortcut copy and paste image

This commit is contained in:
Faisal Amir 2025-08-15 16:34:42 +07:00
parent f70449fd98
commit e04bb86171
2 changed files with 73 additions and 1 deletions

View File

@ -332,6 +332,41 @@ const ChatInput = ({ model, className, initialMessage }: ChatInputProps) => {
}
}
const handlePaste = (e: React.ClipboardEvent) => {
const clipboardItems = e.clipboardData?.items
if (!clipboardItems) return
const imageItems = Array.from(clipboardItems).filter(item =>
item.type.startsWith('image/')
)
if (imageItems.length > 0) {
e.preventDefault()
const files: File[] = []
let processedCount = 0
imageItems.forEach((item) => {
const file = item.getAsFile()
if (file) {
files.push(file)
processedCount++
// When all files are collected, process them
if (processedCount === imageItems.length) {
const syntheticEvent = {
target: {
files: files,
},
} as unknown as React.ChangeEvent<HTMLInputElement>
handleFileChange(syntheticEvent)
}
}
})
}
}
return (
<div className="relative">
<div className="relative">
@ -359,6 +394,7 @@ const ChatInput = ({ model, className, initialMessage }: ChatInputProps) => {
isFocused && 'ring-1 ring-main-view-fg/10',
isDragOver && 'ring-2 ring-accent border-accent'
)}
data-drop-zone="true"
onDragEnter={handleDragEnter}
onDragLeave={handleDragLeave}
onDragOver={handleDragOver}
@ -423,6 +459,7 @@ const ChatInput = ({ model, className, initialMessage }: ChatInputProps) => {
// When Shift+Enter is pressed, a new line is added (default behavior)
}
}}
onPaste={handlePaste}
placeholder={t('common:placeholder.chatInput')}
autoFocus
spellCheck={spellCheckChatInput}

View File

@ -26,7 +26,7 @@ import {
ResizablePanel,
ResizableHandle,
} from '@/components/ui/resizable'
import { useCallback } from 'react'
import { useCallback, useEffect } from 'react'
import GlobalError from '@/containers/GlobalError'
import { GlobalEventHandler } from '@/providers/GlobalEventHandler'
@ -65,6 +65,41 @@ const AppLayout = () => {
[setLeftPanelSize, setLeftPanel]
)
// Prevent default drag and drop behavior globally
useEffect(() => {
const preventDefaults = (e: DragEvent) => {
e.preventDefault()
e.stopPropagation()
}
const handleGlobalDrop = (e: DragEvent) => {
e.preventDefault()
e.stopPropagation()
// Only prevent if the target is not within a chat input or other valid drop zone
const target = e.target as Element
const isValidDropZone = target?.closest('[data-drop-zone="true"]') ||
target?.closest('.chat-input-drop-zone') ||
target?.closest('[data-tauri-drag-region]')
if (!isValidDropZone) {
// Prevent the file from opening in the window
return false
}
}
// Add event listeners to prevent default drag/drop behavior
window.addEventListener('dragenter', preventDefaults)
window.addEventListener('dragover', preventDefaults)
window.addEventListener('drop', handleGlobalDrop)
return () => {
window.removeEventListener('dragenter', preventDefaults)
window.removeEventListener('dragover', preventDefaults)
window.removeEventListener('drop', handleGlobalDrop)
}
}, [])
return (
<Fragment>
<AnalyticProvider />