Spaces:
Running
Running
| import { useState } from 'react' | |
| import ReactMarkdown from 'react-markdown' | |
| export default function MessageBubble({ message }) { | |
| const [copied, setCopied] = useState(false) | |
| const isUser = message.role === 'user' | |
| const isBot = message.role === 'assistant' | |
| const handleCopy = async () => { | |
| try { | |
| await navigator.clipboard.writeText(message.content) | |
| setCopied(true) | |
| setTimeout(() => setCopied(false), 2000) | |
| } catch (_) {} | |
| } | |
| return ( | |
| <div className={`message-row ${isUser ? 'user' : ''}`}> | |
| {/* Avatar */} | |
| {isBot && ( | |
| <div className="message-avatar bot" aria-label="AI ΰ¦Έΰ¦Ήΰ¦ΰ¦Ύΰ¦°ΰ§">ব</div> | |
| )} | |
| {isUser && ( | |
| <div className="message-avatar user" aria-label="বΰ§ΰ¦―বহারΰ¦ΰ¦Ύΰ¦°ΰ§">ΰ¦</div> | |
| )} | |
| <div className="message-bubble-wrapper"> | |
| {/* Bubble */} | |
| {message.loading ? ( | |
| /* ββ Loading State ββββββββββββββββββββββββ */ | |
| <div className="loading-bubble"> | |
| <div className="loading-dot" /> | |
| <div className="loading-dot" /> | |
| <div className="loading-dot" /> | |
| {message.step && ( | |
| <span className="loading-label">{message.step}</span> | |
| )} | |
| </div> | |
| ) : message.isError ? ( | |
| /* ββ Error State ββββββββββββββββββββββββββ */ | |
| <div className="error-bubble">{message.content}</div> | |
| ) : ( | |
| /* ββ Normal Message βββββββββββββββββββββββ */ | |
| <div className={`message-bubble ${isUser ? 'user' : 'bot'}`}> | |
| {isBot ? ( | |
| <ReactMarkdown>{message.content}</ReactMarkdown> | |
| ) : ( | |
| message.isFile ? ( | |
| <span style={{ display: 'flex', alignItems: 'center', gap: 6 }}> | |
| {message.content} | |
| </span> | |
| ) : ( | |
| message.content | |
| ) | |
| )} | |
| </div> | |
| )} | |
| {/* Meta row */} | |
| {!message.loading && message.content && ( | |
| <div className="message-meta"> | |
| <span className="message-time">{message.time}</span> | |
| {isBot && !message.isError && ( | |
| <button className="copy-btn" onClick={handleCopy} id={`copy-${message.id}`}> | |
| {copied ? 'β ΰ¦ΰ¦ͺΰ¦Ώ ΰ¦Ήΰ¦―ΰ¦Όΰ§ΰ¦ΰ§' : 'β§ ΰ¦ΰ¦ͺΰ¦Ώ'} | |
| </button> | |
| )} | |
| </div> | |
| )} | |
| </div> | |
| </div> | |
| ) | |
| } | |