Fix ereader padding and swiping

This commit is contained in:
advplyr 2023-03-06 10:58:08 -06:00
parent 39fbb0902e
commit bf62b82037
8 changed files with 80 additions and 74 deletions

View file

@ -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);
}

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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
View file

@ -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",

View file

@ -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"

View file

@ -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)) {