From 9bd26a55c940e2345aef897b0e2fd21477e999b4 Mon Sep 17 00:00:00 2001 From: Mister-Hope Date: Fri, 28 Mar 2025 21:19:59 +0800 Subject: [PATCH 1/2] feat(plugin-slimsearch): improve a11y, close #411 --- docs/plugins/search/slimsearch.md | 10 + docs/zh/plugins/search/slimsearch.md | 12 +- .../src/client/components/SearchModal.ts | 13 +- .../src/client/components/SearchResult.ts | 301 ++++++++++-------- .../src/client/helpers/search.ts | 5 +- .../src/client/styles/search-result.scss | 121 ++++--- .../src/client/utils/querySplitter.ts | 2 +- .../plugin-slimsearch/src/node/locales.ts | 19 ++ .../plugin-slimsearch/src/shared/locales.ts | 7 + 9 files changed, 297 insertions(+), 193 deletions(-) diff --git a/docs/plugins/search/slimsearch.md b/docs/plugins/search/slimsearch.md index b55d51bf18..56c2bba88d 100644 --- a/docs/plugins/search/slimsearch.md +++ b/docs/plugins/search/slimsearch.md @@ -295,6 +295,16 @@ Options used to create index per locale, the object keys should be the locale pa */ search: string + /** + * Clear search text + */ + clear: string + + /** + * Remove current item + */ + remove: string + /** * Searching text */ diff --git a/docs/zh/plugins/search/slimsearch.md b/docs/zh/plugins/search/slimsearch.md index 929502a3cd..b65e74791e 100644 --- a/docs/zh/plugins/search/slimsearch.md +++ b/docs/zh/plugins/search/slimsearch.md @@ -293,6 +293,16 @@ export default defineUserConfig({ */ search: string + /** + * 清除搜索文字 + */ + clear: string + + /** + * 删除当前项目 + */ + remove: string + /** * 搜索中文字 */ @@ -470,7 +480,7 @@ export default defineUserConfig({ 如果你想要访问搜索 API,你可以从 `@vuepress/plugin-slimsearch/client` 中导入 `createSearchWorker` 来获取搜索结果: ```ts -import { createSearchWorker } from 'vuepress-plugin-search-pro/client' +import { createSearchWorker } from '@vuepress/plugin-slimsearch/client' const { all, suggest, search, terminate } = createSearchWorker() diff --git a/plugins/search/plugin-slimsearch/src/client/components/SearchModal.ts b/plugins/search/plugin-slimsearch/src/client/components/SearchModal.ts index 783f0898ee..2899c80e3e 100644 --- a/plugins/search/plugin-slimsearch/src/client/components/SearchModal.ts +++ b/plugins/search/plugin-slimsearch/src/client/components/SearchModal.ts @@ -28,6 +28,7 @@ import { import { locales, options } from '../define.js' import { useSearchOptions } from '../helpers/index.js' import { CLOSE_ICON } from '../icons/index.js' +import { defaultQuerySplitter } from '../utils/index.js' import SearchKeyHints from './SearchKeyHints.js' import { SearchLoading } from './SearchLoading.js' import { SearchIcon } from './icons.js' @@ -109,9 +110,9 @@ export default defineComponent({ () => ( searchOptions.value.querySplitter?.(input.value) ?? - Promise.resolve(input.value.split(' ')) + Promise.resolve(defaultQuerySplitter(input.value)) ).then((result) => { - queries.value = result + queries.value = result.filter((item) => item.length) }), Math.min(options.searchDelay, options.suggestDelay), ), @@ -148,14 +149,18 @@ export default defineComponent({ h('form', [ h( 'label', - { 'for': 'search-pro', 'aria-label': locale.value.search }, + { + 'id': 'slimsearch-label', + 'for': 'slimsearch-input', + 'aria-label': locale.value.search, + }, h(SearchIcon), ), h('input', { 'ref': inputElement, 'type': 'search', 'class': 'slimsearch-input', - 'id': 'search-pro', + 'id': 'slimsearch-input', 'placeholder': locale.value.placeholder, 'spellcheck': 'false', 'autocapitalize': 'off', diff --git a/plugins/search/plugin-slimsearch/src/client/components/SearchResult.ts b/plugins/search/plugin-slimsearch/src/client/components/SearchResult.ts index ddf22c9186..455e5128b6 100644 --- a/plugins/search/plugin-slimsearch/src/client/components/SearchResult.ts +++ b/plugins/search/plugin-slimsearch/src/client/components/SearchResult.ts @@ -172,46 +172,52 @@ export default defineComponent({ const renderSearchQueryHistory = (): VNode | null => enableQueryHistory ? h( - 'ul', - { class: 'slimsearch-result-list' }, - h('li', { class: 'slimsearch-result-list-item' }, [ + 'div', + { class: 'slimsearch-records' }, + h('div', { class: 'slimsearch-record' }, [ h( 'div', - { class: 'slimsearch-result-title' }, + { class: 'slimsearch-record-title' }, locale.value.queryHistory, ), - queryHistories.value.map((item, historyIndex) => - h( - 'div', - { - class: [ - 'slimsearch-result-item', - { - active: - activatedHistoryStatus.isQuery && - activatedHistoryStatus.index === historyIndex, + h( + 'ul', + { class: 'slimsearch-record-contents', role: 'listbox' }, + queryHistories.value.map((item, historyIndex) => { + const active = + activatedHistoryStatus.isQuery && + activatedHistoryStatus.index === historyIndex + + return h( + 'li', + { + 'class': ['slimsearch-record-matches', { active }], + 'role': 'option', + 'aria-selected': active, + 'onClick': () => { + emit('updateQuery', item) }, - ], - onClick: () => { - emit('updateQuery', item) }, - }, - [ - h(HistoryIcon, { - class: 'slimsearch-result-type', - }), - h('div', { class: 'slimsearch-result-content' }, item), - h('button', { - class: 'slimsearch-remove-icon', - innerHTML: CLOSE_ICON, - onClick: (event: Event) => { - event.preventDefault() - event.stopPropagation() - removeQueryHistory(historyIndex) - }, - }), - ], - ), + h('div', [ + h(HistoryIcon, { + class: 'slimsearch-record-type', + }), + h('div', { class: 'slimsearch-record-content' }, item), + h('button', { + 'type': 'button', + 'class': 'slimsearch-remove-icon', + 'title': locale.value.remove, + 'aria-label': locale.value.remove, + 'innerHTML': CLOSE_ICON, + 'onClick': (event: Event) => { + event.preventDefault() + event.stopPropagation() + removeQueryHistory(historyIndex) + }, + }), + ]), + ) + }), ), ]), ) @@ -221,57 +227,71 @@ export default defineComponent({ enableResultHistory ? h( 'ul', - { class: 'slimsearch-result-list' }, - h('li', { class: 'slimsearch-result-list-item' }, [ + { class: 'slimsearch-records' }, + h('li', { class: 'slimsearch-record' }, [ h( 'div', - { class: 'slimsearch-result-title' }, + { class: 'slimsearch-record-title' }, locale.value.resultHistory, ), - - resultHistories.value.map((item, historyIndex) => - h( - RouteLink, - { - to: item.link, - class: [ - 'slimsearch-result-item', - { - active: - !activatedHistoryStatus.isQuery && - activatedHistoryStatus.index === historyIndex, - }, - ], - onClick: () => { - resetSearchResult() + h( + 'ul', + { class: 'slimsearch-record-contents', role: 'listbox' }, + resultHistories.value.map((item, historyIndex) => { + const active = + !activatedHistoryStatus.isQuery && + activatedHistoryStatus.index === historyIndex + + return h( + 'li', + { + 'class': ['slimsearch-record-matches', { active }], + 'role': 'option', + 'aria-selected': active, }, - }, - () => [ - h(HistoryIcon, { - class: 'slimsearch-result-type', - }), - h('div', { class: 'slimsearch-result-content' }, [ - item.header - ? h('div', { class: 'content-header' }, item.header) - : null, - h( - 'div', - item.display - .map((display) => getVNodes(display)) - .flat(), - ), - ]), - h('button', { - class: 'slimsearch-remove-icon', - innerHTML: CLOSE_ICON, - onClick: (event: Event) => { - event.preventDefault() - event.stopPropagation() - removeResultHistory(historyIndex) + h( + RouteLink, + { + to: item.link, + onClick: () => { + resetSearchResult() + }, }, - }), - ], - ), + () => [ + h(HistoryIcon, { + class: 'slimsearch-record-type', + }), + h('div', { class: 'slimsearch-record-content' }, [ + item.header + ? h( + 'div', + { class: 'slimsearch-record-content-header' }, + item.header, + ) + : null, + h( + 'div', + item.display + .map((display) => getVNodes(display)) + .flat(), + ), + ]), + h('button', { + 'type': 'button', + 'class': 'slimsearch-remove-icon', + 'title': locale.value.remove, + 'aria-label': locale.value.remove, + 'innerHTML': CLOSE_ICON, + 'onClick': (event: Event) => { + event.preventDefault() + event.stopPropagation() + removeResultHistory(historyIndex) + }, + }), + ], + ), + ) + }), ), ]), ) @@ -318,7 +338,7 @@ export default defineComponent({ () => { document .querySelector( - '.slimsearch-result-list-item.active .slimsearch-result-item.active', + '.slimsearch-record.active .slimsearch-record-matches.active', ) ?.scrollIntoView(false) }, @@ -329,6 +349,7 @@ export default defineComponent({ h( 'div', { + id: 'slimsearch-results', class: [ 'slimsearch-result-wrapper', { @@ -337,79 +358,99 @@ export default defineComponent({ : !hasHistory.value, }, ], - id: 'slimsearch-results', }, props.queries.length ? isSearching.value ? h(SearchLoading, { hint: locale.value.searching }) : hasResults.value ? h( - 'ul', - { class: 'slimsearch-result-list' }, + 'div', + { + 'class': 'slimsearch-records', + 'role': 'listbox', + 'aria-labeledby': 'slimsearch-label', + }, results.value.map(({ title, contents }, index) => { const isCurrentResultActive = activatedResultIndex.value === index return h( - 'li', + 'div', { - class: [ - 'slimsearch-result-list-item', + 'class': [ + 'slimsearch-record', { active: isCurrentResultActive }, ], + 'role': 'group', + 'aria-selected': isCurrentResultActive, }, [ h( 'div', - { class: 'slimsearch-result-title' }, + { class: 'slimsearch-record-title' }, title || locale.value.defaultTitle, ), - contents.map((item, contentIndex) => { - const isCurrentContentActive = - isCurrentResultActive && - activatedResultContentIndex.value === contentIndex - - return h( - RouteLink, - { - to: getResultPath(item), - class: [ - 'slimsearch-result-item', + h( + 'ul', + { class: 'slimsearch-record-contents' }, + contents.map((item, contentIndex) => { + const isCurrentContentActive = + isCurrentResultActive && + activatedResultContentIndex.value === contentIndex + + return h( + 'li', + { + 'class': [ + 'slimsearch-record-matches', + { active: isCurrentContentActive }, + ], + 'role': 'option', + 'aria-selected': isCurrentContentActive, + }, + h( + RouteLink, { - 'active': isCurrentContentActive, - 'aria-selected': isCurrentContentActive, + to: getResultPath(item), + onClick: () => { + addQueryHistory(props.queries.join(' ')) + addResultHistory(item) + resetSearchResult() + }, }, - ], - onClick: () => { - addQueryHistory(props.queries.join(' ')) - addResultHistory(item) - resetSearchResult() - }, - }, - () => [ - item.type === 'text' - ? null - : h( - item.type === 'title' - ? TitleIcon - : item.type === 'heading' - ? HeadingIcon - : HeartIcon, - { class: 'slimsearch-result-type' }, + () => [ + item.type === 'text' + ? null + : h( + item.type === 'title' + ? TitleIcon + : item.type === 'heading' + ? HeadingIcon + : HeartIcon, + { class: 'slimsearch-record-type' }, + ), + h( + 'div', + { class: 'slimsearch-record-content' }, + [ + item.type === 'text' && item.header + ? h( + 'div', + { + class: + 'slimsearch-record-content-header', + }, + item.header, + ) + : null, + h('div', getDisplay(item)), + ], ), - h('div', { class: 'slimsearch-result-content' }, [ - item.type === 'text' && item.header - ? h( - 'div', - { class: 'content-header' }, - item.header, - ) - : null, - h('div', getDisplay(item)), - ]), - ], - ) - }), + ], + ), + ) + }), + ), ], ) }), diff --git a/plugins/search/plugin-slimsearch/src/client/helpers/search.ts b/plugins/search/plugin-slimsearch/src/client/helpers/search.ts index 37bac18aba..2966b1a694 100644 --- a/plugins/search/plugin-slimsearch/src/client/helpers/search.ts +++ b/plugins/search/plugin-slimsearch/src/client/helpers/search.ts @@ -6,7 +6,6 @@ import { useRouteLocale } from 'vuepress/client' import { isFunction } from 'vuepress/shared' import type { SearchResult, WorkerSearchOptions } from '../typings/index.js' -import { defaultQuerySplitter } from '../utils/index.js' declare const __VUEPRESS_DEV__: boolean @@ -35,9 +34,7 @@ export interface SearchOptions extends SearchLocaleOptions { locales?: Record } -const searchOptions: Ref = ref({ - querySplitter: (query) => Promise.resolve(defaultQuerySplitter(query)), -}) +const searchOptions: Ref = ref({}) const slimsearchSymbol: InjectionKey> = Symbol( __VUEPRESS_DEV__ ? 'slimsearch' : '', diff --git a/plugins/search/plugin-slimsearch/src/client/styles/search-result.scss b/plugins/search/plugin-slimsearch/src/client/styles/search-result.scss index a32936fcef..5635443e60 100644 --- a/plugins/search/plugin-slimsearch/src/client/styles/search-result.scss +++ b/plugins/search/plugin-slimsearch/src/client/styles/search-result.scss @@ -31,17 +31,20 @@ } } -.slimsearch-result-list { +.slimsearch-records { margin: 0; padding: 0; } -.slimsearch-result-list-item { +.slimsearch-record { display: block; +} + +li.slimsearch-record { list-style: none; } -.slimsearch-result-title { +.slimsearch-record-title { position: sticky; top: -2px; z-index: 10; @@ -58,12 +61,68 @@ line-height: 2rem; text-indent: 0.5em; - .slimsearch-result-item.active & { + .slimsearch-record-matches.active & { color: var(--vp-c-accent); } } -.slimsearch-result-type { +.slimsearch-record-contents { + margin: 0; + padding: 0; + list-style: none; +} + +.slimsearch-record-matches { + margin: 0.5rem 0; + padding: 0.5rem 0.75rem; + border-radius: 0.25rem; + + background: var(--vp-c-bg-alt); + color: inherit; + box-shadow: 0 1px 3px 0 var(--vp-c-shadow); + + font-weight: normal; + white-space: pre-wrap; + word-wrap: break-word; + + > * { + display: flex; + align-items: center; + } + + a { + color: inherit; + } + + strong { + color: var(--vp-c-accent); + } + + &:hover, + &.active { + background-color: var(--vp-c-accent-hover); + color: var(--vp-c-white); + cursor: pointer; + + .slimsearch-record-type, + .slimsearch-remove-icon, + strong { + color: var(--vp-c-white); + } + } +} + +.slimsearch-record-content { + display: flex; + flex-flow: column; + flex-grow: 1; + align-items: stretch; + justify-content: center; + + line-height: 1.5; +} + +.slimsearch-record-type { display: block; width: 1rem; @@ -98,52 +157,8 @@ } } -.slimsearch-result-content { - display: flex; - flex-flow: column; - flex-grow: 1; - align-items: stretch; - justify-content: center; - - line-height: 1.5; - - .content-header { - margin-bottom: 0.25rem; - border-bottom: 1px solid var(--vp-c-border-hard); - font-size: 0.9em; - } -} - -.slimsearch-result-item { - display: flex; - align-items: center; - - margin: 0.5rem 0; - padding: 0.5rem 0.75rem; - border-radius: 0.25rem; - - background: var(--vp-c-bg-alt); - color: inherit; - box-shadow: 0 1px 3px 0 var(--vp-c-shadow); - - font-weight: normal; - white-space: pre-wrap; - word-wrap: break-word; - - strong { - color: var(--vp-c-accent); - } - - &:hover, - &.active { - background-color: var(--vp-c-accent-hover); - color: var(--vp-c-white); - cursor: pointer; - - .slimsearch-result-type, - .slimsearch-remove-icon, - strong { - color: var(--vp-c-white); - } - } +.slimsearch-record-content-header { + margin-bottom: 0.25rem; + border-bottom: 1px solid var(--vp-c-border-hard); + font-size: 0.9em; } diff --git a/plugins/search/plugin-slimsearch/src/client/utils/querySplitter.ts b/plugins/search/plugin-slimsearch/src/client/utils/querySplitter.ts index 724fae9aea..126d01d6ae 100644 --- a/plugins/search/plugin-slimsearch/src/client/utils/querySplitter.ts +++ b/plugins/search/plugin-slimsearch/src/client/utils/querySplitter.ts @@ -1,7 +1,7 @@ const CJK_REGEXP = /[\u4e00-\u9fff\u3400-\u4dbf\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]/ -export const defaultQuerySplitter = (query: string): string[] => +export const defaultQuerySplitter = (query = ''): string[] => query .split(/\s+/) .map((word) => { diff --git a/plugins/search/plugin-slimsearch/src/node/locales.ts b/plugins/search/plugin-slimsearch/src/node/locales.ts index b0a6bc182e..5439e3ef80 100644 --- a/plugins/search/plugin-slimsearch/src/node/locales.ts +++ b/plugins/search/plugin-slimsearch/src/node/locales.ts @@ -12,6 +12,7 @@ export const slimsearchLocaleInfo: DefaultLocaleInfo = [ placeholder: 'Search', search: 'Search', clear: 'Clear search query', + remove: 'Delete current item', searching: 'Searching', defaultTitle: 'Documentation', select: 'to select', @@ -32,6 +33,7 @@ export const slimsearchLocaleInfo: DefaultLocaleInfo = [ placeholder: '搜索', search: '搜索', clear: '清除搜索文字', + remove: '删除当前项目', searching: '搜索中', defaultTitle: '文档', select: '选择', @@ -52,6 +54,7 @@ export const slimsearchLocaleInfo: DefaultLocaleInfo = [ placeholder: '搜索', search: '搜索', clear: '清除搜索文字', + remove: '刪除當前項目', searching: '搜索中', defaultTitle: '文檔', select: '選擇', @@ -72,6 +75,7 @@ export const slimsearchLocaleInfo: DefaultLocaleInfo = [ placeholder: 'Suche', search: 'Suche', clear: 'Suchanfrage löschen', + remove: 'Aktuellen Eintrag löschen', searching: 'Suche', defaultTitle: 'Dokumentation', select: 'auswählen', @@ -92,6 +96,7 @@ export const slimsearchLocaleInfo: DefaultLocaleInfo = [ placeholder: 'Tìm kiếm', search: 'Tìm kiếm', clear: 'Xóa tìm kiếm', + remove: 'Xóa mục hiện tại', searching: 'Đang tìm kiếm', defaultTitle: 'Tài liệu', select: 'chọn', @@ -112,6 +117,7 @@ export const slimsearchLocaleInfo: DefaultLocaleInfo = [ placeholder: 'Пошук', search: 'Пошук', clear: 'очистити пошуковий запит', + remove: 'Видалити поточний елемент', searching: 'Пошук', defaultTitle: 'Документація', select: 'вибрати', @@ -132,6 +138,7 @@ export const slimsearchLocaleInfo: DefaultLocaleInfo = [ placeholder: 'Поиск', search: 'Поиск', clear: 'Очистить поисковый запрос', + remove: 'Удалить текущий элемент', searching: 'Поиск', defaultTitle: 'Документация', select: 'выбрать', @@ -152,6 +159,7 @@ export const slimsearchLocaleInfo: DefaultLocaleInfo = [ placeholder: 'Pesquisar', search: 'Pesquisar', clear: 'Limpar pesquisa', + remove: 'Remover item atual', searching: 'Pesquisando', defaultTitle: 'Documentação', select: 'selecionar', @@ -172,6 +180,7 @@ export const slimsearchLocaleInfo: DefaultLocaleInfo = [ placeholder: 'Szukaj', search: 'Szukaj', clear: 'Wyczyść zapytanie', + remove: 'Usuń bieżący element', searching: 'Szukanie', defaultTitle: 'Dokumentacja', select: 'wybierz', @@ -192,6 +201,7 @@ export const slimsearchLocaleInfo: DefaultLocaleInfo = [ placeholder: 'Hľadať', search: 'Hľadať', clear: 'Vymazať vyhľadávanie', + remove: 'Odstrániť aktuálny prvok', searching: 'Hľadanie', defaultTitle: 'Dokumentácia', select: 'vybrať', @@ -212,6 +222,7 @@ export const slimsearchLocaleInfo: DefaultLocaleInfo = [ placeholder: 'Rechercher', search: 'Rechercher', clear: 'Effacer la recherche', + remove: "Supprimer l'élément actuel", searching: 'Recherche', defaultTitle: 'Documentation', select: 'sélectionner', @@ -232,6 +243,7 @@ export const slimsearchLocaleInfo: DefaultLocaleInfo = [ placeholder: 'Buscar', search: 'Buscar', clear: 'Limpiar búsqueda', + remove: 'Eliminar elemento actual', searching: 'Buscando', defaultTitle: 'Documentación', select: 'seleccionar', @@ -252,6 +264,7 @@ export const slimsearchLocaleInfo: DefaultLocaleInfo = [ placeholder: '検索', search: '検索', clear: '検索文字列をクリア', + remove: '現在の項目を削除', searching: '検索中', defaultTitle: 'ドキュメント', select: '選択', @@ -272,6 +285,7 @@ export const slimsearchLocaleInfo: DefaultLocaleInfo = [ placeholder: 'Ara', search: 'Ara', clear: 'Arama metnini temizle', + remove: 'Geçerli öğeyi sil', searching: 'Aranıyor', defaultTitle: 'Dökümantasyon', select: 'seç', @@ -292,6 +306,7 @@ export const slimsearchLocaleInfo: DefaultLocaleInfo = [ placeholder: '검색', search: '검색', clear: '검색어 지우기', + remove: '현재 항목 삭제', searching: '검색 중', defaultTitle: '문서', select: '선택', @@ -312,6 +327,7 @@ export const slimsearchLocaleInfo: DefaultLocaleInfo = [ placeholder: 'Etsi', search: 'Etsi', clear: 'Tyhjennä hakukysely', + remove: 'Poista nykyinen kohde', searching: 'Etsitään', defaultTitle: 'Dokumentaatio', select: 'valitaksesi', @@ -332,6 +348,7 @@ export const slimsearchLocaleInfo: DefaultLocaleInfo = [ placeholder: 'Keresés', search: 'Keresés', clear: 'Keresési kifejezés törlése', + remove: 'Aktuális elem törlése', searching: 'Keresés', defaultTitle: 'Dokumentáció', select: 'kiválasztáshoz', @@ -352,6 +369,7 @@ export const slimsearchLocaleInfo: DefaultLocaleInfo = [ placeholder: 'Cari sesuatu', search: 'Cari', clear: 'Hapus pencarian', + remove: 'Hapus item saat ini', searching: 'Sedang mencari', defaultTitle: 'Dokumentasi', select: 'pilih', @@ -372,6 +390,7 @@ export const slimsearchLocaleInfo: DefaultLocaleInfo = [ placeholder: 'Zoeken', search: 'Zoeken', clear: 'Zoekopdracht wissen', + remove: 'Verwijder huidig item', searching: 'Zoeken', defaultTitle: 'Documentatie', select: 'Selecteren', diff --git a/plugins/search/plugin-slimsearch/src/shared/locales.ts b/plugins/search/plugin-slimsearch/src/shared/locales.ts index a6b39c0c49..eec4f7dbb8 100644 --- a/plugins/search/plugin-slimsearch/src/shared/locales.ts +++ b/plugins/search/plugin-slimsearch/src/shared/locales.ts @@ -25,6 +25,13 @@ export interface SlimSearchLocaleData { */ clear: string + /** + * Remove current item + * + * 删除当前项目 + */ + remove: string + /** * Searching text * From ac4b7eb08b7d4904c8d0da527eaacc4f828a8e69 Mon Sep 17 00:00:00 2001 From: Mister-Hope Date: Fri, 28 Mar 2025 21:22:29 +0800 Subject: [PATCH 2/2] feat: only show suggestion with 3 more char --- .../plugin-slimsearch/src/client/composables/useSuggestions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/search/plugin-slimsearch/src/client/composables/useSuggestions.ts b/plugins/search/plugin-slimsearch/src/client/composables/useSuggestions.ts index 6020c7b8b6..9972fed9e3 100644 --- a/plugins/search/plugin-slimsearch/src/client/composables/useSuggestions.ts +++ b/plugins/search/plugin-slimsearch/src/client/composables/useSuggestions.ts @@ -33,7 +33,7 @@ export const useSuggestions = (queries: Ref): SuggestionsRef => { ...options } = searchOptions.value - if (query) + if (query.length >= 3) suggest(query, routeLocale.value, options) .then((items) => suggestionsFilter(