fix(webui): replace searchbox for authors in filter panel

This commit is contained in:
Gauthier Roebroeck 2021-06-01 11:35:53 +08:00
parent 61ca80dc72
commit 14e6718252
2 changed files with 122 additions and 60 deletions

View file

@ -16,20 +16,30 @@
{{ f.name }}
</v-expansion-panel-header>
<v-expansion-panel-content class="no-padding">
<v-autocomplete
<search-box-base
v-if="f.search"
:search-function="f.search"
@selected="click(key, $event)"
>
<template v-slot:item="data">
<v-list-item-content class="text-body-2">{{ data.item }}</v-list-item-content>
</template>
</search-box-base>
<v-list
v-if="f.search"
v-model="model[key]"
:items="items[key]"
:search-input.sync="search[key]"
:loading="loading[key]"
:hide-no-data="!search[key] || loading[key]"
@keydown.esc="search[key] = null"
multiple
deletable-chips
small-chips
dense
solo
/>
>
<v-list-item v-for="(v, i) in filtersActive[key]"
:key="i"
@click.stop="click(key, v)"
>
<v-list-item-icon>
<v-icon color="secondary">mdi-checkbox-marked</v-icon>
</v-list-item-icon>
<v-list-item-title>{{ v }}</v-list-item-title>
</v-list-item>
</v-list>
<v-list
v-if="f.values"
@ -57,17 +67,11 @@
<script lang="ts">
import Vue, {PropType} from 'vue'
import SearchBoxBase from "@/components/SearchBoxBase.vue";
export default Vue.extend({
name: 'FilterPanels',
data: () => {
return {
search: {} as any,
model: {} as any,
items: {} as any,
loading: {} as any,
}
},
components: {SearchBoxBase},
props: {
filtersOptions: {
type: Object as PropType<FiltersOptions>,
@ -78,46 +82,6 @@ export default Vue.extend({
required: true,
},
},
watch: {
search: {
deep: true,
async handler(val: any) {
for (const prop in val) {
if (val[prop] !== null) {
this.loading[prop] = true
this.$set(this.items, prop, await (this.filtersOptions[prop] as any).search(val[prop]))
this.loading[prop] = false
}
}
},
},
model: {
deep: true,
async handler(val: any) {
for (const prop in val) {
if (val[prop] !== null && val[prop] !== this.filtersActive[prop]) {
let r = this.$_.cloneDeep(this.filtersActive)
r[prop] = this.$_.clone(val[prop])
this.$emit('update:filtersActive', r)
}
}
},
},
filtersActive: {
deep: true,
immediate: true,
handler(val: any) {
for (const prop in val) {
if (val[prop].length > 0) {
// we need to add existing values to items also, else v-autocomplete won't show it
this.$set(this.items, prop, this.$_.union(this.items[prop], val[prop]))
this.$set(this.model, prop, val[prop])
}
}
},
},
},
methods: {
clear(key: string) {
let r = this.$_.cloneDeep(this.filtersActive)

View file

@ -0,0 +1,98 @@
<template>
<div>
<v-autocomplete
v-model="selectedItem"
:placeholder="$t('search.search')"
:no-data-text="$t('searchbox.no_results')"
:loading="loading"
:items="results"
:hide-no-data="!showResults"
clearable
solo
hide-details
no-filter
dense
append-icon=""
auto-select-first
:search-input.sync="search"
@keydown.esc="clear"
ref="searchbox"
>
<template v-slot:selection>
</template>
<template v-slot:item="data">
<slot name="item" v-bind:item="data.item"></slot>
</template>
</v-autocomplete>
</div>
</template>
<script lang="ts">
import {debounce} from 'lodash'
import Vue, {PropType} from 'vue'
import {BookDto} from '@/types/komga-books'
import {SeriesDto} from "@/types/komga-series";
export default Vue.extend({
name: 'SearchBoxBase',
data: function () {
return {
selectedItem: null as unknown as any,
search: null,
showResults: false,
loading: false,
results: [],
}
},
watch: {
selectedItem(val, old) {
if (val) {
this.$nextTick(() => {
this.selectedItem = undefined
this.clear()
})
this.$emit('selected', val)
//@ts-ignore
this.$refs.searchbox.blur()
}
},
search(val) {
this.searchItems(val)
},
showResults(val) {
!val && this.clear()
},
},
props: {
searchFunction: {
type: Function as PropType<Function>,
required: true,
},
},
methods: {
getLibraryName(item: BookDto | SeriesDto): string {
return this.$store.getters.getLibraryById(item.libraryId).name;
},
searchItems: debounce(async function (this: any, query: string) {
if (query) {
this.loading = true
this.results = await this.searchFunction.apply(this, [query])
this.showResults = true
this.loading = false
} else {
this.clear()
}
}, 500),
clear() {
this.search = null
this.results = []
this.showResults = false
},
},
})
</script>