documentation/.vuepress/theme/SearchBox.vue
Jakob Schrettenbrunner 0d99fbae04 upgrade vuepress and evertythin else to latest version
apart from tailwind
2020-04-18 01:18:24 +02:00

138 lines
3.5 KiB
Vue

<template>
<div class="search-box">
<input
@input="query = $event.target.value"
aria-label="Search"
:value="query"
placeholder="Search"
autocomplete="off"
spellcheck="false"
@focus="focused = true"
@blur="focused = false"
@keyup.enter="go(focusIndex)"
@keyup.up="onUp"
@keyup.down="onDown"
/>
<div class="suggestion-container" v-if="showSuggestions" @mouseleave="unfocus">
<div class="suggestion-padding"></div>
<ul class="suggestions" :class="{ 'align-right': alignRight }">
<li
class="suggestion"
v-for="(s, i) in suggestions"
:class="{ focused: i === focusIndex }"
@mousedown="go(i)"
@mouseenter="focus(i)"
>
<a :href="s.path" @click.prevent>
<span class="page-title">{{ s.title || s.path }}</span>
<span v-if="s.header" class="header">&gt; {{ s.header.title }}</span>
</a>
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
data() {
return {
query: "",
focused: false,
focusIndex: 0
};
},
computed: {
showSuggestions() {
return this.focused && this.suggestions && this.suggestions.length;
},
suggestions() {
const query = this.query.trim().toLowerCase();
if (!query) {
return;
}
const { pages, themeConfig } = this.$site;
const max = themeConfig.searchMaxSuggestions || 5;
const localePath = this.$localePath;
const matches = item =>
item.title && item.title.toLowerCase().indexOf(query) > -1;
const res = [];
for (let i = 0; i < pages.length; i++) {
if (res.length >= max) break;
const p = pages[i];
// filter out results that do not match current locale
if (this.getPageLocalePath(p) !== localePath) {
continue;
}
if (matches(p)) {
res.push(p);
} else if (p.headers) {
for (let j = 0; j < p.headers.length; j++) {
if (res.length >= max) break;
const h = p.headers[j];
if (matches(h)) {
res.push(
Object.assign({}, p, {
path: p.path + "#" + h.slug,
header: h
})
);
}
}
}
}
return res;
},
// make suggestions align right when there are not enough items
alignRight() {
const navCount = (this.$site.themeConfig.nav || []).length;
const repo = this.$site.repo ? 1 : 0;
return navCount + repo <= 2;
}
},
methods: {
getPageLocalePath(page) {
for (const localePath in this.$site.locales || {}) {
if (localePath !== "/" && page.path.indexOf(localePath) === 0) {
return localePath;
}
}
return "/";
},
onUp() {
if (this.showSuggestions) {
if (this.focusIndex > 0) {
this.focusIndex--;
} else {
this.focusIndex = this.suggestions.length - 1;
}
}
},
onDown() {
if (this.showSuggestions) {
if (this.focusIndex < this.suggestions.length - 1) {
this.focusIndex++;
} else {
this.focusIndex = 0;
}
}
},
go(i) {
if (!this.showSuggestions) {
return;
}
this.$router.push(this.suggestions[i].path);
this.query = "";
this.focusIndex = 0;
},
focus(i) {
this.focusIndex = i;
},
unfocus() {
this.focusIndex = -1;
}
}
};
</script>