Update modal and image viewer with simpler carousel

This commit is contained in:
Michael Winter 2026-03-08 11:40:37 +01:00
parent ffe6bd4409
commit 5347bf0023
3 changed files with 43 additions and 33 deletions

View file

@ -1,34 +1,16 @@
<template>
<div class="flex flex-col items-center justify-center h-full">
<div class="relative w-full flex-1 flex items-center justify-center min-h-0 p-4">
<!-- Previous button -->
<button
v-if="gallery.length > 1"
@click="prev"
class="absolute left-2 z-10 p-2 bg-gray-600 rounded-full text-white hover:bg-gray-700"
>
<Icon name="mdi:chevron-left" class="w-6 h-6" />
</button>
<div class="flex flex-col h-full">
<div class="relative h-[60vh] w-full flex items-center justify-center">
<!-- Image -->
<NuxtImg
v-if="gallery[currentIndex]"
:src="'/' + bucket + '/' + gallery[currentIndex].image"
class="max-w-full max-h-[60vh] object-contain"
class="max-w-full max-h-full object-contain"
/>
<!-- Next button -->
<button
v-if="gallery.length > 1"
@click="next"
class="absolute right-2 z-10 p-2 bg-gray-600 rounded-full text-white hover:bg-gray-700"
>
<Icon name="mdi:chevron-right" class="w-6 h-6" />
</button>
</div>
<!-- Dots indicator -->
<div v-if="gallery.length > 1" class="flex gap-2 py-2">
<div v-if="gallery.length > 1" class="flex gap-2 py-2 justify-center">
<button
v-for="(img, index) in gallery"
:key="index"
@ -52,11 +34,7 @@ const props = defineProps({
const currentIndex = ref(props.initialIndex)
const next = () => {
currentIndex.value = (currentIndex.value + 1) % props.gallery.length
}
const prev = () => {
currentIndex.value = (currentIndex.value - 1 + props.gallery.length) % props.gallery.length
}
watch(() => props.initialIndex, (newVal) => {
currentIndex.value = newVal
})
</script>

View file

@ -95,7 +95,7 @@ provide('modal', api)
leave-to="opacity-0 scale-95"
>
<DialogPanel
class="w-full transform overflow-hidden bg-white text-left align-middle shadow-xl transition-all"
class="w-full transform overflow-hidden bg-white text-left align-middle shadow-xl transition-all py-4"
:class="{
'h-screen': fullscreen,
'max-w-[min(85vw,1200px)] rounded-lg': !fullscreen,

View file

@ -68,7 +68,17 @@
</footer>
<Modal v-model="modalStore.isOpen" :maxHeight="modalStore.type === 'image' && modalStore.soundcloudUrl ? 'calc(85vh + 60px)' : '85vh'">
<div class="flex flex-col h-full overflow-hidden">
<div class="flex flex-col h-full overflow-hidden relative">
<!-- Navigation buttons for images - fixed to modal -->
<template v-if="modalStore.type === 'image' && modalStore.gallery && modalStore.gallery.length > 1">
<button @click="prevImage" class="absolute left-2 top-1/2 -translate-y-1/2 z-20 text-gray-600 hover:text-gray-900">
<Icon name="mdi:chevron-left" class="w-10 h-10" />
</button>
<button @click="nextImage" class="absolute right-2 top-1/2 -translate-y-1/2 z-20 text-gray-600 hover:text-gray-900">
<Icon name="mdi:chevron-right" class="w-10 h-10" />
</button>
</template>
<div v-if="modalStore.type === 'image'" class="flex-1 flex items-center justify-center min-h-0">
<ImageViewer :bucket="modalStore.bucket" :gallery="modalStore.gallery" :initialIndex="modalStore.initialIndex"></ImageViewer>
</div>
@ -108,7 +118,7 @@
</ClientOnly>
</div>
</div>
<div v-if="modalStore.type === 'pdf' || modalStore.type === 'image' || modalStore.type === 'document'" class="absolute bottom-2 right-2 z-10">
<div v-if="modalStore.type === 'pdf' || modalStore.type === 'image' || modalStore.type === 'document'" class="absolute bottom-0 right-0 p-4 z-10">
<a :href="modalStore.type === 'pdf' ? modalStore.pdfUrl : modalStore.type === 'image' ? '/' + modalStore.bucket + '/' + modalStore.gallery[0]?.image : modalStore.type === 'document' ? modalStore.iframeUrl : undefined" target="_blank" rel="noopener noreferrer" class="p-2 bg-gray-600 rounded-lg inline-flex items-center justify-center pointer-events-auto">
<Icon name="mdi:open-in-new" class="w-5 h-5 text-white" />
</a>
@ -121,11 +131,33 @@
<script setup>
import { useAudioPlayerStore } from "@/stores/AudioPlayerStore"
import { useModalStore } from "@/stores/ModalStore"
import { onMounted, computed } from "vue"
import { onMounted, computed, ref } from "vue"
const audioPlayerStore = useAudioPlayerStore()
const modalStore = useModalStore()
const currentImageIndex = ref(0)
const prevImage = () => {
if (modalStore.gallery && modalStore.gallery.length > 0) {
currentImageIndex.value = (currentImageIndex.value - 1 + modalStore.gallery.length) % modalStore.gallery.length
modalStore.initialIndex = currentImageIndex.value
}
}
const nextImage = () => {
if (modalStore.gallery && modalStore.gallery.length > 0) {
currentImageIndex.value = (currentImageIndex.value + 1) % modalStore.gallery.length
modalStore.initialIndex = currentImageIndex.value
}
}
watch(() => modalStore.isOpen, (isOpen) => {
if (isOpen) {
currentImageIndex.value = modalStore.initialIndex || 0
}
})
const route = useRoute()
const pageTitle = computed(() => {