@@ -35,6 +35,8 @@ export const ChatInput: React.FC<{
3535 const [ inputValue , setInputValue ] = useState ( '' )
3636 const [ attachedFiles , setAttachedFiles ] = useState < AttachedFile [ ] > ( [ ] )
3737 const [ uploadErrors , setUploadErrors ] = useState < string [ ] > ( [ ] )
38+ const [ dragCounter , setDragCounter ] = useState ( 0 )
39+ const isDragOver = dragCounter > 0
3840
3941 // Check if speech-to-text is available in the browser
4042 const isSttAvailable =
@@ -234,11 +236,42 @@ export const ChatInput: React.FC<{
234236
235237 { /* Text Input Area with Controls */ }
236238 < motion . div
237- className = 'rounded-2xl border border-gray-200 bg-white shadow-sm md:rounded-3xl'
239+ className = { `rounded-2xl border shadow-sm transition-all duration-200 md:rounded-3xl ${
240+ isDragOver
241+ ? 'border-purple-500 bg-purple-50/50 dark:border-purple-500 dark:bg-purple-950/20'
242+ : 'border-gray-200 bg-white'
243+ } `}
238244 onClick = { handleActivate }
239245 initial = { { opacity : 0 , y : 10 } }
240246 animate = { { opacity : 1 , y : 0 } }
241247 transition = { { duration : 0.2 } }
248+ onDragEnter = { ( e ) => {
249+ e . preventDefault ( )
250+ e . stopPropagation ( )
251+ if ( ! isStreaming ) {
252+ setDragCounter ( ( prev ) => prev + 1 )
253+ }
254+ } }
255+ onDragOver = { ( e ) => {
256+ e . preventDefault ( )
257+ e . stopPropagation ( )
258+ if ( ! isStreaming ) {
259+ e . dataTransfer . dropEffect = 'copy'
260+ }
261+ } }
262+ onDragLeave = { ( e ) => {
263+ e . preventDefault ( )
264+ e . stopPropagation ( )
265+ setDragCounter ( ( prev ) => Math . max ( 0 , prev - 1 ) )
266+ } }
267+ onDrop = { ( e ) => {
268+ e . preventDefault ( )
269+ e . stopPropagation ( )
270+ setDragCounter ( 0 )
271+ if ( ! isStreaming ) {
272+ handleFileSelect ( e . dataTransfer . files )
273+ }
274+ } }
242275 >
243276 { /* File Previews */ }
244277 { attachedFiles . length > 0 && (
@@ -341,7 +374,7 @@ export const ChatInput: React.FC<{
341374 value = { inputValue }
342375 onChange = { handleInputChange }
343376 className = 'flex w-full resize-none items-center overflow-hidden bg-transparent text-base outline-none placeholder:text-gray-400 md:font-[330]'
344- placeholder = { isActive ? '' : '' }
377+ placeholder = { isDragOver ? 'Drop files here...' : isActive ? '' : '' }
345378 rows = { 1 }
346379 style = { {
347380 minHeight : window . innerWidth >= 768 ? '24px' : '28px' ,
@@ -366,14 +399,14 @@ export const ChatInput: React.FC<{
366399 className = '-translate-y-1/2 absolute top-1/2 left-0 transform select-none text-base text-gray-400 md:hidden'
367400 style = { { paddingTop : '3px' , paddingBottom : '3px' } }
368401 >
369- { PLACEHOLDER_MOBILE }
402+ { isDragOver ? 'Drop files here...' : PLACEHOLDER_MOBILE }
370403 </ div >
371404 { /* Desktop placeholder */ }
372405 < div
373406 className = '-translate-y-1/2 absolute top-1/2 left-0 hidden transform select-none font-[330] text-base text-gray-400 md:block'
374407 style = { { paddingTop : '4px' , paddingBottom : '4px' } }
375408 >
376- { PLACEHOLDER_DESKTOP }
409+ { isDragOver ? 'Drop files here...' : PLACEHOLDER_DESKTOP }
377410 </ div >
378411 </ >
379412 ) }
0 commit comments