Files
codeg/src/components/message/message-bubble.tsx
2026-03-06 22:56:13 +08:00

61 lines
1.7 KiB
TypeScript

"use client"
import { memo } from "react"
import { formatDistanceToNow } from "date-fns"
import { User, Bot, Terminal, Cpu } from "lucide-react"
import { cn } from "@/lib/utils"
import { ContentPartsRenderer } from "./content-parts-renderer"
import type { AdaptedMessage } from "@/lib/adapters/ai-elements-adapter"
interface MessageBubbleProps {
message: AdaptedMessage
}
function RoleIcon({ role }: { role: string }) {
switch (role) {
case "user":
return <User className="h-4 w-4" />
case "assistant":
return <Bot className="h-4 w-4" />
case "system":
return <Cpu className="h-4 w-4" />
case "tool":
return <Terminal className="h-4 w-4" />
default:
return <Bot className="h-4 w-4" />
}
}
export const MessageBubble = memo(function MessageBubble({
message,
}: MessageBubbleProps) {
const isUser = message.role === "user"
const timeAgo = formatDistanceToNow(new Date(message.timestamp), {
addSuffix: true,
})
return (
<div className={cn("flex gap-3 px-4 py-3", isUser ? "bg-muted/30" : "")}>
<div
className={cn(
"w-7 h-7 rounded-full flex items-center justify-center shrink-0 mt-0.5",
isUser
? "bg-primary text-primary-foreground"
: "bg-secondary text-secondary-foreground"
)}
>
<RoleIcon role={message.role} />
</div>
<div className="flex-1 min-w-0 space-y-2">
<div className="flex items-center gap-2">
<span className="text-xs font-medium capitalize">{message.role}</span>
<span className="text-xs text-muted-foreground">{timeAgo}</span>
</div>
<ContentPartsRenderer parts={message.content} role={message.role} />
</div>
</div>
)
})