diff --git a/CHANGELOG.md b/CHANGELOG.md index f2176cffb..7a8763e17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ - Model: `/model` output now includes auth source location (env/auth.json/models.json). - Docs: clarify auth storage, migration, and OpenAI Codex OAuth onboarding. - Sandbox: copy inbound media into sandbox workspaces so agent tools can read attachments. +- Control UI: show a reading indicator bubble while the assistant is responding. - Status: show runtime (docker/direct) and move shortcuts to `/help`. - Status: show model auth source (api-key/oauth). diff --git a/ui/src/styles/components.css b/ui/src/styles/components.css index 78a14c295..7c7c4df03 100644 --- a/ui/src/styles/components.css +++ b/ui/src/styles/components.css @@ -595,6 +595,56 @@ } } +.chat-bubble.chat-reading-indicator { + width: fit-content; + padding: 10px 14px; +} + +.chat-reading-indicator__dots { + display: inline-flex; + align-items: center; + gap: 6px; + height: 10px; +} + +.chat-reading-indicator__dots > span { + width: 6px; + height: 6px; + border-radius: 999px; + background: var(--chat-text); + opacity: 0.55; + transform: translateY(0); + animation: chatReadingDot 1.1s ease-in-out infinite; +} + +.chat-reading-indicator__dots > span:nth-child(2) { + animation-delay: 0.12s; +} + +.chat-reading-indicator__dots > span:nth-child(3) { + animation-delay: 0.24s; +} + +@keyframes chatReadingDot { + 0%, + 80%, + 100% { + opacity: 0.45; + transform: translateY(0); + } + 40% { + opacity: 0.95; + transform: translateY(-2px); + } +} + +@media (prefers-reduced-motion: reduce) { + .chat-reading-indicator__dots > span { + animation: none; + opacity: 0.75; + } +} + .chat-text { overflow-wrap: anywhere; word-break: break-word; diff --git a/ui/src/ui/views/chat.ts b/ui/src/ui/views/chat.ts index 90660d319..f78a67a8f 100644 --- a/ui/src/ui/views/chat.ts +++ b/ui/src/ui/views/chat.ts @@ -78,15 +78,17 @@ export function renderChat(props: ChatProps) {