[web] Simplify search pages

This commit is contained in:
Alain Nussbaumer 2025-03-18 10:20:42 +01:00
parent 9bea7fef7d
commit 722307653a
3 changed files with 49 additions and 72 deletions

File diff suppressed because one or more lines are too long

View File

@ -8,7 +8,7 @@
<div class="control has-icons-left"> <div class="control has-icons-left">
<input <input
ref="search_field" ref="search_field"
v-model="query" v-model="searchStore.query"
class="input is-rounded" class="input is-rounded"
type="text" type="text"
:placeholder="$t('page.search.placeholder')" :placeholder="$t('page.search.placeholder')"
@ -39,7 +39,7 @@
<div v-for="item in history" :key="item" class="control"> <div v-for="item in history" :key="item" class="control">
<div class="tags has-addons"> <div class="tags has-addons">
<a class="tag" @click="openSearch(item)" v-text="item" /> <a class="tag" @click="openSearch(item)" v-text="item" />
<a class="tag is-delete" @click="removeSearch(item)" /> <a class="tag is-delete" @click="searchStore.remove(item)" />
</div> </div>
</div> </div>
</div> </div>
@ -56,9 +56,8 @@
<component :is="components[type]" :items="items" /> <component :is="components[type]" :items="items" />
</template> </template>
<template v-if="!expanded" #footer> <template v-if="!expanded" #footer>
<nav v-if="showAllButton(items)" class="level">
<div class="level-item">
<control-button <control-button
v-if="showAllButton(items)"
:button="{ :button="{
handler: () => expand(type), handler: () => expand(type),
title: $t( title: $t(
@ -68,8 +67,6 @@
) )
}" }"
/> />
</div>
</nav>
<div v-if="!items.total" class="has-text-centered-mobile"> <div v-if="!items.total" class="has-text-centered-mobile">
<i v-text="$t('page.search.no-results')" /> <i v-text="$t('page.search.no-results')" />
</div> </div>
@ -131,7 +128,6 @@ export default {
}, },
results: new Map(), results: new Map(),
limit: {}, limit: {},
query: '',
types: SEARCH_TYPES types: SEARCH_TYPES
} }
}, },
@ -143,33 +139,23 @@ export default {
return this.searchStore.history return this.searchStore.history
} }
}, },
watch: {
query() {
this.searchStore.query = this.query
}
},
mounted() { mounted() {
this.searchStore.source = this.$route.name this.searchStore.source = this.$route.name
this.query = this.searchStore.query
this.limit = PAGE_SIZE this.limit = PAGE_SIZE
this.search() this.search()
}, },
methods: { methods: {
expand(type) { expand(type) {
this.query = this.searchStore.query
this.types = [type] this.types = [type]
this.limit = -1 this.limit = -1
this.search() this.search()
}, },
openSearch(query) { openSearch(query) {
this.query = query this.searchStore.query = query
this.types = SEARCH_TYPES this.types = SEARCH_TYPES
this.limit = PAGE_SIZE this.limit = PAGE_SIZE
this.search() this.search()
}, },
removeSearch(query) {
this.searchStore.remove(query)
},
reset() { reset() {
this.results.clear() this.results.clear()
this.types.forEach((type) => { this.types.forEach((type) => {
@ -181,8 +167,11 @@ export default {
this.types = SEARCH_TYPES this.types = SEARCH_TYPES
this.limit = PAGE_SIZE this.limit = PAGE_SIZE
} }
this.query = this.query.trim() this.searchStore.query = this.searchStore.query.trim()
if (!this.query || !this.query.replace(/^query:/u, '')) { if (
!this.searchStore.query ||
!this.searchStore.query.replace(/^query:/u, '')
) {
this.$refs.search_field.focus() this.$refs.search_field.focus()
return return
} }
@ -190,7 +179,7 @@ export default {
this.types.forEach((type) => { this.types.forEach((type) => {
this.searchItems(type) this.searchItems(type)
}) })
this.searchStore.add(this.query) this.searchStore.add(this.searchStore.query)
}, },
searchItems(type) { searchItems(type) {
const music = type !== 'audiobook' && type !== 'podcast' const music = type !== 'audiobook' && type !== 'podcast'
@ -199,13 +188,13 @@ export default {
limit: this.limit, limit: this.limit,
type: music ? type : 'album' type: music ? type : 'album'
} }
if (this.query.startsWith('query:')) { if (this.searchStore.query.startsWith('query:')) {
parameters.expression = `(${this.query.replace(/^query:/u, '').trim()}) and media_kind is ${kind}` parameters.expression = `(${this.searchStore.query.replace(/^query:/u, '').trim()}) and media_kind is ${kind}`
} else if (music) { } else if (music) {
parameters.query = this.query parameters.query = this.searchStore.query
parameters.media_kind = kind parameters.media_kind = kind
} else { } else {
parameters.expression = `(album includes "${this.query}" or artist includes "${this.query}") and media_kind is ${kind}` parameters.expression = `(album includes "${this.searchStore.query}" or artist includes "${this.searchStore.query}") and media_kind is ${kind}`
} }
webapi.search(parameters).then(({ data }) => { webapi.search(parameters).then(({ data }) => {
this.results.set(type, new GroupedList(data[`${parameters.type}s`])) this.results.set(type, new GroupedList(data[`${parameters.type}s`]))

View File

@ -8,7 +8,7 @@
<div class="control has-icons-left"> <div class="control has-icons-left">
<input <input
ref="search_field" ref="search_field"
v-model="query" v-model="searchStore.query"
class="input is-rounded" class="input is-rounded"
type="text" type="text"
:placeholder="$t('page.search.placeholder')" :placeholder="$t('page.search.placeholder')"
@ -22,7 +22,7 @@
<div v-for="item in history" :key="item" class="control"> <div v-for="item in history" :key="item" class="control">
<div class="tags has-addons"> <div class="tags has-addons">
<a class="tag" @click="openSearch(item)" v-text="item" /> <a class="tag" @click="openSearch(item)" v-text="item" />
<a class="tag is-delete" @click="removeSearch(item)" /> <a class="tag is-delete" @click="searchStore.remove(item)" />
</div> </div>
</div> </div>
</div> </div>
@ -51,9 +51,8 @@
</vue-eternal-loading> </vue-eternal-loading>
</template> </template>
<template v-if="!expanded" #footer> <template v-if="!expanded" #footer>
<nav v-if="showAllButton(items)" class="level">
<div class="level-item">
<control-button <control-button
v-if="showAllButton(items)"
:button="{ :button="{
handler: () => expand(type), handler: () => expand(type),
title: $t( title: $t(
@ -63,8 +62,6 @@
) )
}" }"
/> />
</div>
</nav>
<div v-if="!items.total" class="has-text-centered-mobile"> <div v-if="!items.total" class="has-text-centered-mobile">
<i v-text="$t('page.search.no-results')" /> <i v-text="$t('page.search.no-results')" />
</div> </div>
@ -116,7 +113,6 @@ export default {
}, },
results: new Map(), results: new Map(),
parameters: {}, parameters: {},
query: '',
types: SEARCH_TYPES types: SEARCH_TYPES
} }
}, },
@ -130,35 +126,25 @@ export default {
) )
} }
}, },
watch: {
query() {
this.searchStore.query = this.query
}
},
mounted() { mounted() {
this.searchStore.source = this.$route.name this.searchStore.source = this.$route.name
this.query = this.searchStore.query
this.parameters.limit = PAGE_SIZE this.parameters.limit = PAGE_SIZE
this.search() this.search()
}, },
methods: { methods: {
expand(type) { expand(type) {
this.query = this.searchStore.query
this.types = [type] this.types = [type]
this.parameters.limit = PAGE_SIZE_EXPANDED this.parameters.limit = PAGE_SIZE_EXPANDED
this.parameters.offset = 0 this.parameters.offset = 0
this.search() this.search()
}, },
openSearch(query) { openSearch(query) {
this.query = query this.searchStore.query = query
this.types = SEARCH_TYPES this.types = SEARCH_TYPES
this.parameters.limit = PAGE_SIZE this.parameters.limit = PAGE_SIZE
this.parameters.offset = 0 this.parameters.offset = 0
this.search() this.search()
}, },
removeSearch(query) {
this.searchStore.remove(query)
},
reset() { reset() {
this.results.clear() this.results.clear()
this.types.forEach((type) => { this.types.forEach((type) => {
@ -170,8 +156,8 @@ export default {
this.types = SEARCH_TYPES this.types = SEARCH_TYPES
this.parameters.limit = PAGE_SIZE this.parameters.limit = PAGE_SIZE
} }
this.query = this.query.trim() this.searchStore.query = this.searchStore.query.trim()
if (!this.query) { if (!this.searchStore.query) {
this.$refs.search_field.focus() this.$refs.search_field.focus()
return return
} }
@ -181,20 +167,22 @@ export default {
this.results.set(type, data[`${type}s`]) this.results.set(type, data[`${type}s`])
}) })
}) })
this.searchStore.add(this.query) this.searchStore.add(this.searchStore.query)
}, },
searchItems() { searchItems() {
return webapi.spotify().then(({ data }) => { return webapi.spotify().then(({ data }) => {
this.parameters.market = data.webapi_country this.parameters.market = data.webapi_country
const spotifyApi = new SpotifyWebApi() const spotifyApi = new SpotifyWebApi()
spotifyApi.setAccessToken(data.webapi_token) spotifyApi.setAccessToken(data.webapi_token)
return spotifyApi.search(this.query, this.types, this.parameters) return spotifyApi.search(
this.searchStore.query,
this.types,
this.parameters
)
}) })
}, },
searchLibrary() { searchLibrary() {
this.$router.push({ this.$router.push({ name: 'search-library' })
name: 'search-library'
})
}, },
searchNext({ loaded }) { searchNext({ loaded }) {
const [type] = this.types, const [type] = this.types,