|
|
|
@ -241,10 +241,12 @@ async function fetchExcerpt(id: string) {
|
|
|
|
|
/* Search input focus */
|
|
|
|
|
|
|
|
|
|
const searchInput = ref<HTMLInputElement>()
|
|
|
|
|
|
|
|
|
|
function focusSearchInput() {
|
|
|
|
|
const disableReset = computed(() => {
|
|
|
|
|
return filterText.value?.length <= 0
|
|
|
|
|
})
|
|
|
|
|
function focusSearchInput(select = true) {
|
|
|
|
|
searchInput.value?.focus()
|
|
|
|
|
searchInput.value?.select()
|
|
|
|
|
select && searchInput.value?.select()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
@ -259,11 +261,11 @@ function onSearchBarClick(event: PointerEvent) {
|
|
|
|
|
|
|
|
|
|
/* Search keyboard selection */
|
|
|
|
|
|
|
|
|
|
const selectedIndex = ref(0)
|
|
|
|
|
const selectedIndex = ref(-1)
|
|
|
|
|
const disableMouseOver = ref(false)
|
|
|
|
|
|
|
|
|
|
watch(results, () => {
|
|
|
|
|
selectedIndex.value = 0
|
|
|
|
|
watch(results, (r) => {
|
|
|
|
|
selectedIndex.value = r.length ? 0 : -1
|
|
|
|
|
scrollToSelectedResult()
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
@ -360,6 +362,11 @@ onBeforeUnmount(() => {
|
|
|
|
|
isLocked.value = false
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
function resetSearch() {
|
|
|
|
|
filterText.value = ''
|
|
|
|
|
nextTick().then(() => focusSearchInput(false))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function formMarkRegex(terms: Set<string>) {
|
|
|
|
|
return new RegExp(
|
|
|
|
|
[...terms]
|
|
|
|
@ -377,11 +384,20 @@ function formMarkRegex(terms: Set<string>) {
|
|
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
<Teleport to="body">
|
|
|
|
|
<div ref="el" class="VPLocalSearchBox" aria-modal="true">
|
|
|
|
|
<div
|
|
|
|
|
ref="el"
|
|
|
|
|
role="button"
|
|
|
|
|
:aria-owns="results?.length ? 'localsearch-list' : undefined"
|
|
|
|
|
aria-expanded="true"
|
|
|
|
|
aria-haspopup="listbox"
|
|
|
|
|
aria-labelledby="localsearch-label"
|
|
|
|
|
class="VPLocalSearchBox"
|
|
|
|
|
>
|
|
|
|
|
<div class="backdrop" @click="$emit('close')" />
|
|
|
|
|
|
|
|
|
|
<div class="shell">
|
|
|
|
|
<div class="search-bar" @pointerup="onSearchBarClick($event)">
|
|
|
|
|
<form class="search-bar" @pointerup="onSearchBarClick($event)" @submit.prevent="">
|
|
|
|
|
<label :title="placeholder" id="localsearch-label" for="localsearch-input">
|
|
|
|
|
<svg
|
|
|
|
|
class="search-icon"
|
|
|
|
|
width="18"
|
|
|
|
@ -400,11 +416,12 @@ function formMarkRegex(terms: Set<string>) {
|
|
|
|
|
<path d="m21 21l-4.35-4.35" />
|
|
|
|
|
</g>
|
|
|
|
|
</svg>
|
|
|
|
|
</label>
|
|
|
|
|
<div class="search-actions before">
|
|
|
|
|
<button
|
|
|
|
|
class="back-button"
|
|
|
|
|
:title="$t('modal.backButtonTitle')"
|
|
|
|
|
@click="$emit('close')"
|
|
|
|
|
@click="selectedIndex > -1 && $emit('close')"
|
|
|
|
|
>
|
|
|
|
|
<svg
|
|
|
|
|
width="18"
|
|
|
|
@ -427,6 +444,8 @@ function formMarkRegex(terms: Set<string>) {
|
|
|
|
|
ref="searchInput"
|
|
|
|
|
v-model="filterText"
|
|
|
|
|
:placeholder="placeholder"
|
|
|
|
|
id="localsearch-input"
|
|
|
|
|
aria-labelledby="localsearch-label"
|
|
|
|
|
class="search-input"
|
|
|
|
|
/>
|
|
|
|
|
<div class="search-actions">
|
|
|
|
@ -435,7 +454,7 @@ function formMarkRegex(terms: Set<string>) {
|
|
|
|
|
class="toggle-layout-button"
|
|
|
|
|
:class="{ 'detailed-list': showDetailedList }"
|
|
|
|
|
:title="$t('modal.displayDetails')"
|
|
|
|
|
@click="showDetailedList = !showDetailedList"
|
|
|
|
|
@click="selectedIndex > -1 && (showDetailedList = !showDetailedList)"
|
|
|
|
|
>
|
|
|
|
|
<svg
|
|
|
|
|
width="18"
|
|
|
|
@ -456,8 +475,10 @@ function formMarkRegex(terms: Set<string>) {
|
|
|
|
|
|
|
|
|
|
<button
|
|
|
|
|
class="clear-button"
|
|
|
|
|
type="reset"
|
|
|
|
|
:disabled="disableReset"
|
|
|
|
|
:title="$t('modal.resetButtonTitle')"
|
|
|
|
|
@click="filterText = ''"
|
|
|
|
|
@click="resetSearch"
|
|
|
|
|
>
|
|
|
|
|
<svg
|
|
|
|
|
width="18"
|
|
|
|
@ -476,16 +497,23 @@ function formMarkRegex(terms: Set<string>) {
|
|
|
|
|
</svg>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</form>
|
|
|
|
|
|
|
|
|
|
<div
|
|
|
|
|
<ul
|
|
|
|
|
ref="resultsEl"
|
|
|
|
|
:id="results?.length ? 'localsearch-list' : undefined"
|
|
|
|
|
:role="results?.length ? 'listbox' : undefined"
|
|
|
|
|
:aria-labelledby="results?.length ? 'localsearch-label' : undefined"
|
|
|
|
|
class="results"
|
|
|
|
|
@mousemove="disableMouseOver = false"
|
|
|
|
|
>
|
|
|
|
|
<a
|
|
|
|
|
<li
|
|
|
|
|
v-for="(p, index) in results"
|
|
|
|
|
:key="p.id"
|
|
|
|
|
role="option"
|
|
|
|
|
:aria-selected="selectedIndex === index ? 'true' : 'false'"
|
|
|
|
|
>
|
|
|
|
|
<a
|
|
|
|
|
:href="p.id"
|
|
|
|
|
class="result"
|
|
|
|
|
:class="{
|
|
|
|
@ -526,15 +554,15 @@ function formMarkRegex(terms: Set<string>) {
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
|
|
<div
|
|
|
|
|
</li>
|
|
|
|
|
<li
|
|
|
|
|
v-if="filterText && !results.length && enableNoResults"
|
|
|
|
|
class="no-results"
|
|
|
|
|
>
|
|
|
|
|
{{ $t('modal.noResultsText') }} "<strong>{{ filterText }}</strong
|
|
|
|
|
>"
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</li>
|
|
|
|
|
</ul>
|
|
|
|
|
|
|
|
|
|
<div class="search-keyboard-shortcuts">
|
|
|
|
|
<span>
|
|
|
|
@ -692,11 +720,15 @@ function formMarkRegex(terms: Set<string>) {
|
|
|
|
|
padding: 8px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.search-actions button:hover,
|
|
|
|
|
.search-actions button:not([disabled]):hover,
|
|
|
|
|
.toggle-layout-button.detailed-list {
|
|
|
|
|
color: var(--vp-c-brand);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.search-actions button.clear-button:disabled {
|
|
|
|
|
opacity: 0.37;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.search-keyboard-shortcuts {
|
|
|
|
|
font-size: 0.8rem;
|
|
|
|
|
opacity: 75%;
|
|
|
|
|