Files
video-create/web/client/src/components/chat/ChatMessage.tsx

79 lines
2.8 KiB
TypeScript
Raw Normal View History

import { cn } from '@/lib/utils';
import { renderMarkdown } from '@/lib/markdown';
import { RefreshCw, ArrowRight, Quote } from 'lucide-react';
import type { Message } from '@/types';
interface Props {
message: Message;
onRegenerate?: (msgId: string) => void;
onContinue?: (msgId: string) => void;
onQuote?: (content: string) => void;
}
export function ChatMessage({ message, onRegenerate, onContinue, onQuote }: Props) {
const isUser = message.role === 'user';
const isEmpty = !message.content;
return (
<div className={cn('mb-4 flex group', isUser ? 'justify-end' : 'justify-start')}>
<div className="max-w-[80%]">
<div
className={cn(
'rounded-xl px-4 py-2.5',
isUser
? 'bg-indigo-600 text-white'
: 'bg-white text-zinc-700 border border-zinc-200 shadow-sm'
)}
>
{isEmpty ? (
<span className="text-zinc-400 italic text-xs">...</span>
) : isUser ? (
<p className="text-sm leading-relaxed whitespace-pre-wrap">{message.content}</p>
) : (
<div
className="markdown-body text-sm leading-relaxed"
dangerouslySetInnerHTML={{ __html: renderMarkdown(message.content) }}
/>
)}
</div>
{/* Action buttons - only for assistant messages */}
{!isUser && !isEmpty && (
<div className="flex gap-1 mt-1 opacity-0 group-hover:opacity-100 transition-opacity">
{onQuote && (
<button
onClick={() => onQuote(message.content)}
className="flex items-center gap-0.5 px-1.5 py-0.5 rounded text-[10px] text-zinc-400 hover:text-zinc-600 hover:bg-zinc-100 transition-colors"
title="引用"
>
<Quote size={10} />
</button>
)}
{onRegenerate && (
<button
onClick={() => onRegenerate(message.id)}
className="flex items-center gap-0.5 px-1.5 py-0.5 rounded text-[10px] text-zinc-400 hover:text-zinc-600 hover:bg-zinc-100 transition-colors"
title="重新生成"
>
<RefreshCw size={10} />
</button>
)}
{onContinue && (
<button
onClick={() => onContinue(message.id)}
className="flex items-center gap-0.5 px-1.5 py-0.5 rounded text-[10px] text-zinc-400 hover:text-zinc-600 hover:bg-zinc-100 transition-colors"
title="继续"
>
<ArrowRight size={10} />
</button>
)}
</div>
)}
</div>
</div>
);
}