import { Send, StopCircle, Image as ImageIcon, Paperclip } from "lucide-react" import { Button } from "../../ui/button" import { useEffect } from "react" import { TFile, TFolder } from "@/lib/types" import { ALLOWED_FILE_TYPES } from "./types" import { looksLikeCode } from "./lib/chatUtils" import { ChatInputProps } from "./types" export default function ChatInput({ input, setInput, isGenerating, handleSend, handleStopGeneration, onImageUpload, addContextTab, activeFileName, editorRef, lastCopiedRangeRef, contextTabs, onRemoveTab, textareaRef, }: ChatInputProps) { // Auto-resize textarea as content changes useEffect(() => { if (textareaRef.current) { textareaRef.current.style.height = 'auto' textareaRef.current.style.height = textareaRef.current.scrollHeight + 'px' } }, [input]) // Handle keyboard events for sending messages const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === "Enter") { if (e.ctrlKey) { e.preventDefault() handleSend(true) // Send with full context } else if (!e.shiftKey && !isGenerating) { e.preventDefault() handleSend(false) } } else if (e.key === "Backspace" && input === "" && contextTabs.length > 0) { e.preventDefault() // Remove the last context tab const lastTab = contextTabs[contextTabs.length - 1] onRemoveTab(lastTab.id) } } // Handle paste events for image and code const handlePaste = async (e: React.ClipboardEvent) => { // Handle image paste const items = Array.from(e.clipboardData.items); for (const item of items) { if (item.type.startsWith('image/')) { e.preventDefault(); const file = item.getAsFile(); if (!file) continue; try { // Convert image to base64 string for context tab title and timestamp const reader = new FileReader(); reader.onload = () => { const base64String = reader.result as string; addContextTab( "image", `Image ${new Date().toLocaleTimeString('en-US', { hour12: true, hour: '2-digit', minute: '2-digit' }).replace(/(\d{2}):(\d{2})/, '$1:$2')}`, base64String ); }; reader.readAsDataURL(file); } catch (error) { console.error('Error processing pasted image:', error); } return; } } // Get text from clipboard const text = e.clipboardData.getData('text'); // If text doesn't contain newlines or doesn't look like code, let it paste normally if (!text || !text.includes('\n') || !looksLikeCode(text)) { return; } e.preventDefault(); const editor = editorRef.current; const currentSelection = editor?.getSelection(); const lines = text.split('\n'); // TODO: FIX THIS: even when i paste the outside code, it shows the active file name,it works when no tabs are open, just does not work when the tab is open // If selection exists in editor, use file name and line numbers if (currentSelection && !currentSelection.isEmpty()) { addContextTab( "code", `${activeFileName} (${currentSelection.startLineNumber}-${currentSelection.endLineNumber})`, text, { start: currentSelection.startLineNumber, end: currentSelection.endLineNumber } ); return; } // If we have stored line range from a copy operation in the editor if (lastCopiedRangeRef.current) { const range = lastCopiedRangeRef.current; addContextTab( "code", `${activeFileName} (${range.startLine}-${range.endLine})`, text, { start: range.startLine, end: range.endLine } ); return; } // For code pasted from outside the editor addContextTab( "code", `Pasted Code (1-${lines.length})`, text, { start: 1, end: lines.length } ); }; // Handle image upload from local machine via input const handleImageUpload = () => { const input = document.createElement('input') input.type = 'file' input.accept = 'image/*' input.onchange = (e) => { const file = (e.target as HTMLInputElement).files?.[0] if (file) onImageUpload(file) } input.click() } // Helper function to flatten the file tree const getAllFiles = (items: (TFile | TFolder)[]): TFile[] => { return items.reduce((acc: TFile[], item) => { if (item.type === "file") { acc.push(item) } else { acc.push(...getAllFiles(item.children)) } return acc }, []) } // Handle file upload from local machine via input const handleFileUpload = () => { const input = document.createElement('input') input.type = 'file' input.accept = '.txt,.md,.csv,.json,.js,.ts,.html,.css,.pdf' input.onchange = (e) => { const file = (e.target as HTMLInputElement).files?.[0] if (file) { if (!(file.type in ALLOWED_FILE_TYPES)) { alert('Unsupported file type. Please upload text, code, or PDF files.') return } const reader = new FileReader() reader.onload = () => { addContextTab("file", file.name, reader.result as string) } reader.readAsText(file) } } input.click() } return (