This repository has been archived on 2020-11-22. You can view files and clone it, but cannot push or open issues/pull-requests.
mangareader/frontend/src/views/Reader.vue

171 lines
4.3 KiB
Vue

<template>
<div class="reader" v-shortkey="{left: ['arrowleft'], right: ['arrowright']}" @shortkey="navigation">
<div class="page-container">
<img ref="currentImage" :style="{ width: getRealPageWidth() }" :src="info.pages[page]" @load="setScroll(); setOrientation()">
<!-- prefetching -->
<img style="display: none;" :src="info.pages[page-1]">
<img style="display: none;" :src="info.pages[page+1]">
</div>
<div class="sidebar" :style="{ display: showSidebar ? '' : 'none' }">
<h3>{{ info.title }}</h3>
<router-link :to="'/series/' + info.series">All Volumes</router-link>
<p>{{ page + 1 }}/{{ info.pages.length }}</p>
<p>
<button :disabled="originalPageWidth" v-on:click="changePageWidth(-5)">-</button>
<span>{{ pageWidth }}</span>
<button :disabled="originalPageWidth" v-on:click="changePageWidth(5)">+</button>
<br/>
<button v-on:click="originalPageWidth = !originalPageWidth">{{ originalPageWidth ? 'fixed width' : '1:1' }}</button>
</p>
<button v-on:click="changeDirection">{{ direction.toUpperCase() }}</button>
<button class="hide" v-on:click="showSidebar = false">Hide</button>
</div>
<div class="sidebar-enabler" :style="{ display: showSidebar ? 'none' : '' }" v-on:click="showSidebar = true"></div>
</div>
</template>
<script>
import API from '@/api-client.js'
export default {
name: 'Reader',
data () {
return {
info: {
pages: []
},
scrollPositions: [],
pageWidth: 60,
originalPageWidth: false,
showSidebar: true,
direction: 'rtl',
orientation: 'vertical'
}
},
computed: {
page: {
get () {
if (this.$route.hash) {
return this.$route.hash.substr(1) - 1
} else {
return 0
}
},
set (value) {
this.$router.push({ hash: '#' + (value + 1) })
}
}
},
mounted () {
API.getVolumeInfo(this.$route.params.id, info => (this.info = info))
},
methods: {
setPage (page) {
// save scroll position
this.scrollPositions[this.page] = window.pageYOffset
// set page
if (page >= 0 && page < this.info.pages.length) {
this.page = page
}
},
setScroll () {
// load saved scroll posotion, if available, reset to 0 otherwise
if (this.scrollPositions[this.page]) {
window.scrollTo(0, this.scrollPositions[this.page])
} else {
window.scrollTo(0, 0)
}
},
navigation (event) {
if ((event.srcKey === 'right' && this.direction === 'ltr') || (event.srcKey === 'left' && this.direction === 'rtl')) {
this.setPage(this.page + 1)
} else if ((event.srcKey === 'left' && this.direction === 'ltr') || (event.srcKey === 'right' && this.direction === 'rtl')) {
this.setPage(this.page - 1)
} else {
throw new Error('cannot nagivate: invalid parameters')
}
},
changePageWidth (change) {
if (this.pageWidth + change > 0 && this.pageWidth + change <= 100) {
this.pageWidth += change
}
},
changeDirection () {
if (this.direction === 'rtl') {
this.direction = 'ltr'
} else if (this.direction === 'ltr') {
this.direction = 'rtl'
} else {
throw new Error('cannot change reading direction: invalid direction currently set')
}
},
setOrientation () {
let image = this.$refs.currentImage
if (image.width < image.height) {
this.orientation = 'vertical'
} else if (image.width > image.height) {
this.orientation = 'horizontal'
} else if (image.width === image.height) {
this.orientation = 'square'
}
},
getRealPageWidth () {
if (this.orientation === 'horizontal') {
return '100%'
}
if (this.originalPageWidth === true) {
return 'auto'
}
return this.pageWidth + '%'
}
}
}
</script>
<style scoped>
.reader {
display: flex;
position: relative;
}
.page-container {
flex-grow: 1;
}
img {
vertical-align: top;
}
.sidebar-enabler {
position: absolute;
top: 0px;
right: 0px;
height: 100%;
width: 250px;
}
.sidebar {
flex: 0 0 250px;
background-color: #eee;
height: 100vh;
position: sticky;
top: 0;
}
button.hide {
bottom: 1em;
right: 1em;
position: absolute;
}
</style>