mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-10-27 11:18:14 +01:00 
			
		
		
		
	Update:Audio player visible when ereader is open #1800 and adding zoom to PDF reader
This commit is contained in:
		
							parent
							
								
									2cc23b6d6b
								
							
						
					
					
						commit
						2fa73f7a8d
					
				| @ -1,11 +1,11 @@ | ||||
| <template> | ||||
|   <div class="w-full h-full"> | ||||
|     <div v-show="showPageMenu" v-click-outside="clickOutside" class="pagemenu absolute top-9 right-20 rounded-md overflow-y-auto bg-bg shadow-lg z-20 border border-gray-400 w-52"> | ||||
|     <div v-show="showPageMenu" v-click-outside="clickOutside" class="pagemenu absolute top-9 left-8 rounded-md overflow-y-auto bg-bg shadow-lg z-20 border border-gray-400 w-52"> | ||||
|       <div v-for="(file, index) in pages" :key="file" class="w-full cursor-pointer hover:bg-black-200 px-2 py-1" :class="page === index ? 'bg-black-200' : ''" @click="setPage(index)"> | ||||
|         <p class="text-sm truncate">{{ file }}</p> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div v-show="showInfoMenu" v-click-outside="clickOutside" class="pagemenu absolute top-9 right-10 rounded-md overflow-y-auto bg-bg shadow-lg z-20 border border-gray-400 w-96"> | ||||
|     <div v-show="showInfoMenu" v-click-outside="clickOutside" class="pagemenu absolute top-9 left-20 rounded-md overflow-y-auto bg-bg shadow-lg z-20 border border-gray-400 w-96"> | ||||
|       <div v-for="key in comicMetadataKeys" :key="key" class="w-full px-2 py-1"> | ||||
|         <p class="text-xs"> | ||||
|           <strong>{{ key }}</strong | ||||
| @ -14,17 +14,17 @@ | ||||
|       </div> | ||||
|     </div> | ||||
| 
 | ||||
|     <div v-if="comicMetadata" class="absolute top-0 right-52 bg-bg text-gray-100 border-b border-l border-r border-gray-400 hover:bg-black-200 cursor-pointer rounded-b-md w-10 h-9 flex items-center justify-center text-center z-20" @mousedown.prevent @click.stop.prevent="showInfoMenu = !showInfoMenu"> | ||||
|     <div v-if="comicMetadata" class="absolute top-0 left-20 bg-bg text-gray-100 border-b border-l border-r border-gray-400 hover:bg-black-200 cursor-pointer rounded-b-md w-10 h-9 flex items-center justify-center text-center z-20" @mousedown.prevent @click.stop.prevent="showInfoMenu = !showInfoMenu"> | ||||
|       <span class="material-icons text-xl">more</span> | ||||
|     </div> | ||||
|     <div class="absolute top-0 bg-bg text-gray-100 border-b border-l border-r border-gray-400 hover:bg-black-200 cursor-pointer rounded-b-md w-10 h-9 flex items-center justify-center text-center z-20" style="right: 156px" @mousedown.prevent @click.stop.prevent="showPageMenu = !showPageMenu"> | ||||
|     <div class="absolute top-0 left-8 bg-bg text-gray-100 border-b border-l border-r border-gray-400 hover:bg-black-200 cursor-pointer rounded-b-md w-10 h-9 flex items-center justify-center text-center z-20" @mousedown.prevent @click.stop.prevent="showPageMenu = !showPageMenu"> | ||||
|       <span class="material-icons text-xl">menu</span> | ||||
|     </div> | ||||
|     <div class="absolute top-0 right-20 bg-bg text-gray-100 border-b border-l border-r border-gray-400 rounded-b-md px-2 h-9 flex items-center text-center z-20"> | ||||
|     <div class="absolute top-0 right-16 bg-bg text-gray-100 border-b border-l border-r border-gray-400 rounded-b-md px-2 h-9 flex items-center text-center z-20"> | ||||
|       <p class="font-mono">{{ page + 1 }} / {{ numPages }}</p> | ||||
|     </div> | ||||
| 
 | ||||
|     <div class="overflow-hidden m-auto comicwrapper relative"> | ||||
|     <div class="overflow-hidden w-full h-full relative"> | ||||
|       <div v-show="canGoPrev" class="absolute top-0 left-0 h-full w-1/2 hover:opacity-100 opacity-0 z-10 cursor-pointer" @click.stop.prevent="prev" @mousedown.prevent> | ||||
|         <div class="flex items-center justify-center h-full w-1/2"> | ||||
|           <span v-show="loadedFirstPage" class="material-icons text-5xl text-white cursor-pointer text-opacity-30 hover:text-opacity-90">arrow_back_ios</span> | ||||
| @ -36,17 +36,13 @@ | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="h-full flex justify-center"> | ||||
|         <img v-if="mainImg" :src="mainImg" class="object-contain comicimg" /> | ||||
|         <img v-if="mainImg" :src="mainImg" class="object-contain h-full m-auto" /> | ||||
|       </div> | ||||
| 
 | ||||
|       <div v-show="loading" class="w-full h-full absolute top-0 left-0 flex items-center justify-center z-10"> | ||||
|         <ui-loading-indicator /> | ||||
|       </div> | ||||
|     </div> | ||||
| 
 | ||||
|     <!-- <div v-show="loading" class="w-screen h-screen absolute top-0 left-0 bg-black bg-opacity-20 flex items-center justify-center"> | ||||
|       <ui-loading-indicator /> | ||||
|     </div> --> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| @ -61,7 +57,12 @@ Archive.init({ | ||||
| 
 | ||||
| export default { | ||||
|   props: { | ||||
|     url: String | ||||
|     url: String, | ||||
|     libraryItem: { | ||||
|       type: Object, | ||||
|       default: () => {} | ||||
|     }, | ||||
|     playerOpen: Boolean | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
| @ -249,15 +250,6 @@ export default { | ||||
| 
 | ||||
| <style scoped> | ||||
| .pagemenu { | ||||
|   max-height: calc(100vh - 60px); | ||||
| } | ||||
| .comicimg { | ||||
|   height: calc(100vh - 40px); | ||||
|   margin: auto; | ||||
| } | ||||
| .comicwrapper { | ||||
|   width: 100vw; | ||||
|   height: calc(100vh - 40px); | ||||
|   margin-top: 20px; | ||||
|   max-height: calc(100% - 48px); | ||||
| } | ||||
| </style> | ||||
| @ -1,5 +1,5 @@ | ||||
| <template> | ||||
|   <div class="h-full w-full"> | ||||
|   <div id="epub-reader" class="h-full w-full"> | ||||
|     <div class="h-full flex items-center justify-center"> | ||||
|       <div style="width: 100px; max-width: 100px" class="h-full hidden sm:flex items-center overflow-x-hidden justify-center"> | ||||
|         <span v-if="hasPrev" class="material-icons text-white text-opacity-50 hover:text-opacity-80 cursor-pointer text-6xl" @mousedown.prevent @click="prev">chevron_left</span> | ||||
| @ -28,17 +28,24 @@ export default { | ||||
|     libraryItem: { | ||||
|       type: Object, | ||||
|       default: () => {} | ||||
|     } | ||||
|     }, | ||||
|     playerOpen: Boolean | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       windowWidth: 0, | ||||
|       windowHeight: 0, | ||||
|       /** @type {ePub.Book} */ | ||||
|       book: null, | ||||
|       /** @type {ePub.Rendition} */ | ||||
|       rendition: null | ||||
|     } | ||||
|   }, | ||||
|   watch: { | ||||
|     playerOpen() { | ||||
|       this.resize() | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     /** @returns {string} */ | ||||
|     libraryItemId() { | ||||
| @ -64,6 +71,10 @@ export default { | ||||
|     readerWidth() { | ||||
|       if (this.windowWidth < 640) return this.windowWidth | ||||
|       return this.windowWidth - 200 | ||||
|     }, | ||||
|     readerHeight() { | ||||
|       if (this.windowHeight < 400 || !this.playerOpen) return this.windowHeight | ||||
|       return this.windowHeight - 164 | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
| @ -203,13 +214,13 @@ export default { | ||||
|       /** @type {ePub.Book} */ | ||||
|       reader.book = new ePub(reader.url, { | ||||
|         width: this.readerWidth, | ||||
|         height: window.innerHeight - 50 | ||||
|         height: this.readerHeight - 50 | ||||
|       }) | ||||
| 
 | ||||
|       /** @type {ePub.Rendition} */ | ||||
|       reader.rendition = reader.book.renderTo('viewer', { | ||||
|         width: this.readerWidth, | ||||
|         height: window.innerHeight * 0.8 | ||||
|         height: this.readerHeight * 0.8 | ||||
|       }) | ||||
| 
 | ||||
|       // load saved progress | ||||
| @ -253,17 +264,19 @@ export default { | ||||
|     }, | ||||
|     resize() { | ||||
|       this.windowWidth = window.innerWidth | ||||
|       this.rendition?.resize(this.readerWidth, window.innerHeight * 0.8) | ||||
|       this.windowHeight = window.innerHeight | ||||
|       this.rendition?.resize(this.readerWidth, this.readerHeight * 0.8) | ||||
|     } | ||||
|   }, | ||||
|   mounted() { | ||||
|     this.windowWidth = window.innerWidth | ||||
|     this.windowHeight = window.innerHeight | ||||
|     window.addEventListener('resize', this.resize) | ||||
|     this.initEpub() | ||||
|   }, | ||||
|   beforeDestroy() { | ||||
|     window.removeEventListener('resize', this.resize) | ||||
|     this.book?.destroy() | ||||
|   }, | ||||
|   mounted() { | ||||
|     this.windowWidth = window.innerWidth | ||||
|     window.addEventListener('resize', this.resize) | ||||
|     this.initEpub() | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <template> | ||||
|   <div class="w-full h-full"> | ||||
|     <div class="h-full max-h-full w-full"> | ||||
|       <div class="ebook-viewer absolute overflow-y-scroll left-0 right-0 top-12 w-full max-w-4xl m-auto z-10 border border-black border-opacity-20 shadow-md bg-white"> | ||||
|       <div class="ebook-viewer absolute overflow-y-scroll left-0 right-0 top-16 w-full max-w-4xl m-auto z-10 border border-black border-opacity-20 shadow-md bg-white"> | ||||
|         <iframe title="html-viewer" width="100%"> Loading </iframe> | ||||
|       </div> | ||||
|     </div> | ||||
| @ -15,7 +15,12 @@ import defaultCss from '@/assets/ebooks/basic.js' | ||||
| 
 | ||||
| export default { | ||||
|   props: { | ||||
|     url: String | ||||
|     url: String, | ||||
|     libraryItem: { | ||||
|       type: Object, | ||||
|       default: () => {} | ||||
|     }, | ||||
|     playerOpen: Boolean | ||||
|   }, | ||||
|   data() { | ||||
|     return {} | ||||
|  | ||||
| @ -11,13 +11,17 @@ | ||||
|       </div> | ||||
|     </div> | ||||
| 
 | ||||
|     <div class="absolute top-0 right-20 bg-bg text-gray-100 border-b border-l border-r border-gray-400 rounded-b-md px-2 h-9 flex items-center text-center"> | ||||
|     <div class="absolute top-0 right-20 bg-bg text-gray-100 border-b border-l border-r border-gray-400 z-20 rounded-b-md px-2 h-9 flex items-center text-center"> | ||||
|       <p class="font-mono">{{ page }} / {{ numPages }}</p> | ||||
|     </div> | ||||
|     <div class="absolute top-0 right-40 bg-bg text-gray-100 border-b border-l border-r border-gray-400 z-20 rounded-b-md px-2 h-9 flex items-center text-center"> | ||||
|       <ui-icon-btn icon="zoom_out" :size="8" :disabled="!canScaleDown" borderless class="mr-px" @click="zoomOut" /> | ||||
|       <ui-icon-btn icon="zoom_in" :size="8" :disabled="!canScaleUp" borderless class="ml-px" @click="zoomIn" /> | ||||
|     </div> | ||||
| 
 | ||||
|     <div :style="{ height: pdfHeight + 'px' }" class="overflow-hidden m-auto"> | ||||
|       <div class="flex items-center justify-center"> | ||||
|         <div :style="{ width: pdfWidth + 'px', height: pdfHeight + 'px' }" class="w-full h-full overflow-auto"> | ||||
|         <div :style="{ width: pdfWidth + 'px', height: pdfHeight + 'px' }" class="overflow-auto"> | ||||
|           <div v-if="loadedRatio > 0 && loadedRatio < 1" style="background-color: green; color: white; text-align: center" :style="{ width: loadedRatio * 100 + '%' }">{{ Math.floor(loadedRatio * 100) }}%</div> | ||||
|           <pdf ref="pdf" class="m-auto z-10 border border-black border-opacity-20 shadow-md" :src="url" :page="page" :rotate="rotate" @progress="progressEvt" @error="error" @num-pages="numPagesLoaded" @link-clicked="page = $event" @loaded="loadedEvt"></pdf> | ||||
|         </div> | ||||
| @ -41,10 +45,14 @@ export default { | ||||
|     libraryItem: { | ||||
|       type: Object, | ||||
|       default: () => {} | ||||
|     } | ||||
|     }, | ||||
|     playerOpen: Boolean | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       windowWidth: 0, | ||||
|       windowHeight: 0, | ||||
|       scale: 1, | ||||
|       rotate: 0, | ||||
|       loadedRatio: 0, | ||||
|       page: 1, | ||||
| @ -55,11 +63,18 @@ export default { | ||||
|     libraryItemId() { | ||||
|       return this.libraryItem?.id | ||||
|     }, | ||||
|     fitToPageWidth() { | ||||
|       return this.pdfHeight * 0.6 | ||||
|     }, | ||||
|     pdfWidth() { | ||||
|       return this.pdfHeight * 0.6667 | ||||
|       return this.fitToPageWidth * this.scale | ||||
|     }, | ||||
|     pdfHeight() { | ||||
|       return window.innerHeight - 120 | ||||
|       if (this.windowHeight < 400 || !this.playerOpen) return this.windowHeight - 120 | ||||
|       return this.windowHeight - 284 | ||||
|     }, | ||||
|     maxScale() { | ||||
|       return Math.floor((this.windowWidth * 10) / this.fitToPageWidth) / 10 | ||||
|     }, | ||||
|     canGoNext() { | ||||
|       return this.page < this.numPages | ||||
| @ -67,6 +82,12 @@ export default { | ||||
|     canGoPrev() { | ||||
|       return this.page > 1 | ||||
|     }, | ||||
|     canScaleUp() { | ||||
|       return this.scale < this.maxScale | ||||
|     }, | ||||
|     canScaleDown() { | ||||
|       return this.scale > 1 | ||||
|     }, | ||||
|     userMediaProgress() { | ||||
|       if (!this.libraryItemId) return | ||||
|       return this.$store.getters['user/getUserMediaProgress'](this.libraryItemId) | ||||
| @ -76,6 +97,12 @@ export default { | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     zoomIn() { | ||||
|       this.scale += 0.1 | ||||
|     }, | ||||
|     zoomOut() { | ||||
|       this.scale -= 0.1 | ||||
|     }, | ||||
|     updateProgress() { | ||||
|       if (!this.numPages) { | ||||
|         console.error('Num pages not loaded') | ||||
| @ -113,8 +140,19 @@ export default { | ||||
|     }, | ||||
|     error(err) { | ||||
|       console.error(err) | ||||
|     }, | ||||
|     resize() { | ||||
|       this.windowWidth = window.innerWidth | ||||
|       this.windowHeight = window.innerHeight | ||||
|     } | ||||
|   }, | ||||
|   mounted() {} | ||||
|   mounted() { | ||||
|     this.windowWidth = window.innerWidth | ||||
|     this.windowHeight = window.innerHeight | ||||
|     window.addEventListener('resize', this.resize) | ||||
|   }, | ||||
|   beforeDestroy() { | ||||
|     window.removeEventListener('resize', this.resize) | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| @ -1,5 +1,5 @@ | ||||
| <template> | ||||
|   <div v-if="show" class="w-screen h-screen fixed top-0 left-0 z-60 bg-primary text-white"> | ||||
|   <div v-if="show" id="reader" class="absolute top-0 left-0 w-full z-60 bg-primary text-white" :class="{ 'reader-player-open': !!streamLibraryItem }"> | ||||
|     <div class="absolute top-4 left-4 z-20"> | ||||
|       <span v-if="hasToC && !tocOpen" ref="tocButton" class="material-icons cursor-pointer text-2xl" @click="toggleToC">menu</span> | ||||
|     </div> | ||||
| @ -17,7 +17,7 @@ | ||||
|       <span class="material-icons cursor-pointer text-2xl" @click="close">close</span> | ||||
|     </div> | ||||
| 
 | ||||
|     <component v-if="componentName" ref="readerComponent" :is="componentName" :url="ebookUrl" :library-item="selectedLibraryItem" /> | ||||
|     <component v-if="componentName" ref="readerComponent" :is="componentName" :url="ebookUrl" :library-item="selectedLibraryItem" :player-open="!!streamLibraryItem" /> | ||||
| 
 | ||||
|     <!-- TOC side nav --> | ||||
|     <div v-if="tocOpen" class="w-full h-full fixed inset-0 bg-black/20 z-20" @click.stop.prevent="toggleToC"></div> | ||||
| @ -72,6 +72,9 @@ export default { | ||||
|       else if (this.ebookType === 'comic') return 'readers-comic-reader' | ||||
|       return null | ||||
|     }, | ||||
|     streamLibraryItem() { | ||||
|       return this.$store.state.streamLibraryItem | ||||
|     }, | ||||
|     hasToC() { | ||||
|       return this.isEpub | ||||
|     }, | ||||
| @ -191,11 +194,19 @@ export default { | ||||
| </script> | ||||
| 
 | ||||
| <style> | ||||
| .ebook-viewer { | ||||
|   height: calc(100% - 96px); | ||||
| } | ||||
| .tocContent { | ||||
|   height: calc(100% - 36px); | ||||
|   overflow-y: auto; | ||||
| } | ||||
| #reader { | ||||
|   height: 100%; | ||||
| } | ||||
| #reader.reader-player-open { | ||||
|   height: calc(100% - 164px); | ||||
| } | ||||
| @media (max-height: 400px) { | ||||
|   #reader.reader-player-open { | ||||
|     height: 100%; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @ -35,7 +35,7 @@ export const getters = { | ||||
|     return state.serverSettings[key] | ||||
|   }, | ||||
|   getLibraryItemIdStreaming: state => { | ||||
|     return state.streamLibraryItem ? state.streamLibraryItem.id : null | ||||
|     return state.streamLibraryItem?.id || null | ||||
|   }, | ||||
|   getIsStreamingFromDifferentLibrary: (state, getters, rootState) => { | ||||
|     if (!state.streamLibraryItem) return false | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user