diff --git a/config/ssrTemplate.js b/config/ssrTemplate.js index 37923ae8cc43f..afaf56352808e 100644 --- a/config/ssrTemplate.js +++ b/config/ssrTemplate.js @@ -13,10 +13,10 @@ module.exports = { <%~ metaAttribute %> <% }); %> <% it.stylesheets.forEach((stylesheet) => { %> - + <% }); %> <% it.scripts.forEach((script) => { %> - + <% }); %>
> @@ -25,7 +25,7 @@ module.exports = { <%~ it.appHtml %> <% it.scripts.forEach((script) => { %> - + <% }); %> <%~ it.postBodyTags %> diff --git a/docusaurus.config.js b/docusaurus.config.js index 010d7b24170ae..92701cb023f17 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -77,7 +77,7 @@ const config = { sidebarPath: require.resolve('./sidebarsCommunity.json'), }), ], - process.env.NODE_ENV === 'development' ? null : customDocusaurusPlugin, + // process.env.NODE_ENV === 'development' ? null : customDocusaurusPlugin, [ '@docusaurus/plugin-pwa', { @@ -202,26 +202,37 @@ const config = { }), ], ], - themes: [ - [ - '@easyops-cn/docusaurus-search-local', - { - hashed: true, - language: ['en', 'zh'], - highlightSearchTermsOnTargetPage: true, - // indexPages: true, - indexDocs: true, - docsRouteBasePath: '/', - indexBlog: false, - explicitSearchResultPath: true, - searchBarShortcut: true, - searchBarShortcutHint: true, - }, - ], - ], + // themes: [ + // [ + // '@easyops-cn/docusaurus-search-local', + // { + // hashed: true, + // language: ['en', 'zh'], + // highlightSearchTermsOnTargetPage: true, + // // indexPages: true, + // indexDocs: true, + // docsRouteBasePath: '/', + // indexBlog: false, + // explicitSearchResultPath: true, + // searchBarShortcut: true, + // searchBarShortcutHint: true, + // }, + // ], + // ], themeConfig: /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ ({ + algolia: { + appId: 'UUKF60R98F', + apiKey: '1b34939eb7c1508a11571110b04cbc2e', + indexName: 'apache-doris', + contextualSearch: true, + searchParameters: { + facetFilters: ['docusaurus_tag', 'language', 'lang', 'version', 'type'], + }, + maxResultsPerGroup: 7, + debug: true, + }, matomo: { matomoUrl: 'https://analytics.apache.org/', siteId: '43', @@ -316,7 +327,8 @@ const config = { // to: '/docs/install/source-install/compilation-with-docker', type: 'doc', docId: 'install/source-install/compilation-with-docker', - activeBaseRegex: 'summary|install/cluster-deployment|install/source-install|db-connect|table-design|data-operate|query|lakehouse|compute-storage-decoupled|admin-manual|practical-guide|sql-manual', + activeBaseRegex: + 'summary|install/cluster-deployment|install/source-install|db-connect|table-design|data-operate|query|lakehouse|compute-storage-decoupled|admin-manual|practical-guide|sql-manual', }, { label: '性能测试', @@ -379,7 +391,8 @@ const config = { // to: '/docs/install/source-install/compilation-with-docker', type: 'doc', docId: 'install/source-install/compilation-with-docker', - activeBaseRegex: 'summary|install/cluster-deployment|install/source-install|db-connect|table-design|data-operate|query|lakehouse|compute-storage-decoupled|admin-manual|practical-guide|sql-manual' + activeBaseRegex: + 'summary|install/cluster-deployment|install/source-install|db-connect|table-design|data-operate|query|lakehouse|compute-storage-decoupled|admin-manual|practical-guide|sql-manual', }, { label: 'Benchmark', diff --git a/package.json b/package.json index 7afcd67caf91b..5393125cb87d2 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { "name": "doris-website", - "version": "2.0.0", + "version": "3.0.0", "private": true, "scripts": { "docusaurus": "docusaurus", "start": "docusaurus start", "start:zh-CN": "docusaurus start --locale zh-CN", - "build": "NODE_OPTIONS=--max_old_space_size=8192 PWA_SERVICE_WORKER_URL=https://doris.apache.org/sw.js docusaurus build", + "build": "NODE_OPTIONS=--max_old_space_size=12288 PWA_SERVICE_WORKER_URL=https://doris.apache.org/sw.js docusaurus build", "build:version": "docusaurus set-versions && docusaurus build", "swizzle": "docusaurus swizzle", "deploy": "docusaurus deploy", @@ -23,7 +23,6 @@ "@docusaurus/plugin-client-redirects": "^2.4.1", "@docusaurus/plugin-pwa": "^2.4.1", "@docusaurus/preset-classic": "^2.4.1", - "@easyops-cn/docusaurus-search-local": "^0.30.2", "@mdx-js/react": "^1.6.22", "antd": "^5.12.2", "autoprefixer": "^10.4.16", diff --git a/src/scss/custom.scss b/src/scss/custom.scss index 32e6d8cdb4fce..a4d7adc69acc9 100644 --- a/src/scss/custom.scss +++ b/src/scss/custom.scss @@ -18,14 +18,12 @@ @import './components/search'; @import './common'; - @layer utilities { .transition-slide { @apply inline-block transform transition-transform duration-300 hover:translate-x-1 group-hover:translate-x-1; } } - .button-primary { display: flex; height: 52px; @@ -34,16 +32,16 @@ align-items: center; gap: 4px; border-radius: 4px; - background: var(--b-1, #444FD9); + background: var(--b-1, #444fd9); color: white; } :root { - --font-family-base: "SF Pro Display", "SF Pro Icons", "Helvetica Neue", Helvetica, Arial, sans-serif; + --font-family-base: 'SF Pro Display', 'SF Pro Icons', 'Helvetica Neue', Helvetica, Arial, sans-serif; } .markdown :where(p, h1, h2, h3, h4, h5, h6, li, blockquote) { font-family: var(--font-family-base); - color: #2a2f34 + color: #2a2f34; } // body, .markdown { // font-family: var(--font-family-base); @@ -53,4 +51,58 @@ .navbar__link { font-family: var(--font-family-base); font-weight: 400 !important; -} \ No newline at end of file +} + +.DocSearch { + /* --docsearch-primary-color: var(--ifm-color-primary); */ + /* --docsearch-text-color: var(--ifm-font-color-base); */ + --docsearch-muted-color: var(--ifm-color-secondary-darkest); + --docsearch-container-background: rgba(94, 100, 112, 0.7); + /* 弹窗 */ + --docsearch-modal-background: var(--ifm-color-secondary-lighter); + /* 搜索框 */ + --docsearch-searchbox-background: var(--ifm-color-secondary); + --docsearch-searchbox-focus-background: var(--ifm-color-white); + /* 条目 */ + --docsearch-hit-color: var(--ifm-font-color-base); + --docsearch-hit-active-color: var(--ifm-color-white); + --docsearch-hit-background: var(--ifm-color-white); + /* 页脚 */ + --docsearch-footer-background: var(--ifm-color-white); + &.DocSearch-Button { + border-radius: 8px; + background-color: #f7f9fe; + height: 40px; + padding: 0 16px; + width: 247px; + color: #4c576c; + font-size: 14px; + font-weight: normal; + &:hover { + box-shadow: none; + background: #f7f9fe; + } + .DocSearch-Button-Placeholder { + color: #8592a6; + font-size: 12px; + font-weight: normal; + } + .DocSearch-Button-Keys { + min-width: auto; + background-color: #fff; + border-radius: 2px; + .DocSearch-Button-Key { + margin-right: 0; + box-shadow: none; + background: transparent; + border-radius: 0; + top: 1px; + width: 14px; + } + } + .DocSearch-Search-Icon { + width: 14px; + stroke-width: 1.5; + } + } +} diff --git a/src/theme/SearchBar/EmptyTemplate.js b/src/theme/SearchBar/EmptyTemplate.js deleted file mode 100644 index 0c67ba65f422a..0000000000000 --- a/src/theme/SearchBar/EmptyTemplate.js +++ /dev/null @@ -1,12 +0,0 @@ -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 `${iconNoResults}${translate({ - id: "theme.SearchBar.noResultsText", - message: "No results", - })}`; - } - return `⚠️ The search index is only available when you run docusaurus build!`; -} diff --git a/src/theme/SearchBar/SearchBar.jsx b/src/theme/SearchBar/SearchBar.jsx deleted file mode 100644 index 14154b5a238b0..0000000000000 --- a/src/theme/SearchBar/SearchBar.jsx +++ /dev/null @@ -1,281 +0,0 @@ -import React, { useCallback, useEffect, useRef, useState } from 'react'; -import clsx from 'clsx'; -import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; -import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; -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 { fetchIndexes } from './fetchIndexes'; -import { SearchSourceFactory } from '../../utils/SearchSourceFactory'; -import { SuggestionTemplate } from './SuggestionTemplate'; -import { EmptyTemplate } from './EmptyTemplate'; -import { - searchResultLimits, - Mark, - searchBarShortcut, - searchBarShortcutHint, - docsPluginIdForPreferredVersion, - indexDocs, -} from '../../utils/proxiedGenerated'; -import LoadingRing from '../LoadingRing/LoadingRing'; -import styles from './SearchBar.module.css'; -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 { - siteConfig: { baseUrl }, - } = useDocusaurusContext(); - // It returns undefined for non-docs pages - const activePlugin = useActivePlugin(); - let versionUrl = baseUrl; - // 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); - 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 location = useLocation(); - const searchBarRef = useRef(null); - const indexState = useRef('empty'); // empty, loaded, done - // 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 loadIndex = useCallback(async () => { - if (indexState.current !== 'empty') { - // Do not load the index (again) if its already loaded or in the process of being loaded. - return; - } - indexState.current = 'loading'; - setLoading(true); - const [{ wrappedIndexes, zhDictionary }, autoComplete] = await Promise.all([ - fetchIndexes(versionUrl), - fetchAutoCompleteJS(), - ]); - search.current = autoComplete( - searchBarRef.current, - { - hint: false, - autoselect: true, - openOnFocus: true, - cssClasses: { - root: styles.searchBar, - 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: SearchSourceFactory(wrappedIndexes, zhDictionary, searchResultLimits), - templates: { - suggestion: SuggestionTemplate, - empty: EmptyTemplate, - footer: ({ query, isEmpty }) => { - if (isEmpty) { - return; - } - const a = document.createElement('a'); - const url = `${baseUrl}search?q=${encodeURIComponent(query)}`; - a.href = url; - a.textContent = translate({ - id: 'theme.SearchBar.seeAll', - message: 'See all results', - }); - a.addEventListener('click', e => { - if (!e.ctrlKey && !e.metaKey) { - e.preventDefault(); - search.current.autocomplete.close(); - history.push(url); - } - }); - 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(); - }); - indexState.current = 'done'; - setLoading(false); - if (focusAfterIndexLoaded.current) { - const input = searchBarRef.current; - if (input.value) { - search.current.autocomplete.open(); - } - input.focus(); - } - }, [baseUrl, versionUrl, history]); - useEffect(() => { - if (!Mark) { - return; - } - const keywords = ExecutionEnvironment.canUseDOM - ? 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(' ')); - }); - }, [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 = ExecutionEnvironment.canUseDOM - ? /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.code === 'KeyK') { - event.preventDefault(); - searchBarRef.current?.focus(); - onInputFocus(); - } - }; - document.addEventListener('keydown', handleShortcut); - return () => { - document.removeEventListener('keydown', handleShortcut); - }; - }, [isMac, onInputFocus]); - 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 ( -
+