fix(chat): animate app logo while thinking
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
---
|
||||
date: 2026-11-05
|
||||
pr: pending
|
||||
feature: Animated application logo while thinking
|
||||
impact: The thinking indicator uses the application logo with a gentle animation, disabled when reduced motion is requested. Chat behavior is unchanged.
|
||||
---
|
||||
|
||||
The thinking indicator no longer uses the old character GIF. The new animation
|
||||
is applied to the existing application logo without changing chat events.
|
||||
@@ -21,7 +21,6 @@ import VirtualMessageList from "./VirtualMessageList.vue";
|
||||
import MessageItem from "./MessageItem.vue";
|
||||
import { groupRunMessages } from "./groupRunMessages";
|
||||
import { LIVE_CHAT_MAX_LOADED_MESSAGES, useChatStore, type Message } from "@/stores/hermes/chat";
|
||||
import thinkingImage from "@/assets/thinking.gif";
|
||||
import { useToolTraceVisibility } from "@/composables/useToolTraceVisibility";
|
||||
|
||||
const chatStore = useChatStore();
|
||||
@@ -527,7 +526,7 @@ defineExpose({
|
||||
<div v-if="isThinkingIndicatorVisible" class="streaming-indicator">
|
||||
<div class="thinking-status">
|
||||
<img
|
||||
:src="thinkingImage"
|
||||
src="/app-logo.png"
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
class="thinking-avatar"
|
||||
@@ -1479,10 +1478,19 @@ defineExpose({
|
||||
.thinking-avatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: $radius-md;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
flex-shrink: 0;
|
||||
filter: brightness(1.18) contrast(1.08) saturate(1.08);
|
||||
animation: thinking-avatar-breathe 2.4s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes thinking-avatar-breathe {
|
||||
0%, 100% { transform: translateY(0) scale(1); filter: drop-shadow(0 0 2px rgba(var(--accent-primary-rgb), 0.12)); }
|
||||
50% { transform: translateY(-2px) scale(1.06); filter: drop-shadow(0 0 7px rgba(var(--accent-primary-rgb), 0.4)); }
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.thinking-status .thinking-avatar, .thinking-status .thinking-status-label { animation: none; }
|
||||
}
|
||||
|
||||
.thinking-status-copy {
|
||||
|
||||
@@ -138,6 +138,25 @@ test('groups assistant output across tool calls until the run ends', async ({ pa
|
||||
await expect(page.locator('.run-end')).toHaveText('Run output ended')
|
||||
})
|
||||
|
||||
test('animates the application logo while thinking and respects reduced motion', async ({ page }) => {
|
||||
await authenticate(page, TEST_ACCESS_KEY, 'research')
|
||||
await mockHermesApi(page)
|
||||
await mockChatSocket(page)
|
||||
await page.goto('/#/hermes/chat')
|
||||
await sendChatMessage(page, 'think')
|
||||
const { sessionId } = await waitForRunSessionId(page)
|
||||
await page.evaluate((sid) => {
|
||||
(window as any).__PW_CHAT_SOCKET__.latest.__trigger('run.started', { event: 'run.started', session_id: sid, run_id: 'thinking-logo' })
|
||||
}, sessionId)
|
||||
const avatar = page.locator('.thinking-avatar')
|
||||
await expect(avatar).toBeVisible()
|
||||
await expect(avatar).toHaveAttribute('src', '/app-logo.png')
|
||||
await expect(avatar).toHaveCSS('animation-name', /^thinking-avatar-breathe/)
|
||||
await page.emulateMedia({ reducedMotion: 'reduce' })
|
||||
await expect(avatar).toHaveCSS('animation-name', 'none')
|
||||
await expect(page.locator('.thinking-status-label')).toHaveCSS('animation-name', 'none')
|
||||
})
|
||||
|
||||
test('opens the session model dialog and the session search from the chat header', async ({ page }) => {
|
||||
await authenticate(page, TEST_ACCESS_KEY, 'research')
|
||||
await mockHermesApi(page, { sessions: [sampleSession] })
|
||||
|
||||
Reference in New Issue
Block a user