feat(theme): add semantic markup to local search dialog (#2325)

pull/1844/head
Joaquín Sánchez 2 years ago committed by GitHub
parent c9a98ac6bb
commit 4ddb96fe50
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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,34 +384,44 @@ 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)">
<svg
class="search-icon"
width="18"
height="18"
viewBox="0 0 24 24"
aria-hidden="true"
>
<g
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
<form class="search-bar" @pointerup="onSearchBarClick($event)" @submit.prevent="">
<label :title="placeholder" id="localsearch-label" for="localsearch-input">
<svg
class="search-icon"
width="18"
height="18"
viewBox="0 0 24 24"
aria-hidden="true"
>
<circle cx="11" cy="11" r="8" />
<path d="m21 21l-4.35-4.35" />
</g>
</svg>
<g
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
>
<circle cx="11" cy="11" r="8" />
<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,65 +497,72 @@ 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"
:href="p.id"
class="result"
:class="{
selected: selectedIndex === index
}"
:aria-label="[...p.titles, p.title].join(' > ')"
@mouseenter="!disableMouseOver && (selectedIndex = index)"
@focusin="selectedIndex = index"
@click="$emit('close')"
role="option"
:aria-selected="selectedIndex === index ? 'true' : 'false'"
>
<div>
<div class="titles">
<span class="title-icon">#</span>
<span v-for="(t, index) in p.titles" :key="index" class="title">
<span class="text" v-html="t" />
<svg width="18" height="18" viewBox="0 0 24 24">
<path
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="m9 18l6-6l-6-6"
/>
</svg>
</span>
<span class="title main">
<span class="text" v-html="p.title" />
</span>
</div>
<a
:href="p.id"
class="result"
:class="{
selected: selectedIndex === index
}"
:aria-label="[...p.titles, p.title].join(' > ')"
@mouseenter="!disableMouseOver && (selectedIndex = index)"
@focusin="selectedIndex = index"
@click="$emit('close')"
>
<div>
<div class="titles">
<span class="title-icon">#</span>
<span v-for="(t, index) in p.titles" :key="index" class="title">
<span class="text" v-html="t" />
<svg width="18" height="18" viewBox="0 0 24 24">
<path
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="m9 18l6-6l-6-6"
/>
</svg>
</span>
<span class="title main">
<span class="text" v-html="p.title" />
</span>
</div>
<div v-if="showDetailedList" class="excerpt-wrapper">
<div v-if="p.text" class="excerpt" inert>
<div class="vp-doc" v-html="p.text" />
<div v-if="showDetailedList" class="excerpt-wrapper">
<div v-if="p.text" class="excerpt" inert>
<div class="vp-doc" v-html="p.text" />
</div>
<div class="excerpt-gradient-bottom" />
<div class="excerpt-gradient-top" />
</div>
<div class="excerpt-gradient-bottom" />
<div class="excerpt-gradient-top" />
</div>
</div>
</a>
<div
</a>
</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%;

Loading…
Cancel
Save