mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-07-10 19:31:39 +00:00
add a layout option to the authors page Cards|Table
This commit is contained in:
parent
c72eac9987
commit
9246e46423
4 changed files with 113 additions and 6 deletions
|
|
@ -98,6 +98,7 @@
|
||||||
|
|
||||||
<!-- author sort select -->
|
<!-- author sort select -->
|
||||||
<controls-sort-select v-if="authors?.length" v-model="settings.authorSortBy" :descending.sync="settings.authorSortDesc" :items="authorSortItems" class="w-36 sm:w-44 md:w-48 h-7.5 ml-1 sm:ml-4" @change="updateAuthorSort" />
|
<controls-sort-select v-if="authors?.length" v-model="settings.authorSortBy" :descending.sync="settings.authorSortDesc" :items="authorSortItems" class="w-36 sm:w-44 md:w-48 h-7.5 ml-1 sm:ml-4" @change="updateAuthorSort" />
|
||||||
|
<controls-layout-select v-if="authors?.length" v-model="settings.authorPageLayout" :items="layoutSelectItems" class="w-24 sm:w-44 md:w-48 h-7.5 ml-1 sm:ml-4" @change="updateAuthorLayout" />
|
||||||
</template>
|
</template>
|
||||||
<!-- home page -->
|
<!-- home page -->
|
||||||
<template v-else-if="isHome">
|
<template v-else-if="isHome">
|
||||||
|
|
@ -195,6 +196,18 @@ export default {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
layoutSelectItems() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
text: 'Cards',
|
||||||
|
value: 'cards'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Table',
|
||||||
|
value: 'table'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
authorSortItems() {
|
authorSortItems() {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
|
@ -593,6 +606,9 @@ export default {
|
||||||
updateAuthorSort() {
|
updateAuthorSort() {
|
||||||
this.saveSettings()
|
this.saveSettings()
|
||||||
},
|
},
|
||||||
|
updateAuthorLayout() {
|
||||||
|
this.saveSettings()
|
||||||
|
},
|
||||||
saveSettings() {
|
saveSettings() {
|
||||||
this.$store.dispatch('user/updateUserSettings', this.settings)
|
this.$store.dispatch('user/updateUserSettings', this.settings)
|
||||||
},
|
},
|
||||||
|
|
|
||||||
66
client/components/controls/LayoutSelect.vue
Normal file
66
client/components/controls/LayoutSelect.vue
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
<template>
|
||||||
|
<div ref="wrapper" class="relative" v-click-outside="clickOutside">
|
||||||
|
<button type="button" class="relative w-full h-full border border-gray-500 hover:border-gray-400 rounded shadow-sm pl-3 pr-3 py-0 text-left focus:outline-none 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 text-xs" :class="!selectedText ? 'text-gray-300' : ''">{{ selectedText }}</span>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<ul v-show="showMenu" class="absolute z-10 mt-1 w-full bg-bg border border-black-200 shadow-lg max-h-80 rounded-md py-1 ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none text-sm" role="listbox" aria-labelledby="listbox-label">
|
||||||
|
<template v-for="item in items">
|
||||||
|
<li :key="item.value" class="select-none relative py-2 pr-9 cursor-pointer hover:bg-white/5" :class="item.value === selected ? 'bg-white/5 text-yellow-400' : 'text-gray-200 hover:text-white'" 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,
|
||||||
|
items: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
showMenu: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
selected: {
|
||||||
|
get() {
|
||||||
|
return this.value
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$emit('input', val)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
selectedText() {
|
||||||
|
var _selected = this.selected
|
||||||
|
if (!_selected) return ''
|
||||||
|
var _sel = this.items.find((i) => i.value === _selected)
|
||||||
|
if (!_sel) return ''
|
||||||
|
return _sel.text
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
clickOutside() {
|
||||||
|
this.showMenu = false
|
||||||
|
},
|
||||||
|
clickedOption(val) {
|
||||||
|
if (this.selected === val) {
|
||||||
|
} else {
|
||||||
|
this.selected = val
|
||||||
|
}
|
||||||
|
this.showMenu = false
|
||||||
|
this.$nextTick(() => this.$emit('change', val))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -2,12 +2,33 @@
|
||||||
<div class="page" :class="streamLibraryItem ? 'streaming' : ''">
|
<div class="page" :class="streamLibraryItem ? 'streaming' : ''">
|
||||||
<app-book-shelf-toolbar page="authors" is-home :authors="authors" />
|
<app-book-shelf-toolbar page="authors" is-home :authors="authors" />
|
||||||
<div id="bookshelf" class="w-full h-full p-8e overflow-y-auto" :style="{ fontSize: sizeMultiplier + 'rem' }">
|
<div id="bookshelf" class="w-full h-full p-8e overflow-y-auto" :style="{ fontSize: sizeMultiplier + 'rem' }">
|
||||||
<!-- Cover size widget -->
|
<div v-if="authorLayoutType === 'cards'">
|
||||||
<widgets-cover-size-widget class="fixed right-4 z-50" :style="{ bottom: streamLibraryItem ? '181px' : '16px' }" />
|
<!-- Cover size widget -->
|
||||||
<div class="flex flex-wrap justify-center">
|
<widgets-cover-size-widget class="fixed right-4 z-50" :style="{ bottom: streamLibraryItem ? '181px' : '16px' }" />
|
||||||
<template v-for="author in authorsSorted">
|
<div class="flex flex-wrap justify-center">
|
||||||
<cards-author-card :key="author.id" :author="author" class="p-3e" @edit="editAuthor" />
|
<template v-for="author in authorsSorted">
|
||||||
</template>
|
<cards-author-card :key="author.id" :author="author" class="p-3e" @edit="editAuthor" />
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="authorLayoutType === 'table'">
|
||||||
|
<table class="tracksTable max-w-2xl mx-auto">
|
||||||
|
<tr>
|
||||||
|
<th class="text-left">{{ $strings.LabelName }}</th>
|
||||||
|
<th class="text-center w-24">{{ $strings.LabelBooks }}</th>
|
||||||
|
</tr>
|
||||||
|
<tr v-for="author in authorsSorted" :key="author.id">
|
||||||
|
<td>
|
||||||
|
<nuxt-link :to="`/author/${author.id}`">
|
||||||
|
<p class="text-sm md:text-base text-gray-100">{{ author.name }}</p>
|
||||||
|
</nuxt-link>
|
||||||
|
</td>
|
||||||
|
<td class="text-center w-24 h-12">
|
||||||
|
<nuxt-link :to="`/library/${currentLibraryId}/bookshelf?filter=authors.${$encode(author.id)}`" class="hover:underline">{{ author.numBooks }}</nuxt-link>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -53,6 +74,9 @@ export default {
|
||||||
authorSortBy() {
|
authorSortBy() {
|
||||||
return this.$store.getters['user/getUserSetting']('authorSortBy') || 'name'
|
return this.$store.getters['user/getUserSetting']('authorSortBy') || 'name'
|
||||||
},
|
},
|
||||||
|
authorLayoutType() {
|
||||||
|
return this.$store.getters['user/getUserSetting']('authorPageLayout') || 'cards'
|
||||||
|
},
|
||||||
authorSortDesc() {
|
authorSortDesc() {
|
||||||
return !!this.$store.getters['user/getUserSetting']('authorSortDesc')
|
return !!this.$store.getters['user/getUserSetting']('authorSortDesc')
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
export const state = () => ({
|
export const state = () => ({
|
||||||
user: null,
|
user: null,
|
||||||
settings: {
|
settings: {
|
||||||
|
authorPageLayout: 'cards',
|
||||||
orderBy: 'media.metadata.title',
|
orderBy: 'media.metadata.title',
|
||||||
orderDesc: false,
|
orderDesc: false,
|
||||||
filterBy: 'all',
|
filterBy: 'all',
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue