feat(search): support `minisearch` customization (#2576)

Co-authored-by: Divyansh Singh <40380293+brc-dd@users.noreply.github.com>
pull/2588/head
烽宁 1 year ago committed by GitHub
parent e8074e60ec
commit 9fee5542cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,3 +1,7 @@
---
outline: deep
---
# Search # Search
## Local Search ## Local Search
@ -58,6 +62,38 @@ export default defineConfig({
}) })
``` ```
### miniSearch options
You can configure MiniSearch like this:
```ts
import { defineConfig } from 'vitepress'
export default defineConfig({
themeConfig: {
search: {
provider: 'local',
options: {
miniSearch: {
/**
* @type {Pick<import('minisearch').Options, 'extractField' | 'tokenize' | 'processTerm'>}
*/
options: { /* ... */ },
/**
* @type {import('minisearch').SearchOptions}
* @default
* { fuzzy: 0.2, prefix: true, boost: { title: 4, text: 2, titles: 1 } }
*/
searchOptions: { /* ... */ }
}
}
}
}
})
```
Learn more in [MiniSearch docs](https://lucaong.github.io/minisearch/classes/_minisearch_.minisearch.html).
## Algolia Search ## Algolia Search
VitePress supports searching your docs site using [Algolia DocSearch](https://docsearch.algolia.com/docs/what-is-docsearch). Refer their getting started guide. In your `.vitepress/config.ts` you'll need to provide at least the following to make it work: VitePress supports searching your docs site using [Algolia DocSearch](https://docsearch.algolia.com/docs/what-is-docsearch). Refer their getting started guide. In your `.vitepress/config.ts` you'll need to provide at least the following to make it work:

@ -80,8 +80,12 @@ const searchIndex = computedAsync(async () =>
searchOptions: { searchOptions: {
fuzzy: 0.2, fuzzy: 0.2,
prefix: true, prefix: true,
boost: { title: 4, text: 2, titles: 1 } boost: { title: 4, text: 2, titles: 1 },
} ...(theme.value.search?.provider === 'local' &&
theme.value.search.options?.miniSearch?.searchOptions)
},
...(theme.value.search?.provider === 'local' &&
theme.value.search.options?.miniSearch?.options)
} }
) )
) )
@ -396,8 +400,16 @@ function formMarkRegex(terms: Set<string>) {
<div class="backdrop" @click="$emit('close')" /> <div class="backdrop" @click="$emit('close')" />
<div class="shell"> <div class="shell">
<form class="search-bar" @pointerup="onSearchBarClick($event)" @submit.prevent=""> <form
<label :title="placeholder" id="localsearch-label" for="localsearch-input"> class="search-bar"
@pointerup="onSearchBarClick($event)"
@submit.prevent=""
>
<label
:title="placeholder"
id="localsearch-label"
for="localsearch-input"
>
<svg <svg
class="search-icon" class="search-icon"
width="18" width="18"
@ -454,7 +466,9 @@ function formMarkRegex(terms: Set<string>) {
class="toggle-layout-button" class="toggle-layout-button"
:class="{ 'detailed-list': showDetailedList }" :class="{ 'detailed-list': showDetailedList }"
:title="$t('modal.displayDetails')" :title="$t('modal.displayDetails')"
@click="selectedIndex > -1 && (showDetailedList = !showDetailedList)" @click="
selectedIndex > -1 && (showDetailedList = !showDetailedList)
"
> >
<svg <svg
width="18" width="18"
@ -527,7 +541,11 @@ function formMarkRegex(terms: Set<string>) {
<div> <div>
<div class="titles"> <div class="titles">
<span class="title-icon">#</span> <span class="title-icon">#</span>
<span v-for="(t, index) in p.titles" :key="index" class="title"> <span
v-for="(t, index) in p.titles"
:key="index"
class="title"
>
<span class="text" v-html="t" /> <span class="text" v-html="t" />
<svg width="18" height="18" viewBox="0 0 24 24"> <svg width="18" height="18" viewBox="0 0 24 24">
<path <path
@ -547,7 +565,7 @@ function formMarkRegex(terms: Set<string>) {
<div v-if="showDetailedList" class="excerpt-wrapper"> <div v-if="showDetailedList" class="excerpt-wrapper">
<div v-if="p.text" class="excerpt" inert> <div v-if="p.text" class="excerpt" inert>
<div class="vp-doc" v-html="p.text" /> <div class="vp-doc" v-html="p.text" />
</div> </div>
<div class="excerpt-gradient-bottom" /> <div class="excerpt-gradient-bottom" />
<div class="excerpt-gradient-top" /> <div class="excerpt-gradient-top" />
@ -726,7 +744,7 @@ function formMarkRegex(terms: Set<string>) {
} }
.search-actions button.clear-button:disabled { .search-actions button.clear-button:disabled {
opacity: 0.37; opacity: 0.37;
} }
.search-keyboard-shortcuts { .search-keyboard-shortcuts {

@ -1,12 +1,12 @@
import path from 'node:path'
import type { Plugin, ViteDevServer } from 'vite'
import MiniSearch from 'minisearch'
import fs from 'fs-extra'
import _debug from 'debug' import _debug from 'debug'
import fs from 'fs-extra'
import MiniSearch from 'minisearch'
import path from 'path'
import type { Plugin, ViteDevServer } from 'vite'
import type { SiteConfig } from '../config' import type { SiteConfig } from '../config'
import type { MarkdownEnv } from '../markdown' import type { MarkdownEnv } from '../markdown'
import { createMarkdownRenderer } from '../markdown' import { createMarkdownRenderer } from '../markdown'
import { resolveSiteDataByRoute, slash } from '../shared' import { resolveSiteDataByRoute, slash, type DefaultTheme } from '../shared'
const debug = _debug('vitepress:local-search') const debug = _debug('vitepress:local-search')
@ -21,7 +21,7 @@ interface IndexObject {
} }
export async function localSearchPlugin( export async function localSearchPlugin(
siteConfig: SiteConfig siteConfig: SiteConfig<DefaultTheme.Config>
): Promise<Plugin> { ): Promise<Plugin> {
if (siteConfig.site.themeConfig?.search?.provider !== 'local') { if (siteConfig.site.themeConfig?.search?.provider !== 'local') {
return { return {
@ -63,7 +63,9 @@ export async function localSearchPlugin(
if (!index) { if (!index) {
index = new MiniSearch<IndexObject>({ index = new MiniSearch<IndexObject>({
fields: ['title', 'titles', 'text'], fields: ['title', 'titles', 'text'],
storeFields: ['title', 'titles'] storeFields: ['title', 'titles'],
...(siteConfig.site.themeConfig?.search?.provider === 'local' &&
siteConfig.site.themeConfig.search.options?.miniSearch?.options)
}) })
indexByLocales.set(locale, index) indexByLocales.set(locale, index)
} }

@ -1,4 +1,5 @@
import { type ComputedRef, type Ref } from 'vue' import type { Options as MiniSearchOptions } from 'minisearch'
import type { ComputedRef, Ref } from 'vue'
import type { DocSearchProps } from './docsearch.js' import type { DocSearchProps } from './docsearch.js'
import type { LocalSearchTranslations } from './local-search.js' import type { LocalSearchTranslations } from './local-search.js'
import type { PageData } from './shared.js' import type { PageData } from './shared.js'
@ -335,6 +336,20 @@ export namespace DefaultTheme {
translations?: LocalSearchTranslations translations?: LocalSearchTranslations
locales?: Record<string, Partial<Omit<LocalSearchOptions, 'locales'>>> locales?: Record<string, Partial<Omit<LocalSearchOptions, 'locales'>>>
miniSearch?: {
/**
* @see https://lucaong.github.io/minisearch/modules/_minisearch_.html#options
*/
options?: Pick<
MiniSearchOptions,
'extractField' | 'tokenize' | 'processTerm'
>
/**
* @see https://lucaong.github.io/minisearch/modules/_minisearch_.html#searchoptions-1
*/
searchOptions?: MiniSearchOptions['searchOptions']
}
} }
// algolia ------------------------------------------------------------------- // algolia -------------------------------------------------------------------

Loading…
Cancel
Save