diff --git a/app/assistant.tsx b/app/assistant.tsx deleted file mode 100644 index c229d29..0000000 --- a/app/assistant.tsx +++ /dev/null @@ -1,21 +0,0 @@ -"use client"; - -import { AssistantRuntimeProvider } from "@assistant-ui/react"; -import { useChatRuntime } from "@assistant-ui/react-ai-sdk"; -import { Thread } from "@/components/assistant-ui/thread"; -import { ThreadList } from "@/components/assistant-ui/thread-list"; - -export const Assistant = () => { - const runtime = useChatRuntime({ - api: "/api/chat", - }); - - return ( - -
- - -
-
- ); -}; diff --git a/components/chat-input.tsx b/components/chat-input.tsx index 0d0dcf1..0c66888 100644 --- a/components/chat-input.tsx +++ b/components/chat-input.tsx @@ -1,6 +1,6 @@ "use client"; -import React, { useCallback, useRef, useEffect } from "react"; +import React, { useCallback, useRef, useEffect, useState } from "react"; import { Button } from "@/components/ui/button"; import { Textarea } from "@/components/ui/textarea"; import { Loader2, Send, RotateCcw, Image as ImageIcon, X } from "lucide-react"; @@ -35,6 +35,7 @@ export function ChatInput({ }: ChatInputProps) { const textareaRef = useRef(null); const fileInputRef = useRef(null); + const [isDragging, setIsDragging] = useState(false); // Auto-resize textarea based on content const adjustTextareaHeight = useCallback(() => { @@ -49,34 +50,6 @@ export function ChatInput({ adjustTextareaHeight(); }, [input, adjustTextareaHeight]); - // Handle clipboard paste events - const handlePaste = useCallback( - (e: React.ClipboardEvent) => { - if (!onFileChange) return; - - const items = e.clipboardData.items; - const imageItems = Array.from(items).filter( - (item) => item.type.indexOf("image") !== -1 - ); - - if (imageItems.length > 0) { - e.preventDefault(); - - // Convert clipboard image to File - const file = imageItems[0].getAsFile(); - if (file) { - // Create a new FileList-like object - const dataTransfer = new DataTransfer(); - dataTransfer.items.add(file); - - // Pass to the existing file handler - onFileChange(dataTransfer.files); - } - } - }, - [onFileChange] - ); - // Handle keyboard shortcuts const handleKeyDown = (e: React.KeyboardEvent) => { if ((e.metaKey || e.ctrlKey) && e.key === "Enter") { @@ -110,8 +83,55 @@ export function ChatInput({ fileInputRef.current?.click(); }; + // Handle drag events + const handleDragOver = (e: React.DragEvent) => { + e.preventDefault(); + e.stopPropagation(); + setIsDragging(true); + }; + + const handleDragLeave = (e: React.DragEvent) => { + e.preventDefault(); + e.stopPropagation(); + setIsDragging(false); + }; + + const handleDrop = (e: React.DragEvent) => { + e.preventDefault(); + e.stopPropagation(); + setIsDragging(false); + + if (status === "streaming") return; + + const droppedFiles = e.dataTransfer.files; + + // Only process image files + if (droppedFiles.length > 0) { + const imageFiles = Array.from(droppedFiles).filter((file) => + file.type.startsWith("image/") + ); + + if (imageFiles.length > 0 && onFileChange) { + // Create a new FileList-like object with only image files + const dt = new DataTransfer(); + imageFiles.forEach((file) => dt.items.add(file)); + onFileChange(dt.files); + } + } + }; + return ( -
+ {/* File preview area */} {files && files.length > 0 && (
@@ -135,7 +155,7 @@ export function ChatInput({