fix(chat): add shimmer to waiting status

This commit is contained in:
mesalogo
2026-10-11 22:26:50 +08:00
parent ae46cccc20
commit bcb1ebbe62
3 changed files with 52 additions and 5 deletions
+5 -1
View File
@@ -560,17 +560,21 @@ describe('ChatTimeline', () => {
messageStartIndex: 0, ...callbacks, retryContent: '', totalMessageCount: 1
}
const message: Message = {
id: 'status-message', role: 'assistant', content: '已有内容',
id: 'status-message', role: 'assistant', content: '',
createdAt: Date.now(), state: 'streaming'
}
const { rerender } = render(<ChatTimeline {...props} messages={[message]} />)
expect(screen.getByRole('status', { name: '等待后续进展' })).toBeVisible()
expect(screen.getByRole('status', { name: '等待后续进展' })).toHaveClass('message__status--active')
expect(document.querySelector('.message__status-dot--active')).toBeNull()
rerender(<ChatTimeline {...props} messages={[{ ...message, content: '已有内容' }]} />)
expect(screen.getByRole('status', { name: '等待后续进展' })).not.toHaveClass('message__status--active')
const tool = { callId: 'read-1', name: 'read', summary: 'Read file' }
rerender(<ChatTimeline {...props} messages={[{
...message, tools: [{ ...tool, state: 'pending' }]
}]} />)
expect(screen.getByRole('status', { name: '工具待执行:read' })).toBeVisible()
expect(screen.getByRole('status', { name: '工具待执行:read' })).toHaveClass('message__status--active')
rerender(<ChatTimeline {...props} messages={[{
...message, tools: [{ ...tool, state: 'running' }]
}]} />)
+10 -4
View File
@@ -754,6 +754,10 @@ function ChatMessageRowView({
? t('chat.status.waitingForSubagent')
: t('chat.status.waitingForProgress'))
: message.status
const isWaitingForResponse = message.role === 'assistant' &&
message.state === 'streaming' &&
!message.content.trim() &&
!message.blocks?.some(block => block.type === 'text' && block.content.trim())
const roleCaption = message.role !== 'assistant'
? undefined
@@ -1232,9 +1236,11 @@ function ChatMessageRowView({
: 'polite'
}
className={
failed
? 'message__status message__status--error'
: 'message__status'
[
'message__status',
failed && 'message__status--error',
isWaitingForResponse && 'message__status--active'
].filter(Boolean).join(' ')
}
role={
message.state !== 'error' && (message.knowledgeRetrieval || compressionMarkers.length > 0)
@@ -1248,7 +1254,7 @@ function ChatMessageRowView({
aria-hidden="true"
className="message__status-dot"
/>
{statusText}
<span className="message__status-label">{statusText}</span>
</div>
)}
{canRetry && Boolean(retryContent?.trim()) && (
+37
View File
@@ -7343,6 +7343,31 @@ button > svg {
color: var(--danger);
}
.message__status--active {
color: var(--text-muted);
}
.message__status-label {
min-width: 0;
}
.message__status--active .message__status-label {
background: linear-gradient(
105deg,
var(--text-muted) 0%,
var(--text-muted) 38%,
var(--text-primary) 50%,
var(--text-muted) 62%,
var(--text-muted) 100%
);
background-size: 320% 100%;
background-position: 140% 0;
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
animation: message-status-shimmer 2.2s linear infinite;
}
.context-compression-event {
display: flex;
width: 100%;
@@ -18209,6 +18234,18 @@ textarea.field-control {
}
}
@keyframes message-status-shimmer {
0%,
12% {
background-position: 140% 0;
}
88%,
100% {
background-position: -40% 0;
}
}
@keyframes composer-recording-pulse {
0%,
100% {