diff --git a/projects/frontend/src/views/gallery/gallery-view.vue b/projects/frontend/src/views/gallery/gallery-view.vue index b566d20..f20e075 100644 --- a/projects/frontend/src/views/gallery/gallery-view.vue +++ b/projects/frontend/src/views/gallery/gallery-view.vue @@ -3,8 +3,10 @@ import { computed, onMounted, ref, + useTemplateRef, } from 'vue' import PrimeVueCarousel from 'primevue/carousel' +import PrimeVueImage from 'primevue/image' import { marked } from 'marked' import type { GalleryEntry, @@ -27,6 +29,7 @@ const emits = defineEmits<{ (e: 'loaded'): void }>() +const imageRef = useTemplateRef('image-ref' as any) const ready = ref(false) const resolved = ref({} as GalleryEntry) const currentRoute = getCurrentRoute() @@ -48,9 +51,9 @@ const fields = computed(() => { }) const variants = computed(() => (resolved.value as GalleryEntryWithVariants).variants) const currentSelection = defineModel('currentSelection', { type: Number, default: 0 }) -const currentUrl = computed(() => (resolved.value as GalleryEntryWithVariants).variants[currentSelection.value].url) -const currentAlt = computed(() => (resolved.value as GalleryEntryWithVariants).variants[currentSelection.value].alternativeText) -const currentCaption = computed(() => (resolved.value as GalleryEntryWithVariants).variants[currentSelection.value].caption) +const currentUrl = computed(() => (resolved.value as GalleryEntryWithVariants).variants[currentSelection.value]?.url) +const currentAlt = computed(() => (resolved.value as GalleryEntryWithVariants).variants[currentSelection.value]?.alternativeText) +const currentCaption = computed(() => (resolved.value as GalleryEntryWithVariants).variants[currentSelection.value]?.caption) const carouselResponsiveOptions = [ { breakpoint: '800px', @@ -60,7 +63,29 @@ const carouselResponsiveOptions = [ ] const onVariantSelected = (event: Event, id: number) => { - currentSelection.value = id + if (id === currentSelection.value) { + return + } + + // prevent resizing from image swap by storing the previous width/height + if (!!imageRef.value) { + imageRef.value.style.width = `${imageRef.value.clientWidth}px` + imageRef.value.style.height = `${imageRef.value.clientHeight}px` + } + + // remove the image for a frame so that it won't get stuck on the old one while the new one loads + currentSelection.value = -1 + requestAnimationFrame(() => { + currentSelection.value = id + + // allow a second for the image to load before unsetting the width/height + setTimeout(() => { + if (!!imageRef.value) { + imageRef.value.style.width = `unset` + imageRef.value.style.height = `unset` + } + }, 1000) + }) } onMounted(async () => { @@ -84,11 +109,15 @@ onMounted(async () => { v-if='ready' ) .view-outlet - img( - :src='currentUrl' - :title='currentCaption || currentAlt || description' - :alt='currentAlt || currentCaption || description' + .image-wrapper( + ref='image-ref' ) + PrimeVueImage( + :src='currentUrl' + :title='currentCaption || currentAlt || description' + :alt='currentAlt || currentCaption || description' + preview + ) PrimeVueCarousel( :value='variants' :numVisible='5' @@ -122,5 +151,8 @@ onMounted(async () => { diff --git a/projects/frontend/src/views/shared/media-list.vue b/projects/frontend/src/views/shared/media-list.vue index f4c89fd..1bbb979 100644 --- a/projects/frontend/src/views/shared/media-list.vue +++ b/projects/frontend/src/views/shared/media-list.vue @@ -101,7 +101,7 @@ onMounted(async () => { :class='[template]' ) Transition - .navigation( + .list-controls( v-if='ready' ) .input.labeled-checkbox(