@docusaurus/theme-search-algolia 3.8.1 → 3.9.0-canary-6403
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/client/index.d.ts +3 -1
- package/lib/client/index.js +3 -1
- package/lib/client/useAlgoliaAskAi.d.ts +32 -0
- package/lib/client/useAlgoliaAskAi.js +59 -0
- package/lib/client/useAlgoliaContextualFacetFilters.d.ts +3 -1
- package/lib/client/useAlgoliaContextualFacetFilters.js +11 -0
- package/lib/client/utils.d.ts +9 -0
- package/lib/client/utils.js +21 -0
- package/lib/docSearchVersion.d.ts +7 -0
- package/lib/docSearchVersion.js +13 -0
- package/lib/index.js +20 -0
- package/lib/theme/SearchBar/index.js +12 -12
- package/lib/theme/SearchBar/styles.css +4 -0
- package/lib/theme/SearchPage/index.js +70 -25
- package/lib/theme/SearchPage/styles.module.css +12 -4
- package/lib/theme/SearchTranslations/index.d.ts +47 -0
- package/lib/theme/SearchTranslations/index.js +186 -31
- package/lib/validateThemeConfig.d.ts +4 -3
- package/lib/validateThemeConfig.js +66 -4
- package/package.json +14 -14
- package/src/client/index.ts +6 -1
- package/src/client/useAlgoliaAskAi.ts +108 -0
- package/src/client/useAlgoliaContextualFacetFilters.ts +17 -1
- package/src/client/utils.ts +40 -0
- package/src/docSearchVersion.ts +12 -0
- package/src/index.ts +21 -0
- package/src/theme/SearchBar/index.tsx +41 -24
- package/src/theme/SearchBar/styles.css +4 -0
- package/src/theme/SearchPage/index.tsx +71 -25
- package/src/theme/SearchPage/styles.module.css +12 -4
- package/src/theme/SearchTranslations/index.ts +237 -32
- package/src/theme-search-algolia.d.ts +51 -16
- package/src/validateThemeConfig.ts +87 -9
|
@@ -9,7 +9,62 @@ import {translate} from '@docusaurus/Translate';
|
|
|
9
9
|
|
|
10
10
|
import type {DocSearchTranslations} from '@docsearch/react';
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
// TODO Docusaurus v4: require DocSearch v4
|
|
13
|
+
// This needs to be cleaned after the upgrade
|
|
14
|
+
// Docusaurus v3 was made compatible with both DocSearch v3 and v4
|
|
15
|
+
// This implies that labels have been kept retro-compatible with v3
|
|
16
|
+
// Once we upgrade, we should be able to rely on v4 types only
|
|
17
|
+
// and remove v3 retro-compatibility labels that do not exist anymore in v4
|
|
18
|
+
const translations: DocSearchTranslations & {
|
|
19
|
+
placeholder: string;
|
|
20
|
+
modal: {
|
|
21
|
+
searchBox: {
|
|
22
|
+
placeholderText: string;
|
|
23
|
+
placeholderTextAskAi: string;
|
|
24
|
+
placeholderTextAskAiStreaming: string;
|
|
25
|
+
enterKeyHintAskAi: string;
|
|
26
|
+
searchInputLabel: string;
|
|
27
|
+
backToKeywordSearchButtonText: string;
|
|
28
|
+
backToKeywordSearchButtonAriaLabel: string;
|
|
29
|
+
enterKeyHint: string;
|
|
30
|
+
clearButtonTitle: string;
|
|
31
|
+
clearButtonAriaLabel: string;
|
|
32
|
+
closeButtonText: string;
|
|
33
|
+
resetButtonTitle: string;
|
|
34
|
+
resetButtonAriaLabel: string;
|
|
35
|
+
cancelButtonText: string;
|
|
36
|
+
cancelButtonAriaLabel: string;
|
|
37
|
+
closeButtonAriaLabel: string;
|
|
38
|
+
};
|
|
39
|
+
startScreen: {
|
|
40
|
+
recentConversationsTitle: string;
|
|
41
|
+
removeRecentConversationButtonTitle: string;
|
|
42
|
+
};
|
|
43
|
+
resultsScreen: {
|
|
44
|
+
askAiPlaceholder: string;
|
|
45
|
+
};
|
|
46
|
+
askAiScreen: {
|
|
47
|
+
disclaimerText: string;
|
|
48
|
+
relatedSourcesText: string;
|
|
49
|
+
thinkingText: string;
|
|
50
|
+
copyButtonText: string;
|
|
51
|
+
copyButtonCopiedText: string;
|
|
52
|
+
copyButtonTitle: string;
|
|
53
|
+
likeButtonTitle: string;
|
|
54
|
+
dislikeButtonTitle: string;
|
|
55
|
+
thanksForFeedbackText: string;
|
|
56
|
+
preToolCallText: string;
|
|
57
|
+
duringToolCallText: string;
|
|
58
|
+
afterToolCallText: string;
|
|
59
|
+
};
|
|
60
|
+
footer: {
|
|
61
|
+
submitQuestionText: string;
|
|
62
|
+
poweredByText: string;
|
|
63
|
+
backToSearchText: string;
|
|
64
|
+
searchByText: string;
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
} = {
|
|
13
68
|
button: {
|
|
14
69
|
buttonText: translate({
|
|
15
70
|
id: 'theme.SearchBar.label',
|
|
@@ -44,6 +99,69 @@ const translations: DocSearchTranslations & {placeholder: string} = {
|
|
|
44
99
|
message: 'Cancel',
|
|
45
100
|
description: 'The label and ARIA label for search box cancel button',
|
|
46
101
|
}),
|
|
102
|
+
|
|
103
|
+
// v4
|
|
104
|
+
clearButtonTitle: translate({
|
|
105
|
+
id: 'theme.SearchModal.searchBox.resetButtonTitle',
|
|
106
|
+
message: 'Clear the query',
|
|
107
|
+
description: 'The label and ARIA label for search box reset button',
|
|
108
|
+
}),
|
|
109
|
+
clearButtonAriaLabel: translate({
|
|
110
|
+
id: 'theme.SearchModal.searchBox.resetButtonTitle',
|
|
111
|
+
message: 'Clear the query',
|
|
112
|
+
description: 'The label and ARIA label for search box reset button',
|
|
113
|
+
}),
|
|
114
|
+
closeButtonText: translate({
|
|
115
|
+
id: 'theme.SearchModal.searchBox.cancelButtonText',
|
|
116
|
+
message: 'Cancel',
|
|
117
|
+
description: 'The label and ARIA label for search box cancel button',
|
|
118
|
+
}),
|
|
119
|
+
closeButtonAriaLabel: translate({
|
|
120
|
+
id: 'theme.SearchModal.searchBox.cancelButtonText',
|
|
121
|
+
message: 'Cancel',
|
|
122
|
+
description: 'The label and ARIA label for search box cancel button',
|
|
123
|
+
}),
|
|
124
|
+
placeholderText: translate({
|
|
125
|
+
id: 'theme.SearchModal.searchBox.placeholderText',
|
|
126
|
+
message: 'Search docs',
|
|
127
|
+
description: 'The placeholder text for the main search input field',
|
|
128
|
+
}),
|
|
129
|
+
placeholderTextAskAi: translate({
|
|
130
|
+
id: 'theme.SearchModal.searchBox.placeholderTextAskAi',
|
|
131
|
+
message: 'Ask another question...',
|
|
132
|
+
description: 'The placeholder text when in AI question mode',
|
|
133
|
+
}),
|
|
134
|
+
placeholderTextAskAiStreaming: translate({
|
|
135
|
+
id: 'theme.SearchModal.searchBox.placeholderTextAskAiStreaming',
|
|
136
|
+
message: 'Answering...',
|
|
137
|
+
description:
|
|
138
|
+
'The placeholder text for search box when AI is streaming an answer',
|
|
139
|
+
}),
|
|
140
|
+
enterKeyHint: translate({
|
|
141
|
+
id: 'theme.SearchModal.searchBox.enterKeyHint',
|
|
142
|
+
message: 'search',
|
|
143
|
+
description: 'The hint for the search box enter key text',
|
|
144
|
+
}),
|
|
145
|
+
enterKeyHintAskAi: translate({
|
|
146
|
+
id: 'theme.SearchModal.searchBox.enterKeyHintAskAi',
|
|
147
|
+
message: 'enter',
|
|
148
|
+
description: 'The hint for the Ask AI search box enter key text',
|
|
149
|
+
}),
|
|
150
|
+
searchInputLabel: translate({
|
|
151
|
+
id: 'theme.SearchModal.searchBox.searchInputLabel',
|
|
152
|
+
message: 'Search',
|
|
153
|
+
description: 'The ARIA label for search input',
|
|
154
|
+
}),
|
|
155
|
+
backToKeywordSearchButtonText: translate({
|
|
156
|
+
id: 'theme.SearchModal.searchBox.backToKeywordSearchButtonText',
|
|
157
|
+
message: 'Back to keyword search',
|
|
158
|
+
description: 'The text for back to keyword search button',
|
|
159
|
+
}),
|
|
160
|
+
backToKeywordSearchButtonAriaLabel: translate({
|
|
161
|
+
id: 'theme.SearchModal.searchBox.backToKeywordSearchButtonAriaLabel',
|
|
162
|
+
message: 'Back to keyword search',
|
|
163
|
+
description: 'The ARIA label for back to keyword search button',
|
|
164
|
+
}),
|
|
47
165
|
},
|
|
48
166
|
startScreen: {
|
|
49
167
|
recentSearchesTitle: translate({
|
|
@@ -54,17 +172,17 @@ const translations: DocSearchTranslations & {placeholder: string} = {
|
|
|
54
172
|
noRecentSearchesText: translate({
|
|
55
173
|
id: 'theme.SearchModal.startScreen.noRecentSearchesText',
|
|
56
174
|
message: 'No recent searches',
|
|
57
|
-
description: 'The text when no recent searches',
|
|
175
|
+
description: 'The text when there are no recent searches',
|
|
58
176
|
}),
|
|
59
177
|
saveRecentSearchButtonTitle: translate({
|
|
60
178
|
id: 'theme.SearchModal.startScreen.saveRecentSearchButtonTitle',
|
|
61
179
|
message: 'Save this search',
|
|
62
|
-
description: 'The
|
|
180
|
+
description: 'The title for save recent search button',
|
|
63
181
|
}),
|
|
64
182
|
removeRecentSearchButtonTitle: translate({
|
|
65
183
|
id: 'theme.SearchModal.startScreen.removeRecentSearchButtonTitle',
|
|
66
184
|
message: 'Remove this search from history',
|
|
67
|
-
description: 'The
|
|
185
|
+
description: 'The title for remove recent search button',
|
|
68
186
|
}),
|
|
69
187
|
favoriteSearchesTitle: translate({
|
|
70
188
|
id: 'theme.SearchModal.startScreen.favoriteSearchesTitle',
|
|
@@ -74,91 +192,178 @@ const translations: DocSearchTranslations & {placeholder: string} = {
|
|
|
74
192
|
removeFavoriteSearchButtonTitle: translate({
|
|
75
193
|
id: 'theme.SearchModal.startScreen.removeFavoriteSearchButtonTitle',
|
|
76
194
|
message: 'Remove this search from favorites',
|
|
77
|
-
description: 'The
|
|
195
|
+
description: 'The title for remove favorite search button',
|
|
196
|
+
}),
|
|
197
|
+
recentConversationsTitle: translate({
|
|
198
|
+
id: 'theme.SearchModal.startScreen.recentConversationsTitle',
|
|
199
|
+
message: 'Recent conversations',
|
|
200
|
+
description: 'The title for recent conversations',
|
|
201
|
+
}),
|
|
202
|
+
removeRecentConversationButtonTitle: translate({
|
|
203
|
+
id: 'theme.SearchModal.startScreen.removeRecentConversationButtonTitle',
|
|
204
|
+
message: 'Remove this conversation from history',
|
|
205
|
+
description: 'The title for remove recent conversation button',
|
|
78
206
|
}),
|
|
79
207
|
},
|
|
80
208
|
errorScreen: {
|
|
81
209
|
titleText: translate({
|
|
82
210
|
id: 'theme.SearchModal.errorScreen.titleText',
|
|
83
211
|
message: 'Unable to fetch results',
|
|
84
|
-
description: 'The title for error screen
|
|
212
|
+
description: 'The title for error screen',
|
|
85
213
|
}),
|
|
86
214
|
helpText: translate({
|
|
87
215
|
id: 'theme.SearchModal.errorScreen.helpText',
|
|
88
216
|
message: 'You might want to check your network connection.',
|
|
89
|
-
description: 'The help text for error screen
|
|
217
|
+
description: 'The help text for error screen',
|
|
218
|
+
}),
|
|
219
|
+
},
|
|
220
|
+
resultsScreen: {
|
|
221
|
+
askAiPlaceholder: translate({
|
|
222
|
+
id: 'theme.SearchModal.resultsScreen.askAiPlaceholder',
|
|
223
|
+
message: 'Ask AI: ',
|
|
224
|
+
description: 'The placeholder text for Ask AI input',
|
|
225
|
+
}),
|
|
226
|
+
},
|
|
227
|
+
askAiScreen: {
|
|
228
|
+
disclaimerText: translate({
|
|
229
|
+
id: 'theme.SearchModal.askAiScreen.disclaimerText',
|
|
230
|
+
message:
|
|
231
|
+
'Answers are generated with AI which can make mistakes. Verify responses.',
|
|
232
|
+
description: 'The disclaimer text for AI answers',
|
|
233
|
+
}),
|
|
234
|
+
relatedSourcesText: translate({
|
|
235
|
+
id: 'theme.SearchModal.askAiScreen.relatedSourcesText',
|
|
236
|
+
message: 'Related sources',
|
|
237
|
+
description: 'The text for related sources',
|
|
238
|
+
}),
|
|
239
|
+
thinkingText: translate({
|
|
240
|
+
id: 'theme.SearchModal.askAiScreen.thinkingText',
|
|
241
|
+
message: 'Thinking...',
|
|
242
|
+
description: 'The text when AI is thinking',
|
|
243
|
+
}),
|
|
244
|
+
copyButtonText: translate({
|
|
245
|
+
id: 'theme.SearchModal.askAiScreen.copyButtonText',
|
|
246
|
+
message: 'Copy',
|
|
247
|
+
description: 'The text for copy button',
|
|
248
|
+
}),
|
|
249
|
+
copyButtonCopiedText: translate({
|
|
250
|
+
id: 'theme.SearchModal.askAiScreen.copyButtonCopiedText',
|
|
251
|
+
message: 'Copied!',
|
|
252
|
+
description: 'The text for copy button when copied',
|
|
253
|
+
}),
|
|
254
|
+
copyButtonTitle: translate({
|
|
255
|
+
id: 'theme.SearchModal.askAiScreen.copyButtonTitle',
|
|
256
|
+
message: 'Copy',
|
|
257
|
+
description: 'The title for copy button',
|
|
258
|
+
}),
|
|
259
|
+
likeButtonTitle: translate({
|
|
260
|
+
id: 'theme.SearchModal.askAiScreen.likeButtonTitle',
|
|
261
|
+
message: 'Like',
|
|
262
|
+
description: 'The title for like button',
|
|
263
|
+
}),
|
|
264
|
+
dislikeButtonTitle: translate({
|
|
265
|
+
id: 'theme.SearchModal.askAiScreen.dislikeButtonTitle',
|
|
266
|
+
message: 'Dislike',
|
|
267
|
+
description: 'The title for dislike button',
|
|
268
|
+
}),
|
|
269
|
+
thanksForFeedbackText: translate({
|
|
270
|
+
id: 'theme.SearchModal.askAiScreen.thanksForFeedbackText',
|
|
271
|
+
message: 'Thanks for your feedback!',
|
|
272
|
+
description: 'The text for thanks for feedback',
|
|
273
|
+
}),
|
|
274
|
+
preToolCallText: translate({
|
|
275
|
+
id: 'theme.SearchModal.askAiScreen.preToolCallText',
|
|
276
|
+
message: 'Searching...',
|
|
277
|
+
description: 'The text before tool call',
|
|
278
|
+
}),
|
|
279
|
+
duringToolCallText: translate({
|
|
280
|
+
id: 'theme.SearchModal.askAiScreen.duringToolCallText',
|
|
281
|
+
message: 'Searching for ',
|
|
282
|
+
description: 'The text during tool call',
|
|
283
|
+
}),
|
|
284
|
+
afterToolCallText: translate({
|
|
285
|
+
id: 'theme.SearchModal.askAiScreen.afterToolCallText',
|
|
286
|
+
message: 'Searched for',
|
|
287
|
+
description: 'The text after tool call',
|
|
90
288
|
}),
|
|
91
289
|
},
|
|
92
290
|
footer: {
|
|
93
291
|
selectText: translate({
|
|
94
292
|
id: 'theme.SearchModal.footer.selectText',
|
|
95
|
-
message: '
|
|
96
|
-
description: 'The
|
|
293
|
+
message: 'Select',
|
|
294
|
+
description: 'The select text for footer',
|
|
295
|
+
}),
|
|
296
|
+
submitQuestionText: translate({
|
|
297
|
+
id: 'theme.SearchModal.footer.submitQuestionText',
|
|
298
|
+
message: 'Submit question',
|
|
299
|
+
description: 'The submit question text for footer',
|
|
97
300
|
}),
|
|
98
301
|
selectKeyAriaLabel: translate({
|
|
99
302
|
id: 'theme.SearchModal.footer.selectKeyAriaLabel',
|
|
100
303
|
message: 'Enter key',
|
|
101
|
-
description:
|
|
102
|
-
'The ARIA label for the Enter key button that makes the selection',
|
|
304
|
+
description: 'The ARIA label for select key in footer',
|
|
103
305
|
}),
|
|
104
306
|
navigateText: translate({
|
|
105
307
|
id: 'theme.SearchModal.footer.navigateText',
|
|
106
|
-
message: '
|
|
107
|
-
description:
|
|
108
|
-
'The explanatory text of the action for the Arrow up and Arrow down key',
|
|
308
|
+
message: 'Navigate',
|
|
309
|
+
description: 'The navigate text for footer',
|
|
109
310
|
}),
|
|
110
311
|
navigateUpKeyAriaLabel: translate({
|
|
111
312
|
id: 'theme.SearchModal.footer.navigateUpKeyAriaLabel',
|
|
112
313
|
message: 'Arrow up',
|
|
113
|
-
description:
|
|
114
|
-
'The ARIA label for the Arrow up key button that makes the navigation',
|
|
314
|
+
description: 'The ARIA label for navigate up key in footer',
|
|
115
315
|
}),
|
|
116
316
|
navigateDownKeyAriaLabel: translate({
|
|
117
317
|
id: 'theme.SearchModal.footer.navigateDownKeyAriaLabel',
|
|
118
318
|
message: 'Arrow down',
|
|
119
|
-
description:
|
|
120
|
-
'The ARIA label for the Arrow down key button that makes the navigation',
|
|
319
|
+
description: 'The ARIA label for navigate down key in footer',
|
|
121
320
|
}),
|
|
122
321
|
closeText: translate({
|
|
123
322
|
id: 'theme.SearchModal.footer.closeText',
|
|
124
|
-
message: '
|
|
125
|
-
description: 'The
|
|
323
|
+
message: 'Close',
|
|
324
|
+
description: 'The close text for footer',
|
|
126
325
|
}),
|
|
127
326
|
closeKeyAriaLabel: translate({
|
|
128
327
|
id: 'theme.SearchModal.footer.closeKeyAriaLabel',
|
|
129
328
|
message: 'Escape key',
|
|
130
|
-
description:
|
|
131
|
-
|
|
329
|
+
description: 'The ARIA label for close key in footer',
|
|
330
|
+
}),
|
|
331
|
+
poweredByText: translate({
|
|
332
|
+
id: 'theme.SearchModal.footer.searchByText',
|
|
333
|
+
message: 'Powered by',
|
|
334
|
+
description: "The 'Powered by' text for footer",
|
|
132
335
|
}),
|
|
133
336
|
searchByText: translate({
|
|
134
337
|
id: 'theme.SearchModal.footer.searchByText',
|
|
135
|
-
message: '
|
|
136
|
-
description:
|
|
338
|
+
message: 'Powered by',
|
|
339
|
+
description: "The 'Powered by' text for footer",
|
|
340
|
+
}),
|
|
341
|
+
backToSearchText: translate({
|
|
342
|
+
id: 'theme.SearchModal.footer.backToSearchText',
|
|
343
|
+
message: 'Back to search',
|
|
344
|
+
description: 'The back to search text for footer',
|
|
137
345
|
}),
|
|
138
346
|
},
|
|
139
347
|
noResultsScreen: {
|
|
140
348
|
noResultsText: translate({
|
|
141
349
|
id: 'theme.SearchModal.noResultsScreen.noResultsText',
|
|
142
|
-
message: 'No results for',
|
|
143
|
-
description:
|
|
144
|
-
'The text explains that there are no results for the following search',
|
|
350
|
+
message: 'No results found for',
|
|
351
|
+
description: 'The text when there are no results',
|
|
145
352
|
}),
|
|
146
353
|
suggestedQueryText: translate({
|
|
147
354
|
id: 'theme.SearchModal.noResultsScreen.suggestedQueryText',
|
|
148
355
|
message: 'Try searching for',
|
|
149
|
-
description:
|
|
150
|
-
'The text for the suggested query when no results are found for the following search',
|
|
356
|
+
description: 'The text for suggested query',
|
|
151
357
|
}),
|
|
152
358
|
reportMissingResultsText: translate({
|
|
153
359
|
id: 'theme.SearchModal.noResultsScreen.reportMissingResultsText',
|
|
154
360
|
message: 'Believe this query should return results?',
|
|
155
|
-
description:
|
|
156
|
-
'The text for the question where the user thinks there are missing results',
|
|
361
|
+
description: 'The text for reporting missing results',
|
|
157
362
|
}),
|
|
158
363
|
reportMissingResultsLinkText: translate({
|
|
159
364
|
id: 'theme.SearchModal.noResultsScreen.reportMissingResultsLinkText',
|
|
160
365
|
message: 'Let us know.',
|
|
161
|
-
description: 'The text for
|
|
366
|
+
description: 'The link text for reporting missing results',
|
|
162
367
|
}),
|
|
163
368
|
},
|
|
164
369
|
},
|
|
@@ -5,9 +5,27 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
// TODO Docusaurus v4: remove after we drop support for DocSearch v3
|
|
9
|
+
declare module '@docsearch/react/button';
|
|
10
|
+
declare module '@docsearch/react/useDocSearchKeyboardEvents';
|
|
11
|
+
declare module '@docsearch/react/version';
|
|
12
|
+
|
|
8
13
|
declare module '@docusaurus/theme-search-algolia' {
|
|
9
|
-
import type {DeepPartial} from 'utility-types';
|
|
14
|
+
import type {DeepPartial, Overwrite} from 'utility-types';
|
|
15
|
+
|
|
10
16
|
import type {DocSearchProps} from '@docsearch/react';
|
|
17
|
+
import type {FacetFilters} from 'algoliasearch/lite';
|
|
18
|
+
|
|
19
|
+
// The config after normalization (e.g. AskAI string -> object)
|
|
20
|
+
export type AskAiConfig = {
|
|
21
|
+
indexName: string;
|
|
22
|
+
apiKey: string;
|
|
23
|
+
appId: string;
|
|
24
|
+
assistantId: string;
|
|
25
|
+
searchParameters?: {
|
|
26
|
+
facetFilters?: FacetFilters;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
11
29
|
|
|
12
30
|
// DocSearch props that Docusaurus exposes directly through props forwarding
|
|
13
31
|
type DocusaurusDocSearchProps = Pick<
|
|
@@ -20,9 +38,15 @@ declare module '@docusaurus/theme-search-algolia' {
|
|
|
20
38
|
| 'searchParameters'
|
|
21
39
|
| 'insights'
|
|
22
40
|
| 'initialQuery'
|
|
23
|
-
|
|
41
|
+
> & {
|
|
42
|
+
// Docusaurus normalizes the AskAI config to an object
|
|
43
|
+
askAi?: AskAiConfig;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export type ThemeConfigAlgolia = DocusaurusDocSearchProps & {
|
|
47
|
+
// TODO Docusaurus v4: upgrade to DocSearch v4, migrate indexName to indices
|
|
48
|
+
indexName: string;
|
|
24
49
|
|
|
25
|
-
type ThemeConfigAlgolia = DocusaurusDocSearchProps & {
|
|
26
50
|
// Docusaurus custom options, not coming from DocSearch
|
|
27
51
|
contextualSearch: boolean;
|
|
28
52
|
externalUrlRegex?: string;
|
|
@@ -33,21 +57,23 @@ declare module '@docusaurus/theme-search-algolia' {
|
|
|
33
57
|
};
|
|
34
58
|
};
|
|
35
59
|
|
|
36
|
-
export type ThemeConfig =
|
|
60
|
+
export type ThemeConfig = {
|
|
37
61
|
algolia: ThemeConfigAlgolia;
|
|
38
62
|
};
|
|
39
63
|
|
|
40
|
-
export type UserThemeConfig =
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
64
|
+
export type UserThemeConfig = {
|
|
65
|
+
algolia?: Overwrite<
|
|
66
|
+
DeepPartial<ThemeConfigAlgolia>,
|
|
67
|
+
{
|
|
68
|
+
// Required fields:
|
|
69
|
+
appId: ThemeConfigAlgolia['appId'];
|
|
70
|
+
apiKey: ThemeConfigAlgolia['apiKey'];
|
|
71
|
+
indexName: ThemeConfigAlgolia['indexName'];
|
|
72
|
+
// askAi also accepts a shorter string form
|
|
73
|
+
askAi?: string | AskAiConfig;
|
|
74
|
+
}
|
|
75
|
+
>;
|
|
76
|
+
};
|
|
51
77
|
}
|
|
52
78
|
|
|
53
79
|
declare module '@theme/SearchPage' {
|
|
@@ -65,6 +91,15 @@ declare module '@theme/SearchBar' {
|
|
|
65
91
|
declare module '@theme/SearchTranslations' {
|
|
66
92
|
import type {DocSearchTranslations} from '@docsearch/react';
|
|
67
93
|
|
|
68
|
-
const translations: DocSearchTranslations & {
|
|
94
|
+
const translations: DocSearchTranslations & {
|
|
95
|
+
placeholder: string;
|
|
96
|
+
// TODO Docusaurus v4: cleanup after we drop support for DocSearch v3
|
|
97
|
+
modal?: {
|
|
98
|
+
searchBox?: {
|
|
99
|
+
placeholderText?: string;
|
|
100
|
+
placeholderTextAskAi?: string;
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
};
|
|
69
104
|
export default translations;
|
|
70
105
|
}
|
|
@@ -7,22 +7,27 @@
|
|
|
7
7
|
|
|
8
8
|
import {escapeRegexp} from '@docusaurus/utils';
|
|
9
9
|
import {Joi} from '@docusaurus/utils-validation';
|
|
10
|
+
import {docSearchV3} from './docSearchVersion';
|
|
11
|
+
import type {ThemeConfigValidationContext} from '@docusaurus/types';
|
|
10
12
|
import type {
|
|
11
13
|
ThemeConfig,
|
|
12
|
-
|
|
13
|
-
} from '@docusaurus/
|
|
14
|
+
ThemeConfigAlgolia,
|
|
15
|
+
} from '@docusaurus/theme-search-algolia';
|
|
14
16
|
|
|
15
17
|
export const DEFAULT_CONFIG = {
|
|
16
18
|
// Enabled by default, as it makes sense in most cases
|
|
17
19
|
// see also https://github.com/facebook/docusaurus/issues/5880
|
|
18
20
|
contextualSearch: true,
|
|
19
|
-
|
|
20
21
|
searchParameters: {},
|
|
21
22
|
searchPagePath: 'search',
|
|
22
|
-
}
|
|
23
|
+
} satisfies Partial<ThemeConfigAlgolia>;
|
|
24
|
+
|
|
25
|
+
const FacetFiltersSchema = Joi.array().items(
|
|
26
|
+
Joi.alternatives().try(Joi.string(), Joi.array().items(Joi.string())),
|
|
27
|
+
);
|
|
23
28
|
|
|
24
29
|
export const Schema = Joi.object<ThemeConfig>({
|
|
25
|
-
algolia: Joi.object({
|
|
30
|
+
algolia: Joi.object<ThemeConfigAlgolia>({
|
|
26
31
|
// Docusaurus attributes
|
|
27
32
|
contextualSearch: Joi.boolean().default(DEFAULT_CONFIG.contextualSearch),
|
|
28
33
|
externalUrlRegex: Joi.string().optional(),
|
|
@@ -33,7 +38,9 @@ export const Schema = Joi.object<ThemeConfig>({
|
|
|
33
38
|
}),
|
|
34
39
|
apiKey: Joi.string().required(),
|
|
35
40
|
indexName: Joi.string().required(),
|
|
36
|
-
searchParameters: Joi.object(
|
|
41
|
+
searchParameters: Joi.object({
|
|
42
|
+
facetFilters: FacetFiltersSchema.optional(),
|
|
43
|
+
})
|
|
37
44
|
.default(DEFAULT_CONFIG.searchParameters)
|
|
38
45
|
.unknown(),
|
|
39
46
|
searchPagePath: Joi.alternatives()
|
|
@@ -53,15 +60,86 @@ export const Schema = Joi.object<ThemeConfig>({
|
|
|
53
60
|
}).required(),
|
|
54
61
|
to: Joi.string().required(),
|
|
55
62
|
}).optional(),
|
|
63
|
+
// Ask AI configuration (DocSearch v4 only)
|
|
64
|
+
askAi: Joi.alternatives()
|
|
65
|
+
.try(
|
|
66
|
+
// Simple string format (assistantId only)
|
|
67
|
+
Joi.string(),
|
|
68
|
+
// Full configuration object
|
|
69
|
+
Joi.object({
|
|
70
|
+
indexName: Joi.string().required(),
|
|
71
|
+
apiKey: Joi.string().required(),
|
|
72
|
+
appId: Joi.string().required(),
|
|
73
|
+
assistantId: Joi.string().required(),
|
|
74
|
+
searchParameters: Joi.object({
|
|
75
|
+
facetFilters: FacetFiltersSchema.optional(),
|
|
76
|
+
}).optional(),
|
|
77
|
+
}),
|
|
78
|
+
)
|
|
79
|
+
.custom(
|
|
80
|
+
(
|
|
81
|
+
askAiInput: string | ThemeConfigAlgolia['askAi'] | undefined,
|
|
82
|
+
helpers,
|
|
83
|
+
) => {
|
|
84
|
+
if (!askAiInput) {
|
|
85
|
+
return askAiInput;
|
|
86
|
+
}
|
|
87
|
+
const algolia: ThemeConfigAlgolia = helpers.state.ancestors[0];
|
|
88
|
+
const algoliaFacetFilters = algolia.searchParameters?.facetFilters;
|
|
89
|
+
if (typeof askAiInput === 'string') {
|
|
90
|
+
return {
|
|
91
|
+
assistantId: askAiInput,
|
|
92
|
+
indexName: algolia.indexName,
|
|
93
|
+
apiKey: algolia.apiKey,
|
|
94
|
+
appId: algolia.appId,
|
|
95
|
+
...(algoliaFacetFilters
|
|
96
|
+
? {
|
|
97
|
+
searchParameters: {
|
|
98
|
+
facetFilters: algoliaFacetFilters,
|
|
99
|
+
},
|
|
100
|
+
}
|
|
101
|
+
: {}),
|
|
102
|
+
} satisfies ThemeConfigAlgolia['askAi'];
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (
|
|
106
|
+
askAiInput.searchParameters?.facetFilters === undefined &&
|
|
107
|
+
algoliaFacetFilters
|
|
108
|
+
) {
|
|
109
|
+
askAiInput.searchParameters = askAiInput.searchParameters ?? {};
|
|
110
|
+
askAiInput.searchParameters.facetFilters = algoliaFacetFilters;
|
|
111
|
+
}
|
|
112
|
+
return askAiInput;
|
|
113
|
+
},
|
|
114
|
+
)
|
|
115
|
+
.optional()
|
|
116
|
+
.messages({
|
|
117
|
+
'alternatives.types':
|
|
118
|
+
'askAi must be either a string (assistantId) or an object with indexName, apiKey, appId, and assistantId',
|
|
119
|
+
}),
|
|
56
120
|
})
|
|
57
121
|
.label('themeConfig.algolia')
|
|
58
122
|
.required()
|
|
59
|
-
.unknown(),
|
|
123
|
+
.unknown(),
|
|
60
124
|
});
|
|
61
125
|
|
|
126
|
+
// TODO Docusaurus v4: remove this check when we drop DocSearch v3
|
|
127
|
+
function ensureAskAISupported(themeConfig: ThemeConfig) {
|
|
128
|
+
// enforce DocsSearch v4 requirement when AskAI is configured
|
|
129
|
+
if (themeConfig.algolia.askAi && docSearchV3) {
|
|
130
|
+
throw new Error(
|
|
131
|
+
'The askAi feature is only supported in DocSearch v4. ' +
|
|
132
|
+
'Please upgrade to DocSearch v4 by installing "@docsearch/react": "^4.0.0" ' +
|
|
133
|
+
'or remove the askAi configuration from your theme config.',
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
62
138
|
export function validateThemeConfig({
|
|
63
139
|
validate,
|
|
64
|
-
themeConfig,
|
|
140
|
+
themeConfig: themeConfigInput,
|
|
65
141
|
}: ThemeConfigValidationContext<ThemeConfig>): ThemeConfig {
|
|
66
|
-
|
|
142
|
+
const themeConfig = validate(Schema, themeConfigInput);
|
|
143
|
+
ensureAskAISupported(themeConfig);
|
|
144
|
+
return themeConfig;
|
|
67
145
|
}
|