Enhance Vereinsmeisterschaften and Vorstand pages with image support for players and board members. Implement lightbox functionality for player images in Vereinsmeisterschaften. Update CSV handling to include image filenames for better data management. Refactor components to utilize PersonCard for board members, improving code readability and maintainability.
This commit is contained in:
@@ -295,6 +295,12 @@
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sm:col-span-2">
|
||||
<ImageUpload
|
||||
v-model="trainer.imageFilename"
|
||||
label="Foto"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -459,6 +465,12 @@
|
||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||
/>
|
||||
</div>
|
||||
<div class="sm:col-span-2">
|
||||
<ImageUpload
|
||||
v-model="position.imageFilename"
|
||||
label="Foto"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -123,9 +123,28 @@
|
||||
<span class="w-8 h-8 bg-primary-600 text-white rounded-full flex items-center justify-center text-sm font-bold">
|
||||
{{ result.platz }}
|
||||
</span>
|
||||
<div>
|
||||
<div class="flex items-center gap-2">
|
||||
<div v-if="result.imageFilename1" class="flex-shrink-0">
|
||||
<img
|
||||
:src="`/api/personen/${result.imageFilename1}?width=32&height=32`"
|
||||
:alt="result.spieler1"
|
||||
class="w-8 h-8 rounded-full object-cover border border-gray-300"
|
||||
loading="lazy"
|
||||
/>
|
||||
</div>
|
||||
<span class="font-medium text-gray-900">{{ result.spieler1 }}</span>
|
||||
<span v-if="result.spieler2" class="text-gray-600"> & {{ result.spieler2 }}</span>
|
||||
<span v-if="result.spieler2" class="text-gray-600 flex items-center gap-2">
|
||||
&
|
||||
<div v-if="result.imageFilename2" class="flex-shrink-0">
|
||||
<img
|
||||
:src="`/api/personen/${result.imageFilename2}?width=32&height=32`"
|
||||
:alt="result.spieler2"
|
||||
class="w-8 h-8 rounded-full object-cover border border-gray-300"
|
||||
loading="lazy"
|
||||
/>
|
||||
</div>
|
||||
{{ result.spieler2 }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex space-x-2">
|
||||
@@ -170,12 +189,15 @@
|
||||
class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4"
|
||||
@click.self="closeModal"
|
||||
>
|
||||
<div class="bg-white rounded-lg max-w-md w-full p-6">
|
||||
<h3 class="text-lg font-semibold text-gray-900 mb-4">
|
||||
{{ editingResult ? 'Ergebnis bearbeiten' : 'Neues Ergebnis hinzufügen' }}
|
||||
</h3>
|
||||
<div class="bg-white rounded-lg max-w-md w-full max-h-[90vh] flex flex-col">
|
||||
<div class="p-6 border-b border-gray-200 flex-shrink-0">
|
||||
<h3 class="text-lg font-semibold text-gray-900">
|
||||
{{ editingResult ? 'Ergebnis bearbeiten' : 'Neues Ergebnis hinzufügen' }}
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<form @submit.prevent="saveResult" class="space-y-4">
|
||||
<div class="overflow-y-auto flex-1 p-6">
|
||||
<form id="result-form" @submit.prevent="saveResult" class="space-y-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Jahr</label>
|
||||
<input
|
||||
@@ -236,6 +258,20 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<ImageUpload
|
||||
v-model="formData.imageFilename1"
|
||||
label="Foto Spieler 1"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-if="formData.kategorie === 'Doppel' || formData.kategorie === 'Mixed'">
|
||||
<ImageUpload
|
||||
v-model="formData.imageFilename2"
|
||||
label="Foto Spieler 2"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Bemerkung (optional)</label>
|
||||
<textarea
|
||||
@@ -245,22 +281,25 @@
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end space-x-3 pt-4">
|
||||
<button
|
||||
type="button"
|
||||
@click="closeModal"
|
||||
class="px-4 py-2 text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors"
|
||||
>
|
||||
Abbrechen
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
class="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors"
|
||||
>
|
||||
{{ editingResult ? 'Aktualisieren' : 'Hinzufügen' }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="p-6 border-t border-gray-200 flex-shrink-0 flex justify-end space-x-3">
|
||||
<button
|
||||
type="button"
|
||||
@click="closeModal"
|
||||
class="px-4 py-2 text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors"
|
||||
>
|
||||
Abbrechen
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
form="result-form"
|
||||
class="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors"
|
||||
>
|
||||
{{ editingResult ? 'Aktualisieren' : 'Hinzufügen' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -330,7 +369,9 @@ const formData = ref({
|
||||
platz: '',
|
||||
spieler1: '',
|
||||
spieler2: '',
|
||||
bemerkung: ''
|
||||
bemerkung: '',
|
||||
imageFilename1: '',
|
||||
imageFilename2: ''
|
||||
})
|
||||
|
||||
const loadResults = async () => {
|
||||
@@ -370,6 +411,7 @@ const loadResults = async () => {
|
||||
}
|
||||
values.push(current.trim())
|
||||
|
||||
// Mindestens 6 Spalten erforderlich (die neuen Bildspalten sind optional)
|
||||
if (values.length < 6) return null
|
||||
|
||||
return {
|
||||
@@ -378,7 +420,9 @@ const loadResults = async () => {
|
||||
platz: values[2].trim(),
|
||||
spieler1: values[3].trim(),
|
||||
spieler2: values[4].trim(),
|
||||
bemerkung: values[5].trim()
|
||||
bemerkung: values[5].trim(),
|
||||
imageFilename1: values[6]?.trim() || '',
|
||||
imageFilename2: values[7]?.trim() || ''
|
||||
}
|
||||
}).filter(result => result !== null)
|
||||
} catch (error) {
|
||||
@@ -445,7 +489,9 @@ const addNewResult = () => {
|
||||
platz: '',
|
||||
spieler1: '',
|
||||
spieler2: '',
|
||||
bemerkung: ''
|
||||
bemerkung: '',
|
||||
imageFilename1: '',
|
||||
imageFilename2: ''
|
||||
}
|
||||
showModal.value = true
|
||||
}
|
||||
@@ -461,7 +507,9 @@ const addResultForYear = (jahr) => {
|
||||
platz: '',
|
||||
spieler1: '',
|
||||
spieler2: '',
|
||||
bemerkung: ''
|
||||
bemerkung: '',
|
||||
imageFilename1: '',
|
||||
imageFilename2: ''
|
||||
}
|
||||
showModal.value = true
|
||||
}
|
||||
@@ -477,7 +525,9 @@ const addResultForKategorie = (jahr, kategorie) => {
|
||||
platz: '',
|
||||
spieler1: '',
|
||||
spieler2: '',
|
||||
bemerkung: ''
|
||||
bemerkung: '',
|
||||
imageFilename1: '',
|
||||
imageFilename2: ''
|
||||
}
|
||||
showModal.value = true
|
||||
}
|
||||
@@ -493,7 +543,9 @@ const editResult = (result, jahr, kategorie, index) => {
|
||||
platz: result.platz,
|
||||
spieler1: result.spieler1,
|
||||
spieler2: result.spieler2,
|
||||
bemerkung: result.bemerkung
|
||||
bemerkung: result.bemerkung,
|
||||
imageFilename1: result.imageFilename1 || '',
|
||||
imageFilename2: result.imageFilename2 || ''
|
||||
}
|
||||
showModal.value = true
|
||||
}
|
||||
@@ -649,7 +701,7 @@ const closeBemerkungModal = () => {
|
||||
const save = async () => {
|
||||
try {
|
||||
// CSV generieren
|
||||
const csvHeader = 'Jahr,Kategorie,Platz,Spieler1,Spieler2,Bemerkung'
|
||||
const csvHeader = 'Jahr,Kategorie,Platz,Spieler1,Spieler2,Bemerkung,imageFilename1,imageFilename2'
|
||||
const csvRows = results.value.map(result => {
|
||||
return [
|
||||
result.jahr,
|
||||
@@ -657,7 +709,9 @@ const save = async () => {
|
||||
result.platz,
|
||||
result.spieler1,
|
||||
result.spieler2,
|
||||
result.bemerkung
|
||||
result.bemerkung,
|
||||
result.imageFilename1 || '',
|
||||
result.imageFilename2 || ''
|
||||
].map(field => `"${field}"`).join(',')
|
||||
})
|
||||
|
||||
|
||||
@@ -16,6 +16,14 @@
|
||||
:key="trainer.id"
|
||||
class="bg-white p-8 rounded-xl shadow-lg"
|
||||
>
|
||||
<div v-if="trainer.imageFilename" class="mb-4 flex justify-center">
|
||||
<img
|
||||
:src="`/api/personen/${trainer.imageFilename}?width=200&height=200`"
|
||||
:alt="trainer.name"
|
||||
class="w-32 h-32 object-cover rounded-full border-4 border-primary-100 shadow-md"
|
||||
loading="lazy"
|
||||
/>
|
||||
</div>
|
||||
<h3 class="text-2xl font-display font-bold text-gray-900 mb-2">{{ trainer.lizenz }}</h3>
|
||||
<p class="text-gray-600 mb-4">{{ trainer.name }}</p>
|
||||
<p class="text-sm text-gray-500">
|
||||
|
||||
@@ -88,13 +88,37 @@
|
||||
>
|
||||
{{ ergebnis.platz }}
|
||||
</div>
|
||||
<div>
|
||||
<span class="font-semibold text-gray-900">
|
||||
{{ ergebnis.spieler1 }}
|
||||
<span v-if="ergebnis.spieler2" class="text-gray-600">
|
||||
/ {{ ergebnis.spieler2 }}
|
||||
<div class="flex items-center gap-2">
|
||||
<div v-if="ergebnis.imageFilename1" class="flex-shrink-0">
|
||||
<img
|
||||
:src="`/api/personen/${ergebnis.imageFilename1}?width=40&height=40`"
|
||||
:alt="ergebnis.spieler1"
|
||||
class="w-10 h-10 rounded-full object-cover border-2 border-gray-300 cursor-pointer hover:border-primary-500 transition-colors"
|
||||
loading="lazy"
|
||||
@click="openLightbox(ergebnis.imageFilename1, ergebnis.spieler1)"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<span class="font-semibold text-gray-900">
|
||||
{{ ergebnis.spieler1 }}
|
||||
</span>
|
||||
</span>
|
||||
<span v-if="ergebnis.spieler2" class="text-gray-600">
|
||||
<span v-if="ergebnis.imageFilename2" class="ml-2 inline-flex items-center gap-2">
|
||||
/
|
||||
<img
|
||||
:src="`/api/personen/${ergebnis.imageFilename2}?width=40&height=40`"
|
||||
:alt="ergebnis.spieler2"
|
||||
class="w-10 h-10 rounded-full object-cover border-2 border-gray-300 cursor-pointer hover:border-primary-500 transition-colors"
|
||||
loading="lazy"
|
||||
@click="openLightbox(ergebnis.imageFilename2, ergebnis.spieler2)"
|
||||
/>
|
||||
{{ ergebnis.spieler2 }}
|
||||
</span>
|
||||
<span v-else class="text-gray-600">
|
||||
/ {{ ergebnis.spieler2 }}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-sm text-gray-500">
|
||||
@@ -147,6 +171,37 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Lightbox für Bilder -->
|
||||
<div
|
||||
v-if="lightboxImage"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-90 p-4"
|
||||
@click="closeLightbox"
|
||||
tabindex="0"
|
||||
@keydown="handleLightboxKeydown"
|
||||
>
|
||||
<div class="relative max-w-5xl max-h-full" @click.stop>
|
||||
<!-- Close Button -->
|
||||
<button
|
||||
@click="closeLightbox"
|
||||
class="absolute top-4 right-4 text-white hover:text-gray-300 z-10 bg-black bg-opacity-50 rounded-full p-3"
|
||||
aria-label="Schließen"
|
||||
>
|
||||
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<img
|
||||
:src="`/api/personen/${lightboxImage.filename}`"
|
||||
:alt="lightboxImage.name"
|
||||
class="max-w-[90%] max-h-[90vh] object-contain mx-auto"
|
||||
/>
|
||||
<div class="mt-4 text-white text-center">
|
||||
<h3 class="text-xl font-semibold">{{ lightboxImage.name }}</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -156,6 +211,7 @@ import { Trophy } from 'lucide-vue-next'
|
||||
|
||||
const results = ref([])
|
||||
const selectedYear = ref('alle')
|
||||
const lightboxImage = ref(null)
|
||||
|
||||
const loadResults = async () => {
|
||||
try {
|
||||
@@ -188,6 +244,7 @@ const loadResults = async () => {
|
||||
}
|
||||
values.push(current.trim())
|
||||
|
||||
// Mindestens 6 Spalten erforderlich (die neuen Bildspalten sind optional)
|
||||
if (values.length < 6) return null
|
||||
|
||||
return {
|
||||
@@ -196,7 +253,9 @@ const loadResults = async () => {
|
||||
platz: values[2].trim(),
|
||||
spieler1: values[3].trim(),
|
||||
spieler2: values[4].trim(),
|
||||
bemerkung: values[5].trim()
|
||||
bemerkung: values[5].trim(),
|
||||
imageFilename1: values[6]?.trim() || '',
|
||||
imageFilename2: values[7]?.trim() || ''
|
||||
}
|
||||
}).filter(result => result !== null)
|
||||
} catch (error) {
|
||||
@@ -268,6 +327,26 @@ const totalDoubles = computed(() => {
|
||||
return results.value.filter(r => r.kategorie === 'Doppel' && r.platz === '1').length
|
||||
})
|
||||
|
||||
function openLightbox(filename, name) {
|
||||
lightboxImage.value = { filename, name }
|
||||
document.body.style.overflow = 'hidden'
|
||||
setTimeout(() => {
|
||||
const modal = document.querySelector('[tabindex="0"]')
|
||||
if (modal) modal.focus()
|
||||
}, 100)
|
||||
}
|
||||
|
||||
function closeLightbox() {
|
||||
lightboxImage.value = null
|
||||
document.body.style.overflow = ''
|
||||
}
|
||||
|
||||
function handleLightboxKeydown(event) {
|
||||
if (event.key === 'Escape') {
|
||||
closeLightbox()
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadResults()
|
||||
})
|
||||
|
||||
@@ -13,112 +13,106 @@
|
||||
|
||||
<div v-if="config" class="grid md:grid-cols-2 gap-8 not-prose">
|
||||
<!-- Vorsitzender -->
|
||||
<div v-if="config.vorstand.vorsitzender.vorname" class="bg-white p-6 rounded-xl shadow-lg border border-gray-100">
|
||||
<h3 class="text-xl font-display font-bold text-gray-900 mb-2">Vorsitzender</h3>
|
||||
<h4 class="text-lg font-semibold text-primary-600 mb-3">
|
||||
{{ config.vorstand.vorsitzender.vorname }} {{ config.vorstand.vorsitzender.nachname }}
|
||||
</h4>
|
||||
<div class="space-y-1 text-gray-600">
|
||||
<p v-if="config.vorstand.vorsitzender.strasse">{{ config.vorstand.vorsitzender.strasse }}</p>
|
||||
<p v-if="config.vorstand.vorsitzender.plz">{{ config.vorstand.vorsitzender.plz }} {{ config.vorstand.vorsitzender.ort }}</p>
|
||||
<p v-if="config.vorstand.vorsitzender.telefon">Tel. {{ config.vorstand.vorsitzender.telefon }}</p>
|
||||
<p v-if="config.vorstand.vorsitzender.email">
|
||||
<a :href="`mailto:${config.vorstand.vorsitzender.email}`" class="text-primary-600 hover:underline">
|
||||
{{ config.vorstand.vorsitzender.email }}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<PersonCard
|
||||
v-if="config.vorstand.vorsitzender.vorname"
|
||||
title="Vorsitzender"
|
||||
:name="`${config.vorstand.vorsitzender.vorname} ${config.vorstand.vorsitzender.nachname}`"
|
||||
:image-filename="config.vorstand.vorsitzender.imageFilename"
|
||||
>
|
||||
<p v-if="config.vorstand.vorsitzender.strasse">{{ config.vorstand.vorsitzender.strasse }}</p>
|
||||
<p v-if="config.vorstand.vorsitzender.plz">{{ config.vorstand.vorsitzender.plz }} {{ config.vorstand.vorsitzender.ort }}</p>
|
||||
<p v-if="config.vorstand.vorsitzender.telefon">Tel. {{ config.vorstand.vorsitzender.telefon }}</p>
|
||||
<p v-if="config.vorstand.vorsitzender.email">
|
||||
<a :href="`mailto:${config.vorstand.vorsitzender.email}`" class="text-primary-600 hover:underline">
|
||||
{{ config.vorstand.vorsitzender.email }}
|
||||
</a>
|
||||
</p>
|
||||
</PersonCard>
|
||||
|
||||
<!-- Stellvertreter -->
|
||||
<div v-if="config.vorstand.stellvertreter.vorname" class="bg-white p-6 rounded-xl shadow-lg border border-gray-100">
|
||||
<h3 class="text-xl font-display font-bold text-gray-900 mb-2">Stellvertreter</h3>
|
||||
<h4 class="text-lg font-semibold text-primary-600 mb-3">
|
||||
{{ config.vorstand.stellvertreter.vorname }} {{ config.vorstand.stellvertreter.nachname }}
|
||||
</h4>
|
||||
<div class="space-y-1 text-gray-600">
|
||||
<p v-if="config.vorstand.stellvertreter.strasse">{{ config.vorstand.stellvertreter.strasse }}</p>
|
||||
<p v-if="config.vorstand.stellvertreter.plz">{{ config.vorstand.stellvertreter.plz }} {{ config.vorstand.stellvertreter.ort }}</p>
|
||||
<p v-if="config.vorstand.stellvertreter.telefon">Tel. {{ config.vorstand.stellvertreter.telefon }}</p>
|
||||
<p v-if="config.vorstand.stellvertreter.email">
|
||||
<a :href="`mailto:${config.vorstand.stellvertreter.email}`" class="text-primary-600 hover:underline">
|
||||
{{ config.vorstand.stellvertreter.email }}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<PersonCard
|
||||
v-if="config.vorstand.stellvertreter.vorname"
|
||||
title="Stellvertreter"
|
||||
:name="`${config.vorstand.stellvertreter.vorname} ${config.vorstand.stellvertreter.nachname}`"
|
||||
:image-filename="config.vorstand.stellvertreter.imageFilename"
|
||||
>
|
||||
<p v-if="config.vorstand.stellvertreter.strasse">{{ config.vorstand.stellvertreter.strasse }}</p>
|
||||
<p v-if="config.vorstand.stellvertreter.plz">{{ config.vorstand.stellvertreter.plz }} {{ config.vorstand.stellvertreter.ort }}</p>
|
||||
<p v-if="config.vorstand.stellvertreter.telefon">Tel. {{ config.vorstand.stellvertreter.telefon }}</p>
|
||||
<p v-if="config.vorstand.stellvertreter.email">
|
||||
<a :href="`mailto:${config.vorstand.stellvertreter.email}`" class="text-primary-600 hover:underline">
|
||||
{{ config.vorstand.stellvertreter.email }}
|
||||
</a>
|
||||
</p>
|
||||
</PersonCard>
|
||||
|
||||
<!-- Kassenwart -->
|
||||
<div v-if="config.vorstand.kassenwart.vorname" class="bg-white p-6 rounded-xl shadow-lg border border-gray-100">
|
||||
<h3 class="text-xl font-display font-bold text-gray-900 mb-2">Kassenwart</h3>
|
||||
<h4 class="text-lg font-semibold text-primary-600 mb-3">
|
||||
{{ config.vorstand.kassenwart.vorname }} {{ config.vorstand.kassenwart.nachname }}
|
||||
</h4>
|
||||
<div class="space-y-1 text-gray-600">
|
||||
<p v-if="config.vorstand.kassenwart.strasse">{{ config.vorstand.kassenwart.strasse }}</p>
|
||||
<p v-if="config.vorstand.kassenwart.plz">{{ config.vorstand.kassenwart.plz }} {{ config.vorstand.kassenwart.ort }}</p>
|
||||
<p v-if="config.vorstand.kassenwart.telefon">Tel. {{ config.vorstand.kassenwart.telefon }}</p>
|
||||
<p v-if="config.vorstand.kassenwart.email">
|
||||
<a :href="`mailto:${config.vorstand.kassenwart.email}`" class="text-primary-600 hover:underline">
|
||||
{{ config.vorstand.kassenwart.email }}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<PersonCard
|
||||
v-if="config.vorstand.kassenwart.vorname"
|
||||
title="Kassenwart"
|
||||
:name="`${config.vorstand.kassenwart.vorname} ${config.vorstand.kassenwart.nachname}`"
|
||||
:image-filename="config.vorstand.kassenwart.imageFilename"
|
||||
>
|
||||
<p v-if="config.vorstand.kassenwart.strasse">{{ config.vorstand.kassenwart.strasse }}</p>
|
||||
<p v-if="config.vorstand.kassenwart.plz">{{ config.vorstand.kassenwart.plz }} {{ config.vorstand.kassenwart.ort }}</p>
|
||||
<p v-if="config.vorstand.kassenwart.telefon">Tel. {{ config.vorstand.kassenwart.telefon }}</p>
|
||||
<p v-if="config.vorstand.kassenwart.email">
|
||||
<a :href="`mailto:${config.vorstand.kassenwart.email}`" class="text-primary-600 hover:underline">
|
||||
{{ config.vorstand.kassenwart.email }}
|
||||
</a>
|
||||
</p>
|
||||
</PersonCard>
|
||||
|
||||
<!-- Schriftführer -->
|
||||
<div v-if="config.vorstand.schriftfuehrer.vorname" class="bg-white p-6 rounded-xl shadow-lg border border-gray-100">
|
||||
<h3 class="text-xl font-display font-bold text-gray-900 mb-2">Schriftführer</h3>
|
||||
<h4 class="text-lg font-semibold text-primary-600 mb-3">
|
||||
{{ config.vorstand.schriftfuehrer.vorname }} {{ config.vorstand.schriftfuehrer.nachname }}
|
||||
</h4>
|
||||
<div class="space-y-1 text-gray-600">
|
||||
<p v-if="config.vorstand.schriftfuehrer.strasse">{{ config.vorstand.schriftfuehrer.strasse }}</p>
|
||||
<p v-if="config.vorstand.schriftfuehrer.plz">{{ config.vorstand.schriftfuehrer.plz }} {{ config.vorstand.schriftfuehrer.ort }}</p>
|
||||
<p v-if="config.vorstand.schriftfuehrer.telefon">Tel. {{ config.vorstand.schriftfuehrer.telefon }}</p>
|
||||
<p v-if="config.vorstand.schriftfuehrer.email">
|
||||
<a :href="`mailto:${config.vorstand.schriftfuehrer.email}`" class="text-primary-600 hover:underline">
|
||||
{{ config.vorstand.schriftfuehrer.email }}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<PersonCard
|
||||
v-if="config.vorstand.schriftfuehrer.vorname"
|
||||
title="Schriftführer"
|
||||
:name="`${config.vorstand.schriftfuehrer.vorname} ${config.vorstand.schriftfuehrer.nachname}`"
|
||||
:image-filename="config.vorstand.schriftfuehrer.imageFilename"
|
||||
>
|
||||
<p v-if="config.vorstand.schriftfuehrer.strasse">{{ config.vorstand.schriftfuehrer.strasse }}</p>
|
||||
<p v-if="config.vorstand.schriftfuehrer.plz">{{ config.vorstand.schriftfuehrer.plz }} {{ config.vorstand.schriftfuehrer.ort }}</p>
|
||||
<p v-if="config.vorstand.schriftfuehrer.telefon">Tel. {{ config.vorstand.schriftfuehrer.telefon }}</p>
|
||||
<p v-if="config.vorstand.schriftfuehrer.email">
|
||||
<a :href="`mailto:${config.vorstand.schriftfuehrer.email}`" class="text-primary-600 hover:underline">
|
||||
{{ config.vorstand.schriftfuehrer.email }}
|
||||
</a>
|
||||
</p>
|
||||
</PersonCard>
|
||||
|
||||
<!-- Sportwart -->
|
||||
<div v-if="config.vorstand.sportwart.vorname" class="bg-white p-6 rounded-xl shadow-lg border border-gray-100">
|
||||
<h3 class="text-xl font-display font-bold text-gray-900 mb-2">Sportwart</h3>
|
||||
<h4 class="text-lg font-semibold text-primary-600 mb-3">
|
||||
{{ config.vorstand.sportwart.vorname }} {{ config.vorstand.sportwart.nachname }}
|
||||
</h4>
|
||||
<div class="space-y-1 text-gray-600">
|
||||
<p v-if="config.vorstand.sportwart.strasse">{{ config.vorstand.sportwart.strasse }}</p>
|
||||
<p v-if="config.vorstand.sportwart.plz">{{ config.vorstand.sportwart.plz }} {{ config.vorstand.sportwart.ort }}</p>
|
||||
<p v-if="config.vorstand.sportwart.telefon">Tel. {{ config.vorstand.sportwart.telefon }}</p>
|
||||
<p v-if="config.vorstand.sportwart.email">
|
||||
<a :href="`mailto:${config.vorstand.sportwart.email}`" class="text-primary-600 hover:underline">
|
||||
{{ config.vorstand.sportwart.email }}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<PersonCard
|
||||
v-if="config.vorstand.sportwart.vorname"
|
||||
title="Sportwart"
|
||||
:name="`${config.vorstand.sportwart.vorname} ${config.vorstand.sportwart.nachname}`"
|
||||
:image-filename="config.vorstand.sportwart.imageFilename"
|
||||
>
|
||||
<p v-if="config.vorstand.sportwart.strasse">{{ config.vorstand.sportwart.strasse }}</p>
|
||||
<p v-if="config.vorstand.sportwart.plz">{{ config.vorstand.sportwart.plz }} {{ config.vorstand.sportwart.ort }}</p>
|
||||
<p v-if="config.vorstand.sportwart.telefon">Tel. {{ config.vorstand.sportwart.telefon }}</p>
|
||||
<p v-if="config.vorstand.sportwart.email">
|
||||
<a :href="`mailto:${config.vorstand.sportwart.email}`" class="text-primary-600 hover:underline">
|
||||
{{ config.vorstand.sportwart.email }}
|
||||
</a>
|
||||
</p>
|
||||
</PersonCard>
|
||||
|
||||
<!-- Jugendwart -->
|
||||
<div v-if="config.vorstand.jugendwart.vorname" class="bg-white p-6 rounded-xl shadow-lg border border-gray-100">
|
||||
<h3 class="text-xl font-display font-bold text-gray-900 mb-2">Jugendwart</h3>
|
||||
<h4 class="text-lg font-semibold text-primary-600 mb-3">
|
||||
{{ config.vorstand.jugendwart.vorname }} {{ config.vorstand.jugendwart.nachname }}
|
||||
</h4>
|
||||
<div class="space-y-1 text-gray-600">
|
||||
<p v-if="config.vorstand.jugendwart.strasse">{{ config.vorstand.jugendwart.strasse }}</p>
|
||||
<p v-if="config.vorstand.jugendwart.plz">{{ config.vorstand.jugendwart.plz }} {{ config.vorstand.jugendwart.ort }}</p>
|
||||
<p v-if="config.vorstand.jugendwart.telefon">Tel. {{ config.vorstand.jugendwart.telefon }}</p>
|
||||
<p v-if="config.vorstand.jugendwart.email">
|
||||
<a :href="`mailto:${config.vorstand.jugendwart.email}`" class="text-primary-600 hover:underline">
|
||||
{{ config.vorstand.jugendwart.email }}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<PersonCard
|
||||
v-if="config.vorstand.jugendwart.vorname"
|
||||
title="Jugendwart"
|
||||
:name="`${config.vorstand.jugendwart.vorname} ${config.vorstand.jugendwart.nachname}`"
|
||||
:image-filename="config.vorstand.jugendwart.imageFilename"
|
||||
>
|
||||
<p v-if="config.vorstand.jugendwart.strasse">{{ config.vorstand.jugendwart.strasse }}</p>
|
||||
<p v-if="config.vorstand.jugendwart.plz">{{ config.vorstand.jugendwart.plz }} {{ config.vorstand.jugendwart.ort }}</p>
|
||||
<p v-if="config.vorstand.jugendwart.telefon">Tel. {{ config.vorstand.jugendwart.telefon }}</p>
|
||||
<p v-if="config.vorstand.jugendwart.email">
|
||||
<a :href="`mailto:${config.vorstand.jugendwart.email}`" class="text-primary-600 hover:underline">
|
||||
{{ config.vorstand.jugendwart.email }}
|
||||
</a>
|
||||
</p>
|
||||
</PersonCard>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user