113 lines
3.5 KiB
Vue
113 lines
3.5 KiB
Vue
<template>
|
|
<section
|
|
v-if="images.length > 0"
|
|
id="gallery"
|
|
class="py-16 sm:py-20 bg-gradient-to-b from-white to-gray-50"
|
|
>
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div class="text-center mb-16">
|
|
<h2 class="text-4xl sm:text-5xl font-display font-bold text-gray-900 mb-4">
|
|
Galerie
|
|
</h2>
|
|
<div class="w-24 h-1 bg-primary-600 mx-auto mb-6" />
|
|
<p class="text-xl text-gray-600 max-w-3xl mx-auto">
|
|
Eindrücke von unserem Verein
|
|
</p>
|
|
</div>
|
|
|
|
<div class="grid sm:grid-cols-4 lg:grid-cols-6 xl:grid-cols-8 gap-2">
|
|
<div
|
|
v-for="image in images"
|
|
:key="image.filename"
|
|
class="group relative w-20 h-20 rounded-md overflow-hidden shadow-sm hover:shadow-lg transition-all duration-300 cursor-pointer"
|
|
@click="openLightbox(image)"
|
|
>
|
|
<img
|
|
:src="`/galerie/${image.filename}`"
|
|
:alt="image.title"
|
|
class="w-full h-full object-cover group-hover:scale-110 transition-transform duration-700"
|
|
>
|
|
<div class="absolute inset-0 bg-gradient-to-t from-black/70 via-black/20 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300 flex items-end">
|
|
<p class="text-white font-semibold text-xs p-1 truncate">
|
|
{{ image.title }}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Lightbox Modal -->
|
|
<div
|
|
v-if="lightboxImage"
|
|
class="fixed inset-0 z-50 bg-black/90 flex items-center justify-center p-4"
|
|
@click="closeLightbox"
|
|
>
|
|
<div class="relative w-full h-full flex items-center justify-center">
|
|
<button
|
|
class="absolute top-4 right-4 z-10 w-10 h-10 bg-white/20 hover:bg-white/30 rounded-full flex items-center justify-center text-white transition-colors"
|
|
@click.stop="closeLightbox"
|
|
>
|
|
<X :size="24" />
|
|
</button>
|
|
<img
|
|
:src="`/galerie/${lightboxImage.filename}`"
|
|
:alt="lightboxImage.title"
|
|
class="max-w-[80vw] max-h-[80vh] object-contain rounded-lg"
|
|
@click.stop
|
|
>
|
|
<div class="absolute bottom-4 left-4 right-4 text-center">
|
|
<p class="text-white font-semibold text-lg bg-black/50 rounded-lg px-4 py-2">
|
|
{{ lightboxImage.title }}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, onMounted } from 'vue'
|
|
import { X } from 'lucide-vue-next'
|
|
|
|
const images = ref([])
|
|
const lightboxImage = ref(null)
|
|
|
|
const loadImages = async () => {
|
|
try {
|
|
const response = await $fetch('/api/galerie')
|
|
images.value = response || []
|
|
} catch (error) {
|
|
console.error('Fehler beim Laden der Galerie-Bilder:', error)
|
|
images.value = []
|
|
}
|
|
}
|
|
|
|
const openLightbox = (image) => {
|
|
lightboxImage.value = image
|
|
document.body.style.overflow = 'hidden' // Verhindert Scrollen im Hintergrund
|
|
}
|
|
|
|
const closeLightbox = () => {
|
|
lightboxImage.value = null
|
|
document.body.style.overflow = 'auto' // Erlaubt wieder Scrollen
|
|
}
|
|
|
|
// ESC-Taste zum Schließen
|
|
const handleKeydown = (event) => {
|
|
if (event.key === 'Escape' && lightboxImage.value) {
|
|
closeLightbox()
|
|
}
|
|
}
|
|
|
|
onMounted(() => {
|
|
loadImages()
|
|
document.addEventListener('keydown', handleKeydown)
|
|
})
|
|
|
|
onUnmounted(() => {
|
|
document.removeEventListener('keydown', handleKeydown)
|
|
document.body.style.overflow = 'auto' // Cleanup
|
|
})
|
|
</script>
|
|
|