Skip to content

Commit 7c2534f

Browse files
committed
Move dynamic icons (AIChatIcon and AISearchIcon) to @gitbook/icons package
1 parent 6b43773 commit 7c2534f

File tree

12 files changed

+248
-85
lines changed

12 files changed

+248
-85
lines changed

.changeset/wide-games-design.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@gitbook/icons": minor
3+
"gitbook": patch
4+
---
5+
6+
Move dynamic icons (AIChatIcon and AISearchIcon) to `@gitbook/icons` package

packages/gitbook/src/components/AI/useAI.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ import type { ReactNode } from 'react';
77

88
import { tString, useLanguage } from '@/intl/client';
99
import type { GitBookAssistant } from '@gitbook/browser-types';
10+
import { AIChatIcon, AISearchIcon } from '@gitbook/icons';
1011
import { useAIChatController, useAIChatState } from '.';
11-
import { AIChatIcon, AISearchIcon, getAIChatName } from '../AIChat';
12+
import { getAIChatName } from '../AIChat';
1213
import { useIntegrationAssistants } from '../Integrations';
1314
import { useSearch } from '../Search/useSearch';
1415

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { t, tString, useLanguage } from '@/intl/client';
44
import type { TranslationLanguage } from '@/intl/translations';
55
import { tcls } from '@/lib/tailwind';
66
import { Icon } from '@gitbook/icons';
7+
import { AIChatIcon } from '@gitbook/icons';
78
import React from 'react';
89
import { useHotkeys } from 'react-hotkeys-hook';
910
import {
@@ -28,7 +29,6 @@ import { useNow } from '../hooks';
2829
import { Button } from '../primitives';
2930
import { ScrollContainer } from '../primitives/ScrollContainer';
3031
import { AIChatControlButton } from './AIChatControlButton';
31-
import { AIChatIcon } from './AIChatIcon';
3232
import { AIChatInput } from './AIChatInput';
3333
import { AIChatMessages } from './AIChatMessages';
3434
import AIChatSuggestedQuestions from './AIChatSuggestedQuestions';
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
export * from './AIChat';
22
export * from './AIChatButton';
3-
export * from './AIChatIcon';
43
export * from './AIResponseFeedback';
54
export * from './AIChatControlButton';

packages/gitbook/src/components/Search/SearchAskAnswer.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import { Icon } from '@gitbook/icons';
88
import { readStreamableValue } from 'ai/rsc';
99
import React from 'react';
1010

11-
import { AIResponseFeedback, AISearchIcon } from '../AIChat';
11+
import { AISearchIcon } from '@gitbook/icons';
12+
import { AIResponseFeedback } from '../AIChat';
1213
import { HoldMessage } from '../AIChat/AIChatMessages';
1314
import { useTrackEvent } from '../Insights';
1415
import { Button, Link } from '../primitives';
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
declare module '*.module.css' {
2+
const classes: Record<string, string>;
3+
export default classes;
4+
}

packages/gitbook/src/components/AIChat/AIChatIcon.tsx renamed to packages/icons/src/dynamic/AIChatIcon.tsx

Lines changed: 82 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { tcls } from '@/lib/tailwind';
2-
import { Icon, IconStyle } from '@gitbook/icons';
31
import type React from 'react';
2+
import { Icon } from '../Icon';
3+
import styles from './icons.module.css';
44

55
interface AIChatIconProps extends React.SVGProps<SVGSVGElement> {
66
className?: string;
@@ -10,7 +10,7 @@ interface AIChatIconProps extends React.SVGProps<SVGSVGElement> {
1010
}
1111

1212
export function AIChatIcon({
13-
className = 'size-4',
13+
className = styles.icon,
1414
size,
1515
trademark = true,
1616
state = 'default',
@@ -21,12 +21,18 @@ export function AIChatIcon({
2121
<Icon
2222
icon="sparkle"
2323
{...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-
)}
24+
className={className}
25+
style={{
26+
animation: {
27+
intro: `${styles.spin} 2s forwards cubic-bezier(0.16,1,0.3,1)`,
28+
thinking: `${styles.spin} 2s infinite forwards cubic-bezier(0.16,1,0.3,1)`,
29+
working: `${styles.spin} 2s infinite forwards cubic-bezier(0.16,1,0.3,1)`,
30+
done: '',
31+
confirm: '',
32+
default: '',
33+
error: '',
34+
}[state],
35+
}}
3036
/>
3137
);
3238
}
@@ -50,28 +56,36 @@ export function AIChatIcon({
5056
<path
5157
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"
5258
stroke="currentColor"
53-
strokeWidth="1.2"
59+
strokeWidth={state === 'intro' ? '1.2' : '1'}
5460
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' }}
61+
shapeRendering="crispEdges"
62+
className={styles.fade}
63+
style={{
64+
animation: {
65+
intro: `${styles.fadeIn} 2s .5s backwards, ${styles.spin} 2s 1s forwards cubic-bezier(0.43,1.54,0.64,1)`,
66+
thinking: `${styles.spin} 2s 1s infinite forwards cubic-bezier(0.16,1,0.3,1)`,
67+
working: `${styles.spin} 2s 1s infinite forwards cubic-bezier(0.16,1,0.3,1)`,
68+
done: '',
69+
confirm: '',
70+
default: '',
71+
error: '',
72+
}[state],
73+
transitionDelay:
74+
state === 'default' || state === 'thinking' ? '.3s' : undefined,
75+
opacity: ['done', 'confirm', 'error'].includes(state) ? 0 : 1,
76+
transformOrigin: '13px 3.5px',
77+
}}
6678
/>
6779

6880
{/* Error */}
6981
<g
7082
clipPath="url(#clip0_153_2034)"
71-
className={tcls(
72-
'text-danger-subtle',
73-
state === 'error' ? 'animate-[fadeIn_.5s_.3s_both]' : 'hidden'
74-
)}
83+
className={styles.fade}
84+
style={{
85+
color: 'rgb(var(--danger-9))',
86+
opacity: state === 'error' ? 1 : 0,
87+
transitionDelay: state === 'error' ? '.3s' : undefined,
88+
}}
7589
>
7690
<path
7791
d="M13.0312 1.42059L13.0312 3.95184"
@@ -94,37 +108,52 @@ export function AIChatIcon({
94108
strokeWidth="1.2"
95109
strokeLinecap="round"
96110
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-
)}
111+
className={styles.fade}
112+
style={{
113+
opacity: state === 'done' ? 1 : 0,
114+
transitionDelay: state === 'done' ? '.3s' : undefined,
115+
}}
104116
/>
105117

106118
{/* Confirm */}
107119
<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-
)}
120+
className={styles.fade}
121+
style={{
122+
fill: 'rgb(var(--primary-9))',
123+
opacity: state === 'confirm' ? 1 : 0,
124+
transitionDelay: state === 'confirm' ? '.3s' : undefined,
125+
animation: {
126+
intro: '',
127+
thinking: '',
128+
working: '',
129+
done: '',
130+
confirm: `${styles.bounce} 1s infinite both`,
131+
default: '',
132+
error: '',
133+
}[state],
134+
}}
116135
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"
117136
/>
118137

119-
{/* Background */}
138+
{/* Background */}
120139
<path
121140
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"
122141
stroke="currentColor"
123142
strokeOpacity="0.25"
124143
strokeWidth="1.2"
125144
strokeLinecap="round"
126145
strokeLinejoin="round"
127-
className={tcls(state === 'intro' && 'animate-[fadeIn_2s_forwards]')}
146+
style={{
147+
animation: {
148+
intro: `${styles.fadeIn} 2s forwards`,
149+
thinking: '',
150+
working: '',
151+
done: '',
152+
confirm: '',
153+
default: '',
154+
error: '',
155+
}[state],
156+
}}
128157
/>
129158

130159
{/* Logo */}
@@ -154,46 +183,19 @@ export function AIChatIcon({
154183
strokeWidth="1.2"
155184
strokeLinecap="round"
156185
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-
)}
186+
style={{
187+
animation: {
188+
intro: `${styles.pathEnter} 2s both`,
189+
thinking: `${styles.pathLoading} 2s infinite both`,
190+
working: `${styles.pathLoading} 2s infinite both`,
191+
done: `${styles.pathEnter} 1s forwards ease`,
192+
confirm: '',
193+
default: '',
194+
error: '',
195+
}[state],
196+
}}
163197
/>
164198
</g>
165199
</svg>
166200
);
167201
}
168-
169-
export function AISearchIcon({
170-
className = 'size-4',
171-
state = 'default',
172-
}: Pick<AIChatIconProps, 'className' | 'state'>) {
173-
return (
174-
<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-
)}
182-
>
183-
<Icon icon="search" className={className} />
184-
<Icon
185-
icon="sparkle"
186-
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-
)}
196-
/>
197-
</div>
198-
);
199-
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import type React from 'react';
2+
import { Icon } from '../Icon';
3+
import { IconStyle } from '../types';
4+
import styles from './icons.module.css';
5+
6+
interface AISearchIconProps extends React.SVGProps<SVGSVGElement> {
7+
className?: string;
8+
state?: 'default' | 'intro' | 'thinking' | 'working' | 'done' | 'error' | 'confirm';
9+
}
10+
11+
export function AISearchIcon({ className = styles.icon, state = 'default' }: AISearchIconProps) {
12+
return (
13+
<div
14+
style={{
15+
position: 'relative',
16+
animation: {
17+
intro: `${styles.fadeIn} 1s both, ${styles.orbit} 1s cubic-bezier(0.16,1,0.3,1)`,
18+
thinking: `${styles.fadeIn} 1s both, ${styles.orbit} 1s ease-out, ${styles.orbit} 2s 1s infinite forwards linear`,
19+
working: '',
20+
done: '',
21+
confirm: '',
22+
default: '',
23+
error: '',
24+
}[state],
25+
}}
26+
>
27+
<Icon icon="search" className={className} />
28+
<Icon
29+
icon="sparkle"
30+
iconStyle={IconStyle.Solid}
31+
style={{
32+
position: 'absolute',
33+
top: '15.7%',
34+
left: '15.6%',
35+
width: '50%',
36+
height: '50%',
37+
animation: {
38+
intro: `${styles.spin} 2s .5s forwards cubic-bezier(0.16,1,0.3,1)`,
39+
thinking: `${styles.spin} 2s infinite forwards cubic-bezier(0.16,1,0.3,1)`,
40+
working: `${styles.spin} 2s infinite forwards cubic-bezier(0.16,1,0.3,1)`,
41+
done: '',
42+
confirm: '',
43+
default: '',
44+
error: '',
45+
}[state],
46+
}}
47+
/>
48+
</div>
49+
);
50+
}

0 commit comments

Comments
 (0)