Skip to content

Commit acb9f53

Browse files
authored
Inline search modal (#3416)
1 parent 6016846 commit acb9f53

40 files changed

+809
-921
lines changed

.changeset/purple-toys-grow.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"gitbook": minor
3+
---
4+
5+
New search layout

packages/gitbook/src/components/AIActions/AIActions.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { ChatGPTIcon } from '@/components/AIActions/assets/ChatGPTIcon';
66
import { ClaudeIcon } from '@/components/AIActions/assets/ClaudeIcon';
77
import { MarkdownIcon } from '@/components/AIActions/assets/MarkdownIcon';
88
import { getAIChatName } from '@/components/AIChat';
9-
import AIChatIcon from '@/components/AIChat/AIChatIcon';
9+
import { AIChatIcon } from '@/components/AIChat';
1010
import { Button } from '@/components/primitives/Button';
1111
import { DropdownMenuItem } from '@/components/primitives/DropdownMenu';
1212
import { tString, useLanguage } from '@/intl/client';

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
import { useNow } from '../hooks';
1414
import { Button } from '../primitives';
1515
import { DropdownMenu, DropdownMenuItem } from '../primitives/DropdownMenu';
16-
import AIChatIcon from './AIChatIcon';
16+
import { AIChatIcon } from './AIChatIcon';
1717
import { AIChatInput } from './AIChatInput';
1818
import { AIChatMessages } from './AIChatMessages';
1919
import AIChatSuggestedQuestions from './AIChatSuggestedQuestions';
@@ -108,7 +108,7 @@ export function AIChatWindow(props: {
108108

109109
return (
110110
<div
111-
className="ai-chat inset-y-0 right-0 z-40 mx-auto flex max-w-3xl animate-present px-4 py-4 transition-all duration-300 sm:px-6 lg:fixed lg:w-80 lg:animate-enterFromRight lg:pr-4 lg:pl-0 xl:w-96"
111+
className="ai-chat inset-y-0 right-0 z-40 mx-auto flex max-w-3xl animate-present scroll-mt-36 px-4 py-4 transition-all duration-300 sm:px-6 lg:fixed lg:w-80 lg:animate-enterFromRight lg:pr-4 lg:pl-0 xl:w-96"
112112
ref={containerRef}
113113
>
114114
<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">

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

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
'use client';
2-
import { t, useLanguage } from '@/intl/client';
2+
import { tcls } from '@/lib/tailwind';
33
import { useAIChatController, useAIChatState } from '../AI/useAIChat';
44
import { Button } from '../primitives';
55
import { KeyboardShortcut } from '../primitives/KeyboardShortcut';
6-
import AIChatIcon from './AIChatIcon';
6+
import { getAIChatName } from './AIChat';
7+
import { AIChatIcon } from './AIChatIcon';
78

89
/**
910
* Button to open/close the AI chat.
@@ -13,20 +14,16 @@ export function AIChatButton(props: { trademark: boolean }) {
1314
const chatController = useAIChatController();
1415
const chat = useAIChatState();
1516

16-
const language = useLanguage();
17-
1817
return (
1918
<Button
2019
icon={<AIChatIcon trademark={trademark} />}
2120
iconOnly
2221
size="default"
23-
variant="secondary"
24-
className="!px-3 bg-tint-base py-2.5"
22+
variant="header"
23+
className={tcls('h-9 px-2.5')}
2524
label={
2625
<div className="flex items-center gap-2">
27-
{trademark
28-
? t(language, 'ai_chat_assistant_name')
29-
: t(language, 'ai_chat_assistant_name_unbranded')}
26+
{getAIChatName(trademark)}
3027
<KeyboardShortcut keys={['mod', 'j']} className="border-tint-11 text-tint-1" />
3128
</div>
3229
}

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ interface AIChatIconProps extends React.SVGProps<SVGSVGElement> {
99
trademark?: boolean;
1010
}
1111

12-
const AIChatIcon = ({
12+
export const AIChatIcon = ({
1313
className = 'size-4',
1414
size,
1515
trademark = true,
@@ -148,5 +148,3 @@ const AIChatIcon = ({
148148
</svg>
149149
);
150150
};
151-
152-
export default AIChatIcon;

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ export function AIChatMessages(props: {
2626
message.content ? 'animate-[fadeIn_500ms_both]' : '',
2727
'shrink-0',
2828
'last:min-h-[calc(100%-5rem)]',
29+
'scroll-mt-36',
30+
'lg:scroll-mt-0',
2931
'flex flex-col gap-6',
3032
message.role === AIMessageRole.User
3133
? 'max-w-[80%] self-end circular-corners:rounded-2xl rounded-corners:rounded-md bg-tint px-4 py-2'
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
export * from './AIChat';
2+
export * from './AIChatButton';
3+
export * from './AIChatIcon';

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

Lines changed: 3 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,8 @@
11
import type { GitBookSiteContext } from '@/lib/context';
2-
import { Suspense } from 'react';
32

43
import { CONTAINER_STYLE, HEADER_HEIGHT_DESKTOP } from '@/components/layout';
54
import { getSpaceLanguage, t } from '@/intl/server';
65
import { tcls } from '@/lib/tailwind';
7-
8-
import { CustomizationAIMode } from '@gitbook/api';
9-
import { AIChatButton } from '../AIChat/AIChatButton';
10-
import { SearchButton } from '../Search';
116
import { SiteSectionTabs, encodeClientSiteSections } from '../SiteSections';
127
import { HeaderLink } from './HeaderLink';
138
import { HeaderLinkMore } from './HeaderLinkMore';
@@ -22,9 +17,9 @@ import { SpacesDropdown } from './SpacesDropdown';
2217
export function Header(props: {
2318
context: GitBookSiteContext;
2419
withTopHeader?: boolean;
25-
withAIChat?: boolean;
20+
search?: React.ReactNode;
2621
}) {
27-
const { context, withTopHeader, withAIChat } = props;
22+
const { context, withTopHeader, search } = props;
2823
const { siteSpace, siteSpaces, sections, customization } = context;
2924

3025
return (
@@ -123,54 +118,7 @@ export function Header(props: {
123118
: ['order-last']
124119
)}
125120
>
126-
<Suspense fallback={null}>
127-
<SearchButton
128-
style={[
129-
'theme-bold:bg-header-link/2',
130-
'theme-bold:hover:bg-header-link/3',
131-
132-
'theme-bold:text-header-link/8',
133-
'theme-bold:hover:text-header-link',
134-
135-
'theme-bold:ring-header-link/4',
136-
'theme-bold:hover:ring-header-link/5',
137-
138-
'theme-bold:[&_svg]:text-header-link/10',
139-
'theme-bold:[&_.shortcut]:text-header-link/8',
140-
141-
'theme-bold:contrast-more:bg-header-background',
142-
'theme-bold:contrast-more:text-header-link',
143-
'theme-bold:contrast-more:ring-header-link',
144-
'theme-bold:contrast-more:hover:bg-header-background',
145-
'theme-bold:contrast-more:hover:ring-header-link',
146-
'theme-bold:contrast-more:focus:text-header-link',
147-
'theme-bold:contrast-more:focus:bg-header-background',
148-
'theme-bold:contrast-more:focus:ring-header-link',
149-
150-
'theme-bold:shadow-none',
151-
'theme-bold:hover:shadow-none',
152-
'whitespace-nowrap',
153-
]}
154-
>
155-
<span className={tcls('flex-1')}>
156-
{t(
157-
getSpaceLanguage(customization),
158-
// TODO: remove aiSearch and optional chain once the cache has been fully updated (after 11/07/2025)
159-
customization.aiSearch?.enabled ||
160-
customization.ai?.mode !==
161-
CustomizationAIMode.None
162-
? 'search_or_ask'
163-
: 'search'
164-
)}
165-
...
166-
</span>
167-
</SearchButton>
168-
</Suspense>
169-
{withAIChat && (
170-
<AIChatButton
171-
trademark={context.customization.trademark.enabled}
172-
/>
173-
)}
121+
{search}
174122
</div>
175123

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

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ function HeaderItemButton(
104104
const variant = (() => {
105105
switch (linkStyle) {
106106
case 'button-secondary':
107-
return 'secondary';
107+
return 'header';
108108
case 'button-primary':
109109
return 'primary';
110110
default:
@@ -120,9 +120,7 @@ function HeaderItemButton(
120120
{
121121
'button-primary':
122122
'theme-bold:bg-header-link theme-bold:text-header-background theme-bold:shadow-none theme-bold:hover:bg-header-link theme-bold:hover:text-header-background theme-bold:hover:shadow-none',
123-
'button-secondary': tcls(
124-
'theme-bold:bg-header-link/2 theme-gradient:bg-tint-base theme-muted:bg-tint-base theme-bold:text-header-link theme-bold:shadow-none theme-bold:ring-header-link/4 theme-bold:hover:bg-header-link/3 theme-bold:hover:text-header-link theme-bold:hover:shadow-none theme-bold:hover:ring-header-link/5 theme-bold:contrast-more:bg-header-background theme-bold:contrast-more:text-header-link theme-bold:contrast-more:ring-header-link theme-bold:contrast-more:hover:ring-header-link'
125-
),
123+
'button-secondary': '',
126124
}[linkStyle]
127125
)}
128126
insights={{

packages/gitbook/src/components/RootLayout/CustomizationRootLayout.tsx

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import {
2-
CustomizationHeaderPreset,
32
CustomizationIconsStyle,
43
CustomizationSidebarBackgroundStyle,
54
CustomizationSidebarListStyle,
@@ -86,11 +85,6 @@ export async function CustomizationRootLayout(props: {
8685
suppressHydrationWarning
8786
lang={customization.internationalization.locale}
8887
className={tcls(
89-
/* This offset is used when scrolling to elements on the page, like #anchors and (on mobile) the latest AI chat message.
90-
* It is set to the maximum height of the header (64px) + sections (44px) + offset (40px) */
91-
customization.header.preset === CustomizationHeaderPreset.None
92-
? null
93-
: 'scroll-pt-[148px]',
9488
customization.styling.corners && `${customization.styling.corners}-corners`,
9589
'theme' in customization.styling && `theme-${customization.styling.theme}`,
9690
tintColor ? ' tint' : 'no-tint',

0 commit comments

Comments
 (0)