Skip to content

Commit e708572

Browse files
authored
Merge pull request #655 from miurla/feature/animated-loading-logo
feat: add animated loading logo with eye movement
2 parents c621912 + 5498b96 commit e708572

File tree

4 files changed

+65
-26
lines changed

4 files changed

+65
-26
lines changed

app/globals.css

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,21 @@
232232
opacity: 1;
233233
}
234234
}
235+
@keyframes lookAround {
236+
0%,
237+
100% {
238+
transform: translateX(0);
239+
}
240+
25% {
241+
transform: translateX(10px);
242+
}
243+
50% {
244+
transform: translateX(0);
245+
}
246+
75% {
247+
transform: translateX(-10px);
248+
}
249+
}
235250
}
236251

237252
@utility container {

components/answer-section.tsx

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import type {
1212
} from '@/lib/types/ai'
1313

1414
import { CollapsibleMessage } from './collapsible-message'
15-
import { DefaultSkeleton } from './default-skeleton'
1615
import { MarkdownMessage } from './message'
1716
import { MessageActions } from './message-actions'
1817

@@ -53,25 +52,6 @@ export function AnswerSection({
5352
return Promise.resolve(undefined)
5453
}
5554

56-
const message = content ? (
57-
<div className="flex flex-col gap-1">
58-
<MarkdownMessage message={content} citationMaps={citationMaps} />
59-
{showActions && (
60-
<MessageActions
61-
message={content} // Keep original message content for copy
62-
messageId={messageId}
63-
traceId={metadata?.traceId}
64-
feedbackScore={metadata?.feedbackScore}
65-
chatId={chatId}
66-
enableShare={enableShare}
67-
reload={handleReload}
68-
status={status}
69-
/>
70-
)}
71-
</div>
72-
) : (
73-
<DefaultSkeleton />
74-
)
7555
return (
7656
<CollapsibleMessage
7757
role="assistant"
@@ -81,7 +61,23 @@ export function AnswerSection({
8161
showBorder={false}
8262
showIcon={false}
8363
>
84-
{message}
64+
{content && (
65+
<div className="flex flex-col gap-1">
66+
<MarkdownMessage message={content} citationMaps={citationMaps} />
67+
{showActions && (
68+
<MessageActions
69+
message={content} // Keep original message content for copy
70+
messageId={messageId}
71+
traceId={metadata?.traceId}
72+
feedbackScore={metadata?.feedbackScore}
73+
chatId={chatId}
74+
enableShare={enableShare}
75+
reload={handleReload}
76+
status={status}
77+
/>
78+
)}
79+
</div>
80+
)}
8581
</CollapsibleMessage>
8682
)
8783
}

components/chat-messages.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { UseChatHelpers } from '@ai-sdk/react'
77
import type { UIDataTypes, UIMessage, UITools } from '@/lib/types/ai'
88
import { cn } from '@/lib/utils'
99

10+
import { AnimatedLogo } from './ui/animated-logo'
1011
import { ChatError } from './chat-error'
1112
import { DefaultSkeleton } from './default-skeleton'
1213
import { RenderMessage } from './render-message'
@@ -69,10 +70,7 @@ export function ChatMessages({
6970
if (!sections.length) return null
7071

7172
// Check if loading indicator should be shown
72-
const showLoading =
73-
isLoading &&
74-
sections.length > 0 &&
75-
sections[sections.length - 1].assistantMessages.length === 0
73+
const showLoading = status === 'submitted' || status === 'streaming'
7674

7775
// Helper function to get tool count with caching
7876
const getToolCount = (message?: UIMessage): number => {
@@ -180,7 +178,6 @@ export function ChatMessages({
180178
onUpdateMessage={onUpdateMessage}
181179
reload={reload}
182180
/>
183-
{showLoading && <DefaultSkeleton />}
184181
</div>
185182

186183
{/* Assistant messages */}
@@ -202,6 +199,12 @@ export function ChatMessages({
202199
/>
203200
</div>
204201
))}
202+
{/* Show loading after assistant messages */}
203+
{showLoading && sectionIndex === sections.length - 1 && (
204+
<div className="flex justify-start py-4">
205+
<AnimatedLogo className="h-10 w-10" />
206+
</div>
207+
)}
205208
{sectionIndex === sections.length - 1 && (
206209
<ChatError error={error} />
207210
)}

components/ui/animated-logo.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
'use client'
2+
3+
import { cn } from '@/lib/utils'
4+
5+
export function AnimatedLogo({
6+
className,
7+
...props
8+
}: React.ComponentProps<'svg'>) {
9+
return (
10+
<svg
11+
fill="currentColor"
12+
viewBox="0 0 256 256"
13+
role="img"
14+
xmlns="http://www.w3.org/2000/svg"
15+
className={cn('h-8 w-8', className)}
16+
{...props}
17+
>
18+
<circle cx="128" cy="128" r="128" fill="black"></circle>
19+
<g className="animate-[lookAround_2s_ease-in-out_infinite] origin-center">
20+
<circle cx="102" cy="128" r="18" fill="white"></circle>
21+
<circle cx="154" cy="128" r="18" fill="white"></circle>
22+
</g>
23+
</svg>
24+
)
25+
}

0 commit comments

Comments
 (0)