Initial commit: Harheimer TC Website
- Vue 3 + Nuxt 3 Framework - Tailwind CSS Styling - Responsive Design mit schwarz-roten Vereinsfarben - Dynamische Galerie mit Lightbox - Event-Management über CSV-Dateien - Mannschaftsübersicht mit dynamischen Seiten - SMTP-Kontaktformular - Google Maps Integration - Mobile-optimierte Navigation mit Submenus - Trainer-Übersicht - Vereinsmeisterschaften, Spielsysteme, TT-Regeln - Impressum mit Datenschutzerklärung
This commit is contained in:
106
components/Gallery.vue
Normal file
106
components/Gallery.vue
Normal file
@@ -0,0 +1,106 @@
|
||||
<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
|
||||
@click.stop="closeLightbox"
|
||||
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"
|
||||
>
|
||||
<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>
|
||||
|
||||
Reference in New Issue
Block a user