"use client"; import { useState, useEffect, useRef } from "react"; import { useTheme } from "next-themes"; import { Code, Eye, Send, Download, Copy, Maximize2, Minimize2, FileCode2, X, Github, } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Textarea } from "@/components/ui/textarea"; import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { ResizableHandle, ResizablePanel, ResizablePanelGroup, } from "@/components/ui/resizable"; import { ScrollArea } from "@/components/ui/scroll-area"; import { Message, PreviewState } from "@/lib/types"; // @ts-expect-error import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; import { customOneDark, customOneLight, generateUUID } from "@/lib/utils"; import DynamicFileRenderer from "@/webzero/preview"; import ThemeToggle from "@/components/ThemeToggle"; import { SidebarTrigger } from "@/components/ui/sidebar"; import { useSessionContext } from "@/context/SessionContext"; function CodeMessageCard({ version, onClick, }: { version: number; onClick: () => void; }) { return (
Code v{version}
); } const sendMessage = async (content: string) => { const response = await fetch("/api/new", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ content }), }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || "Failed to send message"); } const data = await response.json(); return data; }; const sendIteration = async ( previousDescription: string, newUpdate: string, currentCode: string ) => { const response = await fetch("/api/iterate", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ previousDescription, newUpdate, currentCode }), }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || "Failed to process iteration"); } const data = await response.json(); return data; }; export function ChatPage() { const [message, setMessage] = useState(""); const [isLoading, setIsLoading] = useState(false); const [currentIteration, setCurrentIteration] = useState<{ previousDescription: string; currentCode: string; } | null>(null); const [previewState, setPreviewState] = useState({ isFullscreen: false, isOpen: false, }); const [selectedAIMessage, setSelectedAIMessage] = useState( null ); const { theme } = useTheme(); const isDark = theme === "dark"; const messagesEndRef = useRef(null); const scrollToBottom = () => { messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); }; const { sessions, currentSessionId, updateSessionMessages } = useSessionContext(); const currentSession = sessions.find( (session) => session.id === currentSessionId ); useEffect(() => { setSelectedAIMessage(null); setPreviewState((prev) => ({ ...prev, isOpen: false, isFullscreen: false, })); if (currentSession && currentSession.messages.length > 0) { const lastAIMessage = currentSession.messages .slice() .reverse() .find((msg) => msg.from === "ai"); if (lastAIMessage) { const precedingUserMessage = currentSession.messages[ currentSession.messages.indexOf(lastAIMessage) - 1 ]; if (precedingUserMessage && precedingUserMessage.from === "user") { setCurrentIteration({ previousDescription: precedingUserMessage.content, currentCode: lastAIMessage.content, }); } else { setCurrentIteration(null); } } else { setCurrentIteration(null); } } else { setCurrentIteration(null); } }, [currentSessionId]); useEffect(() => { scrollToBottom(); }, [currentSession?.messages]); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!message.trim() || !currentSessionId) return; setIsLoading(true); const newUserMessage: Message = { id: generateUUID().toString(), from: "user", content: message, }; const updatedMessages = [ ...(currentSession?.messages || []), newUserMessage, ]; updateSessionMessages(currentSessionId, updatedMessages); setMessage(""); try { let response; if (currentIteration) { response = await sendIteration( currentIteration.previousDescription, message, currentIteration.currentCode ); } else { response = await sendMessage(message); } updateSessionMessages(currentSessionId, [...updatedMessages, response]); setCurrentIteration({ previousDescription: message, currentCode: response.content, }); setSelectedAIMessage(response); setPreviewState((prev) => ({ ...prev, isOpen: true })); } catch (error) { console.error("Error:", error); } finally { setIsLoading(false); } }; const handleCopyCode = async (code: string) => { try { await navigator.clipboard.writeText(code); } catch (error) { console.error("Failed to copy code:", error); } }; const handleDownloadCode = (code: string, filename: string) => { const blob = new Blob([code], { type: "text/plain" }); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = filename; a.click(); URL.revokeObjectURL(url); }; const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); handleSubmit(e); } }; const toggleFullscreen = () => { setPreviewState((prev) => ({ ...prev, isFullscreen: !prev.isFullscreen, })); }; return (

WebZero

{!currentSession || currentSession.messages.length === 0 ? (

Welcome to WebZero