ChatInterface
chatinterface-1779378413147.tsx
'use client'
import { useState, useRef, useEffect } from 'react'
interface Msg { id: number; role: 'user' | 'assistant'; content: string; streaming?: boolean }
const RESPONSES = [
"Here's a React component for you:
```tsx
export default function Button() {
return <button className="bg-gold-500 text-black px-4 py-2 rounded">Click me</button>
}
```",
"I found 12 matching components in the Empire UI library. The most popular are: **GlowButton**, **HoverTiltCard**, and **CommandMenu**. Would you like the code for any of these?",
"Great choice! The `RadialProgress` component uses SVG stroke animation with `stroke-dashoffset`. It supports 4 metrics simultaneously and animates on mount. Here's how to install it...",
"I can generate a custom component for that. Give me a moment... ✨
Here's a `PricingToggle` with monthly/annual billing and animated transitions between prices.",
]
export default function ChatInterface() {
const [msgs, setMsgs] = useState<Msg[]>([
{ id: 0, role: 'assistant', content: 'Hi! I\'m Empire UI Assistant. Ask me to find or generate any React component.' }
])
const [input, setInput] = useState('')
const [loading, setLoading] = useState(false)
const bottomRef = useRef<HTMLDivElement>(null)
useEffect(() => { bottomRef.current?.scrollIntoView({ behavior: 'smooth' }) }, [msgs])
async function send() {
if (!input.trim() || loading) return
const userMsg: Msg = { id: Date.now(), role: 'user', content: input }
setMsgs(m => [...m, userMsg])
setInput('')
setLoading(true)
const responseText = RESPONSES[Math.floor(Math.random() * RESPONSES.length)]
const aiMsg: Msg = { id: Date.now() + 1, role: 'assistant', content: '', streaming: true }
setMsgs(m => [...m, aiMsg])
for (let i = 0; i <= responseText.length; i++) {
await new Promise(r => setTimeout(r, 15))
setMsgs(m => m.map(msg => msg.id === aiMsg.id ? { ...msg, content: responseText.slice(0, i) } : msg))
}
setMsgs(m => m.map(msg => msg.id === aiMsg.id ? { ...msg, streaming: false } : msg))
setLoading(false)
}
return (
<div style={{ background: '#0A0A0A', height: 480, display: 'flex', flexDirection: 'column', border: '1px solid rgba(255,255,255,0.08)', borderRadius: 16, overflow: 'hidden' }}>
{/* Header */}
<div style={{ padding: '14px 20px', borderBottom: '1px solid rgba(255,255,255,0.06)', display: 'flex', alignItems: 'center', gap: 10, background: '#111' }}>
<div style={{ width: 32, height: 32, borderRadius: '50%', background: 'linear-gradient(135deg, #C9A84C, #6366f1)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 16 }}>⚡</div>
<div>
<div style={{ color: '#F5F5F0', fontSize: 14, fontWeight: 600 }}>Empire UI Assistant</div>
<div style={{ color: '#22c55e', fontSize: 11 }}>● Online</div>
</div>
</div>
{/* Messages */}
<div style={{ flex: 1, overflowY: 'auto', padding: '16px 20px', display: 'flex', flexDirection: 'column', gap: 12 }}>
{msgs.map(msg => (
<div key={msg.id} style={{ display: 'flex', justifyContent: msg.role === 'user' ? 'flex-end' : 'flex-start', gap: 8 }}>
{msg.role === 'assistant' && (
<div style={{ width: 28, height: 28, borderRadius: '50%', background: 'linear-gradient(135deg, #C9A84C, #6366f1)', flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 14 }}>⚡</div>
)}
<div style={{
maxWidth: '75%', padding: '10px 14px', borderRadius: msg.role === 'user' ? '16px 16px 4px 16px' : '16px 16px 16px 4px',
background: msg.role === 'user' ? '#C9A84C' : '#1a1a1a',
color: msg.role === 'user' ? '#0A0A0A' : '#F5F5F0', fontSize: 14, lineHeight: 1.5,
border: msg.role === 'assistant' ? '1px solid rgba(255,255,255,0.06)' : 'none',
}}>
{msg.content}
{msg.streaming && <span style={{ display: 'inline-block', width: 2, height: 14, background: '#C9A84C', marginLeft: 2, animation: 'blink 0.7s step-end infinite', verticalAlign: 'text-bottom' }} />}
</div>
</div>
))}
<div ref={bottomRef} />
</div>
{/* Input */}
<div style={{ padding: '12px 16px', borderTop: '1px solid rgba(255,255,255,0.06)', display: 'flex', gap: 10 }}>
<input
value={input} onChange={e => setInput(e.target.value)}
onKeyDown={e => e.key === 'Enter' && !e.shiftKey && send()}
placeholder="Ask for a component..."
style={{ flex: 1, background: '#1a1a1a', border: '1px solid rgba(255,255,255,0.08)', color: '#F5F5F0', padding: '10px 14px', borderRadius: 10, fontSize: 14, outline: 'none' }}
/>
<button onClick={send} disabled={!input.trim() || loading} style={{
background: input.trim() ? '#C9A84C' : 'rgba(255,255,255,0.06)',
color: input.trim() ? '#0A0A0A' : '#555', border: 'none',
padding: '10px 16px', borderRadius: 10, cursor: 'pointer', fontWeight: 700, fontSize: 14,
}}>↑</button>
</div>
<style>{`@keyframes blink { 0%,100% { opacity: 1 } 50% { opacity: 0 } }`}</style>
</div>
)
}Component info
CategoryAI-Specific
Frameworkreact
TierFREE
Views0
Copies0
About
Full AI chat interface with streaming simulation, message bubbles, and input area
More from AI-Specific
'use client'
import { useState } from 'react'
const TEMPLATES = [
{ id: 'role', label: 'System role', color: '#6366f1', content: 'You are a {role} expert who {expertise}.' },
{ id: 'task', label: 'Task', color: '#C9A84C', content: 'Your task is PromptBuilder
AI-Specific
import React, { useState, useEffect } from 'react';
interface ChatBubbleProps {
message: string;
isAI: boolean;
}
const ChatBubble: React.FC<ChatBubbleProps> = ({ message, isAI }) => {
const [isTyping, setIsTyping] = useState(false);
const ChatBubble
AI-Specific
import React, { useState, useEffect } from 'react';
interface Props {
text: string;
speed: number;
}
const StreamingText: React.FC<Props> = ({ text, speed }) => {
const [displayedText, setDisplayedText] = useState('');
const [tokens, setTokStreamingText
AI-Specific