aboutsummaryrefslogtreecommitdiff
path: root/viewer/src/views/item_handlers/async/AsyncEpubViewer.vue
diff options
context:
space:
mode:
Diffstat (limited to 'viewer/src/views/item_handlers/async/AsyncEpubViewer.vue')
-rw-r--r--viewer/src/views/item_handlers/async/AsyncEpubViewer.vue149
1 files changed, 149 insertions, 0 deletions
diff --git a/viewer/src/views/item_handlers/async/AsyncEpubViewer.vue b/viewer/src/views/item_handlers/async/AsyncEpubViewer.vue
new file mode 100644
index 0000000..712a844
--- /dev/null
+++ b/viewer/src/views/item_handlers/async/AsyncEpubViewer.vue
@@ -0,0 +1,149 @@
1<!--
2-- ldgallery - A static generator which turns a collection of tagged
3-- pictures into a searchable web gallery.
4--
5-- Copyright (C) 2022 Pacien TRAN-GIRARD
6--
7-- This program is free software: you can redistribute it and/or modify
8-- it under the terms of the GNU Affero General Public License as
9-- published by the Free Software Foundation, either version 3 of the
10-- License, or (at your option) any later version.
11--
12-- This program is distributed in the hope that it will be useful,
13-- but WITHOUT ANY WARRANTY; without even the implied warranty of
14-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15-- GNU Affero General Public License for more details.
16--
17-- You should have received a copy of the GNU Affero General Public License
18-- along with this program. If not, see <https://www.gnu.org/licenses/>.
19-->
20
21<template>
22 <div :class="$style.container">
23 <div
24 ref="view"
25 :class="$style.epubView"
26 class="scrollbar"
27 />
28
29 <ul
30 v-if="prevSection || nextSection"
31 :class="$style.navBar"
32 >
33 <li>
34 <a
35 v-if="prevSection"
36 @click.prevent="goToPrevSection"
37 >« {{ prevSectionLabel }}</a>
38 </li>
39
40 <li>
41 {{ currSectionLabel }}
42 </li>
43
44 <li>
45 <a
46 v-if="nextSection"
47 @click.prevent="goToNextSection"
48 >{{ nextSectionLabel }} »</a>
49 </li>
50 </ul>
51 </div>
52</template>
53
54<script setup lang="ts">
55
56import { EPUBItem } from '@/@types/gallery';
57import { useItemResource } from '@/services/ui/ldItemResourceUrl';
58import ePub from 'epubjs';
59import { SpineItem } from 'epubjs/types/section';
60import { PropType, Ref, ref, toRef, computed, watchEffect } from 'vue';
61import { useI18n } from 'vue-i18n';
62const { t } = useI18n();
63
64const props = defineProps({
65 item: { type: Object as PropType<EPUBItem>, required: true },
66});
67
68const { itemResourceUrl } = useItemResource(toRef(props, 'item'));
69const view = ref<HTMLDivElement>();
70
71const book = computed(() => ePub(itemResourceUrl.value));
72
73const rendition = computed(() => {
74 if (!view.value) return;
75 return book.value.renderTo(view.value, {
76 flow: 'scrolled-doc',
77 width: '100%',
78 fullsize: true,
79 });
80});
81
82const currSection = ref<SpineItem>();
83const prevSection = ref<SpineItem>();
84const nextSection = ref<SpineItem>();
85
86// TODO: reflow on side panel open/close event, like when resizing the window
87
88watchEffect(async() => {
89 if (!rendition.value) return;
90 await rendition.value.display();
91 rendition.value.on('rendered', updateNavigation);
92});
93
94function updateNavigation(currentSection: SpineItem) {
95 currSection.value = currentSection;
96 prevSection.value = currentSection.prev();
97 nextSection.value = currentSection.next();
98}
99
100const currSectionLabel = computed(() => getSectionTitle(currSection) ?? '');
101const prevSectionLabel = computed(() =>
102 getSectionTitle(prevSection) ?? t('epubViewer.previousSection'));
103const nextSectionLabel = computed(() =>
104 getSectionTitle(nextSection) ?? t('epubViewer.nextSection'));
105
106function getSectionTitle(section: Ref<SpineItem | undefined>): string | null {
107 if (!section.value?.href) return null;
108 return book.value?.navigation.get(section.value.href).label;
109}
110
111function goToPrevSection() {
112 rendition.value?.prev();
113}
114
115function goToNextSection() {
116 rendition.value?.next();
117}
118</script>
119
120<style lang="scss" module>
121@import "~@/assets/scss/theme";
122
123.container {
124 display: flex;
125 flex-direction: column;
126 height: 100%;
127}
128
129.epubView {
130 flex: 1;
131 overflow-x: hidden;
132}
133
134.navBar {
135 display: flex;
136 flex-direction: row;
137 list-style-type: none;
138 margin: 0;
139 padding: .75em;
140
141 background-color: $panel-bottom-bgcolor;
142 color: $panel-bottom-txtcolor;
143
144 > * {
145 flex: 1;
146 text-align: center;
147 }
148}
149</style>