Skip to content

Commit 9c69cc4

Browse files
authored
Add customizable suggested questions (#3789)
1 parent b77623b commit 9c69cc4

File tree

9 files changed

+45
-11
lines changed

9 files changed

+45
-11
lines changed

.changeset/ready-aliens-lose.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"gitbook": patch
3+
---
4+
5+
Add customizable suggested questions

bun.lock

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"lockfileVersion": 1,
3+
"configVersion": 0,
34
"workspaces": {
45
"": {
56
"name": "gitbook",
@@ -345,7 +346,7 @@
345346
"react-dom": "catalog:",
346347
},
347348
"catalog": {
348-
"@gitbook/api": "0.153.0",
349+
"@gitbook/api": "0.154.0",
349350
"@scalar/api-client-react": "^1.3.46",
350351
"@tsconfig/node20": "^20.1.6",
351352
"@tsconfig/strictest": "^2.0.6",
@@ -726,7 +727,7 @@
726727

727728
"@fortawesome/fontawesome-svg-core": ["@fortawesome/fontawesome-svg-core@6.6.0", "", { "dependencies": { "@fortawesome/fontawesome-common-types": "6.6.0" } }, "sha512-KHwPkCk6oRT4HADE7smhfsKudt9N/9lm6EJ5BVg0tD1yPA5hht837fB87F8pn15D8JfTqQOjhKTktwmLMiD7Kg=="],
728729

729-
"@gitbook/api": ["@gitbook/api@0.153.0", "", { "dependencies": { "event-iterator": "^2.0.0", "eventsource-parser": "^3.0.0" } }, "sha512-ArNPFoqwId4Flicz8xPEdGqXQkzxyxP7S8Uv3wIfCX2e4cLhpcS7xCJGEHOJrqe1tNs1ovT1N2MWfpdIqzXqig=="],
730+
"@gitbook/api": ["@gitbook/api@0.154.0", "", { "dependencies": { "event-iterator": "^2.0.0", "eventsource-parser": "^3.0.0" } }, "sha512-huEgWWa2H+H4ofYEAQl9r49u0gVjDHHWVNJKhd6SgGCfefjNPHkQj9zaky/5DBQzlu/+SDmutWiOtYdrykQO8w=="],
730731

731732
"@gitbook/browser-types": ["@gitbook/browser-types@workspace:packages/browser-types"],
732733

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
"catalog": {
4242
"@tsconfig/strictest": "^2.0.6",
4343
"@tsconfig/node20": "^20.1.6",
44-
"@gitbook/api": "0.153.0",
44+
"@gitbook/api": "0.154.0",
4545
"@scalar/api-client-react": "^1.3.46",
4646
"@types/react": "^19.0.0",
4747
"@types/react-dom": "^19.0.0",

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { useSearch } from '../Search/useSearch';
1515
// Unify assistants configuration context with the assistants hook in one place
1616
export type AIConfig = {
1717
aiMode: CustomizationAIMode;
18+
suggestions?: string[];
1819
trademark: boolean;
1920
};
2021

@@ -49,8 +50,11 @@ export type Assistant = Omit<GitBookAssistant, 'icon'> & {
4950
const AIContext = React.createContext<AIConfig | null>(null);
5051

5152
export function AIContextProvider(props: React.PropsWithChildren<AIConfig>): React.ReactElement {
52-
const { aiMode, trademark, children } = props;
53-
const value = React.useMemo(() => ({ aiMode, trademark }), [aiMode, trademark]);
53+
const { aiMode, trademark, suggestions, children } = props;
54+
const value = React.useMemo(
55+
() => ({ aiMode, trademark, suggestions }),
56+
[aiMode, trademark, suggestions]
57+
);
5458
return <AIContext.Provider value={value}>{children}</AIContext.Provider>;
5559
}
5660

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,11 @@ export function AIChat() {
101101
</EmbeddableFrameButtons>
102102
</EmbeddableFrameHeader>
103103
<EmbeddableFrameBody>
104-
<AIChatBody chatController={chatController} chat={chat} />
104+
<AIChatBody
105+
chatController={chatController}
106+
chat={chat}
107+
suggestions={config.suggestions}
108+
/>
105109
</EmbeddableFrameBody>
106110
</EmbeddableFrameMain>
107111
</EmbeddableFrame>

packages/gitbook/src/components/Embeddable/EmbeddableRootLayout.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export async function EmbeddableRootLayout({
4141
>
4242
<AIContextProvider
4343
aiMode={context.customization.ai.mode}
44+
suggestions={context.customization.ai.suggestions}
4445
trademark={context.customization.trademark.enabled}
4546
>
4647
<SpaceLayoutServerContext

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export function SearchContainer({
5858
viewport,
5959
siteSpaces,
6060
}: SearchContainerProps) {
61-
const { assistants } = useAI();
61+
const { assistants, config } = useAI();
6262

6363
const [state, setSearchState] = useSearch();
6464
const searchAsk = useSearchAskState();
@@ -200,7 +200,8 @@ export function SearchContainer({
200200
siteSpaceId: siteSpace.id,
201201
siteSpaceIds,
202202
scope: state?.scope ?? 'default',
203-
withAI: withAI,
203+
withAI,
204+
suggestions: config.suggestions,
204205
});
205206
const searchValue = state?.query ?? (withSearchAI || !withAI ? state?.ask : null) ?? '';
206207

packages/gitbook/src/components/Search/useSearchResults.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,9 @@ export function useSearchResults(props: {
3535
siteSpaceIds: string[];
3636
scope: SearchScope;
3737
withAI: boolean;
38+
suggestions?: string[];
3839
}) {
39-
const { disabled, query, siteSpaceId, siteSpaceIds, scope } = props;
40+
const { disabled, query, siteSpaceId, siteSpaceIds, scope, suggestions } = props;
4041

4142
const trackEvent = useTrackEvent();
4243

@@ -78,6 +79,22 @@ export function useSearchResults(props: {
7879
const questions = new Set<string>();
7980
const recommendedQuestions: ResultType[] = [];
8081

82+
if (suggestions && suggestions.length > 0) {
83+
suggestions.forEach((question) => {
84+
questions.add(question);
85+
});
86+
setResultsState({
87+
results: suggestions.map((question, index) => ({
88+
type: 'recommended-question',
89+
id: `recommended-question-${index}`,
90+
question,
91+
})),
92+
fetching: false,
93+
error: false,
94+
});
95+
return;
96+
}
97+
8198
const timeout = setTimeout(async () => {
8299
if (cancelled) {
83100
return;
@@ -175,14 +192,14 @@ export function useSearchResults(props: {
175192
cancelled = true;
176193
clearTimeout(timeout);
177194
};
178-
}, [query, scope, trackEvent, withAI, siteSpaceId, siteSpaceIds, disabled]);
195+
}, [query, scope, trackEvent, withAI, siteSpaceId, siteSpaceIds, disabled, suggestions]);
179196

180197
const aiEnrichedResults: ResultType[] = React.useMemo(() => {
181198
if (!withAI) {
182199
return resultsState.results;
183200
}
184201
return withAskTriggers(resultsState.results, query, assistants);
185-
}, [resultsState.results, query, withAI]);
202+
}, [resultsState.results, query, withAI, assistants]);
186203

187204
return { ...resultsState, results: aiEnrichedResults };
188205
}

packages/gitbook/src/components/SiteLayout/SiteLayout.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ export async function SiteLayout(props: {
5656
>
5757
<AIContextProvider
5858
aiMode={customization.ai?.mode}
59+
suggestions={context.customization.ai?.suggestions}
5960
trademark={customization.trademark.enabled}
6061
>
6162
<SpaceLayout

0 commit comments

Comments
 (0)