Skip to content

Commit fe78d62

Browse files
feat: ARIA UI overhaul — thinking indicator, session summary dialog, message polish
- Add "Thinking…" animation immediately after user sends a message (fixes perceived freeze while waiting for first token) - Add "Running…" label to between-tool-call indicator - Replace session-close toast with a full SessionSummaryDialog showing commands run, stats, and ARIA's last response - Fix race condition and stale-closure bug that prevented summary dialog from appearing - Polish ARIA panel: gradient header, larger glowing empty-state icon, capability chips with emojis, focus glow on input box, solid send button, modern quick-suggestion chips - Polish message bubbles: rounded-2xl, subtle border, gradient avatar with ring
1 parent 55dd850 commit fe78d62

4 files changed

Lines changed: 233 additions & 49 deletions

File tree

src/renderer/src/components/ai/AiMessage.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,13 @@ export function AiMessage({ message, approval, blacklist, onApproveCommand, onBl
4242
}
4343

4444
return (
45-
<div className={cn('flex gap-2.5 px-3 py-2 group', (isUser || isRtl) && !isProactive ? 'flex-row-reverse' : '')}>
45+
<div className={cn('flex gap-2.5 px-3 py-1.5 group', (isUser || isRtl) && !isProactive ? 'flex-row-reverse' : '')}>
4646
{/* Avatar */}
4747
<div className={cn(
4848
'w-6 h-6 rounded-full shrink-0 flex items-center justify-center mt-1',
49-
isUser ? 'bg-primary/20 text-primary'
50-
: isProactive ? 'bg-muted text-muted-foreground'
51-
: 'bg-primary/15 text-primary'
49+
isUser ? 'bg-primary/25 text-primary ring-1 ring-primary/20'
50+
: isProactive ? 'bg-muted/80 text-muted-foreground'
51+
: 'bg-gradient-to-br from-primary/30 to-primary/10 text-primary ring-1 ring-primary/15'
5252
)}>
5353
{isUser ? <User className="w-3 h-3" />
5454
: isProactive ? <Eye className="w-3 h-3" />
@@ -59,12 +59,12 @@ export function AiMessage({ message, approval, blacklist, onApproveCommand, onBl
5959
<div
6060
dir={dir}
6161
className={cn(
62-
'flex-1 min-w-0 rounded-xl px-3 py-2.5 text-sm leading-relaxed relative',
62+
'flex-1 min-w-0 rounded-2xl px-3 py-2.5 text-sm leading-relaxed relative',
6363
isUser
64-
? 'bg-primary/15 text-foreground ml-10'
64+
? 'bg-primary/12 text-foreground ml-8 border border-primary/15'
6565
: isProactive
66-
? 'bg-muted/30 text-muted-foreground text-xs italic'
67-
: 'bg-card/60 text-foreground'
66+
? 'bg-muted/20 text-muted-foreground text-xs italic border border-border/30'
67+
: 'bg-card/50 text-foreground border border-border/40'
6868
)}
6969
>
7070
{isProactive && (

src/renderer/src/components/ai/AiPanel.tsx

Lines changed: 65 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -395,10 +395,11 @@ export function AiPanel({ activeSession, splitSession, allSessions, getTerminalC
395395
return (
396396
<div className="flex flex-col h-full min-h-0 border-l border-border bg-background">
397397
{/* Header */}
398-
<div className="flex items-center gap-2 px-3 py-2.5 border-b border-border shrink-0">
398+
<div className="flex items-center gap-2 px-3 py-2.5 border-b border-border/60 shrink-0 bg-gradient-to-r from-primary/5 via-transparent to-transparent">
399399
{/* ARIA logo */}
400-
<div className="flex items-center justify-center w-6 h-6 rounded-lg bg-gradient-to-br from-primary/30 to-primary/10 shrink-0">
400+
<div className="relative flex items-center justify-center w-7 h-7 rounded-lg bg-gradient-to-br from-primary/40 to-primary/10 shrink-0 shadow-sm">
401401
<Sparkles className="w-3.5 h-3.5 text-primary" />
402+
<span className="absolute inset-0 rounded-lg ring-1 ring-primary/20" />
402403
</div>
403404
<span className="text-sm font-bold text-foreground tracking-tight">ARIA</span>
404405

@@ -489,12 +490,15 @@ export function AiPanel({ activeSession, splitSession, allSessions, getTerminalC
489490
{/* No session notice */}
490491
{!activeSession && (
491492
<div className="flex flex-col items-center justify-center flex-1 gap-4 p-6 text-center">
492-
<div className="flex items-center justify-center w-12 h-12 rounded-2xl bg-muted/50 border border-border">
493-
<AlertCircle className="w-5 h-5 text-muted-foreground/50" />
493+
<div className="relative">
494+
<div className="absolute inset-0 rounded-2xl bg-muted/30 blur-xl scale-150" />
495+
<div className="relative flex items-center justify-center w-12 h-12 rounded-2xl bg-muted/60 border border-border/60">
496+
<AlertCircle className="w-5 h-5 text-muted-foreground/40" />
497+
</div>
494498
</div>
495-
<div className="space-y-1">
496-
<p className="text-sm font-medium text-foreground/70">No active session</p>
497-
<p className="text-xs text-muted-foreground/60 max-w-[180px] leading-relaxed">
499+
<div className="space-y-1.5">
500+
<p className="text-sm font-semibold text-foreground/60">No active session</p>
501+
<p className="text-xs text-muted-foreground/50 max-w-[170px] leading-relaxed">
498502
Connect to a device to start chatting with ARIA
499503
</p>
500504
</div>
@@ -509,28 +513,33 @@ export function AiPanel({ activeSession, splitSession, allSessions, getTerminalC
509513
<div className="flex flex-col items-center justify-center h-full gap-5 px-5 py-8 text-center">
510514
{/* Glowing icon */}
511515
<div className="relative">
512-
<div className="absolute inset-0 rounded-2xl bg-primary/20 blur-xl scale-150" />
513-
<div className="relative flex items-center justify-center w-14 h-14 rounded-2xl bg-gradient-to-br from-primary/25 to-primary/5 border border-primary/20">
514-
<Sparkles className="w-6 h-6 text-primary" />
516+
<div className="absolute inset-0 rounded-3xl bg-primary/25 blur-2xl scale-[1.8]" />
517+
<div className="relative flex items-center justify-center w-16 h-16 rounded-3xl bg-gradient-to-br from-primary/30 to-primary/5 border border-primary/25 shadow-lg shadow-primary/10">
518+
<Sparkles className="w-7 h-7 text-primary drop-shadow-[0_0_8px_rgba(139,92,246,0.6)]" />
515519
</div>
516520
</div>
517521

518522
{/* Heading */}
519-
<div className="space-y-1.5">
520-
<p className="text-sm font-semibold text-foreground">
523+
<div className="space-y-2">
524+
<p className="text-base font-bold text-foreground tracking-tight">
521525
Hi, I'm ARIA
522526
</p>
523-
<p className="text-xs text-muted-foreground/70 leading-relaxed max-w-[200px]">
524-
Your AI network engineer.<br/>
525-
Connected to <span className="font-semibold text-foreground/60">{activeSession.connection.name}</span>.
527+
<p className="text-xs text-muted-foreground/60 leading-relaxed max-w-[190px]">
528+
AI agent for <span className="font-semibold text-foreground/70">{activeSession.connection.name}</span>.
529+
Describe a problem and I'll investigate it.
526530
</p>
527531
</div>
528532

529533
{/* Capability chips */}
530534
<div className="flex flex-wrap gap-1.5 justify-center max-w-[220px]">
531-
{['Diagnose issues', 'Read configs', 'Run commands', 'Plan changes'].map(cap => (
532-
<span key={cap} className="text-[11px] px-2 py-1 rounded-full bg-primary/8 border border-primary/15 text-primary/70 font-medium">
533-
{cap}
535+
{[
536+
{ label: 'Diagnose', icon: '🔍' },
537+
{ label: 'Configs', icon: '📋' },
538+
{ label: 'Commands', icon: '⚡' },
539+
{ label: 'Plan', icon: '🗺️' },
540+
].map(cap => (
541+
<span key={cap.label} className="text-[11px] px-2.5 py-1 rounded-full bg-primary/8 border border-primary/15 text-primary/75 font-medium flex items-center gap-1">
542+
<span>{cap.icon}</span>{cap.label}
534543
</span>
535544
))}
536545
</div>
@@ -548,16 +557,37 @@ export function AiPanel({ activeSession, splitSession, allSessions, getTerminalC
548557
/>
549558
))}
550559

551-
{/* Thinking indicator — shown when agent is active but not streaming text */}
560+
{/* Waiting for first token — last message is user and we're streaming */}
561+
{(() => {
562+
const lastMsg = aiMessages[aiMessages.length - 1]
563+
const isWaitingForFirstToken = aiStreaming && (lastMsg?.role === 'user' || lastMsg?.role === 'auto')
564+
if (!isWaitingForFirstToken) return null
565+
return (
566+
<div className="flex items-center gap-2.5 px-3 py-2">
567+
<div className="w-7 h-7 rounded-full bg-gradient-to-br from-primary/30 to-primary/10 border border-primary/20 flex items-center justify-center shrink-0">
568+
<Sparkles className="w-3.5 h-3.5 text-primary animate-spin" style={{ animationDuration: '2s' }} />
569+
</div>
570+
<div className="flex items-center gap-2 px-3 py-2 rounded-2xl bg-card/80 border border-border/40 shadow-sm">
571+
<span className="w-1.5 h-1.5 rounded-full bg-primary animate-bounce" style={{ animationDelay: '0ms' }} />
572+
<span className="w-1.5 h-1.5 rounded-full bg-primary animate-bounce" style={{ animationDelay: '120ms' }} />
573+
<span className="w-1.5 h-1.5 rounded-full bg-primary animate-bounce" style={{ animationDelay: '240ms' }} />
574+
<span className="text-[11px] text-muted-foreground/60 font-medium ml-1">Thinking…</span>
575+
</div>
576+
</div>
577+
)
578+
})()}
579+
580+
{/* Thinking indicator — between tool calls (agent active, not streaming) */}
552581
{aiAgentActive && !aiStreaming && (
553582
<div className="flex items-center gap-2.5 px-3 py-2">
554-
<div className="w-6 h-6 rounded-full bg-primary/15 flex items-center justify-center shrink-0">
555-
<Sparkles className="w-3 h-3 text-primary" />
583+
<div className="w-7 h-7 rounded-full bg-gradient-to-br from-primary/30 to-primary/10 border border-primary/20 flex items-center justify-center shrink-0">
584+
<Sparkles className="w-3.5 h-3.5 text-primary animate-pulse" />
556585
</div>
557-
<div className="flex items-center gap-1 px-3 py-2 rounded-xl bg-card/60">
558-
<span className="w-1.5 h-1.5 rounded-full bg-primary/60 animate-bounce" style={{ animationDelay: '0ms' }} />
559-
<span className="w-1.5 h-1.5 rounded-full bg-primary/60 animate-bounce" style={{ animationDelay: '150ms' }} />
560-
<span className="w-1.5 h-1.5 rounded-full bg-primary/60 animate-bounce" style={{ animationDelay: '300ms' }} />
586+
<div className="flex items-center gap-1.5 px-3 py-2 rounded-2xl bg-card/80 border border-border/40 shadow-sm">
587+
<span className="w-1.5 h-1.5 rounded-full bg-primary animate-bounce" style={{ animationDelay: '0ms' }} />
588+
<span className="w-1.5 h-1.5 rounded-full bg-primary animate-bounce" style={{ animationDelay: '120ms' }} />
589+
<span className="w-1.5 h-1.5 rounded-full bg-primary animate-bounce" style={{ animationDelay: '240ms' }} />
590+
<span className="text-[11px] text-muted-foreground/60 font-medium ml-1">Running…</span>
561591
</div>
562592
</div>
563593
)}
@@ -604,17 +634,19 @@ export function AiPanel({ activeSession, splitSession, allSessions, getTerminalC
604634
}}
605635
title={historySet.has(cmd) ? 'From your history' : undefined}
606636
className={cn(
607-
'shrink-0 text-[11px] px-3 py-1.5 rounded-full flex items-center gap-1',
637+
'shrink-0 text-[11px] px-2.5 py-1 rounded-lg flex items-center gap-1.5',
608638
historySet.has(cmd)
609-
? 'bg-amber-500/8 border border-amber-500/20 text-amber-600 dark:text-amber-400 hover:bg-amber-500/15 hover:border-amber-500/35'
610-
: 'bg-primary/6 border border-primary/15 text-primary/70 hover:bg-primary/12 hover:border-primary/30 hover:text-primary',
639+
? 'bg-amber-500/10 border border-amber-500/25 text-amber-500 hover:bg-amber-500/18 hover:border-amber-500/40'
640+
: 'bg-muted/60 border border-border/60 text-muted-foreground hover:bg-primary/10 hover:border-primary/25 hover:text-primary',
611641
'transition-all whitespace-nowrap font-medium'
612642
)}
613643
>
614-
{historySet.has(cmd) && (
615-
<svg className="w-2.5 h-2.5 shrink-0 opacity-70" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
644+
{historySet.has(cmd) ? (
645+
<svg className="w-2.5 h-2.5 shrink-0" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
616646
<circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/>
617647
</svg>
648+
) : (
649+
<Sparkles className="w-2.5 h-2.5 shrink-0 opacity-50" />
618650
)}
619651
{cmd}
620652
</button>
@@ -625,7 +657,7 @@ export function AiPanel({ activeSession, splitSession, allSessions, getTerminalC
625657
})()}
626658

627659
{/* Input box */}
628-
<div className="border-t border-border px-3 pt-2 pb-2 shrink-0">
660+
<div className="border-t border-border/60 px-3 pt-2 pb-2 shrink-0 bg-gradient-to-t from-background to-transparent">
629661
{!licenseValid ? (
630662
/* ── No License Gate ── */
631663
<div className="flex flex-col items-center gap-3 py-4 px-3 rounded-xl border border-red-500/20 bg-red-500/5">
@@ -648,7 +680,7 @@ export function AiPanel({ activeSession, splitSession, allSessions, getTerminalC
648680
</div>
649681
) : (
650682
<>
651-
<div className="bg-card/60 border border-border rounded-xl">
683+
<div className="bg-card/70 border border-border/70 rounded-xl shadow-sm transition-all focus-within:border-primary/40 focus-within:shadow-[0_0_0_3px_rgba(139,92,246,0.08)]">
652684
{/* Text area row */}
653685
<div className="flex items-end gap-2 px-3 pt-2.5 pb-1">
654686
<textarea
@@ -740,7 +772,7 @@ export function AiPanel({ activeSession, splitSession, allSessions, getTerminalC
740772
onClick={handleSubmit}
741773
disabled={!input.trim()}
742774
title="Send (Enter)"
743-
className="shrink-0 p-1.5 rounded-lg bg-primary/20 text-primary hover:bg-primary/30 disabled:opacity-30 disabled:cursor-not-allowed transition-colors"
775+
className="shrink-0 p-1.5 rounded-lg bg-primary text-primary-foreground hover:bg-primary/85 disabled:opacity-25 disabled:cursor-not-allowed transition-all shadow-sm shadow-primary/20"
744776
>
745777
<Send className="w-3.5 h-3.5" />
746778
</button>

0 commit comments

Comments
 (0)