Some bugfix (#1460)
1. Fixed some issues with the search box.
2. Some style optimizations.
---------
Co-authored-by: liyang <liyang@selectdb.com>
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/current.json b/i18n/zh-CN/docusaurus-plugin-content-docs/current.json
index e928746..08715a1 100644
--- a/i18n/zh-CN/docusaurus-plugin-content-docs/current.json
+++ b/i18n/zh-CN/docusaurus-plugin-content-docs/current.json
@@ -23,6 +23,14 @@
"message": "版本发布",
"description": "The label for category Releases in sidebar docs"
},
+ "sidebar.docs.category.Tutorials": {
+ "message": "使用教程",
+ "description": "The label for category Tutorials in sidebar docs"
+ },
+ "sidebar.docs.category.Building lakehouse": {
+ "message": "构建 lakehouse",
+ "description": "The label for category Building lakehouse in sidebar docs"
+ },
"sidebar.docs.category.Quick Start": {
"message": "快速体验",
"description": "The label for category Quick Start in sidebar docs"
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-1.2.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-1.2.json
index 4986b45..682456c 100644
--- a/i18n/zh-CN/docusaurus-plugin-content-docs/version-1.2.json
+++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-1.2.json
@@ -27,6 +27,14 @@
"message": "Doris 介绍",
"description": "The label for category Doris Introduction in sidebar docs"
},
+ "sidebar.docs.category.Tutorials": {
+ "message": "使用教程",
+ "description": "The label for category Tutorials in sidebar docs"
+ },
+ "sidebar.docs.category.Building lakehouse": {
+ "message": "构建 lakehouse",
+ "description": "The label for category Building lakehouse in sidebar docs"
+ },
"sidebar.docs.category.Install And Deploy": {
"message": "安装部署",
"description": "The label for category Install And Deploy in sidebar docs"
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-2.0.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-2.0.json
index cbd3601..94048c4 100644
--- a/i18n/zh-CN/docusaurus-plugin-content-docs/version-2.0.json
+++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-2.0.json
@@ -27,6 +27,14 @@
"message": "快速体验",
"description": "The label for category Quick Start in sidebar docs"
},
+ "sidebar.docs.category.Tutorials": {
+ "message": "使用教程",
+ "description": "The label for category Tutorials in sidebar docs"
+ },
+ "sidebar.docs.category.Building lakehouse": {
+ "message": "构建 lakehouse",
+ "description": "The label for category Building lakehouse in sidebar docs"
+ },
"sidebar.docs.category.Installation and Deployment": {
"message": "安装部署",
"description": "The label for category Installation and Deployment in sidebar docs"
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-2.1.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-2.1.json
index 247ea98..fb787a4 100644
--- a/i18n/zh-CN/docusaurus-plugin-content-docs/version-2.1.json
+++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-2.1.json
@@ -27,6 +27,14 @@
"message": "快速体验",
"description": "The label for category Quick Start in sidebar docs"
},
+ "sidebar.docs.category.Tutorials": {
+ "message": "使用教程",
+ "description": "The label for category Tutorials in sidebar docs"
+ },
+ "sidebar.docs.category.Building lakehouse": {
+ "message": "构建 lakehouse",
+ "description": "The label for category Building lakehouse in sidebar docs"
+ },
"sidebar.docs.category.Installation and Deployment": {
"message": "安装部署",
"description": "The label for category Install and Deploy in sidebar docs"
diff --git a/i18n/zh-CN/docusaurus-plugin-content-docs/version-3.0.json b/i18n/zh-CN/docusaurus-plugin-content-docs/version-3.0.json
index 631798c..678f655 100644
--- a/i18n/zh-CN/docusaurus-plugin-content-docs/version-3.0.json
+++ b/i18n/zh-CN/docusaurus-plugin-content-docs/version-3.0.json
@@ -27,6 +27,14 @@
"message": "快速体验",
"description": "The label for category Quick Start in sidebar docs"
},
+ "sidebar.docs.category.Tutorials": {
+ "message": "使用教程",
+ "description": "The label for category Tutorials in sidebar docs"
+ },
+ "sidebar.docs.category.Building lakehouse": {
+ "message": "构建 lakehouse",
+ "description": "The label for category Building lakehouse in sidebar docs"
+ },
"sidebar.docs.category.Installation and Deployment": {
"message": "安装部署",
"description": "The label for category Installation and Deployment in sidebar docs"
diff --git a/shared/interfaces.js b/shared/interfaces.js
new file mode 100644
index 0000000..f4037df
--- /dev/null
+++ b/shared/interfaces.js
@@ -0,0 +1,8 @@
+export var SearchDocumentType;
+(function (SearchDocumentType) {
+ SearchDocumentType[SearchDocumentType["Title"] = 0] = "Title";
+ SearchDocumentType[SearchDocumentType["Heading"] = 1] = "Heading";
+ SearchDocumentType[SearchDocumentType["Description"] = 2] = "Description";
+ SearchDocumentType[SearchDocumentType["Keywords"] = 3] = "Keywords";
+ SearchDocumentType[SearchDocumentType["Content"] = 4] = "Content";
+})(SearchDocumentType || (SearchDocumentType = {}));
diff --git a/src/constant/common.tsx b/src/constant/common.tsx
index 4d8c292..b1f71a6 100644
--- a/src/constant/common.tsx
+++ b/src/constant/common.tsx
@@ -18,3 +18,6 @@
'Top News': <TopNewsIcon />,
All: <AllBlogIcon />,
};
+
+export const VERSIONS = ['1.2', '2.0', '2.1', '3.0', 'dev'];
+export const DEFAULT_VERSION = '2.1';
\ No newline at end of file
diff --git a/src/scss/components/markdown.scss b/src/scss/components/markdown.scss
index 1945ab4..f9e5498 100644
--- a/src/scss/components/markdown.scss
+++ b/src/scss/components/markdown.scss
@@ -113,6 +113,7 @@
.theme-admonition {
padding: calc(var(--custom-leading) * 2);
+ box-shadow: none;
}
h2 {
diff --git a/src/scss/components/navbar.scss b/src/scss/components/navbar.scss
index a9700af..0dc57d4 100644
--- a/src/scss/components/navbar.scss
+++ b/src/scss/components/navbar.scss
@@ -30,7 +30,6 @@
display: flex !important;
align-items: center;
justify-content: center;
- pointer-events: none;
padding: 5px 7px;
background-color: #fff;
border: none;
@@ -74,8 +73,6 @@
outline: none !important;
}
.navbar__search span span {
- max-height: 580px !important;
- overflow: scroll !important;
top: 2.5rem !important;
}
}
diff --git a/src/scss/components/toc.scss b/src/scss/components/toc.scss
index 3ada29d..54f3b72 100644
--- a/src/scss/components/toc.scss
+++ b/src/scss/components/toc.scss
@@ -3,6 +3,7 @@
.toc-icon-content {
display: flex;
margin-bottom: 0.5rem;
+ align-items: center;
cursor: pointer;
}
diff --git a/src/shared/interfaces.js b/src/shared/interfaces.js
new file mode 100644
index 0000000..f4037df
--- /dev/null
+++ b/src/shared/interfaces.js
@@ -0,0 +1,8 @@
+export var SearchDocumentType;
+(function (SearchDocumentType) {
+ SearchDocumentType[SearchDocumentType["Title"] = 0] = "Title";
+ SearchDocumentType[SearchDocumentType["Heading"] = 1] = "Heading";
+ SearchDocumentType[SearchDocumentType["Description"] = 2] = "Description";
+ SearchDocumentType[SearchDocumentType["Keywords"] = 3] = "Keywords";
+ SearchDocumentType[SearchDocumentType["Content"] = 4] = "Content";
+})(SearchDocumentType || (SearchDocumentType = {}));
diff --git a/src/theme/Admonition/Layout/styles.module.css b/src/theme/Admonition/Layout/styles.module.css
index 88df7e6..3f5fe3b 100644
--- a/src/theme/Admonition/Layout/styles.module.css
+++ b/src/theme/Admonition/Layout/styles.module.css
@@ -3,9 +3,12 @@
}
.admonitionHeading {
- font: var(--ifm-heading-font-weight) var(--ifm-h5-font-size) /
- var(--ifm-heading-line-height) var(--ifm-heading-font-family);
+ font: var(--ifm-heading-font-weight) var(--ifm-h5-font-size) / var(--ifm-heading-line-height) var(--ifm-heading-font-family);
text-transform: uppercase;
+ font-size: 1rem;
+ color: #00000A;
+ margin-bottom: 0.75rem !important;
+ font-weight: 600;
}
/* Heading alone without content (does not handle fragment content) */
@@ -30,6 +33,6 @@
fill: var(--ifm-alert-foreground-color);
}
-.admonitionContent > :last-child {
+.admonitionContent> :last-child {
margin-bottom: 0;
-}
+}
\ No newline at end of file
diff --git a/src/theme/DocSidebarItem/Category/style.scss b/src/theme/DocSidebarItem/Category/style.scss
index c642c47..2398c43 100644
--- a/src/theme/DocSidebarItem/Category/style.scss
+++ b/src/theme/DocSidebarItem/Category/style.scss
@@ -58,7 +58,7 @@
.divider {
width: calc(100% - 0.625rem);
- border: 0.5px solid #edf2fa;
+ border: 0.5px solid #DFE5F0;
margin: 1rem 0 1rem 0;
position: relative;
left: 0.625rem;
diff --git a/src/theme/Footer/index.tsx b/src/theme/Footer/index.tsx
index 3ce1831..097a13a 100644
--- a/src/theme/Footer/index.tsx
+++ b/src/theme/Footer/index.tsx
@@ -25,11 +25,14 @@
}
const { copyright, links, logo, style } = footer;
- const [isDocsPage, setIsDocsPage] = useState(false);
+ const [isDocsPage, setIsDocsPage] = useState(false); // docs page or community page
useEffect(() => {
if (typeof window !== 'undefined') {
const pathname = location.pathname.split('/')[1];
- const docsPage = pathname === 'docs' || location.pathname.includes('zh-CN/docs');
+ const docsPage =
+ pathname === 'docs' ||
+ location.pathname.includes('zh-CN/docs') ||
+ location.pathname.includes('community');
setIsDocsPage(docsPage);
}
}, [typeof window !== 'undefined' && location.pathname]);
@@ -39,30 +42,13 @@
if (isDocsPage) {
return (
<div className="docs-footer flex-col lg:flex-row">
- <div className="logo w-full lg:w-[var(--doc-sidebar-width)] pt-28 lg:h-auto">
- <FooterLogo logo={logo} />
- </div>
- <div className="content container">
- <div className="my-7 text-[#8592A6] text-sm">
- {/* border-b border-[#F7F9FE] */}
- <div className="flex flex-col lg:flex-row pb-3 flex-wrap">
- <div className=" w-40 mb-3 lg:mb-0 font-medium">RESOURCES</div>
- {ResourcesItems.map(({ label, href }) => (
- <Link className="w-40 no-underline mb-2" href={href}>
- {label}
- </Link>
- ))}
- </div>
- <div className="flex flex-col lg:flex-row pt-3 flex-wrap">
- <div className="w-40 mb-3 lg:mb-0 font-medium">COMMUNITY</div>
- {CommunityItems.map(({ label, href }) => (
- <Link className="w-40 no-underline mb-2" href={href}>
- {label}
- </Link>
- ))}
- </div>
- </div>
- </div>
+ <p className='docs-footer-p'>
+ The contents of this website are © 2024{' '}
+ <Link href="https://www.apache.org/">Apache Software Foundation</Link> under the terms of the{' '}
+ <Link href="https://www.apache.org/licenses/LICENSE-2.0.html">Apache License v2.</Link> Apache
+ Doris, Doris, and the Doris logo are either registered trademarks or trademarks of The Apache
+ Software Foundation in the United States and other countries.
+ </p>
</div>
);
}
diff --git a/src/theme/Footer/styles.scss b/src/theme/Footer/styles.scss
index e70eebf..2320381 100644
--- a/src/theme/Footer/styles.scss
+++ b/src/theme/Footer/styles.scss
@@ -212,23 +212,20 @@
}
.docs-footer {
- height: 7.625rem;
+ height: 3.25rem;
background-color: #fff;
- display: flex;
- border-top: 1px solid #edf2fa;
- .logo {
- position: relative;
- .footer__logo {
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- width: 8.5625rem;
- height: 3.5rem;
- margin-top: 0;
- }
+ padding: 1rem 1.5rem;
+ border-top: 1px solid #EDF2FA;
+ .docs-footer-p {
+ text-align: center;
+ color: rgba(29, 29, 29, 0.4);
+ font-family: Inter;
+ font-size: 9px;
+ font-style: normal;
+ font-weight: 400;
+ line-height: 20px;
}
- .content {
- flex: 1;
+ .docs-footer-p a {
+ text-decoration: underline;
}
}
diff --git a/src/theme/Navbar/Content/index.tsx b/src/theme/Navbar/Content/index.tsx
index 275af09..0243b53 100644
--- a/src/theme/Navbar/Content/index.tsx
+++ b/src/theme/Navbar/Content/index.tsx
@@ -86,11 +86,13 @@
const [isEN, setIsEN] = useState(true);
const docItems = isEN ? useThemeConfig().docNavbarEN.items : useThemeConfig().docNavbarZH.items;
const [leftItems, rightItems] = splitNavbarItems(items);
- const [leftDocItems,rightDocItems] = splitNavbarItems(docItems);
- const [isDocsPage, setIsDocsPage] = useState(false);
+ const [leftDocItems, rightDocItems] = splitNavbarItems(docItems);
+ const [isDocsPage, setIsDocsPage] = useState(
+ typeof window !== 'undefined' ? location.pathname.includes('docs') : false,
+ );
const [isCommunity, setIsCommunity] = useState(false);
const searchBarItem = items.find(item => item.type === 'search');
-
+
const [currentVersion, setCurrentVersion] = useState('');
useEffect(() => {
getGithubStar();
@@ -139,8 +141,7 @@
function getNavItem(type: string) {
return items.find(item => item.type === type);
}
-
-
+
return (
<NavbarContentLayout
left={
@@ -166,10 +167,7 @@
{!isDocsPage ? (
<NavbarItems items={leftItems} />
) : (
- <NavbarItems
- items={leftDocItems}
- isDocsPage={isDocsPage}
- />
+ <NavbarItems items={leftDocItems} isDocsPage={isDocsPage} />
)}
</div>
{/* */}
diff --git a/src/theme/SearchBar/EmptyTemplate.js b/src/theme/SearchBar/EmptyTemplate.js
new file mode 100644
index 0000000..0c67ba6
--- /dev/null
+++ b/src/theme/SearchBar/EmptyTemplate.js
@@ -0,0 +1,12 @@
+import { translate } from "@docusaurus/Translate";
+import { iconNoResults } from "./icons";
+import styles from "./SearchBar.module.css";
+export function EmptyTemplate() {
+ if (process.env.NODE_ENV === "production") {
+ return `<span class="${styles.noResults}"><span class="${styles.noResultsIcon}">${iconNoResults}</span><span>${translate({
+ id: "theme.SearchBar.noResultsText",
+ message: "No results",
+ })}</span></span>`;
+ }
+ return `<span class="${styles.noResults}">⚠️ The search index is only available when you run docusaurus build!</span>`;
+}
diff --git a/src/theme/SearchBar/SearchBar.jsx b/src/theme/SearchBar/SearchBar.jsx
new file mode 100644
index 0000000..3272a11
--- /dev/null
+++ b/src/theme/SearchBar/SearchBar.jsx
@@ -0,0 +1,402 @@
+import React, { useCallback, useEffect, useRef, useState } from 'react';
+import clsx from 'clsx';
+import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
+import useIsBrowser from '@docusaurus/useIsBrowser';
+import { useHistory, useLocation } from '@docusaurus/router';
+import { translate } from '@docusaurus/Translate';
+import { ReactContextError, useDocsPreferredVersion } from '@docusaurus/theme-common';
+import { useActivePlugin } from '@docusaurus/plugin-content-docs/client';
+import { fetchIndexesByWorker, searchByWorker } from './searchByWorker';
+import { SuggestionTemplate } from './SuggestionTemplate';
+import { EmptyTemplate } from './EmptyTemplate';
+import {
+ Mark,
+ searchBarShortcut,
+ searchBarShortcutHint,
+ searchBarPosition,
+ docsPluginIdForPreferredVersion,
+ indexDocs,
+ searchContextByPaths,
+ hideSearchBarWithNoSearchContext,
+ useAllContextsWithNoSearchContext,
+} from '../../utils/proxiedGenerated';
+import LoadingRing from '../LoadingRing/LoadingRing';
+import styles from './SearchBar.module.css';
+import { normalizeContextByPath } from '../../utils/normalizeContextByPath';
+import useIsDocPage from '@site/src/hooks/use-is-doc';
+import { VERSIONS } from '@site/src/constant/common';
+async function fetchAutoCompleteJS() {
+ const autoCompleteModule = await import('@easyops-cn/autocomplete.js');
+ const autoComplete = autoCompleteModule.default;
+ if (autoComplete.noConflict) {
+ // For webpack v5 since docusaurus v2.0.0-alpha.75
+ autoComplete.noConflict();
+ } else if (autoCompleteModule.noConflict) {
+ // For webpack v4 before docusaurus v2.0.0-alpha.74
+ autoCompleteModule.noConflict();
+ }
+ return autoComplete;
+}
+const SEARCH_PARAM_HIGHLIGHT = '_highlight';
+export default function SearchBar({ handleSearchBarToggle }) {
+ const isBrowser = useIsBrowser();
+ const location = useLocation();
+ const {
+ siteConfig: { baseUrl },
+ i18n: { currentLocale },
+ } = useDocusaurusContext();
+ // It returns undefined for non-docs pages
+ const activePlugin = useActivePlugin();
+ const [isDocsPage] = useIsDocPage(false);
+ let versionUrl = baseUrl;
+ if (location?.pathname && location.pathname.includes('zh-CN') && !versionUrl.includes('zh-CN')) {
+ versionUrl = baseUrl + 'zh-CN/';
+ }
+ if (location?.pathname) {
+ VERSIONS.forEach(version => {
+ if (location.pathname.includes(version)) {
+ versionUrl += `docs/${version}/`;
+ }
+ });
+ }
+
+ // For non-docs pages while using plugin-content-docs with custom ids,
+ // this will throw an error of:
+ // > Docusaurus plugin global data not found for "docusaurus-plugin-content-docs" plugin with id "default".
+ // It seems that we can not get the correct id for non-docs pages.
+ // try {
+ // // The try-catch is a hack because useDocsPreferredVersion just throws an
+ // // exception when versions are not used.
+ // // The same hack is used in SearchPage.tsx
+ // // eslint-disable-next-line react-hooks/rules-of-hooks
+ // const { preferredVersion } = useDocsPreferredVersion(activePlugin?.pluginId ?? docsPluginIdForPreferredVersion);
+ // console.log('preferredVersion',preferredVersion);
+
+ // if (preferredVersion && !preferredVersion.isLast) {
+ // versionUrl = preferredVersion.path + "/";
+ // }
+ // }
+ // catch (e) {
+ // if (indexDocs) {
+ // if (e instanceof ReactContextError) {
+ // /* ignore, happens when website doesn't use versions */
+ // }
+ // else {
+ // throw e;
+ // }
+ // }
+ // }
+
+ const history = useHistory();
+ const searchBarRef = useRef(null);
+ const indexStateMap = useRef(new Map());
+ // Should the input be focused after the index is loaded?
+ const focusAfterIndexLoaded = useRef(false);
+ const [loading, setLoading] = useState(false);
+ const [inputChanged, setInputChanged] = useState(false);
+ const [inputValue, setInputValue] = useState('');
+ const search = useRef(null);
+ const prevSearchContext = useRef('');
+ const [searchContext, setSearchContext] = useState('');
+ useEffect(() => {
+ if (!Array.isArray(searchContextByPaths)) {
+ return;
+ }
+ let nextSearchContext = '';
+ if (location.pathname.startsWith(versionUrl)) {
+ const uri = location.pathname.substring(versionUrl.length);
+ let matchedPath;
+ for (const _path of searchContextByPaths) {
+ const path = typeof _path === 'string' ? _path : _path.path;
+ if (uri === path || uri.startsWith(`${path}/`)) {
+ matchedPath = path;
+ break;
+ }
+ }
+ if (matchedPath) {
+ nextSearchContext = matchedPath;
+ }
+ }
+ if (prevSearchContext.current !== nextSearchContext) {
+ // Reset index state map once search context is changed.
+ indexStateMap.current.delete(nextSearchContext);
+ prevSearchContext.current = nextSearchContext;
+ }
+ setSearchContext(nextSearchContext);
+ }, [location.pathname, versionUrl]);
+ const hidden = !!hideSearchBarWithNoSearchContext && Array.isArray(searchContextByPaths) && searchContext === '';
+ const loadIndex = useCallback(async () => {
+ if (hidden || indexStateMap.current.get(searchContext)) {
+ // Do not load the index (again) if its already loaded or in the process of being loaded.
+ return;
+ }
+ indexStateMap.current.set(searchContext, 'loading');
+ search.current?.autocomplete.destroy();
+ setLoading(true);
+ const [autoComplete] = await Promise.all([
+ fetchAutoCompleteJS(),
+ fetchIndexesByWorker(versionUrl, searchContext),
+ ]);
+ const searchFooterLinkElement = ({ query, isEmpty }) => {
+ const a = document.createElement('a');
+ const params = new URLSearchParams();
+ params.set('q', query);
+ let linkText;
+ if (searchContext) {
+ const detailedSearchContext =
+ searchContext && Array.isArray(searchContextByPaths)
+ ? searchContextByPaths.find(item =>
+ typeof item === 'string' ? item === searchContext : item.path === searchContext,
+ )
+ : searchContext;
+ const translatedSearchContext = detailedSearchContext
+ ? normalizeContextByPath(detailedSearchContext, currentLocale).label
+ : searchContext;
+ if (useAllContextsWithNoSearchContext && isEmpty) {
+ linkText = translate(
+ {
+ id: 'theme.SearchBar.seeAllOutsideContext',
+ message: 'See all results outside "{context}"',
+ },
+ { context: translatedSearchContext },
+ );
+ } else {
+ linkText = translate(
+ {
+ id: 'theme.SearchBar.searchInContext',
+ message: 'See all results within "{context}"',
+ },
+ { context: translatedSearchContext },
+ );
+ }
+ } else {
+ linkText = translate({
+ id: 'theme.SearchBar.seeAll',
+ message: 'See all results',
+ });
+ }
+ if (
+ searchContext &&
+ Array.isArray(searchContextByPaths) &&
+ (!useAllContextsWithNoSearchContext || !isEmpty)
+ ) {
+ params.set('ctx', searchContext);
+ }
+ if (versionUrl !== baseUrl) {
+ if (!versionUrl.startsWith(baseUrl)) {
+ throw new Error(
+ `Version url '${versionUrl}' does not start with base url '${baseUrl}', this is a bug of \`@easyops-cn/docusaurus-search-local\`, please report it.`,
+ );
+ }
+ params.set('version', versionUrl.substring(baseUrl.length));
+ }
+ const url = `${baseUrl}search/?${params.toString()}`;
+ a.href = url;
+ a.textContent = linkText;
+ a.addEventListener('click', e => {
+ if (!e.ctrlKey && !e.metaKey) {
+ e.preventDefault();
+ search.current?.autocomplete.close();
+ history.push(url);
+ }
+ });
+ return a;
+ };
+ search.current = autoComplete(
+ searchBarRef.current,
+ {
+ hint: false,
+ autoselect: true,
+ openOnFocus: true,
+ cssClasses: {
+ root: clsx(styles.searchBar, {
+ [styles.searchBarLeft]: searchBarPosition === 'left',
+ }),
+ noPrefix: true,
+ dropdownMenu: styles.dropdownMenu,
+ input: styles.input,
+ hint: styles.hint,
+ suggestions: styles.suggestions,
+ suggestion: styles.suggestion,
+ cursor: styles.cursor,
+ dataset: styles.dataset,
+ empty: styles.empty,
+ },
+ },
+ [
+ {
+ source: async (input, callback) => {
+ const result = await searchByWorker(versionUrl, searchContext, input);
+ callback(result);
+ },
+ templates: {
+ suggestion: SuggestionTemplate,
+ empty: EmptyTemplate,
+ footer: ({ query, isEmpty }) => {
+ if (isEmpty && (!searchContext || !useAllContextsWithNoSearchContext)) {
+ return;
+ }
+ const a = searchFooterLinkElement({ query, isEmpty });
+ const div = document.createElement('div');
+ div.className = styles.hitFooter;
+ div.appendChild(a);
+ return div;
+ },
+ },
+ },
+ ],
+ )
+ .on('autocomplete:selected', function (event, { document: { u, h }, tokens }) {
+ searchBarRef.current?.blur();
+ let url = u;
+ if (Mark && tokens.length > 0) {
+ const params = new URLSearchParams();
+ for (const token of tokens) {
+ params.append(SEARCH_PARAM_HIGHLIGHT, token);
+ }
+ url += `?${params.toString()}`;
+ }
+ if (h) {
+ url += h;
+ }
+ history.push(url);
+ })
+ .on('autocomplete:closed', () => {
+ searchBarRef.current?.blur();
+ });
+ indexStateMap.current.set(searchContext, 'done');
+ setLoading(false);
+ if (focusAfterIndexLoaded.current) {
+ const input = searchBarRef.current;
+ if (input.value) {
+ search.current?.autocomplete.open();
+ }
+ input.focus();
+ }
+ }, [hidden, searchContext, versionUrl, baseUrl, history]);
+ useEffect(() => {
+ if (!Mark) {
+ return;
+ }
+ const keywords = isBrowser ? new URLSearchParams(location.search).getAll(SEARCH_PARAM_HIGHLIGHT) : [];
+ // A workaround to fix an issue of highlighting in code blocks.
+ // See https://github.com/easyops-cn/docusaurus-search-local/issues/92
+ // Code blocks will be re-rendered after this `useEffect` ran.
+ // So we make the marking run after a macro task.
+ setTimeout(() => {
+ const root = document.querySelector('article');
+ if (!root) {
+ return;
+ }
+ const mark = new Mark(root);
+ mark.unmark();
+ if (keywords.length !== 0) {
+ mark.mark(keywords);
+ }
+ // Apply any keywords to the search input so that we can clear marks in case we loaded a page with a highlight in the url
+ setInputValue(keywords.join(' '));
+ search.current?.autocomplete.setVal(keywords.join(' '));
+ });
+ }, [isBrowser, location.search, location.pathname]);
+ const [focused, setFocused] = useState(false);
+ const onInputFocus = useCallback(() => {
+ focusAfterIndexLoaded.current = true;
+ loadIndex();
+ setFocused(true);
+ handleSearchBarToggle?.(true);
+ }, [handleSearchBarToggle, loadIndex]);
+ const onInputBlur = useCallback(() => {
+ setFocused(false);
+ handleSearchBarToggle?.(false);
+ }, [handleSearchBarToggle]);
+ const onInputMouseEnter = useCallback(() => {
+ loadIndex();
+ }, [loadIndex]);
+ const onInputChange = useCallback(event => {
+ setInputValue(event.target.value);
+ if (event.target.value) {
+ setInputChanged(true);
+ }
+ }, []);
+ // Implement hint icons for the search shortcuts on mac and the rest operating systems.
+ const isMac = isBrowser ? /mac/i.test(navigator.userAgentData?.platform ?? navigator.platform) : false;
+ useEffect(() => {
+ if (!searchBarShortcut) {
+ return;
+ }
+ // Add shortcuts command/ctrl + K
+ const handleShortcut = event => {
+ if ((isMac ? event.metaKey : event.ctrlKey) && (event.key === 'k' || event.key === 'K')) {
+ event.preventDefault();
+ searchBarRef.current?.focus();
+ onInputFocus();
+ }
+ };
+ document.addEventListener('keydown', handleShortcut);
+ return () => {
+ document.removeEventListener('keydown', handleShortcut);
+ };
+ }, [isMac, onInputFocus]);
+
+ useEffect(() => {
+ if (isDocsPage) {
+ loadIndex();
+ }
+ }, [location.pathname, isDocsPage]);
+
+ const onClearSearch = useCallback(() => {
+ const params = new URLSearchParams(location.search);
+ params.delete(SEARCH_PARAM_HIGHLIGHT);
+ const paramsStr = params.toString();
+ const searchUrl = location.pathname + (paramsStr != '' ? `?${paramsStr}` : '') + location.hash;
+ if (searchUrl != location.pathname + location.search + location.hash) {
+ history.push(searchUrl);
+ }
+ // We always clear these here because in case no match was selected the above history push wont happen
+ setInputValue('');
+ search.current?.autocomplete.setVal('');
+ }, [location.pathname, location.search, location.hash, history]);
+
+ return (
+ <div
+ className={clsx('navbar__search', styles.searchBarContainer, {
+ [styles.searchIndexLoading]: loading && inputChanged,
+ [styles.focused]: focused,
+ })}
+ hidden={hidden}
+ // Manually make the search bar be LTR even if in RTL
+ dir="ltr"
+ >
+ <input
+ placeholder={translate({
+ id: 'theme.SearchBar.label',
+ message: 'Search',
+ description: 'The ARIA label and placeholder for search button',
+ })}
+ aria-label="Search"
+ className={clsx('navbar__search-input', styles.navbarSearchInput)}
+ onMouseEnter={onInputMouseEnter}
+ onFocus={onInputFocus}
+ onBlur={onInputBlur}
+ onChange={onInputChange}
+ ref={searchBarRef}
+ value={inputValue}
+ />
+ <LoadingRing className={styles.searchBarLoadingRing} />
+ {searchBarShortcut &&
+ searchBarShortcutHint &&
+ (inputValue !== '' ? (
+ <button className={styles.searchClearButton} onClick={onClearSearch}>
+ ✕
+ </button>
+ ) : (
+ isBrowser && (
+ <div className={styles.searchHintContainer}>
+ <kbd className={styles.searchHint}>{isMac ? '⌘' : 'ctrl'}</kbd>
+ <kbd className={styles.searchHint}>K</kbd>
+ </div>
+ )
+ ))}
+ </div>
+ );
+}
diff --git a/src/theme/SearchBar/SearchBar.module.css b/src/theme/SearchBar/SearchBar.module.css
new file mode 100644
index 0000000..c5d9dfb
--- /dev/null
+++ b/src/theme/SearchBar/SearchBar.module.css
@@ -0,0 +1,298 @@
+.searchBar .dropdownMenu {
+ left: auto !important;
+ right: 0 !important;
+
+ background: var(--search-local-modal-background, #f5f6f7);
+ border-radius: 6px;
+ box-shadow: var(
+ --search-local-modal-shadow,
+ inset 1px 1px 0 0 hsla(0, 0%, 100%, 0.5),
+ 0 3px 8px 0 #555a64
+ );
+ margin-top: 8px;
+ width: var(--search-local-modal-width, 560px);
+ position: relative;
+
+ padding: var(--search-local-spacing, 12px);
+}
+
+.navbarSearchInput {
+ border: none !important;
+ background-color: #f7f9fe !important;
+ background-image: url('/static/images/search-icon.svg');
+ height: 2.5rem !important;
+ background-position: 0.625rem center !important;
+ padding-left: 2.25rem !important;
+ color: #4c576c !important;
+ width: 15.43rem !important;
+ border-radius: 0.5rem;
+}
+
+
+@media not (max-width: 996px) {
+ .searchBar.searchBarLeft .dropdownMenu {
+ left: 0 !important;
+ right: auto !important;
+ }
+}
+
+@media (max-width: 576px) {
+ :global(.navbar__search-input):not(:focus) {
+ width: 2rem;
+ }
+
+ .searchBar .dropdownMenu {
+ width: var(--search-local-modal-width-sm, 340px);
+ max-width: calc(100vw - var(--ifm-navbar-padding-horizontal) * 2);
+ }
+}
+
+html[data-theme="dark"] .searchBar .dropdownMenu {
+ background: var(--search-local-modal-background, var(--ifm-background-color));
+ box-shadow: var(
+ --search-local-modal-shadow,
+ inset 1px 1px 0 0 #2c2e40,
+ 0 3px 8px 0 #000309
+ );
+}
+
+.searchBar .dropdownMenu .suggestion {
+ cursor: pointer;
+ background: var(--search-local-hit-background, #fff);
+ border-radius: 4px;
+ box-shadow: var(--search-local-hit-shadow, 0 1px 3px 0 #d4d9e1);
+ padding: 0 var(--search-local-spacing, 12px);
+ width: 100%;
+
+ align-items: center;
+ color: var(--search-local-hit-color, #444950);
+ display: flex;
+ flex-direction: row;
+ height: var(--search-local-hit-height, 56px);
+}
+
+html[data-theme="dark"] .dropdownMenu .suggestion {
+ background: var(--search-local-hit-background, var(--ifm-color-emphasis-100));
+ box-shadow: var(--search-local-hit-shadow, none);
+ color: var(--search-local-hit-color, var(--ifm-font-color-base));
+}
+
+.searchBar .dropdownMenu .suggestion:not(:last-child) {
+ margin-bottom: 4px;
+}
+
+.searchBar .dropdownMenu .suggestion.cursor {
+ background-color: var(
+ --search-local-highlight-color,
+ var(--ifm-color-primary)
+ );
+}
+
+.hitTree,
+.hitIcon,
+.hitPath,
+.noResultsIcon,
+.hitFooter a {
+ color: var(--search-local-muted-color, #969faf);
+}
+
+html[data-theme="dark"] .hitTree,
+html[data-theme="dark"] .hitIcon,
+html[data-theme="dark"] .hitPath,
+html[data-theme="dark"] .noResultsIcon {
+ color: var(--search-local-muted-color, var(--ifm-color-secondary-darkest));
+}
+
+.hitTree {
+ display: flex;
+ align-items: center;
+}
+
+.hitTree > svg {
+ height: var(--search-local-hit-height, 56px);
+ opacity: 0.5;
+ stroke-width: var(--search-local-icon-stroke-width, 1.4);
+ width: 24px;
+}
+
+.hitIcon {
+ stroke-width: var(--search-local-icon-stroke-width, 1.4);
+
+ height: 20px;
+ width: 20px;
+}
+
+.hitWrapper {
+ flex: 1 1 auto;
+ display: flex;
+ flex-direction: column;
+ font-weight: 500;
+ justify-content: center;
+ margin: 0 8px;
+ overflow-x: hidden;
+ width: 80%;
+}
+
+.hitWrapper mark {
+ background: none;
+ color: var(--search-local-highlight-color, var(--ifm-color-primary));
+}
+
+.hitTitle {
+ font-size: 0.9em;
+}
+
+.hitPath {
+ font-size: 0.75em;
+}
+
+.hitPath,
+.hitTitle {
+ white-space: nowrap;
+ overflow-x: hidden;
+ text-overflow: ellipsis;
+}
+
+.hitAction {
+ height: 20px;
+ width: 20px;
+}
+
+.hideAction > svg {
+ display: none;
+}
+
+.noResults {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: var(--search-local-spacing, 12px) 0;
+}
+
+.noResultsIcon {
+ margin-bottom: var(--search-local-spacing, 12px);
+}
+
+.hitFooter {
+ text-align: center;
+ margin-top: var(--search-local-spacing, 12px);
+ font-size: 0.85em;
+}
+
+.hitFooter a {
+ text-decoration: underline;
+}
+
+.cursor .hideAction > svg {
+ display: block;
+}
+
+.suggestion.cursor,
+.suggestion.cursor mark,
+.suggestion.cursor .hitTree,
+.suggestion.cursor .hitIcon,
+.suggestion.cursor .hitPath {
+ color: var(
+ --search-local-hit-active-color,
+ var(--ifm-color-white)
+ ) !important;
+}
+
+.suggestion.cursor mark {
+ text-decoration: underline;
+}
+
+.searchBarContainer {
+ margin-left: 16px;
+}
+
+.searchBarContainer .searchBarLoadingRing {
+ display: none;
+ position: absolute;
+ left: 10px;
+ top: 6px;
+}
+
+.searchBarContainer .searchClearButton {
+ position: absolute;
+ right: 0.8rem;
+ top: 50%;
+ transform: translate(0, -50%);
+ padding: 0;
+ background: none;
+ border: none;
+ line-height: 1rem;
+}
+
+:global(.navbar__search) {
+ position: relative;
+}
+
+.searchIndexLoading :global(.navbar__search-input) {
+ background-image: none;
+}
+
+.searchBarContainer.searchIndexLoading .searchBarLoadingRing {
+ display: inline-block;
+}
+
+.searchHintContainer {
+ position: absolute;
+ right: 10px;
+ top: 0px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: 100%;
+ pointer-events: none;
+ gap: 4px;
+}
+
+.searchHint {
+ color: var(--ifm-navbar-search-input-placeholder-color);
+ background-color: var(--ifm-navbar-search-input-background-color);
+ border: 1px solid var(--ifm-color-emphasis-500);
+ box-shadow: inset 0 -1px 0 var(--ifm-color-emphasis-500);
+}
+
+@media (max-width: 576px) {
+ .searchBarContainer:not(.focused) .searchClearButton,
+ .searchHintContainer {
+ display: none;
+ }
+}
+
+html[dir="rtl"] .searchHintContainer {
+ right: auto;
+ left: 10px;
+}
+
+html[dir="rtl"] .searchBarContainer .searchClearButton {
+ right: auto;
+ left: 0.8rem;
+}
+
+html[dir="rtl"] .searchBarContainer .searchBarLoadingRing {
+ left: auto;
+ right: 10px;
+}
+
+html[dir="rtl"] :global(.navbar__search-input) {
+ padding: 0 2.25em 0 0.5em;
+}
+
+/* For autocomplete.js only. */
+.input {
+}
+.hint {
+}
+.suggestions {
+ max-height: 500px !important;
+ overflow: scroll !important;
+}
+.dataset {
+}
+.empty {
+}
+/**/
diff --git a/src/theme/SearchBar/SuggestionTemplate.js b/src/theme/SearchBar/SuggestionTemplate.js
new file mode 100644
index 0000000..427a6a6
--- /dev/null
+++ b/src/theme/SearchBar/SuggestionTemplate.js
@@ -0,0 +1,54 @@
+import { SearchDocumentType, } from "../../../shared/interfaces";
+import { concatDocumentPath } from "../../utils/concatDocumentPath";
+import { getStemmedPositions } from "../../utils/getStemmedPositions";
+import { highlight } from "../../utils/highlight";
+import { highlightStemmed } from "../../utils/highlightStemmed";
+import { explicitSearchResultPath } from "../../utils/proxiedGenerated";
+import { iconAction, iconContent, iconHeading, iconTitle, iconTreeInter, iconTreeLast, } from "./icons";
+import styles from "./SearchBar.module.css";
+export function SuggestionTemplate({ document, type, page, metadata, tokens, isInterOfTree, isLastOfTree, }) {
+ const isTitle = type === SearchDocumentType.Title;
+ const isKeywords = type === SearchDocumentType.Keywords;
+ const isTitleRelated = isTitle || isKeywords;
+ const isHeading = type === SearchDocumentType.Heading;
+ const tree = [];
+ if (isInterOfTree) {
+ tree.push(iconTreeInter);
+ }
+ else if (isLastOfTree) {
+ tree.push(iconTreeLast);
+ }
+ const treeWrapper = tree.map((item) => `<span class="${styles.hitTree}">${item}</span>`);
+ const icon = `<span class="${styles.hitIcon}">${isTitleRelated ? iconTitle : isHeading ? iconHeading : iconContent}</span>`;
+ const wrapped = [
+ `<span class="${styles.hitTitle}">${isKeywords
+ ? highlight(document.s, tokens)
+ : highlightStemmed(document.t, getStemmedPositions(metadata, "t"), tokens)}</span>`,
+ ];
+ const needsExplicitHitPath = !isInterOfTree && !isLastOfTree && explicitSearchResultPath;
+ if (needsExplicitHitPath) {
+ const pathItems = page
+ ? page.b
+ ?.concat(page.t)
+ .concat(!document.s || document.s === page.t ? [] : document.s)
+ : document.b;
+ wrapped.push(`<span class="${styles.hitPath}">${concatDocumentPath(pathItems ?? [])}</span>`);
+ }
+ else if (!isTitleRelated) {
+ wrapped.push(`<span class="${styles.hitPath}">${highlight(page.t ||
+ // Todo(weareoutman): This is for EasyOps only.
+ // istanbul ignore next
+ (document.u.startsWith("/docs/api-reference/")
+ ? "API Reference"
+ : ""), tokens)}</span>`);
+ }
+ const action = `<span class="${styles.hitAction}">${iconAction}</span>`;
+ return [
+ ...treeWrapper,
+ icon,
+ `<span class="${styles.hitWrapper}">`,
+ ...wrapped,
+ "</span>",
+ action,
+ ].join("");
+}
diff --git a/src/theme/SearchBar/__mocks__/icons.js b/src/theme/SearchBar/__mocks__/icons.js
new file mode 100644
index 0000000..7c2f79e
--- /dev/null
+++ b/src/theme/SearchBar/__mocks__/icons.js
@@ -0,0 +1,7 @@
+export const iconTitle = '<svg class="icon-title"></svg>';
+export const iconHeading = '<svg class="icon-heading"></svg>';
+export const iconContent = '<svg class="icon-content"></svg>';
+export const iconAction = '<svg class="icon-action"></svg>';
+export const iconNoResults = '<svg class="icon-no-results"></svg>';
+export const iconTreeInter = '<svg class="icon-tree-inner"></svg>';
+export const iconTreeLast = '<svg class="icon-tree-last"></svg>';
diff --git a/src/theme/SearchBar/icons.js b/src/theme/SearchBar/icons.js
new file mode 100644
index 0000000..d538021
--- /dev/null
+++ b/src/theme/SearchBar/icons.js
@@ -0,0 +1,7 @@
+export const iconTitle = '<svg width="20" height="20" viewBox="0 0 20 20"><path d="M17 6v12c0 .52-.2 1-1 1H4c-.7 0-1-.33-1-1V2c0-.55.42-1 1-1h8l5 5zM14 8h-3.13c-.51 0-.87-.34-.87-.87V4" stroke="currentColor" fill="none" fill-rule="evenodd" stroke-linejoin="round"></path></svg>';
+export const iconHeading = '<svg width="20" height="20" viewBox="0 0 20 20"><path d="M13 13h4-4V8H7v5h6v4-4H7V8H3h4V3v5h6V3v5h4-4v5zm-6 0v4-4H3h4z" stroke="currentColor" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"></path></svg>';
+export const iconContent = '<svg width="20" height="20" viewBox="0 0 20 20"><path d="M17 5H3h14zm0 5H3h14zm0 5H3h14z" stroke="currentColor" fill="none" fill-rule="evenodd" stroke-linejoin="round"></path></svg>';
+export const iconAction = '<svg width="20" height="20" viewBox="0 0 20 20"><g stroke="currentColor" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"><path d="M18 3v4c0 2-2 4-4 4H2"></path><path d="M8 17l-6-6 6-6"></path></g></svg>';
+export const iconNoResults = '<svg width="40" height="40" viewBox="0 0 20 20" fill="none" fill-rule="evenodd" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="M15.5 4.8c2 3 1.7 7-1 9.7h0l4.3 4.3-4.3-4.3a7.8 7.8 0 01-9.8 1m-2.2-2.2A7.8 7.8 0 0113.2 2.4M2 18L18 2"></path></svg>';
+export const iconTreeInter = '<svg viewBox="0 0 24 54"><g stroke="currentColor" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"><path d="M8 6v42M20 27H8.3"></path></g></svg>';
+export const iconTreeLast = '<svg viewBox="0 0 24 54"><g stroke="currentColor" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"><path d="M8 6v21M20 27H8.3"></path></g></svg>';
diff --git a/src/theme/SearchBar/index.js b/src/theme/SearchBar/index.js
index 381d901..369df71 100644
--- a/src/theme/SearchBar/index.js
+++ b/src/theme/SearchBar/index.js
@@ -1,10 +1,3 @@
-import React from 'react';
-import SearchBar from '@theme-original/SearchBar';
-
-export default function SearchBarWrapper(props) {
- return (
- <>
- <SearchBar {...props} />
- </>
- );
-}
+import "../../utils/proxiedGenerated";
+import SearchBar from "./SearchBar";
+export default SearchBar;
diff --git a/src/theme/SearchBar/searchByWorker.js b/src/theme/SearchBar/searchByWorker.js
new file mode 100644
index 0000000..cd53fa7
--- /dev/null
+++ b/src/theme/SearchBar/searchByWorker.js
@@ -0,0 +1,24 @@
+import * as Comlink from "comlink";
+let remoteWorkerPromise;
+function getRemoteWorker() {
+ if (process.env.NODE_ENV === "production" && !remoteWorkerPromise) {
+ remoteWorkerPromise = (async () => {
+ const Remote = Comlink.wrap(new Worker(new URL("./worker.js", import.meta.url)));
+ return await new Remote();
+ })();
+ }
+ return remoteWorkerPromise;
+}
+export async function fetchIndexesByWorker(baseUrl, searchContext) {
+ if (process.env.NODE_ENV === "production") {
+ const remoteWorker = await getRemoteWorker();
+ await remoteWorker.fetchIndexes(baseUrl, searchContext);
+ }
+}
+export async function searchByWorker(baseUrl, searchContext, input) {
+ if (process.env.NODE_ENV === "production") {
+ const remoteWorker = await getRemoteWorker();
+ return remoteWorker.search(baseUrl, searchContext, input);
+ }
+ return [];
+}
diff --git a/src/theme/SearchBar/worker.js b/src/theme/SearchBar/worker.js
new file mode 100644
index 0000000..b2d3d11
--- /dev/null
+++ b/src/theme/SearchBar/worker.js
@@ -0,0 +1,94 @@
+import * as Comlink from "comlink";
+import lunr from "lunr";
+import { searchIndexUrl, searchResultLimits, language } from "@easyops-cn/docusaurus-search-local/dist/client/client/utils/proxiedGeneratedConstants";
+import { tokenize } from "@easyops-cn/docusaurus-search-local/dist/client/client/utils/tokenize";
+import { smartQueries } from "@easyops-cn/docusaurus-search-local/dist/client/client/utils/smartQueries";
+import { SearchDocumentType, } from "../../shared/interfaces";
+import { sortSearchResults } from "@easyops-cn/docusaurus-search-local/dist/client/client/utils/sortSearchResults";
+import { processTreeStatusOfSearchResults } from "@easyops-cn/docusaurus-search-local/dist/client/client/utils/processTreeStatusOfSearchResults";
+const cache = new Map();
+export class SearchWorker {
+ async fetchIndexes(baseUrl, searchContext) {
+ await this.lowLevelFetchIndexes(baseUrl, searchContext);
+ }
+ async lowLevelFetchIndexes(baseUrl, searchContext) {
+ const cacheKey = `${baseUrl}${searchContext}`;
+ let promise = cache.get(cacheKey);
+ if (!promise) {
+ promise = legacyFetchIndexes(baseUrl, searchContext);
+ cache.set(cacheKey, promise);
+ }
+ return promise;
+ }
+ async search(baseUrl, searchContext, input) {
+ const rawTokens = tokenize(input, language);
+ if (rawTokens.length === 0) {
+ return [];
+ }
+ const { wrappedIndexes, zhDictionary } = await this.lowLevelFetchIndexes(baseUrl, searchContext);
+ const queries = smartQueries(rawTokens, zhDictionary);
+ const results = [];
+ search: for (const { term, tokens } of queries) {
+ for (const { documents, index, type } of wrappedIndexes) {
+ results.push(...index
+ .query((query) => {
+ for (const item of term) {
+ query.term(item.value, {
+ wildcard: item.wildcard,
+ presence: item.presence,
+ });
+ }
+ })
+ .slice(0, searchResultLimits)
+ // Remove duplicated results.
+ .filter((result) => !results.some((item) => item.document.i.toString() === result.ref))
+ .slice(0, searchResultLimits - results.length)
+ .map((result) => {
+ const document = documents.find((doc) => doc.i.toString() === result.ref);
+ return {
+ document,
+ type,
+ page: type !== SearchDocumentType.Title &&
+ wrappedIndexes[0].documents.find((doc) => doc.i === document.p),
+ metadata: result.matchData.metadata,
+ tokens,
+ score: result.score,
+ };
+ }));
+ if (results.length >= searchResultLimits) {
+ break search;
+ }
+ }
+ }
+ sortSearchResults(results);
+ processTreeStatusOfSearchResults(results);
+ return results;
+ }
+}
+async function legacyFetchIndexes(baseUrl, searchContext) {
+ const url = `${baseUrl}${searchIndexUrl.replace("{dir}", searchContext ? `-${searchContext.replace(/\//g, "-")}` : "")}`;
+ // Catch potential attacks.
+ const fullUrl = new URL(url, location.origin);
+ if (fullUrl.origin !== location.origin) {
+ throw new Error("Unexpected version url");
+ }
+ const json = (await (await fetch(url)).json());
+ const wrappedIndexes = json.map(({ documents, index }, type) => ({
+ type: type,
+ documents,
+ index: lunr.Index.load(index),
+ }));
+ const zhDictionary = json.reduce((acc, item) => {
+ for (const tuple of item.index.invertedIndex) {
+ if (/\p{Unified_Ideograph}/u.test(tuple[0][0])) {
+ acc.add(tuple[0]);
+ }
+ }
+ return acc;
+ }, new Set());
+ return {
+ wrappedIndexes,
+ zhDictionary: Array.from(zhDictionary),
+ };
+}
+Comlink.expose(SearchWorker);
diff --git a/src/theme/TOC/index.tsx b/src/theme/TOC/index.tsx
index d08817f..5571d8e 100644
--- a/src/theme/TOC/index.tsx
+++ b/src/theme/TOC/index.tsx
@@ -6,7 +6,9 @@
import HomeIcon from '@site/static/images/toc-icon/home.svg';
import PdfIcon from '@site/static/images/toc-icon/pdf.svg';
import GithubIcon from '@site/static/images/toc-icon/github.svg';
+import ConcatIcon from '@site/static/images/toc-icon/concat.svg';
import { DOWNLOAD_PDFS } from '@site/src/constant/download.data';
+import { VERSIONS } from '@site/src/constant/common';
import Link from '@docusaurus/Link';
import styles from './styles.module.css';
@@ -37,14 +39,14 @@
const [currentVersion, setCurrentVersion] = useState(DEFAULT_VERSION);
const handleMouseEnter = (id: string) => {
const dom = document.getElementById(id);
- dom.style.color = '#444FD9';
- dom.firstChild.style.fill = '#444FD9';
+ dom!.style.color = '#444FD9';
+ dom!.firstChild!.style.fill = '#444FD9';
};
const handleMouseLeave = (id: string) => {
const dom = document.getElementById(id);
- dom.style.color = '#1F1F26';
- dom.firstChild.style.fill = '#7F7F83';
+ dom!.style.color = '#1F1F26';
+ dom!.firstChild!.style.fill = '#7F7F83';
};
useEffect(() => {
@@ -55,7 +57,7 @@
const secPath = location.pathname.includes('zh-CN/docs')
? location.pathname.split('/')[3]
: location.pathname.split('/')[2];
- if (pathname === 'docs' && ['dev', '3.0', '2.0', '1.2'].includes(secPath)) {
+ if (pathname === 'docs' && VERSIONS.includes(secPath)) {
setCurrentVersion(secPath);
} else {
setCurrentVersion(DEFAULT_VERSION);
@@ -100,7 +102,7 @@
onMouseEnter={() => handleMouseEnter('toc-icon-github')}
onMouseLeave={() => handleMouseLeave('toc-icon-github')}
>
- <GithubIcon />
+ {isCN ? <ConcatIcon /> : <GithubIcon />}
<span>{isCN ? '技术论坛' : 'Ask Questions on Discussion'}</span>
</Link>
</div>
diff --git a/src/utils/normalizeContextByPath.js b/src/utils/normalizeContextByPath.js
new file mode 100644
index 0000000..99c29d6
--- /dev/null
+++ b/src/utils/normalizeContextByPath.js
@@ -0,0 +1,24 @@
+export function normalizeContextByPath(context, currentLocale) {
+ if (typeof context === "string") {
+ return {
+ label: context,
+ path: context,
+ };
+ }
+ else {
+ const { label, path } = context;
+ if (typeof label === "string") {
+ return { label, path };
+ }
+ if (Object.prototype.hasOwnProperty.call(label, currentLocale)) {
+ return {
+ label: label[currentLocale],
+ path,
+ };
+ }
+ return {
+ label: path,
+ path,
+ };
+ }
+}
diff --git a/static/images/toc-icon/concat.svg b/static/images/toc-icon/concat.svg
new file mode 100644
index 0000000..7b77546
--- /dev/null
+++ b/static/images/toc-icon/concat.svg
@@ -0,0 +1,21 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="#7F7F83" xmlns="http://www.w3.org/2000/svg">
+ <g clip-path="url(#clip0_8016_3647)">
+ <path
+ d="M3.04395 4.7041C3.04395 4.28989 3.37973 3.9541 3.79395 3.9541H16.2575C16.6717 3.9541 17.0075 4.28989 17.0075 4.7041V13.1767C17.0075 13.591 16.6717 13.9267 16.2575 13.9267H10.0218C9.86403 13.9267 9.71031 13.9765 9.58246 14.0689L5.67114 16.8957L6.09631 13.9267H3.79395C3.37973 13.9267 3.04395 13.591 3.04395 13.1767V4.7041Z"
+ />
+ <path
+ d="M6.5 9.93701C7.05228 9.93701 7.5 9.4893 7.5 8.93701C7.5 8.38473 7.05228 7.93701 6.5 7.93701C5.94772 7.93701 5.5 8.38473 5.5 8.93701C5.5 9.4893 5.94772 9.93701 6.5 9.93701Z"
+ fill="white" />
+ <path
+ d="M10 9.93701C10.5523 9.93701 11 9.4893 11 8.93701C11 8.38473 10.5523 7.93701 10 7.93701C9.44772 7.93701 9 8.38473 9 8.93701C9 9.4893 9.44772 9.93701 10 9.93701Z"
+ fill="white" />
+ <path
+ d="M13.5 9.93701C14.0523 9.93701 14.5 9.4893 14.5 8.93701C14.5 8.38473 14.0523 7.93701 13.5 7.93701C12.9477 7.93701 12.5 8.38473 12.5 8.93701C12.5 9.4893 12.9477 9.93701 13.5 9.93701Z"
+ fill="white" />
+ </g>
+ <defs>
+ <clipPath id="clip0_8016_3647">
+ <rect width="20" height="20" />
+ </clipPath>
+ </defs>
+</svg>
\ No newline at end of file
diff --git a/static/images/toc-icon/github-active.svg b/static/images/toc-icon/github-active.svg
deleted file mode 100644
index 904b642..0000000
--- a/static/images/toc-icon/github-active.svg
+++ /dev/null
@@ -1,12 +0,0 @@
-<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
- <g clip-path="url(#clip0_8019_4572)">
- <path
- d="M11.0061 3C14.9792 2.99839 18.1973 6.21483 18.1973 10.1848C18.1973 13.3241 16.1842 15.9927 13.3806 16.9727C13.0031 17.0675 13.0609 16.7992 13.0609 16.616V15.3709C15.2411 15.6263 15.3295 14.1836 15.4757 13.9426C15.7713 13.4381 16.4702 13.3096 16.2613 13.0686C15.7649 12.8132 15.2588 13.1329 14.6724 13.9989C14.2482 14.627 13.4208 14.521 13.0015 14.4166C12.9099 14.039 12.7139 13.7016 12.444 13.4398C14.7029 13.0349 15.6444 11.6564 15.6444 10.0177C15.6444 9.2224 15.3825 8.49139 14.8684 7.90177C15.1961 6.92977 14.8378 6.09754 14.7896 5.97384C13.8562 5.89029 12.8858 6.64219 12.8103 6.70163C12.2801 6.55864 11.6744 6.48313 10.9964 6.48313C10.3152 6.48313 9.70794 6.56185 9.17294 6.70645C8.99139 6.56828 8.09169 5.92242 7.22412 6.00115C7.17753 6.12486 6.82728 6.9378 7.13575 7.89695C6.61521 8.48818 6.35012 9.22562 6.35012 10.0225C6.35012 11.6644 7.29802 13.0445 9.56334 13.443C9.18579 13.8157 8.95122 14.333 8.95122 14.905V16.7124C8.93837 16.857 8.95122 17 8.71023 17C5.86493 16.0409 3.8165 13.353 3.8165 10.1864C3.8165 6.21483 7.03614 3 11.0061 3Z"
- fill="#636CDF" />
- </g>
- <defs>
- <clipPath id="clip0_8019_4572">
- <rect width="21" height="20" fill="white" />
- </clipPath>
- </defs>
-</svg>
\ No newline at end of file
diff --git a/static/images/toc-icon/home-active.svg b/static/images/toc-icon/home-active.svg
deleted file mode 100644
index 1cb9a98..0000000
--- a/static/images/toc-icon/home-active.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
- <path fill-rule="evenodd" clip-rule="evenodd"
- d="M3.33983 6.44003C3.06163 6.62549 2.89453 6.93773 2.89453 7.27208V16.2106C2.89453 16.6466 3.24799 17.0001 3.684 17.0001H16.3156C16.7516 17.0001 17.1051 16.6466 17.1051 16.2106V7.27208C17.1051 6.93773 16.938 6.62549 16.6598 6.44003L10.5545 2.36985C10.2186 2.14592 9.78099 2.14592 9.44509 2.36985L3.33983 6.44003ZM10.6001 10.6001C10.6001 10.2687 10.3315 10.0001 10.0001 10.0001C9.66873 10.0001 9.4001 10.2687 9.4001 10.6001L9.4001 13.9001C9.4001 14.2314 9.66873 14.5001 10.0001 14.5001C10.3315 14.5001 10.6001 14.2314 10.6001 13.9001V10.6001Z"
- fill="#636CDF" />
-</svg>
\ No newline at end of file
diff --git a/static/images/toc-icon/pdf-active.svg b/static/images/toc-icon/pdf-active.svg
deleted file mode 100644
index 3e9bf42..0000000
--- a/static/images/toc-icon/pdf-active.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
- <path
- d="M15.1754 4H4.28648C3.43093 4 2.73096 4.70001 2.73096 5.55559V16.4445C2.73096 17.3 3.43093 18 4.28648 18H15.1754C16.031 18 16.731 17.3 16.731 16.4445V5.55559C16.7309 4.70005 16.0309 4 15.1754 4ZM9.38379 9.99791C9.20496 10.5735 8.9996 11.4635 8.69752 12.1952C8.54177 12.5909 8.54931 12.522 8.43222 12.7719L8.53333 12.7391C9.57248 12.4483 10.3 12.3762 10.9767 12.2517C10.8409 12.1445 10.7229 12.0616 10.6295 11.9761C10.1646 11.4614 10.0023 11.3648 9.38379 9.99791ZM14.4834 13.2945C14.3512 13.4423 14.1179 13.5278 13.7757 13.5278C13.1845 13.5278 12.6473 13.3646 11.8694 12.9679C10.5316 13.1157 9.10894 13.2724 8.30779 13.529C8.26889 13.5445 8.22232 13.5601 8.16779 13.5835C7.20334 15.2323 6.48721 15.9314 5.85782 15.9036C5.65823 15.8948 5.36806 15.779 5.2747 15.7246L5.15937 15.6151L5.11878 15.5381C5.06438 15.398 5.04885 15.2658 5.07992 15.118C5.16549 14.7058 5.60882 14.0525 6.54219 13.4692C6.68998 13.3602 7.02728 13.188 7.33836 13.0402C7.57376 12.6657 7.68248 12.4258 7.98104 11.7624C8.31886 10.9608 8.62662 10.0029 8.82105 9.31852V9.31074C8.53336 8.36958 8.36222 7.73134 8.64997 6.69682C8.71997 6.40128 8.97655 6.09795 9.26448 6.09795H9.45109C9.62999 6.09795 9.8011 6.16021 9.92556 6.28457C10.4389 6.79797 10.1977 8.12065 9.94113 9.15516C9.92556 9.20177 9.91774 9.24063 9.90999 9.26399C10.2211 10.1429 10.7129 11.0108 11.2029 11.4153C11.4051 11.5707 11.6032 11.7495 11.8521 11.8895C12.2021 11.8505 12.5156 11.8167 12.8344 11.8167C13.7989 11.8167 14.3823 11.9879 14.6078 12.3534C14.6856 12.4778 14.7245 12.6256 14.7012 12.7811C14.6934 12.9756 14.6235 13.1545 14.4834 13.2945ZM13.9919 12.6447C13.9141 12.5669 13.6908 12.3451 12.6018 12.3451C12.5475 12.3451 12.414 12.3313 12.3441 12.409C12.9118 12.6579 13.4552 12.8468 13.8129 12.8468C13.8675 12.8468 13.9141 12.839 13.9607 12.8313H13.9918C14.0307 12.8158 14.0541 12.8079 14.0619 12.7302C14.0464 12.7068 14.0308 12.6757 13.9919 12.6447ZM7.14576 13.7595C6.9824 13.8528 6.85022 13.9383 6.7724 14.0006C6.22018 14.5062 5.87017 15.0195 5.83128 15.3152C6.18125 15.1985 6.64012 14.685 7.14576 13.7595ZM9.36649 8.4927L9.40535 8.46155C9.45981 8.21269 9.49787 7.94535 9.54455 7.77417L9.56788 7.64974C9.64563 7.20638 9.61594 6.94731 9.48369 6.7607L9.36701 6.72177C9.34721 6.75189 9.32903 6.78304 9.31254 6.81509C9.18036 7.14178 9.18759 7.79272 9.36649 8.4927Z"
- fill="#636CDF" />
-</svg>
\ No newline at end of file