@docusaurus/theme-search-algolia 2.2.0 → 2.3.0
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 +2 -0
- package/lib/client/index.js +2 -0
- package/lib/client/useAlgoliaThemeConfig.d.ts +2 -0
- package/lib/client/useAlgoliaThemeConfig.js +11 -0
- package/lib/client/useSearchResultUrlProcessor.d.ts +11 -0
- package/lib/client/useSearchResultUrlProcessor.js +33 -0
- package/lib/theme/SearchBar/index.js +19 -22
- package/lib/theme/SearchPage/index.js +15 -15
- package/lib/validateThemeConfig.js +13 -0
- package/package.json +10 -10
- package/src/client/index.ts +2 -0
- package/src/client/useAlgoliaThemeConfig.ts +15 -0
- package/src/client/useSearchResultUrlProcessor.ts +54 -0
- package/src/theme/SearchBar/index.tsx +20 -24
- package/src/theme/SearchPage/index.tsx +15 -17
- package/src/theme-search-algolia.d.ts +10 -0
- package/src/validateThemeConfig.ts +14 -0
package/lib/client/index.d.ts
CHANGED
|
@@ -4,4 +4,6 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
|
+
export { useAlgoliaThemeConfig } from './useAlgoliaThemeConfig';
|
|
7
8
|
export { useAlgoliaContextualFacetFilters } from './useAlgoliaContextualFacetFilters';
|
|
9
|
+
export { useSearchResultUrlProcessor } from './useSearchResultUrlProcessor';
|
package/lib/client/index.js
CHANGED
|
@@ -4,4 +4,6 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
|
+
export { useAlgoliaThemeConfig } from './useAlgoliaThemeConfig';
|
|
7
8
|
export { useAlgoliaContextualFacetFilters } from './useAlgoliaContextualFacetFilters';
|
|
9
|
+
export { useSearchResultUrlProcessor } from './useSearchResultUrlProcessor';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
|
8
|
+
export function useAlgoliaThemeConfig() {
|
|
9
|
+
const { siteConfig: { themeConfig }, } = useDocusaurusContext();
|
|
10
|
+
return themeConfig;
|
|
11
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Process the search result url from Algolia to its final form, ready to be
|
|
9
|
+
* navigated to or used as a link
|
|
10
|
+
*/
|
|
11
|
+
export declare function useSearchResultUrlProcessor(): (url: string) => string;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
import { useCallback } from 'react';
|
|
8
|
+
import { isRegexpStringMatch } from '@docusaurus/theme-common';
|
|
9
|
+
import { useBaseUrlUtils } from '@docusaurus/useBaseUrl';
|
|
10
|
+
import { useAlgoliaThemeConfig } from './useAlgoliaThemeConfig';
|
|
11
|
+
function replacePathname(pathname, replaceSearchResultPathname) {
|
|
12
|
+
return replaceSearchResultPathname
|
|
13
|
+
? pathname.replaceAll(new RegExp(replaceSearchResultPathname.from, 'g'), replaceSearchResultPathname.to)
|
|
14
|
+
: pathname;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Process the search result url from Algolia to its final form, ready to be
|
|
18
|
+
* navigated to or used as a link
|
|
19
|
+
*/
|
|
20
|
+
export function useSearchResultUrlProcessor() {
|
|
21
|
+
const { withBaseUrl } = useBaseUrlUtils();
|
|
22
|
+
const { algolia: { externalUrlRegex, replaceSearchResultPathname }, } = useAlgoliaThemeConfig();
|
|
23
|
+
return useCallback((url) => {
|
|
24
|
+
const parsedURL = new URL(url);
|
|
25
|
+
// Algolia contains an external domain => navigate to URL
|
|
26
|
+
if (isRegexpStringMatch(externalUrlRegex, parsedURL.href)) {
|
|
27
|
+
return url;
|
|
28
|
+
}
|
|
29
|
+
// Otherwise => transform to relative URL for SPA navigation
|
|
30
|
+
const relativeUrl = `${parsedURL.pathname + parsedURL.hash}`;
|
|
31
|
+
return withBaseUrl(replacePathname(relativeUrl, replaceSearchResultPathname));
|
|
32
|
+
}, [withBaseUrl, externalUrlRegex, replaceSearchResultPathname]);
|
|
33
|
+
}
|
|
@@ -4,18 +4,20 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
|
-
import React, {
|
|
8
|
-
import {
|
|
9
|
-
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
|
10
|
-
import {useHistory} from '@docusaurus/router';
|
|
11
|
-
import {useBaseUrlUtils} from '@docusaurus/useBaseUrl';
|
|
12
|
-
import Link from '@docusaurus/Link';
|
|
7
|
+
import React, {useCallback, useMemo, useRef, useState} from 'react';
|
|
8
|
+
import {DocSearchButton, useDocSearchKeyboardEvents} from '@docsearch/react';
|
|
13
9
|
import Head from '@docusaurus/Head';
|
|
10
|
+
import Link from '@docusaurus/Link';
|
|
11
|
+
import {useHistory} from '@docusaurus/router';
|
|
14
12
|
import {isRegexpStringMatch} from '@docusaurus/theme-common';
|
|
15
13
|
import {useSearchPage} from '@docusaurus/theme-common/internal';
|
|
16
|
-
import {
|
|
17
|
-
|
|
14
|
+
import {
|
|
15
|
+
useAlgoliaContextualFacetFilters,
|
|
16
|
+
useSearchResultUrlProcessor,
|
|
17
|
+
} from '@docusaurus/theme-search-algolia/client';
|
|
18
18
|
import Translate from '@docusaurus/Translate';
|
|
19
|
+
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
|
20
|
+
import {createPortal} from 'react-dom';
|
|
19
21
|
import translations from '@theme/SearchTranslations';
|
|
20
22
|
let DocSearchModal = null;
|
|
21
23
|
function Hit({hit, children}) {
|
|
@@ -39,6 +41,7 @@ function mergeFacetFilters(f1, f2) {
|
|
|
39
41
|
}
|
|
40
42
|
function DocSearch({contextualSearch, externalUrlRegex, ...props}) {
|
|
41
43
|
const {siteMetadata} = useDocusaurusContext();
|
|
44
|
+
const processSearchResultUrl = useSearchResultUrlProcessor();
|
|
42
45
|
const contextualSearchFacetFilters = useAlgoliaContextualFacetFilters();
|
|
43
46
|
const configFacetFilters = props.searchParameters?.facetFilters ?? [];
|
|
44
47
|
const facetFilters = contextualSearch
|
|
@@ -51,7 +54,6 @@ function DocSearch({contextualSearch, externalUrlRegex, ...props}) {
|
|
|
51
54
|
...props.searchParameters,
|
|
52
55
|
facetFilters,
|
|
53
56
|
};
|
|
54
|
-
const {withBaseUrl} = useBaseUrlUtils();
|
|
55
57
|
const history = useHistory();
|
|
56
58
|
const searchContainer = useRef(null);
|
|
57
59
|
const searchButtonRef = useRef(null);
|
|
@@ -104,19 +106,14 @@ function DocSearch({contextualSearch, externalUrlRegex, ...props}) {
|
|
|
104
106
|
},
|
|
105
107
|
}).current;
|
|
106
108
|
const transformItems = useRef((items) =>
|
|
107
|
-
|
|
108
|
-
//
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
return {
|
|
116
|
-
...item,
|
|
117
|
-
url: withBaseUrl(`${url.pathname}${url.hash}`),
|
|
118
|
-
};
|
|
119
|
-
}),
|
|
109
|
+
props.transformItems
|
|
110
|
+
? // Custom transformItems
|
|
111
|
+
props.transformItems(items)
|
|
112
|
+
: // Default transformItems
|
|
113
|
+
items.map((item) => ({
|
|
114
|
+
...item,
|
|
115
|
+
url: processSearchResultUrl(item.url),
|
|
116
|
+
})),
|
|
120
117
|
).current;
|
|
121
118
|
const resultsFooterComponent = useMemo(
|
|
122
119
|
() =>
|
|
@@ -5,26 +5,29 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
/* eslint-disable jsx-a11y/no-autofocus */
|
|
8
|
-
import React, {useEffect,
|
|
8
|
+
import React, {useEffect, useReducer, useRef, useState} from 'react';
|
|
9
9
|
import clsx from 'clsx';
|
|
10
|
-
import algoliaSearch from 'algoliasearch/lite';
|
|
11
10
|
import algoliaSearchHelper from 'algoliasearch-helper';
|
|
11
|
+
import algoliaSearch from 'algoliasearch/lite';
|
|
12
|
+
import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
|
|
12
13
|
import Head from '@docusaurus/Head';
|
|
13
14
|
import Link from '@docusaurus/Link';
|
|
14
|
-
import
|
|
15
|
+
import {useAllDocsData} from '@docusaurus/plugin-content-docs/client';
|
|
15
16
|
import {
|
|
16
17
|
HtmlClassNameProvider,
|
|
17
|
-
usePluralForm,
|
|
18
|
-
isRegexpStringMatch,
|
|
19
18
|
useEvent,
|
|
19
|
+
usePluralForm,
|
|
20
20
|
} from '@docusaurus/theme-common';
|
|
21
21
|
import {
|
|
22
|
-
useTitleFormatter,
|
|
23
22
|
useSearchPage,
|
|
23
|
+
useTitleFormatter,
|
|
24
24
|
} from '@docusaurus/theme-common/internal';
|
|
25
|
-
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
|
26
|
-
import {useAllDocsData} from '@docusaurus/plugin-content-docs/client';
|
|
27
25
|
import Translate, {translate} from '@docusaurus/Translate';
|
|
26
|
+
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
|
27
|
+
import {
|
|
28
|
+
useAlgoliaThemeConfig,
|
|
29
|
+
useSearchResultUrlProcessor,
|
|
30
|
+
} from '@docusaurus/theme-search-algolia/client';
|
|
28
31
|
import Layout from '@theme/Layout';
|
|
29
32
|
import styles from './styles.module.css';
|
|
30
33
|
// Very simple pluralization: probably good enough for now
|
|
@@ -114,12 +117,12 @@ function SearchVersionSelectList({docsSearchVersionsHelpers}) {
|
|
|
114
117
|
}
|
|
115
118
|
function SearchPageContent() {
|
|
116
119
|
const {
|
|
117
|
-
siteConfig: {themeConfig},
|
|
118
120
|
i18n: {currentLocale},
|
|
119
121
|
} = useDocusaurusContext();
|
|
120
122
|
const {
|
|
121
|
-
algolia: {appId, apiKey, indexName
|
|
122
|
-
} =
|
|
123
|
+
algolia: {appId, apiKey, indexName},
|
|
124
|
+
} = useAlgoliaThemeConfig();
|
|
125
|
+
const processSearchResultUrl = useSearchResultUrlProcessor();
|
|
123
126
|
const documentsFoundPlural = useDocumentsFoundPlural();
|
|
124
127
|
const docsSearchVersionsHelpers = useDocsSearchVersionsHelpers();
|
|
125
128
|
const {searchQuery, setSearchQuery} = useSearchPage();
|
|
@@ -191,15 +194,12 @@ function SearchPageContent() {
|
|
|
191
194
|
_highlightResult: {hierarchy},
|
|
192
195
|
_snippetResult: snippet = {},
|
|
193
196
|
}) => {
|
|
194
|
-
const parsedURL = new URL(url);
|
|
195
197
|
const titles = Object.keys(hierarchy).map((key) =>
|
|
196
198
|
sanitizeValue(hierarchy[key].value),
|
|
197
199
|
);
|
|
198
200
|
return {
|
|
199
201
|
title: titles.pop(),
|
|
200
|
-
url:
|
|
201
|
-
? parsedURL.href
|
|
202
|
-
: parsedURL.pathname + parsedURL.hash,
|
|
202
|
+
url: processSearchResultUrl(url),
|
|
203
203
|
summary: snippet.content
|
|
204
204
|
? `${sanitizeValue(snippet.content.value)}...`
|
|
205
205
|
: '',
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.validateThemeConfig = exports.Schema = exports.DEFAULT_CONFIG = void 0;
|
|
10
|
+
const utils_1 = require("@docusaurus/utils");
|
|
10
11
|
const utils_validation_1 = require("@docusaurus/utils-validation");
|
|
11
12
|
exports.DEFAULT_CONFIG = {
|
|
12
13
|
// Enabled by default, as it makes sense in most cases
|
|
@@ -33,6 +34,18 @@ exports.Schema = utils_validation_1.Joi.object({
|
|
|
33
34
|
.try(utils_validation_1.Joi.boolean().invalid(true), utils_validation_1.Joi.string())
|
|
34
35
|
.allow(null)
|
|
35
36
|
.default(exports.DEFAULT_CONFIG.searchPagePath),
|
|
37
|
+
replaceSearchResultPathname: utils_validation_1.Joi.object({
|
|
38
|
+
from: utils_validation_1.Joi.custom((from) => {
|
|
39
|
+
if (typeof from === 'string') {
|
|
40
|
+
return (0, utils_1.escapeRegexp)(from);
|
|
41
|
+
}
|
|
42
|
+
else if (from instanceof RegExp) {
|
|
43
|
+
return from.source;
|
|
44
|
+
}
|
|
45
|
+
throw new Error(`it should be a RegExp or a string, but received ${from}`);
|
|
46
|
+
}).required(),
|
|
47
|
+
to: utils_validation_1.Joi.string().required(),
|
|
48
|
+
}).optional(),
|
|
36
49
|
})
|
|
37
50
|
.label('themeConfig.algolia')
|
|
38
51
|
.required()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@docusaurus/theme-search-algolia",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "Algolia search component for Docusaurus.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"sideEffects": [
|
|
@@ -34,13 +34,13 @@
|
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@docsearch/react": "^3.1.1",
|
|
37
|
-
"@docusaurus/core": "2.
|
|
38
|
-
"@docusaurus/logger": "2.
|
|
39
|
-
"@docusaurus/plugin-content-docs": "2.
|
|
40
|
-
"@docusaurus/theme-common": "2.
|
|
41
|
-
"@docusaurus/theme-translations": "2.
|
|
42
|
-
"@docusaurus/utils": "2.
|
|
43
|
-
"@docusaurus/utils-validation": "2.
|
|
37
|
+
"@docusaurus/core": "2.3.0",
|
|
38
|
+
"@docusaurus/logger": "2.3.0",
|
|
39
|
+
"@docusaurus/plugin-content-docs": "2.3.0",
|
|
40
|
+
"@docusaurus/theme-common": "2.3.0",
|
|
41
|
+
"@docusaurus/theme-translations": "2.3.0",
|
|
42
|
+
"@docusaurus/utils": "2.3.0",
|
|
43
|
+
"@docusaurus/utils-validation": "2.3.0",
|
|
44
44
|
"algoliasearch": "^4.13.1",
|
|
45
45
|
"algoliasearch-helper": "^3.10.0",
|
|
46
46
|
"clsx": "^1.2.1",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"utility-types": "^3.10.0"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@docusaurus/module-type-aliases": "2.
|
|
54
|
+
"@docusaurus/module-type-aliases": "2.3.0"
|
|
55
55
|
},
|
|
56
56
|
"peerDependencies": {
|
|
57
57
|
"react": "^16.8.4 || ^17.0.0",
|
|
@@ -60,5 +60,5 @@
|
|
|
60
60
|
"engines": {
|
|
61
61
|
"node": ">=16.14"
|
|
62
62
|
},
|
|
63
|
-
"gitHead": "
|
|
63
|
+
"gitHead": "ad477781bdca6a11fa9c6daef5048bdcec0ee37e"
|
|
64
64
|
}
|
package/src/client/index.ts
CHANGED
|
@@ -5,4 +5,6 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
export {useAlgoliaThemeConfig} from './useAlgoliaThemeConfig';
|
|
8
9
|
export {useAlgoliaContextualFacetFilters} from './useAlgoliaContextualFacetFilters';
|
|
10
|
+
export {useSearchResultUrlProcessor} from './useSearchResultUrlProcessor';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
|
8
|
+
import type {ThemeConfig} from '@docusaurus/theme-search-algolia';
|
|
9
|
+
|
|
10
|
+
export function useAlgoliaThemeConfig(): ThemeConfig {
|
|
11
|
+
const {
|
|
12
|
+
siteConfig: {themeConfig},
|
|
13
|
+
} = useDocusaurusContext();
|
|
14
|
+
return themeConfig as ThemeConfig;
|
|
15
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {useCallback} from 'react';
|
|
9
|
+
import {isRegexpStringMatch} from '@docusaurus/theme-common';
|
|
10
|
+
import {useBaseUrlUtils} from '@docusaurus/useBaseUrl';
|
|
11
|
+
import {useAlgoliaThemeConfig} from './useAlgoliaThemeConfig';
|
|
12
|
+
import type {ThemeConfig} from '@docusaurus/theme-search-algolia';
|
|
13
|
+
|
|
14
|
+
function replacePathname(
|
|
15
|
+
pathname: string,
|
|
16
|
+
replaceSearchResultPathname: ThemeConfig['algolia']['replaceSearchResultPathname'],
|
|
17
|
+
): string {
|
|
18
|
+
return replaceSearchResultPathname
|
|
19
|
+
? pathname.replaceAll(
|
|
20
|
+
new RegExp(replaceSearchResultPathname.from, 'g'),
|
|
21
|
+
replaceSearchResultPathname.to,
|
|
22
|
+
)
|
|
23
|
+
: pathname;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Process the search result url from Algolia to its final form, ready to be
|
|
28
|
+
* navigated to or used as a link
|
|
29
|
+
*/
|
|
30
|
+
export function useSearchResultUrlProcessor(): (url: string) => string {
|
|
31
|
+
const {withBaseUrl} = useBaseUrlUtils();
|
|
32
|
+
const {
|
|
33
|
+
algolia: {externalUrlRegex, replaceSearchResultPathname},
|
|
34
|
+
} = useAlgoliaThemeConfig();
|
|
35
|
+
|
|
36
|
+
return useCallback(
|
|
37
|
+
(url: string) => {
|
|
38
|
+
const parsedURL = new URL(url);
|
|
39
|
+
|
|
40
|
+
// Algolia contains an external domain => navigate to URL
|
|
41
|
+
if (isRegexpStringMatch(externalUrlRegex, parsedURL.href)) {
|
|
42
|
+
return url;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Otherwise => transform to relative URL for SPA navigation
|
|
46
|
+
const relativeUrl = `${parsedURL.pathname + parsedURL.hash}`;
|
|
47
|
+
|
|
48
|
+
return withBaseUrl(
|
|
49
|
+
replacePathname(relativeUrl, replaceSearchResultPathname),
|
|
50
|
+
);
|
|
51
|
+
},
|
|
52
|
+
[withBaseUrl, externalUrlRegex, replaceSearchResultPathname],
|
|
53
|
+
);
|
|
54
|
+
}
|
|
@@ -5,20 +5,23 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import React, {
|
|
9
|
-
import {
|
|
10
|
-
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
|
11
|
-
import {useHistory} from '@docusaurus/router';
|
|
12
|
-
import {useBaseUrlUtils} from '@docusaurus/useBaseUrl';
|
|
13
|
-
import Link from '@docusaurus/Link';
|
|
8
|
+
import React, {useCallback, useMemo, useRef, useState} from 'react';
|
|
9
|
+
import {DocSearchButton, useDocSearchKeyboardEvents} from '@docsearch/react';
|
|
14
10
|
import Head from '@docusaurus/Head';
|
|
11
|
+
import Link from '@docusaurus/Link';
|
|
12
|
+
import {useHistory} from '@docusaurus/router';
|
|
15
13
|
import {isRegexpStringMatch} from '@docusaurus/theme-common';
|
|
16
14
|
import {useSearchPage} from '@docusaurus/theme-common/internal';
|
|
17
|
-
import {
|
|
18
|
-
|
|
15
|
+
import {
|
|
16
|
+
useAlgoliaContextualFacetFilters,
|
|
17
|
+
useSearchResultUrlProcessor,
|
|
18
|
+
} from '@docusaurus/theme-search-algolia/client';
|
|
19
19
|
import Translate from '@docusaurus/Translate';
|
|
20
|
+
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
|
21
|
+
import {createPortal} from 'react-dom';
|
|
20
22
|
import translations from '@theme/SearchTranslations';
|
|
21
23
|
|
|
24
|
+
import type {AutocompleteState} from '@algolia/autocomplete-core';
|
|
22
25
|
import type {
|
|
23
26
|
DocSearchModal as DocSearchModalType,
|
|
24
27
|
DocSearchModalProps,
|
|
@@ -28,7 +31,6 @@ import type {
|
|
|
28
31
|
StoredDocSearchHit,
|
|
29
32
|
} from '@docsearch/react/dist/esm/types';
|
|
30
33
|
import type {SearchClient} from 'algoliasearch/lite';
|
|
31
|
-
import type {AutocompleteState} from '@algolia/autocomplete-core';
|
|
32
34
|
|
|
33
35
|
type DocSearchProps = Omit<
|
|
34
36
|
DocSearchModalProps,
|
|
@@ -88,6 +90,7 @@ function DocSearch({
|
|
|
88
90
|
...props
|
|
89
91
|
}: DocSearchProps) {
|
|
90
92
|
const {siteMetadata} = useDocusaurusContext();
|
|
93
|
+
const processSearchResultUrl = useSearchResultUrlProcessor();
|
|
91
94
|
|
|
92
95
|
const contextualSearchFacetFilters =
|
|
93
96
|
useAlgoliaContextualFacetFilters() as FacetFilters;
|
|
@@ -107,7 +110,6 @@ function DocSearch({
|
|
|
107
110
|
facetFilters,
|
|
108
111
|
};
|
|
109
112
|
|
|
110
|
-
const {withBaseUrl} = useBaseUrlUtils();
|
|
111
113
|
const history = useHistory();
|
|
112
114
|
const searchContainer = useRef<HTMLDivElement | null>(null);
|
|
113
115
|
const searchButtonRef = useRef<HTMLButtonElement>(null);
|
|
@@ -172,20 +174,14 @@ function DocSearch({
|
|
|
172
174
|
|
|
173
175
|
const transformItems = useRef<DocSearchModalProps['transformItems']>(
|
|
174
176
|
(items) =>
|
|
175
|
-
|
|
176
|
-
//
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
const url = new URL(item.url);
|
|
184
|
-
return {
|
|
185
|
-
...item,
|
|
186
|
-
url: withBaseUrl(`${url.pathname}${url.hash}`),
|
|
187
|
-
};
|
|
188
|
-
}),
|
|
177
|
+
props.transformItems
|
|
178
|
+
? // Custom transformItems
|
|
179
|
+
props.transformItems(items)
|
|
180
|
+
: // Default transformItems
|
|
181
|
+
items.map((item) => ({
|
|
182
|
+
...item,
|
|
183
|
+
url: processSearchResultUrl(item.url),
|
|
184
|
+
})),
|
|
189
185
|
).current;
|
|
190
186
|
|
|
191
187
|
const resultsFooterComponent: DocSearchProps['resultsFooterComponent'] =
|
|
@@ -7,32 +7,34 @@
|
|
|
7
7
|
|
|
8
8
|
/* eslint-disable jsx-a11y/no-autofocus */
|
|
9
9
|
|
|
10
|
-
import React, {useEffect,
|
|
10
|
+
import React, {useEffect, useReducer, useRef, useState} from 'react';
|
|
11
11
|
import clsx from 'clsx';
|
|
12
12
|
|
|
13
|
-
import algoliaSearch from 'algoliasearch/lite';
|
|
14
13
|
import algoliaSearchHelper from 'algoliasearch-helper';
|
|
14
|
+
import algoliaSearch from 'algoliasearch/lite';
|
|
15
15
|
|
|
16
|
+
import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
|
|
16
17
|
import Head from '@docusaurus/Head';
|
|
17
18
|
import Link from '@docusaurus/Link';
|
|
18
|
-
import
|
|
19
|
+
import {useAllDocsData} from '@docusaurus/plugin-content-docs/client';
|
|
19
20
|
import {
|
|
20
21
|
HtmlClassNameProvider,
|
|
21
|
-
usePluralForm,
|
|
22
|
-
isRegexpStringMatch,
|
|
23
22
|
useEvent,
|
|
23
|
+
usePluralForm,
|
|
24
24
|
} from '@docusaurus/theme-common';
|
|
25
25
|
import {
|
|
26
|
-
useTitleFormatter,
|
|
27
26
|
useSearchPage,
|
|
27
|
+
useTitleFormatter,
|
|
28
28
|
} from '@docusaurus/theme-common/internal';
|
|
29
|
-
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
|
30
|
-
import {useAllDocsData} from '@docusaurus/plugin-content-docs/client';
|
|
31
29
|
import Translate, {translate} from '@docusaurus/Translate';
|
|
30
|
+
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
|
31
|
+
import {
|
|
32
|
+
useAlgoliaThemeConfig,
|
|
33
|
+
useSearchResultUrlProcessor,
|
|
34
|
+
} from '@docusaurus/theme-search-algolia/client';
|
|
32
35
|
import Layout from '@theme/Layout';
|
|
33
36
|
|
|
34
37
|
import styles from './styles.module.css';
|
|
35
|
-
import type {ThemeConfig} from '@docusaurus/theme-search-algolia';
|
|
36
38
|
|
|
37
39
|
// Very simple pluralization: probably good enough for now
|
|
38
40
|
function useDocumentsFoundPlural() {
|
|
@@ -156,12 +158,12 @@ type ResultDispatcher =
|
|
|
156
158
|
|
|
157
159
|
function SearchPageContent(): JSX.Element {
|
|
158
160
|
const {
|
|
159
|
-
siteConfig: {themeConfig},
|
|
160
161
|
i18n: {currentLocale},
|
|
161
162
|
} = useDocusaurusContext();
|
|
162
163
|
const {
|
|
163
|
-
algolia: {appId, apiKey, indexName
|
|
164
|
-
} =
|
|
164
|
+
algolia: {appId, apiKey, indexName},
|
|
165
|
+
} = useAlgoliaThemeConfig();
|
|
166
|
+
const processSearchResultUrl = useSearchResultUrlProcessor();
|
|
165
167
|
const documentsFoundPlural = useDocumentsFoundPlural();
|
|
166
168
|
|
|
167
169
|
const docsSearchVersionsHelpers = useDocsSearchVersionsHelpers();
|
|
@@ -244,16 +246,12 @@ function SearchPageContent(): JSX.Element {
|
|
|
244
246
|
_highlightResult: {hierarchy: {[key: string]: {value: string}}};
|
|
245
247
|
_snippetResult: {content?: {value: string}};
|
|
246
248
|
}) => {
|
|
247
|
-
const parsedURL = new URL(url);
|
|
248
249
|
const titles = Object.keys(hierarchy).map((key) =>
|
|
249
250
|
sanitizeValue(hierarchy[key]!.value),
|
|
250
251
|
);
|
|
251
|
-
|
|
252
252
|
return {
|
|
253
253
|
title: titles.pop()!,
|
|
254
|
-
url:
|
|
255
|
-
? parsedURL.href
|
|
256
|
-
: parsedURL.pathname + parsedURL.hash,
|
|
254
|
+
url: processSearchResultUrl(url),
|
|
257
255
|
summary: snippet.content
|
|
258
256
|
? `${sanitizeValue(snippet.content.value)}...`
|
|
259
257
|
: '',
|
|
@@ -17,13 +17,23 @@ declare module '@docusaurus/theme-search-algolia' {
|
|
|
17
17
|
indexName: string;
|
|
18
18
|
searchParameters: {[key: string]: unknown};
|
|
19
19
|
searchPagePath: string | false | null;
|
|
20
|
+
replaceSearchResultPathname?: {
|
|
21
|
+
from: string;
|
|
22
|
+
to: string;
|
|
23
|
+
};
|
|
20
24
|
};
|
|
21
25
|
};
|
|
22
26
|
export type UserThemeConfig = DeepPartial<ThemeConfig>;
|
|
23
27
|
}
|
|
24
28
|
|
|
25
29
|
declare module '@docusaurus/theme-search-algolia/client' {
|
|
30
|
+
import type {ThemeConfig} from '@docusaurus/theme-search-algolia';
|
|
31
|
+
|
|
32
|
+
export function useAlgoliaThemeConfig(): ThemeConfig;
|
|
33
|
+
|
|
26
34
|
export function useAlgoliaContextualFacetFilters(): [string, string[]];
|
|
35
|
+
|
|
36
|
+
export function useSearchResultUrlProcessor(): (url: string) => string;
|
|
27
37
|
}
|
|
28
38
|
|
|
29
39
|
declare module '@theme/SearchPage' {
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import {escapeRegexp} from '@docusaurus/utils';
|
|
8
9
|
import {Joi} from '@docusaurus/utils-validation';
|
|
9
10
|
import type {
|
|
10
11
|
ThemeConfig,
|
|
@@ -39,6 +40,19 @@ export const Schema = Joi.object<ThemeConfig>({
|
|
|
39
40
|
.try(Joi.boolean().invalid(true), Joi.string())
|
|
40
41
|
.allow(null)
|
|
41
42
|
.default(DEFAULT_CONFIG.searchPagePath),
|
|
43
|
+
replaceSearchResultPathname: Joi.object({
|
|
44
|
+
from: Joi.custom((from) => {
|
|
45
|
+
if (typeof from === 'string') {
|
|
46
|
+
return escapeRegexp(from);
|
|
47
|
+
} else if (from instanceof RegExp) {
|
|
48
|
+
return from.source;
|
|
49
|
+
}
|
|
50
|
+
throw new Error(
|
|
51
|
+
`it should be a RegExp or a string, but received ${from}`,
|
|
52
|
+
);
|
|
53
|
+
}).required(),
|
|
54
|
+
to: Joi.string().required(),
|
|
55
|
+
}).optional(),
|
|
42
56
|
})
|
|
43
57
|
.label('themeConfig.algolia')
|
|
44
58
|
.required()
|