mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-01-22 00:07:52 +01:00
Merge pull request #2246 from MxMarx/expand-cover-images
show a modal with cover images when clicked
This commit is contained in:
commit
1df4dca4bb
@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="streamLibraryItem" id="streamContainer" class="w-full fixed bottom-0 left-0 right-0 h-48 md:h-40 z-50 bg-primary px-2 md:px-4 pb-1 md:pb-4 pt-2">
|
<div v-if="streamLibraryItem" id="streamContainer" class="w-full fixed bottom-0 left-0 right-0 h-48 md:h-40 z-50 bg-primary px-2 md:px-4 pb-1 md:pb-4 pt-2">
|
||||||
<div id="videoDock" />
|
<div id="videoDock" />
|
||||||
<nuxt-link v-if="!playerHandler.isVideo" :to="`/item/${streamLibraryItem.id}`" class="absolute left-2 top-2 md:left-4 cursor-pointer">
|
<div class="absolute left-2 top-2 md:left-4 cursor-pointer">
|
||||||
<covers-book-cover :library-item="streamLibraryItem" :width="bookCoverWidth" :book-cover-aspect-ratio="coverAspectRatio" />
|
<covers-book-cover expand-on-click :library-item="streamLibraryItem" :width="bookCoverWidth" :book-cover-aspect-ratio="coverAspectRatio" />
|
||||||
</nuxt-link>
|
</div>
|
||||||
<div class="flex items-start mb-6 md:mb-0" :class="playerHandler.isVideo ? 'ml-4 pl-96' : isSquareCover ? 'pl-18 sm:pl-24' : 'pl-12 sm:pl-16'">
|
<div class="flex items-start mb-6 md:mb-0" :class="playerHandler.isVideo ? 'ml-4 pl-96' : isSquareCover ? 'pl-18 sm:pl-24' : 'pl-12 sm:pl-16'">
|
||||||
<div class="min-w-0">
|
<div class="min-w-0">
|
||||||
<nuxt-link :to="`/item/${streamLibraryItem.id}`" class="hover:underline cursor-pointer text-sm sm:text-lg block truncate">
|
<nuxt-link :to="`/item/${streamLibraryItem.id}`" class="hover:underline cursor-pointer text-sm sm:text-lg block truncate">
|
||||||
|
@ -5,7 +5,8 @@
|
|||||||
<div class="absolute cover-bg" ref="coverBg" />
|
<div class="absolute cover-bg" ref="coverBg" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<img v-if="libraryItem" ref="cover" :src="fullCoverUrl" loading="lazy" @error="imageError" @load="imageLoaded" class="w-full h-full absolute top-0 left-0 z-10 duration-300 transition-opacity" :style="{ opacity: imageReady ? '1' : '0' }" :class="showCoverBg ? 'object-contain' : 'object-fill'" />
|
<img v-if="libraryItem" ref="cover" :src="fullCoverUrl" loading="lazy" draggable="false" @error="imageError" @load="imageLoaded" class="w-full h-full absolute top-0 left-0 z-10 duration-300 transition-opacity" :style="{ opacity: imageReady ? '1' : '0' }" :class="showCoverBg ? 'object-contain' : 'object-fill'" @click="clickCover" />
|
||||||
|
|
||||||
<div v-show="loading && libraryItem" class="absolute top-0 left-0 h-full w-full flex items-center justify-center">
|
<div v-show="loading && libraryItem" class="absolute top-0 left-0 h-full w-full flex items-center justify-center">
|
||||||
<p class="text-center" :style="{ fontSize: 0.75 * sizeMultiplier + 'rem' }">{{ title }}</p>
|
<p class="text-center" :style="{ fontSize: 0.75 * sizeMultiplier + 'rem' }">{{ title }}</p>
|
||||||
<div class="absolute top-2 right-2">
|
<div class="absolute top-2 right-2">
|
||||||
@ -43,6 +44,7 @@ export default {
|
|||||||
type: Number,
|
type: Number,
|
||||||
default: 120
|
default: 120
|
||||||
},
|
},
|
||||||
|
expandOnClick: Boolean,
|
||||||
bookCoverAspectRatio: Number
|
bookCoverAspectRatio: Number
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
@ -132,6 +134,11 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
clickCover() {
|
||||||
|
if (this.expandOnClick && this.libraryItem) {
|
||||||
|
this.$store.commit('globals/setRawCoverPreviewModal', this.libraryItem.id)
|
||||||
|
}
|
||||||
|
},
|
||||||
setCoverBg() {
|
setCoverBg() {
|
||||||
if (this.$refs.coverBg) {
|
if (this.$refs.coverBg) {
|
||||||
this.$refs.coverBg.style.backgroundImage = `url("${this.fullCoverUrl}")`
|
this.$refs.coverBg.style.backgroundImage = `url("${this.fullCoverUrl}")`
|
||||||
|
33
client/components/modals/RawCoverPreviewModal.vue
Normal file
33
client/components/modals/RawCoverPreviewModal.vue
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<template>
|
||||||
|
<modals-modal v-model="show" name="cover" :width="'90%'" :height="'90%'" :contentMarginTop="0">
|
||||||
|
<div class="w-full h-full" @click="show = false">
|
||||||
|
<img loading="lazy" :src="rawCoverUrl" class="w-full h-full z-10 object-scale-down" />
|
||||||
|
</div>
|
||||||
|
</modals-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
show: {
|
||||||
|
get() {
|
||||||
|
return this.$store.state.globals.showRawCoverPreviewModal
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$store.commit('globals/setShowRawCoverPreviewModal', val)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
selectedLibraryItemId() {
|
||||||
|
return this.$store.state.globals.selectedLibraryItemId
|
||||||
|
},
|
||||||
|
rawCoverUrl() {
|
||||||
|
return this.$store.getters['globals/getLibraryItemCoverSrcById'](this.selectedLibraryItemId, null, true)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {},
|
||||||
|
mounted() {}
|
||||||
|
}
|
||||||
|
</script>
|
@ -19,6 +19,7 @@
|
|||||||
<modals-authors-edit-modal />
|
<modals-authors-edit-modal />
|
||||||
<modals-batch-quick-match-model />
|
<modals-batch-quick-match-model />
|
||||||
<modals-rssfeed-open-close-modal />
|
<modals-rssfeed-open-close-modal />
|
||||||
|
<modals-raw-cover-preview-modal />
|
||||||
<prompt-confirm />
|
<prompt-confirm />
|
||||||
<readers-reader />
|
<readers-reader />
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,21 +3,21 @@
|
|||||||
<div class="w-full h-full overflow-y-auto px-2 py-6 lg:p-8">
|
<div class="w-full h-full overflow-y-auto px-2 py-6 lg:p-8">
|
||||||
<div class="flex flex-col lg:flex-row max-w-6xl mx-auto">
|
<div class="flex flex-col lg:flex-row max-w-6xl mx-auto">
|
||||||
<div class="w-full flex justify-center lg:block lg:w-52" style="min-width: 208px">
|
<div class="w-full flex justify-center lg:block lg:w-52" style="min-width: 208px">
|
||||||
<div class="relative" style="height: fit-content">
|
<div class="relative group" style="height: fit-content">
|
||||||
<covers-book-cover :library-item="libraryItem" :width="bookCoverWidth" :book-cover-aspect-ratio="bookCoverAspectRatio" />
|
<covers-book-cover class="relative group-hover:brightness-75 transition cursor-pointer" expand-on-click :library-item="libraryItem" :width="bookCoverWidth" :book-cover-aspect-ratio="bookCoverAspectRatio" />
|
||||||
|
|
||||||
<!-- Item Progress Bar -->
|
<!-- Item Progress Bar -->
|
||||||
<div v-if="!isPodcast" class="absolute bottom-0 left-0 h-1.5 shadow-sm z-10" :class="userIsFinished ? 'bg-success' : 'bg-yellow-400'" :style="{ width: 208 * progressPercent + 'px' }"></div>
|
<div v-if="!isPodcast" class="absolute bottom-0 left-0 h-1.5 shadow-sm z-10" :class="userIsFinished ? 'bg-success' : 'bg-yellow-400'" :style="{ width: 208 * progressPercent + 'px' }"></div>
|
||||||
|
|
||||||
<!-- Item Cover Overlay -->
|
<!-- Item Cover Overlay -->
|
||||||
<div class="absolute top-0 left-0 w-full h-full z-10 bg-black bg-opacity-30 opacity-0 hover:opacity-100 transition-opacity" @mousedown.prevent @mouseup.prevent>
|
<div class="absolute top-0 left-0 w-full h-full z-10 opacity-0 group-hover:opacity-100 pointer-events-none">
|
||||||
<div v-show="showPlayButton && !isStreaming" class="h-full flex items-center justify-center pointer-events-none">
|
<div v-show="showPlayButton && !isStreaming" class="h-full flex items-center justify-center pointer-events-none">
|
||||||
<div class="hover:text-white text-gray-200 hover:scale-110 transform duration-200 pointer-events-auto cursor-pointer" @click.stop.prevent="playItem">
|
<div class="hover:text-white text-gray-200 hover:scale-110 transform duration-200 pointer-events-auto cursor-pointer" @click.stop.prevent="playItem">
|
||||||
<span class="material-icons text-4xl">play_circle_filled</span>
|
<span class="material-icons text-4xl">play_circle_filled</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span class="absolute bottom-2.5 right-2.5 z-10 material-icons text-lg cursor-pointer text-white text-opacity-75 hover:text-opacity-100 hover:scale-110 transform duration-200" @click="showEditCover">edit</span>
|
<span class="absolute bottom-2.5 right-2.5 z-10 material-icons text-lg cursor-pointer text-white text-opacity-75 hover:text-opacity-100 hover:scale-110 transform duration-200 pointer-events-auto" @click="showEditCover">edit</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -11,6 +11,7 @@ export const state = () => ({
|
|||||||
showViewPodcastEpisodeModal: false,
|
showViewPodcastEpisodeModal: false,
|
||||||
showRSSFeedOpenCloseModal: false,
|
showRSSFeedOpenCloseModal: false,
|
||||||
showConfirmPrompt: false,
|
showConfirmPrompt: false,
|
||||||
|
showRawCoverPreviewModal: false,
|
||||||
confirmPromptOptions: null,
|
confirmPromptOptions: null,
|
||||||
showEditAuthorModal: false,
|
showEditAuthorModal: false,
|
||||||
rssFeedEntity: null,
|
rssFeedEntity: null,
|
||||||
@ -20,6 +21,7 @@ export const state = () => ({
|
|||||||
selectedCollection: null,
|
selectedCollection: null,
|
||||||
selectedAuthor: null,
|
selectedAuthor: null,
|
||||||
selectedMediaItems: [],
|
selectedMediaItems: [],
|
||||||
|
selectedLibraryItemId: null,
|
||||||
isCasting: false, // Actively casting
|
isCasting: false, // Actively casting
|
||||||
isChromecastInitialized: false, // Script loadeds
|
isChromecastInitialized: false, // Script loadeds
|
||||||
showBatchQuickMatchModal: false,
|
showBatchQuickMatchModal: false,
|
||||||
@ -80,7 +82,7 @@ export const state = () => ({
|
|||||||
})
|
})
|
||||||
|
|
||||||
export const getters = {
|
export const getters = {
|
||||||
getLibraryItemCoverSrc: (state, getters, rootState, rootGetters) => (libraryItem, placeholder = null) => {
|
getLibraryItemCoverSrc: (state, getters, rootState, rootGetters) => (libraryItem, placeholder = null, raw = false) => {
|
||||||
if (!placeholder) placeholder = `${rootState.routerBasePath}/book_placeholder.jpg`
|
if (!placeholder) placeholder = `${rootState.routerBasePath}/book_placeholder.jpg`
|
||||||
if (!libraryItem) return placeholder
|
if (!libraryItem) return placeholder
|
||||||
const media = libraryItem.media
|
const media = libraryItem.media
|
||||||
@ -94,7 +96,7 @@ export const getters = {
|
|||||||
const libraryItemId = libraryItem.libraryItemId || libraryItem.id // Workaround for /users/:id page showing media progress covers
|
const libraryItemId = libraryItem.libraryItemId || libraryItem.id // Workaround for /users/:id page showing media progress covers
|
||||||
|
|
||||||
if (process.env.NODE_ENV !== 'production') { // Testing
|
if (process.env.NODE_ENV !== 'production') { // Testing
|
||||||
return `http://localhost:3333${rootState.routerBasePath}/api/items/${libraryItemId}/cover?token=${userToken}&ts=${lastUpdate}`
|
return `http://localhost:3333${rootState.routerBasePath}/api/items/${libraryItemId}/cover?token=${userToken}&ts=${lastUpdate}${raw ? '&raw=1' : ''}`
|
||||||
}
|
}
|
||||||
|
|
||||||
return `${rootState.routerBasePath}/api/items/${libraryItemId}/cover?token=${userToken}&ts=${lastUpdate}`
|
return `${rootState.routerBasePath}/api/items/${libraryItemId}/cover?token=${userToken}&ts=${lastUpdate}`
|
||||||
@ -156,6 +158,13 @@ export const mutations = {
|
|||||||
state.confirmPromptOptions = options
|
state.confirmPromptOptions = options
|
||||||
state.showConfirmPrompt = true
|
state.showConfirmPrompt = true
|
||||||
},
|
},
|
||||||
|
setShowRawCoverPreviewModal(state, val) {
|
||||||
|
state.showRawCoverPreviewModal = val
|
||||||
|
},
|
||||||
|
setRawCoverPreviewModal(state, libraryItemId) {
|
||||||
|
state.selectedLibraryItemId = libraryItemId
|
||||||
|
state.showRawCoverPreviewModal = true
|
||||||
|
},
|
||||||
setEditCollection(state, collection) {
|
setEditCollection(state, collection) {
|
||||||
state.selectedCollection = collection
|
state.selectedCollection = collection
|
||||||
state.showEditCollectionModal = true
|
state.showEditCollectionModal = true
|
||||||
|
Loading…
Reference in New Issue
Block a user