feat(desktop): add collapsible queued message panel
This commit is contained in:
parent
3c1fa3f349
commit
37a68fc5c0
1 changed files with 54 additions and 25 deletions
|
|
@ -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>
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue