Sorting and filtering

This commit is contained in:
Mark Cooper 2021-08-18 20:18:44 -05:00
parent a89d2e71cc
commit 7532b756a7
14 changed files with 450 additions and 42 deletions

View file

@ -20,13 +20,17 @@
</template>
<script>
import { sort } from '@/assets/fastSort'
console.log('SORT', sort)
export default {
data() {
return {
width: 0,
bookWidth: 176,
booksPerRow: 0,
groupedBooks: []
groupedBooks: [],
currFilterOrderKey: null
}
},
computed: {
@ -36,34 +40,19 @@ export default {
audiobooks() {
return this.$store.state.audiobooks.audiobooks
},
orderBy() {
return this.$store.state.settings.orderBy
},
orderDesc() {
return this.$store.state.settings.orderDesc
filterOrderKey() {
return this.$store.getters['settings/getFilterOrderKey']
}
},
methods: {
sortAudiobooks() {
var audiobooks = this.audiobooks.map((ab) => ({ ...ab }))
audiobooks.sort((a, b) => {
var bookA = a.book || {}
var bookB = b.book || {}
if (this.orderDesc) {
return bookB[this.orderBy] > bookA[this.orderBy] ? 1 : -1
} else {
// ASCENDING A -> Z
return bookA[this.orderBy] > bookB[this.orderBy] ? 1 : -1
}
})
return audiobooks
},
setGroupedBooks() {
var groups = []
var currentRow = 0
var currentGroup = []
var audiobooksSorted = this.sortAudiobooks()
console.log('AB SORTED', audiobooksSorted)
var audiobooksSorted = this.$store.getters['audiobooks/getFilteredAndSorted']()
this.currFilterOrderKey = this.filterOrderKey
for (let i = 0; i < audiobooksSorted.length; i++) {
var row = Math.floor(i / this.booksPerRow)
if (row > currentRow) {
@ -102,18 +91,27 @@ export default {
console.log('[AudioBookshelf] Audiobooks Updated')
this.setGroupedBooks()
},
settingsUpdated() {
// var newSortKey = `${this.orderBy}-${this.orderDesc}`
if (this.currFilterOrderKey !== this.filterOrderKey) {
this.setGroupedBooks()
}
},
scan() {
this.$root.socket.emit('scan')
}
},
mounted() {
this.$store.commit('audiobooks/addListener', { id: 'bookshelf', meth: this.audiobooksUpdated })
this.$store.commit('settings/addListener', { id: 'bookshelf', meth: this.settingsUpdated })
this.$store.dispatch('audiobooks/load')
this.init()
window.addEventListener('resize', this.resize)
},
beforeDestroy() {
this.$store.commit('audiobooks/removeListener', 'bookshelf')
this.$store.commit('settings/removeListener', 'bookshelf')
window.removeEventListener('resize', this.resize)
}
}

View file

@ -1,8 +1,13 @@
<template>
<div class="w-full h-10 relative">
<div id="toolbar" class="absolute top-0 left-0 w-full h-full z-10 flex items-center px-8">
<p>Order By: {{ orderBy }}</p>
<p class="px-4">Desc: {{ orderDesc ? 'Desc' : 'Asc' }}</p>
<!-- <p>Order By: {{ settings.orderBy }}</p>
<p class="px-4">Desc: {{ settings.orderDesc ? 'Desc' : 'Asc' }}</p> -->
<p class="font-book">{{ numShowing }} Audiobooks</p>
<div class="flex-grow" />
<controls-filter-select v-model="settings.filterBy" class="w-28 h-7.5" @change="updateFilter" />
<span class="px-4 text-sm">by</span>
<controls-order-select v-model="settings.orderBy" :descending.sync="settings.orderDesc" class="w-40 h-7.5" @change="updateOrder" />
</div>
</div>
</template>
@ -10,18 +15,33 @@
<script>
export default {
data() {
return {}
},
computed: {
orderBy() {
return this.$store.state.settings.orderBy
},
orderDesc() {
return this.$store.state.settings.orderDesc
return {
settings: {}
}
},
methods: {},
mounted() {}
computed: {
numShowing() {
return this.$store.getters['audiobooks/getFiltered']().length
}
},
methods: {
updateOrder() {
this.saveSettings()
},
updateFilter() {
this.saveSettings()
},
saveSettings() {
// Send to server
this.$store.commit('settings/setSettings', this.settings)
},
init() {
this.settings = { ...this.$store.state.settings.settings }
}
},
mounted() {
this.init()
}
}
</script>

View file

@ -0,0 +1,79 @@
<template>
<div ref="wrapper" class="relative" v-click-outside="clickOutside">
<button type="button" class="relative w-full h-full bg-fg border border-gray-500 hover:border-gray-300 rounded shadow-sm pl-3 pr-3 py-0 text-left focus:outline-none sm:text-sm cursor-pointer" aria-haspopup="listbox" aria-expanded="true" aria-labelledby="listbox-label" @click.prevent="showMenu = !showMenu">
<span class="flex items-center justify-between">
<span class="block truncate" :class="!selectedText ? 'text-gray-300' : ''">{{ selectedText }}</span>
</span>
<span class="ml-3 absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
<svg class="h-5 w-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M10 3a1 1 0 01.707.293l3 3a1 1 0 01-1.414 1.414L10 5.414 7.707 7.707a1 1 0 01-1.414-1.414l3-3A1 1 0 0110 3zm-3.707 9.293a1 1 0 011.414 0L10 14.586l2.293-2.293a1 1 0 011.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>
</span>
</button>
<ul v-show="showMenu" class="absolute z-10 mt-1 w-full bg-bg border border-black-200 shadow-lg max-h-56 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm" tabindex="-1" role="listbox" aria-labelledby="listbox-label" aria-activedescendant="listbox-option-3">
<template v-for="item in items">
<li :key="item.value" class="text-gray-50 select-none relative py-2 pr-9 cursor-pointer hover:bg-black-400" id="listbox-option-0" role="option" @click="clickedOption(item.value)">
<div class="flex items-center">
<span class="font-normal ml-3 block truncate">{{ item.text }}</span>
</div>
</li>
</template>
</ul>
</div>
</template>
<script>
export default {
props: {
value: String
},
data() {
return {
showMenu: false,
items: [
{
text: 'All',
value: 'all'
},
{
text: 'Genre',
value: 'genre'
},
{
text: 'Tag',
value: 'tag'
}
]
}
},
computed: {
selected: {
get() {
return this.value
},
set(val) {
this.$emit('input', val)
}
},
selectedText() {
var _sel = this.items.find((i) => i.value === this.selected)
if (!_sel) return ''
return _sel.text
}
},
methods: {
clickOutside() {
this.showMenu = false
},
clickedOption(val) {
if (this.selected === val) {
return
}
this.selected = val
this.showMenu = false
this.$nextTick(() => this.$emit('change', val))
}
}
}
</script>

View file

@ -0,0 +1,101 @@
<template>
<div ref="wrapper" class="relative" v-click-outside="clickOutside">
<button type="button" class="relative w-full h-full bg-fg border border-gray-500 hover:border-gray-300 rounded shadow-sm pl-3 pr-3 py-0 text-left focus:outline-none sm:text-sm cursor-pointer" aria-haspopup="listbox" aria-expanded="true" aria-labelledby="listbox-label" @click.prevent="showMenu = !showMenu">
<span class="flex items-center justify-between">
<span class="block truncate" :class="!selectedText ? 'text-gray-300' : ''">{{ selectedText }}</span>
<span class="material-icons text-xl text-yellow-400">{{ descending ? 'expand_more' : 'expand_less' }}</span>
</span>
<!-- <span class="ml-3 absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
<svg class="h-5 w-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M10 3a1 1 0 01.707.293l3 3a1 1 0 01-1.414 1.414L10 5.414 7.707 7.707a1 1 0 01-1.414-1.414l3-3A1 1 0 0110 3zm-3.707 9.293a1 1 0 011.414 0L10 14.586l2.293-2.293a1 1 0 011.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>
</span> -->
</button>
<ul v-show="showMenu" class="absolute z-10 mt-1 w-full bg-bg border border-black-200 shadow-lg max-h-56 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm" tabindex="-1" role="listbox" aria-labelledby="listbox-label" aria-activedescendant="listbox-option-3">
<template v-for="item in items">
<li :key="item.value" class="text-gray-50 select-none relative py-2 pr-9 cursor-pointer hover:bg-black-400" id="listbox-option-0" role="option" @click="clickedOption(item.value)">
<div class="flex items-center">
<span class="font-normal ml-3 block truncate">{{ item.text }}</span>
</div>
<span v-if="item.value === selected" class="text-yellow-400 absolute inset-y-0 right-0 flex items-center pr-4">
<span class="material-icons text-xl">{{ descending ? 'expand_more' : 'expand_less' }}</span>
</span>
</li>
</template>
</ul>
</div>
</template>
<script>
export default {
props: {
value: String,
descending: Boolean
},
data() {
return {
showMenu: false,
items: [
{
text: 'Title',
value: 'book.title'
},
{
text: 'Author',
value: 'book.author'
},
{
text: 'Added At',
value: 'addedAt'
},
{
text: 'Duration',
value: 'duration'
},
{
text: 'Size',
value: 'size'
}
]
}
},
computed: {
selected: {
get() {
return this.value
},
set(val) {
this.$emit('input', val)
}
},
selectedDesc: {
get() {
return this.descending
},
set(val) {
this.$emit('update:descending', val)
}
},
selectedText() {
var _sel = this.items.find((i) => i.value === this.selected)
if (!_sel) return ''
return _sel.text
}
},
methods: {
clickOutside() {
this.showMenu = false
},
clickedOption(val) {
if (this.selected === val) {
this.selectedDesc = !this.selectedDesc
} else {
this.selected = val
}
this.showMenu = false
this.$nextTick(() => this.$emit('change', val))
}
}
}
</script>