picoclaw/web/frontend/src/components/chat/user-message.tsx
wenjie dcb4b67e00
fix(web): clean up restored chat transcripts and optimize chat UI (#2605)
Filter raw tool messages from session history and avoid duplicate summaries for visible message-tool output. Preserve final assistant replies after tool delivery and add coverage for visible transcript counts.

Also refine the chat UI with collapsible reasoning blocks, send shortcut hints, command-style user messages, stable scroll gutters, and updated i18n strings.
2026-04-21 11:52:58 +08:00

54 lines
1.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { cn } from "@/lib/utils"
import type { ChatAttachment } from "@/store/chat"
interface UserMessageProps {
content: string
attachments?: ChatAttachment[]
}
export function UserMessage({ content, attachments = [] }: UserMessageProps) {
const hasText = content.trim().length > 0
const isCommand = content.trim().startsWith("/")
const imageAttachments = attachments.filter(
(attachment) => attachment.type === "image",
)
return (
<div className="flex w-full flex-col items-end gap-1.5">
{imageAttachments.length > 0 && (
<div className="flex max-w-[70%] flex-wrap justify-end gap-2">
{imageAttachments.map((attachment, index) => (
<img
key={`${attachment.url}-${index}`}
src={attachment.url}
alt={attachment.filename || "Uploaded image"}
className="max-h-72 max-w-full object-cover"
/>
))}
</div>
)}
{hasText && (
<div
className={cn(
"max-w-[70%] wrap-break-word whitespace-pre-wrap",
isCommand
? "rounded-xl border border-zinc-200 bg-transparent px-4 py-3 font-mono text-[14px] text-zinc-800 dark:border-zinc-800/60 dark:bg-[#121212] dark:text-zinc-200 dark:shadow-sm"
: "rounded-2xl rounded-tr-sm bg-violet-500 px-5 py-3 text-[15px] leading-relaxed text-white shadow-sm",
)}
>
{isCommand ? (
<div className="flex items-start gap-2.5">
<span className="font-bold text-emerald-600 select-none dark:text-emerald-400">
</span>
<span className="mt-[1px]">{content}</span>
</div>
) : (
content
)}
</div>
)}
</div>
)
}