82 lines
3.0 KiB
TypeScript
82 lines
3.0 KiB
TypeScript
import { useState } from 'react'
|
|
import { User, Bot, Eye, EyeOff, Volume2 } from 'lucide-react'
|
|
import { ChatMessage as ChatMessageType } from '../stores/chatStore'
|
|
import { MessageContent } from './MessageContent'
|
|
import { TTSControls } from './TTSControls'
|
|
import { useSettingsStore } from '../stores/settingsStore'
|
|
import clsx from 'clsx'
|
|
|
|
interface ChatMessageProps {
|
|
message: ChatMessageType
|
|
}
|
|
|
|
export function ChatMessage({ message }: ChatMessageProps) {
|
|
const isUser = message.role === 'user'
|
|
const { ttsConversationMode } = useSettingsStore()
|
|
const [isTextVisible, setIsTextVisible] = useState(!ttsConversationMode)
|
|
|
|
return (
|
|
<div
|
|
className={clsx(
|
|
'flex gap-3 p-4 rounded-lg',
|
|
isUser
|
|
? 'bg-blue-50 dark:bg-blue-900/20 ml-8'
|
|
: 'bg-gray-50 dark:bg-gray-800/50 mr-8'
|
|
)}
|
|
>
|
|
<div
|
|
className={clsx(
|
|
'w-8 h-8 rounded-full flex items-center justify-center flex-shrink-0',
|
|
isUser
|
|
? 'bg-blue-500 text-white'
|
|
: 'bg-gradient-to-br from-purple-500 to-indigo-600 text-white'
|
|
)}
|
|
>
|
|
{isUser ? <User className="w-5 h-5" /> : <Bot className="w-5 h-5" />}
|
|
</div>
|
|
<div className="flex-1 min-w-0">
|
|
<div className="flex items-center gap-2 mb-1">
|
|
<span className="font-semibold text-gray-800 dark:text-white text-sm">
|
|
{isUser ? 'You' : 'EVE'}
|
|
</span>
|
|
<span className="text-xs text-gray-500 dark:text-gray-400">
|
|
{new Date(message.timestamp).toLocaleTimeString()}
|
|
</span>
|
|
</div>
|
|
<div className="text-gray-700 dark:text-gray-200">
|
|
{isUser ? (
|
|
// User messages: simple pre-wrap for plain text
|
|
<div className="whitespace-pre-wrap break-words">{message.content}</div>
|
|
) : (
|
|
// Assistant messages: full markdown rendering
|
|
<>
|
|
{ttsConversationMode && (
|
|
<div className="mb-2 flex items-center gap-2">
|
|
<button
|
|
onClick={() => setIsTextVisible(!isTextVisible)}
|
|
className="flex items-center gap-1 px-2 py-1 text-xs bg-purple-500/20 hover:bg-purple-500/30
|
|
text-purple-700 dark:text-purple-300 rounded-md transition-colors"
|
|
>
|
|
{isTextVisible ? <EyeOff className="w-3 h-3" /> : <Eye className="w-3 h-3" />}
|
|
{isTextVisible ? 'Hide Text' : 'Show Text'}
|
|
</button>
|
|
<div className="flex items-center gap-1 text-xs text-purple-600 dark:text-purple-400">
|
|
<Volume2 className="w-3 h-3" />
|
|
<span>Audio Mode</span>
|
|
</div>
|
|
</div>
|
|
)}
|
|
{isTextVisible && <MessageContent content={message.content} />}
|
|
<TTSControls
|
|
text={message.content}
|
|
messageId={message.id}
|
|
autoPlay={ttsConversationMode}
|
|
/>
|
|
</>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|