Skip to content

Commit 9ad8f45

Browse files
authored
Rebrand assistant (#3458)
1 parent a385525 commit 9ad8f45

File tree

15 files changed

+203
-55
lines changed

15 files changed

+203
-55
lines changed

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

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,19 @@ import { AIChatInput } from './AIChatInput';
1717
import { AIChatMessages } from './AIChatMessages';
1818
import AIChatSuggestedQuestions from './AIChatSuggestedQuestions';
1919

20-
export function AIChat() {
20+
export function AIChat(props: { trademark: boolean }) {
21+
const { trademark } = props;
2122
const chat = useAIChatState();
2223

2324
if (!chat.opened) {
2425
return null;
2526
}
2627

27-
return <AIChatWindow chat={chat} />;
28+
return <AIChatWindow chat={chat} trademark={trademark} />;
2829
}
2930

30-
export function AIChatWindow(props: { chat: AIChatState }) {
31-
const { chat } = props;
31+
export function AIChatWindow(props: { chat: AIChatState; trademark: boolean }) {
32+
const { chat, trademark } = props;
3233

3334
const [input, setInput] = React.useState('');
3435
const chatController = useAIChatController();
@@ -91,11 +92,26 @@ export function AIChatWindow(props: { chat: AIChatState }) {
9192
<div className="relative flex h-full grow flex-col overflow-hidden circular-corners:rounded-3xl rounded-corners:rounded-md bg-tint-base text-sm text-tint depth-subtle:shadow-lg shadow-tint ring-1 ring-tint-subtle">
9293
<div className="flex items-center gap-2 border-tint-subtle border-b bg-tint-subtle px-4 py-2 text-tint-strong">
9394
<AIChatIcon
94-
className={`size-5 text-tint ${chat.loading ? 'animate-pulse' : ''}`}
95-
state={chat.loading ? 'thinking' : 'default'}
95+
className="size-5 text-tint"
96+
trademark={trademark}
97+
state={
98+
chat.error
99+
? 'error'
100+
: chat.loading
101+
? chat.messages[chat.messages.length - 1].content
102+
? 'working'
103+
: 'thinking'
104+
: chat.messages.length > 0
105+
? 'done'
106+
: 'default'
107+
}
96108
/>
97109
<div className="flex flex-col">
98-
<div className="font-bold">Docs Assistant</div>
110+
<div className="font-bold">
111+
{trademark
112+
? tString(language, 'ai_chat_assistant_name')
113+
: tString(language, 'ai_chat_assistant_name_unbranded')}
114+
</div>
99115
<div
100116
className={`text-tint text-xs leading-none transition-all duration-500 ${
101117
chat.loading ? 'h-3 opacity-11' : 'h-0 opacity-0'
@@ -153,7 +169,11 @@ export function AIChatWindow(props: { chat: AIChatState }) {
153169
{isEmpty ? (
154170
<div className="flex min-h-full w-full shrink-0 flex-col items-center justify-center gap-6 py-4">
155171
<div className="flex size-32 animate-[fadeIn_500ms_both] items-center justify-center rounded-full bg-tint-subtle">
156-
<AIChatIcon className="size-16 animate-[present_500ms_200ms_both]" />
172+
<AIChatIcon
173+
state="intro"
174+
trademark={trademark}
175+
className="size-16 animate-[present_500ms_200ms_both]"
176+
/>
157177
</div>
158178
<div className="animate-[fadeIn_500ms_400ms_both]">
159179
<h5 className=" text-center font-bold text-lg text-tint-strong">

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,25 @@ import AIChatIcon from './AIChatIcon';
77
/**
88
* Button to open/close the AI chat.
99
*/
10-
export function AIChatButton() {
10+
export function AIChatButton(props: { trademark: boolean }) {
11+
const { trademark } = props;
1112
const chatController = useAIChatController();
1213
const chat = useAIChatState();
1314

1415
const language = useLanguage();
1516

1617
return (
1718
<Button
18-
icon={<AIChatIcon />}
19+
icon={<AIChatIcon trademark={trademark} />}
1920
iconOnly
2021
size="default"
2122
variant="secondary"
2223
className="!px-3 bg-tint-base py-2.5"
23-
label={tString(language, 'ai_chat_assistant_name')}
24+
label={
25+
trademark
26+
? tString(language, 'ai_chat_assistant_name')
27+
: tString(language, 'ai_chat_assistant_name_unbranded')
28+
}
2429
onClick={() => {
2530
if (chat.opened) {
2631
chatController.close();

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

Lines changed: 104 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,146 @@
1+
import { tcls } from '@/lib/tailwind';
2+
import { Icon } from '@gitbook/icons';
13
import type React from 'react';
24

35
interface AIChatIconProps extends React.SVGProps<SVGSVGElement> {
46
className?: string;
57
size?: number;
6-
state?: 'thinking' | 'default';
8+
state?: 'default' | 'intro' | 'thinking' | 'working' | 'done' | 'error';
9+
trademark?: boolean;
710
}
811

912
const AIChatIcon = ({
1013
className = 'size-4',
1114
size,
15+
trademark = true,
1216
state = 'default',
1317
...props
1418
}: AIChatIconProps) => {
19+
if (!trademark) {
20+
return (
21+
<Icon
22+
icon="sparkle"
23+
className={tcls(
24+
className,
25+
state === 'thinking' || state === 'working'
26+
? 'animate-[spin_2s_infinite_forwards_cubic-bezier(0.16,1,0.3,1)]'
27+
: ''
28+
)}
29+
/>
30+
);
31+
}
32+
1533
return (
1634
<svg
1735
width="16"
1836
height="16"
1937
viewBox="0 0 16 16"
20-
fill="none"
21-
xmlns="http://www.w3.org/2000/svg"
38+
preserveAspectRatio="xMaxYMid meet"
2239
className={className}
23-
{...(size && { width: size, height: size })}
40+
aria-busy={state === 'thinking'}
2441
{...props}
42+
fill="none"
43+
xmlns="http://www.w3.org/2000/svg"
2544
>
26-
<title>Docs Assistant</title>
45+
<title>GitBook Assistant</title>
46+
47+
{/* Sparkle */}
2748
<path
2849
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"
2950
stroke="currentColor"
3051
strokeWidth="1.2"
3152
strokeLinejoin="round"
32-
className={state === 'thinking' ? 'animate-spin' : ''}
53+
className={tcls(
54+
state === 'intro' &&
55+
'animate-[fadeIn_.5s_.7s_both,spin_2s_1s_forwards_cubic-bezier(.43,1.54,.64,1)]',
56+
(state === 'working' || state === 'thinking') &&
57+
'animate-[fadeIn_.5s_.3s_both,spin_2s_infinite_forwards_cubic-bezier(0.16,1,0.3,1)]',
58+
state === 'done' && 'animate-[fadeOut_.5s_both]',
59+
state === 'default' && 'animate-[fadeIn_0s_both]',
60+
state === 'error' && 'hidden'
61+
)}
3362
style={{ transformOrigin: '13px 3.5px' }}
3463
/>
64+
65+
{/* Error */}
66+
<g
67+
clipPath="url(#clip0_153_2034)"
68+
className={tcls(state === 'error' ? 'animate-[fadeIn_.5s_.3s_both]' : 'hidden')}
69+
>
70+
<path
71+
d="M13.0312 1.42059L13.0312 3.95184"
72+
stroke="currentColor"
73+
strokeWidth="1.2"
74+
strokeLinecap="round"
75+
/>
76+
<path
77+
d="M13.0312 6.00253V6.00263"
78+
stroke="currentColor"
79+
strokeWidth="1.2"
80+
strokeLinecap="round"
81+
/>
82+
</g>
83+
84+
{/* Check */}
3585
<path
36-
d="M9.479 10.2734C9.479 11.2369 8.6115 11.2578 7.54138 11.2578C6.47126 11.2578 5.60376 11.2369 5.60376 10.2734"
37-
stroke="currentColor"
38-
strokeWidth="1.2"
39-
strokeLinecap="round"
40-
/>
41-
<path
42-
d="M9.47913 6.77344L9.47913 7.77344"
43-
stroke="currentColor"
44-
strokeWidth="1.2"
45-
strokeLinecap="round"
46-
/>
47-
<path
48-
d="M5.60388 6.77344L5.60388 7.77344"
86+
d="M10.8051 3.71161L12.2401 5.27411L14.823 2.14911"
4987
stroke="currentColor"
5088
strokeWidth="1.2"
5189
strokeLinecap="round"
90+
strokeLinejoin="round"
91+
className={tcls(
92+
state === 'done'
93+
? 'animate-[fadeIn_.5s_.3s_both]'
94+
: 'animate-[fadeOut_.5s_both]'
95+
)}
5296
/>
97+
98+
{/* Background */}
5399
<path
54-
d="M13.2813 8.875L13.2813 10.125C13.2813 12.3341 11.4904 14.125 9.28125 14.125L1.80165 14.125L1.80165 6.78125C1.80165 4.57211 3.59251 2.78125 5.80165 2.78125L7.67889 2.78125"
100+
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"
55101
stroke="currentColor"
102+
strokeOpacity="0.25"
56103
strokeWidth="1.2"
57104
strokeLinecap="round"
58105
strokeLinejoin="round"
106+
className={tcls(state === 'intro' && 'animate-[fadeIn_2s_forwards]')}
59107
/>
108+
109+
{/* Logo */}
110+
<mask
111+
id="mask0_220_25"
112+
style={{ maskType: 'alpha' }}
113+
maskUnits="userSpaceOnUse"
114+
x="0"
115+
y="1"
116+
width="16"
117+
height="14"
118+
>
119+
<path
120+
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"
121+
stroke="currentColor"
122+
pathLength="100"
123+
strokeWidth="1.2"
124+
strokeLinecap="round"
125+
strokeLinejoin="round"
126+
/>
127+
</mask>
128+
<g mask="url(#mask0_220_25)">
129+
<path
130+
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.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.75395L14.1991 4.90434L9.37937 2.12165C8.76057 1.76438 7.99907 1.76386 7.38027 2.12113C5.89314 2.97972 3.20298 4.53289 2.5596 4.90434C1.77376 5.35804 1 6.11597 1.00148 7.9207"
131+
stroke="currentColor"
132+
pathLength="100"
133+
strokeWidth="1.2"
134+
strokeLinecap="round"
135+
strokeLinejoin="round"
136+
className={tcls(
137+
(state === 'thinking' || state === 'working') &&
138+
'animate-[pathLoading_2s_infinite_forwards]',
139+
state === 'intro' && 'animate-[pathEnter_2s_forwards]',
140+
state === 'done' && 'animate-[pathEnter_1s_forwards_ease]'
141+
)}
142+
/>
143+
</g>
60144
</svg>
61145
);
62146
};

packages/gitbook/src/components/Header/Header.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,11 @@ export function Header(props: {
166166
</span>
167167
</SearchButton>
168168
</Suspense>
169-
{withAIChat && <AIChatButton />}
169+
{withAIChat && (
170+
<AIChatButton
171+
trademark={context.customization.trademark.enabled}
172+
/>
173+
)}
170174
</div>
171175

172176
{customization.header.links.length > 0 && (

packages/gitbook/src/components/SpaceLayout/SpaceLayout.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@ export function SpaceLayout(props: {
7979
withAIChat={withAIChat}
8080
context={context}
8181
/>
82-
{withAIChat ? <AIChat /> : null}
82+
{withAIChat ? (
83+
<AIChat trademark={context.customization.trademark.enabled} />
84+
) : null}
8385
<div className="scroll-nojump">
8486
<div className="motion-safe:transition-all motion-safe:duration-300 lg:chat-open:mr-80 xl:chat-open:mr-96">
8587
<div

packages/gitbook/src/intl/translations/de.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ export const de = {
6464
link_tooltip_external_link: 'Externe Verlinkung zu',
6565
link_tooltip_page_anchor: 'Zum Abschnitt springen',
6666
open_in_new_tab: 'In neuem Tab öffnen',
67-
ai_chat_assistant_name: 'Docs-Assistent',
67+
ai_chat_assistant_name: 'GitBook-Assistent',
68+
ai_chat_assistant_name_unbranded: 'KI-Assistent',
6869
ai_chat_assistant_description: 'Ich helfe Ihnen bei der Dokumentation.',
6970
ai_chat_assistant_greeting_morning: 'Guten Morgen',
7071
ai_chat_assistant_greeting_afternoon: 'Guten Tag',
@@ -77,7 +78,7 @@ export const de = {
7778
ai_chat_error: 'Etwas ist schief gelaufen.',
7879
ai_chat_context_title: 'Basierend auf Ihrem Kontext',
7980
ai_chat_context_description:
80-
'Der Docs-Assistent verwendet KI und Ihren Kontext, um Antworten zu generieren und Aktionen durchzuführen.',
81+
'Der Assistent verwendet KI und Ihren Kontext, um Antworten zu generieren und Aktionen durchzuführen.',
8182
ai_chat_context_pages_youve_read: 'Seiten, die Sie gelesen haben',
8283
ai_chat_context_info_provided_by_the_site: 'Von der Website bereitgestellte Informationen',
8384
ai_chat_context_previous_messages: 'Vorherige Nachrichten',

packages/gitbook/src/intl/translations/en.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ export const en = {
6262
link_tooltip_external_link: 'External link to',
6363
link_tooltip_page_anchor: 'Jump to section',
6464
open_in_new_tab: 'Open in new tab',
65-
ai_chat_assistant_name: 'Docs Assistant',
65+
ai_chat_assistant_name: 'GitBook Assistant',
66+
ai_chat_assistant_name_unbranded: 'AI Assistant',
6667
ai_chat_assistant_description: "I'm here to help you with the docs.",
6768
ai_chat_assistant_greeting_morning: 'Good morning',
6869
ai_chat_assistant_greeting_afternoon: 'Good afternoon',
@@ -75,7 +76,7 @@ export const en = {
7576
ai_chat_error: 'Something went wrong.',
7677
ai_chat_context_title: 'Based on your context',
7778
ai_chat_context_description:
78-
'Docs Assistant uses AI and your context to generate answers and perform actions.',
79+
'The assistant uses AI and your context to generate answers and perform actions.',
7980
ai_chat_context_pages_youve_read: "Pages you've read",
8081
ai_chat_context_info_provided_by_the_site: 'Info provided by the site',
8182
ai_chat_context_previous_messages: 'Previous messages',

packages/gitbook/src/intl/translations/es.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ export const es: TranslationLanguage = {
6666
link_tooltip_external_link: 'Enlace externo a',
6767
link_tooltip_page_anchor: 'Saltar a la sección',
6868
open_in_new_tab: 'Abrir en una nueva pestaña',
69-
ai_chat_assistant_name: 'Asistente de Docs',
69+
ai_chat_assistant_name: 'Asistente de GitBook',
70+
ai_chat_assistant_name_unbranded: 'Asistente de IA',
7071
ai_chat_assistant_description: 'Estoy aquí para ayudarte con la documentación.',
7172
ai_chat_assistant_greeting_morning: 'Buenos días',
7273
ai_chat_assistant_greeting_afternoon: 'Buenas tardes',
@@ -79,7 +80,7 @@ export const es: TranslationLanguage = {
7980
ai_chat_error: 'Algo salió mal.',
8081
ai_chat_context_title: 'Basado en tu contexto',
8182
ai_chat_context_description:
82-
'El Asistente de Docs usa IA y tu contexto para generar respuestas y realizar acciones.',
83+
'El asistente usa IA y tu contexto para generar respuestas y realizar acciones.',
8384
ai_chat_context_pages_youve_read: 'Páginas que has leído',
8485
ai_chat_context_info_provided_by_the_site: 'Información proporcionada por el sitio',
8586
ai_chat_context_previous_messages: 'Mensajes anteriores',

packages/gitbook/src/intl/translations/fr.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ export const fr: TranslationLanguage = {
6464
link_tooltip_external_link: 'Lien externe à',
6565
link_tooltip_page_anchor: 'Sauter à la section',
6666
open_in_new_tab: 'Ouvrir dans un nouvel onglet',
67-
ai_chat_assistant_name: 'Assistant Docs',
67+
ai_chat_assistant_name: 'Assistant GitBook',
68+
ai_chat_assistant_name_unbranded: 'Assistant IA',
6869
ai_chat_assistant_description: 'Je suis là pour vous aider avec la documentation.',
6970
ai_chat_assistant_greeting_morning: 'Bonjour',
7071
ai_chat_assistant_greeting_afternoon: 'Bon après-midi',
@@ -77,7 +78,7 @@ export const fr: TranslationLanguage = {
7778
ai_chat_error: 'Une erreur est survenue.',
7879
ai_chat_context_title: 'Basé sur votre contexte',
7980
ai_chat_context_description:
80-
"L'Assistant Docs utilise l'IA et votre contexte pour générer des réponses et effectuer des actions.",
81+
"L'assistant utilise l'IA et votre contexte pour générer des réponses et effectuer des actions.",
8182
ai_chat_context_pages_youve_read: 'Pages que vous avez lues',
8283
ai_chat_context_info_provided_by_the_site: 'Informations fournies par le site',
8384
ai_chat_context_previous_messages: 'Messages précédents',

0 commit comments

Comments
 (0)