Spaces:
Running
Running
File size: 4,933 Bytes
b42dfef 04c818a b42dfef 04c818a b42dfef 04c818a b42dfef 04c818a b42dfef 04c818a b42dfef 04c818a b42dfef 04c818a b42dfef 04c818a 7f9535b 04c818a b42dfef 04c818a b42dfef 04c818a b42dfef 04c818a b42dfef 04c818a b42dfef 04c818a b42dfef 04c818a b42dfef |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
'use client';
import { useState, useRef, useEffect } from 'react';
import type { Message } from '@/types';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
interface ChatInterfaceProps {
messages: Message[];
onSendMessage: (message: string) => void;
isGenerating: boolean;
isAuthenticated?: boolean;
}
export default function ChatInterface({ messages, onSendMessage, isGenerating, isAuthenticated = false }: ChatInterfaceProps) {
const [input, setInput] = useState('');
const messagesEndRef = useRef<HTMLDivElement>(null);
const scrollToBottom = () => {
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
};
useEffect(() => {
scrollToBottom();
}, [messages]);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (input.trim() && !isGenerating) {
onSendMessage(input);
setInput('');
}
};
return (
<div className="flex flex-col h-full bg-[#000000]">
{/* Messages */}
<div className="flex-1 overflow-y-auto p-4 space-y-3">
{messages.length === 0 ? (
<div className="text-center text-[#86868b] mt-12">
{isAuthenticated ? (
<>
<p className="text-lg font-medium text-[#f5f5f7]">Start a conversation</p>
<p className="text-sm mt-2 text-[#86868b]">Describe what you want to build</p>
</>
) : (
<>
<p className="text-lg font-medium text-[#f5f5f7]">Sign in to get started</p>
<p className="text-sm mt-2 text-[#86868b]">Use Dev Login or sign in with Hugging Face</p>
</>
)}
</div>
) : (
messages.map((message, index) => (
<div
key={index}
className={`flex ${message.role === 'user' ? 'justify-end' : 'justify-start'}`}
>
<div
className={`max-w-[85%] rounded-2xl px-4 py-3 ${
message.role === 'user'
? 'bg-white text-black'
: 'bg-[#2d2d2f] text-[#f5f5f7]'
}`}
>
<div className="text-sm leading-relaxed">
{message.role === 'assistant' ? (
<ReactMarkdown
remarkPlugins={[remarkGfm]}
className="prose prose-invert prose-sm max-w-none [&>p]:my-0 [&>ul]:my-1 [&>ol]:my-1"
components={{
a: ({ node, ...props }) => <a {...props} target="_blank" rel="noopener noreferrer" />
}}
>
{message.content}
</ReactMarkdown>
) : (
<p className="whitespace-pre-wrap break-words">{message.content}</p>
)}
</div>
{message.timestamp && (
<div className="text-[10px] opacity-40 mt-2 text-right">
{new Date(message.timestamp).toLocaleTimeString()}
</div>
)}
</div>
</div>
))
)}
<div ref={messagesEndRef} />
</div>
{/* Input */}
<div className="border-t border-[#424245]/30 p-3 bg-[#000000]">
<form onSubmit={handleSubmit} className="flex items-center gap-2">
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder={isAuthenticated ? "Message AnyCoder..." : "Sign in first..."}
disabled={isGenerating || !isAuthenticated}
className="flex-1 px-4 py-2.5 bg-[#2d2d2f] text-[#f5f5f7] text-sm border border-[#424245]/50 rounded-full focus:outline-none focus:border-[#424245] disabled:opacity-40 disabled:cursor-not-allowed placeholder-[#86868b]"
/>
<button
type="submit"
disabled={isGenerating || !input.trim() || !isAuthenticated}
className="p-2.5 bg-white text-black rounded-full hover:bg-[#f5f5f7] disabled:bg-[#2d2d2f] disabled:text-[#86868b] disabled:cursor-not-allowed transition-all active:scale-95 flex-shrink-0"
>
{isGenerating ? (
<svg className="w-4 h-4 animate-spin" fill="none" stroke="currentColor" viewBox="0 0 24 24" strokeWidth={2.5}>
<path strokeLinecap="round" strokeLinejoin="round" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
</svg>
) : (
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" strokeWidth={2.5}>
<path strokeLinecap="round" strokeLinejoin="round" d="M5 12h14M12 5l7 7-7 7" />
</svg>
)}
</button>
</form>
</div>
</div>
);
}
|