mirror of
https://github.com/advplyr/audiobookshelf-app.git
synced 2025-06-24 14:18:50 +02:00
Fix ereader padding and swiping
This commit is contained in:
parent
39fbb0902e
commit
bf62b82037
8 changed files with 80 additions and 74 deletions
|
@ -1,11 +1,11 @@
|
|||
<template>
|
||||
<div id="comic-reader" class="w-full h-full">
|
||||
<div v-show="showPageMenu" v-click-outside="clickOutside" class="pagemenu absolute right-20 rounded-md overflow-y-auto bg-bg shadow-lg z-20 border border-gray-400 w-52" style="top: 72px">
|
||||
<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)">
|
||||
<div id="comic-reader" class="w-full h-full relative">
|
||||
<div v-show="showPageMenu" v-click-outside="clickOutsideObj" class="pagemenu absolute top-12 right-16 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.stop="setPage(index)">
|
||||
<p class="text-sm truncate">{{ file }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="showInfoMenu" v-click-outside="clickOutside" class="pagemenu absolute top-20 right-0 rounded-md overflow-y-auto bg-bg shadow-lg z-20 border border-gray-400 w-full" style="top: 72px">
|
||||
<div v-show="showInfoMenu" v-click-outside="clickedOutsideInfoMenu" class="pagemenu absolute top-12 right-0 rounded-md overflow-y-auto bg-bg shadow-lg z-20 border border-gray-400 w-full" @click.stop.prevent>
|
||||
<div v-for="key in comicMetadataKeys" :key="key" class="w-full px-2 py-1">
|
||||
<p class="text-xs">
|
||||
<strong>{{ key }}</strong>
|
||||
|
@ -14,13 +14,13 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="comicMetadata" class="absolute top-8 right-36 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 right-3 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="clickShowInfoMenu">
|
||||
<span class="material-icons text-lg">more</span>
|
||||
</div>
|
||||
<div class="absolute top-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" style="right: 92px" @mousedown.prevent @click.stop.prevent="showPageMenu = !showPageMenu">
|
||||
<div class="absolute top-0 right-16 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 @mouseup.prevent @click.stop.prevent="clickShowPageMenu">
|
||||
<span class="material-icons text-lg">menu</span>
|
||||
</div>
|
||||
<div class="absolute top-8 right-4 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 left-3 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" @click.stop>
|
||||
<p class="font-mono">{{ page + 1 }} / {{ numPages }}</p>
|
||||
</div>
|
||||
|
||||
|
@ -61,7 +61,12 @@ export default {
|
|||
showInfoMenu: false,
|
||||
loadTimeout: null,
|
||||
loadedFirstPage: false,
|
||||
comicMetadata: null
|
||||
comicMetadata: null,
|
||||
clickOutsideObj: {
|
||||
handler: this.clickedOutside,
|
||||
events: ['mousedown'],
|
||||
isActive: true
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
@ -84,9 +89,19 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
clickOutside() {
|
||||
if (this.showPageMenu) this.showPageMenu = false
|
||||
if (this.showInfoMenu) this.showInfoMenu = false
|
||||
clickShowInfoMenu() {
|
||||
this.showInfoMenu = !this.showInfoMenu
|
||||
this.showPageMenu = false
|
||||
},
|
||||
clickShowPageMenu() {
|
||||
this.showPageMenu = !this.showPageMenu
|
||||
this.showInfoMenu = false
|
||||
},
|
||||
clickedOutside() {
|
||||
this.showPageMenu = false
|
||||
},
|
||||
clickedOutsideInfoMenu() {
|
||||
this.showInfoMenu = false
|
||||
},
|
||||
next() {
|
||||
if (!this.canGoNext) return
|
||||
|
@ -100,7 +115,8 @@ export default {
|
|||
if (index < 0 || index > this.numPages - 1) {
|
||||
return
|
||||
}
|
||||
var filename = this.pages[index]
|
||||
this.showPageMenu = false
|
||||
const filename = this.pages[index]
|
||||
this.page = index
|
||||
return this.extractFile(filename)
|
||||
},
|
||||
|
@ -235,8 +251,16 @@ export default {
|
|||
|
||||
<style scoped>
|
||||
#comic-reader {
|
||||
height: calc(100% - 32px);
|
||||
height: calc(100% - 36px);
|
||||
max-height: calc(100% - 36px);
|
||||
padding-top: 36px;
|
||||
}
|
||||
.reader-player-open #comic-reader {
|
||||
height: calc(100% - 156px);
|
||||
max-height: calc(100% - 156px);
|
||||
padding-top: 36px;
|
||||
}
|
||||
|
||||
.pagemenu {
|
||||
max-height: calc(100% - 80px);
|
||||
}
|
||||
|
|
|
@ -140,13 +140,13 @@ export default {
|
|||
|
||||
<style>
|
||||
#epub-frame {
|
||||
height: calc(100% - 32px);
|
||||
max-height: calc(100% - 32px);
|
||||
height: calc(100% - 52px);
|
||||
max-height: calc(100% - 52px);
|
||||
overflow: hidden;
|
||||
}
|
||||
.reader-player-open #epub-frame {
|
||||
height: calc(100% - 132px);
|
||||
max-height: calc(100% - 132px);
|
||||
height: calc(100% - 152px);
|
||||
max-height: calc(100% - 152px);
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
|
@ -1,9 +1,9 @@
|
|||
<template>
|
||||
<div class="mobi-ebook-viewer w-full">
|
||||
<div class="mobi-ebook-viewer w-full relative">
|
||||
<div class="absolute overflow-hidden left-0 right-0 w-full max-w-full m-auto z-10 border border-black border-opacity-20 shadow-md bg-white">
|
||||
<iframe title="html-viewer" class="w-full overflow-hidden"> Loading </iframe>
|
||||
</div>
|
||||
<div class="fixed bottom-0 left-0 h-8 w-full bg-bg px-2 flex items-center z-20" :style="{ bottom: playerLibraryItemId ? '100px' : '0px' }">
|
||||
<div class="fixed bottom-0 left-0 h-8 w-full bg-bg px-2 flex items-center z-20" :style="{ bottom: playerLibraryItemId ? '120px' : '0px' }">
|
||||
<p class="text-xs">mobi</p>
|
||||
<div class="flex-grow" />
|
||||
</div>
|
||||
|
@ -25,9 +25,6 @@ export default {
|
|||
computed: {
|
||||
playerLibraryItemId() {
|
||||
return this.$store.state.playerLibraryItemId
|
||||
},
|
||||
readerHeightOffset() {
|
||||
return this.playerLibraryItemId ? 164 : 64
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
@ -122,13 +119,15 @@ export default {
|
|||
|
||||
<style>
|
||||
.mobi-ebook-viewer {
|
||||
height: calc(100% - 32px);
|
||||
max-height: calc(100% - 32px);
|
||||
overflow: hidden;
|
||||
height: calc(100% - 52px);
|
||||
max-height: calc(100% - 52px);
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.reader-player-open .mobi-ebook-viewer {
|
||||
height: calc(100% - 132px);
|
||||
max-height: calc(100% - 132px);
|
||||
overflow: hidden;
|
||||
height: calc(100% - 152px);
|
||||
max-height: calc(100% - 152px);
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="w-full h-full pt-20 relative">
|
||||
<div class="w-full h-full pt-6 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 class="material-icons text-5xl text-white cursor-pointer text-opacity-30 hover:text-opacity-90">arrow_back_ios</span>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div v-if="show" class="absolute top-0 left-0 w-full h-full bg-bg z-40 pt-8" :class="{ 'reader-player-open': !!playerLibraryItemId }">
|
||||
<div class="h-8 w-full bg-primary flex items-center px-2 fixed top-0 left-0 z-30 box-shadow-sm">
|
||||
<div v-if="show" class="absolute top-0 left-0 w-full h-full bg-bg z-40 pt-14" :class="{ 'reader-player-open': !!playerLibraryItemId }">
|
||||
<div class="h-14 pt-6 w-full bg-primary flex items-center px-2 fixed top-0 left-0 z-30 box-shadow-sm">
|
||||
<p class="w-5/6 truncate">{{ title }}</p>
|
||||
<div class="flex-grow" />
|
||||
<span class="material-icons text-xl text-white" @click.stop="show = false">close</span>
|
||||
|
@ -132,7 +132,9 @@ export default {
|
|||
|
||||
const touchDistanceX = Math.abs(this.touchendX - this.touchstartX)
|
||||
const touchDistanceY = Math.abs(this.touchendY - this.touchstartY)
|
||||
if (touchDistanceX < 100 || touchDistanceY > touchDistanceX) return
|
||||
if (touchDistanceX < 60 || touchDistanceY > touchDistanceX) {
|
||||
return
|
||||
}
|
||||
|
||||
if (this.touchendX < this.touchstartX) {
|
||||
console.log('swiped left')
|
||||
|
@ -144,8 +146,8 @@ export default {
|
|||
}
|
||||
},
|
||||
touchstart(e) {
|
||||
this.touchstartX = e.changedTouches[0].screenX
|
||||
this.touchstartY = e.changedTouches[0].screenY
|
||||
this.touchstartX = e.touches[0].screenX
|
||||
this.touchstartY = e.touches[0].screenY
|
||||
this.touchstartTime = Date.now()
|
||||
},
|
||||
touchend(e) {
|
||||
|
|
14
package-lock.json
generated
14
package-lock.json
generated
|
@ -26,6 +26,7 @@
|
|||
"libarchive.js": "^1.3.0",
|
||||
"nuxt": "^2.15.7",
|
||||
"socket.io-client": "^4.1.3",
|
||||
"v-click-outside": "^3.2.0",
|
||||
"vue-pdf": "^4.2.0",
|
||||
"vue-toastification": "^1.7.11",
|
||||
"vuedraggable": "^2.24.3"
|
||||
|
@ -17192,6 +17193,14 @@
|
|||
"node": ">= 0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/v-click-outside": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/v-click-outside/-/v-click-outside-3.2.0.tgz",
|
||||
"integrity": "sha512-QD0bDy38SHJXQBjgnllmkI/rbdiwmq9RC+/+pvrFjYJKTn8dtp7Penf9q1lLBta280fYG2q53mgLhQ+3l3z74w==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/vary": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
|
@ -31992,6 +32001,11 @@
|
|||
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
||||
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
|
||||
},
|
||||
"v-click-outside": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/v-click-outside/-/v-click-outside-3.2.0.tgz",
|
||||
"integrity": "sha512-QD0bDy38SHJXQBjgnllmkI/rbdiwmq9RC+/+pvrFjYJKTn8dtp7Penf9q1lLBta280fYG2q53mgLhQ+3l3z74w=="
|
||||
},
|
||||
"vary": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
"libarchive.js": "^1.3.0",
|
||||
"nuxt": "^2.15.7",
|
||||
"socket.io-client": "^4.1.3",
|
||||
"v-click-outside": "^3.2.0",
|
||||
"vue-pdf": "^4.2.0",
|
||||
"vue-toastification": "^1.7.11",
|
||||
"vuedraggable": "^2.24.3"
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import Vue from 'vue'
|
||||
import vClickOutside from 'v-click-outside'
|
||||
import { App } from '@capacitor/app'
|
||||
import { Dialog } from '@capacitor/dialog'
|
||||
import { StatusBar, Style } from '@capacitor/status-bar';
|
||||
import { formatDistance, format, addDays, isDate } from 'date-fns'
|
||||
import { Capacitor } from '@capacitor/core';
|
||||
import { Capacitor } from '@capacitor/core'
|
||||
|
||||
Vue.directive('click-outside', vClickOutside.directive)
|
||||
|
||||
if (Capacitor.getPlatform() != 'web') {
|
||||
const setStatusBarStyleDark = async () => {
|
||||
|
@ -150,43 +153,6 @@ Vue.prototype.$sanitizeFilename = (input, colonReplacement = ' - ') => {
|
|||
return sanitized
|
||||
}
|
||||
|
||||
function isClickedOutsideEl(clickEvent, elToCheckOutside, ignoreSelectors = [], ignoreElems = []) {
|
||||
const isDOMElement = (element) => {
|
||||
return element instanceof Element || element instanceof HTMLDocument
|
||||
}
|
||||
|
||||
const clickedEl = clickEvent.srcElement
|
||||
const didClickOnIgnoredEl = ignoreElems.filter((el) => el).some((element) => element.contains(clickedEl) || element.isEqualNode(clickedEl))
|
||||
const didClickOnIgnoredSelector = ignoreSelectors.length ? ignoreSelectors.map((selector) => clickedEl.closest(selector)).reduce((curr, accumulator) => curr && accumulator, true) : false
|
||||
|
||||
if (isDOMElement(elToCheckOutside) && !elToCheckOutside.contains(clickedEl) && !didClickOnIgnoredEl && !didClickOnIgnoredSelector) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
Vue.directive('click-outside', {
|
||||
bind: function (el, binding, vnode) {
|
||||
let vm = vnode.context;
|
||||
let callback = binding.value;
|
||||
if (typeof callback !== 'function') {
|
||||
console.error('Invalid callback', binding)
|
||||
return
|
||||
}
|
||||
el['__click_outside__'] = (ev) => {
|
||||
if (isClickedOutsideEl(ev, el)) {
|
||||
callback.call(vm, ev)
|
||||
}
|
||||
}
|
||||
document.addEventListener('click', el['__click_outside__'], false)
|
||||
},
|
||||
unbind: function (el, binding, vnode) {
|
||||
document.removeEventListener('click', el['__click_outside__'], false)
|
||||
delete el['__click_outside__']
|
||||
}
|
||||
})
|
||||
|
||||
function xmlToJson(xml) {
|
||||
const json = {};
|
||||
for (const res of xml.matchAll(/(?:<(\w*)(?:\s[^>]*)*>)((?:(?!<\1).)*)(?:<\/\1>)|<(\w*)(?:\s*)*\/>/gm)) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue