Spaces:
Running
Running
File size: 4,663 Bytes
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 |
'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-[#1d1d1f]">
{/* Messages */}
<div className="flex-1 overflow-y-auto p-5 space-y-4">
{messages.length === 0 ? (
<div className="text-center text-[#a1a1a6] mt-12">
<div className="text-5xl mb-5">π¬</div>
{isAuthenticated ? (
<>
<p className="text-lg font-semibold text-[#e5e5e7] tracking-tight">Start a conversation</p>
<p className="text-sm mt-3 text-[#86868b] leading-relaxed">Describe what you want to build and I'll generate the code</p>
</>
) : (
<>
<p className="text-lg font-semibold text-[#ff9f0a]">π Sign in to get started</p>
<p className="text-sm mt-3 text-[#86868b] leading-relaxed">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 p-4 shadow-sm ${
message.role === 'user'
? 'bg-[#007aff] text-white'
: 'bg-[#2c2c2e] text-[#e5e5e7] border border-[#48484a]'
}`}
>
<div className="flex items-start space-x-3">
<div className="text-base flex-shrink-0">
{message.role === 'user' ? 'π€' : 'π€'}
</div>
<div className="flex-1 text-sm leading-relaxed">
{message.role === 'assistant' ? (
<ReactMarkdown
remarkPlugins={[remarkGfm]}
className="prose prose-invert prose-sm max-w-none"
>
{message.content}
</ReactMarkdown>
) : (
<p className="whitespace-pre-wrap font-medium">{message.content}</p>
)}
</div>
</div>
{message.timestamp && (
<div className="text-xs opacity-50 mt-2 text-right font-medium">
{new Date(message.timestamp).toLocaleTimeString()}
</div>
)}
</div>
</div>
))
)}
<div ref={messagesEndRef} />
</div>
{/* Input */}
<div className="border-t border-[#48484a] p-4 bg-[#28282a]">
<form onSubmit={handleSubmit} className="flex space-x-3">
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder={isAuthenticated ? "Message AnyCoder..." : "π Please sign in first..."}
disabled={isGenerating || !isAuthenticated}
className="flex-1 px-4 py-3 bg-[#3a3a3c] text-[#e5e5e7] text-sm border border-[#48484a] rounded-xl focus:outline-none focus:ring-2 focus:ring-[#007aff] focus:border-transparent disabled:opacity-50 disabled:cursor-not-allowed placeholder-[#86868b] font-medium shadow-sm"
/>
<button
type="submit"
disabled={isGenerating || !input.trim() || !isAuthenticated}
className="px-5 py-3 bg-[#007aff] text-white text-sm rounded-xl hover:bg-[#0051d5] disabled:bg-[#48484a] disabled:cursor-not-allowed transition-all font-semibold shadow-md disabled:shadow-none active:scale-95"
>
{isGenerating ? 'β³' : 'β'}
</button>
</form>
</div>
</div>
);
}
|