aboutsummaryrefslogtreecommitdiff
path: root/viewer/src/views/item_handlers/PictureViewer.vue
diff options
context:
space:
mode:
Diffstat (limited to 'viewer/src/views/item_handlers/PictureViewer.vue')
-rw-r--r--viewer/src/views/item_handlers/PictureViewer.vue129
1 files changed, 129 insertions, 0 deletions
diff --git a/viewer/src/views/item_handlers/PictureViewer.vue b/viewer/src/views/item_handlers/PictureViewer.vue
new file mode 100644
index 0000000..10055fd
--- /dev/null
+++ b/viewer/src/views/item_handlers/PictureViewer.vue
@@ -0,0 +1,129 @@
1<!-- ldgallery - A static generator which turns a collection of tagged
2-- pictures into a searchable web gallery.
3--
4-- Copyright (C) 2019-2022 Guillaume FOUET
5--
6-- This program is free software: you can redistribute it and/or modify
7-- it under the terms of the GNU Affero General Public License as
8-- published by the Free Software Foundation, either version 3 of the
9-- License, or (at your option) any later version.
10--
11-- This program is distributed in the hope that it will be useful,
12-- but WITHOUT ANY WARRANTY; without even the implied warranty of
13-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14-- GNU Affero General Public License for more details.
15--
16-- You should have received a copy of the GNU Affero General Public License
17-- along with this program. If not, see <https://www.gnu.org/licenses/>.
18-->
19
20<template>
21 <div
22 ref="containerElement"
23 v-dragscroll
24 class="scrollbar"
25 :class="$style.pictureContainer"
26 @dblclick="uiStore.toggleFullscreen()"
27 >
28 <img
29 v-if="!error"
30 ref="imageElement"
31 :src="itemResourceUrl"
32 :class="[$style.pictureElement, $style.slowLoading]"
33 :style="imageStyle"
34 @load="clearSlowLoading"
35 @error="onError"
36 >
37 <LdLoading v-if="loader" />
38 </div>
39</template>
40
41<script setup lang="ts">
42import { PictureItem } from '@/@types/gallery';
43import LdLoading from '@/components/LdLoading.vue';
44import { useItemResource } from '@/services/ui/ldItemResourceUrl';
45import { useLdZoom } from '@/services/ui/ldZoom';
46import { useUiStore } from '@/store/uiStore';
47import { unrefElement, VueInstance } from '@vueuse/core';
48import { createToast } from 'mosha-vue-toastify';
49import { CSSProperties, onMounted, onUnmounted, PropType, ref } from 'vue';
50import { useI18n } from 'vue-i18n';
51
52const props = defineProps({
53 item: { type: Object as PropType<PictureItem>, required: true },
54});
55
56const { t } = useI18n();
57const uiStore = useUiStore();
58
59const imageStyle = ref<CSSProperties>({});
60const error = ref(false);
61const loader = ref(false);
62
63const containerElement = ref<HTMLDivElement>();
64const imageElement = ref<VueInstance>();
65
66const { itemResourceUrl, thumbnailResourceUrl } = useItemResource(props.item);
67
68onMounted(() => {
69 generateSlowLoadingStyle();
70 if (!containerElement.value) return;
71 useLdZoom(
72 imageStyle,
73 containerElement.value,
74 unrefElement(imageElement) as HTMLImageElement,
75 props.item.properties,
76 );
77});
78
79onUnmounted(() => {
80 clearSlowLoading();
81});
82
83function clearSlowLoading() {
84 imageStyle.value.backgroundImage = undefined;
85 loader.value = false;
86}
87
88function generateSlowLoadingStyle() {
89 clearSlowLoading();
90 loader.value = true;
91 if (thumbnailResourceUrl.value) {
92 imageStyle.value.backgroundImage = `url('${thumbnailResourceUrl.value}')`;
93 }
94}
95
96function onError() {
97 clearSlowLoading();
98 error.value = true;
99 createToast(t('gallery.resource-loading-error'), {
100 type: 'danger',
101 position: 'top-center',
102 timeout: 10000,
103 showIcon: true,
104 });
105}
106</script>
107
108<style lang="scss" module>
109@import "~@/assets/scss/theme";
110
111.pictureContainer {
112 height: 100%;
113}
114
115.pictureElement {
116 max-width: unset;
117 max-height: unset;
118 cursor: grab;
119}
120
121.slowLoading {
122 background-repeat: no-repeat;
123 background-position: center;
124 background-size: contain;
125 background-color: $content-bgcolor;
126 background-blend-mode: soft-light;
127 opacity: 1 !important;
128}
129</style>