feat(webui): display collections in search results and search box

closes #212
This commit is contained in:
Gauthier Roebroeck 2020-06-26 17:54:52 +08:00
parent 50b516d0c5
commit 82aec45660
2 changed files with 65 additions and 11 deletions

View file

@ -19,7 +19,8 @@
:min-width="$vuetify.breakpoint.mdAndUp ? $vuetify.breakpoint.width * .4 : $vuetify.breakpoint.width * .8" :min-width="$vuetify.breakpoint.mdAndUp ? $vuetify.breakpoint.width * .4 : $vuetify.breakpoint.width * .8"
> >
<v-list> <v-list>
<v-list-item v-if="series.length === 0 && books.length === 0">No results</v-list-item> <v-list-item v-if="series.length === 0 && books.length === 0 && collections.length === 0">No results
</v-list-item>
<template v-if="series.length !== 0"> <template v-if="series.length !== 0">
<v-subheader>SERIES</v-subheader> <v-subheader>SERIES</v-subheader>
@ -57,13 +58,31 @@
</v-list-item> </v-list-item>
</template> </template>
<template v-if="collections.length !== 0">
<v-subheader>COLLECTIONS</v-subheader>
<v-list-item v-for="item in collections"
:key="item.id"
link
:to="{name: 'browse-collection', params: {collectionId: item.id}}"
>
<v-img :src="collectionThumbnailUrl(item.id)"
height="50"
max-width="35"
class="ma-1 mr-3"
/>
<v-list-item-content>
<v-list-item-title v-text="item.name"/>
</v-list-item-content>
</v-list-item>
</template>
</v-list> </v-list>
</v-menu> </v-menu>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { bookThumbnailUrl, seriesThumbnailUrl } from '@/functions/urls' import { bookThumbnailUrl, collectionThumbnailUrl, seriesThumbnailUrl } from '@/functions/urls'
import { debounce } from 'lodash' import { debounce } from 'lodash'
import Vue from 'vue' import Vue from 'vue'
@ -76,6 +95,7 @@ export default Vue.extend({
loading: false, loading: false,
series: [] as SeriesDto[], series: [] as SeriesDto[],
books: [] as BookDto[], books: [] as BookDto[],
collections: [] as CollectionDto[],
pageSize: 10, pageSize: 10,
} }
}, },
@ -93,6 +113,7 @@ export default Vue.extend({
this.loading = true this.loading = true
this.series = (await this.$komgaSeries.getSeries(undefined, { size: this.pageSize }, query)).content this.series = (await this.$komgaSeries.getSeries(undefined, { size: this.pageSize }, query)).content
this.books = (await this.$komgaBooks.getBooks(undefined, { size: this.pageSize }, query)).content this.books = (await this.$komgaBooks.getBooks(undefined, { size: this.pageSize }, query)).content
this.collections = (await this.$komgaCollections.getCollections(undefined, { size: this.pageSize }, false, query)).content
this.showResults = true this.showResults = true
this.loading = false this.loading = false
} else { } else {
@ -104,6 +125,7 @@ export default Vue.extend({
this.showResults = false this.showResults = false
this.series = [] this.series = []
this.books = [] this.books = []
this.collections = []
}, },
searchDetails () { searchDetails () {
const s = this.search const s = this.search
@ -117,6 +139,9 @@ export default Vue.extend({
bookThumbnailUrl (bookId: number): string { bookThumbnailUrl (bookId: number): string {
return bookThumbnailUrl(bookId) return bookThumbnailUrl(bookId)
}, },
collectionThumbnailUrl (collectionId: number): string {
return collectionThumbnailUrl(collectionId)
},
}, },
}) })
</script> </script>

View file

@ -23,9 +23,9 @@
<div class="title">Series</div> <div class="title">Series</div>
</template> </template>
<template v-slot:content> <template v-slot:content>
<div v-for="(s, i) in series" <div v-for="(item, index) in series"
:key="i"> :key="index">
<item-card class="ma-2 card" :item="s"/> <item-card class="ma-2 card" :item="item"/>
</div> </div>
</template> </template>
</horizontal-scroller> </horizontal-scroller>
@ -35,9 +35,21 @@
<div class="title">Books</div> <div class="title">Books</div>
</template> </template>
<template v-slot:content> <template v-slot:content>
<div v-for="(s, i) in books" <div v-for="(item, index) in books"
:key="i"> :key="index">
<item-card class="ma-2 card" :item="s"/> <item-card class="ma-2 card" :item="item"/>
</div>
</template>
</horizontal-scroller>
<horizontal-scroller v-if="collections.length !== 0" class="my-4">
<template v-slot:prepend>
<div class="title">Collections</div>
</template>
<template v-slot:content>
<div v-for="(item, index) in collections"
:key="index">
<item-card class="ma-2 card" :item="item"/>
</div> </div>
</template> </template>
</horizontal-scroller> </horizontal-scroller>
@ -53,10 +65,9 @@ import EmptyState from '@/components/EmptyState.vue'
import HorizontalScroller from '@/components/HorizontalScroller.vue' import HorizontalScroller from '@/components/HorizontalScroller.vue'
import ItemCard from '@/components/ItemCard.vue' import ItemCard from '@/components/ItemCard.vue'
import ToolbarSticky from '@/components/ToolbarSticky.vue' import ToolbarSticky from '@/components/ToolbarSticky.vue'
import { BOOK_CHANGED, COLLECTION_CHANGED, LIBRARY_DELETED, SERIES_CHANGED } from '@/types/events'
import Vue from 'vue' import Vue from 'vue'
const cookiePageSize = 'pagesize'
export default Vue.extend({ export default Vue.extend({
name: 'Search', name: 'Search',
components: { components: {
@ -69,10 +80,23 @@ export default Vue.extend({
return { return {
series: [] as SeriesDto[], series: [] as SeriesDto[],
books: [] as BookDto[], books: [] as BookDto[],
collections: [] as CollectionDto[],
pageSize: 50, pageSize: 50,
loading: false, loading: false,
} }
}, },
created () {
this.$eventHub.$on(LIBRARY_DELETED, this.reloadResults)
this.$eventHub.$on(SERIES_CHANGED, this.reloadResults)
this.$eventHub.$on(BOOK_CHANGED, this.reloadResults)
this.$eventHub.$on(COLLECTION_CHANGED, this.reloadResults)
},
beforeDestroy () {
this.$eventHub.$off(LIBRARY_DELETED, this.reloadResults)
this.$eventHub.$off(SERIES_CHANGED, this.reloadResults)
this.$eventHub.$off(BOOK_CHANGED, this.reloadResults)
this.$eventHub.$off(COLLECTION_CHANGED, this.reloadResults)
},
watch: { watch: {
'$route.query.q': { '$route.query.q': {
handler: function (val) { handler: function (val) {
@ -84,21 +108,26 @@ export default Vue.extend({
}, },
computed: { computed: {
emptyResults (): boolean { emptyResults (): boolean {
return !this.loading && this.series.length === 0 && this.books.length === 0 return !this.loading && this.series.length === 0 && this.books.length === 0 && this.collections.length === 0
}, },
}, },
methods: { methods: {
reloadResults () {
this.loadResults(this.$route.query.q.toString())
},
async loadResults (search: string) { async loadResults (search: string) {
if (search) { if (search) {
this.loading = true this.loading = true
this.series = (await this.$komgaSeries.getSeries(undefined, { size: this.pageSize }, search)).content this.series = (await this.$komgaSeries.getSeries(undefined, { size: this.pageSize }, search)).content
this.books = (await this.$komgaBooks.getBooks(undefined, { size: this.pageSize }, search)).content this.books = (await this.$komgaBooks.getBooks(undefined, { size: this.pageSize }, search)).content
this.collections = (await this.$komgaCollections.getCollections(undefined, { size: this.pageSize }, undefined, search)).content
this.loading = false this.loading = false
} else { } else {
this.series = [] this.series = []
this.books = [] this.books = []
this.collections = []
} }
}, },
}, },