feat(desktop): add collapsible queued message panel

This commit is contained in:
Jiayuan Zhang 2026-02-17 01:34:59 +08:00
parent 3c1fa3f349
commit 37a68fc5c0

View file

@ -1,3 +1,4 @@
import { useMemo, useState } from 'react'
import type { QueuedLocalMessage } from '../hooks/use-local-chat'
interface QueuedMessageBarProps {
@ -8,45 +9,73 @@ interface QueuedMessageBarProps {
}
export function QueuedMessageBar({ messages, isRunning, onRemove, onClear }: QueuedMessageBarProps) {
const [expanded, setExpanded] = useState(false)
if (messages.length === 0) return null
const statusText = isRunning
? 'Agent is running. Queued messages will send automatically.'
: 'Queued messages are being sent.'
const firstMessagePreview = useMemo(() => {
const text = messages[0]?.text ?? ''
if (text.length <= 120) return text
return `${text.slice(0, 120)}...`
}, [messages])
return (
<div className="container px-4 pb-2">
<div className="rounded-lg border bg-muted/40">
<div className="flex items-center justify-between px-3 pt-2 pb-1">
<span className="text-xs font-medium text-foreground/80">
<div className="flex items-center justify-between gap-2 px-3 pt-2 pb-1">
<div className="text-xs font-medium text-foreground/80">
{messages.length} queued message{messages.length > 1 ? 's' : ''}
</span>
<button
onClick={onClear}
className="text-xs text-muted-foreground hover:text-foreground transition-colors"
>
Clear
</button>
</div>
<div className="flex items-center gap-2">
{messages.length > 1 && (
<button
onClick={() => setExpanded((prev) => !prev)}
className="text-xs text-muted-foreground hover:text-foreground transition-colors"
>
{expanded ? 'Collapse' : 'Expand'}
</button>
)}
<button
onClick={onClear}
className="text-xs text-muted-foreground hover:text-foreground transition-colors"
>
Clear
</button>
</div>
</div>
<div className="px-3 pb-2 text-xs text-muted-foreground">{statusText}</div>
<div className="px-2 pb-2 space-y-1">
{messages.slice(0, 3).map((item) => (
<div key={item.id} className="flex items-start justify-between gap-2 rounded-md bg-background/70 px-2 py-1.5">
<div className="text-xs text-foreground/85 break-all">{item.text}</div>
<button
onClick={() => onRemove(item.id)}
className="shrink-0 text-xs text-muted-foreground hover:text-foreground transition-colors"
>
Remove
</button>
{expanded ? (
<div className="px-2 pb-2">
<div className="max-h-40 space-y-1 overflow-y-auto pr-1">
{messages.map((item) => (
<div key={item.id} className="flex items-start justify-between gap-2 rounded-md bg-background/70 px-2 py-1.5">
<div className="text-xs text-foreground/85 break-all">{item.text}</div>
<button
onClick={() => onRemove(item.id)}
className="shrink-0 text-xs text-muted-foreground hover:text-foreground transition-colors"
>
Remove
</button>
</div>
))}
</div>
))}
{messages.length > 3 && (
<div className="px-1 text-xs text-muted-foreground">
+{messages.length - 3} more
</div>
) : (
<div className="px-2 pb-2 space-y-1">
<div className="rounded-md bg-background/70 px-2 py-1.5 text-xs text-foreground/85 break-all">
{firstMessagePreview}
</div>
)}
</div>
{messages.length > 1 && (
<div className="px-1 text-xs text-muted-foreground">
+{messages.length - 1} more
</div>
)}
</div>
)}
</div>
</div>
)