Skip to content

Commit 44feb3b

Browse files
authored
Rework dynamic icons (AIChatIcon, AISearchIcon) (#3853)
1 parent 6b43773 commit 44feb3b

File tree

1 file changed

+114
-66
lines changed

1 file changed

+114
-66
lines changed

packages/gitbook/src/components/AIChat/AIChatIcon.tsx

Lines changed: 114 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { tcls } from '@/lib/tailwind';
21
import { Icon, IconStyle } from '@gitbook/icons';
32
import type React from 'react';
43

@@ -21,12 +20,18 @@ export function AIChatIcon({
2120
<Icon
2221
icon="sparkle"
2322
{...props}
24-
className={tcls(
25-
className,
26-
(state === 'thinking' || state === 'working') &&
27-
'animate-[spin_2s_infinite_forwards_cubic-bezier(0.16,1,0.3,1)]',
28-
state === 'intro' && 'animate-[spin_2s_forwards_cubic-bezier(0.16,1,0.3,1)]'
29-
)}
23+
className={className}
24+
style={{
25+
animation: {
26+
intro: 'spin 2s forwards cubic-bezier(0.16,1,0.3,1)',
27+
thinking: 'spin 2s infinite forwards cubic-bezier(0.16,1,0.3,1)',
28+
working: 'spin 2s infinite forwards cubic-bezier(0.16,1,0.3,1)',
29+
done: '',
30+
confirm: '',
31+
default: '',
32+
error: '',
33+
}[state],
34+
}}
3035
/>
3136
);
3237
}
@@ -50,28 +55,36 @@ export function AIChatIcon({
5055
<path
5156
d="M12.8916 1.06265C12.921 0.979101 13.0392 0.979127 13.0685 1.06267C13.239 1.5478 13.3439 1.84646 13.516 2.1032C13.6683 2.33042 13.8578 2.53033 14.0766 2.6945C14.3239 2.88 14.6165 3.00068 15.0919 3.19671C15.1761 3.23142 15.1761 3.3506 15.0919 3.38531C14.6165 3.58134 14.3239 3.70203 14.0766 3.88752C13.8578 4.05169 13.6683 4.2516 13.516 4.47882C13.3439 4.73556 13.239 5.03423 13.0685 5.51937C13.0392 5.60291 12.921 5.60292 12.8916 5.51938C12.7212 5.03423 12.6162 4.73557 12.4442 4.47882C12.2919 4.2516 12.1023 4.05169 11.8835 3.88752C11.6363 3.70202 11.3436 3.58134 10.8682 3.38531C10.7841 3.3506 10.7841 3.23141 10.8683 3.1967C11.3436 3.00067 11.6363 2.87999 11.8835 2.6945C12.1023 2.53033 12.2919 2.33042 12.4442 2.1032C12.6162 1.84646 12.7212 1.54779 12.8916 1.06265Z"
5257
stroke="currentColor"
53-
strokeWidth="1.2"
58+
strokeWidth={state === 'intro' ? '1.2' : '1'}
5459
strokeLinejoin="round"
55-
className={tcls(
56-
state === 'intro' &&
57-
'animate-[fadeIn_.5s_.7s_both,spin_2s_1s_forwards_cubic-bezier(.43,1.54,.64,1)]',
58-
(state === 'working' || state === 'thinking') &&
59-
'animate-[fadeIn_.5s_.3s_both,spin_2s_1s_infinite_forwards_cubic-bezier(0.16,1,0.3,1)]',
60-
state === 'done' && 'animate-[fadeOut_.5s_both]',
61-
state === 'confirm' && 'animate-[fadeOut_.5s_both]',
62-
state === 'default' && 'animate-[fadeIn_0s_both]',
63-
state === 'error' && 'hidden'
64-
)}
65-
style={{ transformOrigin: '13px 3.5px' }}
60+
shapeRendering="crispEdges"
61+
className="transition-opacity duration-300"
62+
style={{
63+
animation: {
64+
intro: 'fadeIn .5s .5s backwards, spin 2s .5s forwards cubic-bezier(0.43,1.54,0.64,1)',
65+
thinking: 'spin 2s 1s infinite forwards cubic-bezier(0.16,1,0.3,1)',
66+
working: 'spin 2s 1s infinite forwards cubic-bezier(0.16,1,0.3,1)',
67+
done: '',
68+
confirm: '',
69+
default: '',
70+
error: '',
71+
}[state],
72+
transitionDelay:
73+
state === 'default' || state === 'thinking' ? '.3s' : undefined,
74+
opacity: ['done', 'confirm', 'error'].includes(state) ? 0 : 1,
75+
transformOrigin: '13px 3.5px',
76+
}}
6677
/>
6778

6879
{/* Error */}
6980
<g
7081
clipPath="url(#clip0_153_2034)"
71-
className={tcls(
72-
'text-danger-subtle',
73-
state === 'error' ? 'animate-[fadeIn_.5s_.3s_both]' : 'hidden'
74-
)}
82+
className="transition-opacity duration-300"
83+
style={{
84+
color: 'rgb(var(--danger-9))',
85+
opacity: state === 'error' ? 1 : 0,
86+
transitionDelay: state === 'error' ? '.3s' : undefined,
87+
}}
7588
>
7689
<path
7790
d="M13.0312 1.42059L13.0312 3.95184"
@@ -94,37 +107,52 @@ export function AIChatIcon({
94107
strokeWidth="1.2"
95108
strokeLinecap="round"
96109
strokeLinejoin="round"
97-
className={tcls(
98-
state === 'done'
99-
? 'animate-[fadeIn_.5s_.3s_both]'
100-
: 'animate-[fadeOut_.5s_both]',
101-
state === 'intro' && 'hidden',
102-
state === 'confirm' && 'hidden'
103-
)}
110+
className="transition-opacity duration-300"
111+
style={{
112+
opacity: state === 'done' ? 1 : 0,
113+
transitionDelay: state === 'done' ? '.3s' : undefined,
114+
}}
104115
/>
105116

106117
{/* Confirm */}
107118
<path
108-
className={tcls(
109-
'fill-primary-9',
110-
state === 'confirm'
111-
? 'animate-[fadeIn_.5s_.3s_both,bounceSmall_1s_infinite_both]'
112-
: state === 'thinking'
113-
? 'animate-[fadeOut_.5s_both]'
114-
: 'hidden'
115-
)}
119+
className="transition-opacity duration-300"
120+
style={{
121+
fill: 'rgb(var(--primary-9))',
122+
opacity: state === 'confirm' ? 1 : 0,
123+
transitionDelay: state === 'confirm' ? '.3s' : undefined,
124+
animation: {
125+
intro: '',
126+
thinking: '',
127+
working: '',
128+
done: '',
129+
confirm: 'bounceSmall 1s infinite both',
130+
default: '',
131+
error: '',
132+
}[state],
133+
}}
116134
d="M12.9463 5.24512C13.3688 5.24422 13.713 5.58625 13.7139 6.00879C13.7146 6.43114 13.3725 6.77338 12.9502 6.77441C12.5279 6.77505 12.1845 6.43408 12.1836 6.01172C12.1828 5.58953 12.5242 5.24649 12.9463 5.24512ZM13.0391 0.0751953C14.0688 0.0730893 14.9049 0.90586 14.9072 1.93555C14.9084 2.5063 14.6484 3.04679 14.2012 3.40137L13.7773 3.7373C13.6151 3.86604 13.5201 4.06239 13.5205 4.26953V4.30371C13.5211 4.62139 13.2639 4.879 12.9463 4.87988C12.6288 4.88032 12.3701 4.62417 12.3691 4.30664V4.27246C12.3679 3.71272 12.6238 3.18263 13.0625 2.83496L13.4854 2.49902C13.6565 2.36341 13.7562 2.1568 13.7559 1.93848C13.755 1.54463 13.4358 1.22503 13.042 1.22559H12.9385C12.488 1.22679 12.1225 1.59352 12.123 2.04395L12.124 2.21875C12.1245 2.53649 11.8676 2.79522 11.5498 2.7959C11.2321 2.79653 10.9746 2.53928 10.9736 2.22168L10.9727 2.04688C10.9706 0.960578 11.8493 0.0778178 12.9355 0.0751953H13.0391Z"
117135
/>
118136

119-
{/* Background */}
137+
{/* Background */}
120138
<path
121139
d="M3.5625 8.78512L7.26347 10.9219C7.88227 11.2791 8.64467 11.2791 9.26347 10.9219L14.25 8.0429C14.5833 7.85045 15 8.09101 15 8.47591V10.2777C15 10.4563 14.9047 10.6214 14.75 10.7107L9.26347 13.8784C8.64467 14.2356 7.88228 14.2356 7.26347 13.8784L3.5625 11.7416C2.70833 11.2978 1 9.93199 1 8.01949M1 8.01949C1 6.6448 1.84765 5.98698 2.62903 5.71701C3.15426 5.53555 3.71577 5.70568 4.19701 5.98353L7.26347 7.75395C7.88228 8.11122 8.64467 8.11122 9.26347 7.75395L10.9095 6.80362M1 8.01949C1 6.4945 2.03973 5.30731 2.5596 4.90434L7.37937 2.12165C7.79013 1.88449 8.26417 1.80476 8.71747 1.88245"
122140
stroke="currentColor"
123141
strokeOpacity="0.25"
124142
strokeWidth="1.2"
125143
strokeLinecap="round"
126144
strokeLinejoin="round"
127-
className={tcls(state === 'intro' && 'animate-[fadeIn_2s_forwards]')}
145+
style={{
146+
animation: {
147+
intro: 'fadeIn 2s forwards',
148+
thinking: '',
149+
working: '',
150+
done: '',
151+
confirm: '',
152+
default: '',
153+
error: '',
154+
}[state],
155+
}}
128156
/>
129157

130158
{/* Logo */}
@@ -154,45 +182,65 @@ export function AIChatIcon({
154182
strokeWidth="1.2"
155183
strokeLinecap="round"
156184
strokeLinejoin="round"
157-
className={tcls(
158-
(state === 'thinking' || state === 'working') &&
159-
'animate-[pathLoading_2s_infinite_both]',
160-
state === 'intro' && 'animate-[pathEnter_2s_both]',
161-
state === 'done' && 'animate-[pathEnter_1s_forwards_ease]'
162-
)}
185+
style={{
186+
animation: {
187+
intro: 'pathEnter 1.5s both ease-out',
188+
thinking: 'pathLoading 2s infinite both',
189+
working: 'pathLoading 2s infinite both',
190+
done: 'pathEnter 1s forwards ease',
191+
confirm: '',
192+
default: '',
193+
error: '',
194+
}[state],
195+
}}
163196
/>
164197
</g>
165198
</svg>
166199
);
167200
}
168201

169-
export function AISearchIcon({
170-
className = 'size-4',
171-
state = 'default',
172-
}: Pick<AIChatIconProps, 'className' | 'state'>) {
202+
interface AISearchIconProps extends React.SVGProps<SVGSVGElement> {
203+
className?: string;
204+
state?: 'default' | 'intro' | 'thinking' | 'working' | 'done' | 'error' | 'confirm';
205+
}
206+
207+
export function AISearchIcon({ className = 'size-4', state = 'default' }: AISearchIconProps) {
173208
return (
174209
<div
175-
className={tcls(
176-
'relative',
177-
state === 'intro' && 'animate-[fadeIn_1s_both,orbit_1s_cubic-bezier(0.16,1,0.3,1)]',
178-
state === 'thinking' || state === 'working'
179-
? 'animate-[fadeIn_1s_both,orbit_1s_ease-out,orbit_2s_1s_infinite_forwards_linear]'
180-
: ''
181-
)}
210+
style={{
211+
position: 'relative',
212+
animation: {
213+
intro: 'fadeIn 1s both, orbit 1s cubic-bezier(0.16,1,0.3,1)',
214+
thinking:
215+
'fadeIn 1s both, orbit 1s orbit 2s 1s infinite forwards linear ease-out,',
216+
working: '',
217+
done: '',
218+
confirm: '',
219+
default: '',
220+
error: '',
221+
}[state],
222+
}}
182223
>
183224
<Icon icon="search" className={className} />
184225
<Icon
185226
icon="sparkle"
186227
iconStyle={IconStyle.Solid}
187-
className={tcls(
188-
'absolute top-[15.7%] left-[15.6%] size-[50%]',
189-
state === 'thinking' || state === 'working'
190-
? 'animate-[spin_2s_infinite_forwards_cubic-bezier(0.16,1,0.3,1)]'
191-
: '',
192-
state === 'intro'
193-
? 'animate-[spin_2s_.5s_forwards_cubic-bezier(0.16,1,0.3,1)]'
194-
: ''
195-
)}
228+
style={{
229+
position: 'absolute',
230+
top: '15.7%',
231+
left: '15.6%',
232+
width: '50%',
233+
height: '50%',
234+
animation: {
235+
intro: 'spin 2s .5s forwards cubic-bezier(0.16,1,0.3,1)',
236+
thinking: 'spin 2s infinite forwards cubic-bezier(0.16,1,0.3,1)',
237+
working: 'spin 2s infinite forwards cubic-bezier(0.16,1,0.3,1)',
238+
done: '',
239+
confirm: '',
240+
default: '',
241+
error: '',
242+
}[state],
243+
}}
196244
/>
197245
</div>
198246
);

0 commit comments

Comments
 (0)