mirror of
https://github.com/gotson/komga.git
synced 2025-12-21 07:56:57 +01:00
parent
a5c7b17829
commit
604ccf1192
2 changed files with 124 additions and 96 deletions
|
|
@ -1,113 +1,94 @@
|
|||
<template>
|
||||
<div id="searchbox">
|
||||
<v-text-field v-model="search"
|
||||
solo
|
||||
hide-details
|
||||
clearable
|
||||
prepend-inner-icon="mdi-magnify"
|
||||
:label="$t('search.search')"
|
||||
:loading="loading"
|
||||
@click:clear="clear"
|
||||
@keydown.esc="clear"
|
||||
@keydown.enter="searchDetails"
|
||||
/>
|
||||
<v-menu nudge-bottom="57"
|
||||
nudge-right="52"
|
||||
attach="#searchbox"
|
||||
v-model="showResults"
|
||||
:max-height="$vuetify.breakpoint.height * .9"
|
||||
:min-width="$vuetify.breakpoint.mdAndUp ? $vuetify.breakpoint.width * .4 : $vuetify.breakpoint.width * .8"
|
||||
<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
|
||||
return-object
|
||||
prepend-inner-icon="mdi-magnify"
|
||||
append-icon=""
|
||||
item-text="id"
|
||||
auto-select-first
|
||||
:search-input.sync="search"
|
||||
:menu-props="{maxHeight: $vuetify.breakpoint.height * .9, minWidth: $vuetify.breakpoint.mdAndUp ? $vuetify.breakpoint.width * .4 : $vuetify.breakpoint.width * .8}"
|
||||
@keydown.esc="clear"
|
||||
ref="searchbox"
|
||||
>
|
||||
<v-list>
|
||||
<v-list-item
|
||||
v-if="series.length === 0 && books.length === 0 && collections.length === 0 && readLists.length === 0">
|
||||
{{ $t('searchbox.no_results') }}
|
||||
</v-list-item>
|
||||
<template v-slot:selection>
|
||||
</template>
|
||||
|
||||
<template v-if="series.length !== 0">
|
||||
<v-subheader class="text-uppercase">{{ $t('common.series') }}</v-subheader>
|
||||
<v-list-item v-for="item in series"
|
||||
:key="item.id"
|
||||
link
|
||||
:to="{name: 'browse-series', params: {seriesId: item.id}}"
|
||||
<template v-slot:item="data">
|
||||
<template v-if="typeof data.item !== 'object'">
|
||||
<v-list-item-content v-text="data.item"></v-list-item-content>
|
||||
</template>
|
||||
|
||||
<template v-if="data.item.type === 'search'">
|
||||
<v-list-item-content>{{ $t('searchbox.search_all') }}</v-list-item-content>
|
||||
</template>
|
||||
|
||||
<template v-if="data.item.type === 'series'">
|
||||
<v-img :src="seriesThumbnailUrl(data.item.id)"
|
||||
height="50"
|
||||
max-width="35"
|
||||
class="my-1 mx-3"
|
||||
>
|
||||
<v-img :src="seriesThumbnailUrl(item.id)"
|
||||
height="50"
|
||||
max-width="35"
|
||||
class="my-1 mx-3"
|
||||
>
|
||||
<span v-if="item.booksUnreadCount !== 0"
|
||||
<span v-if="data.item.booksUnreadCount !== 0"
|
||||
class="white--text pa-0 px-1 text-caption"
|
||||
:style="{background: 'orange', position: 'absolute', right: 0}"
|
||||
>
|
||||
{{ item.booksUnreadCount }}
|
||||
{{ data.item.booksUnreadCount }}
|
||||
</span>
|
||||
</v-img>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title v-text="item.metadata.title"/>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-img>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title v-text="data.item.metadata.title"/>
|
||||
</v-list-item-content>
|
||||
</template>
|
||||
|
||||
<template v-if="books.length !== 0">
|
||||
<v-subheader class="text-uppercase">{{ $t('common.books') }}</v-subheader>
|
||||
<v-list-item v-for="item in books"
|
||||
:key="item.id"
|
||||
link
|
||||
:to="{name: 'browse-book', params: {bookId: item.id}}"
|
||||
<template v-if="data.item.type === 'book'">
|
||||
<v-img :src="bookThumbnailUrl(data.item.id)"
|
||||
height="50"
|
||||
max-width="35"
|
||||
class="my-1 mx-3"
|
||||
>
|
||||
<v-img :src="bookThumbnailUrl(item.id)"
|
||||
height="50"
|
||||
max-width="35"
|
||||
class="my-1 mx-3"
|
||||
>
|
||||
<div class="unread" v-if="isUnread(item)"/>
|
||||
</v-img>
|
||||
<div class="unread" v-if="isUnread(data.item)"/>
|
||||
</v-img>
|
||||
|
||||
<v-list-item-content>
|
||||
<v-list-item-title v-text="item.metadata.title"/>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title v-text="data.item.metadata.title"/>
|
||||
</v-list-item-content>
|
||||
</template>
|
||||
|
||||
<template v-if="collections.length !== 0">
|
||||
<v-subheader class="text-uppercase">{{ $t('common.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="my-1 mx-3"
|
||||
/>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title v-text="item.name"/>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<template v-if="data.item.type === 'collection'">
|
||||
<v-img :src="collectionThumbnailUrl(data.item.id)"
|
||||
height="50"
|
||||
max-width="35"
|
||||
class="my-1 mx-3"
|
||||
/>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title v-text="data.item.name"/>
|
||||
</v-list-item-content>
|
||||
</template>
|
||||
|
||||
<template v-if="readLists.length !== 0">
|
||||
<v-subheader class="text-uppercase">{{ $t('common.readlists') }}</v-subheader>
|
||||
<v-list-item v-for="item in readLists"
|
||||
:key="item.id"
|
||||
link
|
||||
:to="{name: 'browse-readlist', params: {readListId: item.id}}"
|
||||
>
|
||||
<v-img :src="readListThumbnailUrl(item.id)"
|
||||
height="50"
|
||||
max-width="35"
|
||||
class="my-1 mx-3"
|
||||
/>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title v-text="item.name"/>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
<template v-if="data.item.type === 'readlist'">
|
||||
<v-img :src="readListThumbnailUrl(data.item.id)"
|
||||
height="50"
|
||||
max-width="35"
|
||||
class="my-1 mx-3"
|
||||
/>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title v-text="data.item.name"/>
|
||||
</v-list-item-content>
|
||||
</template>
|
||||
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</template>
|
||||
</v-autocomplete>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -124,6 +105,7 @@ export default Vue.extend({
|
|||
name: 'SearchBox',
|
||||
data: function () {
|
||||
return {
|
||||
selectedItem: null as unknown as any,
|
||||
search: null,
|
||||
showResults: false,
|
||||
loading: false,
|
||||
|
|
@ -135,6 +117,25 @@ export default Vue.extend({
|
|||
}
|
||||
},
|
||||
watch: {
|
||||
selectedItem(val, old) {
|
||||
if (val && val.hasOwnProperty('type')) {
|
||||
this.$nextTick(() => {
|
||||
this.selectedItem = undefined
|
||||
})
|
||||
|
||||
if (val.type === 'series') this.$router.push({name: 'browse-series', params: {seriesId: val.id}})
|
||||
else if (val.type === 'book') this.$router.push({name: 'browse-book', params: {bookId: val.id}})
|
||||
else if (val.type === 'collection') this.$router.push({
|
||||
name: 'browse-collection',
|
||||
params: {collectionId: val.id},
|
||||
})
|
||||
else if (val.type === 'readlist') this.$router.push({name: 'browse-readlist', params: {readListId: val.id}})
|
||||
else if (val.type === 'search') this.searchDetails()
|
||||
|
||||
//@ts-ignore
|
||||
this.$refs.searchbox.blur()
|
||||
}
|
||||
},
|
||||
search(val) {
|
||||
this.searchItems(val)
|
||||
},
|
||||
|
|
@ -142,6 +143,31 @@ export default Vue.extend({
|
|||
!val && this.clear()
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
results(): object[] {
|
||||
const results = []
|
||||
if (this.search) {
|
||||
results.push({type: 'search'})
|
||||
if (this.series.length > 0) {
|
||||
results.push({header: this.$t('common.series').toString().toUpperCase()})
|
||||
results.push(...this.series.map(o => ({...o, type: 'series'})))
|
||||
}
|
||||
if (this.books.length > 0) {
|
||||
results.push({header: this.$t('common.books').toString().toUpperCase()})
|
||||
results.push(...this.books.map(o => ({...o, type: 'book'})))
|
||||
}
|
||||
if (this.collections.length > 0) {
|
||||
results.push({header: this.$t('common.collections').toString().toUpperCase()})
|
||||
results.push(...this.collections.map(o => ({...o, type: 'collection'})))
|
||||
}
|
||||
if (this.readLists.length > 0) {
|
||||
results.push({header: this.$t('common.readlists').toString().toUpperCase()})
|
||||
results.push(...this.readLists.map(o => ({...o, type: 'readlist'})))
|
||||
}
|
||||
}
|
||||
return results
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
searchItems: debounce(async function (this: any, query: string) {
|
||||
if (query) {
|
||||
|
|
@ -158,6 +184,7 @@ export default Vue.extend({
|
|||
}, 500),
|
||||
clear() {
|
||||
this.search = null
|
||||
// this.selectedItem = null
|
||||
this.showResults = false
|
||||
this.series = []
|
||||
this.books = []
|
||||
|
|
|
|||
|
|
@ -121,6 +121,7 @@
|
|||
"collections": "Collections",
|
||||
"create": "Create",
|
||||
"delete": "Delete",
|
||||
"download": "Download",
|
||||
"email": "Email",
|
||||
"filter_no_matches": "The active filter has no matches",
|
||||
"genre": "Genre",
|
||||
|
|
@ -133,15 +134,14 @@
|
|||
"pages_n": "No pages | 1 page | {count} pages",
|
||||
"password": "Password",
|
||||
"publisher": "Publisher",
|
||||
"read": "Read",
|
||||
"readlists": "Read Lists",
|
||||
"required": "Required",
|
||||
"roles": "Roles",
|
||||
"series": "Series",
|
||||
"tags": "Tags",
|
||||
"use_filter_panel_to_change_filter": "Use the filter panel to change the active filter",
|
||||
"year": "year",
|
||||
"download": "Download",
|
||||
"read": "Read"
|
||||
"year": "year"
|
||||
},
|
||||
"dashboard": {
|
||||
"keep_reading": "Keep Reading",
|
||||
|
|
@ -423,7 +423,8 @@
|
|||
"search_results_for": "Search results for \"{name}\""
|
||||
},
|
||||
"searchbox": {
|
||||
"no_results": "No results"
|
||||
"no_results": "No results",
|
||||
"search_all": "Search all…"
|
||||
},
|
||||
"server": {
|
||||
"server_management": {
|
||||
|
|
|
|||
Loading…
Reference in a new issue