diff --git a/website/src/theme/SearchBar/index.js b/website/src/theme/SearchBar/index.js
new file mode 100644
index 00000000..98269ded
--- /dev/null
+++ b/website/src/theme/SearchBar/index.js
@@ -0,0 +1,204 @@
+import React, {useState, useRef, useCallback, useMemo} from 'react';
+import {createPortal} from 'react-dom';
+import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
+import {useHistory} from '@docusaurus/router';
+import {useBaseUrlUtils} from '@docusaurus/useBaseUrl';
+import Link from '@docusaurus/Link';
+import Head from '@docusaurus/Head';
+import {isRegexpStringMatch} from '@docusaurus/theme-common';
+import {useSearchPage} from '@docusaurus/theme-common/internal';
+import {DocSearchButton, useDocSearchKeyboardEvents} from '@docsearch/react';
+import Translate from '@docusaurus/Translate';
+import translations from '@theme/SearchTranslations';
+import {useContextualSearchFilters} from '@docusaurus/theme-common';
+// eslint-disable-next-line import/extensions
+import {tagToCounter} from '../SearchMetadata';
+let DocSearchModal = null;
+function Hit({hit, children}) {
+ return {children};
+}
+function ResultsFooter({state, onClose}) {
+ const {generateSearchPageLink} = useSearchPage();
+ return (
+
+
+ {'See all {count} results'}
+
+
+ );
+}
+function mergeFacetFilters(f1, f2) {
+ const normalize = f => {
+ return typeof f === 'string' ? [f] : f;
+ };
+ return [...normalize(f1), ...normalize(f2)];
+}
+
+function usePuppeteerSearchFilters() {
+ const {locale, tags} = useContextualSearchFilters();
+ const languageFilter = `language:${locale}`;
+ return [
+ languageFilter,
+ tags.map(tag => {
+ return `counter:${tagToCounter.get(tag)}`;
+ }),
+ ];
+}
+
+function DocSearch({contextualSearch, externalUrlRegex, ...props}) {
+ const {siteMetadata} = useDocusaurusContext();
+ const contextualSearchFacetFilters = usePuppeteerSearchFilters();
+ const configFacetFilters = props.searchParameters?.facetFilters ?? [];
+ const facetFilters = contextualSearch
+ ? // Merge contextual search filters with config filters
+ mergeFacetFilters(contextualSearchFacetFilters, configFacetFilters)
+ : // ... or use config facetFilters
+ configFacetFilters;
+ // We let user override default searchParameters if she wants to
+ const searchParameters = {
+ ...props.searchParameters,
+ facetFilters,
+ };
+ const {withBaseUrl} = useBaseUrlUtils();
+ const history = useHistory();
+ const searchContainer = useRef(null);
+ const searchButtonRef = useRef(null);
+ const [isOpen, setIsOpen] = useState(false);
+ const [initialQuery, setInitialQuery] = useState(undefined);
+ const importDocSearchModalIfNeeded = useCallback(() => {
+ if (DocSearchModal) {
+ return Promise.resolve();
+ }
+ return Promise.all([
+ import('@docsearch/react/modal'),
+ import('@docsearch/react/style'),
+ import('./styles.css'),
+ ]).then(([{DocSearchModal: Modal}]) => {
+ DocSearchModal = Modal;
+ });
+ }, []);
+ const onOpen = useCallback(() => {
+ importDocSearchModalIfNeeded().then(() => {
+ searchContainer.current = document.createElement('div');
+ document.body.insertBefore(
+ searchContainer.current,
+ document.body.firstChild
+ );
+ setIsOpen(true);
+ });
+ }, [importDocSearchModalIfNeeded, setIsOpen]);
+ const onClose = useCallback(() => {
+ setIsOpen(false);
+ searchContainer.current?.remove();
+ }, [setIsOpen]);
+ const onInput = useCallback(
+ event => {
+ importDocSearchModalIfNeeded().then(() => {
+ setIsOpen(true);
+ setInitialQuery(event.key);
+ });
+ },
+ [importDocSearchModalIfNeeded, setIsOpen, setInitialQuery]
+ );
+ const navigator = useRef({
+ navigate({itemUrl}) {
+ // Algolia results could contain URL's from other domains which cannot
+ // be served through history and should navigate with window.location
+ if (isRegexpStringMatch(externalUrlRegex, itemUrl)) {
+ window.location.href = itemUrl;
+ } else {
+ history.push(itemUrl);
+ }
+ },
+ }).current;
+ const transformItems = useRef(items => {
+ return items.map(item => {
+ // If Algolia contains a external domain, we should navigate without
+ // relative URL
+ if (isRegexpStringMatch(externalUrlRegex, item.url)) {
+ return item;
+ }
+ // We transform the absolute URL into a relative URL.
+ const url = new URL(item.url);
+ return {
+ ...item,
+ url: withBaseUrl(`${url.pathname}${url.hash}`),
+ };
+ });
+ }).current;
+ const resultsFooterComponent = useMemo(() => {
+ return footerProps => {
+ return ;
+ };
+ }, [onClose]);
+ const transformSearchClient = useCallback(
+ searchClient => {
+ searchClient.addAlgoliaAgent(
+ 'docusaurus',
+ siteMetadata.docusaurusVersion
+ );
+ return searchClient;
+ },
+ [siteMetadata.docusaurusVersion]
+ );
+ useDocSearchKeyboardEvents({
+ isOpen,
+ onOpen,
+ onClose,
+ onInput,
+ searchButtonRef,
+ });
+ return (
+ <>
+
+ {/* This hints the browser that the website will load data from Algolia,
+ and allows it to preconnect to the DocSearch cluster. It makes the first
+ query faster, especially on mobile. */}
+
+
+
+
+
+ {isOpen &&
+ DocSearchModal &&
+ searchContainer.current &&
+ createPortal(
+ ,
+ searchContainer.current
+ )}
+ >
+ );
+}
+export default function SearchBar() {
+ const {siteConfig} = useDocusaurusContext();
+ return ;
+}
diff --git a/website/src/theme/SearchBar/styles.css b/website/src/theme/SearchBar/styles.css
new file mode 100644
index 00000000..fdf8dff9
--- /dev/null
+++ b/website/src/theme/SearchBar/styles.css
@@ -0,0 +1,14 @@
+:root {
+ --docsearch-primary-color: var(--ifm-color-primary);
+ --docsearch-text-color: var(--ifm-font-color-base);
+}
+
+.DocSearch-Button {
+ margin: 0;
+ transition: all var(--ifm-transition-fast)
+ var(--ifm-transition-timing-default);
+}
+
+.DocSearch-Container {
+ z-index: calc(var(--ifm-z-index-fixed) + 1);
+}
diff --git a/website/src/theme/SearchMetadata/index.js b/website/src/theme/SearchMetadata/index.js
index 94ada7b4..3d5a04c8 100644
--- a/website/src/theme/SearchMetadata/index.js
+++ b/website/src/theme/SearchMetadata/index.js
@@ -4,18 +4,29 @@ import Head from '@docusaurus/Head';
// Tracks the global package version as a local, monotonic counter. This
// prevents Algolia from deleting based on differing package versions and
// instead delete based on the number of versions we intend to keep documented.
-let globalCounter = -1;
-const versionToCounter = new Map();
-export default function SearchMetadata({locale, version}) {
+class MonotonicCountMap {
+ #counter = -1;
+ #map = new Map();
+
+ get(key) {
+ console.log(key);
+ let counter = this.#map.get(key);
+ if (!counter) {
+ counter = ++this.#counter;
+ this.#map.set(key, counter);
+ }
+ return counter;
+ }
+}
+
+export const tagToCounter = new MonotonicCountMap();
+
+export default function SearchMetadata({locale, tag}) {
const language = locale;
let counter;
- if (version) {
- counter = versionToCounter.get(version);
- if (!counter) {
- counter = ++globalCounter;
- versionToCounter.set(version, counter);
- }
+ if (tag) {
+ counter = tagToCounter.get(tag);
}
return (
diff --git a/website/src/theme/SearchPage/index.js b/website/src/theme/SearchPage/index.js
index dd2cd539..f8970808 100644
--- a/website/src/theme/SearchPage/index.js
+++ b/website/src/theme/SearchPage/index.js
@@ -20,6 +20,8 @@ import {useAllDocsData} from '@docusaurus/plugin-content-docs/client';
import Translate, {translate} from '@docusaurus/Translate';
import Layout from '@theme/Layout';
import styles from './styles.module.css';
+// eslint-disable-next-line import/extensions
+import {tagToCounter} from '../SearchMetadata';
// Very simple pluralization: probably good enough for now
function useDocumentsFoundPlural() {
const {selectMessage} = usePluralForm();
@@ -263,11 +265,17 @@ function SearchPageContent() {
const makeSearch = useEvent((page = 0) => {
algoliaHelper.addDisjunctiveFacetRefinement(
'counter',
- document
- .querySelector('meta[name="docsearch:counter"]')
- .getAttribute('content')
+ tagToCounter.get('default')
);
algoliaHelper.addDisjunctiveFacetRefinement('language', currentLocale);
+ Object.entries(docsSearchVersionsHelpers.searchVersions).forEach(
+ ([pluginId, searchVersion]) => {
+ algoliaHelper.addDisjunctiveFacetRefinement(
+ 'counter',
+ tagToCounter.get(`docs-${pluginId}-${searchVersion}`)
+ );
+ }
+ );
algoliaHelper.setQuery(searchQuery).setPage(page).search();
});
useEffect(() => {