From 00510820a2794efcadbc83f7f8b54318fe198ecb Mon Sep 17 00:00:00 2001
From: Zéro~Informatique
Date: Tue, 26 Jul 2022 08:44:34 +0200
Subject: viewer: migrate to vue 3, general refactoring and cleanup

Non-exhaustive list of fixes and improvements done at the same time:

- html default background to grey (avoids white flash during init)
- unified links behavior
- added more theme variables
- removed the flex-expand transition (it wasn't working) and replaced it
  with a slide
- fixed LdLoading not centered on the content
- title on removable tags
- fixed an issue with encoded URI from vue-router
- unified Item resource URLs
- removed the iframe for PlainTextViewer (it wasn't working properly)
  and replaced it with a pre
- fixed clear and search buttons tabindex
- fixed the information panel bumping up during the fade animation of
  tag's dropdown
- fixed some focus outlines not appearing correctly
- moved CSS variables to the :root context
- Code cleaning

GitHub: closes #217
GitHub: closes #300
GitHub: closes #297
GitHub: closes #105
GitHub: closes #267
GitHub: closes #275
GitHub: closes #228
GitHub: closes #215
GitHub: closes #112
---
 viewer/src/views/item_handlers/PictureViewer.vue | 129 +++++++++++++++++++++++
 1 file changed, 129 insertions(+)
 create mode 100644 viewer/src/views/item_handlers/PictureViewer.vue

(limited to 'viewer/src/views/item_handlers/PictureViewer.vue')

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 @@
+<!-- ldgallery - A static generator which turns a collection of tagged
+--             pictures into a searchable web gallery.
+--
+-- Copyright (C) 2019-2022  Guillaume FOUET
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU Affero General Public License as
+-- published by the Free Software Foundation, either version 3 of the
+-- License, or (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU Affero General Public License for more details.
+--
+-- You should have received a copy of the GNU Affero General Public License
+-- along with this program.  If not, see <https://www.gnu.org/licenses/>.
+-->
+
+<template>
+  <div
+    ref="containerElement"
+    v-dragscroll
+    class="scrollbar"
+    :class="$style.pictureContainer"
+    @dblclick="uiStore.toggleFullscreen()"
+  >
+    <img
+      v-if="!error"
+      ref="imageElement"
+      :src="itemResourceUrl"
+      :class="[$style.pictureElement, $style.slowLoading]"
+      :style="imageStyle"
+      @load="clearSlowLoading"
+      @error="onError"
+    >
+    <LdLoading v-if="loader" />
+  </div>
+</template>
+
+<script setup lang="ts">
+import { PictureItem } from '@/@types/gallery';
+import LdLoading from '@/components/LdLoading.vue';
+import { useItemResource } from '@/services/ui/ldItemResourceUrl';
+import { useLdZoom } from '@/services/ui/ldZoom';
+import { useUiStore } from '@/store/uiStore';
+import { unrefElement, VueInstance } from '@vueuse/core';
+import { createToast } from 'mosha-vue-toastify';
+import { CSSProperties, onMounted, onUnmounted, PropType, ref } from 'vue';
+import { useI18n } from 'vue-i18n';
+
+const props = defineProps({
+  item: { type: Object as PropType<PictureItem>, required: true },
+});
+
+const { t } = useI18n();
+const uiStore = useUiStore();
+
+const imageStyle = ref<CSSProperties>({});
+const error = ref(false);
+const loader = ref(false);
+
+const containerElement = ref<HTMLDivElement>();
+const imageElement = ref<VueInstance>();
+
+const { itemResourceUrl, thumbnailResourceUrl } = useItemResource(props.item);
+
+onMounted(() => {
+  generateSlowLoadingStyle();
+  if (!containerElement.value) return;
+  useLdZoom(
+    imageStyle,
+    containerElement.value,
+    unrefElement(imageElement) as HTMLImageElement,
+    props.item.properties,
+  );
+});
+
+onUnmounted(() => {
+  clearSlowLoading();
+});
+
+function clearSlowLoading() {
+  imageStyle.value.backgroundImage = undefined;
+  loader.value = false;
+}
+
+function generateSlowLoadingStyle() {
+  clearSlowLoading();
+  loader.value = true;
+  if (thumbnailResourceUrl.value) {
+    imageStyle.value.backgroundImage = `url('${thumbnailResourceUrl.value}')`;
+  }
+}
+
+function onError() {
+  clearSlowLoading();
+  error.value = true;
+  createToast(t('gallery.resource-loading-error'), {
+    type: 'danger',
+    position: 'top-center',
+    timeout: 10000,
+    showIcon: true,
+  });
+}
+</script>
+
+<style lang="scss" module>
+@import "~@/assets/scss/theme";
+
+.pictureContainer {
+  height: 100%;
+}
+
+.pictureElement {
+  max-width: unset;
+  max-height: unset;
+  cursor: grab;
+}
+
+.slowLoading {
+  background-repeat: no-repeat;
+  background-position: center;
+  background-size: contain;
+  background-color: $content-bgcolor;
+  background-blend-mode: soft-light;
+  opacity: 1 !important;
+}
+</style>
-- 
cgit v1.2.3

