From 5c800623ada14bf1090f328c9a5c354eefe5e14e Mon Sep 17 00:00:00 2001 From: Daniel Leroux Date: Tue, 21 May 2024 12:09:56 +0200 Subject: [PATCH] docs(installation): align instructions between frameworks (#1282) Co-authored-by: Lukas Maurer --- .../docs/installation/angular.md | 40 +- .../docs/installation/javascript.md | 42 +- .../documentation/docs/installation/react.md | 40 +- .../documentation/docs/installation/vue.md | 38 +- packages/documentation/package.json | 16 +- .../src/components/FrameworkSelection.tsx | 11 +- .../documentation/src/components/Icons.tsx | 7 +- .../src/components/PlaygroundV2/index.tsx | 2 +- .../src/components/SwitchTheme.tsx | 32 +- packages/documentation/src/css/search.scss | 83 ++-- .../src/theme/Navbar/Logo/index.tsx | 7 +- .../src/theme/SearchBar/DocSearch.js | 15 +- .../SearchBar/HighlightSearchResults.jsx | 53 +++ .../src/theme/SearchBar/algolia.css | 4 + .../src/theme/SearchBar/index.jsx | 148 +++++++ .../src/theme/SearchBar/index.tsx | 123 ------ .../src/theme/SearchBar/lunar-search.js | 7 +- .../src/theme/SearchBar/templates.js | 2 +- .../src/theme/SiteMetadata/index.tsx | 149 +++++++ packages/documentation/tsconfig.json | 3 +- pnpm-lock.yaml | 363 +++++++++++------- 21 files changed, 770 insertions(+), 415 deletions(-) create mode 100644 packages/documentation/src/theme/SearchBar/HighlightSearchResults.jsx create mode 100644 packages/documentation/src/theme/SearchBar/index.jsx delete mode 100644 packages/documentation/src/theme/SearchBar/index.tsx create mode 100644 packages/documentation/src/theme/SiteMetadata/index.tsx diff --git a/packages/documentation/docs/installation/angular.md b/packages/documentation/docs/installation/angular.md index d259e42639..276c10d03f 100644 --- a/packages/documentation/docs/installation/angular.md +++ b/packages/documentation/docs/installation/angular.md @@ -3,22 +3,30 @@ sidebar_position: 1 sidebar_title: Angular title: Angular --- - -### Install dependencies - -Install `@siemens/ix-angular` and `@siemens/ix-icons` using a package manager: - -#### npm - -``` -npm i -S @siemens/ix-angular @siemens/ix-icons -``` - -#### yarn - -``` -yarn add @siemens/ix-angular @siemens/ix-icons -``` +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +### Library installation + +Install `@siemens/ix`, `@siemens/ix-angular` and `@siemens/ix-icons` using a package manager: + + + + ``` + npm install @siemens/ix @siemens/ix-angular @siemens/ix-icons + ``` + + + ``` + yarn add @siemens/ix @siemens/ix-angular @siemens/ix-icons + ``` + + + ``` + pnpm add @siemens/ix @siemens/ix-angular @siemens/ix-icons + ``` + + ### Import styles diff --git a/packages/documentation/docs/installation/javascript.md b/packages/documentation/docs/installation/javascript.md index e0ecdeb686..6644ef6af2 100644 --- a/packages/documentation/docs/installation/javascript.md +++ b/packages/documentation/docs/installation/javascript.md @@ -3,24 +3,31 @@ sidebar_position: 3 sidebar_title: Web Components title: Web Components --- - +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; import Playground from '@site/src/components/PlaygroundV2'; -## Installation +### Library installation Install `@siemens/ix` and `@siemens/ix-icons` using a package manager: -### npm - -``` -npm i -S @siemens/ix @siemens/ix-icons -``` - -### yarn - -``` -yarn add @siemens/ix @siemens/ix-icons -``` + + + ``` + npm install @siemens/ix @siemens/ix-icons + ``` + + + ``` + yarn add @siemens/ix @siemens/ix-icons + ``` + + + ``` + pnpm add @siemens/ix @siemens/ix-icons + ``` + + ## Build @@ -50,13 +57,12 @@ In the following section we will describe how you can build an application with ```javascript import '@siemens/ix/dist/siemens-ix/siemens-ix.css'; -import { applyPolyfills, defineCustomElements } from '@siemens/ix/loader'; -import { defineCustomElements as ixIconsDefineCustomElements } from '@siemens/ix-icons/loader'; +import { defineCustomElements } from '@siemens/ix/loader'; +import { defineCustomElements as defineIxIconCustomElement } from '@siemens/ix-icons/loader'; (async () => { - await applyPolyfills(); - await ixIconsDefineCustomElements(); - await defineCustomElements(); + defineIxIconCustomElement(); + defineCustomElements(); })(); ``` diff --git a/packages/documentation/docs/installation/react.md b/packages/documentation/docs/installation/react.md index 828e8c8bc4..0be9d70882 100644 --- a/packages/documentation/docs/installation/react.md +++ b/packages/documentation/docs/installation/react.md @@ -3,22 +3,30 @@ sidebar_position: 2 sidebar_title: React title: React --- - -### Install dependencies - -Install `@siemens/ix-react` and `@siemens/ix-icons` using a package manager: - -#### npm - -``` -npm i -S @siemens/ix-react @siemens/ix-icons -``` - -#### yarn - -``` -yarn add @siemens/ix-react@latest @siemens/ix-icons -``` +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +### Library installation + +Install `@siemens/ix`, `@siemens/ix-react` and `@siemens/ix-icons` using a package manager: + + + + ``` + npm install @siemens/ix @siemens/ix-react @siemens/ix-icons + ``` + + + ``` + yarn add @siemens/ix @siemens/ix-react @siemens/ix-icons + ``` + + + ``` + pnpm add @siemens/ix @siemens/ix-react @siemens/ix-icons + ``` + + ### Import styles diff --git a/packages/documentation/docs/installation/vue.md b/packages/documentation/docs/installation/vue.md index 7398bbec1c..f3ac015fbe 100644 --- a/packages/documentation/docs/installation/vue.md +++ b/packages/documentation/docs/installation/vue.md @@ -3,6 +3,8 @@ sidebar_position: 4 sidebar_title: Vue title: Vue --- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; :::caution Experimental disclaimer @@ -12,21 +14,27 @@ Nevertheless feedback of any kind will be helpful. ::: -### Install dependencies - -Install `@siemens/ix-vue` and `@siemens/ix-icons` using a package manager: - -#### npm - -``` -npm i -S @siemens/ix-vue @siemens/ix-icons -``` - -#### yarn - -``` -yarn add @siemens/ix-vue@latest @siemens/ix-icons -``` +### Library installation + +Install `@siemens/ix`, `@siemens/ix-vue` and `@siemens/ix-icons` using a package manager: + + + + ``` + npm install @siemens/ix @siemens/ix-vue @siemens/ix-icons + ``` + + + ``` + yarn add @siemens/ix @siemens/ix-vue @siemens/ix-icons + ``` + + + ``` + pnpm add @siemens/ix @siemens/ix-vue @siemens/ix-icons + ``` + + ### Usage diff --git a/packages/documentation/package.json b/packages/documentation/package.json index 02cacfc5fd..1db229e25d 100644 --- a/packages/documentation/package.json +++ b/packages/documentation/package.json @@ -20,17 +20,17 @@ "generate-changelog": "ts-node -P ./scripts/tsconfig.json ./scripts/generate-changelog.ts" }, "dependencies": { - "@docusaurus/core": "3.1.0", - "@docusaurus/preset-classic": "3.1.0", - "@docusaurus/theme-live-codeblock": "3.1.0", + "@docusaurus/core": "3.3.2", + "@docusaurus/preset-classic": "3.3.2", + "@docusaurus/theme-live-codeblock": "3.3.2", "@mdx-js/react": "^3.0.0", "@siemens/ix": "workspace:*", "@siemens/ix-echarts": "workspace:*", - "@siemens/ix-icons": "2.1.0", + "@siemens/ix-icons": "^2.0.0", "@siemens/ix-react": "workspace:*", "@stackblitz/sdk": "^1.8.1", "clsx": "^1.2.1", - "docusaurus-lunr-search": "^2.3.2", + "docusaurus-lunr-search": "^3.4.0", "docusaurus-plugin-sass": "^0.2.2", "execa": "^5.1.1", "html-test-app": "workspace:*", @@ -42,9 +42,9 @@ "sass": "^1.54.8" }, "devDependencies": { - "@docusaurus/module-type-aliases": "3.1.0", - "@docusaurus/tsconfig": "3.1.0", - "@docusaurus/types": "3.1.0", + "@docusaurus/module-type-aliases": "3.3.2", + "@docusaurus/tsconfig": "3.3.2", + "@docusaurus/types": "3.3.2", "@types/fs-extra": "^9.0.13", "@types/rimraf": "^3.0.2", "@types/tar": "^6.1.7", diff --git a/packages/documentation/src/components/FrameworkSelection.tsx b/packages/documentation/src/components/FrameworkSelection.tsx index 15ea678f08..08bf9ba93f 100644 --- a/packages/documentation/src/components/FrameworkSelection.tsx +++ b/packages/documentation/src/components/FrameworkSelection.tsx @@ -7,6 +7,7 @@ * LICENSE file in the root directory of this source tree. */ +import { IxSelect, IxSelectItem } from '@siemens/ix-react'; import React, { useEffect, useLayoutEffect, useRef, useState } from 'react'; export default function FrameworkSelection(): JSX.Element { @@ -35,18 +36,18 @@ export default function FrameworkSelection(): JSX.Element { }, [ref]); return ( - - - - + > + + ); } diff --git a/packages/documentation/src/components/Icons.tsx b/packages/documentation/src/components/Icons.tsx index 6f4906aaf8..33ce8efc41 100644 --- a/packages/documentation/src/components/Icons.tsx +++ b/packages/documentation/src/components/Icons.tsx @@ -11,6 +11,7 @@ import ICON_LIST from '@siemens/ix-icons/dist/sample.json'; import clsx from 'clsx'; import React, { useRef, useState } from 'react'; import styles from './Icons.module.css'; +import { IxIcon } from '@siemens/ix-react'; const Icons: React.FC = () => { const refs = useRef<{ [k: string]: any }>({}); @@ -38,10 +39,10 @@ const Icons: React.FC = () => {
{}} + onClick={() => { }} >
- +
{ @@ -51,7 +52,7 @@ const Icons: React.FC = () => { type="text" readOnly value={icon} - onChange={() => {}} + onChange={() => { }} >
))} diff --git a/packages/documentation/src/components/PlaygroundV2/index.tsx b/packages/documentation/src/components/PlaygroundV2/index.tsx index 20f3dd718e..dcba6a5b89 100644 --- a/packages/documentation/src/components/PlaygroundV2/index.tsx +++ b/packages/documentation/src/components/PlaygroundV2/index.tsx @@ -189,7 +189,7 @@ function SourceCodePreview(props: { let filesToFetch = []; if (props.framework === TargetFramework.ANGULAR) { - filesToFetch = [`${props.name}.ts`, `${props.name}.html`]; + filesToFetch.push(...[`${props.name}.html`, `${props.name}.ts`]); } if (props.framework === TargetFramework.JAVASCRIPT) { diff --git a/packages/documentation/src/components/SwitchTheme.tsx b/packages/documentation/src/components/SwitchTheme.tsx index 0568f71eb1..8d8c7ad220 100644 --- a/packages/documentation/src/components/SwitchTheme.tsx +++ b/packages/documentation/src/components/SwitchTheme.tsx @@ -14,6 +14,12 @@ import { ThemeChangeEvent } from '../utils/theme-change-event'; import { getDefaultTheme } from './config'; import styles from './SwitchTheme.module.css'; +function applyThemeToBody(themes: string[], theme: string) { + themes.forEach((t) => document.body.classList.remove(t)); + + setTimeout(() => document.body.classList.add(theme), 0) +} + function ThemeEntry(props: { label: string; color: string; @@ -57,21 +63,6 @@ export function SwitchTheme(props: { }, ]); - useEffect(() => { - let storedTheme = localStorage.getItem('theme'); - - if (!storedTheme) { - const theme = getDefaultTheme(context); - setTheme(theme); - localStorage.setItem('theme', theme); - storedTheme = theme; - } else { - setTheme(storedTheme); - } - - document.body.className = storedTheme; - }, []); - useEffect(() => { if (context.siteConfig.customFields.withBrandTheme) { setRegisteredThemes([ @@ -88,16 +79,19 @@ export function SwitchTheme(props: { }, ]); } + + let storedTheme = window.localStorage.getItem('docusaurus-theme'); + + onThemeChange(storedTheme || getDefaultTheme(context)); }, []); const onThemeChange = (theme: string) => { setTheme(theme); - localStorage.setItem('theme', theme); - document.body.className = theme; - + window.localStorage.setItem('docusaurus-theme', theme); dispatchThemeChange(theme); - setOpen(false); + + applyThemeToBody(registeredThemes.map((t) => t.id), theme); }; function getLabel(id: string = 'theme-classic-dark') { diff --git a/packages/documentation/src/css/search.scss b/packages/documentation/src/css/search.scss index 005910024c..9ed7f4b8a3 100644 --- a/packages/documentation/src/css/search.scss +++ b/packages/documentation/src/css/search.scss @@ -7,51 +7,28 @@ * LICENSE file in the root directory of this source tree. */ -.aa-DetachedSearchButton { - background-color: var(--theme-color-2) !important; - border: none !important; - - cursor: pointer !important; -} - -.aa-DetachedSearchButton:focus { - box-shadow: none !important; -} - -.aa-DetachedSearchButtonIcon { - color: var(--theme-color-std-text) !important; - cursor: pointer !important; - display: none !important; -} - -.aa-DetachedSearchButtonPlaceholder { - align-items: center; - display: flex; - justify-content: flex-start; - background-color: var(--theme-color-1); - width: 100%; - height: 1.875rem; - border-bottom: var(--theme-std-bdr-1); - padding-left: 0.5rem; - - font-family: Siemens Sans, Arial, sans-serif; - font-size: 12px; - font-weight: normal; - font-stretch: normal; + #search_input_react { + font-feature-settings: "clig" off, "liga" off; + font-family: Siemens Sans, Siemens Sans, Arial, Helvetica, sans-serif; font-style: normal; - line-height: 1.33; - letter-spacing: normal; - text-align: left; -} - -.aa-DetachedSearchButtonPlaceholder:active { - outline: none; - box-shadow: none; + font-size: var(--theme-ms-0); + line-height: var(--theme-line-height-md); + font-weight: var(--theme-font-weight-normal); + letter-spacing: var(--theme-letter-spacing-xl); + text-decoration: none; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smooting: grayscale; + min-height: 2rem; + width: 100%; + padding: 0.25rem 0.5rem; + background-color: var(--theme-input--background); + color: var(--theme-input--color); + text-overflow: ellipsis; + border: var(--theme-input--border-thickness, 1px) solid var(--theme-input--border-color); + border-radius: var(--theme-input--border-radius); + box-shadow: var(--theme-input--box-shadow); } -.aa-Label { - margin-bottom: 0px !important; -} @media (max-width: 500px) { #search_input_react { @@ -64,3 +41,25 @@ display: none; } } + +.ds-dropdown-menu { + color: var(--theme-color-std-text) !important; +} +.ds-dropdown-menu::before { + border-color: var(--theme-color-3) !important; + background-color: var(--theme-color-3) !important; +} + +.algolia-docsearch-suggestion--no-results, +.algolia-docsearch-suggestion--category-header { + color: var(--theme-input--color); + background-color: var(--theme-color-3) !important; +} + +.algolia-docsearch-suggestion--wrapper { + background-color: var(--theme-color-0) !important; +} + +.algolia-docsearch-suggestion--text { + color: var(--theme-input--color); +} diff --git a/packages/documentation/src/theme/Navbar/Logo/index.tsx b/packages/documentation/src/theme/Navbar/Logo/index.tsx index 8adb084f76..dcf7969392 100644 --- a/packages/documentation/src/theme/Navbar/Logo/index.tsx +++ b/packages/documentation/src/theme/Navbar/Logo/index.tsx @@ -14,11 +14,14 @@ export default function NavbarLogo(): JSX.Element { const [logo, setLogo] = useState(''); const updateLogo = () => { - if (!document.body.className.includes('theme-')) { + const theme = /theme-(.*)/g; + const dark = /theme-(.*)-dark/g; + + if (!theme.test(document.body.className)) { setLogo(`${base}img/logo.svg`); return; } - if (document.body.className.includes('-dark')) { + if (dark.test(document.body.className)) { setLogo(`${base}img/logo.svg`); } else { setLogo(`${base}img/logo-dark.svg`); diff --git a/packages/documentation/src/theme/SearchBar/DocSearch.js b/packages/documentation/src/theme/SearchBar/DocSearch.js index 19d8fdf9ee..77a53de996 100644 --- a/packages/documentation/src/theme/SearchBar/DocSearch.js +++ b/packages/documentation/src/theme/SearchBar/DocSearch.js @@ -22,7 +22,8 @@ class DocSearch { queryHook = false, handleSelected = false, enhancedSearchInput = false, - layout = "collumns" + layout = "column", + maxHits = 5 }) { this.input = DocSearch.getInputFromSelector(inputSelector); this.queryDataCallback = queryDataCallback || null; @@ -46,7 +47,7 @@ class DocSearch { this.isSimpleLayout = layout === "simple"; - this.client = new LunrSearchAdapter(searchDocs, searchIndex, baseUrl); + this.client = new LunrSearchAdapter(searchDocs, searchIndex, baseUrl, maxHits); if (enhancedSearchInput) { this.input = DocSearch.injectSearchBox(this.input); @@ -85,6 +86,16 @@ class DocSearch { if (enhancedSearchInput) { DocSearch.bindSearchBoxEvent(); } + + // Ctrl/Cmd + K should focus the search bar, emulating the Algolia search UI + document.addEventListener('keydown', (e) => { + if ((e.ctrlKey || e.metaKey) && e.key == 'k') { + this.input.focus(); + + // By default, using Ctrl + K in Chrome will open the location bar, so disable this + e.preventDefault(); + } + }); } static injectSearchBox(input) { diff --git a/packages/documentation/src/theme/SearchBar/HighlightSearchResults.jsx b/packages/documentation/src/theme/SearchBar/HighlightSearchResults.jsx new file mode 100644 index 0000000000..8e703994b4 --- /dev/null +++ b/packages/documentation/src/theme/SearchBar/HighlightSearchResults.jsx @@ -0,0 +1,53 @@ +//copied from https://github.com/cmfcmf/docusaurus-search-local +import Mark from "mark.js"; +import { useEffect, useState } from "react"; +import { useLocation } from "@docusaurus/router"; +import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; +import { useHistory } from "@docusaurus/router"; + +export function HighlightSearchResults() { + const location = useLocation(); + const history = useHistory(); + const { + siteConfig: { baseUrl }, + } = useDocusaurusContext(); + + const [highlightData, setHighlightData] = useState({ wordToHighlight: '', isTitleSuggestion: false , titleText: '' }); + + useEffect(() => { + if ( + !location.state?.highlightState || + location.state.highlightState.wordToHighlight.length === 0 + ) { + return; + } + setHighlightData(location.state.highlightState); + + const { highlightState, ...state } = location.state; + history.replace({ + ...location, + state, + }); + }, [location.state?.highlightState, history, location]); + + useEffect(() => { + if (highlightData.wordToHighlight.length === 0) { + return; + } + + // Make sure to also adjust parse.js if you change the top element here. + const root = document.getElementsByTagName("article")[0] ?? document.getElementsByTagName("main")[0] ; + if (!root) { + return; + } + + const mark = new Mark(root); + const options = { + ignoreJoiners: true, + }; + mark.mark(highlightData.wordToHighlight , options); + return () => mark.unmark(options); + }, [highlightData, baseUrl]); + + return null; +} diff --git a/packages/documentation/src/theme/SearchBar/algolia.css b/packages/documentation/src/theme/SearchBar/algolia.css index ca89694575..9b92cb3ba7 100644 --- a/packages/documentation/src/theme/SearchBar/algolia.css +++ b/packages/documentation/src/theme/SearchBar/algolia.css @@ -547,3 +547,7 @@ html[data-theme='dark'] .algolia-docsearch-suggestion--title { html[data-theme='dark'] .ds-cursor .algolia-docsearch-suggestion--wrapper { background: var(--ifm-background-surface-color) !important; } + +mark { + background-color: lightblue; +} diff --git a/packages/documentation/src/theme/SearchBar/index.jsx b/packages/documentation/src/theme/SearchBar/index.jsx new file mode 100644 index 0000000000..5d0f158b97 --- /dev/null +++ b/packages/documentation/src/theme/SearchBar/index.jsx @@ -0,0 +1,148 @@ +import React, { useRef, useCallback, useState, useEffect } from "react"; +import clsx from "clsx"; +import { useHistory } from "@docusaurus/router"; +import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; +import { usePluginData } from '@docusaurus/useGlobalData'; +import useIsBrowser from "@docusaurus/useIsBrowser"; +import { HighlightSearchResults } from "./HighlightSearchResults"; +const Search = props => { + const initialized = useRef(false); + const searchBarRef = useRef(null); + const [indexReady, setIndexReady] = useState(false); + const history = useHistory(); + const { siteConfig = {} } = useDocusaurusContext(); + const pluginConfig = (siteConfig.plugins || []).find(plugin => Array.isArray(plugin) && typeof plugin[0] === "string" && plugin[0].includes("docusaurus-lunr-search")) + const isBrowser = useIsBrowser(); + const { baseUrl } = siteConfig; + const assetUrl = pluginConfig && pluginConfig[1]?.assetUrl || baseUrl; + const initAlgolia = (searchDocs, searchIndex, DocSearch, options) => { + new DocSearch({ + searchDocs, + searchIndex, + baseUrl, + inputSelector: "#search_input_react", + // Override algolia's default selection event, allowing us to do client-side + // navigation and avoiding a full page refresh. + handleSelected: (_input, _event, suggestion) => { + const url = suggestion.url || "/"; + // Use an anchor tag to parse the absolute url into a relative url + // Alternatively, we can use new URL(suggestion.url) but its not supported in IE + const a = document.createElement("a"); + a.href = url; + _input.setVal(''); // clear value + _event.target.blur(); // remove focus + + // Get the highlight word from the suggestion. + let wordToHighlight = ''; + if (options.highlightResult) { + try { + const matchedLine = suggestion.text || suggestion.subcategory || suggestion.title; + const matchedWordResult = matchedLine.match(new RegExp('\\w*', 'g')); + if (matchedWordResult && matchedWordResult.length > 0) { + const tempDoc = document.createElement('div'); + tempDoc.innerHTML = matchedWordResult[0]; + wordToHighlight = tempDoc.textContent; + } + } catch (e) { + console.log(e); + } + } + + history.push(url, { + highlightState: { wordToHighlight }, + }); + }, + maxHits: options.maxHits + }); + }; + + const pluginData = usePluginData('docusaurus-lunr-search'); + const getSearchDoc = () => + process.env.NODE_ENV === "production" + ? fetch(`${assetUrl}${pluginData.fileNames.searchDoc}`).then((content) => content.json()) + : Promise.resolve({}); + + const getLunrIndex = () => + process.env.NODE_ENV === "production" + ? fetch(`${assetUrl}${pluginData.fileNames.lunrIndex}`).then((content) => content.json()) + : Promise.resolve([]); + + const loadAlgolia = () => { + if (!initialized.current) { + Promise.all([ + getSearchDoc(), + getLunrIndex(), + import("./DocSearch"), + import("./algolia.css") + ]).then(([searchDocFile, searchIndex, { default: DocSearch }]) => { + const { searchDocs, options } = searchDocFile; + if (!searchDocs || searchDocs.length === 0) { + return; + } + initAlgolia(searchDocs, searchIndex, DocSearch, options); + setIndexReady(true); + }); + initialized.current = true; + } + }; + + const toggleSearchIconClick = useCallback( + e => { + if (!searchBarRef.current.contains(e.target)) { + searchBarRef.current.focus(); + } + + props.handleSearchBarToggle && props.handleSearchBarToggle(!props.isSearchBarExpanded); + }, + [props.isSearchBarExpanded] + ); + + let placeholder + if (isBrowser) { + loadAlgolia(); + placeholder = window.navigator.platform.startsWith("Mac") ? + 'Search ⌘+K' : 'Search Ctrl+K' + } + + // auto focus search bar on page load + useEffect(() => { + if (props.autoFocus && indexReady) { + searchBarRef.current.focus(); + } + }, [indexReady]); + + return ( +
+ + + +
+ ); +}; + +export default Search; diff --git a/packages/documentation/src/theme/SearchBar/index.tsx b/packages/documentation/src/theme/SearchBar/index.tsx deleted file mode 100644 index 47b1071a41..0000000000 --- a/packages/documentation/src/theme/SearchBar/index.tsx +++ /dev/null @@ -1,123 +0,0 @@ -import React, { useRef, useCallback, useState } from 'react'; -import clsx from 'clsx'; -import { useHistory } from '@docusaurus/router'; -import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; -import { usePluginData } from '@docusaurus/useGlobalData'; -import useIsBrowser from '@docusaurus/useIsBrowser'; - -const Search = (props) => { - const initialized = useRef(false); - const searchBarRef = useRef(null); - const [indexReady, setIndexReady] = useState(false); - const history = useHistory(); - const { siteConfig = {} } = useDocusaurusContext(); - const isBrowser = useIsBrowser(); - //@ts-ignore - const { baseUrl } = siteConfig; - const initAlgolia = (searchDocs, searchIndex, DocSearch) => { - new DocSearch({ - searchDocs, - searchIndex, - baseUrl, - inputSelector: '#search_input_react', - // Override algolia's default selection event, allowing us to do client-side - // navigation and avoiding a full page refresh. - handleSelected: (_input, _event, suggestion) => { - const url = suggestion.url || '/'; - // Use an anchor tag to parse the absolute url into a relative url - // Alternatively, we can use new URL(suggestion.url) but its not supported in IE - const a = document.createElement('a'); - a.href = url; - // Algolia use closest parent element id #__docusaurus when a h1 page title does not have an id - // So, we can safely remove it. See https://github.com/facebook/docusaurus/issues/1828 for more details. - - history.push(url); - }, - }); - }; - - const pluginData = usePluginData('docusaurus-lunr-search'); - const getSearchDoc = () => - process.env.NODE_ENV === 'production' - ? //@ts-ignore - fetch(`${baseUrl}${pluginData.fileNames.searchDoc}`).then((content) => - content.json() - ) - : Promise.resolve([]); - - const getLunrIndex = () => - process.env.NODE_ENV === 'production' - ? //@ts-ignore - fetch(`${baseUrl}${pluginData.fileNames.lunrIndex}`).then((content) => - content.json() - ) - : Promise.resolve([]); - - const loadAlgolia = () => { - if (!initialized.current) { - Promise.all([ - getSearchDoc(), - getLunrIndex(), - //@ts-ignore - import('./DocSearch'), - import('./algolia.css'), - ]).then(([searchDocs, searchIndex, { default: DocSearch }]) => { - if (searchDocs.length === 0) { - return; - } - initAlgolia(searchDocs, searchIndex, DocSearch); - setIndexReady(true); - }); - initialized.current = true; - } - }; - - const toggleSearchIconClick = useCallback( - (e) => { - if (!searchBarRef.current.contains(e.target)) { - searchBarRef.current.focus(); - } - - props.handleSearchBarToggle && - props.handleSearchBarToggle(!props.isSearchBarExpanded); - }, - [props.isSearchBarExpanded] - ); - - if (isBrowser) { - loadAlgolia(); - } - - return ( -
- - -
- ); -}; - -export default Search; diff --git a/packages/documentation/src/theme/SearchBar/lunar-search.js b/packages/documentation/src/theme/SearchBar/lunar-search.js index ab54de1fea..cac06c40df 100644 --- a/packages/documentation/src/theme/SearchBar/lunar-search.js +++ b/packages/documentation/src/theme/SearchBar/lunar-search.js @@ -2,10 +2,11 @@ import lunr from "@generated/lunr.client"; lunr.tokenizer.separator = /[\s\-/]+/; class LunrSearchAdapter { - constructor(searchDocs, searchIndex, baseUrl = '/') { + constructor(searchDocs, searchIndex, baseUrl = '/', maxHits) { this.searchDocs = searchDocs; this.lunrIndex = lunr.Index.load(searchIndex); this.baseUrl = baseUrl; + this.maxHits = maxHits; } getLunrResult(input) { @@ -116,7 +117,7 @@ class LunrSearchAdapter { return new Promise((resolve, rej) => { const results = this.getLunrResult(input); const hits = []; - results.length > 5 && (results.length = 5); + results.length > this.maxHits && (results.length = this.maxHits); this.titleHitsRes = [] this.contentHitsRes = [] results.forEach(result => { @@ -139,7 +140,7 @@ class LunrSearchAdapter { } } }); - hits.length > 5 && (hits.length = 5); + hits.length > this.maxHits && (hits.length = this.maxHits); resolve(hits); }); } diff --git a/packages/documentation/src/theme/SearchBar/templates.js b/packages/documentation/src/theme/SearchBar/templates.js index 354a98f82b..636c2c11fb 100644 --- a/packages/documentation/src/theme/SearchBar/templates.js +++ b/packages/documentation/src/theme/SearchBar/templates.js @@ -87,7 +87,7 @@ const templates = { searchBox: `