mirror of
https://github.com/advplyr/audiobookshelf-app.git
synced 2025-07-21 19:25:00 +02:00
Add: New search page
This commit is contained in:
parent
2965ccb513
commit
fd79baed61
3 changed files with 129 additions and 2 deletions
|
@ -24,6 +24,10 @@
|
|||
|
||||
<!-- <widgets-connection-icon /> -->
|
||||
|
||||
<nuxt-link class="h-7 mx-2" to="/search">
|
||||
<span class="material-icons" style="font-size: 1.75rem">search</span>
|
||||
</nuxt-link>
|
||||
|
||||
<div class="h-7 mx-2">
|
||||
<span class="material-icons" style="font-size: 1.75rem" @click="clickShowSideDrawer">menu</span>
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
<template>
|
||||
<input v-model="input" ref="input" autofocus :type="type" :disabled="disabled" autocorrect="off" autocapitalize="none" autocomplete="off" :placeholder="placeholder" class="px-2 py-1 bg-bg border border-gray-600 outline-none rounded-sm" :class="disabled ? 'text-gray-300' : 'text-white'" @keyup="keyup" />
|
||||
<div class="relative">
|
||||
<input v-model="input" ref="input" autofocus :type="type" :disabled="disabled" autocorrect="off" autocapitalize="none" autocomplete="off" :placeholder="placeholder" class="py-2 w-full outline-none" :class="inputClass" @keyup="keyup" />
|
||||
<div v-if="prependIcon" class="absolute top-0 left-0 h-full px-2 flex items-center justify-center">
|
||||
<span class="material-icons text-lg">{{ prependIcon }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -8,7 +13,24 @@ export default {
|
|||
value: [String, Number],
|
||||
placeholder: String,
|
||||
type: String,
|
||||
disabled: Boolean
|
||||
disabled: Boolean,
|
||||
borderless: Boolean,
|
||||
bg: {
|
||||
type: String,
|
||||
default: 'bg'
|
||||
},
|
||||
rounded: {
|
||||
type: String,
|
||||
default: 'sm'
|
||||
},
|
||||
prependIcon: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
textSize: {
|
||||
type: String,
|
||||
default: 'lg'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
|
@ -21,6 +43,17 @@ export default {
|
|||
set(val) {
|
||||
this.$emit('input', val)
|
||||
}
|
||||
},
|
||||
inputClass() {
|
||||
var classes = [`bg-${this.bg}`, `rounded-${this.rounded}`, `text-${this.textSize}`]
|
||||
if (this.disabled) classes.push('text-gray-300')
|
||||
else classes.push('text-white')
|
||||
|
||||
if (this.prependIcon) classes.push('pl-10 pr-2')
|
||||
else classes.push('px-2')
|
||||
|
||||
if (!this.borderless) classes.push('border border-gray-600')
|
||||
return classes.join(' ')
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
90
pages/search.vue
Normal file
90
pages/search.vue
Normal file
|
@ -0,0 +1,90 @@
|
|||
<template>
|
||||
<div class="w-full h-full">
|
||||
<div class="px-4 py-6">
|
||||
<ui-text-input ref="input" v-model="search" @input="updateSearch" borderless placeholder="Search" bg="white bg-opacity-5" rounded="md" prepend-icon="search" text-size="base" class="w-full text-lg" />
|
||||
</div>
|
||||
<div class="w-full overflow-x-hidden overflow-y-auto search-content px-4" @click.stop>
|
||||
<div v-show="isFetching" class="w-full py-8 flex justify-center">
|
||||
<p class="text-lg text-gray-400">Fetching...</p>
|
||||
</div>
|
||||
<div v-if="!isFetching && lastSearch && !items.length" class="w-full py-8 flex justify-center">
|
||||
<p class="text-lg text-gray-400">Nothing found</p>
|
||||
</div>
|
||||
<template v-for="item in items">
|
||||
<div class="py-2 border-b border-bg flex" :key="item.id" @click="clickItem(item)">
|
||||
<cards-book-cover :audiobook="item.data" :width="50" />
|
||||
<div class="flex-grow px-4 h-full">
|
||||
<div class="w-full h-full">
|
||||
<p class="text-base truncate">{{ item.data.book.title }}</p>
|
||||
<p class="text-sm text-gray-400 truncate">{{ item.data.book.author }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
search: null,
|
||||
searchTimeout: null,
|
||||
lastSearch: null,
|
||||
isFetching: false,
|
||||
items: []
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
methods: {
|
||||
clickItem(item) {
|
||||
this.show = false
|
||||
this.$router.push(`/audiobook/${item.id}`)
|
||||
},
|
||||
async runSearch(value) {
|
||||
this.lastSearch = value
|
||||
if (!this.lastSearch) {
|
||||
this.items = []
|
||||
return
|
||||
}
|
||||
this.isFetching = true
|
||||
var results = await this.$axios.$get(`/api/audiobooks?q=${value}`).catch((error) => {
|
||||
console.error('Search error', error)
|
||||
return []
|
||||
})
|
||||
this.isFetching = false
|
||||
this.items = results.map((res) => {
|
||||
return {
|
||||
id: res.id,
|
||||
data: res,
|
||||
type: 'audiobook'
|
||||
}
|
||||
})
|
||||
},
|
||||
updateSearch(val) {
|
||||
clearTimeout(this.searchTimeout)
|
||||
this.searchTimeout = setTimeout(() => {
|
||||
this.runSearch(val)
|
||||
}, 500)
|
||||
},
|
||||
setFocus() {
|
||||
setTimeout(() => {
|
||||
if (this.$refs.input) {
|
||||
this.$refs.input.focus()
|
||||
}
|
||||
}, 100)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(this.setFocus())
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.search-content {
|
||||
height: calc(100% - 108px);
|
||||
max-height: calc(100% - 108px);
|
||||
}
|
||||
</style>
|
Loading…
Add table
Add a link
Reference in a new issue