This is an automated email from the ASF dual-hosted git repository.

guoqi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-website.git


The following commit(s) were added to refs/heads/master by this push:
     new 1c6b8aec976 fix: search bar, posts order, style (#1258)
1c6b8aec976 is described below

commit 1c6b8aec9769679613540219d7621b984cfbf494
Author: Young <[email protected]>
AuthorDate: Tue Aug 2 13:53:17 2022 +0800

    fix: search bar, posts order, style (#1258)
---
 blog/src/theme/BlogPosts/index.tsx            |  19 ++-
 blog/src/theme/BlogPosts/style.module.scss    |   2 +-
 blog/src/theme/SearchBar/index.js             | 202 ++++++++++++++++++++++++++
 blog/src/theme/SearchBar/styles.css           |  22 +++
 blog/src/theme/SearchBar/styles.module.css    |  21 +++
 doc/src/theme/SearchBar/index.js              | 202 ++++++++++++++++++++++++++
 doc/src/theme/SearchBar/styles.css            |  22 +++
 doc/src/theme/SearchBar/styles.module.css     |  21 +++
 website/src/theme/SearchBar/index.js          | 202 ++++++++++++++++++++++++++
 website/src/theme/SearchBar/styles.css        |  22 +++
 website/src/theme/SearchBar/styles.module.css |  21 +++
 yarn.lock                                     |   2 +-
 12 files changed, 746 insertions(+), 12 deletions(-)

diff --git a/blog/src/theme/BlogPosts/index.tsx 
b/blog/src/theme/BlogPosts/index.tsx
index 91bd6abcf87..5316246c0e8 100644
--- a/blog/src/theme/BlogPosts/index.tsx
+++ b/blog/src/theme/BlogPosts/index.tsx
@@ -70,7 +70,12 @@ const BlogPostItem: FC<BlogPostItemProps> = (props) => {
   const image = assets?.image ?? frontMatter.image ?? defaultImg;
 
   return (
-    <article className={className} itemProp="blogPost" itemScope 
itemType="http://schema.org/BlogPosting";>
+    <article
+      className={className}
+      itemProp="blogPost"
+      itemScope
+      itemType="http://schema.org/BlogPosting";
+    >
       <Link itemProp="url" to={permalink} aria-label={`Read more about 
${title}`}>
         <LazyLoadImage
           height={232}
@@ -169,7 +174,7 @@ const BlogPosts: FC<BlogPostsProps> = ({
   useIntersectionObserver,
   ...props
 }) => {
-  let posts = items.map(({ content: BlogPostContent }) => (
+  const posts = items.map(({ content: BlogPostContent }) => (
     <BlogPostItem
       key={BlogPostContent.metadata.permalink}
       frontMatter={BlogPostContent.frontMatter}
@@ -182,10 +187,8 @@ const BlogPosts: FC<BlogPostsProps> = ({
     </BlogPostItem>
   ));
 
-  const max = (pickedPosts.length > 10 ? pickedPosts.length - 10 : 
pickedPosts.length);
-  const endIdx = isFirstPage
-    ? 2 * Math.floor(max / 2)
-    : 3 * Math.floor(max / 3);
+  const max = pickedPosts.length > 10 ? pickedPosts.length - 10 : 
pickedPosts.length;
+  const endIdx = isFirstPage ? 2 * Math.floor(max / 2) : 3;
   const { pathname } = useLocation();
 
   if (!pathname.includes('/tags/')) {
@@ -212,10 +215,6 @@ const BlogPosts: FC<BlogPostsProps> = ({
         </BlogPostItem>
       )),
     );
-
-    if (!isFirstPage) {
-      posts = shuffle(posts);
-    }
   }
 
   return (
diff --git a/blog/src/theme/BlogPosts/style.module.scss 
b/blog/src/theme/BlogPosts/style.module.scss
index bf6563e3e2b..f2f0cca0122 100644
--- a/blog/src/theme/BlogPosts/style.module.scss
+++ b/blog/src/theme/BlogPosts/style.module.scss
@@ -64,7 +64,7 @@
   font-family: apple-system, system-ui, sans-serif;
 
   article {
-    margin: 0 1.25rem 2.5rem;
+    margin: 0 1.25rem 3rem;
     border-radius: 1rem;
     overflow: hidden;
     border: 2px solid transparent;
diff --git a/blog/src/theme/SearchBar/index.js 
b/blog/src/theme/SearchBar/index.js
new file mode 100644
index 00000000000..1c65093dee5
--- /dev/null
+++ b/blog/src/theme/SearchBar/index.js
@@ -0,0 +1,202 @@
+/* eslint-disable */
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+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 useSearchQuery from '@theme/hooks/useSearchQuery';
+import { DocSearchButton, useDocSearchKeyboardEvents } from '@docsearch/react';
+import useAlgoliaContextualFacetFilters from 
'@theme/hooks/useAlgoliaContextualFacetFilters';
+import { translate } from '@docusaurus/Translate';
+import styles from './styles.module.css';
+
+let DocSearchModal = null;
+
+function Hit({ hit, children }) {
+  return <a href={hit.url}>{children}</a>;
+}
+
+function ResultsFooter({ state, onClose }) {
+  const { generateSearchPageLink } = useSearchQuery();
+
+  return (
+    <Link to={generateSearchPageLink(state.query)} onClick={onClose} 
target="_blank">
+      See all {state.context.nbHits} results
+    </Link>
+  );
+}
+
+function DocSearch({ contextualSearch, ...props }) {
+  const { siteMetadata } = useDocusaurusContext();
+
+  const contextualSearchFacetFilters = useAlgoliaContextualFacetFilters();
+
+  const configFacetFilters = props.searchParameters?.facetFilters ?? [];
+
+  const facetFilters = contextualSearch
+    ? // Merge contextual search filters with config filters
+      [...contextualSearchFacetFilters, ...configFacetFilters]
+    : // ... or use config facetFilters
+      configFacetFilters;
+
+  // we let user override default searchParameters if he 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(null);
+
+  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 }) {
+      history.push(itemUrl);
+    },
+  }).current;
+
+  const transformItems = useRef((items) => {
+    return items.map((item) => {
+      // We transform the absolute URL into a relative URL.
+      // Alternatively, we can use `new URL(item.url)` but it's not
+      // supported in IE.
+      const a = document.createElement('a');
+      a.href = item.url;
+
+      return {
+        ...item,
+        url: withBaseUrl(`${a.pathname}${a.hash}`),
+      };
+    });
+  }).current;
+
+  const resultsFooterComponent = useMemo(
+    () => (footerProps) => <ResultsFooter {...footerProps} onClose={onClose} 
/>,
+    [onClose]
+  );
+
+  const transformSearchClient = useCallback(
+    (searchClient) => {
+      searchClient.addAlgoliaAgent('docusaurus', 
siteMetadata.docusaurusVersion);
+
+      return searchClient;
+    },
+    [siteMetadata.docusaurusVersion]
+  );
+
+  useDocSearchKeyboardEvents({
+    isOpen,
+    onOpen,
+    onClose,
+    onInput,
+    searchButtonRef,
+  });
+
+  const translatedSearchLabel = translate({
+    id: 'theme.SearchBar.label',
+    message: 'Search',
+    description: 'The ARIA label and placeholder for search button',
+  });
+
+  return (
+    <>
+      <Head>
+        {/* 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. */}
+        <link
+          rel="preconnect"
+          href={`https://${props.appId}-dsn.algolia.net`}
+          crossOrigin="anonymous"
+        />
+      </Head>
+
+      <div className={styles.searchBox}>
+        <DocSearchButton
+          onTouchStart={importDocSearchModalIfNeeded}
+          onFocus={importDocSearchModalIfNeeded}
+          onMouseOver={importDocSearchModalIfNeeded}
+          onClick={onOpen}
+          ref={searchButtonRef}
+          translations={{
+            buttonText: translatedSearchLabel,
+            buttonAriaLabel: translatedSearchLabel,
+          }}
+        />
+      </div>
+
+      {isOpen &&
+        createPortal(
+          <DocSearchModal
+            onClose={onClose}
+            initialScrollY={window.scrollY}
+            initialQuery={initialQuery}
+            navigator={navigator}
+            transformItems={transformItems}
+            hitComponent={Hit}
+            resultsFooterComponent={resultsFooterComponent}
+            transformSearchClient={transformSearchClient}
+            {...props}
+            searchParameters={searchParameters}
+          />,
+          searchContainer.current
+        )}
+    </>
+  );
+}
+
+function SearchBar() {
+  const { siteConfig } = useDocusaurusContext();
+  return <DocSearch {...siteConfig.themeConfig.algolia} />;
+}
+
+export default SearchBar;
diff --git a/blog/src/theme/SearchBar/styles.css 
b/blog/src/theme/SearchBar/styles.css
new file mode 100644
index 00000000000..d95b6d37a6c
--- /dev/null
+++ b/blog/src/theme/SearchBar/styles.css
@@ -0,0 +1,22 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+: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/blog/src/theme/SearchBar/styles.module.css 
b/blog/src/theme/SearchBar/styles.module.css
new file mode 100644
index 00000000000..e0df0559d0e
--- /dev/null
+++ b/blog/src/theme/SearchBar/styles.module.css
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+@media (max-width: 996px) {
+  .searchBox {
+    position: absolute;
+    right: var(--ifm-navbar-padding-horizontal);
+  }
+}
+
+@media (min-width: 997px) {
+  .searchBox {
+    padding:
+      var(--ifm-navbar-item-padding-vertical)
+      var(--ifm-navbar-item-padding-horizontal);
+  }
+}
diff --git a/doc/src/theme/SearchBar/index.js b/doc/src/theme/SearchBar/index.js
new file mode 100644
index 00000000000..1c65093dee5
--- /dev/null
+++ b/doc/src/theme/SearchBar/index.js
@@ -0,0 +1,202 @@
+/* eslint-disable */
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+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 useSearchQuery from '@theme/hooks/useSearchQuery';
+import { DocSearchButton, useDocSearchKeyboardEvents } from '@docsearch/react';
+import useAlgoliaContextualFacetFilters from 
'@theme/hooks/useAlgoliaContextualFacetFilters';
+import { translate } from '@docusaurus/Translate';
+import styles from './styles.module.css';
+
+let DocSearchModal = null;
+
+function Hit({ hit, children }) {
+  return <a href={hit.url}>{children}</a>;
+}
+
+function ResultsFooter({ state, onClose }) {
+  const { generateSearchPageLink } = useSearchQuery();
+
+  return (
+    <Link to={generateSearchPageLink(state.query)} onClick={onClose} 
target="_blank">
+      See all {state.context.nbHits} results
+    </Link>
+  );
+}
+
+function DocSearch({ contextualSearch, ...props }) {
+  const { siteMetadata } = useDocusaurusContext();
+
+  const contextualSearchFacetFilters = useAlgoliaContextualFacetFilters();
+
+  const configFacetFilters = props.searchParameters?.facetFilters ?? [];
+
+  const facetFilters = contextualSearch
+    ? // Merge contextual search filters with config filters
+      [...contextualSearchFacetFilters, ...configFacetFilters]
+    : // ... or use config facetFilters
+      configFacetFilters;
+
+  // we let user override default searchParameters if he 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(null);
+
+  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 }) {
+      history.push(itemUrl);
+    },
+  }).current;
+
+  const transformItems = useRef((items) => {
+    return items.map((item) => {
+      // We transform the absolute URL into a relative URL.
+      // Alternatively, we can use `new URL(item.url)` but it's not
+      // supported in IE.
+      const a = document.createElement('a');
+      a.href = item.url;
+
+      return {
+        ...item,
+        url: withBaseUrl(`${a.pathname}${a.hash}`),
+      };
+    });
+  }).current;
+
+  const resultsFooterComponent = useMemo(
+    () => (footerProps) => <ResultsFooter {...footerProps} onClose={onClose} 
/>,
+    [onClose]
+  );
+
+  const transformSearchClient = useCallback(
+    (searchClient) => {
+      searchClient.addAlgoliaAgent('docusaurus', 
siteMetadata.docusaurusVersion);
+
+      return searchClient;
+    },
+    [siteMetadata.docusaurusVersion]
+  );
+
+  useDocSearchKeyboardEvents({
+    isOpen,
+    onOpen,
+    onClose,
+    onInput,
+    searchButtonRef,
+  });
+
+  const translatedSearchLabel = translate({
+    id: 'theme.SearchBar.label',
+    message: 'Search',
+    description: 'The ARIA label and placeholder for search button',
+  });
+
+  return (
+    <>
+      <Head>
+        {/* 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. */}
+        <link
+          rel="preconnect"
+          href={`https://${props.appId}-dsn.algolia.net`}
+          crossOrigin="anonymous"
+        />
+      </Head>
+
+      <div className={styles.searchBox}>
+        <DocSearchButton
+          onTouchStart={importDocSearchModalIfNeeded}
+          onFocus={importDocSearchModalIfNeeded}
+          onMouseOver={importDocSearchModalIfNeeded}
+          onClick={onOpen}
+          ref={searchButtonRef}
+          translations={{
+            buttonText: translatedSearchLabel,
+            buttonAriaLabel: translatedSearchLabel,
+          }}
+        />
+      </div>
+
+      {isOpen &&
+        createPortal(
+          <DocSearchModal
+            onClose={onClose}
+            initialScrollY={window.scrollY}
+            initialQuery={initialQuery}
+            navigator={navigator}
+            transformItems={transformItems}
+            hitComponent={Hit}
+            resultsFooterComponent={resultsFooterComponent}
+            transformSearchClient={transformSearchClient}
+            {...props}
+            searchParameters={searchParameters}
+          />,
+          searchContainer.current
+        )}
+    </>
+  );
+}
+
+function SearchBar() {
+  const { siteConfig } = useDocusaurusContext();
+  return <DocSearch {...siteConfig.themeConfig.algolia} />;
+}
+
+export default SearchBar;
diff --git a/doc/src/theme/SearchBar/styles.css 
b/doc/src/theme/SearchBar/styles.css
new file mode 100644
index 00000000000..d95b6d37a6c
--- /dev/null
+++ b/doc/src/theme/SearchBar/styles.css
@@ -0,0 +1,22 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+: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/doc/src/theme/SearchBar/styles.module.css 
b/doc/src/theme/SearchBar/styles.module.css
new file mode 100644
index 00000000000..e0df0559d0e
--- /dev/null
+++ b/doc/src/theme/SearchBar/styles.module.css
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+@media (max-width: 996px) {
+  .searchBox {
+    position: absolute;
+    right: var(--ifm-navbar-padding-horizontal);
+  }
+}
+
+@media (min-width: 997px) {
+  .searchBox {
+    padding:
+      var(--ifm-navbar-item-padding-vertical)
+      var(--ifm-navbar-item-padding-horizontal);
+  }
+}
diff --git a/website/src/theme/SearchBar/index.js 
b/website/src/theme/SearchBar/index.js
new file mode 100644
index 00000000000..1c65093dee5
--- /dev/null
+++ b/website/src/theme/SearchBar/index.js
@@ -0,0 +1,202 @@
+/* eslint-disable */
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+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 useSearchQuery from '@theme/hooks/useSearchQuery';
+import { DocSearchButton, useDocSearchKeyboardEvents } from '@docsearch/react';
+import useAlgoliaContextualFacetFilters from 
'@theme/hooks/useAlgoliaContextualFacetFilters';
+import { translate } from '@docusaurus/Translate';
+import styles from './styles.module.css';
+
+let DocSearchModal = null;
+
+function Hit({ hit, children }) {
+  return <a href={hit.url}>{children}</a>;
+}
+
+function ResultsFooter({ state, onClose }) {
+  const { generateSearchPageLink } = useSearchQuery();
+
+  return (
+    <Link to={generateSearchPageLink(state.query)} onClick={onClose} 
target="_blank">
+      See all {state.context.nbHits} results
+    </Link>
+  );
+}
+
+function DocSearch({ contextualSearch, ...props }) {
+  const { siteMetadata } = useDocusaurusContext();
+
+  const contextualSearchFacetFilters = useAlgoliaContextualFacetFilters();
+
+  const configFacetFilters = props.searchParameters?.facetFilters ?? [];
+
+  const facetFilters = contextualSearch
+    ? // Merge contextual search filters with config filters
+      [...contextualSearchFacetFilters, ...configFacetFilters]
+    : // ... or use config facetFilters
+      configFacetFilters;
+
+  // we let user override default searchParameters if he 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(null);
+
+  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 }) {
+      history.push(itemUrl);
+    },
+  }).current;
+
+  const transformItems = useRef((items) => {
+    return items.map((item) => {
+      // We transform the absolute URL into a relative URL.
+      // Alternatively, we can use `new URL(item.url)` but it's not
+      // supported in IE.
+      const a = document.createElement('a');
+      a.href = item.url;
+
+      return {
+        ...item,
+        url: withBaseUrl(`${a.pathname}${a.hash}`),
+      };
+    });
+  }).current;
+
+  const resultsFooterComponent = useMemo(
+    () => (footerProps) => <ResultsFooter {...footerProps} onClose={onClose} 
/>,
+    [onClose]
+  );
+
+  const transformSearchClient = useCallback(
+    (searchClient) => {
+      searchClient.addAlgoliaAgent('docusaurus', 
siteMetadata.docusaurusVersion);
+
+      return searchClient;
+    },
+    [siteMetadata.docusaurusVersion]
+  );
+
+  useDocSearchKeyboardEvents({
+    isOpen,
+    onOpen,
+    onClose,
+    onInput,
+    searchButtonRef,
+  });
+
+  const translatedSearchLabel = translate({
+    id: 'theme.SearchBar.label',
+    message: 'Search',
+    description: 'The ARIA label and placeholder for search button',
+  });
+
+  return (
+    <>
+      <Head>
+        {/* 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. */}
+        <link
+          rel="preconnect"
+          href={`https://${props.appId}-dsn.algolia.net`}
+          crossOrigin="anonymous"
+        />
+      </Head>
+
+      <div className={styles.searchBox}>
+        <DocSearchButton
+          onTouchStart={importDocSearchModalIfNeeded}
+          onFocus={importDocSearchModalIfNeeded}
+          onMouseOver={importDocSearchModalIfNeeded}
+          onClick={onOpen}
+          ref={searchButtonRef}
+          translations={{
+            buttonText: translatedSearchLabel,
+            buttonAriaLabel: translatedSearchLabel,
+          }}
+        />
+      </div>
+
+      {isOpen &&
+        createPortal(
+          <DocSearchModal
+            onClose={onClose}
+            initialScrollY={window.scrollY}
+            initialQuery={initialQuery}
+            navigator={navigator}
+            transformItems={transformItems}
+            hitComponent={Hit}
+            resultsFooterComponent={resultsFooterComponent}
+            transformSearchClient={transformSearchClient}
+            {...props}
+            searchParameters={searchParameters}
+          />,
+          searchContainer.current
+        )}
+    </>
+  );
+}
+
+function SearchBar() {
+  const { siteConfig } = useDocusaurusContext();
+  return <DocSearch {...siteConfig.themeConfig.algolia} />;
+}
+
+export default SearchBar;
diff --git a/website/src/theme/SearchBar/styles.css 
b/website/src/theme/SearchBar/styles.css
new file mode 100644
index 00000000000..d95b6d37a6c
--- /dev/null
+++ b/website/src/theme/SearchBar/styles.css
@@ -0,0 +1,22 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+: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/SearchBar/styles.module.css 
b/website/src/theme/SearchBar/styles.module.css
new file mode 100644
index 00000000000..e0df0559d0e
--- /dev/null
+++ b/website/src/theme/SearchBar/styles.module.css
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+@media (max-width: 996px) {
+  .searchBox {
+    position: absolute;
+    right: var(--ifm-navbar-padding-horizontal);
+  }
+}
+
+@media (min-width: 997px) {
+  .searchBox {
+    padding:
+      var(--ifm-navbar-item-padding-vertical)
+      var(--ifm-navbar-item-padding-horizontal);
+  }
+}
diff --git a/yarn.lock b/yarn.lock
index 488a75f9f69..3a5ce5b42b1 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -11500,7 +11500,7 @@ [email protected], style-to-object@^0.3.0:
   dependencies:
     inline-style-parser "0.1.1"
 
-styled-components@^5, styled-components@^5.3.3:
+styled-components@^5.3.3:
   version "5.3.5"
   resolved 
"https://registry.yarnpkg.com/styled-components/-/styled-components-5.3.5.tgz#a750a398d01f1ca73af16a241dec3da6deae5ec4";
   integrity 
sha512-ndETJ9RKaaL6q41B69WudeqLzOpY1A/ET/glXkNZ2T7dPjPqpPCXXQjDFYZWwNnE5co0wX+gTCqx9mfxTmSIPg==

Reply via email to