From 33787d52f5850d32a93a693530d78926700da0b2 Mon Sep 17 00:00:00 2001 From: weareoutman Date: Fri, 15 Dec 2023 11:25:12 +0800 Subject: [PATCH] feat(): customize search context labels closes #382 --- README.md | 56 +++++++++---------- .../src/client/theme/SearchBar/SearchBar.tsx | 11 +++- .../client/theme/SearchPage/SearchPage.tsx | 19 +++++-- docusaurus-search-local/src/declarations.ts | 5 +- docusaurus-search-local/src/index.ts | 2 +- .../src/server/utils/postBuildFactory.ts | 11 +++- .../src/server/utils/validateOptions.ts | 10 +++- website-multi-docs/docusaurus.config.js | 5 +- 8 files changed, 76 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index d0b8487c..d4227481 100644 --- a/README.md +++ b/README.md @@ -69,34 +69,34 @@ module.exports = { ## Theme Options -| Name | Type | Default | Description | -| --------------------------------- | ---------------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| indexDocs | boolean | `true` | Whether to index docs. | -| indexBlog | boolean | `true` | Whether to index blog. | -| indexPages | boolean | `false` | Whether to index pages. | -| docsRouteBasePath | string \| string[] | `"/docs"` | Base route path(s) of docs. Slash at beginning is not required. Note: for [docs-only mode](https://docusaurus.io/docs/docs-introduction#docs-only-mode), this needs to be the same as `routeBasePath` in your `@docusaurus/preset-classic` config e.g., `"/"`. | -| blogRouteBasePath | string \| string[] | `"/blog"` | Base route path(s) of blog. Slash at beginning is not required. | -| language | string \| string[] | `"en"` | All [lunr-languages](https://github.com/MihaiValentin/lunr-languages) supported languages, + `zh` 🔥. | -| hashed | boolean \| `"filename"` \| `"query"` | `false` | Whether to add a hashed query when fetching index (based on the content hash of all indexed `*.md` in `docsDir` and `blogDir` if applicable). Setting to `"filename"` will save hash in filename instead of query. | -| docsDir | string \| string[] | `"docs"` | The dir(s) of docs to get the content hash, it's relative to the dir of your project. | -| blogDir | string \| string[] | `"blog"` | Just like the `docsDir` but applied to blog. | -| removeDefaultStopWordFilter | boolean | `false` | Sometimes people (E.g., us) want to keep the English stop words as indexed, since they maybe are relevant in programming docs. | -| removeDefaultStemmer | boolean | `false` | Enable this if you want to be able to search for any partial word at the cost of search performance. | -| highlightSearchTermsOnTargetPage | boolean | `false` | Highlight search terms on target page. | -| searchResultLimits | number | `8` | Limit the search results. | -| searchResultContextMaxLength | number | `50` | Set the max length of characters of each search result to show. | -| explicitSearchResultPath | boolean | `false` | Whether an explicit path to a heading should be presented on a suggestion template. | -| ignoreFiles | string \| RegExp \| (string \| RegExp)[] | `[]` | Set the match rules to ignore some routes. Put a string if you want an exact match, or put a regex if you want a partial match. Note: without the website base url. | -| ignoreCssSelectors | string \| string[] | `[]` | A list of css selectors to ignore when indexing each page. | -| searchBarShortcut | boolean | `true` | Whether to enable keyboard shortcut to focus in search bar. | -| searchBarShortcutHint | boolean | `true` | Whether to show keyboard shortcut hint in search bar. Disable it if you need to hide the hint while shortcut is still enabled. | -| searchBarPosition | `"auto"` \| `"left"` \| `"right"` | `"auto"` | The side of the navbar the search bar should appear on. By default, it will try to autodetect based on your docusaurus config according to [the docs](https://docusaurus.io/docs/api/themes/configuration#navbar-search). | -| docsPluginIdForPreferredVersion | string | | When you're using multi-instance of docs, set the docs plugin id which you'd like to check the preferred version with, for the search index. | -| zhUserDict | string | | Provide your custom dict for language of zh, [see here](https://github.com/fxsjy/jieba#%E8%BD%BD%E5%85%A5%E8%AF%8D%E5%85%B8) | -| zhUserDictPath | string | | Provide the file path to your custom dict for language of zh, E.g.: `path.resolve("./src/zh-dict.txt")` | -| searchContextByPaths | string[] | | Provide an list of sub-paths as separate search context, E.g.: `["docs", "community", "legacy/resources"]`. It will create multiple search indexes by these paths. | -| hideSearchBarWithNoSearchContext | boolean | `false` | Whether to hide the search bar when no search context was matched. By default, if `searchContextByPaths` is set, pages which are not matched with it will be considered as with a search context of ROOT. By setting `hideSearchBarWithNoSearchContext` to false, these pages will be considered as with NO search context, and the search bar will be hidden. | -| useAllContextsWithNoSearchContext | boolean | `false` | Whether to show results from all the contexts if no context is provided. This option should not be used with `hideSearchBarWithNoSearchContext` set to `true` as this would show results when there is no search context. This will duplicate indexes and might have a performance cost depending on the index sizes. | +| Name | Type | Default | Description | +| --------------------------------- | ------------------------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| indexDocs | boolean | `true` | Whether to index docs. | +| indexBlog | boolean | `true` | Whether to index blog. | +| indexPages | boolean | `false` | Whether to index pages. | +| docsRouteBasePath | string \| string[] | `"/docs"` | Base route path(s) of docs. Slash at beginning is not required. Note: for [docs-only mode](https://docusaurus.io/docs/docs-introduction#docs-only-mode), this needs to be the same as `routeBasePath` in your `@docusaurus/preset-classic` config e.g., `"/"`. | +| blogRouteBasePath | string \| string[] | `"/blog"` | Base route path(s) of blog. Slash at beginning is not required. | +| language | string \| string[] | `"en"` | All [lunr-languages](https://github.com/MihaiValentin/lunr-languages) supported languages, + `zh` 🔥. | +| hashed | boolean \| `"filename"` \| `"query"` | `false` | Whether to add a hashed query when fetching index (based on the content hash of all indexed `*.md` in `docsDir` and `blogDir` if applicable). Setting to `"filename"` will save hash in filename instead of query. | +| docsDir | string \| string[] | `"docs"` | The dir(s) of docs to get the content hash, it's relative to the dir of your project. | +| blogDir | string \| string[] | `"blog"` | Just like the `docsDir` but applied to blog. | +| removeDefaultStopWordFilter | boolean | `false` | Sometimes people (E.g., us) want to keep the English stop words as indexed, since they maybe are relevant in programming docs. | +| removeDefaultStemmer | boolean | `false` | Enable this if you want to be able to search for any partial word at the cost of search performance. | +| highlightSearchTermsOnTargetPage | boolean | `false` | Highlight search terms on target page. | +| searchResultLimits | number | `8` | Limit the search results. | +| searchResultContextMaxLength | number | `50` | Set the max length of characters of each search result to show. | +| explicitSearchResultPath | boolean | `false` | Whether an explicit path to a heading should be presented on a suggestion template. | +| ignoreFiles | string \| RegExp \| (string \| RegExp)[] | `[]` | Set the match rules to ignore some routes. Put a string if you want an exact match, or put a regex if you want a partial match. Note: without the website base url. | +| ignoreCssSelectors | string \| string[] | `[]` | A list of css selectors to ignore when indexing each page. | +| searchBarShortcut | boolean | `true` | Whether to enable keyboard shortcut to focus in search bar. | +| searchBarShortcutHint | boolean | `true` | Whether to show keyboard shortcut hint in search bar. Disable it if you need to hide the hint while shortcut is still enabled. | +| searchBarPosition | `"auto"` \| `"left"` \| `"right"` | `"auto"` | The side of the navbar the search bar should appear on. By default, it will try to autodetect based on your docusaurus config according to [the docs](https://docusaurus.io/docs/api/themes/configuration#navbar-search). | +| docsPluginIdForPreferredVersion | string | | When you're using multi-instance of docs, set the docs plugin id which you'd like to check the preferred version with, for the search index. | +| zhUserDict | string | | Provide your custom dict for language of zh, [see here](https://github.com/fxsjy/jieba#%E8%BD%BD%E5%85%A5%E8%AF%8D%E5%85%B8) | +| zhUserDictPath | string | | Provide the file path to your custom dict for language of zh, E.g.: `path.resolve("./src/zh-dict.txt")` | +| searchContextByPaths | `(string \| { label: string; path: string; } )[]` | | Provide an list of sub-paths as separate search context, E.g.: `["docs", "community", "legacy/resources"]`. It will create multiple search indexes by these paths. | +| hideSearchBarWithNoSearchContext | boolean | `false` | Whether to hide the search bar when no search context was matched. By default, if `searchContextByPaths` is set, pages which are not matched with it will be considered as with a search context of ROOT. By setting `hideSearchBarWithNoSearchContext` to false, these pages will be considered as with NO search context, and the search bar will be hidden. | +| useAllContextsWithNoSearchContext | boolean | `false` | Whether to show results from all the contexts if no context is provided. This option should not be used with `hideSearchBarWithNoSearchContext` set to `true` as this would show results when there is no search context. This will duplicate indexes and might have a performance cost depending on the index sizes. | ### I18N diff --git a/docusaurus-search-local/src/client/theme/SearchBar/SearchBar.tsx b/docusaurus-search-local/src/client/theme/SearchBar/SearchBar.tsx index 70adbbfe..5cc74382 100644 --- a/docusaurus-search-local/src/client/theme/SearchBar/SearchBar.tsx +++ b/docusaurus-search-local/src/client/theme/SearchBar/SearchBar.tsx @@ -112,9 +112,14 @@ export default function SearchBar({ let nextSearchContext = ""; if (location.pathname.startsWith(versionUrl)) { const uri = location.pathname.substring(versionUrl.length); - const matchedPath = searchContextByPaths.find( - (path) => uri === path || uri.startsWith(`${path}/`) - ); + let matchedPath: string | undefined; + 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; } diff --git a/docusaurus-search-local/src/client/theme/SearchPage/SearchPage.tsx b/docusaurus-search-local/src/client/theme/SearchPage/SearchPage.tsx index e99e774f..0088776e 100644 --- a/docusaurus-search-local/src/client/theme/SearchPage/SearchPage.tsx +++ b/docusaurus-search-local/src/client/theme/SearchPage/SearchPage.tsx @@ -174,11 +174,20 @@ function SearchPageContent(): React.ReactElement { }) : ""} - {searchContextByPaths.map((context: string) => ( - - ))} + {searchContextByPaths.map((context) => { + let label: string; + let path: string; + if (typeof context === "string") { + label = path = context; + } else { + ({ label, path } = context); + } + return ( + + ); + })} ) : null} diff --git a/docusaurus-search-local/src/declarations.ts b/docusaurus-search-local/src/declarations.ts index 9d18f643..42e7a04a 100644 --- a/docusaurus-search-local/src/declarations.ts +++ b/docusaurus-search-local/src/declarations.ts @@ -20,7 +20,10 @@ declare module "*/generated.js" { export const searchBarPosition: "left" | "right"; export const docsPluginIdForPreferredVersion: string; export const indexDocs: boolean; - export const searchContextByPaths: string[]; + export const searchContextByPaths: ( + | string + | { label: string; path: string } + )[]; export const hideSearchBarWithNoSearchContext: boolean; export const useAllContextsWithNoSearchContext: boolean; // These below are for mocking only. diff --git a/docusaurus-search-local/src/index.ts b/docusaurus-search-local/src/index.ts index 222aba6d..4c064463 100644 --- a/docusaurus-search-local/src/index.ts +++ b/docusaurus-search-local/src/index.ts @@ -167,7 +167,7 @@ export interface PluginOptions { * Provide an list of sub-paths as separate search context, E.g.: `["docs", "community", "legacy/resources"]`. * It will create multiple search indexes by these paths. */ - searchContextByPaths?: string[]; + searchContextByPaths?: (string | { label: string; path: string })[]; /** * Whether to hide the search bar when no search context was matched. diff --git a/docusaurus-search-local/src/server/utils/postBuildFactory.ts b/docusaurus-search-local/src/server/utils/postBuildFactory.ts index 0c0fa2c2..56b15150 100644 --- a/docusaurus-search-local/src/server/utils/postBuildFactory.ts +++ b/docusaurus-search-local/src/server/utils/postBuildFactory.ts @@ -48,9 +48,14 @@ export function postBuildFactory( for (const doc of documents) { if (doc.u.startsWith(baseUrl)) { const uri = doc.u.substring(baseUrl.length); - const matchedPath = searchContextByPaths.find( - (path) => uri === path || uri.startsWith(`${path}/`) - ); + let matchedPath: string | undefined; + for (const _path of searchContextByPaths) { + const path = typeof _path === "string" ? _path : _path.path; + if (uri === path || uri.startsWith(`${path}/`)) { + matchedPath = path; + break; + } + } if (matchedPath) { let dirAllDocs = docsByDirMap.get(matchedPath); if (!dirAllDocs) { diff --git a/docusaurus-search-local/src/server/utils/validateOptions.ts b/docusaurus-search-local/src/server/utils/validateOptions.ts index bb2020eb..1dcf4a08 100644 --- a/docusaurus-search-local/src/server/utils/validateOptions.ts +++ b/docusaurus-search-local/src/server/utils/validateOptions.ts @@ -43,7 +43,15 @@ const schema = Joi.object({ docsPluginIdForPreferredVersion: Joi.string(), zhUserDict: Joi.string(), zhUserDictPath: Joi.string(), - searchContextByPaths: Joi.array().items(Joi.string()), + searchContextByPaths: Joi.array().items( + Joi.alternatives().try( + Joi.string(), + Joi.object<{ label: string; path: string }>({ + label: Joi.string(), + path: Joi.string(), + }) + ) + ), hideSearchBarWithNoSearchContext: Joi.boolean().default(false), useAllContextsWithNoSearchContext: Joi.boolean().default(false), }); diff --git a/website-multi-docs/docusaurus.config.js b/website-multi-docs/docusaurus.config.js index 923d13ef..9d538b67 100644 --- a/website-multi-docs/docusaurus.config.js +++ b/website-multi-docs/docusaurus.config.js @@ -156,7 +156,10 @@ const config = { docsRouteBasePath: ["docs", "community"], docsDir: ["docs", "community"], docsPluginIdForPreferredVersion: "product", - searchContextByPaths: ["docs", "community"], + searchContextByPaths: [ + "docs", + { label: "Community", path: "community" }, + ], hideSearchBarWithNoSearchContext: true, }), ],