diff --git a/frontend/components/editor/AIChat.tsx b/frontend/components/editor/AIChat.tsx new file mode 100644 index 0000000..6fe7ed3 --- /dev/null +++ b/frontend/components/editor/AIChat.tsx @@ -0,0 +1,64 @@ +import React, { useState, useRef, useEffect } from 'react'; +import { Button } from '../ui/button'; +import { Send } from 'lucide-react'; + +interface Message { + role: 'user' | 'assistant'; + content: string; +} + +export default function AIChat() { + const [messages, setMessages] = useState([]); + const [input, setInput] = useState(''); + const chatContainerRef = useRef(null); + + useEffect(() => { + if (chatContainerRef.current) { + chatContainerRef.current.scrollTop = chatContainerRef.current.scrollHeight; + } + }, [messages]); + + const handleSend = async () => { + if (input.trim() === '') return; + + const newMessage: Message = { role: 'user', content: input }; + setMessages(prev => [...prev, newMessage]); + setInput(''); + + // TODO: Implement actual API call to LLM here + // For now, we'll just simulate a response + setTimeout(() => { + const assistantMessage: Message = { role: 'assistant', content: 'This is a simulated response from the AI.' }; + setMessages(prev => [...prev, assistantMessage]); + }, 1000); + }; + + return ( +
+
+ {messages.map((message, index) => ( +
+
+ {message.content} +
+
+ ))} +
+
+
+ setInput(e.target.value)} + onKeyPress={(e) => e.key === 'Enter' && handleSend()} + className="flex-grow p-2 border rounded-lg" + placeholder="Type your message..." + /> + +
+
+
+ ); +} diff --git a/frontend/components/editor/index.tsx b/frontend/components/editor/index.tsx index bc0e10e..bf4eecc 100644 --- a/frontend/components/editor/index.tsx +++ b/frontend/components/editor/index.tsx @@ -37,6 +37,7 @@ import { Button } from "../ui/button" import React from "react" import { parseTSConfigToMonacoOptions } from "@/lib/tsconfig" import { deepMerge } from "@/lib/utils" +import AIChat from "./AIChat" export default function CodeEditor({ userData, @@ -73,6 +74,12 @@ export default function CodeEditor({ message: "", }) + // Layout state + const [isHorizontalLayout, setIsHorizontalLayout] = useState(false); + + // AI Chat state + const [isAIChatOpen, setIsAIChatOpen] = useState(false); + // File state const [files, setFiles] = useState<(TFolder | TFile)[]>([]) const [tabs, setTabs] = useState([]) @@ -513,20 +520,23 @@ export default function CodeEditor({ [socket, fileContents] ); - // Keydown event listener to trigger file save on Ctrl+S or Cmd+S + // Keydown event listener to trigger file save on Ctrl+S or Cmd+S, and toggle AI chat on Ctrl+L or Cmd+L useEffect(() => { const down = (e: KeyboardEvent) => { if (e.key === "s" && (e.metaKey || e.ctrlKey)) { e.preventDefault() debouncedSaveData(activeFileId); + } else if (e.key === "l" && (e.metaKey || e.ctrlKey)) { + e.preventDefault() + setIsAIChatOpen(prev => !prev); } } document.addEventListener("keydown", down) - + return () => { document.removeEventListener("keydown", down) } - }, [activeFileId, tabs, debouncedSaveData]) + }, [activeFileId, tabs, debouncedSaveData, setIsAIChatOpen]) // Liveblocks live collaboration setup effect useEffect(() => { @@ -837,8 +847,6 @@ export default function CodeEditor({ } }; - const [isHorizontalLayout, setIsHorizontalLayout] = useState(false); - const toggleLayout = () => { setIsHorizontalLayout(prev => !prev); }; @@ -1075,54 +1083,58 @@ export default function CodeEditor({ - - setIsPreviewCollapsed(true)} - onExpand={() => setIsPreviewCollapsed(false)} - > -
- - -
- {!isPreviewCollapsed && ( -
-