Update package-lock.json and package.json to include 'globals' dependency and improve code formatting in various components for better readability.
Some checks failed
Code Analysis (JS/Vue) / analyze (push) Failing after 54s
Some checks failed
Code Analysis (JS/Vue) / analyze (push) Failing after 54s
This commit is contained in:
@@ -1,5 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<section id="about" class="py-16 sm:py-20 bg-gradient-to-b from-white to-gray-50">
|
<section
|
||||||
|
id="about"
|
||||||
|
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="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<div class="text-center mb-16">
|
<div class="text-center mb-16">
|
||||||
<h2 class="text-4xl sm:text-5xl font-display font-bold text-gray-900 mb-4">
|
<h2 class="text-4xl sm:text-5xl font-display font-bold text-gray-900 mb-4">
|
||||||
@@ -36,7 +39,9 @@
|
|||||||
Jährlich finden außerdem unsere Vereinsmeisterschaften statt.
|
Jährlich finden außerdem unsere Vereinsmeisterschaften statt.
|
||||||
</p>
|
</p>
|
||||||
<div class="bg-primary-50 border-l-4 border-primary-600 p-6 rounded-lg">
|
<div class="bg-primary-50 border-l-4 border-primary-600 p-6 rounded-lg">
|
||||||
<h4 class="text-xl font-semibold text-primary-800 mb-3">Wir suchen Verstärkung!</h4>
|
<h4 class="text-xl font-semibold text-primary-800 mb-3">
|
||||||
|
Wir suchen Verstärkung!
|
||||||
|
</h4>
|
||||||
<p class="text-primary-700 mb-4">
|
<p class="text-primary-700 mb-4">
|
||||||
Wir suchen ständig Verstärkungen für unsere Mannschaften!
|
Wir suchen ständig Verstärkungen für unsere Mannschaften!
|
||||||
</p>
|
</p>
|
||||||
@@ -63,7 +68,11 @@
|
|||||||
class="bg-white p-6 rounded-xl shadow-lg hover:shadow-xl transition-shadow border border-gray-100"
|
class="bg-white p-6 rounded-xl shadow-lg hover:shadow-xl transition-shadow border border-gray-100"
|
||||||
>
|
>
|
||||||
<div class="w-12 h-12 bg-primary-100 rounded-lg flex items-center justify-center mb-4">
|
<div class="w-12 h-12 bg-primary-100 rounded-lg flex items-center justify-center mb-4">
|
||||||
<component :is="value.icon" :size="24" class="text-primary-600" />
|
<component
|
||||||
|
:is="value.icon"
|
||||||
|
:size="24"
|
||||||
|
class="text-primary-600"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h4 class="text-xl font-display font-bold text-gray-900 mb-2">
|
<h4 class="text-xl font-display font-bold text-gray-900 mb-2">
|
||||||
{{ value.title }}
|
{{ value.title }}
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<section id="calendar" class="py-16 sm:py-20 bg-white">
|
<section
|
||||||
|
id="calendar"
|
||||||
|
class="py-16 sm:py-20 bg-white"
|
||||||
|
>
|
||||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<div class="text-center mb-16">
|
<div class="text-center mb-16">
|
||||||
<h2 class="text-4xl sm:text-5xl font-display font-bold text-gray-900 mb-4">
|
<h2 class="text-4xl sm:text-5xl font-display font-bold text-gray-900 mb-4">
|
||||||
@@ -28,7 +31,11 @@
|
|||||||
<div class="bg-white rounded-2xl shadow-lg hover:shadow-2xl transition-shadow p-6 border border-gray-100">
|
<div class="bg-white rounded-2xl shadow-lg hover:shadow-2xl transition-shadow p-6 border border-gray-100">
|
||||||
<div class="flex items-start space-x-4">
|
<div class="flex items-start space-x-4">
|
||||||
<div :class="['flex-shrink-0 w-14 h-14 bg-gradient-to-br rounded-xl flex items-center justify-center', event.color]">
|
<div :class="['flex-shrink-0 w-14 h-14 bg-gradient-to-br rounded-xl flex items-center justify-center', event.color]">
|
||||||
<component :is="event.icon" :size="28" class="text-white" />
|
<component
|
||||||
|
:is="event.icon"
|
||||||
|
:size="28"
|
||||||
|
class="text-white"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<div class="text-sm font-semibold text-primary-600 mb-1">
|
<div class="text-sm font-semibold text-primary-600 mb-1">
|
||||||
@@ -57,7 +64,10 @@
|
|||||||
|
|
||||||
<div class="mt-16 text-center">
|
<div class="mt-16 text-center">
|
||||||
<div class="bg-gray-50 rounded-2xl p-8 max-w-2xl mx-auto">
|
<div class="bg-gray-50 rounded-2xl p-8 max-w-2xl mx-auto">
|
||||||
<CalendarIcon :size="48" class="text-primary-600 mx-auto mb-4" />
|
<CalendarIcon
|
||||||
|
:size="48"
|
||||||
|
class="text-primary-600 mx-auto mb-4"
|
||||||
|
/>
|
||||||
<h3 class="text-2xl font-display font-bold text-gray-900 mb-3">
|
<h3 class="text-2xl font-display font-bold text-gray-900 mb-3">
|
||||||
Regelmäßige Angebote
|
Regelmäßige Angebote
|
||||||
</h3>
|
</h3>
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<section id="contact" class="py-16 sm:py-20 bg-white">
|
<section
|
||||||
|
id="contact"
|
||||||
|
class="py-16 sm:py-20 bg-white"
|
||||||
|
>
|
||||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<div class="text-center mb-16">
|
<div class="text-center mb-16">
|
||||||
<h2 class="text-4xl sm:text-5xl font-display font-bold text-gray-900 mb-4">
|
<h2 class="text-4xl sm:text-5xl font-display font-bold text-gray-900 mb-4">
|
||||||
@@ -20,13 +23,21 @@
|
|||||||
class="flex items-start space-x-4 bg-gray-50 p-6 rounded-xl hover:shadow-lg transition-shadow"
|
class="flex items-start space-x-4 bg-gray-50 p-6 rounded-xl hover:shadow-lg transition-shadow"
|
||||||
>
|
>
|
||||||
<div :class="['flex-shrink-0 w-12 h-12 bg-gradient-to-br rounded-lg flex items-center justify-center', info.color]">
|
<div :class="['flex-shrink-0 w-12 h-12 bg-gradient-to-br rounded-lg flex items-center justify-center', info.color]">
|
||||||
<component :is="info.icon" :size="24" class="text-white" />
|
<component
|
||||||
|
:is="info.icon"
|
||||||
|
:size="24"
|
||||||
|
class="text-white"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h3 class="font-display font-bold text-gray-900 mb-2">
|
<h3 class="font-display font-bold text-gray-900 mb-2">
|
||||||
{{ info.title }}
|
{{ info.title }}
|
||||||
</h3>
|
</h3>
|
||||||
<p v-for="(line, i) in info.content" :key="i" class="text-gray-600">
|
<p
|
||||||
|
v-for="(line, i) in info.content"
|
||||||
|
:key="i"
|
||||||
|
class="text-gray-600"
|
||||||
|
>
|
||||||
{{ line }}
|
{{ line }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -61,60 +72,78 @@
|
|||||||
<h3 class="text-2xl font-display font-bold text-gray-900 mb-6">
|
<h3 class="text-2xl font-display font-bold text-gray-900 mb-6">
|
||||||
Senden Sie uns eine Nachricht
|
Senden Sie uns eine Nachricht
|
||||||
</h3>
|
</h3>
|
||||||
<form class="space-y-4" @submit.prevent="sendEmail">
|
<form
|
||||||
|
class="space-y-4"
|
||||||
|
@submit.prevent="sendEmail"
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<label for="name" class="block text-sm font-medium text-gray-700 mb-1">
|
<label
|
||||||
|
for="name"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-1"
|
||||||
|
>
|
||||||
Name *
|
Name *
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
|
||||||
id="name"
|
id="name"
|
||||||
v-model="formData.name"
|
v-model="formData.name"
|
||||||
|
type="text"
|
||||||
required
|
required
|
||||||
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent transition-all"
|
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent transition-all"
|
||||||
placeholder="Ihr Name"
|
placeholder="Ihr Name"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="email" class="block text-sm font-medium text-gray-700 mb-1">
|
<label
|
||||||
|
for="email"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-1"
|
||||||
|
>
|
||||||
E-Mail *
|
E-Mail *
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="email"
|
|
||||||
id="email"
|
id="email"
|
||||||
v-model="formData.email"
|
v-model="formData.email"
|
||||||
|
type="email"
|
||||||
required
|
required
|
||||||
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent transition-all"
|
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent transition-all"
|
||||||
placeholder="ihre@email.de"
|
placeholder="ihre@email.de"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="phone" class="block text-sm font-medium text-gray-700 mb-1">
|
<label
|
||||||
|
for="phone"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-1"
|
||||||
|
>
|
||||||
Telefon
|
Telefon
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="tel"
|
|
||||||
id="phone"
|
id="phone"
|
||||||
v-model="formData.phone"
|
v-model="formData.phone"
|
||||||
|
type="tel"
|
||||||
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent transition-all"
|
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent transition-all"
|
||||||
placeholder="+49 123 456789"
|
placeholder="+49 123 456789"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="subject" class="block text-sm font-medium text-gray-700 mb-1">
|
<label
|
||||||
|
for="subject"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-1"
|
||||||
|
>
|
||||||
Betreff *
|
Betreff *
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
|
||||||
id="subject"
|
id="subject"
|
||||||
v-model="formData.subject"
|
v-model="formData.subject"
|
||||||
|
type="text"
|
||||||
required
|
required
|
||||||
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent transition-all"
|
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent transition-all"
|
||||||
placeholder="Worum geht es?"
|
placeholder="Worum geht es?"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="message" class="block text-sm font-medium text-gray-700 mb-1">
|
<label
|
||||||
|
for="message"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-1"
|
||||||
|
>
|
||||||
Nachricht *
|
Nachricht *
|
||||||
</label>
|
</label>
|
||||||
<textarea
|
<textarea
|
||||||
@@ -127,11 +156,26 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<!-- Status Message -->
|
<!-- Status Message -->
|
||||||
<div v-if="submitStatus" class="p-4 rounded-lg" :class="submitStatus === 'success' ? 'bg-green-50 border border-green-200' : 'bg-red-50 border border-red-200'">
|
<div
|
||||||
|
v-if="submitStatus"
|
||||||
|
class="p-4 rounded-lg"
|
||||||
|
:class="submitStatus === 'success' ? 'bg-green-50 border border-green-200' : 'bg-red-50 border border-red-200'"
|
||||||
|
>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<CheckCircle v-if="submitStatus === 'success'" :size="20" class="text-green-600 mr-2" />
|
<CheckCircle
|
||||||
<AlertCircle v-else :size="20" class="text-red-600 mr-2" />
|
v-if="submitStatus === 'success'"
|
||||||
<p :class="submitStatus === 'success' ? 'text-green-800' : 'text-red-800'" class="text-sm font-medium">
|
:size="20"
|
||||||
|
class="text-green-600 mr-2"
|
||||||
|
/>
|
||||||
|
<AlertCircle
|
||||||
|
v-else
|
||||||
|
:size="20"
|
||||||
|
class="text-red-600 mr-2"
|
||||||
|
/>
|
||||||
|
<p
|
||||||
|
:class="submitStatus === 'success' ? 'text-green-800' : 'text-red-800'"
|
||||||
|
class="text-sm font-medium"
|
||||||
|
>
|
||||||
{{ submitMessage }}
|
{{ submitMessage }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -142,8 +186,15 @@
|
|||||||
:disabled="isSubmitting"
|
:disabled="isSubmitting"
|
||||||
class="w-full px-6 py-4 bg-primary-600 hover:bg-primary-700 disabled:bg-gray-400 disabled:cursor-not-allowed text-white font-semibold rounded-lg shadow-lg hover:shadow-xl transition-all duration-300 flex items-center justify-center"
|
class="w-full px-6 py-4 bg-primary-600 hover:bg-primary-700 disabled:bg-gray-400 disabled:cursor-not-allowed text-white font-semibold rounded-lg shadow-lg hover:shadow-xl transition-all duration-300 flex items-center justify-center"
|
||||||
>
|
>
|
||||||
<Send v-if="!isSubmitting" :size="20" class="mr-2" />
|
<Send
|
||||||
<div v-else class="animate-spin rounded-full h-5 w-5 border-b-2 border-white mr-2"></div>
|
v-if="!isSubmitting"
|
||||||
|
:size="20"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
class="animate-spin rounded-full h-5 w-5 border-b-2 border-white mr-2"
|
||||||
|
/>
|
||||||
{{ isSubmitting ? 'Wird gesendet...' : 'E-Mail senden' }}
|
{{ isSubmitting ? 'Wird gesendet...' : 'E-Mail senden' }}
|
||||||
</button>
|
</button>
|
||||||
<p class="text-sm text-gray-600 text-center">
|
<p class="text-sm text-gray-600 text-center">
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<section id="facilities" class="py-16 sm:py-20 bg-white">
|
<section
|
||||||
|
id="facilities"
|
||||||
|
class="py-16 sm:py-20 bg-white"
|
||||||
|
>
|
||||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<div class="text-center mb-16">
|
<div class="text-center mb-16">
|
||||||
<h2 class="text-4xl sm:text-5xl font-display font-bold text-gray-900 mb-4">
|
<h2 class="text-4xl sm:text-5xl font-display font-bold text-gray-900 mb-4">
|
||||||
@@ -20,7 +23,11 @@
|
|||||||
<div :class="['absolute top-0 left-0 right-0 h-1 bg-gradient-to-r opacity-0 group-hover:opacity-100 transition-opacity', facility.color]" />
|
<div :class="['absolute top-0 left-0 right-0 h-1 bg-gradient-to-r opacity-0 group-hover:opacity-100 transition-opacity', facility.color]" />
|
||||||
<div class="p-8">
|
<div class="p-8">
|
||||||
<div :class="['w-16 h-16 bg-gradient-to-br rounded-xl flex items-center justify-center mb-4 group-hover:scale-110 transition-transform', facility.color]">
|
<div :class="['w-16 h-16 bg-gradient-to-br rounded-xl flex items-center justify-center mb-4 group-hover:scale-110 transition-transform', facility.color]">
|
||||||
<component :is="facility.icon" :size="32" class="text-white" />
|
<component
|
||||||
|
:is="facility.icon"
|
||||||
|
:size="32"
|
||||||
|
class="text-white"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h3 class="text-2xl font-display font-bold text-gray-900 mb-3">
|
<h3 class="text-2xl font-display font-bold text-gray-900 mb-3">
|
||||||
{{ facility.title }}
|
{{ facility.title }}
|
||||||
@@ -40,7 +47,9 @@
|
|||||||
style="background-image: url('https://images.unsplash.com/photo-1534438097545-77fef53fe2e8?q=80&w=2070')"
|
style="background-image: url('https://images.unsplash.com/photo-1534438097545-77fef53fe2e8?q=80&w=2070')"
|
||||||
/>
|
/>
|
||||||
<div class="absolute inset-0 bg-gradient-to-t from-black/60 to-transparent flex items-end">
|
<div class="absolute inset-0 bg-gradient-to-t from-black/60 to-transparent flex items-end">
|
||||||
<p class="text-white font-semibold text-xl p-6">Hochwertige Wettkampftische</p>
|
<p class="text-white font-semibold text-xl p-6">
|
||||||
|
Hochwertige Wettkampftische
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="relative h-[300px] rounded-2xl overflow-hidden shadow-xl group">
|
<div class="relative h-[300px] rounded-2xl overflow-hidden shadow-xl group">
|
||||||
@@ -49,7 +58,9 @@
|
|||||||
style="background-image: url('https://images.unsplash.com/photo-1611004275469-8583ed5d7b8d?q=80&w=2070')"
|
style="background-image: url('https://images.unsplash.com/photo-1611004275469-8583ed5d7b8d?q=80&w=2070')"
|
||||||
/>
|
/>
|
||||||
<div class="absolute inset-0 bg-gradient-to-t from-black/60 to-transparent flex items-end">
|
<div class="absolute inset-0 bg-gradient-to-t from-black/60 to-transparent flex items-end">
|
||||||
<p class="text-white font-semibold text-xl p-6">Moderne Tischtennishalle</p>
|
<p class="text-white font-semibold text-xl p-6">
|
||||||
|
Moderne Tischtennishalle
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,31 +6,43 @@
|
|||||||
© {{ currentYear }} Harheimer TC 1954 e.V.
|
© {{ currentYear }} Harheimer TC 1954 e.V.
|
||||||
</p>
|
</p>
|
||||||
<div class="flex items-center space-x-6 text-sm relative">
|
<div class="flex items-center space-x-6 text-sm relative">
|
||||||
<NuxtLink to="/impressum" class="text-gray-400 hover:text-primary-400 transition-colors">
|
<NuxtLink
|
||||||
|
to="/impressum"
|
||||||
|
class="text-gray-400 hover:text-primary-400 transition-colors"
|
||||||
|
>
|
||||||
Impressum
|
Impressum
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
<NuxtLink to="/kontakt" class="text-gray-400 hover:text-primary-400 transition-colors">
|
<NuxtLink
|
||||||
|
to="/kontakt"
|
||||||
|
class="text-gray-400 hover:text-primary-400 transition-colors"
|
||||||
|
>
|
||||||
Kontakt
|
Kontakt
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
|
|
||||||
<!-- Login/Logout -->
|
<!-- Login/Logout -->
|
||||||
<template v-if="isLoggedIn">
|
<template v-if="isLoggedIn">
|
||||||
<button
|
<button
|
||||||
@click="handleLogout"
|
|
||||||
class="flex items-center space-x-1 text-gray-400 hover:text-primary-400 transition-colors"
|
class="flex items-center space-x-1 text-gray-400 hover:text-primary-400 transition-colors"
|
||||||
|
@click="handleLogout"
|
||||||
>
|
>
|
||||||
<User :size="16" />
|
<User :size="16" />
|
||||||
<span>Abmelden</span>
|
<span>Abmelden</span>
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
<div v-else class="relative">
|
<div
|
||||||
|
v-else
|
||||||
|
class="relative"
|
||||||
|
>
|
||||||
<button
|
<button
|
||||||
@click="toggleMemberMenu"
|
|
||||||
class="flex items-center space-x-1 text-gray-400 hover:text-primary-400 transition-colors"
|
class="flex items-center space-x-1 text-gray-400 hover:text-primary-400 transition-colors"
|
||||||
|
@click="toggleMemberMenu"
|
||||||
>
|
>
|
||||||
<User :size="16" />
|
<User :size="16" />
|
||||||
<span>Mitglieder</span>
|
<span>Mitglieder</span>
|
||||||
<ChevronUp :size="14" :class="['transition-transform', isMemberMenuOpen ? 'rotate-0' : 'rotate-180']" />
|
<ChevronUp
|
||||||
|
:size="14"
|
||||||
|
:class="['transition-transform', isMemberMenuOpen ? 'rotate-0' : 'rotate-180']"
|
||||||
|
/>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!-- Dropdown Menu (appears above) - Only when NOT logged in -->
|
<!-- Dropdown Menu (appears above) - Only when NOT logged in -->
|
||||||
@@ -48,22 +60,22 @@
|
|||||||
>
|
>
|
||||||
<NuxtLink
|
<NuxtLink
|
||||||
to="/login"
|
to="/login"
|
||||||
@click="isMemberMenuOpen = false"
|
|
||||||
class="block px-4 py-2 text-sm text-gray-300 hover:bg-primary-600 hover:text-white transition-colors"
|
class="block px-4 py-2 text-sm text-gray-300 hover:bg-primary-600 hover:text-white transition-colors"
|
||||||
|
@click="isMemberMenuOpen = false"
|
||||||
>
|
>
|
||||||
Anmelden
|
Anmelden
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
<NuxtLink
|
<NuxtLink
|
||||||
to="/registrieren"
|
to="/registrieren"
|
||||||
@click="isMemberMenuOpen = false"
|
|
||||||
class="block px-4 py-2 text-sm text-gray-300 hover:bg-primary-600 hover:text-white transition-colors"
|
class="block px-4 py-2 text-sm text-gray-300 hover:bg-primary-600 hover:text-white transition-colors"
|
||||||
|
@click="isMemberMenuOpen = false"
|
||||||
>
|
>
|
||||||
Registrieren
|
Registrieren
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
<NuxtLink
|
<NuxtLink
|
||||||
to="/passwort-vergessen"
|
to="/passwort-vergessen"
|
||||||
@click="isMemberMenuOpen = false"
|
|
||||||
class="block px-4 py-2 text-sm text-gray-300 hover:bg-primary-600 hover:text-white transition-colors"
|
class="block px-4 py-2 text-sm text-gray-300 hover:bg-primary-600 hover:text-white transition-colors"
|
||||||
|
@click="isMemberMenuOpen = false"
|
||||||
>
|
>
|
||||||
Passwort vergessen
|
Passwort vergessen
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<section v-if="images.length > 0" id="gallery" class="py-16 sm:py-20 bg-gradient-to-b from-white to-gray-50">
|
<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="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<div class="text-center mb-16">
|
<div class="text-center mb-16">
|
||||||
<h2 class="text-4xl sm:text-5xl font-display font-bold text-gray-900 mb-4">
|
<h2 class="text-4xl sm:text-5xl font-display font-bold text-gray-900 mb-4">
|
||||||
@@ -22,9 +26,11 @@
|
|||||||
:src="`/galerie/${image.filename}`"
|
:src="`/galerie/${image.filename}`"
|
||||||
:alt="image.title"
|
:alt="image.title"
|
||||||
class="w-full h-full object-cover group-hover:scale-110 transition-transform duration-700"
|
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">
|
<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>
|
<p class="text-white font-semibold text-xs p-1 truncate">
|
||||||
|
{{ image.title }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -37,8 +43,8 @@
|
|||||||
>
|
>
|
||||||
<div class="relative w-full h-full flex items-center justify-center">
|
<div class="relative w-full h-full flex items-center justify-center">
|
||||||
<button
|
<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"
|
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" />
|
<X :size="24" />
|
||||||
</button>
|
</button>
|
||||||
@@ -47,7 +53,7 @@
|
|||||||
:alt="lightboxImage.title"
|
:alt="lightboxImage.title"
|
||||||
class="max-w-[80vw] max-h-[80vh] object-contain rounded-lg"
|
class="max-w-[80vw] max-h-[80vh] object-contain rounded-lg"
|
||||||
@click.stop
|
@click.stop
|
||||||
/>
|
>
|
||||||
<div class="absolute bottom-4 left-4 right-4 text-center">
|
<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">
|
<p class="text-white font-semibold text-lg bg-black/50 rounded-lg px-4 py-2">
|
||||||
{{ lightboxImage.title }}
|
{{ lightboxImage.title }}
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<section id="home" class="relative min-h-full flex items-center justify-center overflow-hidden bg-gradient-to-br from-gray-50 to-gray-100">
|
<section
|
||||||
|
id="home"
|
||||||
|
class="relative min-h-full flex items-center justify-center overflow-hidden bg-gradient-to-br from-gray-50 to-gray-100"
|
||||||
|
>
|
||||||
<!-- Decorative Elements -->
|
<!-- Decorative Elements -->
|
||||||
<div class="absolute inset-0 z-0">
|
<div class="absolute inset-0 z-0">
|
||||||
<div class="absolute top-0 right-0 w-96 h-96 bg-primary-200/30 rounded-full blur-3xl" />
|
<div class="absolute top-0 right-0 w-96 h-96 bg-primary-200/30 rounded-full blur-3xl" />
|
||||||
@@ -15,14 +18,13 @@
|
|||||||
<div class="relative z-20 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-20 sm:py-8">
|
<div class="relative z-20 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-20 sm:py-8">
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<h1 class="text-5xl sm:text-6xl lg:text-7xl font-display font-bold text-gray-900 mb-6 leading-tight animate-fade-in">
|
<h1 class="text-5xl sm:text-6xl lg:text-7xl font-display font-bold text-gray-900 mb-6 leading-tight animate-fade-in">
|
||||||
Willkommen beim<br />
|
Willkommen beim<br>
|
||||||
<span class="text-primary-600">Harheimer TC</span>
|
<span class="text-primary-600">Harheimer TC</span>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<p class="text-xl sm:text-2xl text-gray-700 mb-8 max-w-3xl mx-auto animate-fade-in-delay-1">
|
<p class="text-xl sm:text-2xl text-gray-700 mb-8 max-w-3xl mx-auto animate-fade-in-delay-1">
|
||||||
Tradition trifft Moderne - Ihr Tischtennisverein in Frankfurt-Harheim seit {{ yearsSinceFounding }} Jahren
|
Tradition trifft Moderne - Ihr Tischtennisverein in Frankfurt-Harheim seit {{ yearsSinceFounding }} Jahren
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -9,7 +9,10 @@
|
|||||||
>
|
>
|
||||||
<div class="flex items-center mb-4">
|
<div class="flex items-center mb-4">
|
||||||
<div class="w-16 h-16 bg-primary-100 rounded-xl flex items-center justify-center group-hover:bg-primary-600 transition-colors">
|
<div class="w-16 h-16 bg-primary-100 rounded-xl flex items-center justify-center group-hover:bg-primary-600 transition-colors">
|
||||||
<UserPlus :size="32" class="text-primary-600 group-hover:text-white transition-colors" />
|
<UserPlus
|
||||||
|
:size="32"
|
||||||
|
class="text-primary-600 group-hover:text-white transition-colors"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h3 class="ml-4 text-2xl font-display font-bold text-gray-900">
|
<h3 class="ml-4 text-2xl font-display font-bold text-gray-900">
|
||||||
Mitglied werden
|
Mitglied werden
|
||||||
@@ -21,7 +24,10 @@
|
|||||||
</p>
|
</p>
|
||||||
<div class="flex items-center text-primary-600 font-semibold group-hover:translate-x-2 transition-transform">
|
<div class="flex items-center text-primary-600 font-semibold group-hover:translate-x-2 transition-transform">
|
||||||
Mehr erfahren
|
Mehr erfahren
|
||||||
<ArrowRight :size="20" class="ml-2" />
|
<ArrowRight
|
||||||
|
:size="20"
|
||||||
|
class="ml-2"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
|
|
||||||
@@ -32,7 +38,10 @@
|
|||||||
>
|
>
|
||||||
<div class="flex items-center mb-4">
|
<div class="flex items-center mb-4">
|
||||||
<div class="w-16 h-16 bg-primary-100 rounded-xl flex items-center justify-center group-hover:bg-primary-600 transition-colors">
|
<div class="w-16 h-16 bg-primary-100 rounded-xl flex items-center justify-center group-hover:bg-primary-600 transition-colors">
|
||||||
<Mail :size="32" class="text-primary-600 group-hover:text-white transition-colors" />
|
<Mail
|
||||||
|
:size="32"
|
||||||
|
class="text-primary-600 group-hover:text-white transition-colors"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h3 class="ml-4 text-2xl font-display font-bold text-gray-900">
|
<h3 class="ml-4 text-2xl font-display font-bold text-gray-900">
|
||||||
Kontakt aufnehmen
|
Kontakt aufnehmen
|
||||||
@@ -44,7 +53,10 @@
|
|||||||
</p>
|
</p>
|
||||||
<div class="flex items-center text-primary-600 font-semibold group-hover:translate-x-2 transition-transform">
|
<div class="flex items-center text-primary-600 font-semibold group-hover:translate-x-2 transition-transform">
|
||||||
Jetzt kontaktieren
|
Jetzt kontaktieren
|
||||||
<ArrowRight :size="20" class="ml-2" />
|
<ArrowRight
|
||||||
|
:size="20"
|
||||||
|
class="ml-2"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -18,7 +18,10 @@
|
|||||||
class="inline-flex items-center px-6 py-3 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors"
|
class="inline-flex items-center px-6 py-3 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors"
|
||||||
>
|
>
|
||||||
Alle Termine anzeigen
|
Alle Termine anzeigen
|
||||||
<ArrowRight :size="20" class="ml-2" />
|
<ArrowRight
|
||||||
|
:size="20"
|
||||||
|
class="ml-2"
|
||||||
|
/>
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,22 +2,28 @@
|
|||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">
|
<label class="block text-sm font-medium text-gray-700 mb-2">
|
||||||
{{ label }}
|
{{ label }}
|
||||||
<span v-if="!required" class="text-gray-500 text-xs">(optional)</span>
|
<span
|
||||||
|
v-if="!required"
|
||||||
|
class="text-gray-500 text-xs"
|
||||||
|
>(optional)</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<div v-if="imageFilename" class="mb-2">
|
<div
|
||||||
|
v-if="imageFilename"
|
||||||
|
class="mb-2"
|
||||||
|
>
|
||||||
<div class="relative inline-block">
|
<div class="relative inline-block">
|
||||||
<img
|
<img
|
||||||
:src="`/api/personen/${imageFilename}?width=100&height=100`"
|
:src="`/api/personen/${imageFilename}?width=100&height=100`"
|
||||||
:alt="label"
|
:alt="label"
|
||||||
class="w-24 h-24 object-cover rounded-lg border-2 border-gray-300"
|
class="w-24 h-24 object-cover rounded-lg border-2 border-gray-300"
|
||||||
/>
|
>
|
||||||
<button
|
<button
|
||||||
v-if="!uploading"
|
v-if="!uploading"
|
||||||
@click="removeImage"
|
|
||||||
class="absolute -top-2 -right-2 bg-red-600 text-white rounded-full p-1 hover:bg-red-700 transition-colors"
|
class="absolute -top-2 -right-2 bg-red-600 text-white rounded-full p-1 hover:bg-red-700 transition-colors"
|
||||||
type="button"
|
type="button"
|
||||||
title="Bild entfernen"
|
title="Bild entfernen"
|
||||||
|
@click="removeImage"
|
||||||
>
|
>
|
||||||
<X :size="14" />
|
<X :size="14" />
|
||||||
</button>
|
</button>
|
||||||
@@ -40,13 +46,22 @@
|
|||||||
class="hidden"
|
class="hidden"
|
||||||
:disabled="uploading"
|
:disabled="uploading"
|
||||||
@change="handleFileSelect"
|
@change="handleFileSelect"
|
||||||
/>
|
>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<div v-if="uploading" class="flex items-center justify-center gap-2 text-gray-600">
|
<div
|
||||||
<Loader2 :size="16" class="animate-spin" />
|
v-if="uploading"
|
||||||
|
class="flex items-center justify-center gap-2 text-gray-600"
|
||||||
|
>
|
||||||
|
<Loader2
|
||||||
|
:size="16"
|
||||||
|
class="animate-spin"
|
||||||
|
/>
|
||||||
<span>Wird hochgeladen...</span>
|
<span>Wird hochgeladen...</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="text-sm text-gray-600">
|
<div
|
||||||
|
v-else
|
||||||
|
class="text-sm text-gray-600"
|
||||||
|
>
|
||||||
<span v-if="!imageFilename">📷 Bild auswählen oder hier ablegen</span>
|
<span v-if="!imageFilename">📷 Bild auswählen oder hier ablegen</span>
|
||||||
<span v-else>🔄 Bild ändern</span>
|
<span v-else>🔄 Bild ändern</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -54,7 +69,12 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p v-if="error" class="mt-1 text-sm text-red-600">{{ error }}</p>
|
<p
|
||||||
|
v-if="error"
|
||||||
|
class="mt-1 text-sm text-red-600"
|
||||||
|
>
|
||||||
|
{{ error }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div v-if="mannschaften.length > 0" class="space-y-8">
|
<div
|
||||||
|
v-if="mannschaften.length > 0"
|
||||||
|
class="space-y-8"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
v-for="(mannschaft, index) in mannschaften"
|
v-for="(mannschaft, index) in mannschaften"
|
||||||
:key="index"
|
:key="index"
|
||||||
@@ -11,7 +14,9 @@
|
|||||||
<h2 class="text-2xl font-display font-bold text-white mb-2">
|
<h2 class="text-2xl font-display font-bold text-white mb-2">
|
||||||
{{ mannschaft.mannschaft }}
|
{{ mannschaft.mannschaft }}
|
||||||
</h2>
|
</h2>
|
||||||
<p class="text-primary-100 text-lg">{{ mannschaft.liga }}</p>
|
<p class="text-primary-100 text-lg">
|
||||||
|
{{ mannschaft.liga }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Content -->
|
<!-- Content -->
|
||||||
@@ -20,24 +25,24 @@
|
|||||||
<div class="grid md:grid-cols-2 gap-6 mb-6">
|
<div class="grid md:grid-cols-2 gap-6 mb-6">
|
||||||
<div class="space-y-3">
|
<div class="space-y-3">
|
||||||
<div class="flex items-center space-x-3">
|
<div class="flex items-center space-x-3">
|
||||||
<div class="w-2 h-2 bg-primary-600 rounded-full"></div>
|
<div class="w-2 h-2 bg-primary-600 rounded-full" />
|
||||||
<span class="text-gray-600">Staffelleiter:</span>
|
<span class="text-gray-600">Staffelleiter:</span>
|
||||||
<span class="font-semibold text-gray-900">{{ mannschaft.staffelleiter }}</span>
|
<span class="font-semibold text-gray-900">{{ mannschaft.staffelleiter }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center space-x-3">
|
<div class="flex items-center space-x-3">
|
||||||
<div class="w-2 h-2 bg-primary-600 rounded-full"></div>
|
<div class="w-2 h-2 bg-primary-600 rounded-full" />
|
||||||
<span class="text-gray-600">Telefon:</span>
|
<span class="text-gray-600">Telefon:</span>
|
||||||
<span class="font-semibold text-gray-900">{{ mannschaft.telefon }}</span>
|
<span class="font-semibold text-gray-900">{{ mannschaft.telefon }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-3">
|
<div class="space-y-3">
|
||||||
<div class="flex items-center space-x-3">
|
<div class="flex items-center space-x-3">
|
||||||
<div class="w-2 h-2 bg-primary-600 rounded-full"></div>
|
<div class="w-2 h-2 bg-primary-600 rounded-full" />
|
||||||
<span class="text-gray-600">Heimspieltag:</span>
|
<span class="text-gray-600">Heimspieltag:</span>
|
||||||
<span class="font-semibold text-gray-900">{{ mannschaft.heimspieltag }}</span>
|
<span class="font-semibold text-gray-900">{{ mannschaft.heimspieltag }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center space-x-3">
|
<div class="flex items-center space-x-3">
|
||||||
<div class="w-2 h-2 bg-primary-600 rounded-full"></div>
|
<div class="w-2 h-2 bg-primary-600 rounded-full" />
|
||||||
<span class="text-gray-600">Spielsystem:</span>
|
<span class="text-gray-600">Spielsystem:</span>
|
||||||
<span class="font-semibold text-gray-900">{{ mannschaft.spielsystem }}</span>
|
<span class="font-semibold text-gray-900">{{ mannschaft.spielsystem }}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -56,8 +61,13 @@
|
|||||||
class="bg-gray-50 rounded-lg p-4 text-center"
|
class="bg-gray-50 rounded-lg p-4 text-center"
|
||||||
:class="spieler === mannschaft.mannschaftsfuehrer ? 'ring-2 ring-primary-500 bg-primary-50' : ''"
|
:class="spieler === mannschaft.mannschaftsfuehrer ? 'ring-2 ring-primary-500 bg-primary-50' : ''"
|
||||||
>
|
>
|
||||||
<div class="font-semibold text-gray-900">{{ spieler }}</div>
|
<div class="font-semibold text-gray-900">
|
||||||
<div v-if="spieler === mannschaft.mannschaftsfuehrer" class="text-xs text-primary-600 font-medium mt-1">
|
{{ spieler }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="spieler === mannschaft.mannschaftsfuehrer"
|
||||||
|
class="text-xs text-primary-600 font-medium mt-1"
|
||||||
|
>
|
||||||
Mannschaftsführer
|
Mannschaftsführer
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -76,9 +86,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else class="text-center py-12 bg-gray-50 rounded-xl">
|
<div
|
||||||
<Users :size="48" class="text-gray-400 mx-auto mb-4" />
|
v-else
|
||||||
<p class="text-gray-600">Keine Mannschaftsdaten geladen</p>
|
class="text-center py-12 bg-gray-50 rounded-xl"
|
||||||
|
>
|
||||||
|
<Users
|
||||||
|
:size="48"
|
||||||
|
class="text-gray-400 mx-auto mb-4"
|
||||||
|
/>
|
||||||
|
<p class="text-gray-600">
|
||||||
|
Keine Mannschaftsdaten geladen
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<section id="membership" class="py-16 sm:py-20 bg-gradient-to-b from-gray-50 to-white">
|
<section
|
||||||
|
id="membership"
|
||||||
|
class="py-16 sm:py-20 bg-gradient-to-b from-gray-50 to-white"
|
||||||
|
>
|
||||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<div class="text-center mb-16">
|
<div class="text-center mb-16">
|
||||||
<h2 class="text-4xl sm:text-5xl font-display font-bold text-gray-900 mb-4">
|
<h2 class="text-4xl sm:text-5xl font-display font-bold text-gray-900 mb-4">
|
||||||
@@ -20,7 +23,10 @@
|
|||||||
plan.popular ? 'ring-4 ring-primary-500 scale-105' : ''
|
plan.popular ? 'ring-4 ring-primary-500 scale-105' : ''
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
<div v-if="plan.popular" class="absolute top-0 right-0 bg-primary-600 text-white px-4 py-1 text-sm font-semibold rounded-bl-lg">
|
<div
|
||||||
|
v-if="plan.popular"
|
||||||
|
class="absolute top-0 right-0 bg-primary-600 text-white px-4 py-1 text-sm font-semibold rounded-bl-lg"
|
||||||
|
>
|
||||||
Beliebt
|
Beliebt
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -28,7 +34,11 @@
|
|||||||
|
|
||||||
<div class="p-8">
|
<div class="p-8">
|
||||||
<div :class="['w-12 h-12 bg-gradient-to-br rounded-xl flex items-center justify-center mb-4', plan.gradient]">
|
<div :class="['w-12 h-12 bg-gradient-to-br rounded-xl flex items-center justify-center mb-4', plan.gradient]">
|
||||||
<component :is="plan.icon" :size="24" class="text-white" />
|
<component
|
||||||
|
:is="plan.icon"
|
||||||
|
:size="24"
|
||||||
|
class="text-white"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3 class="text-2xl font-display font-bold text-gray-900 mb-2">
|
<h3 class="text-2xl font-display font-bold text-gray-900 mb-2">
|
||||||
@@ -46,8 +56,15 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul class="space-y-3 mb-8">
|
<ul class="space-y-3 mb-8">
|
||||||
<li v-for="feature in plan.features" :key="feature" class="flex items-start">
|
<li
|
||||||
<Check :size="20" class="text-primary-600 mr-3 flex-shrink-0 mt-0.5" />
|
v-for="feature in plan.features"
|
||||||
|
:key="feature"
|
||||||
|
class="flex items-start"
|
||||||
|
>
|
||||||
|
<Check
|
||||||
|
:size="20"
|
||||||
|
class="text-primary-600 mr-3 flex-shrink-0 mt-0.5"
|
||||||
|
/>
|
||||||
<span class="text-gray-700">{{ feature }}</span>
|
<span class="text-gray-700">{{ feature }}</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -84,7 +101,10 @@
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
class="inline-flex items-center px-6 py-3 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors"
|
class="inline-flex items-center px-6 py-3 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors"
|
||||||
>
|
>
|
||||||
<FileText :size="20" class="mr-2" />
|
<FileText
|
||||||
|
:size="20"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
Satzung herunterladen (PDF)
|
Satzung herunterladen (PDF)
|
||||||
</a>
|
</a>
|
||||||
<span class="text-sm text-gray-500">oder</span>
|
<span class="text-sm text-gray-500">oder</span>
|
||||||
@@ -92,7 +112,10 @@
|
|||||||
to="/satzung"
|
to="/satzung"
|
||||||
class="inline-flex items-center px-6 py-3 bg-gray-100 hover:bg-gray-200 text-gray-900 font-semibold rounded-lg transition-colors"
|
class="inline-flex items-center px-6 py-3 bg-gray-100 hover:bg-gray-200 text-gray-900 font-semibold rounded-lg transition-colors"
|
||||||
>
|
>
|
||||||
<Eye :size="20" class="mr-2" />
|
<Eye
|
||||||
|
:size="20"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
Online ansehen
|
Online ansehen
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<section id="membership" class="py-16 sm:py-20 bg-gradient-to-b from-gray-50 to-white">
|
<section
|
||||||
|
id="membership"
|
||||||
|
class="py-16 sm:py-20 bg-gradient-to-b from-gray-50 to-white"
|
||||||
|
>
|
||||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<div class="text-center mb-16">
|
<div class="text-center mb-16">
|
||||||
<h2 class="text-4xl sm:text-5xl font-display font-bold text-gray-900 mb-4">
|
<h2 class="text-4xl sm:text-5xl font-display font-bold text-gray-900 mb-4">
|
||||||
@@ -20,7 +23,10 @@
|
|||||||
plan.popular ? 'ring-4 ring-primary-500 scale-105' : ''
|
plan.popular ? 'ring-4 ring-primary-500 scale-105' : ''
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
<div v-if="plan.popular" class="absolute top-0 right-0 bg-primary-600 text-white px-4 py-1 text-sm font-semibold rounded-bl-lg">
|
<div
|
||||||
|
v-if="plan.popular"
|
||||||
|
class="absolute top-0 right-0 bg-primary-600 text-white px-4 py-1 text-sm font-semibold rounded-bl-lg"
|
||||||
|
>
|
||||||
Beliebt
|
Beliebt
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -28,7 +34,11 @@
|
|||||||
|
|
||||||
<div class="p-8">
|
<div class="p-8">
|
||||||
<div :class="['w-12 h-12 bg-gradient-to-br rounded-xl flex items-center justify-center mb-4', plan.gradient]">
|
<div :class="['w-12 h-12 bg-gradient-to-br rounded-xl flex items-center justify-center mb-4', plan.gradient]">
|
||||||
<component :is="plan.icon" :size="24" class="text-white" />
|
<component
|
||||||
|
:is="plan.icon"
|
||||||
|
:size="24"
|
||||||
|
class="text-white"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3 class="text-2xl font-display font-bold text-gray-900 mb-2">
|
<h3 class="text-2xl font-display font-bold text-gray-900 mb-2">
|
||||||
@@ -46,8 +56,15 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul class="space-y-3 mb-8">
|
<ul class="space-y-3 mb-8">
|
||||||
<li v-for="feature in plan.features" :key="feature" class="flex items-start">
|
<li
|
||||||
<Check :size="20" class="text-primary-600 mr-3 flex-shrink-0 mt-0.5" />
|
v-for="feature in plan.features"
|
||||||
|
:key="feature"
|
||||||
|
class="flex items-start"
|
||||||
|
>
|
||||||
|
<Check
|
||||||
|
:size="20"
|
||||||
|
class="text-primary-600 mr-3 flex-shrink-0 mt-0.5"
|
||||||
|
/>
|
||||||
<span class="text-gray-700">{{ feature }}</span>
|
<span class="text-gray-700">{{ feature }}</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -84,7 +101,10 @@
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
class="inline-flex items-center px-6 py-3 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors"
|
class="inline-flex items-center px-6 py-3 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors"
|
||||||
>
|
>
|
||||||
<FileText :size="20" class="mr-2" />
|
<FileText
|
||||||
|
:size="20"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
Satzung herunterladen (PDF)
|
Satzung herunterladen (PDF)
|
||||||
</a>
|
</a>
|
||||||
<span class="text-sm text-gray-500">oder</span>
|
<span class="text-sm text-gray-500">oder</span>
|
||||||
@@ -92,7 +112,10 @@
|
|||||||
to="/satzung"
|
to="/satzung"
|
||||||
class="inline-flex items-center px-6 py-3 bg-gray-100 hover:bg-gray-200 text-gray-900 font-semibold rounded-lg transition-colors"
|
class="inline-flex items-center px-6 py-3 bg-gray-100 hover:bg-gray-200 text-gray-900 font-semibold rounded-lg transition-colors"
|
||||||
>
|
>
|
||||||
<Eye :size="20" class="mr-2" />
|
<Eye
|
||||||
|
:size="20"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
Online ansehen
|
Online ansehen
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,18 +8,32 @@
|
|||||||
<div class="bg-white rounded-lg max-w-md w-full p-6">
|
<div class="bg-white rounded-lg max-w-md w-full p-6">
|
||||||
<div class="flex items-center mb-4">
|
<div class="flex items-center mb-4">
|
||||||
<div class="flex-shrink-0 w-10 h-10 mx-auto bg-green-100 rounded-full flex items-center justify-center">
|
<div class="flex-shrink-0 w-10 h-10 mx-auto bg-green-100 rounded-full flex items-center justify-center">
|
||||||
<svg class="w-6 h-6 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
|
class="w-6 h-6 text-green-600"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M5 13l4 4L19 7"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<h3 class="text-lg font-medium text-gray-900 mb-2">{{ successTitle }}</h3>
|
<h3 class="text-lg font-medium text-gray-900 mb-2">
|
||||||
<p class="text-sm text-gray-600 mb-6">{{ successMessage }}</p>
|
{{ successTitle }}
|
||||||
|
</h3>
|
||||||
|
<p class="text-sm text-gray-600 mb-6">
|
||||||
|
{{ successMessage }}
|
||||||
|
</p>
|
||||||
<div class="flex justify-center">
|
<div class="flex justify-center">
|
||||||
<button
|
<button
|
||||||
@click="closeSuccess"
|
|
||||||
class="px-6 py-2 bg-primary-600 hover:bg-primary-700 text-white rounded-lg transition-colors"
|
class="px-6 py-2 bg-primary-600 hover:bg-primary-700 text-white rounded-lg transition-colors"
|
||||||
|
@click="closeSuccess"
|
||||||
>
|
>
|
||||||
OK
|
OK
|
||||||
</button>
|
</button>
|
||||||
@@ -37,18 +51,32 @@
|
|||||||
<div class="bg-white rounded-lg max-w-md w-full p-6">
|
<div class="bg-white rounded-lg max-w-md w-full p-6">
|
||||||
<div class="flex items-center mb-4">
|
<div class="flex items-center mb-4">
|
||||||
<div class="flex-shrink-0 w-10 h-10 mx-auto bg-red-100 rounded-full flex items-center justify-center">
|
<div class="flex-shrink-0 w-10 h-10 mx-auto bg-red-100 rounded-full flex items-center justify-center">
|
||||||
<svg class="w-6 h-6 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
class="w-6 h-6 text-red-600"
|
||||||
|
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>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<h3 class="text-lg font-medium text-gray-900 mb-2">{{ errorTitle }}</h3>
|
<h3 class="text-lg font-medium text-gray-900 mb-2">
|
||||||
<p class="text-sm text-gray-600 mb-6">{{ errorMessage }}</p>
|
{{ errorTitle }}
|
||||||
|
</h3>
|
||||||
|
<p class="text-sm text-gray-600 mb-6">
|
||||||
|
{{ errorMessage }}
|
||||||
|
</p>
|
||||||
<div class="flex justify-center">
|
<div class="flex justify-center">
|
||||||
<button
|
<button
|
||||||
@click="closeError"
|
|
||||||
class="px-6 py-2 bg-red-600 hover:bg-red-700 text-white rounded-lg transition-colors"
|
class="px-6 py-2 bg-red-600 hover:bg-red-700 text-white rounded-lg transition-colors"
|
||||||
|
@click="closeError"
|
||||||
>
|
>
|
||||||
OK
|
OK
|
||||||
</button>
|
</button>
|
||||||
@@ -66,24 +94,38 @@
|
|||||||
<div class="bg-white rounded-lg max-w-md w-full p-6">
|
<div class="bg-white rounded-lg max-w-md w-full p-6">
|
||||||
<div class="flex items-center mb-4">
|
<div class="flex items-center mb-4">
|
||||||
<div class="flex-shrink-0 w-10 h-10 mx-auto bg-yellow-100 rounded-full flex items-center justify-center">
|
<div class="flex-shrink-0 w-10 h-10 mx-auto bg-yellow-100 rounded-full flex items-center justify-center">
|
||||||
<svg class="w-6 h-6 text-yellow-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"></path>
|
class="w-6 h-6 text-yellow-600"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<h3 class="text-lg font-medium text-gray-900 mb-2">{{ confirmTitle }}</h3>
|
<h3 class="text-lg font-medium text-gray-900 mb-2">
|
||||||
<p class="text-sm text-gray-600 mb-6">{{ confirmMessage }}</p>
|
{{ confirmTitle }}
|
||||||
|
</h3>
|
||||||
|
<p class="text-sm text-gray-600 mb-6">
|
||||||
|
{{ confirmMessage }}
|
||||||
|
</p>
|
||||||
<div class="flex space-x-3 justify-center">
|
<div class="flex space-x-3 justify-center">
|
||||||
<button
|
<button
|
||||||
@click="closeConfirm"
|
|
||||||
class="px-4 py-2 text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors"
|
class="px-4 py-2 text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors"
|
||||||
|
@click="closeConfirm"
|
||||||
>
|
>
|
||||||
Abbrechen
|
Abbrechen
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@click="executeConfirm"
|
|
||||||
class="px-4 py-2 bg-red-600 hover:bg-red-700 text-white rounded-lg transition-colors"
|
class="px-4 py-2 bg-red-600 hover:bg-red-700 text-white rounded-lg transition-colors"
|
||||||
|
@click="executeConfirm"
|
||||||
>
|
>
|
||||||
Bestätigen
|
Bestätigen
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,15 +1,25 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="bg-white p-6 rounded-xl shadow-lg border border-gray-100">
|
<div class="bg-white p-6 rounded-xl shadow-lg border border-gray-100">
|
||||||
<div v-if="imageFilename" class="mb-4 flex justify-center">
|
<div
|
||||||
|
v-if="imageFilename"
|
||||||
|
class="mb-4 flex justify-center"
|
||||||
|
>
|
||||||
<img
|
<img
|
||||||
:src="`/api/personen/${imageFilename}?width=200&height=200`"
|
:src="`/api/personen/${imageFilename}?width=200&height=200`"
|
||||||
:alt="`${title}: ${name}`"
|
:alt="`${title}: ${name}`"
|
||||||
class="w-32 h-32 object-cover rounded-full border-4 border-primary-100 shadow-md"
|
class="w-32 h-32 object-cover rounded-full border-4 border-primary-100 shadow-md"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
<h3 v-if="title" class="text-xl font-display font-bold text-gray-900 mb-2">{{ title }}</h3>
|
<h3
|
||||||
<h4 class="text-lg font-semibold text-primary-600 mb-3">{{ name }}</h4>
|
v-if="title"
|
||||||
|
class="text-xl font-display font-bold text-gray-900 mb-2"
|
||||||
|
>
|
||||||
|
{{ title }}
|
||||||
|
</h3>
|
||||||
|
<h4 class="text-lg font-semibold text-primary-600 mb-3">
|
||||||
|
{{ name }}
|
||||||
|
</h4>
|
||||||
<div class="space-y-1 text-gray-600">
|
<div class="space-y-1 text-gray-600">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<section v-if="news.length > 0" class="py-16 sm:py-20 bg-white">
|
<section
|
||||||
|
v-if="news.length > 0"
|
||||||
|
class="py-16 sm:py-20 bg-white"
|
||||||
|
>
|
||||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<div class="text-center mb-16">
|
<div class="text-center mb-16">
|
||||||
<h2 class="text-4xl sm:text-5xl font-display font-bold text-gray-900 mb-4">
|
<h2 class="text-4xl sm:text-5xl font-display font-bold text-gray-900 mb-4">
|
||||||
@@ -12,15 +15,21 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-center">
|
<div class="flex justify-center">
|
||||||
<div class="grid gap-8" :class="getGridClass()">
|
<div
|
||||||
|
class="grid gap-8"
|
||||||
|
:class="getGridClass()"
|
||||||
|
>
|
||||||
<article
|
<article
|
||||||
v-for="item in news"
|
v-for="item in news"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
@click="openNewsModal(item)"
|
|
||||||
class="bg-gray-50 rounded-xl p-6 border border-gray-200 hover:shadow-lg transition-shadow w-full max-w-sm flex flex-col cursor-pointer"
|
class="bg-gray-50 rounded-xl p-6 border border-gray-200 hover:shadow-lg transition-shadow w-full max-w-sm flex flex-col cursor-pointer"
|
||||||
|
@click="openNewsModal(item)"
|
||||||
>
|
>
|
||||||
<div class="flex items-center text-sm text-gray-500 mb-3">
|
<div class="flex items-center text-sm text-gray-500 mb-3">
|
||||||
<Calendar :size="16" class="mr-2" />
|
<Calendar
|
||||||
|
:size="16"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
{{ formatDate(item.created) }}
|
{{ formatDate(item.created) }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -47,7 +56,10 @@
|
|||||||
<div class="flex items-center justify-between p-6 border-b border-gray-200">
|
<div class="flex items-center justify-between p-6 border-b border-gray-200">
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<div class="flex items-center text-sm text-gray-500 mb-2">
|
<div class="flex items-center text-sm text-gray-500 mb-2">
|
||||||
<Calendar :size="16" class="mr-2" />
|
<Calendar
|
||||||
|
:size="16"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
{{ formatDate(selectedNews.created) }}
|
{{ formatDate(selectedNews.created) }}
|
||||||
</div>
|
</div>
|
||||||
<h2 class="text-2xl font-display font-bold text-gray-900">
|
<h2 class="text-2xl font-display font-bold text-gray-900">
|
||||||
@@ -55,8 +67,8 @@
|
|||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
@click="closeNewsModal"
|
|
||||||
class="ml-4 p-2 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded-lg transition-colors"
|
class="ml-4 p-2 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded-lg transition-colors"
|
||||||
|
@click="closeNewsModal"
|
||||||
>
|
>
|
||||||
<X :size="24" />
|
<X :size="24" />
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -1,11 +1,23 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<label v-if="label" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
v-if="label"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
{{ label }}
|
{{ label }}
|
||||||
<span v-if="required" class="text-red-500">*</span>
|
<span
|
||||||
|
v-if="required"
|
||||||
|
class="text-red-500"
|
||||||
|
>*</span>
|
||||||
</label>
|
</label>
|
||||||
<div ref="editorContainer" class="border border-gray-300 rounded-lg bg-white"></div>
|
<div
|
||||||
<input type="hidden" :value="modelValue" />
|
ref="editorContainer"
|
||||||
|
class="border border-gray-300 rounded-lg bg-white"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
type="hidden"
|
||||||
|
:value="modelValue"
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -2,56 +2,137 @@
|
|||||||
<section class="py-16 bg-white">
|
<section class="py-16 bg-white">
|
||||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<div class="text-center mb-12">
|
<div class="text-center mb-12">
|
||||||
<h2 class="text-3xl font-bold text-gray-900 mb-4">Nächste Spiele</h2>
|
<h2 class="text-3xl font-bold text-gray-900 mb-4">
|
||||||
|
Nächste Spiele
|
||||||
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Loading State -->
|
<!-- Loading State -->
|
||||||
<div v-if="isLoading" class="text-center py-8">
|
<div
|
||||||
<svg class="w-8 h-8 text-gray-400 mx-auto mb-4 animate-spin" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
v-if="isLoading"
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
class="text-center py-8"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="w-8 h-8 text-gray-400 mx-auto mb-4 animate-spin"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<p class="text-gray-600">Spielplan wird geladen...</p>
|
<p class="text-gray-600">
|
||||||
|
Spielplan wird geladen...
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Error State -->
|
<!-- Error State -->
|
||||||
<div v-else-if="error" class="text-center py-8">
|
<div
|
||||||
<svg class="w-12 h-12 text-gray-400 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
v-else-if="error"
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
|
class="text-center py-8"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="w-12 h-12 text-gray-400 mx-auto mb-4"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M9 5H7a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<p class="text-gray-600 mb-4">{{ error }}</p>
|
<p class="text-gray-600 mb-4">
|
||||||
<NuxtLink to="/mannschaften/spielplaene" class="inline-flex items-center px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors">
|
{{ error }}
|
||||||
|
</p>
|
||||||
|
<NuxtLink
|
||||||
|
to="/mannschaften/spielplaene"
|
||||||
|
class="inline-flex items-center px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors"
|
||||||
|
>
|
||||||
Zum Spielplan
|
Zum Spielplan
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Empty State -->
|
<!-- Empty State -->
|
||||||
<div v-else-if="!upcomingGames || upcomingGames.length === 0" class="text-center py-8">
|
<div
|
||||||
<svg class="w-12 h-12 text-gray-400 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
v-else-if="!upcomingGames || upcomingGames.length === 0"
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
|
class="text-center py-8"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="w-12 h-12 text-gray-400 mx-auto mb-4"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M9 5H7a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<h3 class="text-lg font-medium text-gray-900 mb-2">Keine kommenden Spiele</h3>
|
<h3 class="text-lg font-medium text-gray-900 mb-2">
|
||||||
<p class="text-gray-600 mb-4">Derzeit sind keine Spiele geplant.</p>
|
Keine kommenden Spiele
|
||||||
<NuxtLink to="/mannschaften/spielplaene" class="inline-flex items-center px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors">
|
</h3>
|
||||||
|
<p class="text-gray-600 mb-4">
|
||||||
|
Derzeit sind keine Spiele geplant.
|
||||||
|
</p>
|
||||||
|
<NuxtLink
|
||||||
|
to="/mannschaften/spielplaene"
|
||||||
|
class="inline-flex items-center px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors"
|
||||||
|
>
|
||||||
Zum Spielplan
|
Zum Spielplan
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Games Grid -->
|
<!-- Games Grid -->
|
||||||
<div v-else class="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
|
<div
|
||||||
<div v-for="game in upcomingGames" :key="`${game.Termin}-${game.HeimMannschaft}`"
|
v-else
|
||||||
class="bg-white rounded-xl shadow-lg border border-gray-200 hover:shadow-xl transition-shadow">
|
class="grid gap-6 md:grid-cols-2 lg:grid-cols-3"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="game in upcomingGames"
|
||||||
|
:key="`${game.Termin}-${game.HeimMannschaft}`"
|
||||||
|
class="bg-white rounded-xl shadow-lg border border-gray-200 hover:shadow-xl transition-shadow"
|
||||||
|
>
|
||||||
<div class="p-6">
|
<div class="p-6">
|
||||||
<!-- Date and Time -->
|
<!-- Date and Time -->
|
||||||
<div class="flex items-center justify-between mb-4">
|
<div class="flex items-center justify-between mb-4">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<svg class="w-5 h-5 text-primary-600 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
class="w-5 h-5 text-primary-600 mr-2"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<span class="text-sm font-medium text-gray-900">{{ formatDate(game.Termin) }}</span>
|
<span class="text-sm font-medium text-gray-900">{{ formatDate(game.Termin) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center text-sm text-gray-600">
|
<div class="flex items-center text-sm text-gray-600">
|
||||||
<svg class="w-4 h-4 text-gray-400 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
class="w-4 h-4 text-gray-400 mr-1"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
{{ formatTime(game.Termin) }}
|
{{ formatTime(game.Termin) }}
|
||||||
</div>
|
</div>
|
||||||
@@ -61,8 +142,12 @@
|
|||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<p class="text-sm text-gray-600 mb-1">Heim</p>
|
<p class="text-sm text-gray-600 mb-1">
|
||||||
<p class="font-semibold text-gray-900">{{ formatTeamName(game.HeimMannschaft, game.HeimMannschaftAltersklasse) }}</p>
|
Heim
|
||||||
|
</p>
|
||||||
|
<p class="font-semibold text-gray-900">
|
||||||
|
{{ formatTeamName(game.HeimMannschaft, game.HeimMannschaftAltersklasse) }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-center mx-4">
|
<div class="text-center mx-4">
|
||||||
<div class="w-8 h-8 bg-primary-100 rounded-full flex items-center justify-center">
|
<div class="w-8 h-8 bg-primary-100 rounded-full flex items-center justify-center">
|
||||||
@@ -70,16 +155,33 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-1 text-right">
|
<div class="flex-1 text-right">
|
||||||
<p class="text-sm text-gray-600 mb-1">Gast</p>
|
<p class="text-sm text-gray-600 mb-1">
|
||||||
<p class="font-semibold text-gray-900">{{ formatTeamName(game.GastMannschaft, game.GastMannschaftAltersklasse) }}</p>
|
Gast
|
||||||
|
</p>
|
||||||
|
<p class="font-semibold text-gray-900">
|
||||||
|
{{ formatTeamName(game.GastMannschaft, game.GastMannschaftAltersklasse) }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Competition Info -->
|
<!-- Competition Info -->
|
||||||
<div v-if="game.Runde" class="flex items-center text-sm text-gray-600">
|
<div
|
||||||
<svg class="w-4 h-4 text-gray-400 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
v-if="game.Runde"
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
class="flex items-center text-sm text-gray-600"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="w-4 h-4 text-gray-400 mr-2"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
{{ formatRunde(game.Runde) }}
|
{{ formatRunde(game.Runde) }}
|
||||||
</div>
|
</div>
|
||||||
@@ -88,12 +190,27 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- View All Button -->
|
<!-- View All Button -->
|
||||||
<div v-if="upcomingGames && upcomingGames.length > 0" class="text-center mt-8">
|
<div
|
||||||
<NuxtLink to="/mannschaften/spielplaene"
|
v-if="upcomingGames && upcomingGames.length > 0"
|
||||||
class="inline-flex items-center px-6 py-3 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors">
|
class="text-center mt-8"
|
||||||
|
>
|
||||||
|
<NuxtLink
|
||||||
|
to="/mannschaften/spielplaene"
|
||||||
|
class="inline-flex items-center px-6 py-3 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors"
|
||||||
|
>
|
||||||
Alle Spiele anzeigen
|
Alle Spiele anzeigen
|
||||||
<svg class="w-4 h-4 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
class="w-4 h-4 ml-2"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M9 5l7 7-7 7"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,43 +1,60 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div v-if="naechsteTermine.length > 0" class="space-y-2 mb-6">
|
<div
|
||||||
<div
|
v-if="naechsteTermine.length > 0"
|
||||||
v-for="(termin, index) in naechsteTermine"
|
class="space-y-2 mb-6"
|
||||||
:key="index"
|
>
|
||||||
class="bg-gray-50 rounded-lg p-3 hover:bg-gray-100 transition-colors"
|
<div
|
||||||
>
|
v-for="(termin, index) in naechsteTermine"
|
||||||
<div class="flex items-center justify-between">
|
:key="index"
|
||||||
<div class="flex items-center space-x-3">
|
class="bg-gray-50 rounded-lg p-3 hover:bg-gray-100 transition-colors"
|
||||||
<div class="w-16 h-16 bg-primary-600 rounded-lg flex flex-col items-center justify-center text-white text-[10px] font-bold leading-tight py-1.5 px-1.5">
|
>
|
||||||
<span class="text-lg leading-none">{{ formatDay(termin.datum) }}</span>
|
<div class="flex items-center justify-between">
|
||||||
<span class="leading-none mt-0.5">{{ formatMonth(termin.datum) }}</span>
|
<div class="flex items-center space-x-3">
|
||||||
<span class="text-[10px] leading-none opacity-95 mt-0.5">{{ formatYear(termin.datum) }}</span>
|
<div class="w-16 h-16 bg-primary-600 rounded-lg flex flex-col items-center justify-center text-white text-[10px] font-bold leading-tight py-1.5 px-1.5">
|
||||||
<span
|
<span class="text-lg leading-none">{{ formatDay(termin.datum) }}</span>
|
||||||
v-if="termin.uhrzeit"
|
<span class="leading-none mt-0.5">{{ formatMonth(termin.datum) }}</span>
|
||||||
class="text-[10px] leading-none mt-1 px-2 py-0.5 rounded-md bg-white/40 ring-1 ring-white/50 backdrop-blur-[1.5px] whitespace-nowrap"
|
<span class="text-[10px] leading-none opacity-95 mt-0.5">{{ formatYear(termin.datum) }}</span>
|
||||||
>
|
<span
|
||||||
{{ formatOnlyTime(termin.uhrzeit) }} Uhr
|
v-if="termin.uhrzeit"
|
||||||
</span>
|
class="text-[10px] leading-none mt-1 px-2 py-0.5 rounded-md bg-white/40 ring-1 ring-white/50 backdrop-blur-[1.5px] whitespace-nowrap"
|
||||||
</div>
|
>
|
||||||
<div>
|
{{ formatOnlyTime(termin.uhrzeit) }} Uhr
|
||||||
<h3 class="font-semibold text-gray-900">{{ termin.titel }}</h3>
|
</span>
|
||||||
<p class="text-sm text-gray-600">{{ termin.beschreibung }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<span :class="[
|
<div>
|
||||||
|
<h3 class="font-semibold text-gray-900">
|
||||||
|
{{ termin.titel }}
|
||||||
|
</h3>
|
||||||
|
<p class="text-sm text-gray-600">
|
||||||
|
{{ termin.beschreibung }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
:class="[
|
||||||
'px-2 py-1 text-xs font-medium rounded-full',
|
'px-2 py-1 text-xs font-medium rounded-full',
|
||||||
termin.kategorie === 'Turnier' ? 'bg-yellow-100 text-yellow-800' : 'bg-blue-100 text-blue-800'
|
termin.kategorie === 'Turnier' ? 'bg-yellow-100 text-yellow-800' : 'bg-blue-100 text-blue-800'
|
||||||
]">
|
]"
|
||||||
{{ termin.kategorie }}
|
>
|
||||||
</span>
|
{{ termin.kategorie }}
|
||||||
</div>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div v-else class="text-center py-8 bg-gray-50 rounded-lg">
|
<div
|
||||||
<Calendar :size="32" class="text-gray-400 mx-auto mb-2" />
|
v-else
|
||||||
<p class="text-gray-600 text-sm">Keine kommenden Termine</p>
|
class="text-center py-8 bg-gray-50 rounded-lg"
|
||||||
</div>
|
>
|
||||||
|
<Calendar
|
||||||
|
:size="32"
|
||||||
|
class="text-gray-400 mx-auto mb-2"
|
||||||
|
/>
|
||||||
|
<p class="text-gray-600 text-sm">
|
||||||
|
Keine kommenden Termine
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
95
eslint.config.js
Normal file
95
eslint.config.js
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
import js from '@eslint/js'
|
||||||
|
import vue from 'eslint-plugin-vue'
|
||||||
|
import parser from 'vue-eslint-parser'
|
||||||
|
import globals from 'globals'
|
||||||
|
|
||||||
|
export default [
|
||||||
|
js.configs.recommended,
|
||||||
|
...vue.configs['flat/recommended'],
|
||||||
|
{
|
||||||
|
files: ['**/*.vue', '**/*.js'],
|
||||||
|
languageOptions: {
|
||||||
|
parser: parser,
|
||||||
|
ecmaVersion: 'latest',
|
||||||
|
sourceType: 'module',
|
||||||
|
globals: {
|
||||||
|
...globals.browser,
|
||||||
|
...globals.node,
|
||||||
|
...globals.es2021,
|
||||||
|
// Nuxt/Vue specific globals
|
||||||
|
'$fetch': 'readonly',
|
||||||
|
'useAuthStore': 'readonly',
|
||||||
|
'useRoute': 'readonly',
|
||||||
|
'useRouter': 'readonly',
|
||||||
|
'navigateTo': 'readonly',
|
||||||
|
'useHead': 'readonly',
|
||||||
|
'useFetch': 'readonly',
|
||||||
|
'definePageMeta': 'readonly',
|
||||||
|
'defineNuxtRouteMiddleware': 'readonly',
|
||||||
|
'defineEventHandler': 'readonly',
|
||||||
|
'readBody': 'readonly',
|
||||||
|
'getCookie': 'readonly',
|
||||||
|
'setCookie': 'readonly',
|
||||||
|
'deleteCookie': 'readonly',
|
||||||
|
'getHeader': 'readonly',
|
||||||
|
'getRouterParam': 'readonly',
|
||||||
|
'getQuery': 'readonly',
|
||||||
|
'sendStream': 'readonly',
|
||||||
|
'sendRedirect': 'readonly',
|
||||||
|
'createError': 'readonly',
|
||||||
|
'useRuntimeConfig': 'readonly',
|
||||||
|
'process': 'readonly',
|
||||||
|
// Vue Composition API
|
||||||
|
'onUnmounted': 'readonly',
|
||||||
|
'provide': 'readonly',
|
||||||
|
'inject': 'readonly',
|
||||||
|
'ref': 'readonly',
|
||||||
|
'reactive': 'readonly',
|
||||||
|
'computed': 'readonly',
|
||||||
|
'watch': 'readonly',
|
||||||
|
'onMounted': 'readonly',
|
||||||
|
'defineComponent': 'readonly',
|
||||||
|
'defineProps': 'readonly',
|
||||||
|
'defineEmits': 'readonly',
|
||||||
|
'defineExpose': 'readonly'
|
||||||
|
},
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: 'latest',
|
||||||
|
sourceType: 'module'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
'vue/multi-word-component-names': 'off',
|
||||||
|
'vue/no-v-html': 'warn',
|
||||||
|
'no-unused-vars': ['warn', {
|
||||||
|
argsIgnorePattern: '^_',
|
||||||
|
varsIgnorePattern: '^_'
|
||||||
|
}],
|
||||||
|
'vue/no-unused-vars': ['warn', {
|
||||||
|
ignorePattern: '^_'
|
||||||
|
}],
|
||||||
|
'no-undef': 'warn',
|
||||||
|
'no-console': 'off'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ignores: [
|
||||||
|
'node_modules/**',
|
||||||
|
'.output/**',
|
||||||
|
'.nuxt/**',
|
||||||
|
'.next/**',
|
||||||
|
'dist/**',
|
||||||
|
'build/**',
|
||||||
|
'*.config.js',
|
||||||
|
'*.config.ts',
|
||||||
|
'*.config.cjs',
|
||||||
|
'*.cjs',
|
||||||
|
'temp/**',
|
||||||
|
'backups/**',
|
||||||
|
'public/**',
|
||||||
|
'tests/**',
|
||||||
|
'scripts/**'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
24
package-lock.json
generated
24
package-lock.json
generated
@@ -29,6 +29,7 @@
|
|||||||
"autoprefixer": "^10.4.0",
|
"autoprefixer": "^10.4.0",
|
||||||
"dotenv": "^17.2.3",
|
"dotenv": "^17.2.3",
|
||||||
"eslint-plugin-vue": "^10.6.2",
|
"eslint-plugin-vue": "^10.6.2",
|
||||||
|
"globals": "^16.5.0",
|
||||||
"lucide-vue-next": "^0.344.0",
|
"lucide-vue-next": "^0.344.0",
|
||||||
"postcss": "^8.4.0",
|
"postcss": "^8.4.0",
|
||||||
"supertest": "^7.1.0",
|
"supertest": "^7.1.0",
|
||||||
@@ -1114,6 +1115,20 @@
|
|||||||
"concat-map": "0.0.1"
|
"concat-map": "0.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@eslint/eslintrc/node_modules/globals": {
|
||||||
|
"version": "14.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
|
||||||
|
"integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
|
||||||
|
"devOptional": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@eslint/eslintrc/node_modules/ignore": {
|
"node_modules/@eslint/eslintrc/node_modules/ignore": {
|
||||||
"version": "5.3.2",
|
"version": "5.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
||||||
@@ -7599,12 +7614,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/globals": {
|
"node_modules/globals": {
|
||||||
"version": "14.0.0",
|
"version": "16.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz",
|
||||||
"integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
|
"integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
"postinstall": "nuxt prepare",
|
"postinstall": "nuxt prepare",
|
||||||
"test": "vitest run",
|
"test": "vitest run",
|
||||||
"test:watch": "vitest watch",
|
"test:watch": "vitest watch",
|
||||||
"lint": "eslint . --ext .js,.vue --fix"
|
"lint": "eslint . --fix"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@pinia/nuxt": "^0.11.2",
|
"@pinia/nuxt": "^0.11.2",
|
||||||
@@ -36,6 +36,7 @@
|
|||||||
"autoprefixer": "^10.4.0",
|
"autoprefixer": "^10.4.0",
|
||||||
"dotenv": "^17.2.3",
|
"dotenv": "^17.2.3",
|
||||||
"eslint-plugin-vue": "^10.6.2",
|
"eslint-plugin-vue": "^10.6.2",
|
||||||
|
"globals": "^16.5.0",
|
||||||
"lucide-vue-next": "^0.344.0",
|
"lucide-vue-next": "^0.344.0",
|
||||||
"postcss": "^8.4.0",
|
"postcss": "^8.4.0",
|
||||||
"supertest": "^7.1.0",
|
"supertest": "^7.1.0",
|
||||||
|
|||||||
@@ -17,9 +17,15 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Pending Users -->
|
<!-- Pending Users -->
|
||||||
<div v-if="pendingUsers.length > 0" class="mb-8">
|
<div
|
||||||
|
v-if="pendingUsers.length > 0"
|
||||||
|
class="mb-8"
|
||||||
|
>
|
||||||
<h2 class="text-2xl font-display font-bold text-gray-900 mb-4">
|
<h2 class="text-2xl font-display font-bold text-gray-900 mb-4">
|
||||||
<AlertCircle :size="24" class="inline text-yellow-600 mr-2" />
|
<AlertCircle
|
||||||
|
:size="24"
|
||||||
|
class="inline text-yellow-600 mr-2"
|
||||||
|
/>
|
||||||
Wartende Registrierungen ({{ pendingUsers.length }})
|
Wartende Registrierungen ({{ pendingUsers.length }})
|
||||||
</h2>
|
</h2>
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
@@ -30,9 +36,18 @@
|
|||||||
>
|
>
|
||||||
<div class="flex items-start justify-between">
|
<div class="flex items-start justify-between">
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<h3 class="text-lg font-semibold text-gray-900">{{ user.name }}</h3>
|
<h3 class="text-lg font-semibold text-gray-900">
|
||||||
<p class="text-sm text-gray-600 mt-1">{{ user.email }}</p>
|
{{ user.name }}
|
||||||
<p v-if="user.phone" class="text-sm text-gray-600">{{ user.phone }}</p>
|
</h3>
|
||||||
|
<p class="text-sm text-gray-600 mt-1">
|
||||||
|
{{ user.email }}
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
v-if="user.phone"
|
||||||
|
class="text-sm text-gray-600"
|
||||||
|
>
|
||||||
|
{{ user.phone }}
|
||||||
|
</p>
|
||||||
<p class="text-xs text-gray-500 mt-2">
|
<p class="text-xs text-gray-500 mt-2">
|
||||||
Registriert am: {{ formatDate(user.created) }}
|
Registriert am: {{ formatDate(user.created) }}
|
||||||
</p>
|
</p>
|
||||||
@@ -43,27 +58,41 @@
|
|||||||
v-model="user.selectedRole"
|
v-model="user.selectedRole"
|
||||||
class="px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-primary-600"
|
class="px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-primary-600"
|
||||||
>
|
>
|
||||||
<option value="mitglied">Mitglied</option>
|
<option value="mitglied">
|
||||||
<option value="vorstand">Vorstand</option>
|
Mitglied
|
||||||
<option value="admin">Administrator</option>
|
</option>
|
||||||
<option value="newsletter">Newsletter</option>
|
<option value="vorstand">
|
||||||
|
Vorstand
|
||||||
|
</option>
|
||||||
|
<option value="admin">
|
||||||
|
Administrator
|
||||||
|
</option>
|
||||||
|
<option value="newsletter">
|
||||||
|
Newsletter
|
||||||
|
</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<!-- Approve Button -->
|
<!-- Approve Button -->
|
||||||
<button
|
<button
|
||||||
@click="approveUser(user)"
|
|
||||||
class="px-4 py-2 bg-green-600 hover:bg-green-700 text-white text-sm font-semibold rounded-lg transition-colors flex items-center justify-center"
|
class="px-4 py-2 bg-green-600 hover:bg-green-700 text-white text-sm font-semibold rounded-lg transition-colors flex items-center justify-center"
|
||||||
|
@click="approveUser(user)"
|
||||||
>
|
>
|
||||||
<Check :size="16" class="mr-1" />
|
<Check
|
||||||
|
:size="16"
|
||||||
|
class="mr-1"
|
||||||
|
/>
|
||||||
Freischalten
|
Freischalten
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!-- Reject Button -->
|
<!-- Reject Button -->
|
||||||
<button
|
<button
|
||||||
@click="rejectUser(user)"
|
|
||||||
class="px-4 py-2 bg-red-600 hover:bg-red-700 text-white text-sm font-semibold rounded-lg transition-colors flex items-center justify-center"
|
class="px-4 py-2 bg-red-600 hover:bg-red-700 text-white text-sm font-semibold rounded-lg transition-colors flex items-center justify-center"
|
||||||
|
@click="rejectUser(user)"
|
||||||
>
|
>
|
||||||
<X :size="16" class="mr-1" />
|
<X
|
||||||
|
:size="16"
|
||||||
|
class="mr-1"
|
||||||
|
/>
|
||||||
Ablehnen
|
Ablehnen
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -102,15 +131,25 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="bg-white divide-y divide-gray-200">
|
<tbody class="bg-white divide-y divide-gray-200">
|
||||||
<tr v-for="user in activeUsers" :key="user.id" class="hover:bg-gray-50">
|
<tr
|
||||||
|
v-for="user in activeUsers"
|
||||||
|
:key="user.id"
|
||||||
|
class="hover:bg-gray-50"
|
||||||
|
>
|
||||||
<td class="px-6 py-4 whitespace-nowrap">
|
<td class="px-6 py-4 whitespace-nowrap">
|
||||||
<div class="text-sm font-medium text-gray-900">{{ user.name }}</div>
|
<div class="text-sm font-medium text-gray-900">
|
||||||
|
{{ user.name }}
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="px-6 py-4 whitespace-nowrap">
|
<td class="px-6 py-4 whitespace-nowrap">
|
||||||
<div class="text-sm text-gray-600">{{ user.email }}</div>
|
<div class="text-sm text-gray-600">
|
||||||
|
{{ user.email }}
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="px-6 py-4 whitespace-nowrap">
|
<td class="px-6 py-4 whitespace-nowrap">
|
||||||
<div class="text-sm text-gray-600">{{ user.phone || '-' }}</div>
|
<div class="text-sm text-gray-600">
|
||||||
|
{{ user.phone || '-' }}
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="px-6 py-4 whitespace-nowrap">
|
<td class="px-6 py-4 whitespace-nowrap">
|
||||||
<div class="flex flex-wrap gap-1">
|
<div class="flex flex-wrap gap-1">
|
||||||
@@ -129,8 +168,8 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
@click="openRoleModal(user)"
|
|
||||||
class="mt-1 text-xs text-primary-600 hover:text-primary-800"
|
class="mt-1 text-xs text-primary-600 hover:text-primary-800"
|
||||||
|
@click="openRoleModal(user)"
|
||||||
>
|
>
|
||||||
Bearbeiten
|
Bearbeiten
|
||||||
</button>
|
</button>
|
||||||
@@ -143,12 +182,15 @@
|
|||||||
<td class="px-6 py-4 whitespace-nowrap text-right text-sm">
|
<td class="px-6 py-4 whitespace-nowrap text-right text-sm">
|
||||||
<button
|
<button
|
||||||
v-if="user.id !== currentUserId"
|
v-if="user.id !== currentUserId"
|
||||||
@click="deactivateUser(user)"
|
|
||||||
class="text-red-600 hover:text-red-800 font-medium"
|
class="text-red-600 hover:text-red-800 font-medium"
|
||||||
|
@click="deactivateUser(user)"
|
||||||
>
|
>
|
||||||
Deaktivieren
|
Deaktivieren
|
||||||
</button>
|
</button>
|
||||||
<span v-else class="text-gray-400">Eigenes Konto</span>
|
<span
|
||||||
|
v-else
|
||||||
|
class="text-gray-400"
|
||||||
|
>Eigenes Konto</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
@@ -157,15 +199,27 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Success/Error Messages -->
|
<!-- Success/Error Messages -->
|
||||||
<div v-if="successMessage" class="fixed bottom-20 right-4 bg-green-50 border border-green-200 rounded-lg p-4 shadow-lg">
|
<div
|
||||||
|
v-if="successMessage"
|
||||||
|
class="fixed bottom-20 right-4 bg-green-50 border border-green-200 rounded-lg p-4 shadow-lg"
|
||||||
|
>
|
||||||
<p class="text-sm text-green-800 flex items-center">
|
<p class="text-sm text-green-800 flex items-center">
|
||||||
<Check :size="18" class="mr-2" />
|
<Check
|
||||||
|
:size="18"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
{{ successMessage }}
|
{{ successMessage }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="errorMessage" class="fixed bottom-20 right-4 bg-red-50 border border-red-200 rounded-lg p-4 shadow-lg">
|
<div
|
||||||
|
v-if="errorMessage"
|
||||||
|
class="fixed bottom-20 right-4 bg-red-50 border border-red-200 rounded-lg p-4 shadow-lg"
|
||||||
|
>
|
||||||
<p class="text-sm text-red-800 flex items-center">
|
<p class="text-sm text-red-800 flex items-center">
|
||||||
<AlertCircle :size="18" class="mr-2" />
|
<AlertCircle
|
||||||
|
:size="18"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
{{ errorMessage }}
|
{{ errorMessage }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -185,58 +239,61 @@
|
|||||||
<div class="space-y-3 mb-6">
|
<div class="space-y-3 mb-6">
|
||||||
<label class="flex items-center">
|
<label class="flex items-center">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
|
||||||
v-model="selectedRoles"
|
v-model="selectedRoles"
|
||||||
|
type="checkbox"
|
||||||
value="mitglied"
|
value="mitglied"
|
||||||
class="h-4 w-4 text-primary-600 focus:ring-primary-500 border-gray-300 rounded"
|
class="h-4 w-4 text-primary-600 focus:ring-primary-500 border-gray-300 rounded"
|
||||||
/>
|
>
|
||||||
<span class="ml-2 text-sm text-gray-700">Mitglied</span>
|
<span class="ml-2 text-sm text-gray-700">Mitglied</span>
|
||||||
</label>
|
</label>
|
||||||
<label class="flex items-center">
|
<label class="flex items-center">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
|
||||||
v-model="selectedRoles"
|
v-model="selectedRoles"
|
||||||
|
type="checkbox"
|
||||||
value="vorstand"
|
value="vorstand"
|
||||||
class="h-4 w-4 text-primary-600 focus:ring-primary-500 border-gray-300 rounded"
|
class="h-4 w-4 text-primary-600 focus:ring-primary-500 border-gray-300 rounded"
|
||||||
/>
|
>
|
||||||
<span class="ml-2 text-sm text-gray-700">Vorstand</span>
|
<span class="ml-2 text-sm text-gray-700">Vorstand</span>
|
||||||
</label>
|
</label>
|
||||||
<label class="flex items-center">
|
<label class="flex items-center">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
|
||||||
v-model="selectedRoles"
|
v-model="selectedRoles"
|
||||||
|
type="checkbox"
|
||||||
value="newsletter"
|
value="newsletter"
|
||||||
class="h-4 w-4 text-primary-600 focus:ring-primary-500 border-gray-300 rounded"
|
class="h-4 w-4 text-primary-600 focus:ring-primary-500 border-gray-300 rounded"
|
||||||
/>
|
>
|
||||||
<span class="ml-2 text-sm text-gray-700">Newsletter</span>
|
<span class="ml-2 text-sm text-gray-700">Newsletter</span>
|
||||||
</label>
|
</label>
|
||||||
<label class="flex items-center">
|
<label class="flex items-center">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
|
||||||
v-model="selectedRoles"
|
v-model="selectedRoles"
|
||||||
|
type="checkbox"
|
||||||
value="admin"
|
value="admin"
|
||||||
class="h-4 w-4 text-primary-600 focus:ring-primary-500 border-gray-300 rounded"
|
class="h-4 w-4 text-primary-600 focus:ring-primary-500 border-gray-300 rounded"
|
||||||
/>
|
>
|
||||||
<span class="ml-2 text-sm text-gray-700">Administrator</span>
|
<span class="ml-2 text-sm text-gray-700">Administrator</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="selectedRoles.length === 0" class="mb-4 text-sm text-red-600">
|
<div
|
||||||
|
v-if="selectedRoles.length === 0"
|
||||||
|
class="mb-4 text-sm text-red-600"
|
||||||
|
>
|
||||||
Mindestens eine Rolle muss ausgewählt werden.
|
Mindestens eine Rolle muss ausgewählt werden.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-end space-x-3">
|
<div class="flex justify-end space-x-3">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@click="closeRoleModal"
|
|
||||||
class="px-4 py-2 text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors"
|
class="px-4 py-2 text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors"
|
||||||
|
@click="closeRoleModal"
|
||||||
>
|
>
|
||||||
Abbrechen
|
Abbrechen
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@click="saveUserRoles"
|
|
||||||
:disabled="selectedRoles.length === 0"
|
:disabled="selectedRoles.length === 0"
|
||||||
class="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
class="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
|
@click="saveUserRoles"
|
||||||
>
|
>
|
||||||
Speichern
|
Speichern
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -12,11 +12,15 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="space-x-3">
|
<div class="space-x-3">
|
||||||
<button
|
<button
|
||||||
@click="saveConfig"
|
|
||||||
class="inline-flex items-center px-3 py-1.5 sm:px-4 sm:py-2 rounded-lg bg-primary-600 text-white hover:bg-primary-700 disabled:opacity-50 disabled:cursor-not-allowed text-sm sm:text-base"
|
class="inline-flex items-center px-3 py-1.5 sm:px-4 sm:py-2 rounded-lg bg-primary-600 text-white hover:bg-primary-700 disabled:opacity-50 disabled:cursor-not-allowed text-sm sm:text-base"
|
||||||
:disabled="isSaving"
|
:disabled="isSaving"
|
||||||
|
@click="saveConfig"
|
||||||
>
|
>
|
||||||
<Loader2 v-if="isSaving" :size="16" class="animate-spin mr-2" />
|
<Loader2
|
||||||
|
v-if="isSaving"
|
||||||
|
:size="16"
|
||||||
|
class="animate-spin mr-2"
|
||||||
|
/>
|
||||||
{{ isSaving ? 'Speichern...' : 'Speichern' }}
|
{{ isSaving ? 'Speichern...' : 'Speichern' }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -27,478 +31,532 @@
|
|||||||
<!-- Content with top padding -->
|
<!-- Content with top padding -->
|
||||||
<div class="pt-28 sm:pt-32 pb-16">
|
<div class="pt-28 sm:pt-32 pb-16">
|
||||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<!-- Loading State -->
|
||||||
|
<div
|
||||||
|
v-if="isLoading"
|
||||||
|
class="flex items-center justify-center py-12"
|
||||||
|
>
|
||||||
|
<Loader2
|
||||||
|
:size="40"
|
||||||
|
class="animate-spin text-primary-600"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Loading State -->
|
<div
|
||||||
<div v-if="isLoading" class="flex items-center justify-center py-12">
|
v-else
|
||||||
<Loader2 :size="40" class="animate-spin text-primary-600" />
|
class="space-y-6"
|
||||||
</div>
|
>
|
||||||
|
<!-- Tabs -->
|
||||||
<div v-else class="space-y-6">
|
<div class="bg-white rounded-xl shadow-lg border border-gray-100 overflow-hidden">
|
||||||
<!-- Tabs -->
|
<div class="flex border-b border-gray-200">
|
||||||
<div class="bg-white rounded-xl shadow-lg border border-gray-100 overflow-hidden">
|
<button
|
||||||
<div class="flex border-b border-gray-200">
|
v-for="tab in tabs"
|
||||||
<button
|
:key="tab.id"
|
||||||
v-for="tab in tabs"
|
:class="[
|
||||||
:key="tab.id"
|
'flex-1 px-6 py-4 text-sm font-medium transition-colors',
|
||||||
@click="activeTab = tab.id"
|
activeTab === tab.id
|
||||||
:class="[
|
? 'bg-primary-600 text-white'
|
||||||
'flex-1 px-6 py-4 text-sm font-medium transition-colors',
|
: 'bg-gray-50 text-gray-700 hover:bg-gray-100'
|
||||||
activeTab === tab.id
|
]"
|
||||||
? 'bg-primary-600 text-white'
|
@click="activeTab = tab.id"
|
||||||
: 'bg-gray-50 text-gray-700 hover:bg-gray-100'
|
>
|
||||||
]"
|
<component
|
||||||
>
|
:is="tab.icon"
|
||||||
<component :is="tab.icon" :size="18" class="inline mr-2" />
|
:size="18"
|
||||||
{{ tab.label }}
|
class="inline mr-2"
|
||||||
</button>
|
/>
|
||||||
</div>
|
{{ tab.label }}
|
||||||
|
</button>
|
||||||
<!-- Tab Content -->
|
|
||||||
<div class="p-8">
|
|
||||||
<!-- Vereinsdaten -->
|
|
||||||
<div v-if="activeTab === 'verein'">
|
|
||||||
<h2 class="text-2xl font-display font-bold text-gray-900 mb-6">Vereinsdaten</h2>
|
|
||||||
|
|
||||||
<div class="space-y-6">
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Vereinsname</label>
|
|
||||||
<input
|
|
||||||
v-model="config.verein.name"
|
|
||||||
type="text"
|
|
||||||
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="p-4 bg-blue-50 rounded-lg border border-blue-200">
|
|
||||||
<label class="flex items-center cursor-pointer">
|
|
||||||
<input
|
|
||||||
v-model="config.verein.useVorsitzenderAddress"
|
|
||||||
type="checkbox"
|
|
||||||
class="w-5 h-5 text-primary-600 border-gray-300 rounded focus:ring-primary-500"
|
|
||||||
/>
|
|
||||||
<span class="ml-3 text-sm font-medium text-gray-900">
|
|
||||||
Adresse des 1. Vorsitzenden als Vereinsadresse verwenden
|
|
||||||
</span>
|
|
||||||
</label>
|
|
||||||
<p class="text-xs text-gray-600 mt-2 ml-8">
|
|
||||||
Wenn deaktiviert, können Sie unten eine separate Vereinsadresse angeben.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="!config.verein.useVorsitzenderAddress" class="p-6 bg-gray-50 rounded-lg border border-gray-200">
|
|
||||||
<h3 class="text-lg font-semibold text-gray-900 mb-4">Separate Vereinsadresse</h3>
|
|
||||||
<div class="grid sm:grid-cols-2 gap-4">
|
|
||||||
<div class="sm:col-span-2">
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Straße & Hausnummer</label>
|
|
||||||
<input
|
|
||||||
v-model="config.verein.strasse"
|
|
||||||
type="text"
|
|
||||||
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>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">PLZ</label>
|
|
||||||
<input
|
|
||||||
v-model="config.verein.plz"
|
|
||||||
type="text"
|
|
||||||
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>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Ort</label>
|
|
||||||
<input
|
|
||||||
v-model="config.verein.ort"
|
|
||||||
type="text"
|
|
||||||
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>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Trainingszeiten -->
|
<!-- Tab Content -->
|
||||||
<div v-if="activeTab === 'training'">
|
<div class="p-8">
|
||||||
<h2 class="text-2xl font-display font-bold text-gray-900 mb-6">Trainingszeiten & Trainingsort</h2>
|
<!-- Vereinsdaten -->
|
||||||
|
<div v-if="activeTab === 'verein'">
|
||||||
|
<h2 class="text-2xl font-display font-bold text-gray-900 mb-6">
|
||||||
|
Vereinsdaten
|
||||||
|
</h2>
|
||||||
|
|
||||||
<!-- Trainingsort -->
|
<div class="space-y-6">
|
||||||
<div class="mb-8 p-6 bg-gray-50 rounded-lg">
|
|
||||||
<h3 class="text-lg font-semibold text-gray-900 mb-4">Trainingsort</h3>
|
|
||||||
<div class="grid sm:grid-cols-2 gap-4">
|
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Name</label>
|
<label class="block text-sm font-medium text-gray-700 mb-2">Vereinsname</label>
|
||||||
<input
|
<input
|
||||||
v-model="config.training.ort.name"
|
v-model="config.verein.name"
|
||||||
type="text"
|
type="text"
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
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>
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Straße</label>
|
<div class="p-4 bg-blue-50 rounded-lg border border-blue-200">
|
||||||
<input
|
<label class="flex items-center cursor-pointer">
|
||||||
v-model="config.training.ort.strasse"
|
<input
|
||||||
type="text"
|
v-model="config.verein.useVorsitzenderAddress"
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
type="checkbox"
|
||||||
/>
|
class="w-5 h-5 text-primary-600 border-gray-300 rounded focus:ring-primary-500"
|
||||||
|
>
|
||||||
|
<span class="ml-3 text-sm font-medium text-gray-900">
|
||||||
|
Adresse des 1. Vorsitzenden als Vereinsadresse verwenden
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<p class="text-xs text-gray-600 mt-2 ml-8">
|
||||||
|
Wenn deaktiviert, können Sie unten eine separate Vereinsadresse angeben.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">PLZ</label>
|
<div
|
||||||
<input
|
v-if="!config.verein.useVorsitzenderAddress"
|
||||||
v-model="config.training.ort.plz"
|
class="p-6 bg-gray-50 rounded-lg border border-gray-200"
|
||||||
type="text"
|
>
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
<h3 class="text-lg font-semibold text-gray-900 mb-4">
|
||||||
/>
|
Separate Vereinsadresse
|
||||||
</div>
|
</h3>
|
||||||
<div>
|
<div class="grid sm:grid-cols-2 gap-4">
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Ort</label>
|
<div class="sm:col-span-2">
|
||||||
<input
|
<label class="block text-sm font-medium text-gray-700 mb-2">Straße & Hausnummer</label>
|
||||||
v-model="config.training.ort.ort"
|
<input
|
||||||
type="text"
|
v-model="config.verein.strasse"
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
type="text"
|
||||||
/>
|
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>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">PLZ</label>
|
||||||
|
<input
|
||||||
|
v-model="config.verein.plz"
|
||||||
|
type="text"
|
||||||
|
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>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Ort</label>
|
||||||
|
<input
|
||||||
|
v-model="config.verein.ort"
|
||||||
|
type="text"
|
||||||
|
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>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Trainingszeiten -->
|
<!-- Trainingszeiten -->
|
||||||
<div>
|
<div v-if="activeTab === 'training'">
|
||||||
<div class="flex justify-between items-center mb-4">
|
<h2 class="text-2xl font-display font-bold text-gray-900 mb-6">
|
||||||
<h3 class="text-lg font-semibold text-gray-900">Trainingszeiten</h3>
|
Trainingszeiten & Trainingsort
|
||||||
<button
|
</h2>
|
||||||
@click="addTrainingTime"
|
|
||||||
class="flex items-center px-3 py-1 bg-primary-600 hover:bg-primary-700 text-white text-sm rounded-lg transition-colors"
|
|
||||||
>
|
|
||||||
<Plus :size="16" class="mr-1" />
|
|
||||||
Zeit hinzufügen
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="space-y-4">
|
<!-- Trainingsort -->
|
||||||
<div
|
<div class="mb-8 p-6 bg-gray-50 rounded-lg">
|
||||||
v-for="(zeit, index) in config.training.zeiten"
|
<h3 class="text-lg font-semibold text-gray-900 mb-4">
|
||||||
:key="zeit.id"
|
Trainingsort
|
||||||
class="p-4 bg-gray-50 rounded-lg border border-gray-200"
|
</h3>
|
||||||
>
|
|
||||||
<div class="grid sm:grid-cols-4 gap-4">
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Tag</label>
|
|
||||||
<select
|
|
||||||
v-model="zeit.tag"
|
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
|
||||||
>
|
|
||||||
<option>Montag</option>
|
|
||||||
<option>Dienstag</option>
|
|
||||||
<option>Mittwoch</option>
|
|
||||||
<option>Donnerstag</option>
|
|
||||||
<option>Freitag</option>
|
|
||||||
<option>Samstag</option>
|
|
||||||
<option>Sonntag</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Von</label>
|
|
||||||
<input
|
|
||||||
v-model="zeit.von"
|
|
||||||
type="time"
|
|
||||||
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>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Bis</label>
|
|
||||||
<input
|
|
||||||
v-model="zeit.bis"
|
|
||||||
type="time"
|
|
||||||
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>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Gruppe</label>
|
|
||||||
<input
|
|
||||||
v-model="zeit.gruppe"
|
|
||||||
type="text"
|
|
||||||
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>
|
|
||||||
<div class="mt-4">
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Zusätzliche Information (optional)</label>
|
|
||||||
<div class="flex space-x-2">
|
|
||||||
<input
|
|
||||||
v-model="zeit.info"
|
|
||||||
type="text"
|
|
||||||
placeholder="z.B. 'Nur in der Schulzeit', 'Ab 10 Jahren', etc."
|
|
||||||
class="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
@click="removeTrainingTime(index)"
|
|
||||||
class="px-3 py-2 text-red-600 hover:bg-red-50 rounded-lg transition-colors"
|
|
||||||
title="Löschen"
|
|
||||||
>
|
|
||||||
<Trash2 :size="18" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Trainer -->
|
|
||||||
<div v-if="activeTab === 'trainer'">
|
|
||||||
<div class="flex justify-between items-center mb-6">
|
|
||||||
<h2 class="text-2xl font-display font-bold text-gray-900">Trainer</h2>
|
|
||||||
<button
|
|
||||||
@click="addTrainer"
|
|
||||||
class="flex items-center px-4 py-2 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors"
|
|
||||||
>
|
|
||||||
<Plus :size="20" class="mr-2" />
|
|
||||||
Trainer hinzufügen
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="space-y-6">
|
|
||||||
<div
|
|
||||||
v-for="(trainer, index) in config.trainer"
|
|
||||||
:key="trainer.id"
|
|
||||||
class="p-6 bg-gray-50 rounded-lg border border-gray-200"
|
|
||||||
>
|
|
||||||
<div class="grid sm:grid-cols-2 gap-4">
|
<div class="grid sm:grid-cols-2 gap-4">
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Name</label>
|
<label class="block text-sm font-medium text-gray-700 mb-2">Name</label>
|
||||||
<input
|
<input
|
||||||
v-model="trainer.name"
|
v-model="config.training.ort.name"
|
||||||
type="text"
|
type="text"
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
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>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Lizenz</label>
|
|
||||||
<input
|
|
||||||
v-model="trainer.lizenz"
|
|
||||||
type="text"
|
|
||||||
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>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Schwerpunkt</label>
|
|
||||||
<input
|
|
||||||
v-model="trainer.schwerpunkt"
|
|
||||||
type="text"
|
|
||||||
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>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Zusatzinfo</label>
|
|
||||||
<div class="flex space-x-2">
|
|
||||||
<input
|
|
||||||
v-model="trainer.zusatz"
|
|
||||||
type="text"
|
|
||||||
class="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
@click="removeTrainer(index)"
|
|
||||||
class="px-3 py-2 text-red-600 hover:bg-red-50 rounded-lg transition-colors"
|
|
||||||
title="Löschen"
|
|
||||||
>
|
|
||||||
<Trash2 :size="18" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="sm:col-span-2">
|
|
||||||
<ImageUpload
|
|
||||||
v-model="trainer.imageFilename"
|
|
||||||
label="Foto"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Mitgliedschaft -->
|
|
||||||
<div v-if="activeTab === 'mitgliedschaft'">
|
|
||||||
<div class="flex justify-between items-center mb-6">
|
|
||||||
<h2 class="text-2xl font-display font-bold text-gray-900">Mitgliedschaftsoptionen</h2>
|
|
||||||
<button
|
|
||||||
@click="addMembership"
|
|
||||||
class="flex items-center px-4 py-2 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors"
|
|
||||||
>
|
|
||||||
<Plus :size="20" class="mr-2" />
|
|
||||||
Option hinzufügen
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="space-y-6">
|
|
||||||
<div
|
|
||||||
v-for="(membership, index) in config.mitgliedschaft"
|
|
||||||
:key="membership.id"
|
|
||||||
class="p-6 bg-gray-50 rounded-lg border border-gray-200"
|
|
||||||
>
|
|
||||||
<div class="grid sm:grid-cols-3 gap-4 mb-4">
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Typ</label>
|
|
||||||
<input
|
|
||||||
v-model="membership.typ"
|
|
||||||
type="text"
|
|
||||||
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>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Beschreibung</label>
|
|
||||||
<input
|
|
||||||
v-model="membership.beschreibung"
|
|
||||||
type="text"
|
|
||||||
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>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Preis (€/Jahr)</label>
|
|
||||||
<div class="flex space-x-2">
|
|
||||||
<input
|
|
||||||
v-model.number="membership.preis"
|
|
||||||
type="number"
|
|
||||||
class="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
@click="removeMembership(index)"
|
|
||||||
class="px-3 py-2 text-red-600 hover:bg-red-50 rounded-lg transition-colors"
|
|
||||||
title="Löschen"
|
|
||||||
>
|
|
||||||
<Trash2 :size="18" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Features -->
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Leistungen</label>
|
|
||||||
<div class="space-y-2">
|
|
||||||
<div
|
|
||||||
v-for="(feature, fIndex) in membership.features"
|
|
||||||
:key="fIndex"
|
|
||||||
class="flex space-x-2"
|
|
||||||
>
|
>
|
||||||
<input
|
</div>
|
||||||
v-model="membership.features[fIndex]"
|
<div>
|
||||||
type="text"
|
<label class="block text-sm font-medium text-gray-700 mb-2">Straße</label>
|
||||||
class="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
<input
|
||||||
/>
|
v-model="config.training.ort.strasse"
|
||||||
<button
|
type="text"
|
||||||
@click="membership.features.splice(fIndex, 1)"
|
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||||
class="px-3 py-2 text-red-600 hover:bg-red-50 rounded-lg transition-colors"
|
|
||||||
>
|
|
||||||
<X :size="18" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
@click="membership.features.push('')"
|
|
||||||
class="flex items-center px-3 py-1 text-primary-600 hover:bg-primary-50 rounded-lg transition-colors text-sm"
|
|
||||||
>
|
>
|
||||||
<Plus :size="16" class="mr-1" />
|
|
||||||
Leistung hinzufügen
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Vorstand -->
|
|
||||||
<div v-if="activeTab === 'vorstand'">
|
|
||||||
<h2 class="text-2xl font-display font-bold text-gray-900 mb-6">Vorstandsdaten</h2>
|
|
||||||
|
|
||||||
<div class="space-y-8">
|
|
||||||
<div
|
|
||||||
v-for="(position, key) in config.vorstand"
|
|
||||||
:key="key"
|
|
||||||
class="p-6 bg-gray-50 rounded-lg border border-gray-200"
|
|
||||||
>
|
|
||||||
<h3 class="text-lg font-semibold text-gray-900 mb-4 capitalize">
|
|
||||||
{{ formatPositionName(key) }}
|
|
||||||
</h3>
|
|
||||||
<div class="grid sm:grid-cols-2 gap-4">
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Vorname</label>
|
|
||||||
<input
|
|
||||||
v-model="position.vorname"
|
|
||||||
type="text"
|
|
||||||
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>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Nachname</label>
|
|
||||||
<input
|
|
||||||
v-model="position.nachname"
|
|
||||||
type="text"
|
|
||||||
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">
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Straße & Hausnummer</label>
|
|
||||||
<input
|
|
||||||
v-model="position.strasse"
|
|
||||||
type="text"
|
|
||||||
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>
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">PLZ</label>
|
<label class="block text-sm font-medium text-gray-700 mb-2">PLZ</label>
|
||||||
<input
|
<input
|
||||||
v-model="position.plz"
|
v-model="config.training.ort.plz"
|
||||||
type="text"
|
type="text"
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
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>
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Ort</label>
|
<label class="block text-sm font-medium text-gray-700 mb-2">Ort</label>
|
||||||
<input
|
<input
|
||||||
v-model="position.ort"
|
v-model="config.training.ort.ort"
|
||||||
type="text"
|
type="text"
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Trainingszeiten -->
|
||||||
|
<div>
|
||||||
|
<div class="flex justify-between items-center mb-4">
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900">
|
||||||
|
Trainingszeiten
|
||||||
|
</h3>
|
||||||
|
<button
|
||||||
|
class="flex items-center px-3 py-1 bg-primary-600 hover:bg-primary-700 text-white text-sm rounded-lg transition-colors"
|
||||||
|
@click="addTrainingTime"
|
||||||
|
>
|
||||||
|
<Plus
|
||||||
|
:size="16"
|
||||||
|
class="mr-1"
|
||||||
|
/>
|
||||||
|
Zeit hinzufügen
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div
|
||||||
|
v-for="(zeit, index) in config.training.zeiten"
|
||||||
|
:key="zeit.id"
|
||||||
|
class="p-4 bg-gray-50 rounded-lg border border-gray-200"
|
||||||
|
>
|
||||||
|
<div class="grid sm:grid-cols-4 gap-4">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Tag</label>
|
||||||
|
<select
|
||||||
|
v-model="zeit.tag"
|
||||||
|
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||||
|
>
|
||||||
|
<option>Montag</option>
|
||||||
|
<option>Dienstag</option>
|
||||||
|
<option>Mittwoch</option>
|
||||||
|
<option>Donnerstag</option>
|
||||||
|
<option>Freitag</option>
|
||||||
|
<option>Samstag</option>
|
||||||
|
<option>Sonntag</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Von</label>
|
||||||
|
<input
|
||||||
|
v-model="zeit.von"
|
||||||
|
type="time"
|
||||||
|
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>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Bis</label>
|
||||||
|
<input
|
||||||
|
v-model="zeit.bis"
|
||||||
|
type="time"
|
||||||
|
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>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Gruppe</label>
|
||||||
|
<input
|
||||||
|
v-model="zeit.gruppe"
|
||||||
|
type="text"
|
||||||
|
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>
|
||||||
|
<div class="mt-4">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Zusätzliche Information (optional)</label>
|
||||||
|
<div class="flex space-x-2">
|
||||||
|
<input
|
||||||
|
v-model="zeit.info"
|
||||||
|
type="text"
|
||||||
|
placeholder="z.B. 'Nur in der Schulzeit', 'Ab 10 Jahren', etc."
|
||||||
|
class="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="px-3 py-2 text-red-600 hover:bg-red-50 rounded-lg transition-colors"
|
||||||
|
title="Löschen"
|
||||||
|
@click="removeTrainingTime(index)"
|
||||||
|
>
|
||||||
|
<Trash2 :size="18" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Trainer -->
|
||||||
|
<div v-if="activeTab === 'trainer'">
|
||||||
|
<div class="flex justify-between items-center mb-6">
|
||||||
|
<h2 class="text-2xl font-display font-bold text-gray-900">
|
||||||
|
Trainer
|
||||||
|
</h2>
|
||||||
|
<button
|
||||||
|
class="flex items-center px-4 py-2 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors"
|
||||||
|
@click="addTrainer"
|
||||||
|
>
|
||||||
|
<Plus
|
||||||
|
:size="20"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
|
Trainer hinzufügen
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-6">
|
||||||
|
<div
|
||||||
|
v-for="(trainer, index) in config.trainer"
|
||||||
|
:key="trainer.id"
|
||||||
|
class="p-6 bg-gray-50 rounded-lg border border-gray-200"
|
||||||
|
>
|
||||||
|
<div class="grid sm:grid-cols-2 gap-4">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Name</label>
|
||||||
|
<input
|
||||||
|
v-model="trainer.name"
|
||||||
|
type="text"
|
||||||
|
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>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Lizenz</label>
|
||||||
|
<input
|
||||||
|
v-model="trainer.lizenz"
|
||||||
|
type="text"
|
||||||
|
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>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Schwerpunkt</label>
|
||||||
|
<input
|
||||||
|
v-model="trainer.schwerpunkt"
|
||||||
|
type="text"
|
||||||
|
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>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Zusatzinfo</label>
|
||||||
|
<div class="flex space-x-2">
|
||||||
|
<input
|
||||||
|
v-model="trainer.zusatz"
|
||||||
|
type="text"
|
||||||
|
class="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="px-3 py-2 text-red-600 hover:bg-red-50 rounded-lg transition-colors"
|
||||||
|
title="Löschen"
|
||||||
|
@click="removeTrainer(index)"
|
||||||
|
>
|
||||||
|
<Trash2 :size="18" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="sm:col-span-2">
|
||||||
|
<ImageUpload
|
||||||
|
v-model="trainer.imageFilename"
|
||||||
|
label="Foto"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Mitgliedschaft -->
|
||||||
|
<div v-if="activeTab === 'mitgliedschaft'">
|
||||||
|
<div class="flex justify-between items-center mb-6">
|
||||||
|
<h2 class="text-2xl font-display font-bold text-gray-900">
|
||||||
|
Mitgliedschaftsoptionen
|
||||||
|
</h2>
|
||||||
|
<button
|
||||||
|
class="flex items-center px-4 py-2 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors"
|
||||||
|
@click="addMembership"
|
||||||
|
>
|
||||||
|
<Plus
|
||||||
|
:size="20"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
|
Option hinzufügen
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-6">
|
||||||
|
<div
|
||||||
|
v-for="(membership, index) in config.mitgliedschaft"
|
||||||
|
:key="membership.id"
|
||||||
|
class="p-6 bg-gray-50 rounded-lg border border-gray-200"
|
||||||
|
>
|
||||||
|
<div class="grid sm:grid-cols-3 gap-4 mb-4">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Typ</label>
|
||||||
|
<input
|
||||||
|
v-model="membership.typ"
|
||||||
|
type="text"
|
||||||
|
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>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Beschreibung</label>
|
||||||
|
<input
|
||||||
|
v-model="membership.beschreibung"
|
||||||
|
type="text"
|
||||||
|
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>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Preis (€/Jahr)</label>
|
||||||
|
<div class="flex space-x-2">
|
||||||
|
<input
|
||||||
|
v-model.number="membership.preis"
|
||||||
|
type="number"
|
||||||
|
class="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="px-3 py-2 text-red-600 hover:bg-red-50 rounded-lg transition-colors"
|
||||||
|
title="Löschen"
|
||||||
|
@click="removeMembership(index)"
|
||||||
|
>
|
||||||
|
<Trash2 :size="18" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Features -->
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Telefon</label>
|
<label class="block text-sm font-medium text-gray-700 mb-2">Leistungen</label>
|
||||||
<input
|
<div class="space-y-2">
|
||||||
v-model="position.telefon"
|
<div
|
||||||
type="tel"
|
v-for="(feature, fIndex) in membership.features"
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
:key="fIndex"
|
||||||
/>
|
class="flex space-x-2"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
v-model="membership.features[fIndex]"
|
||||||
|
type="text"
|
||||||
|
class="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="px-3 py-2 text-red-600 hover:bg-red-50 rounded-lg transition-colors"
|
||||||
|
@click="membership.features.splice(fIndex, 1)"
|
||||||
|
>
|
||||||
|
<X :size="18" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
class="flex items-center px-3 py-1 text-primary-600 hover:bg-primary-50 rounded-lg transition-colors text-sm"
|
||||||
|
@click="membership.features.push('')"
|
||||||
|
>
|
||||||
|
<Plus
|
||||||
|
:size="16"
|
||||||
|
class="mr-1"
|
||||||
|
/>
|
||||||
|
Leistung hinzufügen
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
</div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">E-Mail</label>
|
</div>
|
||||||
<input
|
</div>
|
||||||
v-model="position.email"
|
|
||||||
type="email"
|
<!-- Vorstand -->
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
<div v-if="activeTab === 'vorstand'">
|
||||||
/>
|
<h2 class="text-2xl font-display font-bold text-gray-900 mb-6">
|
||||||
</div>
|
Vorstandsdaten
|
||||||
<div class="sm:col-span-2">
|
</h2>
|
||||||
<ImageUpload
|
|
||||||
v-model="position.imageFilename"
|
<div class="space-y-8">
|
||||||
label="Foto"
|
<div
|
||||||
/>
|
v-for="(position, key) in config.vorstand"
|
||||||
|
:key="key"
|
||||||
|
class="p-6 bg-gray-50 rounded-lg border border-gray-200"
|
||||||
|
>
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900 mb-4 capitalize">
|
||||||
|
{{ formatPositionName(key) }}
|
||||||
|
</h3>
|
||||||
|
<div class="grid sm:grid-cols-2 gap-4">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Vorname</label>
|
||||||
|
<input
|
||||||
|
v-model="position.vorname"
|
||||||
|
type="text"
|
||||||
|
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>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Nachname</label>
|
||||||
|
<input
|
||||||
|
v-model="position.nachname"
|
||||||
|
type="text"
|
||||||
|
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">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Straße & Hausnummer</label>
|
||||||
|
<input
|
||||||
|
v-model="position.strasse"
|
||||||
|
type="text"
|
||||||
|
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>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">PLZ</label>
|
||||||
|
<input
|
||||||
|
v-model="position.plz"
|
||||||
|
type="text"
|
||||||
|
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>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Ort</label>
|
||||||
|
<input
|
||||||
|
v-model="position.ort"
|
||||||
|
type="text"
|
||||||
|
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>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Telefon</label>
|
||||||
|
<input
|
||||||
|
v-model="position.telefon"
|
||||||
|
type="tel"
|
||||||
|
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>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">E-Mail</label>
|
||||||
|
<input
|
||||||
|
v-model="position.email"
|
||||||
|
type="email"
|
||||||
|
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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Error/Success Messages -->
|
<!-- Error/Success Messages -->
|
||||||
<div v-if="errorMessage" class="flex items-center p-4 rounded-lg bg-red-50 text-red-700">
|
<div
|
||||||
<AlertCircle :size="20" class="mr-2" />
|
v-if="errorMessage"
|
||||||
{{ errorMessage }}
|
class="flex items-center p-4 rounded-lg bg-red-50 text-red-700"
|
||||||
</div>
|
>
|
||||||
|
<AlertCircle
|
||||||
|
:size="20"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
|
{{ errorMessage }}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div v-if="successMessage" class="flex items-center p-4 rounded-lg bg-green-50 text-green-700">
|
<div
|
||||||
<Check :size="20" class="mr-2" />
|
v-if="successMessage"
|
||||||
{{ successMessage }}
|
class="flex items-center p-4 rounded-lg bg-green-50 text-green-700"
|
||||||
|
>
|
||||||
|
<Check
|
||||||
|
:size="20"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
|
{{ successMessage }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,46 +4,126 @@
|
|||||||
<div class="fixed top-20 left-0 right-0 z-40 bg-white border-b border-gray-200 shadow-sm">
|
<div class="fixed top-20 left-0 right-0 z-40 bg-white border-b border-gray-200 shadow-sm">
|
||||||
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-3 sm:py-4">
|
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-3 sm:py-4">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<h1 class="text-xl sm:text-3xl font-display font-bold text-gray-900">Geschichte bearbeiten</h1>
|
<h1 class="text-xl sm:text-3xl font-display font-bold text-gray-900">
|
||||||
|
Geschichte bearbeiten
|
||||||
|
</h1>
|
||||||
<div class="space-x-3">
|
<div class="space-x-3">
|
||||||
<button @click="save" class="inline-flex items-center px-3 py-1.5 sm:px-4 sm:py-2 rounded-lg bg-primary-600 text-white hover:bg-primary-700 text-sm sm:text-base">Speichern</button>
|
<button
|
||||||
|
class="inline-flex items-center px-3 py-1.5 sm:px-4 sm:py-2 rounded-lg bg-primary-600 text-white hover:bg-primary-700 text-sm sm:text-base"
|
||||||
|
@click="save"
|
||||||
|
>
|
||||||
|
Speichern
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Fixed Toolbar below header -->
|
<!-- Fixed Toolbar below header -->
|
||||||
<div class="fixed left-0 right-0 z-30 bg-white border-b border-gray-200 shadow-sm" style="top: 9.5rem;">
|
<div
|
||||||
|
class="fixed left-0 right-0 z-30 bg-white border-b border-gray-200 shadow-sm"
|
||||||
|
style="top: 9.5rem;"
|
||||||
|
>
|
||||||
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<div class="flex flex-wrap items-center gap-1 sm:gap-2 py-1.5 sm:py-2">
|
<div class="flex flex-wrap items-center gap-1 sm:gap-2 py-1.5 sm:py-2">
|
||||||
<!-- Formatierung -->
|
<!-- Formatierung -->
|
||||||
<div class="flex items-center gap-1 border-r pr-2 mr-2">
|
<div class="flex items-center gap-1 border-r pr-2 mr-2">
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm" @click="format('bold')"><strong>B</strong></button>
|
<button
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm" @click="format('italic')"><em>I</em></button>
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm"
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm" @click="formatHeader(1)">H1</button>
|
@click="format('bold')"
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm" @click="formatHeader(2)">H2</button>
|
>
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm" @click="formatHeader(3)">H3</button>
|
<strong>B</strong>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm"
|
||||||
|
@click="format('italic')"
|
||||||
|
>
|
||||||
|
<em>I</em>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm"
|
||||||
|
@click="formatHeader(1)"
|
||||||
|
>
|
||||||
|
H1
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm"
|
||||||
|
@click="formatHeader(2)"
|
||||||
|
>
|
||||||
|
H2
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm"
|
||||||
|
@click="formatHeader(3)"
|
||||||
|
>
|
||||||
|
H3
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Listen -->
|
<!-- Listen -->
|
||||||
<div class="flex items-center gap-1 border-r pr-2 mr-2">
|
<div class="flex items-center gap-1 border-r pr-2 mr-2">
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm" @click="format('insertUnorderedList')">•</button>
|
<button
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm" @click="format('insertOrderedList')">1.</button>
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm"
|
||||||
|
@click="format('insertUnorderedList')"
|
||||||
|
>
|
||||||
|
•
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm"
|
||||||
|
@click="format('insertOrderedList')"
|
||||||
|
>
|
||||||
|
1.
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Schnellzugriff für Geschichts-Abschnitte -->
|
<!-- Schnellzugriff für Geschichts-Abschnitte -->
|
||||||
<div class="flex items-center gap-1 border-r pr-2 mr-2">
|
<div class="flex items-center gap-1 border-r pr-2 mr-2">
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded bg-gray-100 hover:bg-gray-200 text-gray-700 text-xs sm:text-sm" @click="insertHistoryTemplate('generic')">Neuer Abschnitt</button>
|
<button
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded bg-blue-100 hover:bg-blue-200 text-blue-700 text-xs sm:text-sm" @click="insertHistoryTemplate('founding')">Gründung</button>
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded bg-gray-100 hover:bg-gray-200 text-gray-700 text-xs sm:text-sm"
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded bg-green-100 hover:bg-green-200 text-green-700 text-xs sm:text-sm" @click="insertHistoryTemplate('milestone')">Meilenstein</button>
|
@click="insertHistoryTemplate('generic')"
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded bg-yellow-100 hover:bg-yellow-200 text-yellow-700 text-xs sm:text-sm" @click="insertHistoryTemplate('achievement')">Erfolg</button>
|
>
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded bg-red-100 hover:bg-red-200 text-red-700 text-xs sm:text-sm" @click="deleteCurrentSection()">Abschnitt löschen</button>
|
Neuer Abschnitt
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded bg-blue-100 hover:bg-blue-200 text-blue-700 text-xs sm:text-sm"
|
||||||
|
@click="insertHistoryTemplate('founding')"
|
||||||
|
>
|
||||||
|
Gründung
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded bg-green-100 hover:bg-green-200 text-green-700 text-xs sm:text-sm"
|
||||||
|
@click="insertHistoryTemplate('milestone')"
|
||||||
|
>
|
||||||
|
Meilenstein
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded bg-yellow-100 hover:bg-yellow-200 text-yellow-700 text-xs sm:text-sm"
|
||||||
|
@click="insertHistoryTemplate('achievement')"
|
||||||
|
>
|
||||||
|
Erfolg
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded bg-red-100 hover:bg-red-200 text-red-700 text-xs sm:text-sm"
|
||||||
|
@click="deleteCurrentSection()"
|
||||||
|
>
|
||||||
|
Abschnitt löschen
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Weitere Tools -->
|
<!-- Weitere Tools -->
|
||||||
<div class="flex items-center gap-1">
|
<div class="flex items-center gap-1">
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm" @click="createLink()">Link</button>
|
<button
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm" @click="removeFormat()">Clear</button>
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm"
|
||||||
|
@click="createLink()"
|
||||||
|
>
|
||||||
|
Link
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm"
|
||||||
|
@click="removeFormat()"
|
||||||
|
>
|
||||||
|
Clear
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -52,14 +132,13 @@
|
|||||||
<!-- Content with top padding -->
|
<!-- Content with top padding -->
|
||||||
<div class="pt-36 sm:pt-44 pb-16">
|
<div class="pt-36 sm:pt-44 pb-16">
|
||||||
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-3 sm:p-4">
|
||||||
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-3 sm:p-4">
|
<div
|
||||||
<div
|
ref="editor"
|
||||||
ref="editor"
|
class="min-h-[320px] p-3 sm:p-4 outline-none prose max-w-none text-sm sm:text-base"
|
||||||
class="min-h-[320px] p-3 sm:p-4 outline-none prose max-w-none text-sm sm:text-base"
|
contenteditable
|
||||||
contenteditable
|
/>
|
||||||
/>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -14,9 +14,14 @@
|
|||||||
>
|
>
|
||||||
<div class="flex items-center mb-4">
|
<div class="flex items-center mb-4">
|
||||||
<div class="w-12 h-12 bg-indigo-100 rounded-lg flex items-center justify-center group-hover:bg-indigo-600 transition-colors">
|
<div class="w-12 h-12 bg-indigo-100 rounded-lg flex items-center justify-center group-hover:bg-indigo-600 transition-colors">
|
||||||
<Newspaper :size="24" class="text-indigo-600 group-hover:text-white" />
|
<Newspaper
|
||||||
|
:size="24"
|
||||||
|
class="text-indigo-600 group-hover:text-white"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="ml-4 text-xl font-semibold text-gray-900">Über uns</h2>
|
<h2 class="ml-4 text-xl font-semibold text-gray-900">
|
||||||
|
Über uns
|
||||||
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-gray-600">
|
<p class="text-gray-600">
|
||||||
Seite „Über uns" bearbeiten (WYSIWYG)
|
Seite „Über uns" bearbeiten (WYSIWYG)
|
||||||
@@ -30,9 +35,14 @@
|
|||||||
>
|
>
|
||||||
<div class="flex items-center mb-4">
|
<div class="flex items-center mb-4">
|
||||||
<div class="w-12 h-12 bg-amber-100 rounded-lg flex items-center justify-center group-hover:bg-amber-600 transition-colors">
|
<div class="w-12 h-12 bg-amber-100 rounded-lg flex items-center justify-center group-hover:bg-amber-600 transition-colors">
|
||||||
<Newspaper :size="24" class="text-amber-600 group-hover:text-white" />
|
<Newspaper
|
||||||
|
:size="24"
|
||||||
|
class="text-amber-600 group-hover:text-white"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="ml-4 text-xl font-semibold text-gray-900">Geschichte</h2>
|
<h2 class="ml-4 text-xl font-semibold text-gray-900">
|
||||||
|
Geschichte
|
||||||
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-gray-600">
|
<p class="text-gray-600">
|
||||||
Vereinsgeschichte bearbeiten (WYSIWYG)
|
Vereinsgeschichte bearbeiten (WYSIWYG)
|
||||||
@@ -46,9 +56,14 @@
|
|||||||
>
|
>
|
||||||
<div class="flex items-center mb-4">
|
<div class="flex items-center mb-4">
|
||||||
<div class="w-12 h-12 bg-red-100 rounded-lg flex items-center justify-center group-hover:bg-red-600 transition-colors">
|
<div class="w-12 h-12 bg-red-100 rounded-lg flex items-center justify-center group-hover:bg-red-600 transition-colors">
|
||||||
<Newspaper :size="24" class="text-red-600 group-hover:text-white" />
|
<Newspaper
|
||||||
|
:size="24"
|
||||||
|
class="text-red-600 group-hover:text-white"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="ml-4 text-xl font-semibold text-gray-900">TT-Regeln</h2>
|
<h2 class="ml-4 text-xl font-semibold text-gray-900">
|
||||||
|
TT-Regeln
|
||||||
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-gray-600">
|
<p class="text-gray-600">
|
||||||
Tischtennis-Regeln bearbeiten (WYSIWYG)
|
Tischtennis-Regeln bearbeiten (WYSIWYG)
|
||||||
@@ -62,11 +77,23 @@
|
|||||||
>
|
>
|
||||||
<div class="flex items-center mb-4">
|
<div class="flex items-center mb-4">
|
||||||
<div class="w-12 h-12 bg-slate-100 rounded-lg flex items-center justify-center group-hover:bg-slate-600 transition-colors">
|
<div class="w-12 h-12 bg-slate-100 rounded-lg flex items-center justify-center group-hover:bg-slate-600 transition-colors">
|
||||||
<svg class="w-6 h-6 text-slate-600 group-hover:text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
class="w-6 h-6 text-slate-600 group-hover:text-white"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="ml-4 text-xl font-semibold text-gray-900">Satzung</h2>
|
<h2 class="ml-4 text-xl font-semibold text-gray-900">
|
||||||
|
Satzung
|
||||||
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-gray-600">
|
<p class="text-gray-600">
|
||||||
Satzung als PDF hochladen
|
Satzung als PDF hochladen
|
||||||
@@ -79,9 +106,14 @@
|
|||||||
>
|
>
|
||||||
<div class="flex items-center mb-4">
|
<div class="flex items-center mb-4">
|
||||||
<div class="w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center group-hover:bg-blue-600 transition-colors">
|
<div class="w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center group-hover:bg-blue-600 transition-colors">
|
||||||
<Newspaper :size="24" class="text-blue-600 group-hover:text-white" />
|
<Newspaper
|
||||||
|
:size="24"
|
||||||
|
class="text-blue-600 group-hover:text-white"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="ml-4 text-xl font-semibold text-gray-900">News</h2>
|
<h2 class="ml-4 text-xl font-semibold text-gray-900">
|
||||||
|
News
|
||||||
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-gray-600">
|
<p class="text-gray-600">
|
||||||
News erstellen und verwalten (intern und öffentlich)
|
News erstellen und verwalten (intern und öffentlich)
|
||||||
@@ -95,9 +127,14 @@
|
|||||||
>
|
>
|
||||||
<div class="flex items-center mb-4">
|
<div class="flex items-center mb-4">
|
||||||
<div class="w-12 h-12 bg-green-100 rounded-lg flex items-center justify-center group-hover:bg-green-600 transition-colors">
|
<div class="w-12 h-12 bg-green-100 rounded-lg flex items-center justify-center group-hover:bg-green-600 transition-colors">
|
||||||
<Calendar :size="24" class="text-green-600 group-hover:text-white" />
|
<Calendar
|
||||||
|
:size="24"
|
||||||
|
class="text-green-600 group-hover:text-white"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="ml-4 text-xl font-semibold text-gray-900">Termine</h2>
|
<h2 class="ml-4 text-xl font-semibold text-gray-900">
|
||||||
|
Termine
|
||||||
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-gray-600">
|
<p class="text-gray-600">
|
||||||
Vereinstermine erstellen und verwalten
|
Vereinstermine erstellen und verwalten
|
||||||
@@ -111,9 +148,14 @@
|
|||||||
>
|
>
|
||||||
<div class="flex items-center mb-4">
|
<div class="flex items-center mb-4">
|
||||||
<div class="w-12 h-12 bg-purple-100 rounded-lg flex items-center justify-center group-hover:bg-purple-600 transition-colors">
|
<div class="w-12 h-12 bg-purple-100 rounded-lg flex items-center justify-center group-hover:bg-purple-600 transition-colors">
|
||||||
<Users :size="24" class="text-purple-600 group-hover:text-white" />
|
<Users
|
||||||
|
:size="24"
|
||||||
|
class="text-purple-600 group-hover:text-white"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="ml-4 text-xl font-semibold text-gray-900">Mitglieder</h2>
|
<h2 class="ml-4 text-xl font-semibold text-gray-900">
|
||||||
|
Mitglieder
|
||||||
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-gray-600">
|
<p class="text-gray-600">
|
||||||
Mitgliederliste bearbeiten
|
Mitgliederliste bearbeiten
|
||||||
@@ -127,9 +169,14 @@
|
|||||||
>
|
>
|
||||||
<div class="flex items-center mb-4">
|
<div class="flex items-center mb-4">
|
||||||
<div class="w-12 h-12 bg-orange-100 rounded-lg flex items-center justify-center group-hover:bg-orange-600 transition-colors">
|
<div class="w-12 h-12 bg-orange-100 rounded-lg flex items-center justify-center group-hover:bg-orange-600 transition-colors">
|
||||||
<Settings :size="24" class="text-orange-600 group-hover:text-white" />
|
<Settings
|
||||||
|
:size="24"
|
||||||
|
class="text-orange-600 group-hover:text-white"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="ml-4 text-xl font-semibold text-gray-900">Einstellungen</h2>
|
<h2 class="ml-4 text-xl font-semibold text-gray-900">
|
||||||
|
Einstellungen
|
||||||
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-gray-600">
|
<p class="text-gray-600">
|
||||||
Training, Trainer, Mitgliedschaft & Vorstand
|
Training, Trainer, Mitgliedschaft & Vorstand
|
||||||
@@ -144,9 +191,14 @@
|
|||||||
>
|
>
|
||||||
<div class="flex items-center mb-4">
|
<div class="flex items-center mb-4">
|
||||||
<div class="w-12 h-12 bg-yellow-100 rounded-lg flex items-center justify-center group-hover:bg-yellow-600 transition-colors">
|
<div class="w-12 h-12 bg-yellow-100 rounded-lg flex items-center justify-center group-hover:bg-yellow-600 transition-colors">
|
||||||
<UserCog :size="24" class="text-yellow-600 group-hover:text-white" />
|
<UserCog
|
||||||
|
:size="24"
|
||||||
|
class="text-yellow-600 group-hover:text-white"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="ml-4 text-xl font-semibold text-gray-900">Benutzerverwaltung</h2>
|
<h2 class="ml-4 text-xl font-semibold text-gray-900">
|
||||||
|
Benutzerverwaltung
|
||||||
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-gray-600">
|
<p class="text-gray-600">
|
||||||
Benutzer freischalten und verwalten
|
Benutzer freischalten und verwalten
|
||||||
|
|||||||
@@ -8,9 +8,9 @@
|
|||||||
Mitgliedschaftsanträge
|
Mitgliedschaftsanträge
|
||||||
</h1>
|
</h1>
|
||||||
<button
|
<button
|
||||||
@click="refreshApplications"
|
|
||||||
:disabled="loading"
|
:disabled="loading"
|
||||||
class="px-3 py-1.5 sm:px-4 sm:py-2 bg-primary-600 hover:bg-primary-700 disabled:bg-gray-400 text-white text-sm sm:text-base font-medium rounded-lg transition-colors"
|
class="px-3 py-1.5 sm:px-4 sm:py-2 bg-primary-600 hover:bg-primary-700 disabled:bg-gray-400 text-white text-sm sm:text-base font-medium rounded-lg transition-colors"
|
||||||
|
@click="refreshApplications"
|
||||||
>
|
>
|
||||||
{{ loading ? 'Lädt...' : 'Aktualisieren' }}
|
{{ loading ? 'Lädt...' : 'Aktualisieren' }}
|
||||||
</button>
|
</button>
|
||||||
@@ -22,20 +22,37 @@
|
|||||||
<div class="pt-20 sm:pt-24">
|
<div class="pt-20 sm:pt-24">
|
||||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
|
||||||
<!-- Loading State -->
|
<!-- Loading State -->
|
||||||
<div v-if="loading" class="text-center py-12">
|
<div
|
||||||
<div class="animate-spin rounded-full h-12 w-12 border-b-2 border-primary-600 mx-auto"></div>
|
v-if="loading"
|
||||||
<p class="mt-4 text-gray-600">Lade Anträge...</p>
|
class="text-center py-12"
|
||||||
|
>
|
||||||
|
<div class="animate-spin rounded-full h-12 w-12 border-b-2 border-primary-600 mx-auto" />
|
||||||
|
<p class="mt-4 text-gray-600">
|
||||||
|
Lade Anträge...
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Empty State -->
|
<!-- Empty State -->
|
||||||
<div v-else-if="applications.length === 0" class="text-center py-12">
|
<div
|
||||||
<div class="text-gray-400 text-6xl mb-4">📋</div>
|
v-else-if="applications.length === 0"
|
||||||
<h3 class="text-lg font-medium text-gray-900 mb-2">Keine Anträge vorhanden</h3>
|
class="text-center py-12"
|
||||||
<p class="text-gray-600">Es wurden noch keine Mitgliedschaftsanträge eingereicht.</p>
|
>
|
||||||
|
<div class="text-gray-400 text-6xl mb-4">
|
||||||
|
📋
|
||||||
|
</div>
|
||||||
|
<h3 class="text-lg font-medium text-gray-900 mb-2">
|
||||||
|
Keine Anträge vorhanden
|
||||||
|
</h3>
|
||||||
|
<p class="text-gray-600">
|
||||||
|
Es wurden noch keine Mitgliedschaftsanträge eingereicht.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Applications List -->
|
<!-- Applications List -->
|
||||||
<div v-else class="space-y-6">
|
<div
|
||||||
|
v-else
|
||||||
|
class="space-y-6"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
v-for="application in applications"
|
v-for="application in applications"
|
||||||
:key="application.id"
|
:key="application.id"
|
||||||
@@ -66,32 +83,42 @@
|
|||||||
<!-- Actions -->
|
<!-- Actions -->
|
||||||
<div class="flex space-x-2">
|
<div class="flex space-x-2">
|
||||||
<button
|
<button
|
||||||
@click="viewApplication(application)"
|
|
||||||
class="px-3 py-1 text-sm bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg transition-colors"
|
class="px-3 py-1 text-sm bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg transition-colors"
|
||||||
|
@click="viewApplication(application)"
|
||||||
>
|
>
|
||||||
Anzeigen
|
Anzeigen
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="application.metadata.pdfGenerated"
|
v-if="application.metadata.pdfGenerated"
|
||||||
@click="downloadPDF(application.id)"
|
|
||||||
class="px-3 py-1 text-sm bg-blue-100 hover:bg-blue-200 text-blue-700 rounded-lg transition-colors flex items-center"
|
class="px-3 py-1 text-sm bg-blue-100 hover:bg-blue-200 text-blue-700 rounded-lg transition-colors flex items-center"
|
||||||
|
@click="downloadPDF(application.id)"
|
||||||
>
|
>
|
||||||
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
class="w-4 h-4 mr-1"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
PDF
|
PDF
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="application.status === 'pending'"
|
v-if="application.status === 'pending'"
|
||||||
@click="approveApplication(application.id)"
|
|
||||||
class="px-3 py-1 text-sm bg-green-100 hover:bg-green-200 text-green-700 rounded-lg transition-colors"
|
class="px-3 py-1 text-sm bg-green-100 hover:bg-green-200 text-green-700 rounded-lg transition-colors"
|
||||||
|
@click="approveApplication(application.id)"
|
||||||
>
|
>
|
||||||
Genehmigen
|
Genehmigen
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="application.status === 'pending'"
|
v-if="application.status === 'pending'"
|
||||||
@click="rejectApplication(application.id)"
|
|
||||||
class="px-3 py-1 text-sm bg-red-100 hover:bg-red-200 text-red-700 rounded-lg transition-colors"
|
class="px-3 py-1 text-sm bg-red-100 hover:bg-red-200 text-red-700 rounded-lg transition-colors"
|
||||||
|
@click="rejectApplication(application.id)"
|
||||||
>
|
>
|
||||||
Ablehnen
|
Ablehnen
|
||||||
</button>
|
</button>
|
||||||
@@ -104,7 +131,9 @@
|
|||||||
<div class="px-6 py-4">
|
<div class="px-6 py-4">
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
<div>
|
<div>
|
||||||
<h4 class="text-sm font-medium text-gray-900 mb-2">Kontaktdaten</h4>
|
<h4 class="text-sm font-medium text-gray-900 mb-2">
|
||||||
|
Kontaktdaten
|
||||||
|
</h4>
|
||||||
<div class="space-y-1 text-sm text-gray-600">
|
<div class="space-y-1 text-sm text-gray-600">
|
||||||
<p><strong>E-Mail:</strong> {{ application.personalData.email }}</p>
|
<p><strong>E-Mail:</strong> {{ application.personalData.email }}</p>
|
||||||
<p v-if="application.personalData.telefon_privat">
|
<p v-if="application.personalData.telefon_privat">
|
||||||
@@ -117,7 +146,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h4 class="text-sm font-medium text-gray-900 mb-2">Antragsdetails</h4>
|
<h4 class="text-sm font-medium text-gray-900 mb-2">
|
||||||
|
Antragsdetails
|
||||||
|
</h4>
|
||||||
<div class="space-y-1 text-sm text-gray-600">
|
<div class="space-y-1 text-sm text-gray-600">
|
||||||
<p><strong>Art:</strong> {{ application.metadata.mitgliedschaftsart === 'aktiv' ? 'Aktives Mitglied' : 'Passives Mitglied' }}</p>
|
<p><strong>Art:</strong> {{ application.metadata.mitgliedschaftsart === 'aktiv' ? 'Aktives Mitglied' : 'Passives Mitglied' }}</p>
|
||||||
<p><strong>Volljährig:</strong> {{ application.metadata.isVolljaehrig ? 'Ja' : 'Nein' }}</p>
|
<p><strong>Volljährig:</strong> {{ application.metadata.isVolljaehrig ? 'Ja' : 'Nein' }}</p>
|
||||||
@@ -144,11 +175,21 @@
|
|||||||
Antrag: {{ selectedApplication.personalData.vorname }} {{ selectedApplication.personalData.nachname }}
|
Antrag: {{ selectedApplication.personalData.vorname }} {{ selectedApplication.personalData.nachname }}
|
||||||
</h2>
|
</h2>
|
||||||
<button
|
<button
|
||||||
@click="closeModal"
|
|
||||||
class="text-gray-400 hover:text-gray-600"
|
class="text-gray-400 hover:text-gray-600"
|
||||||
|
@click="closeModal"
|
||||||
>
|
>
|
||||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
class="w-6 h-6"
|
||||||
|
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>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -158,7 +199,9 @@
|
|||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
<!-- Personal Data -->
|
<!-- Personal Data -->
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-lg font-medium text-gray-900 mb-4">Persönliche Daten</h3>
|
<h3 class="text-lg font-medium text-gray-900 mb-4">
|
||||||
|
Persönliche Daten
|
||||||
|
</h3>
|
||||||
<div class="space-y-2 text-sm">
|
<div class="space-y-2 text-sm">
|
||||||
<p><strong>Name:</strong> {{ selectedApplication.personalData.vorname }} {{ selectedApplication.personalData.nachname }}</p>
|
<p><strong>Name:</strong> {{ selectedApplication.personalData.vorname }} {{ selectedApplication.personalData.nachname }}</p>
|
||||||
<p><strong>E-Mail:</strong> {{ selectedApplication.personalData.email }}</p>
|
<p><strong>E-Mail:</strong> {{ selectedApplication.personalData.email }}</p>
|
||||||
@@ -173,7 +216,9 @@
|
|||||||
|
|
||||||
<!-- Application Details -->
|
<!-- Application Details -->
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-lg font-medium text-gray-900 mb-4">Antragsdetails</h3>
|
<h3 class="text-lg font-medium text-gray-900 mb-4">
|
||||||
|
Antragsdetails
|
||||||
|
</h3>
|
||||||
<div class="space-y-2 text-sm">
|
<div class="space-y-2 text-sm">
|
||||||
<p><strong>Status:</strong> {{ getStatusText(selectedApplication.status) }}</p>
|
<p><strong>Status:</strong> {{ getStatusText(selectedApplication.status) }}</p>
|
||||||
<p><strong>Art:</strong> {{ selectedApplication.metadata.mitgliedschaftsart === 'aktiv' ? 'Aktives Mitglied' : 'Passives Mitglied' }}</p>
|
<p><strong>Art:</strong> {{ selectedApplication.metadata.mitgliedschaftsart === 'aktiv' ? 'Aktives Mitglied' : 'Passives Mitglied' }}</p>
|
||||||
@@ -187,32 +232,42 @@
|
|||||||
<div class="mt-6 pt-6 border-t border-gray-200">
|
<div class="mt-6 pt-6 border-t border-gray-200">
|
||||||
<div class="flex justify-end space-x-3">
|
<div class="flex justify-end space-x-3">
|
||||||
<button
|
<button
|
||||||
@click="closeModal"
|
|
||||||
class="px-4 py-2 text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors"
|
class="px-4 py-2 text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors"
|
||||||
|
@click="closeModal"
|
||||||
>
|
>
|
||||||
Schließen
|
Schließen
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="selectedApplication.metadata.pdfGenerated"
|
v-if="selectedApplication.metadata.pdfGenerated"
|
||||||
@click="downloadPDF(selectedApplication.id)"
|
|
||||||
class="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors flex items-center"
|
class="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition-colors flex items-center"
|
||||||
|
@click="downloadPDF(selectedApplication.id)"
|
||||||
>
|
>
|
||||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
class="w-4 h-4 mr-2"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
PDF herunterladen
|
PDF herunterladen
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="selectedApplication.status === 'pending'"
|
v-if="selectedApplication.status === 'pending'"
|
||||||
@click="approveApplication(selectedApplication.id)"
|
|
||||||
class="px-4 py-2 bg-green-600 hover:bg-green-700 text-white rounded-lg transition-colors"
|
class="px-4 py-2 bg-green-600 hover:bg-green-700 text-white rounded-lg transition-colors"
|
||||||
|
@click="approveApplication(selectedApplication.id)"
|
||||||
>
|
>
|
||||||
Genehmigen
|
Genehmigen
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="selectedApplication.status === 'pending'"
|
v-if="selectedApplication.status === 'pending'"
|
||||||
@click="rejectApplication(selectedApplication.id)"
|
|
||||||
class="px-4 py-2 bg-red-600 hover:bg-red-700 text-white rounded-lg transition-colors"
|
class="px-4 py-2 bg-red-600 hover:bg-red-700 text-white rounded-lg transition-colors"
|
||||||
|
@click="rejectApplication(selectedApplication.id)"
|
||||||
>
|
>
|
||||||
Ablehnen
|
Ablehnen
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -13,10 +13,13 @@
|
|||||||
<div class="space-x-3">
|
<div class="space-x-3">
|
||||||
<button
|
<button
|
||||||
v-if="canCreateGroup"
|
v-if="canCreateGroup"
|
||||||
@click="showCreateGroupModal = true"
|
|
||||||
class="inline-flex items-center px-3 py-1.5 sm:px-4 sm:py-2 rounded-lg bg-primary-600 text-white hover:bg-primary-700 text-sm sm:text-base"
|
class="inline-flex items-center px-3 py-1.5 sm:px-4 sm:py-2 rounded-lg bg-primary-600 text-white hover:bg-primary-700 text-sm sm:text-base"
|
||||||
|
@click="showCreateGroupModal = true"
|
||||||
>
|
>
|
||||||
<Plus :size="16" class="mr-2" />
|
<Plus
|
||||||
|
:size="16"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
Neue Newsletter-Gruppe
|
Neue Newsletter-Gruppe
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -28,12 +31,21 @@
|
|||||||
<div class="pt-28 sm:pt-32 pb-16">
|
<div class="pt-28 sm:pt-32 pb-16">
|
||||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<!-- Loading State -->
|
<!-- Loading State -->
|
||||||
<div v-if="isLoading" class="flex items-center justify-center py-12">
|
<div
|
||||||
<Loader2 :size="40" class="animate-spin text-primary-600" />
|
v-if="isLoading"
|
||||||
|
class="flex items-center justify-center py-12"
|
||||||
|
>
|
||||||
|
<Loader2
|
||||||
|
:size="40"
|
||||||
|
class="animate-spin text-primary-600"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Newsletter Groups List -->
|
<!-- Newsletter Groups List -->
|
||||||
<div v-else class="space-y-6">
|
<div
|
||||||
|
v-else
|
||||||
|
class="space-y-6"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
v-for="group in groups"
|
v-for="group in groups"
|
||||||
:key="group.id"
|
:key="group.id"
|
||||||
@@ -44,14 +56,19 @@
|
|||||||
<div class="flex items-start justify-between">
|
<div class="flex items-start justify-between">
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<div class="flex items-center space-x-3 mb-2">
|
<div class="flex items-center space-x-3 mb-2">
|
||||||
<h3 class="text-xl font-semibold text-gray-900">{{ group.name }}</h3>
|
<h3 class="text-xl font-semibold text-gray-900">
|
||||||
|
{{ group.name }}
|
||||||
|
</h3>
|
||||||
<span
|
<span
|
||||||
class="px-2 py-1 text-xs font-medium rounded bg-blue-100 text-blue-800"
|
class="px-2 py-1 text-xs font-medium rounded bg-blue-100 text-blue-800"
|
||||||
>
|
>
|
||||||
{{ group.type === 'subscription' ? 'Abonnenten' : 'Gruppe' }}
|
{{ group.type === 'subscription' ? 'Abonnenten' : 'Gruppe' }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p v-if="group.description" class="text-sm text-gray-600 mb-2">
|
<p
|
||||||
|
v-if="group.description"
|
||||||
|
class="text-sm text-gray-600 mb-2"
|
||||||
|
>
|
||||||
{{ group.description }}
|
{{ group.description }}
|
||||||
</p>
|
</p>
|
||||||
<div class="flex items-center space-x-4 text-sm text-gray-500">
|
<div class="flex items-center space-x-4 text-sm text-gray-500">
|
||||||
@@ -68,17 +85,23 @@
|
|||||||
<div class="flex items-center space-x-2 ml-4">
|
<div class="flex items-center space-x-2 ml-4">
|
||||||
<button
|
<button
|
||||||
v-if="group.type === 'subscription'"
|
v-if="group.type === 'subscription'"
|
||||||
@click="showSubscribersModal(group)"
|
|
||||||
class="px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors text-sm"
|
class="px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors text-sm"
|
||||||
|
@click="showSubscribersModal(group)"
|
||||||
>
|
>
|
||||||
<Users :size="16" class="inline mr-1" />
|
<Users
|
||||||
|
:size="16"
|
||||||
|
class="inline mr-1"
|
||||||
|
/>
|
||||||
Abonnenten
|
Abonnenten
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@click="showPostModal(group)"
|
|
||||||
class="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors text-sm"
|
class="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors text-sm"
|
||||||
|
@click="showPostModal(group)"
|
||||||
>
|
>
|
||||||
<Plus :size="16" class="inline mr-1" />
|
<Plus
|
||||||
|
:size="16"
|
||||||
|
class="inline mr-1"
|
||||||
|
/>
|
||||||
Post hinzufügen
|
Post hinzufügen
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -86,10 +109,13 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Posts List Header -->
|
<!-- Posts List Header -->
|
||||||
<div v-if="groupPosts[group.id] && groupPosts[group.id].length > 0" class="border-t border-gray-200">
|
<div
|
||||||
|
v-if="groupPosts[group.id] && groupPosts[group.id].length > 0"
|
||||||
|
class="border-t border-gray-200"
|
||||||
|
>
|
||||||
<button
|
<button
|
||||||
@click="toggleGroupPosts(group.id)"
|
|
||||||
class="w-full px-6 py-4 flex items-center justify-between hover:bg-gray-50 transition-colors"
|
class="w-full px-6 py-4 flex items-center justify-between hover:bg-gray-50 transition-colors"
|
||||||
|
@click="toggleGroupPosts(group.id)"
|
||||||
>
|
>
|
||||||
<span class="text-sm font-medium text-gray-700">
|
<span class="text-sm font-medium text-gray-700">
|
||||||
Posts ({{ groupPosts[group.id].length }})
|
Posts ({{ groupPosts[group.id].length }})
|
||||||
@@ -100,12 +126,20 @@
|
|||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
>
|
>
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M19 9l-7 7-7-7"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!-- Collapsible Posts List -->
|
<!-- Collapsible Posts List -->
|
||||||
<div v-show="expandedGroups[group.id]" class="divide-y divide-gray-200">
|
<div
|
||||||
|
v-show="expandedGroups[group.id]"
|
||||||
|
class="divide-y divide-gray-200"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
v-for="post in groupPosts[group.id]"
|
v-for="post in groupPosts[group.id]"
|
||||||
:key="post.id"
|
:key="post.id"
|
||||||
@@ -113,27 +147,38 @@
|
|||||||
>
|
>
|
||||||
<div class="flex items-start justify-between">
|
<div class="flex items-start justify-between">
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<h4 class="text-lg font-semibold text-gray-900 mb-2">{{ post.title }}</h4>
|
<h4 class="text-lg font-semibold text-gray-900 mb-2">
|
||||||
|
{{ post.title }}
|
||||||
|
</h4>
|
||||||
<div class="flex items-center space-x-4 text-sm text-gray-500 mb-3">
|
<div class="flex items-center space-x-4 text-sm text-gray-500 mb-3">
|
||||||
<span v-if="post.sentAt">Versendet: {{ formatDate(post.sentAt) }}</span>
|
<span v-if="post.sentAt">Versendet: {{ formatDate(post.sentAt) }}</span>
|
||||||
<span v-else class="text-yellow-600">Nicht versendet</span>
|
<span
|
||||||
|
v-else
|
||||||
|
class="text-yellow-600"
|
||||||
|
>Nicht versendet</span>
|
||||||
<span v-if="post.sentTo && post.sentTo.total > 0">
|
<span v-if="post.sentTo && post.sentTo.total > 0">
|
||||||
Empfänger: {{ post.sentTo.sent }}/{{ post.sentTo.total }}
|
Empfänger: {{ post.sentTo.sent }}/{{ post.sentTo.total }}
|
||||||
</span>
|
</span>
|
||||||
<span v-else-if="post.sentTo && post.sentTo.total === 0" class="text-gray-400">
|
<span
|
||||||
|
v-else-if="post.sentTo && post.sentTo.total === 0"
|
||||||
|
class="text-gray-400"
|
||||||
|
>
|
||||||
Keine Empfänger gefunden
|
Keine Empfänger gefunden
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-html="post.content.substring(0, 200) + (post.content.length > 200 ? '...' : '')"
|
|
||||||
class="text-sm text-gray-600 prose prose-sm max-w-none mb-3"
|
class="text-sm text-gray-600 prose prose-sm max-w-none mb-3"
|
||||||
></div>
|
v-html="post.content.substring(0, 200) + (post.content.length > 200 ? '...' : '')"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- Empfängerliste (collapsible) -->
|
<!-- Empfängerliste (collapsible) -->
|
||||||
<div v-if="post.sentTo && post.sentTo.recipients && post.sentTo.recipients.length > 0" class="border-t border-gray-200 mt-3 pt-3">
|
<div
|
||||||
|
v-if="post.sentTo && post.sentTo.recipients && post.sentTo.recipients.length > 0"
|
||||||
|
class="border-t border-gray-200 mt-3 pt-3"
|
||||||
|
>
|
||||||
<button
|
<button
|
||||||
@click="togglePostRecipients(post.id)"
|
|
||||||
class="w-full flex items-center justify-between text-sm text-gray-600 hover:text-gray-900 transition-colors"
|
class="w-full flex items-center justify-between text-sm text-gray-600 hover:text-gray-900 transition-colors"
|
||||||
|
@click="togglePostRecipients(post.id)"
|
||||||
>
|
>
|
||||||
<span class="font-medium">
|
<span class="font-medium">
|
||||||
Empfänger ({{ post.sentTo.recipients.length }})
|
Empfänger ({{ post.sentTo.recipients.length }})
|
||||||
@@ -144,11 +189,19 @@
|
|||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
>
|
>
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M19 9l-7 7-7-7"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div v-show="expandedPosts[post.id]" class="mt-3 space-y-2">
|
<div
|
||||||
|
v-show="expandedPosts[post.id]"
|
||||||
|
class="mt-3 space-y-2"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
v-for="(recipient, idx) in post.sentTo.recipients"
|
v-for="(recipient, idx) in post.sentTo.recipients"
|
||||||
:key="idx"
|
:key="idx"
|
||||||
@@ -157,7 +210,10 @@
|
|||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<span class="font-medium">{{ recipient.email }}</span>
|
<span class="font-medium">{{ recipient.email }}</span>
|
||||||
<span v-if="recipient.name" class="text-gray-600 ml-2">({{ recipient.name }})</span>
|
<span
|
||||||
|
v-if="recipient.name"
|
||||||
|
class="text-gray-600 ml-2"
|
||||||
|
>({{ recipient.name }})</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="text-xs">
|
<span class="text-xs">
|
||||||
{{ recipient.sent ? '✓ Versendet' : '✗ Fehler' }}
|
{{ recipient.sent ? '✓ Versendet' : '✗ Fehler' }}
|
||||||
@@ -165,7 +221,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="post.sentTo && post.sentTo.total === 0" class="border-t border-gray-200 mt-3 pt-3 text-sm text-gray-500">
|
<div
|
||||||
|
v-else-if="post.sentTo && post.sentTo.total === 0"
|
||||||
|
class="border-t border-gray-200 mt-3 pt-3 text-sm text-gray-500"
|
||||||
|
>
|
||||||
Keine Empfänger gefunden
|
Keine Empfänger gefunden
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -173,12 +232,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="p-6 text-center text-gray-500 text-sm border-t border-gray-200">
|
<div
|
||||||
|
v-else
|
||||||
|
class="p-6 text-center text-gray-500 text-sm border-t border-gray-200"
|
||||||
|
>
|
||||||
Noch keine Posts in dieser Gruppe
|
Noch keine Posts in dieser Gruppe
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="groups.length === 0" class="text-center py-12 text-gray-500">
|
<div
|
||||||
|
v-if="groups.length === 0"
|
||||||
|
class="text-center py-12 text-gray-500"
|
||||||
|
>
|
||||||
Noch keine Newsletter-Gruppen vorhanden.
|
Noch keine Newsletter-Gruppen vorhanden.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -199,7 +264,11 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="overflow-y-auto flex-1 p-6">
|
<div class="overflow-y-auto flex-1 p-6">
|
||||||
<form id="group-form" @submit.prevent="saveGroup" class="space-y-6">
|
<form
|
||||||
|
id="group-form"
|
||||||
|
class="space-y-6"
|
||||||
|
@submit.prevent="saveGroup"
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">
|
<label class="block text-sm font-medium text-gray-700 mb-2">
|
||||||
Name *
|
Name *
|
||||||
@@ -210,7 +279,7 @@
|
|||||||
required
|
required
|
||||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
placeholder="z.B. Allgemeiner Newsletter"
|
placeholder="z.B. Allgemeiner Newsletter"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@@ -222,7 +291,7 @@
|
|||||||
rows="3"
|
rows="3"
|
||||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
placeholder="Beschreibung der Newsletter-Gruppe"
|
placeholder="Beschreibung der Newsletter-Gruppe"
|
||||||
></textarea>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@@ -232,12 +301,18 @@
|
|||||||
<select
|
<select
|
||||||
v-model="groupFormData.type"
|
v-model="groupFormData.type"
|
||||||
required
|
required
|
||||||
@change="onGroupTypeChange"
|
|
||||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
|
@change="onGroupTypeChange"
|
||||||
>
|
>
|
||||||
<option value="">Bitte wählen</option>
|
<option value="">
|
||||||
<option value="subscription">Abonnenten-Newsletter</option>
|
Bitte wählen
|
||||||
<option value="group">Gruppen-Newsletter</option>
|
</option>
|
||||||
|
<option value="subscription">
|
||||||
|
Abonnenten-Newsletter
|
||||||
|
</option>
|
||||||
|
<option value="group">
|
||||||
|
Gruppen-Newsletter
|
||||||
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -249,8 +324,12 @@
|
|||||||
v-model="groupFormData.sendToExternal"
|
v-model="groupFormData.sendToExternal"
|
||||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
>
|
>
|
||||||
<option :value="false">Nur Intern</option>
|
<option :value="false">
|
||||||
<option :value="true">Auch Extern</option>
|
Nur Intern
|
||||||
|
</option>
|
||||||
|
<option :value="true">
|
||||||
|
Auch Extern
|
||||||
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -263,12 +342,24 @@
|
|||||||
required
|
required
|
||||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
>
|
>
|
||||||
<option value="">Bitte wählen</option>
|
<option value="">
|
||||||
<option value="alle">Alle</option>
|
Bitte wählen
|
||||||
<option value="erwachsene">Erwachsene</option>
|
</option>
|
||||||
<option value="nachwuchs">Nachwuchs</option>
|
<option value="alle">
|
||||||
<option value="mannschaftsspieler">Mannschaftsspieler</option>
|
Alle
|
||||||
<option value="vorstand">Vorstand</option>
|
</option>
|
||||||
|
<option value="erwachsene">
|
||||||
|
Erwachsene
|
||||||
|
</option>
|
||||||
|
<option value="nachwuchs">
|
||||||
|
Nachwuchs
|
||||||
|
</option>
|
||||||
|
<option value="mannschaftsspieler">
|
||||||
|
Mannschaftsspieler
|
||||||
|
</option>
|
||||||
|
<option value="vorstand">
|
||||||
|
Vorstand
|
||||||
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@@ -277,8 +368,8 @@
|
|||||||
<div class="p-6 border-t border-gray-200 flex justify-end space-x-3 flex-shrink-0">
|
<div class="p-6 border-t border-gray-200 flex justify-end space-x-3 flex-shrink-0">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@click="closeGroupModal"
|
|
||||||
class="px-4 py-2 text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors"
|
class="px-4 py-2 text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors"
|
||||||
|
@click="closeGroupModal"
|
||||||
>
|
>
|
||||||
Abbrechen
|
Abbrechen
|
||||||
</button>
|
</button>
|
||||||
@@ -310,7 +401,11 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="overflow-y-auto flex-1 p-6">
|
<div class="overflow-y-auto flex-1 p-6">
|
||||||
<form id="post-form" @submit.prevent="savePost" class="space-y-6">
|
<form
|
||||||
|
id="post-form"
|
||||||
|
class="space-y-6"
|
||||||
|
@submit.prevent="savePost"
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">
|
<label class="block text-sm font-medium text-gray-700 mb-2">
|
||||||
Titel *
|
Titel *
|
||||||
@@ -321,7 +416,7 @@
|
|||||||
required
|
required
|
||||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
placeholder="Post-Titel"
|
placeholder="Post-Titel"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@@ -336,28 +431,56 @@
|
|||||||
|
|
||||||
<div class="p-6 border-t border-gray-200 flex-shrink-0">
|
<div class="p-6 border-t border-gray-200 flex-shrink-0">
|
||||||
<!-- Erfolgsmeldung -->
|
<!-- Erfolgsmeldung -->
|
||||||
<div v-if="postSuccessMessage" class="space-y-4">
|
<div
|
||||||
|
v-if="postSuccessMessage"
|
||||||
|
class="space-y-4"
|
||||||
|
>
|
||||||
<div class="p-4 bg-green-50 border border-green-200 rounded-lg">
|
<div class="p-4 bg-green-50 border border-green-200 rounded-lg">
|
||||||
<div class="flex items-start">
|
<div class="flex items-start">
|
||||||
<div class="flex-shrink-0">
|
<div class="flex-shrink-0">
|
||||||
<svg class="w-5 h-5 text-green-600" fill="currentColor" viewBox="0 0 20 20">
|
<svg
|
||||||
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd" />
|
class="w-5 h-5 text-green-600"
|
||||||
|
fill="currentColor"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div class="ml-3 flex-1">
|
<div class="ml-3 flex-1">
|
||||||
<p class="text-sm font-medium text-green-800">
|
<p class="text-sm font-medium text-green-800">
|
||||||
{{ postSuccessMessage }}
|
{{ postSuccessMessage }}
|
||||||
</p>
|
</p>
|
||||||
<div v-if="postSuccessStats" class="mt-2 text-sm text-green-700">
|
<div
|
||||||
|
v-if="postSuccessStats"
|
||||||
|
class="mt-2 text-sm text-green-700"
|
||||||
|
>
|
||||||
<p>Empfänger: {{ postSuccessStats.sent }}/{{ postSuccessStats.total }} erfolgreich versendet</p>
|
<p>Empfänger: {{ postSuccessStats.sent }}/{{ postSuccessStats.total }} erfolgreich versendet</p>
|
||||||
<div v-if="postSuccessStats.failed > 0" class="mt-2">
|
<div
|
||||||
<p class="font-medium">⚠️ {{ postSuccessStats.failed }} Fehler beim Versenden:</p>
|
v-if="postSuccessStats.failed > 0"
|
||||||
<ul v-if="postSuccessStats.errorDetails" class="list-disc list-inside mt-1 space-y-1">
|
class="mt-2"
|
||||||
<li v-for="err in postSuccessStats.errorDetails" :key="err.email">
|
>
|
||||||
|
<p class="font-medium">
|
||||||
|
⚠️ {{ postSuccessStats.failed }} Fehler beim Versenden:
|
||||||
|
</p>
|
||||||
|
<ul
|
||||||
|
v-if="postSuccessStats.errorDetails"
|
||||||
|
class="list-disc list-inside mt-1 space-y-1"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
v-for="err in postSuccessStats.errorDetails"
|
||||||
|
:key="err.email"
|
||||||
|
>
|
||||||
{{ err.email }}: {{ err.error }}
|
{{ err.email }}: {{ err.error }}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p v-else-if="postSuccessStats.failedEmails" class="mt-1">
|
<p
|
||||||
|
v-else-if="postSuccessStats.failedEmails"
|
||||||
|
class="mt-1"
|
||||||
|
>
|
||||||
{{ postSuccessStats.failedEmails.join(', ') }}
|
{{ postSuccessStats.failedEmails.join(', ') }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -367,8 +490,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex justify-end">
|
<div class="flex justify-end">
|
||||||
<button
|
<button
|
||||||
@click="closePostModal"
|
|
||||||
class="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors"
|
class="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors"
|
||||||
|
@click="closePostModal"
|
||||||
>
|
>
|
||||||
Schließen
|
Schließen
|
||||||
</button>
|
</button>
|
||||||
@@ -376,11 +499,14 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Formular-Buttons -->
|
<!-- Formular-Buttons -->
|
||||||
<div v-else class="flex justify-end space-x-3">
|
<div
|
||||||
|
v-else
|
||||||
|
class="flex justify-end space-x-3"
|
||||||
|
>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@click="closePostModal"
|
|
||||||
class="px-4 py-2 text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors"
|
class="px-4 py-2 text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors"
|
||||||
|
@click="closePostModal"
|
||||||
>
|
>
|
||||||
Abbrechen
|
Abbrechen
|
||||||
</button>
|
</button>
|
||||||
@@ -410,25 +536,40 @@
|
|||||||
Abonnenten: {{ showSubscribersModalForGroup.name }}
|
Abonnenten: {{ showSubscribersModalForGroup.name }}
|
||||||
</h2>
|
</h2>
|
||||||
<button
|
<button
|
||||||
@click="showAddSubscriberModal = true"
|
|
||||||
class="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors text-sm flex items-center"
|
class="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors text-sm flex items-center"
|
||||||
|
@click="showAddSubscriberModal = true"
|
||||||
>
|
>
|
||||||
<Plus :size="16" class="mr-2" />
|
<Plus
|
||||||
|
:size="16"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
Empfänger hinzufügen
|
Empfänger hinzufügen
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="overflow-y-auto flex-1 p-6">
|
<div class="overflow-y-auto flex-1 p-6">
|
||||||
<div v-if="isLoadingSubscribers" class="flex items-center justify-center py-12">
|
<div
|
||||||
<Loader2 :size="40" class="animate-spin text-primary-600" />
|
v-if="isLoadingSubscribers"
|
||||||
|
class="flex items-center justify-center py-12"
|
||||||
|
>
|
||||||
|
<Loader2
|
||||||
|
:size="40"
|
||||||
|
class="animate-spin text-primary-600"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else-if="subscribers.length === 0" class="text-center py-12 text-gray-500">
|
<div
|
||||||
|
v-else-if="subscribers.length === 0"
|
||||||
|
class="text-center py-12 text-gray-500"
|
||||||
|
>
|
||||||
Keine Abonnenten gefunden.
|
Keine Abonnenten gefunden.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else class="space-y-4">
|
<div
|
||||||
|
v-else
|
||||||
|
class="space-y-4"
|
||||||
|
>
|
||||||
<div class="bg-gray-50 rounded-lg p-4 mb-4">
|
<div class="bg-gray-50 rounded-lg p-4 mb-4">
|
||||||
<p class="text-sm text-gray-600">
|
<p class="text-sm text-gray-600">
|
||||||
<strong>{{ subscribers.length }}</strong> Abonnent{{ subscribers.length !== 1 ? 'en' : '' }}
|
<strong>{{ subscribers.length }}</strong> Abonnent{{ subscribers.length !== 1 ? 'en' : '' }}
|
||||||
@@ -457,7 +598,11 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="bg-white divide-y divide-gray-200">
|
<tbody class="bg-white divide-y divide-gray-200">
|
||||||
<tr v-for="subscriber in subscribers" :key="subscriber.id" class="hover:bg-gray-50">
|
<tr
|
||||||
|
v-for="subscriber in subscribers"
|
||||||
|
:key="subscriber.id"
|
||||||
|
class="hover:bg-gray-50"
|
||||||
|
>
|
||||||
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-900">
|
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-900">
|
||||||
{{ subscriber.email }}
|
{{ subscriber.email }}
|
||||||
</td>
|
</td>
|
||||||
@@ -471,16 +616,16 @@
|
|||||||
subscriber.confirmed && !subscriber.unsubscribedAt
|
subscriber.confirmed && !subscriber.unsubscribedAt
|
||||||
? 'bg-green-100 text-green-800'
|
? 'bg-green-100 text-green-800'
|
||||||
: subscriber.unsubscribedAt
|
: subscriber.unsubscribedAt
|
||||||
? 'bg-red-100 text-red-800'
|
? 'bg-red-100 text-red-800'
|
||||||
: 'bg-yellow-100 text-yellow-800'
|
: 'bg-yellow-100 text-yellow-800'
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
{{
|
{{
|
||||||
subscriber.confirmed && !subscriber.unsubscribedAt
|
subscriber.confirmed && !subscriber.unsubscribedAt
|
||||||
? 'Bestätigt'
|
? 'Bestätigt'
|
||||||
: subscriber.unsubscribedAt
|
: subscriber.unsubscribedAt
|
||||||
? 'Abgemeldet'
|
? 'Abgemeldet'
|
||||||
: 'Ausstehend'
|
: 'Ausstehend'
|
||||||
}}
|
}}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
@@ -489,9 +634,9 @@
|
|||||||
</td>
|
</td>
|
||||||
<td class="px-4 py-3 whitespace-nowrap text-right text-sm font-medium">
|
<td class="px-4 py-3 whitespace-nowrap text-right text-sm font-medium">
|
||||||
<button
|
<button
|
||||||
@click="removeSubscriber(subscriber.id)"
|
|
||||||
class="text-red-600 hover:text-red-900"
|
class="text-red-600 hover:text-red-900"
|
||||||
title="Abonnent entfernen"
|
title="Abonnent entfernen"
|
||||||
|
@click="removeSubscriber(subscriber.id)"
|
||||||
>
|
>
|
||||||
<Trash2 :size="18" />
|
<Trash2 :size="18" />
|
||||||
</button>
|
</button>
|
||||||
@@ -506,8 +651,8 @@
|
|||||||
<div class="p-6 border-t border-gray-200 flex justify-end flex-shrink-0">
|
<div class="p-6 border-t border-gray-200 flex justify-end flex-shrink-0">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@click="closeSubscribersModal"
|
|
||||||
class="px-4 py-2 bg-gray-100 text-gray-700 rounded-lg hover:bg-gray-200 transition-colors"
|
class="px-4 py-2 bg-gray-100 text-gray-700 rounded-lg hover:bg-gray-200 transition-colors"
|
||||||
|
@click="closeSubscribersModal"
|
||||||
>
|
>
|
||||||
Schließen
|
Schließen
|
||||||
</button>
|
</button>
|
||||||
@@ -532,7 +677,11 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="overflow-y-auto flex-1 p-6">
|
<div class="overflow-y-auto flex-1 p-6">
|
||||||
<form id="add-subscriber-form" @submit.prevent="addSubscriber" class="space-y-6">
|
<form
|
||||||
|
id="add-subscriber-form"
|
||||||
|
class="space-y-6"
|
||||||
|
@submit.prevent="addSubscriber"
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">
|
<label class="block text-sm font-medium text-gray-700 mb-2">
|
||||||
E-Mail-Adresse *
|
E-Mail-Adresse *
|
||||||
@@ -543,7 +692,7 @@
|
|||||||
required
|
required
|
||||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
placeholder="empfaenger@example.com"
|
placeholder="empfaenger@example.com"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@@ -555,7 +704,7 @@
|
|||||||
type="text"
|
type="text"
|
||||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
placeholder="Name des Empfängers"
|
placeholder="Name des Empfängers"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@@ -567,17 +716,23 @@
|
|||||||
rows="4"
|
rows="4"
|
||||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
placeholder="Diese Nachricht wird in der Bestätigungsmail angezeigt..."
|
placeholder="Diese Nachricht wird in der Bestätigungsmail angezeigt..."
|
||||||
></textarea>
|
/>
|
||||||
<p class="text-xs text-gray-500 mt-1">
|
<p class="text-xs text-gray-500 mt-1">
|
||||||
Diese Nachricht wird in der Bestätigungsmail angezeigt, um den Empfänger persönlich anzusprechen.
|
Diese Nachricht wird in der Bestätigungsmail angezeigt, um den Empfänger persönlich anzusprechen.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="addSubscriberError" class="p-3 bg-red-50 border border-red-200 rounded-lg text-red-700 text-sm">
|
<div
|
||||||
|
v-if="addSubscriberError"
|
||||||
|
class="p-3 bg-red-50 border border-red-200 rounded-lg text-red-700 text-sm"
|
||||||
|
>
|
||||||
{{ addSubscriberError }}
|
{{ addSubscriberError }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="addSubscriberSuccess" class="p-3 bg-green-50 border border-green-200 rounded-lg text-green-700 text-sm">
|
<div
|
||||||
|
v-if="addSubscriberSuccess"
|
||||||
|
class="p-3 bg-green-50 border border-green-200 rounded-lg text-green-700 text-sm"
|
||||||
|
>
|
||||||
{{ addSubscriberSuccess }}
|
{{ addSubscriberSuccess }}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@@ -586,9 +741,9 @@
|
|||||||
<div class="p-6 border-t border-gray-200 flex justify-end space-x-3 flex-shrink-0">
|
<div class="p-6 border-t border-gray-200 flex justify-end space-x-3 flex-shrink-0">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@click="closeAddSubscriberModal"
|
|
||||||
class="px-4 py-2 text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors"
|
class="px-4 py-2 text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors"
|
||||||
:disabled="isAddingSubscriber"
|
:disabled="isAddingSubscriber"
|
||||||
|
@click="closeAddSubscriberModal"
|
||||||
>
|
>
|
||||||
Abbrechen
|
Abbrechen
|
||||||
</button>
|
</button>
|
||||||
@@ -598,7 +753,11 @@
|
|||||||
class="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors flex items-center disabled:opacity-50"
|
class="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors flex items-center disabled:opacity-50"
|
||||||
:disabled="isAddingSubscriber"
|
:disabled="isAddingSubscriber"
|
||||||
>
|
>
|
||||||
<Loader2 v-if="isAddingSubscriber" :size="16" class="animate-spin mr-2" />
|
<Loader2
|
||||||
|
v-if="isAddingSubscriber"
|
||||||
|
:size="16"
|
||||||
|
class="animate-spin mr-2"
|
||||||
|
/>
|
||||||
<span>{{ isAddingSubscriber ? 'Wird hinzugefügt...' : 'Hinzufügen' }}</span>
|
<span>{{ isAddingSubscriber ? 'Wird hinzugefügt...' : 'Hinzufügen' }}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,25 +2,36 @@
|
|||||||
<div class="min-h-full py-16 bg-gray-50">
|
<div class="min-h-full py-16 bg-gray-50">
|
||||||
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<div class="flex items-center justify-between mb-6">
|
<div class="flex items-center justify-between mb-6">
|
||||||
<h1 class="text-3xl sm:text-4xl font-display font-bold text-gray-900">Satzung verwalten</h1>
|
<h1 class="text-3xl sm:text-4xl font-display font-bold text-gray-900">
|
||||||
|
Satzung verwalten
|
||||||
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-6 mb-6">
|
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-6 mb-6">
|
||||||
<h2 class="text-xl font-semibold mb-4">PDF-Upload</h2>
|
<h2 class="text-xl font-semibold mb-4">
|
||||||
|
PDF-Upload
|
||||||
|
</h2>
|
||||||
|
|
||||||
<form @submit.prevent="uploadPdf" enctype="multipart/form-data" class="space-y-4">
|
<form
|
||||||
|
enctype="multipart/form-data"
|
||||||
|
class="space-y-4"
|
||||||
|
@submit.prevent="uploadPdf"
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<label for="pdf-file" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="pdf-file"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
Neue Satzung hochladen (PDF)
|
Neue Satzung hochladen (PDF)
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
ref="fileInput"
|
|
||||||
id="pdf-file"
|
id="pdf-file"
|
||||||
|
ref="fileInput"
|
||||||
type="file"
|
type="file"
|
||||||
accept=".pdf"
|
accept=".pdf"
|
||||||
@change="handleFileSelect"
|
|
||||||
class="block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-lg file:border-0 file:text-sm file:font-semibold file:bg-primary-50 file:text-primary-700 hover:file:bg-primary-100"
|
class="block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-lg file:border-0 file:text-sm file:font-semibold file:bg-primary-50 file:text-primary-700 hover:file:bg-primary-100"
|
||||||
/>
|
@change="handleFileSelect"
|
||||||
|
>
|
||||||
<p class="mt-1 text-sm text-gray-500">
|
<p class="mt-1 text-sm text-gray-500">
|
||||||
Nur PDF-Dateien bis 10MB sind erlaubt
|
Nur PDF-Dateien bis 10MB sind erlaubt
|
||||||
</p>
|
</p>
|
||||||
@@ -31,20 +42,44 @@
|
|||||||
:disabled="!selectedFile || uploading"
|
:disabled="!selectedFile || uploading"
|
||||||
class="inline-flex items-center px-4 py-2 rounded-lg bg-primary-600 text-white hover:bg-primary-700 disabled:opacity-50 disabled:cursor-not-allowed"
|
class="inline-flex items-center px-4 py-2 rounded-lg bg-primary-600 text-white hover:bg-primary-700 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
>
|
>
|
||||||
<svg v-if="uploading" class="animate-spin -ml-1 mr-3 h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
<svg
|
||||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
v-if="uploading"
|
||||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
class="animate-spin -ml-1 mr-3 h-5 w-5 text-white"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<circle
|
||||||
|
class="opacity-25"
|
||||||
|
cx="12"
|
||||||
|
cy="12"
|
||||||
|
r="10"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="4"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
class="opacity-75"
|
||||||
|
fill="currentColor"
|
||||||
|
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
{{ uploading ? 'Wird hochgeladen...' : 'PDF hochladen' }}
|
{{ uploading ? 'Wird hochgeladen...' : 'PDF hochladen' }}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="currentPdfUrl" class="bg-white rounded-xl shadow-sm border border-gray-200 p-6">
|
<div
|
||||||
<h2 class="text-xl font-semibold mb-4">Aktuelle Satzung</h2>
|
v-if="currentPdfUrl"
|
||||||
|
class="bg-white rounded-xl shadow-sm border border-gray-200 p-6"
|
||||||
|
>
|
||||||
|
<h2 class="text-xl font-semibold mb-4">
|
||||||
|
Aktuelle Satzung
|
||||||
|
</h2>
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p class="text-gray-600">PDF-Datei verfügbar</p>
|
<p class="text-gray-600">
|
||||||
|
PDF-Datei verfügbar
|
||||||
|
</p>
|
||||||
<a
|
<a
|
||||||
:href="currentPdfUrl"
|
:href="currentPdfUrl"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@@ -59,7 +94,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="message" class="mt-4 p-4 rounded-lg" :class="messageType === 'success' ? 'bg-green-50 text-green-700' : 'bg-red-50 text-red-700'">
|
<div
|
||||||
|
v-if="message"
|
||||||
|
class="mt-4 p-4 rounded-lg"
|
||||||
|
:class="messageType === 'success' ? 'bg-green-50 text-green-700' : 'bg-red-50 text-red-700'"
|
||||||
|
>
|
||||||
{{ message }}
|
{{ message }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,15 +4,35 @@
|
|||||||
<div class="fixed top-20 left-0 right-0 z-40 bg-white border-b border-gray-200 shadow-sm">
|
<div class="fixed top-20 left-0 right-0 z-40 bg-white border-b border-gray-200 shadow-sm">
|
||||||
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-3 sm:py-4">
|
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-3 sm:py-4">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<h1 class="text-xl sm:text-3xl font-display font-bold text-gray-900">Spielpläne bearbeiten</h1>
|
<h1 class="text-xl sm:text-3xl font-display font-bold text-gray-900">
|
||||||
|
Spielpläne bearbeiten
|
||||||
|
</h1>
|
||||||
<div class="space-x-3">
|
<div class="space-x-3">
|
||||||
<button @click="showUploadModal = true" class="inline-flex items-center px-3 py-1.5 sm:px-4 sm:py-2 rounded-lg bg-green-600 text-white hover:bg-green-700 text-sm sm:text-base">
|
<button
|
||||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
class="inline-flex items-center px-3 py-1.5 sm:px-4 sm:py-2 rounded-lg bg-green-600 text-white hover:bg-green-700 text-sm sm:text-base"
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"></path>
|
@click="showUploadModal = true"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="w-4 h-4 mr-2"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
CSV hochladen
|
CSV hochladen
|
||||||
</button>
|
</button>
|
||||||
<button @click="save" class="inline-flex items-center px-3 py-1.5 sm:px-4 sm:py-2 rounded-lg bg-primary-600 text-white hover:bg-primary-700 text-sm sm:text-base">Speichern</button>
|
<button
|
||||||
|
class="inline-flex items-center px-3 py-1.5 sm:px-4 sm:py-2 rounded-lg bg-primary-600 text-white hover:bg-primary-700 text-sm sm:text-base"
|
||||||
|
@click="save"
|
||||||
|
>
|
||||||
|
Speichern
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -21,24 +41,45 @@
|
|||||||
<!-- Content with top padding -->
|
<!-- Content with top padding -->
|
||||||
<div class="pt-20 pb-16">
|
<div class="pt-20 pb-16">
|
||||||
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
|
||||||
<!-- CSV Upload Section -->
|
<!-- CSV Upload Section -->
|
||||||
<div class="mb-8 bg-white rounded-xl shadow-lg p-6">
|
<div class="mb-8 bg-white rounded-xl shadow-lg p-6">
|
||||||
<h2 class="text-xl font-semibold text-gray-900 mb-4">Vereins-Spielplan (CSV)</h2>
|
<h2 class="text-xl font-semibold text-gray-900 mb-4">
|
||||||
|
Vereins-Spielplan (CSV)
|
||||||
|
</h2>
|
||||||
|
|
||||||
<!-- Current File Info -->
|
<!-- Current File Info -->
|
||||||
<div v-if="currentFile" class="mb-4 p-4 bg-green-50 border border-green-200 rounded-lg">
|
<div
|
||||||
|
v-if="currentFile"
|
||||||
|
class="mb-4 p-4 bg-green-50 border border-green-200 rounded-lg"
|
||||||
|
>
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<svg class="w-5 h-5 text-green-600 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
class="w-5 h-5 text-green-600 mr-2"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<div>
|
<div>
|
||||||
<p class="text-sm font-medium text-green-800">{{ currentFile.name }}</p>
|
<p class="text-sm font-medium text-green-800">
|
||||||
<p class="text-xs text-green-600">{{ currentFile.size }} bytes, {{ currentFile.lastModified ? new Date(currentFile.lastModified).toLocaleDateString('de-DE') : 'Unbekannt' }}</p>
|
{{ currentFile.name }}
|
||||||
|
</p>
|
||||||
|
<p class="text-xs text-green-600">
|
||||||
|
{{ currentFile.size }} bytes, {{ currentFile.lastModified ? new Date(currentFile.lastModified).toLocaleDateString('de-DE') : 'Unbekannt' }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button @click="removeFile" class="px-3 py-1 text-sm bg-red-100 hover:bg-red-200 text-red-700 rounded-lg transition-colors">
|
<button
|
||||||
|
class="px-3 py-1 text-sm bg-red-100 hover:bg-red-200 text-red-700 rounded-lg transition-colors"
|
||||||
|
@click="removeFile"
|
||||||
|
>
|
||||||
Entfernen
|
Entfernen
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -46,46 +87,75 @@
|
|||||||
|
|
||||||
<!-- Upload Area -->
|
<!-- Upload Area -->
|
||||||
<div
|
<div
|
||||||
|
class="border-2 border-dashed border-gray-300 rounded-lg p-8 text-center hover:border-primary-400 hover:bg-primary-50 transition-colors cursor-pointer"
|
||||||
|
:class="{ 'border-primary-400 bg-primary-50': isDragOver }"
|
||||||
@click="triggerFileInput"
|
@click="triggerFileInput"
|
||||||
@dragover.prevent
|
@dragover.prevent
|
||||||
@dragenter.prevent
|
@dragenter.prevent
|
||||||
@drop.prevent="handleFileDrop"
|
@drop.prevent="handleFileDrop"
|
||||||
class="border-2 border-dashed border-gray-300 rounded-lg p-8 text-center hover:border-primary-400 hover:bg-primary-50 transition-colors cursor-pointer"
|
|
||||||
:class="{ 'border-primary-400 bg-primary-50': isDragOver }"
|
|
||||||
>
|
>
|
||||||
<svg class="w-12 h-12 text-gray-400 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"></path>
|
class="w-12 h-12 text-gray-400 mx-auto mb-4"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<p class="text-lg font-medium text-gray-900 mb-2">CSV-Datei hochladen</p>
|
<p class="text-lg font-medium text-gray-900 mb-2">
|
||||||
<p class="text-sm text-gray-600 mb-4">Klicken Sie hier oder ziehen Sie eine CSV-Datei hierher</p>
|
CSV-Datei hochladen
|
||||||
<p class="text-xs text-gray-500">Unterstützte Formate: .csv</p>
|
</p>
|
||||||
|
<p class="text-sm text-gray-600 mb-4">
|
||||||
|
Klicken Sie hier oder ziehen Sie eine CSV-Datei hierher
|
||||||
|
</p>
|
||||||
|
<p class="text-xs text-gray-500">
|
||||||
|
Unterstützte Formate: .csv
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<input
|
<input
|
||||||
ref="fileInput"
|
ref="fileInput"
|
||||||
type="file"
|
type="file"
|
||||||
accept=".csv"
|
accept=".csv"
|
||||||
@change="handleFileSelect"
|
|
||||||
class="hidden"
|
class="hidden"
|
||||||
/>
|
@change="handleFileSelect"
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Column Selection -->
|
<!-- Column Selection -->
|
||||||
<div v-if="csvData.length > 0 && !columnsSelected" class="bg-white rounded-xl shadow-lg p-6 mb-8">
|
<div
|
||||||
<h2 class="text-xl font-semibold text-gray-900 mb-4">Spalten auswählen</h2>
|
v-if="csvData.length > 0 && !columnsSelected"
|
||||||
<p class="text-sm text-gray-600 mb-6">Wählen Sie die Spalten aus, die für den Spielplan gespeichert werden sollen:</p>
|
class="bg-white rounded-xl shadow-lg p-6 mb-8"
|
||||||
|
>
|
||||||
|
<h2 class="text-xl font-semibold text-gray-900 mb-4">
|
||||||
|
Spalten auswählen
|
||||||
|
</h2>
|
||||||
|
<p class="text-sm text-gray-600 mb-6">
|
||||||
|
Wählen Sie die Spalten aus, die für den Spielplan gespeichert werden sollen:
|
||||||
|
</p>
|
||||||
|
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<div v-for="(header, index) in csvHeaders" :key="index"
|
<div
|
||||||
class="flex items-center justify-between p-4 border border-gray-200 rounded-lg hover:bg-gray-50">
|
v-for="(header, index) in csvHeaders"
|
||||||
|
:key="index"
|
||||||
|
class="flex items-center justify-between p-4 border border-gray-200 rounded-lg hover:bg-gray-50"
|
||||||
|
>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<input
|
<input
|
||||||
:id="`column-${index}`"
|
:id="`column-${index}`"
|
||||||
v-model="selectedColumns[index]"
|
v-model="selectedColumns[index]"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
class="h-4 w-4 text-primary-600 focus:ring-primary-500 border-gray-300 rounded"
|
class="h-4 w-4 text-primary-600 focus:ring-primary-500 border-gray-300 rounded"
|
||||||
/>
|
>
|
||||||
<label :for="`column-${index}`" class="ml-3 text-sm font-medium text-gray-900">
|
<label
|
||||||
|
:for="`column-${index}`"
|
||||||
|
class="ml-3 text-sm font-medium text-gray-900"
|
||||||
|
>
|
||||||
{{ header }}
|
{{ header }}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
@@ -100,18 +170,29 @@
|
|||||||
{{ selectedColumnsCount }} von {{ csvHeaders.length }} Spalten ausgewählt
|
{{ selectedColumnsCount }} von {{ csvHeaders.length }} Spalten ausgewählt
|
||||||
</div>
|
</div>
|
||||||
<div class="space-x-3">
|
<div class="space-x-3">
|
||||||
<button @click="selectAllColumns" class="px-4 py-2 text-sm bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg transition-colors">
|
<button
|
||||||
|
class="px-4 py-2 text-sm bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg transition-colors"
|
||||||
|
@click="selectAllColumns"
|
||||||
|
>
|
||||||
Alle auswählen
|
Alle auswählen
|
||||||
</button>
|
</button>
|
||||||
<button @click="deselectAllColumns" class="px-4 py-2 text-sm bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg transition-colors">
|
<button
|
||||||
|
class="px-4 py-2 text-sm bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg transition-colors"
|
||||||
|
@click="deselectAllColumns"
|
||||||
|
>
|
||||||
Alle abwählen
|
Alle abwählen
|
||||||
</button>
|
</button>
|
||||||
<button @click="suggestHalleColumns" class="px-4 py-2 text-sm bg-blue-100 hover:bg-blue-200 text-blue-700 rounded-lg transition-colors">
|
<button
|
||||||
|
class="px-4 py-2 text-sm bg-blue-100 hover:bg-blue-200 text-blue-700 rounded-lg transition-colors"
|
||||||
|
@click="suggestHalleColumns"
|
||||||
|
>
|
||||||
Halle-Spalten vorschlagen
|
Halle-Spalten vorschlagen
|
||||||
</button>
|
</button>
|
||||||
<button @click="confirmColumnSelection"
|
<button
|
||||||
:disabled="selectedColumnsCount === 0"
|
:disabled="selectedColumnsCount === 0"
|
||||||
class="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors disabled:bg-gray-400">
|
class="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors disabled:bg-gray-400"
|
||||||
|
@click="confirmColumnSelection"
|
||||||
|
>
|
||||||
Auswahl bestätigen
|
Auswahl bestätigen
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -119,14 +200,25 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Data Preview -->
|
<!-- Data Preview -->
|
||||||
<div v-if="csvData.length > 0 && columnsSelected" class="bg-white rounded-xl shadow-lg p-6">
|
<div
|
||||||
|
v-if="csvData.length > 0 && columnsSelected"
|
||||||
|
class="bg-white rounded-xl shadow-lg p-6"
|
||||||
|
>
|
||||||
<div class="flex items-center justify-between mb-4">
|
<div class="flex items-center justify-between mb-4">
|
||||||
<h2 class="text-xl font-semibold text-gray-900">Datenvorschau</h2>
|
<h2 class="text-xl font-semibold text-gray-900">
|
||||||
|
Datenvorschau
|
||||||
|
</h2>
|
||||||
<div class="flex space-x-2">
|
<div class="flex space-x-2">
|
||||||
<button @click="exportCSV" class="px-3 py-1 text-sm bg-blue-100 hover:bg-blue-200 text-blue-700 rounded-lg transition-colors">
|
<button
|
||||||
|
class="px-3 py-1 text-sm bg-blue-100 hover:bg-blue-200 text-blue-700 rounded-lg transition-colors"
|
||||||
|
@click="exportCSV"
|
||||||
|
>
|
||||||
CSV exportieren
|
CSV exportieren
|
||||||
</button>
|
</button>
|
||||||
<button @click="clearData" class="px-3 py-1 text-sm bg-red-100 hover:bg-red-200 text-red-700 rounded-lg transition-colors">
|
<button
|
||||||
|
class="px-3 py-1 text-sm bg-red-100 hover:bg-red-200 text-red-700 rounded-lg transition-colors"
|
||||||
|
@click="clearData"
|
||||||
|
>
|
||||||
Daten löschen
|
Daten löschen
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -137,17 +229,26 @@
|
|||||||
<table class="min-w-full divide-y divide-gray-200">
|
<table class="min-w-full divide-y divide-gray-200">
|
||||||
<thead class="bg-gray-50">
|
<thead class="bg-gray-50">
|
||||||
<tr>
|
<tr>
|
||||||
<th v-for="(header, index) in (columnsSelected ? filteredCsvHeaders : csvHeaders)" :key="index"
|
<th
|
||||||
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
v-for="(header, index) in (columnsSelected ? filteredCsvHeaders : csvHeaders)"
|
||||||
|
:key="index"
|
||||||
|
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
|
||||||
|
>
|
||||||
{{ header }}
|
{{ header }}
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="bg-white divide-y divide-gray-200">
|
<tbody class="bg-white divide-y divide-gray-200">
|
||||||
<tr v-for="(row, rowIndex) in (columnsSelected ? filteredCsvData : csvData).slice(0, 10)" :key="rowIndex"
|
<tr
|
||||||
:class="rowIndex % 2 === 0 ? 'bg-white' : 'bg-gray-50'">
|
v-for="(row, rowIndex) in (columnsSelected ? filteredCsvData : csvData).slice(0, 10)"
|
||||||
<td v-for="(cell, cellIndex) in row" :key="cellIndex"
|
:key="rowIndex"
|
||||||
class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
|
:class="rowIndex % 2 === 0 ? 'bg-white' : 'bg-gray-50'"
|
||||||
|
>
|
||||||
|
<td
|
||||||
|
v-for="(cell, cellIndex) in row"
|
||||||
|
:key="cellIndex"
|
||||||
|
class="px-6 py-4 whitespace-nowrap text-sm text-gray-900"
|
||||||
|
>
|
||||||
{{ cell }}
|
{{ cell }}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -155,7 +256,10 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="(columnsSelected ? filteredCsvData : csvData).length > 10" class="mt-4 text-center text-sm text-gray-600">
|
<div
|
||||||
|
v-if="(columnsSelected ? filteredCsvData : csvData).length > 10"
|
||||||
|
class="mt-4 text-center text-sm text-gray-600"
|
||||||
|
>
|
||||||
Zeige erste 10 von {{ (columnsSelected ? filteredCsvData : csvData).length }} Zeilen
|
Zeige erste 10 von {{ (columnsSelected ? filteredCsvData : csvData).length }} Zeilen
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -166,12 +270,29 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Empty State -->
|
<!-- Empty State -->
|
||||||
<div v-else class="text-center py-12 bg-white rounded-xl shadow-lg">
|
<div
|
||||||
<svg class="w-12 h-12 text-gray-400 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
v-else
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
class="text-center py-12 bg-white rounded-xl shadow-lg"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="w-12 h-12 text-gray-400 mx-auto mb-4"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<p class="text-gray-600">Keine CSV-Daten geladen.</p>
|
<p class="text-gray-600">
|
||||||
<p class="text-sm text-gray-500 mt-2">Laden Sie eine CSV-Datei hoch, um Spielplandaten zu verwalten.</p>
|
Keine CSV-Daten geladen.
|
||||||
|
</p>
|
||||||
|
<p class="text-sm text-gray-500 mt-2">
|
||||||
|
Laden Sie eine CSV-Datei hoch, um Spielplandaten zu verwalten.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -183,7 +304,9 @@
|
|||||||
@click.self="closeUploadModal"
|
@click.self="closeUploadModal"
|
||||||
>
|
>
|
||||||
<div class="bg-white rounded-lg max-w-md w-full p-6">
|
<div class="bg-white rounded-lg max-w-md w-full p-6">
|
||||||
<h3 class="text-lg font-semibold text-gray-900 mb-4">CSV-Datei hochladen</h3>
|
<h3 class="text-lg font-semibold text-gray-900 mb-4">
|
||||||
|
CSV-Datei hochladen
|
||||||
|
</h3>
|
||||||
|
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<div>
|
<div>
|
||||||
@@ -192,18 +315,27 @@
|
|||||||
ref="modalFileInput"
|
ref="modalFileInput"
|
||||||
type="file"
|
type="file"
|
||||||
accept=".csv"
|
accept=".csv"
|
||||||
@change="handleModalFileSelect"
|
|
||||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
/>
|
@change="handleModalFileSelect"
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="selectedFile" class="p-3 bg-gray-50 rounded-lg">
|
<div
|
||||||
<p class="text-sm text-gray-700"><strong>Ausgewählte Datei:</strong> {{ selectedFile.name }}</p>
|
v-if="selectedFile"
|
||||||
<p class="text-xs text-gray-500">{{ selectedFile.size }} bytes</p>
|
class="p-3 bg-gray-50 rounded-lg"
|
||||||
|
>
|
||||||
|
<p class="text-sm text-gray-700">
|
||||||
|
<strong>Ausgewählte Datei:</strong> {{ selectedFile.name }}
|
||||||
|
</p>
|
||||||
|
<p class="text-xs text-gray-500">
|
||||||
|
{{ selectedFile.size }} bytes
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-blue-50 p-4 rounded-lg">
|
<div class="bg-blue-50 p-4 rounded-lg">
|
||||||
<h4 class="text-sm font-medium text-blue-800 mb-2">Erwartetes CSV-Format:</h4>
|
<h4 class="text-sm font-medium text-blue-800 mb-2">
|
||||||
|
Erwartetes CSV-Format:
|
||||||
|
</h4>
|
||||||
<div class="text-xs text-blue-700 space-y-1">
|
<div class="text-xs text-blue-700 space-y-1">
|
||||||
<p>• Erste Zeile: Spaltenüberschriften</p>
|
<p>• Erste Zeile: Spaltenüberschriften</p>
|
||||||
<p>• Spalten: Datum, Mannschaft, Gegner, Ort, Uhrzeit, etc.</p>
|
<p>• Spalten: Datum, Mannschaft, Gegner, Ort, Uhrzeit, etc.</p>
|
||||||
@@ -215,15 +347,15 @@
|
|||||||
|
|
||||||
<div class="flex justify-end space-x-3 pt-4">
|
<div class="flex justify-end space-x-3 pt-4">
|
||||||
<button
|
<button
|
||||||
@click="closeUploadModal"
|
|
||||||
class="px-4 py-2 text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors"
|
class="px-4 py-2 text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors"
|
||||||
|
@click="closeUploadModal"
|
||||||
>
|
>
|
||||||
Abbrechen
|
Abbrechen
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@click="processSelectedFile"
|
|
||||||
:disabled="!selectedFile"
|
:disabled="!selectedFile"
|
||||||
class="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors disabled:bg-gray-400"
|
class="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors disabled:bg-gray-400"
|
||||||
|
@click="processSelectedFile"
|
||||||
>
|
>
|
||||||
Hochladen
|
Hochladen
|
||||||
</button>
|
</button>
|
||||||
@@ -237,9 +369,13 @@
|
|||||||
class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4"
|
class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4"
|
||||||
>
|
>
|
||||||
<div class="bg-white rounded-lg max-w-sm w-full p-6 text-center">
|
<div class="bg-white rounded-lg max-w-sm w-full p-6 text-center">
|
||||||
<div class="animate-spin rounded-full h-12 w-12 border-b-2 border-primary-600 mx-auto mb-4"></div>
|
<div class="animate-spin rounded-full h-12 w-12 border-b-2 border-primary-600 mx-auto mb-4" />
|
||||||
<h3 class="text-lg font-semibold text-gray-900 mb-2">Verarbeitung läuft...</h3>
|
<h3 class="text-lg font-semibold text-gray-900 mb-2">
|
||||||
<p class="text-sm text-gray-600">{{ processingMessage }}</p>
|
Verarbeitung läuft...
|
||||||
|
</h3>
|
||||||
|
<p class="text-sm text-gray-600">
|
||||||
|
{{ processingMessage }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,35 +9,63 @@
|
|||||||
<div class="w-24 h-1 bg-primary-600 mb-4" />
|
<div class="w-24 h-1 bg-primary-600 mb-4" />
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
@click="openAddModal"
|
|
||||||
class="flex items-center px-4 py-2 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors"
|
class="flex items-center px-4 py-2 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors"
|
||||||
|
@click="openAddModal"
|
||||||
>
|
>
|
||||||
<Plus :size="20" class="mr-2" />
|
<Plus
|
||||||
|
:size="20"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
Termin hinzufügen
|
Termin hinzufügen
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Loading State -->
|
<!-- Loading State -->
|
||||||
<div v-if="isLoading" class="flex items-center justify-center py-12">
|
<div
|
||||||
<Loader2 :size="40" class="animate-spin text-primary-600" />
|
v-if="isLoading"
|
||||||
|
class="flex items-center justify-center py-12"
|
||||||
|
>
|
||||||
|
<Loader2
|
||||||
|
:size="40"
|
||||||
|
class="animate-spin text-primary-600"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Termine Table -->
|
<!-- Termine Table -->
|
||||||
<div v-else class="bg-white rounded-xl shadow-lg overflow-hidden">
|
<div
|
||||||
|
v-else
|
||||||
|
class="bg-white rounded-xl shadow-lg overflow-hidden"
|
||||||
|
>
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="min-w-full divide-y divide-gray-200">
|
<table class="min-w-full divide-y divide-gray-200">
|
||||||
<thead class="bg-gray-50">
|
<thead class="bg-gray-50">
|
||||||
<tr>
|
<tr>
|
||||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Datum</th>
|
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Uhrzeit</th>
|
Datum
|
||||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Titel</th>
|
</th>
|
||||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Beschreibung</th>
|
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Kategorie</th>
|
Uhrzeit
|
||||||
<th class="px-4 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">Aktionen</th>
|
</th>
|
||||||
|
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||||
|
Titel
|
||||||
|
</th>
|
||||||
|
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||||
|
Beschreibung
|
||||||
|
</th>
|
||||||
|
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||||
|
Kategorie
|
||||||
|
</th>
|
||||||
|
<th class="px-4 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||||
|
Aktionen
|
||||||
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="bg-white divide-y divide-gray-200">
|
<tbody class="bg-white divide-y divide-gray-200">
|
||||||
<tr v-for="termin in termine" :key="`${termin.datum}-${termin.uhrzeit || ''}-${termin.titel}`" class="hover:bg-gray-50">
|
<tr
|
||||||
|
v-for="termin in termine"
|
||||||
|
:key="`${termin.datum}-${termin.uhrzeit || ''}-${termin.titel}`"
|
||||||
|
class="hover:bg-gray-50"
|
||||||
|
>
|
||||||
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-900">
|
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-900">
|
||||||
{{ formatDate(termin.datum) }}
|
{{ formatDate(termin.datum) }}
|
||||||
</td>
|
</td>
|
||||||
@@ -66,16 +94,16 @@
|
|||||||
</td>
|
</td>
|
||||||
<td class="px-4 py-3 whitespace-nowrap text-right text-sm font-medium space-x-3">
|
<td class="px-4 py-3 whitespace-nowrap text-right text-sm font-medium space-x-3">
|
||||||
<button
|
<button
|
||||||
@click="openEditModal(termin)"
|
|
||||||
class="text-gray-600 hover:text-gray-900"
|
class="text-gray-600 hover:text-gray-900"
|
||||||
title="Bearbeiten"
|
title="Bearbeiten"
|
||||||
|
@click="openEditModal(termin)"
|
||||||
>
|
>
|
||||||
<Pencil :size="18" />
|
<Pencil :size="18" />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@click="confirmDelete(termin)"
|
|
||||||
class="text-red-600 hover:text-red-900"
|
class="text-red-600 hover:text-red-900"
|
||||||
title="Löschen"
|
title="Löschen"
|
||||||
|
@click="confirmDelete(termin)"
|
||||||
>
|
>
|
||||||
<Trash2 :size="18" />
|
<Trash2 :size="18" />
|
||||||
</button>
|
</button>
|
||||||
@@ -85,7 +113,10 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="termine.length === 0" class="text-center py-12 text-gray-500">
|
<div
|
||||||
|
v-if="termine.length === 0"
|
||||||
|
class="text-center py-12 text-gray-500"
|
||||||
|
>
|
||||||
Keine Termine vorhanden.
|
Keine Termine vorhanden.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -101,7 +132,10 @@
|
|||||||
{{ isEditing ? 'Termin bearbeiten' : 'Termin hinzufügen' }}
|
{{ isEditing ? 'Termin bearbeiten' : 'Termin hinzufügen' }}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<form @submit.prevent="saveTermin" class="space-y-4">
|
<form
|
||||||
|
class="space-y-4"
|
||||||
|
@submit.prevent="saveTermin"
|
||||||
|
>
|
||||||
<div class="grid grid-cols-3 gap-4">
|
<div class="grid grid-cols-3 gap-4">
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Datum *</label>
|
<label class="block text-sm font-medium text-gray-700 mb-2">Datum *</label>
|
||||||
@@ -111,7 +145,7 @@
|
|||||||
required
|
required
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||||
:disabled="isSaving"
|
:disabled="isSaving"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Uhrzeit</label>
|
<label class="block text-sm font-medium text-gray-700 mb-2">Uhrzeit</label>
|
||||||
@@ -120,7 +154,7 @@
|
|||||||
type="time"
|
type="time"
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||||
:disabled="isSaving"
|
:disabled="isSaving"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@@ -131,11 +165,21 @@
|
|||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||||
:disabled="isSaving"
|
:disabled="isSaving"
|
||||||
>
|
>
|
||||||
<option value="Training">Training</option>
|
<option value="Training">
|
||||||
<option value="Punktspiel">Punktspiel</option>
|
Training
|
||||||
<option value="Turnier">Turnier</option>
|
</option>
|
||||||
<option value="Veranstaltung">Veranstaltung</option>
|
<option value="Punktspiel">
|
||||||
<option value="Sonstiges">Sonstiges</option>
|
Punktspiel
|
||||||
|
</option>
|
||||||
|
<option value="Turnier">
|
||||||
|
Turnier
|
||||||
|
</option>
|
||||||
|
<option value="Veranstaltung">
|
||||||
|
Veranstaltung
|
||||||
|
</option>
|
||||||
|
<option value="Sonstiges">
|
||||||
|
Sonstiges
|
||||||
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -148,7 +192,7 @@
|
|||||||
required
|
required
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||||
:disabled="isSaving"
|
:disabled="isSaving"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@@ -161,17 +205,23 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="errorMessage" class="flex items-center p-3 rounded-md bg-red-50 text-red-700 text-sm">
|
<div
|
||||||
<AlertCircle :size="20" class="mr-2" />
|
v-if="errorMessage"
|
||||||
|
class="flex items-center p-3 rounded-md bg-red-50 text-red-700 text-sm"
|
||||||
|
>
|
||||||
|
<AlertCircle
|
||||||
|
:size="20"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
{{ errorMessage }}
|
{{ errorMessage }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-end space-x-4 pt-4">
|
<div class="flex justify-end space-x-4 pt-4">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@click="closeModal"
|
|
||||||
class="px-6 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
|
class="px-6 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
|
||||||
:disabled="isSaving"
|
:disabled="isSaving"
|
||||||
|
@click="closeModal"
|
||||||
>
|
>
|
||||||
Abbrechen
|
Abbrechen
|
||||||
</button>
|
</button>
|
||||||
@@ -180,7 +230,11 @@
|
|||||||
class="px-6 py-2 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors flex items-center"
|
class="px-6 py-2 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors flex items-center"
|
||||||
:disabled="isSaving"
|
:disabled="isSaving"
|
||||||
>
|
>
|
||||||
<Loader2 v-if="isSaving" :size="20" class="animate-spin mr-2" />
|
<Loader2
|
||||||
|
v-if="isSaving"
|
||||||
|
:size="20"
|
||||||
|
class="animate-spin mr-2"
|
||||||
|
/>
|
||||||
<span>{{ isSaving ? 'Speichert...' : 'Speichern' }}</span>
|
<span>{{ isSaving ? 'Speichert...' : 'Speichern' }}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,58 +4,142 @@
|
|||||||
<div class="fixed top-20 left-0 right-0 z-40 bg-white border-b border-gray-200 shadow-sm">
|
<div class="fixed top-20 left-0 right-0 z-40 bg-white border-b border-gray-200 shadow-sm">
|
||||||
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-3 sm:py-4">
|
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-3 sm:py-4">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<h1 class="text-xl sm:text-3xl font-display font-bold text-gray-900">TT-Regeln bearbeiten</h1>
|
<h1 class="text-xl sm:text-3xl font-display font-bold text-gray-900">
|
||||||
|
TT-Regeln bearbeiten
|
||||||
|
</h1>
|
||||||
<div class="space-x-3">
|
<div class="space-x-3">
|
||||||
<button @click="save" class="inline-flex items-center px-3 py-1.5 sm:px-4 sm:py-2 rounded-lg bg-primary-600 text-white hover:bg-primary-700 text-sm sm:text-base">Speichern</button>
|
<button
|
||||||
|
class="inline-flex items-center px-3 py-1.5 sm:px-4 sm:py-2 rounded-lg bg-primary-600 text-white hover:bg-primary-700 text-sm sm:text-base"
|
||||||
|
@click="save"
|
||||||
|
>
|
||||||
|
Speichern
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Fixed Toolbar below header -->
|
<!-- Fixed Toolbar below header -->
|
||||||
<div class="fixed left-0 right-0 z-30 bg-white border-b border-gray-200 shadow-sm" style="top: 9.5rem;">
|
<div
|
||||||
|
class="fixed left-0 right-0 z-30 bg-white border-b border-gray-200 shadow-sm"
|
||||||
|
style="top: 9.5rem;"
|
||||||
|
>
|
||||||
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<div class="flex flex-wrap items-center gap-1 sm:gap-2 py-1.5 sm:py-2">
|
<div class="flex flex-wrap items-center gap-1 sm:gap-2 py-1.5 sm:py-2">
|
||||||
<!-- Formatierung -->
|
<!-- Formatierung -->
|
||||||
<div class="flex items-center gap-1 border-r pr-2 mr-2">
|
<div class="flex items-center gap-1 border-r pr-2 mr-2">
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm" @click="format('bold')"><strong>B</strong></button>
|
<button
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm" @click="format('italic')"><em>I</em></button>
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm"
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm" @click="formatHeader(1)">H1</button>
|
@click="format('bold')"
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm" @click="formatHeader(2)">H2</button>
|
>
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm" @click="formatHeader(3)">H3</button>
|
<strong>B</strong>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm"
|
||||||
|
@click="format('italic')"
|
||||||
|
>
|
||||||
|
<em>I</em>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm"
|
||||||
|
@click="formatHeader(1)"
|
||||||
|
>
|
||||||
|
H1
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm"
|
||||||
|
@click="formatHeader(2)"
|
||||||
|
>
|
||||||
|
H2
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm"
|
||||||
|
@click="formatHeader(3)"
|
||||||
|
>
|
||||||
|
H3
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Listen -->
|
<!-- Listen -->
|
||||||
<div class="flex items-center gap-1 border-r pr-2 mr-2">
|
<div class="flex items-center gap-1 border-r pr-2 mr-2">
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm" @click="format('insertUnorderedList')">•</button>
|
<button
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm" @click="format('insertOrderedList')">1.</button>
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm"
|
||||||
|
@click="format('insertUnorderedList')"
|
||||||
|
>
|
||||||
|
•
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm"
|
||||||
|
@click="format('insertOrderedList')"
|
||||||
|
>
|
||||||
|
1.
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Schnellzugriff für Regeln -->
|
<!-- Schnellzugriff für Regeln -->
|
||||||
<div class="flex items-center gap-1 border-r pr-2 mr-2">
|
<div class="flex items-center gap-1 border-r pr-2 mr-2">
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded bg-gray-100 hover:bg-gray-200 text-gray-700 text-xs sm:text-sm" @click="insertRuleTemplate('generic')">Neue Regel</button>
|
<button
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded bg-blue-100 hover:bg-blue-200 text-blue-700 text-xs sm:text-sm" @click="insertRuleTemplate('basic')">Grundregel</button>
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded bg-gray-100 hover:bg-gray-200 text-gray-700 text-xs sm:text-sm"
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded bg-green-100 hover:bg-green-200 text-green-700 text-xs sm:text-sm" @click="insertRuleTemplate('penalty')">Strafregel</button>
|
@click="insertRuleTemplate('generic')"
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded bg-yellow-100 hover:bg-yellow-200 text-yellow-700 text-xs sm:text-sm" @click="insertRuleTemplate('service')">Aufschlag</button>
|
>
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded bg-red-100 hover:bg-red-200 text-red-700 text-xs sm:text-sm" @click="deleteCurrentRule()">Regel löschen</button>
|
Neue Regel
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded bg-blue-100 hover:bg-blue-200 text-blue-700 text-xs sm:text-sm"
|
||||||
|
@click="insertRuleTemplate('basic')"
|
||||||
|
>
|
||||||
|
Grundregel
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded bg-green-100 hover:bg-green-200 text-green-700 text-xs sm:text-sm"
|
||||||
|
@click="insertRuleTemplate('penalty')"
|
||||||
|
>
|
||||||
|
Strafregel
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded bg-yellow-100 hover:bg-yellow-200 text-yellow-700 text-xs sm:text-sm"
|
||||||
|
@click="insertRuleTemplate('service')"
|
||||||
|
>
|
||||||
|
Aufschlag
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded bg-red-100 hover:bg-red-200 text-red-700 text-xs sm:text-sm"
|
||||||
|
@click="deleteCurrentRule()"
|
||||||
|
>
|
||||||
|
Regel löschen
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Weitere Tools -->
|
<!-- Weitere Tools -->
|
||||||
<div class="flex items-center gap-1">
|
<div class="flex items-center gap-1">
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm" @click="createLink()">Link</button>
|
<button
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm" @click="removeFormat()">Clear</button>
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm"
|
||||||
|
@click="createLink()"
|
||||||
|
>
|
||||||
|
Link
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm"
|
||||||
|
@click="removeFormat()"
|
||||||
|
>
|
||||||
|
Clear
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Content with top padding -->
|
<!-- Content with top padding -->
|
||||||
<div class="pb-16" style="padding-top: 12rem;">
|
<div
|
||||||
|
class="pb-16"
|
||||||
|
style="padding-top: 12rem;"
|
||||||
|
>
|
||||||
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
|
||||||
<!-- Hilfe-Sektion -->
|
<!-- Hilfe-Sektion -->
|
||||||
<div class="mb-6 bg-blue-50 border border-blue-200 rounded-lg p-4">
|
<div class="mb-6 bg-blue-50 border border-blue-200 rounded-lg p-4">
|
||||||
<h3 class="text-lg font-semibold text-blue-900 mb-2">💡 So arbeiten Sie mit Regel-Kästchen:</h3>
|
<h3 class="text-lg font-semibold text-blue-900 mb-2">
|
||||||
|
💡 So arbeiten Sie mit Regel-Kästchen:
|
||||||
|
</h3>
|
||||||
<div class="text-sm text-blue-800 space-y-2">
|
<div class="text-sm text-blue-800 space-y-2">
|
||||||
<p><strong>1. Neue Kästchen hinzufügen:</strong> Klicken Sie in ein bestehendes Kästchen und verwenden Sie die Buttons:</p>
|
<p><strong>1. Neue Kästchen hinzufügen:</strong> Klicken Sie in ein bestehendes Kästchen und verwenden Sie die Buttons:</p>
|
||||||
<ul class="ml-4 space-y-1">
|
<ul class="ml-4 space-y-1">
|
||||||
@@ -67,7 +151,9 @@
|
|||||||
<p><strong>2. Kästchen löschen:</strong> Klicken Sie in ein Kästchen und dann auf <span class="bg-red-100 px-2 py-1 rounded text-xs">Regel löschen</span></p>
|
<p><strong>2. Kästchen löschen:</strong> Klicken Sie in ein Kästchen und dann auf <span class="bg-red-100 px-2 py-1 rounded text-xs">Regel löschen</span></p>
|
||||||
<p><strong>3. Kästchen bearbeiten:</strong> Klicken Sie direkt in die Texte und bearbeiten Sie sie</p>
|
<p><strong>3. Kästchen bearbeiten:</strong> Klicken Sie direkt in die Texte und bearbeiten Sie sie</p>
|
||||||
<p><strong>4. Grid-Layout:</strong> Kästchen werden automatisch im Grid-Layout angeordnet</p>
|
<p><strong>4. Grid-Layout:</strong> Kästchen werden automatisch im Grid-Layout angeordnet</p>
|
||||||
<p class="text-xs text-blue-600 mt-2">💡 <strong>Tipp:</strong> Neue Kästchen werden automatisch in das bestehende Grid eingefügt!</p>
|
<p class="text-xs text-blue-600 mt-2">
|
||||||
|
💡 <strong>Tipp:</strong> Neue Kästchen werden automatisch in das bestehende Grid eingefügt!
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,16 @@
|
|||||||
<div class="fixed top-20 left-0 right-0 z-40 bg-white border-b border-gray-200 shadow-sm">
|
<div class="fixed top-20 left-0 right-0 z-40 bg-white border-b border-gray-200 shadow-sm">
|
||||||
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-3 sm:py-4">
|
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-3 sm:py-4">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<h1 class="text-xl sm:text-3xl font-display font-bold text-gray-900">Über uns bearbeiten</h1>
|
<h1 class="text-xl sm:text-3xl font-display font-bold text-gray-900">
|
||||||
|
Über uns bearbeiten
|
||||||
|
</h1>
|
||||||
<div class="space-x-3">
|
<div class="space-x-3">
|
||||||
<button @click="save" class="inline-flex items-center px-3 py-1.5 sm:px-4 sm:py-2 rounded-lg bg-primary-600 text-white hover:bg-primary-700 text-sm sm:text-base">Speichern</button>
|
<button
|
||||||
|
class="inline-flex items-center px-3 py-1.5 sm:px-4 sm:py-2 rounded-lg bg-primary-600 text-white hover:bg-primary-700 text-sm sm:text-base"
|
||||||
|
@click="save"
|
||||||
|
>
|
||||||
|
Speichern
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -16,15 +23,60 @@
|
|||||||
<div class="fixed top-[9.5rem] left-0 right-0 z-30 bg-white border-b border-gray-200 shadow-sm">
|
<div class="fixed top-[9.5rem] left-0 right-0 z-30 bg-white border-b border-gray-200 shadow-sm">
|
||||||
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<div class="flex flex-wrap items-center gap-1 sm:gap-2 py-1.5 sm:py-2">
|
<div class="flex flex-wrap items-center gap-1 sm:gap-2 py-1.5 sm:py-2">
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm" @click="format('bold')"><strong>B</strong></button>
|
<button
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm" @click="format('italic')"><em>I</em></button>
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm"
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm" @click="formatHeader(1)">H1</button>
|
@click="format('bold')"
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm" @click="formatHeader(2)">H2</button>
|
>
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm" @click="formatHeader(3)">H3</button>
|
<strong>B</strong>
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm" @click="format('insertUnorderedList')">•</button>
|
</button>
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm" @click="format('insertOrderedList')">1.</button>
|
<button
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm" @click="createLink()">Link</button>
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm"
|
||||||
<button class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm" @click="removeFormat()">Clear</button>
|
@click="format('italic')"
|
||||||
|
>
|
||||||
|
<em>I</em>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm"
|
||||||
|
@click="formatHeader(1)"
|
||||||
|
>
|
||||||
|
H1
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm"
|
||||||
|
@click="formatHeader(2)"
|
||||||
|
>
|
||||||
|
H2
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm"
|
||||||
|
@click="formatHeader(3)"
|
||||||
|
>
|
||||||
|
H3
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm"
|
||||||
|
@click="format('insertUnorderedList')"
|
||||||
|
>
|
||||||
|
•
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm"
|
||||||
|
@click="format('insertOrderedList')"
|
||||||
|
>
|
||||||
|
1.
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm"
|
||||||
|
@click="createLink()"
|
||||||
|
>
|
||||||
|
Link
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-2 py-1 sm:px-3 sm:py-1 rounded border hover:bg-gray-50 text-xs sm:text-sm"
|
||||||
|
@click="removeFormat()"
|
||||||
|
>
|
||||||
|
Clear
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -32,14 +84,13 @@
|
|||||||
<!-- Content with top padding -->
|
<!-- Content with top padding -->
|
||||||
<div class="pt-36 sm:pt-44 pb-16">
|
<div class="pt-36 sm:pt-44 pb-16">
|
||||||
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-3 sm:p-4">
|
||||||
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-3 sm:p-4">
|
<div
|
||||||
<div
|
ref="editor"
|
||||||
ref="editor"
|
class="min-h-[320px] p-3 sm:p-4 outline-none prose max-w-none text-sm sm:text-base"
|
||||||
class="min-h-[320px] p-3 sm:p-4 outline-none prose max-w-none text-sm sm:text-base"
|
contenteditable
|
||||||
contenteditable
|
/>
|
||||||
/>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,15 +4,35 @@
|
|||||||
<div class="fixed top-20 left-0 right-0 z-40 bg-white border-b border-gray-200 shadow-sm">
|
<div class="fixed top-20 left-0 right-0 z-40 bg-white border-b border-gray-200 shadow-sm">
|
||||||
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-3 sm:py-4">
|
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-3 sm:py-4">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<h1 class="text-xl sm:text-3xl font-display font-bold text-gray-900">Vereinsmeisterschaften bearbeiten</h1>
|
<h1 class="text-xl sm:text-3xl font-display font-bold text-gray-900">
|
||||||
|
Vereinsmeisterschaften bearbeiten
|
||||||
|
</h1>
|
||||||
<div class="space-x-3">
|
<div class="space-x-3">
|
||||||
<button @click="addNewResult" class="inline-flex items-center px-3 py-1.5 sm:px-4 sm:py-2 rounded-lg bg-green-600 text-white hover:bg-green-700 text-sm sm:text-base">
|
<button
|
||||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
class="inline-flex items-center px-3 py-1.5 sm:px-4 sm:py-2 rounded-lg bg-green-600 text-white hover:bg-green-700 text-sm sm:text-base"
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
|
@click="addNewResult"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="w-4 h-4 mr-2"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M12 6v6m0 0v6m0-6h6m-6 0H6"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
Neues Ergebnis
|
Neues Ergebnis
|
||||||
</button>
|
</button>
|
||||||
<button @click="save" class="inline-flex items-center px-3 py-1.5 sm:px-4 sm:py-2 rounded-lg bg-primary-600 text-white hover:bg-primary-700 text-sm sm:text-base">Speichern</button>
|
<button
|
||||||
|
class="inline-flex items-center px-3 py-1.5 sm:px-4 sm:py-2 rounded-lg bg-primary-600 text-white hover:bg-primary-700 text-sm sm:text-base"
|
||||||
|
@click="save"
|
||||||
|
>
|
||||||
|
Speichern
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -21,54 +41,58 @@
|
|||||||
<!-- Content with top padding -->
|
<!-- Content with top padding -->
|
||||||
<div class="pt-20 pb-16">
|
<div class="pt-20 pb-16">
|
||||||
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
|
||||||
<!-- Filter -->
|
<!-- Filter -->
|
||||||
<div class="mb-8 flex flex-wrap gap-4">
|
<div class="mb-8 flex flex-wrap gap-4">
|
||||||
<button
|
<button
|
||||||
v-for="jahr in verfuegbareJahre"
|
v-for="jahr in verfuegbareJahre"
|
||||||
:key="jahr"
|
:key="jahr"
|
||||||
@click="selectedYear = jahr"
|
|
||||||
:class="[
|
:class="[
|
||||||
'px-4 py-2 rounded-lg font-medium transition-colors',
|
'px-4 py-2 rounded-lg font-medium transition-colors',
|
||||||
selectedYear === jahr
|
selectedYear === jahr
|
||||||
? 'bg-primary-600 text-white'
|
? 'bg-primary-600 text-white'
|
||||||
: 'bg-white text-gray-700 hover:bg-gray-100 border border-gray-300'
|
: 'bg-white text-gray-700 hover:bg-gray-100 border border-gray-300'
|
||||||
]"
|
]"
|
||||||
|
@click="selectedYear = jahr"
|
||||||
>
|
>
|
||||||
{{ jahr }}
|
{{ jahr }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@click="selectedYear = 'alle'"
|
|
||||||
:class="[
|
:class="[
|
||||||
'px-4 py-2 rounded-lg font-medium transition-colors',
|
'px-4 py-2 rounded-lg font-medium transition-colors',
|
||||||
selectedYear === 'alle'
|
selectedYear === 'alle'
|
||||||
? 'bg-primary-600 text-white'
|
? 'bg-primary-600 text-white'
|
||||||
: 'bg-white text-gray-700 hover:bg-gray-100 border border-gray-300'
|
: 'bg-white text-gray-700 hover:bg-gray-100 border border-gray-300'
|
||||||
]"
|
]"
|
||||||
|
@click="selectedYear = 'alle'"
|
||||||
>
|
>
|
||||||
Alle Jahre
|
Alle Jahre
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Ergebnisse -->
|
<!-- Ergebnisse -->
|
||||||
<div v-if="filteredResults.length > 0" class="space-y-8">
|
<div
|
||||||
|
v-if="filteredResults.length > 0"
|
||||||
|
class="space-y-8"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
v-for="entry in sortedGroupedResults"
|
v-for="entry in sortedGroupedResults"
|
||||||
:key="entry.jahr"
|
:key="entry.jahr"
|
||||||
class="bg-white rounded-xl shadow-lg p-6"
|
class="bg-white rounded-xl shadow-lg p-6"
|
||||||
>
|
>
|
||||||
<div class="flex items-center justify-between mb-6">
|
<div class="flex items-center justify-between mb-6">
|
||||||
<h2 class="text-2xl font-display font-bold text-gray-900">{{ entry.jahr }}</h2>
|
<h2 class="text-2xl font-display font-bold text-gray-900">
|
||||||
|
{{ entry.jahr }}
|
||||||
|
</h2>
|
||||||
<div class="flex space-x-2">
|
<div class="flex space-x-2">
|
||||||
<button
|
<button
|
||||||
@click="addResultForYear(entry.jahr)"
|
|
||||||
class="px-3 py-1 text-sm bg-green-100 hover:bg-green-200 text-green-700 rounded-lg transition-colors"
|
class="px-3 py-1 text-sm bg-green-100 hover:bg-green-200 text-green-700 rounded-lg transition-colors"
|
||||||
|
@click="addResultForYear(entry.jahr)"
|
||||||
>
|
>
|
||||||
Ergebnis hinzufügen
|
Ergebnis hinzufügen
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@click="deleteYear(entry.jahr)"
|
|
||||||
class="px-3 py-1 text-sm bg-red-100 hover:bg-red-200 text-red-700 rounded-lg transition-colors"
|
class="px-3 py-1 text-sm bg-red-100 hover:bg-red-200 text-red-700 rounded-lg transition-colors"
|
||||||
|
@click="deleteYear(entry.jahr)"
|
||||||
>
|
>
|
||||||
Jahr löschen
|
Jahr löschen
|
||||||
</button>
|
</button>
|
||||||
@@ -76,12 +100,17 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Besondere Bemerkungen -->
|
<!-- Besondere Bemerkungen -->
|
||||||
<div v-if="entry.data.bemerkungen" class="mb-6 p-4 bg-yellow-50 border-l-4 border-yellow-400 rounded-r-lg">
|
<div
|
||||||
|
v-if="entry.data.bemerkungen"
|
||||||
|
class="mb-6 p-4 bg-yellow-50 border-l-4 border-yellow-400 rounded-r-lg"
|
||||||
|
>
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<p class="text-gray-700 font-medium">{{ entry.data.bemerkungen }}</p>
|
<p class="text-gray-700 font-medium">
|
||||||
|
{{ entry.data.bemerkungen }}
|
||||||
|
</p>
|
||||||
<button
|
<button
|
||||||
@click="editBemerkung(entry.jahr)"
|
|
||||||
class="px-2 py-1 text-xs bg-yellow-100 hover:bg-yellow-200 text-yellow-700 rounded transition-colors"
|
class="px-2 py-1 text-xs bg-yellow-100 hover:bg-yellow-200 text-yellow-700 rounded transition-colors"
|
||||||
|
@click="editBemerkung(entry.jahr)"
|
||||||
>
|
>
|
||||||
Bearbeiten
|
Bearbeiten
|
||||||
</button>
|
</button>
|
||||||
@@ -89,24 +118,29 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Kategorien -->
|
<!-- Kategorien -->
|
||||||
<div v-if="Object.keys(entry.data.kategorien).length > 0" class="space-y-6">
|
<div
|
||||||
|
v-if="Object.keys(entry.data.kategorien).length > 0"
|
||||||
|
class="space-y-6"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
v-for="(kategorieResults, kategorie) in entry.data.kategorien"
|
v-for="(kategorieResults, kategorie) in entry.data.kategorien"
|
||||||
:key="kategorie"
|
:key="kategorie"
|
||||||
class="border border-gray-200 rounded-lg p-4"
|
class="border border-gray-200 rounded-lg p-4"
|
||||||
>
|
>
|
||||||
<div class="flex items-center justify-between mb-4">
|
<div class="flex items-center justify-between mb-4">
|
||||||
<h3 class="text-lg font-semibold text-gray-900">{{ kategorie }}</h3>
|
<h3 class="text-lg font-semibold text-gray-900">
|
||||||
|
{{ kategorie }}
|
||||||
|
</h3>
|
||||||
<div class="flex space-x-2">
|
<div class="flex space-x-2">
|
||||||
<button
|
<button
|
||||||
@click="addResultForKategorie(entry.jahr, kategorie)"
|
|
||||||
class="px-2 py-1 text-xs bg-blue-100 hover:bg-blue-200 text-blue-700 rounded transition-colors"
|
class="px-2 py-1 text-xs bg-blue-100 hover:bg-blue-200 text-blue-700 rounded transition-colors"
|
||||||
|
@click="addResultForKategorie(entry.jahr, kategorie)"
|
||||||
>
|
>
|
||||||
Ergebnis hinzufügen
|
Ergebnis hinzufügen
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@click="deleteKategorie(entry.jahr, kategorie)"
|
|
||||||
class="px-2 py-1 text-xs bg-red-100 hover:bg-red-200 text-red-700 rounded transition-colors"
|
class="px-2 py-1 text-xs bg-red-100 hover:bg-red-200 text-red-700 rounded transition-colors"
|
||||||
|
@click="deleteKategorie(entry.jahr, kategorie)"
|
||||||
>
|
>
|
||||||
Kategorie löschen
|
Kategorie löschen
|
||||||
</button>
|
</button>
|
||||||
@@ -124,24 +158,33 @@
|
|||||||
{{ result.platz }}
|
{{ result.platz }}
|
||||||
</span>
|
</span>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<div v-if="result.imageFilename1" class="flex-shrink-0">
|
<div
|
||||||
|
v-if="result.imageFilename1"
|
||||||
|
class="flex-shrink-0"
|
||||||
|
>
|
||||||
<img
|
<img
|
||||||
:src="`/api/personen/${result.imageFilename1}?width=32&height=32`"
|
:src="`/api/personen/${result.imageFilename1}?width=32&height=32`"
|
||||||
:alt="result.spieler1"
|
:alt="result.spieler1"
|
||||||
class="w-8 h-8 rounded-full object-cover border border-gray-300"
|
class="w-8 h-8 rounded-full object-cover border border-gray-300"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
<span class="font-medium text-gray-900">{{ result.spieler1 }}</span>
|
<span class="font-medium text-gray-900">{{ result.spieler1 }}</span>
|
||||||
<span v-if="result.spieler2" class="text-gray-600 flex items-center gap-2">
|
<span
|
||||||
|
v-if="result.spieler2"
|
||||||
|
class="text-gray-600 flex items-center gap-2"
|
||||||
|
>
|
||||||
&
|
&
|
||||||
<div v-if="result.imageFilename2" class="flex-shrink-0">
|
<div
|
||||||
|
v-if="result.imageFilename2"
|
||||||
|
class="flex-shrink-0"
|
||||||
|
>
|
||||||
<img
|
<img
|
||||||
:src="`/api/personen/${result.imageFilename2}?width=32&height=32`"
|
:src="`/api/personen/${result.imageFilename2}?width=32&height=32`"
|
||||||
:alt="result.spieler2"
|
:alt="result.spieler2"
|
||||||
class="w-8 h-8 rounded-full object-cover border border-gray-300"
|
class="w-8 h-8 rounded-full object-cover border border-gray-300"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
{{ result.spieler2 }}
|
{{ result.spieler2 }}
|
||||||
</span>
|
</span>
|
||||||
@@ -149,14 +192,14 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex space-x-2">
|
<div class="flex space-x-2">
|
||||||
<button
|
<button
|
||||||
@click="editResult(result, entry.jahr, kategorie, index)"
|
|
||||||
class="px-2 py-1 text-xs bg-gray-100 hover:bg-gray-200 text-gray-700 rounded transition-colors"
|
class="px-2 py-1 text-xs bg-gray-100 hover:bg-gray-200 text-gray-700 rounded transition-colors"
|
||||||
|
@click="editResult(result, entry.jahr, kategorie, index)"
|
||||||
>
|
>
|
||||||
Bearbeiten
|
Bearbeiten
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@click="deleteResult(entry.jahr, kategorie, index)"
|
|
||||||
class="px-2 py-1 text-xs bg-red-100 hover:bg-red-200 text-red-700 rounded transition-colors"
|
class="px-2 py-1 text-xs bg-red-100 hover:bg-red-200 text-red-700 rounded transition-colors"
|
||||||
|
@click="deleteResult(entry.jahr, kategorie, index)"
|
||||||
>
|
>
|
||||||
Löschen
|
Löschen
|
||||||
</button>
|
</button>
|
||||||
@@ -168,14 +211,29 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else class="text-center py-12 bg-white rounded-xl shadow-lg">
|
<div
|
||||||
<svg class="w-12 h-12 text-gray-400 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
v-else
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4M7.835 4.697a3.42 3.42 0 001.946-.806 3.42 3.42 0 014.438 0 3.42 3.42 0 001.946.806 3.42 3.42 0 013.138 3.138 3.42 3.42 0 00.806 1.946 3.42 3.42 0 010 4.438 3.42 3.42 0 00-.806 1.946 3.42 3.42 0 01-3.138 3.138 3.42 3.42 0 00-1.946.806 3.42 3.42 0 01-4.438 0 3.42 3.42 0 00-1.946-.806 3.42 3.42 0 01-3.138-3.138 3.42 3.42 0 00-.806-1.946 3.42 3.42 0 010-4.438 3.42 3.42 0 00.806-1.946 3.42 3.42 0 013.138-3.138z"></path>
|
class="text-center py-12 bg-white rounded-xl shadow-lg"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="w-12 h-12 text-gray-400 mx-auto mb-4"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M9 12l2 2 4-4M7.835 4.697a3.42 3.42 0 001.946-.806 3.42 3.42 0 014.438 0 3.42 3.42 0 001.946.806 3.42 3.42 0 013.138 3.138 3.42 3.42 0 00.806 1.946 3.42 3.42 0 010 4.438 3.42 3.42 0 00-.806 1.946 3.42 3.42 0 01-3.138 3.138 3.42 3.42 0 00-1.946.806 3.42 3.42 0 01-4.438 0 3.42 3.42 0 00-1.946-.806 3.42 3.42 0 01-3.138-3.138 3.42 3.42 0 00-.806-1.946 3.42 3.42 0 010-4.438 3.42 3.42 0 00.806-1.946 3.42 3.42 0 013.138-3.138z"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<p class="text-gray-600">Keine Ergebnisse vorhanden.</p>
|
<p class="text-gray-600">
|
||||||
|
Keine Ergebnisse vorhanden.
|
||||||
|
</p>
|
||||||
<button
|
<button
|
||||||
@click="addNewResult"
|
|
||||||
class="mt-4 px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors"
|
class="mt-4 px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors"
|
||||||
|
@click="addNewResult"
|
||||||
>
|
>
|
||||||
Erstes Ergebnis hinzufügen
|
Erstes Ergebnis hinzufügen
|
||||||
</button>
|
</button>
|
||||||
@@ -197,98 +255,123 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="overflow-y-auto flex-1 p-6">
|
<div class="overflow-y-auto flex-1 p-6">
|
||||||
<form id="result-form" @submit.prevent="saveResult" class="space-y-4">
|
<form
|
||||||
<div>
|
id="result-form"
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Jahr</label>
|
class="space-y-4"
|
||||||
<input
|
@submit.prevent="saveResult"
|
||||||
v-model="formData.jahr"
|
>
|
||||||
type="text"
|
<div>
|
||||||
required
|
<label class="block text-sm font-medium text-gray-700 mb-2">Jahr</label>
|
||||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
<input
|
||||||
/>
|
v-model="formData.jahr"
|
||||||
</div>
|
type="text"
|
||||||
|
required
|
||||||
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Kategorie</label>
|
<label class="block text-sm font-medium text-gray-700 mb-2">Kategorie</label>
|
||||||
<select
|
<select
|
||||||
v-model="formData.kategorie"
|
v-model="formData.kategorie"
|
||||||
required
|
required
|
||||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
>
|
>
|
||||||
<option value="">Kategorie wählen</option>
|
<option value="">
|
||||||
<option value="Einzel">Einzel</option>
|
Kategorie wählen
|
||||||
<option value="Doppel">Doppel</option>
|
</option>
|
||||||
<option value="Mixed">Mixed</option>
|
<option value="Einzel">
|
||||||
<option value="Jugend">Jugend</option>
|
Einzel
|
||||||
<option value="Senioren">Senioren</option>
|
</option>
|
||||||
</select>
|
<option value="Doppel">
|
||||||
</div>
|
Doppel
|
||||||
|
</option>
|
||||||
|
<option value="Mixed">
|
||||||
|
Mixed
|
||||||
|
</option>
|
||||||
|
<option value="Jugend">
|
||||||
|
Jugend
|
||||||
|
</option>
|
||||||
|
<option value="Senioren">
|
||||||
|
Senioren
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Platz</label>
|
<label class="block text-sm font-medium text-gray-700 mb-2">Platz</label>
|
||||||
<select
|
<select
|
||||||
v-model="formData.platz"
|
v-model="formData.platz"
|
||||||
required
|
required
|
||||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
>
|
>
|
||||||
<option value="">Platz wählen</option>
|
<option value="">
|
||||||
<option value="1">1. Platz</option>
|
Platz wählen
|
||||||
<option value="2">2. Platz</option>
|
</option>
|
||||||
<option value="3">3. Platz</option>
|
<option value="1">
|
||||||
<option value="4">4. Platz</option>
|
1. Platz
|
||||||
</select>
|
</option>
|
||||||
</div>
|
<option value="2">
|
||||||
|
2. Platz
|
||||||
|
</option>
|
||||||
|
<option value="3">
|
||||||
|
3. Platz
|
||||||
|
</option>
|
||||||
|
<option value="4">
|
||||||
|
4. Platz
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Spieler 1</label>
|
<label class="block text-sm font-medium text-gray-700 mb-2">Spieler 1</label>
|
||||||
<input
|
<input
|
||||||
v-model="formData.spieler1"
|
v-model="formData.spieler1"
|
||||||
type="text"
|
type="text"
|
||||||
required
|
required
|
||||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="formData.kategorie === 'Doppel' || formData.kategorie === 'Mixed'">
|
<div v-if="formData.kategorie === 'Doppel' || formData.kategorie === 'Mixed'">
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Spieler 2</label>
|
<label class="block text-sm font-medium text-gray-700 mb-2">Spieler 2</label>
|
||||||
<input
|
<input
|
||||||
v-model="formData.spieler2"
|
v-model="formData.spieler2"
|
||||||
type="text"
|
type="text"
|
||||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<ImageUpload
|
<ImageUpload
|
||||||
v-model="formData.imageFilename1"
|
v-model="formData.imageFilename1"
|
||||||
label="Foto Spieler 1"
|
label="Foto Spieler 1"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="formData.kategorie === 'Doppel' || formData.kategorie === 'Mixed'">
|
<div v-if="formData.kategorie === 'Doppel' || formData.kategorie === 'Mixed'">
|
||||||
<ImageUpload
|
<ImageUpload
|
||||||
v-model="formData.imageFilename2"
|
v-model="formData.imageFilename2"
|
||||||
label="Foto Spieler 2"
|
label="Foto Spieler 2"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Bemerkung (optional)</label>
|
|
||||||
<textarea
|
|
||||||
v-model="formData.bemerkung"
|
|
||||||
rows="3"
|
|
||||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
|
||||||
></textarea>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Bemerkung (optional)</label>
|
||||||
|
<textarea
|
||||||
|
v-model="formData.bemerkung"
|
||||||
|
rows="3"
|
||||||
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="p-6 border-t border-gray-200 flex-shrink-0 flex justify-end space-x-3">
|
<div class="p-6 border-t border-gray-200 flex-shrink-0 flex justify-end space-x-3">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@click="closeModal"
|
|
||||||
class="px-4 py-2 text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors"
|
class="px-4 py-2 text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors"
|
||||||
|
@click="closeModal"
|
||||||
>
|
>
|
||||||
Abbrechen
|
Abbrechen
|
||||||
</button>
|
</button>
|
||||||
@@ -310,23 +393,28 @@
|
|||||||
@click.self="closeBemerkungModal"
|
@click.self="closeBemerkungModal"
|
||||||
>
|
>
|
||||||
<div class="bg-white rounded-lg max-w-md w-full p-6">
|
<div class="bg-white rounded-lg max-w-md w-full p-6">
|
||||||
<h3 class="text-lg font-semibold text-gray-900 mb-4">Bemerkung bearbeiten</h3>
|
<h3 class="text-lg font-semibold text-gray-900 mb-4">
|
||||||
|
Bemerkung bearbeiten
|
||||||
|
</h3>
|
||||||
|
|
||||||
<form @submit.prevent="saveBemerkung" class="space-y-4">
|
<form
|
||||||
|
class="space-y-4"
|
||||||
|
@submit.prevent="saveBemerkung"
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Bemerkung</label>
|
<label class="block text-sm font-medium text-gray-700 mb-2">Bemerkung</label>
|
||||||
<textarea
|
<textarea
|
||||||
v-model="bemerkungText"
|
v-model="bemerkungText"
|
||||||
rows="3"
|
rows="3"
|
||||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
></textarea>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-end space-x-3 pt-4">
|
<div class="flex justify-end space-x-3 pt-4">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@click="closeBemerkungModal"
|
|
||||||
class="px-4 py-2 text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors"
|
class="px-4 py-2 text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors"
|
||||||
|
@click="closeBemerkungModal"
|
||||||
>
|
>
|
||||||
Abbrechen
|
Abbrechen
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -28,7 +28,9 @@
|
|||||||
|
|
||||||
<div class="space-y-6">
|
<div class="space-y-6">
|
||||||
<div class="bg-white p-6 rounded-xl shadow-lg border-l-4 border-primary-600">
|
<div class="bg-white p-6 rounded-xl shadow-lg border-l-4 border-primary-600">
|
||||||
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">10.06.1954 - Gründung des HTC</h3>
|
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">
|
||||||
|
10.06.1954 - Gründung des HTC
|
||||||
|
</h3>
|
||||||
<p class="text-gray-600 mb-3">
|
<p class="text-gray-600 mb-3">
|
||||||
Bei der am 20.05.1954 stattgefundenen Sitzung der SGH wurde die Trennung der einzelnen Abteilungen beschlossen.
|
Bei der am 20.05.1954 stattgefundenen Sitzung der SGH wurde die Trennung der einzelnen Abteilungen beschlossen.
|
||||||
Somit sah sich die TT-Abteilung veranlasst, ihren Sportbetrieb in eigener Regie weiterzuführen.
|
Somit sah sich die TT-Abteilung veranlasst, ihren Sportbetrieb in eigener Regie weiterzuführen.
|
||||||
@@ -40,7 +42,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-white p-6 rounded-xl shadow-lg border-l-4 border-primary-600">
|
<div class="bg-white p-6 rounded-xl shadow-lg border-l-4 border-primary-600">
|
||||||
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">1964 - Neue Trainingsstätte</h3>
|
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">
|
||||||
|
1964 - Neue Trainingsstätte
|
||||||
|
</h3>
|
||||||
<p class="text-gray-600">
|
<p class="text-gray-600">
|
||||||
Mit der Erbauung der Schulturnhalle im Jahre 1964 stand eine für die damaligen Verhältnisse recht moderne
|
Mit der Erbauung der Schulturnhalle im Jahre 1964 stand eine für die damaligen Verhältnisse recht moderne
|
||||||
Übungsstätte zur Verfügung, die dem HTC für einen Tag in der Woche überlassen wurde. Damit waren viele
|
Übungsstätte zur Verfügung, die dem HTC für einen Tag in der Woche überlassen wurde. Damit waren viele
|
||||||
@@ -49,7 +53,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-white p-6 rounded-xl shadow-lg border-l-4 border-primary-600">
|
<div class="bg-white p-6 rounded-xl shadow-lg border-l-4 border-primary-600">
|
||||||
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">1974 - Bürgerhaus</h3>
|
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">
|
||||||
|
1974 - Bürgerhaus
|
||||||
|
</h3>
|
||||||
<p class="text-gray-600">
|
<p class="text-gray-600">
|
||||||
Mit der Erstellung des Bürgerhauses wurde wiederum neuer Trainingsraum geschaffen, der besonders für den
|
Mit der Erstellung des Bürgerhauses wurde wiederum neuer Trainingsraum geschaffen, der besonders für den
|
||||||
Tischtennissport geeignet ist. Der HTC nahm die Gelegenheit war und hielt ab Mai 1974 seine Übungsabende
|
Tischtennissport geeignet ist. Der HTC nahm die Gelegenheit war und hielt ab Mai 1974 seine Übungsabende
|
||||||
@@ -58,7 +64,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-white p-6 rounded-xl shadow-lg border-l-4 border-primary-600">
|
<div class="bg-white p-6 rounded-xl shadow-lg border-l-4 border-primary-600">
|
||||||
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">1976 - Eintragung ins Vereinsregister</h3>
|
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">
|
||||||
|
1976 - Eintragung ins Vereinsregister
|
||||||
|
</h3>
|
||||||
<p class="text-gray-600">
|
<p class="text-gray-600">
|
||||||
Die Eintragung in das Vereinsregister (e. V.) erfolgte im Jahre 1976 und gleichzeitig wurde dem Verein
|
Die Eintragung in das Vereinsregister (e. V.) erfolgte im Jahre 1976 und gleichzeitig wurde dem Verein
|
||||||
die Gemeinnützigkeit zuerkannt.
|
die Gemeinnützigkeit zuerkannt.
|
||||||
@@ -66,7 +74,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-white p-6 rounded-xl shadow-lg border-l-4 border-primary-600">
|
<div class="bg-white p-6 rounded-xl shadow-lg border-l-4 border-primary-600">
|
||||||
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">1978/79 - Sportlicher Höhepunkt</h3>
|
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">
|
||||||
|
1978/79 - Sportlicher Höhepunkt
|
||||||
|
</h3>
|
||||||
<p class="text-gray-600">
|
<p class="text-gray-600">
|
||||||
Ein besonderes Geschenk machten die Spieler des HTC im Jubiläumsjahr ihrem Verein: Die 1. Herrenmannschaft
|
Ein besonderes Geschenk machten die Spieler des HTC im Jubiläumsjahr ihrem Verein: Die 1. Herrenmannschaft
|
||||||
wurde Meister der Bezirksklasse Ffm.-Ost und die 2. Herrenmannschaft Meister der Kreisklasse-A Ffm.-Nord.
|
wurde Meister der Bezirksklasse Ffm.-Ost und die 2. Herrenmannschaft Meister der Kreisklasse-A Ffm.-Nord.
|
||||||
@@ -76,7 +86,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-white p-6 rounded-xl shadow-lg border-l-4 border-primary-600">
|
<div class="bg-white p-6 rounded-xl shadow-lg border-l-4 border-primary-600">
|
||||||
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">Heute</h3>
|
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">
|
||||||
|
Heute
|
||||||
|
</h3>
|
||||||
<p class="text-gray-600">
|
<p class="text-gray-600">
|
||||||
Der HTC hat sich auch in Zukunft zur Aufgabe gemacht, allen interessierten Bürgern und Jugendlichen im
|
Der HTC hat sich auch in Zukunft zur Aufgabe gemacht, allen interessierten Bürgern und Jugendlichen im
|
||||||
Rahmen seiner Möglichkeiten das Tischtennisspielen als Leistungssport oder zur Freizeitgestaltung zu ermöglichen.
|
Rahmen seiner Möglichkeiten das Tischtennisspielen als Leistungssport oder zur Freizeitgestaltung zu ermöglichen.
|
||||||
|
|||||||
@@ -8,52 +8,65 @@
|
|||||||
|
|
||||||
<div class="bg-white p-8 rounded-xl shadow-lg space-y-6">
|
<div class="bg-white p-8 rounded-xl shadow-lg space-y-6">
|
||||||
<div v-if="config">
|
<div v-if="config">
|
||||||
<h2 class="text-xl font-display font-bold text-gray-900 mb-2">Angaben gemäß § 5 TMG</h2>
|
<h2 class="text-xl font-display font-bold text-gray-900 mb-2">
|
||||||
|
Angaben gemäß § 5 TMG
|
||||||
|
</h2>
|
||||||
<p class="text-gray-700">
|
<p class="text-gray-700">
|
||||||
{{ config.verein.name }}<br />
|
{{ config.verein.name }}<br>
|
||||||
<template v-if="config.verein.useVorsitzenderAddress">
|
<template v-if="config.verein.useVorsitzenderAddress">
|
||||||
{{ config.vorstand.vorsitzender.strasse }}<br />
|
{{ config.vorstand.vorsitzender.strasse }}<br>
|
||||||
{{ config.vorstand.vorsitzender.plz }} {{ config.vorstand.vorsitzender.ort }}
|
{{ config.vorstand.vorsitzender.plz }} {{ config.vorstand.vorsitzender.ort }}
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
{{ config.verein.strasse }}<br />
|
{{ config.verein.strasse }}<br>
|
||||||
{{ config.verein.plz }} {{ config.verein.ort }}
|
{{ config.verein.plz }} {{ config.verein.ort }}
|
||||||
</template>
|
</template>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="config">
|
<div v-if="config">
|
||||||
<h2 class="text-xl font-display font-bold text-gray-900 mb-2">Kontakt</h2>
|
<h2 class="text-xl font-display font-bold text-gray-900 mb-2">
|
||||||
|
Kontakt
|
||||||
|
</h2>
|
||||||
<p class="text-gray-700">
|
<p class="text-gray-700">
|
||||||
Telefon: {{ config.vorstand.vorsitzender.telefon }}<br />
|
Telefon: {{ config.vorstand.vorsitzender.telefon }}<br>
|
||||||
E-Mail: <a :href="`mailto:${config.vorstand.vorsitzender.email}`" class="text-primary-600 hover:underline">{{ config.vorstand.vorsitzender.email }}</a><br />
|
E-Mail: <a
|
||||||
|
:href="`mailto:${config.vorstand.vorsitzender.email}`"
|
||||||
|
class="text-primary-600 hover:underline"
|
||||||
|
>{{ config.vorstand.vorsitzender.email }}</a><br>
|
||||||
Internet: www.harheimertc.de
|
Internet: www.harheimertc.de
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="config">
|
<div v-if="config">
|
||||||
<h2 class="text-xl font-display font-bold text-gray-900 mb-2">Vertretungsberechtigter Vorstand</h2>
|
<h2 class="text-xl font-display font-bold text-gray-900 mb-2">
|
||||||
|
Vertretungsberechtigter Vorstand
|
||||||
|
</h2>
|
||||||
<p class="text-gray-700">
|
<p class="text-gray-700">
|
||||||
<span v-if="config.vorstand.vorsitzender.vorname">{{ config.vorstand.vorsitzender.vorname }} {{ config.vorstand.vorsitzender.nachname }}, Vorsitzender<br /></span>
|
<span v-if="config.vorstand.vorsitzender.vorname">{{ config.vorstand.vorsitzender.vorname }} {{ config.vorstand.vorsitzender.nachname }}, Vorsitzender<br></span>
|
||||||
<span v-if="config.vorstand.stellvertreter.vorname">{{ config.vorstand.stellvertreter.vorname }} {{ config.vorstand.stellvertreter.nachname }}, Stellvertreter<br /></span>
|
<span v-if="config.vorstand.stellvertreter.vorname">{{ config.vorstand.stellvertreter.vorname }} {{ config.vorstand.stellvertreter.nachname }}, Stellvertreter<br></span>
|
||||||
<span v-if="config.vorstand.kassenwart.vorname">{{ config.vorstand.kassenwart.vorname }} {{ config.vorstand.kassenwart.nachname }}, Kassenwart<br /></span>
|
<span v-if="config.vorstand.kassenwart.vorname">{{ config.vorstand.kassenwart.vorname }} {{ config.vorstand.kassenwart.nachname }}, Kassenwart<br></span>
|
||||||
<span v-if="config.vorstand.schriftfuehrer.vorname">{{ config.vorstand.schriftfuehrer.vorname }} {{ config.vorstand.schriftfuehrer.nachname }}, Schriftführer<br /></span>
|
<span v-if="config.vorstand.schriftfuehrer.vorname">{{ config.vorstand.schriftfuehrer.vorname }} {{ config.vorstand.schriftfuehrer.nachname }}, Schriftführer<br></span>
|
||||||
<span v-if="config.vorstand.sportwart.vorname">{{ config.vorstand.sportwart.vorname }} {{ config.vorstand.sportwart.nachname }}, Sportwart<br /></span>
|
<span v-if="config.vorstand.sportwart.vorname">{{ config.vorstand.sportwart.vorname }} {{ config.vorstand.sportwart.nachname }}, Sportwart<br></span>
|
||||||
<span v-if="config.vorstand.jugendwart.vorname">{{ config.vorstand.jugendwart.vorname }} {{ config.vorstand.jugendwart.nachname }}, Jugendwart</span>
|
<span v-if="config.vorstand.jugendwart.vorname">{{ config.vorstand.jugendwart.vorname }} {{ config.vorstand.jugendwart.nachname }}, Jugendwart</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h2 class="text-xl font-display font-bold text-gray-900 mb-2">Registereintrag</h2>
|
<h2 class="text-xl font-display font-bold text-gray-900 mb-2">
|
||||||
|
Registereintrag
|
||||||
|
</h2>
|
||||||
<p class="text-gray-700">
|
<p class="text-gray-700">
|
||||||
lsb h-Vereinsnummer: 24091<br />
|
lsb h-Vereinsnummer: 24091<br>
|
||||||
Registereintrag: Amtsgericht Frankfurt am Main, Registergericht<br />
|
Registereintrag: Amtsgericht Frankfurt am Main, Registergericht<br>
|
||||||
Registernummer: VR 6835
|
Registernummer: VR 6835
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h2 class="text-xl font-display font-bold text-gray-900 mb-2">Vereinsatzung</h2>
|
<h2 class="text-xl font-display font-bold text-gray-900 mb-2">
|
||||||
|
Vereinsatzung
|
||||||
|
</h2>
|
||||||
<p class="text-gray-700 mb-4">
|
<p class="text-gray-700 mb-4">
|
||||||
Unsere aktuelle Vereinsatzung können Sie hier herunterladen oder online einsehen:
|
Unsere aktuelle Vereinsatzung können Sie hier herunterladen oder online einsehen:
|
||||||
</p>
|
</p>
|
||||||
@@ -63,64 +76,91 @@
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
class="inline-flex items-center px-4 py-2 bg-primary-600 hover:bg-primary-700 text-white font-medium rounded-lg transition-colors"
|
class="inline-flex items-center px-4 py-2 bg-primary-600 hover:bg-primary-700 text-white font-medium rounded-lg transition-colors"
|
||||||
>
|
>
|
||||||
<FileText :size="16" class="mr-2" />
|
<FileText
|
||||||
|
:size="16"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
Satzung herunterladen (PDF)
|
Satzung herunterladen (PDF)
|
||||||
</a>
|
</a>
|
||||||
<NuxtLink
|
<NuxtLink
|
||||||
to="/satzung"
|
to="/satzung"
|
||||||
class="inline-flex items-center px-4 py-2 bg-gray-100 hover:bg-gray-200 text-gray-900 font-medium rounded-lg transition-colors"
|
class="inline-flex items-center px-4 py-2 bg-gray-100 hover:bg-gray-200 text-gray-900 font-medium rounded-lg transition-colors"
|
||||||
>
|
>
|
||||||
<Eye :size="16" class="mr-2" />
|
<Eye
|
||||||
|
:size="16"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
Online ansehen
|
Online ansehen
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="config">
|
<div v-if="config">
|
||||||
<h2 class="text-xl font-display font-bold text-gray-900 mb-2">Verantwortlich für den Inhalt nach § 55 Abs. 2 RStV</h2>
|
<h2 class="text-xl font-display font-bold text-gray-900 mb-2">
|
||||||
|
Verantwortlich für den Inhalt nach § 55 Abs. 2 RStV
|
||||||
|
</h2>
|
||||||
<p class="text-gray-700">
|
<p class="text-gray-700">
|
||||||
{{ config.vorstand.vorsitzender.vorname }} {{ config.vorstand.vorsitzender.nachname }}<br />
|
{{ config.vorstand.vorsitzender.vorname }} {{ config.vorstand.vorsitzender.nachname }}<br>
|
||||||
<span v-if="config.vorstand.vorsitzender.strasse">{{ config.vorstand.vorsitzender.strasse }}<br /></span>
|
<span v-if="config.vorstand.vorsitzender.strasse">{{ config.vorstand.vorsitzender.strasse }}<br></span>
|
||||||
<span v-if="config.vorstand.vorsitzender.plz">{{ config.vorstand.vorsitzender.plz }} {{ config.vorstand.vorsitzender.ort }}</span>
|
<span v-if="config.vorstand.vorsitzender.plz">{{ config.vorstand.vorsitzender.plz }} {{ config.vorstand.vorsitzender.ort }}</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="config">
|
<div v-if="config">
|
||||||
<h2 class="text-xl font-display font-bold text-gray-900 mb-2">Verantwortlich für die Website</h2>
|
<h2 class="text-xl font-display font-bold text-gray-900 mb-2">
|
||||||
|
Verantwortlich für die Website
|
||||||
|
</h2>
|
||||||
<p class="text-gray-700">
|
<p class="text-gray-700">
|
||||||
{{ config.website.verantwortlicher.vorname }} {{ config.website.verantwortlicher.nachname }}<br />
|
{{ config.website.verantwortlicher.vorname }} {{ config.website.verantwortlicher.nachname }}<br>
|
||||||
E-Mail: <a :href="`mailto:${config.website.verantwortlicher.email}`" class="text-primary-600 hover:underline">{{ config.website.verantwortlicher.email }}</a>
|
E-Mail: <a
|
||||||
|
:href="`mailto:${config.website.verantwortlicher.email}`"
|
||||||
|
class="text-primary-600 hover:underline"
|
||||||
|
>{{ config.website.verantwortlicher.email }}</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h2 class="text-xl font-display font-bold text-gray-900 mb-2">Haftungsausschluss</h2>
|
<h2 class="text-xl font-display font-bold text-gray-900 mb-2">
|
||||||
|
Haftungsausschluss
|
||||||
|
</h2>
|
||||||
|
|
||||||
<h3 class="font-semibold text-gray-900 mt-4 mb-2">Haftung für Inhalte</h3>
|
<h3 class="font-semibold text-gray-900 mt-4 mb-2">
|
||||||
|
Haftung für Inhalte
|
||||||
|
</h3>
|
||||||
<p class="text-gray-700 mb-4">
|
<p class="text-gray-700 mb-4">
|
||||||
Als Diensteanbieter sind wir gemäß § 7 Abs.1 TMG für eigene Inhalte auf diesen Seiten nach den allgemeinen Gesetzen verantwortlich. Nach §§ 8 bis 10 TMG sind wir als Diensteanbieter jedoch nicht verpflichtet, übermittelte oder gespeicherte fremde Informationen zu überwachen oder nach Umständen zu forschen, die auf eine rechtswidrige Tätigkeit hinweisen. Verpflichtungen zur Entfernung oder Sperrung der Nutzung von Informationen nach den allgemeinen Gesetzen bleiben hiervon unberührt. Eine diesbezügliche Haftung ist jedoch erst ab dem Zeitpunkt der Kenntnis einer konkreten Rechtsverletzung möglich. Bei Bekanntwerden von entsprechenden Rechtsverletzungen werden wir diese Inhalte umgehend entfernen. Grundsätzlich sind alle unsere Informationen ohne Gewähr. Auch für den Fall das unzutreffende oder falsche Informationen enthalten sind, wird vom HTC jegliche Haftung ausgeschlossen.
|
Als Diensteanbieter sind wir gemäß § 7 Abs.1 TMG für eigene Inhalte auf diesen Seiten nach den allgemeinen Gesetzen verantwortlich. Nach §§ 8 bis 10 TMG sind wir als Diensteanbieter jedoch nicht verpflichtet, übermittelte oder gespeicherte fremde Informationen zu überwachen oder nach Umständen zu forschen, die auf eine rechtswidrige Tätigkeit hinweisen. Verpflichtungen zur Entfernung oder Sperrung der Nutzung von Informationen nach den allgemeinen Gesetzen bleiben hiervon unberührt. Eine diesbezügliche Haftung ist jedoch erst ab dem Zeitpunkt der Kenntnis einer konkreten Rechtsverletzung möglich. Bei Bekanntwerden von entsprechenden Rechtsverletzungen werden wir diese Inhalte umgehend entfernen. Grundsätzlich sind alle unsere Informationen ohne Gewähr. Auch für den Fall das unzutreffende oder falsche Informationen enthalten sind, wird vom HTC jegliche Haftung ausgeschlossen.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h3 class="font-semibold text-gray-900 mt-4 mb-2">Haftung für Links</h3>
|
<h3 class="font-semibold text-gray-900 mt-4 mb-2">
|
||||||
|
Haftung für Links
|
||||||
|
</h3>
|
||||||
<p class="text-gray-700 mb-4">
|
<p class="text-gray-700 mb-4">
|
||||||
Unser Angebot enthält Links zu externen Websites Dritter, auf deren Inhalte wir keinen Einfluss haben. Deshalb können wir für diese fremden Inhalte auch keine Gewähr übernehmen. Für die Inhalte der verlinkten Seiten ist stets der jeweilige Anbieter oder Betreiber der Seiten verantwortlich. Die verlinkten Seiten wurden zum Zeitpunkt der Verlinkung auf mögliche Rechtsverstöße überprüft. Rechtswidrige Inhalte waren zum Zeitpunkt der Verlinkung nicht erkennbar. Eine permanente inhaltliche Kontrolle der verlinkten Seiten ist jedoch ohne konkrete Anhaltspunkte einer Rechtsverletzung nicht zumutbar. Eine Haftung für Schäden, die ggf. durch das Aufrufen dieser Seiten, bzw. deren Inhalte entstehen, wird vom HTC nicht übernommen. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Links umgehend entfernen.
|
Unser Angebot enthält Links zu externen Websites Dritter, auf deren Inhalte wir keinen Einfluss haben. Deshalb können wir für diese fremden Inhalte auch keine Gewähr übernehmen. Für die Inhalte der verlinkten Seiten ist stets der jeweilige Anbieter oder Betreiber der Seiten verantwortlich. Die verlinkten Seiten wurden zum Zeitpunkt der Verlinkung auf mögliche Rechtsverstöße überprüft. Rechtswidrige Inhalte waren zum Zeitpunkt der Verlinkung nicht erkennbar. Eine permanente inhaltliche Kontrolle der verlinkten Seiten ist jedoch ohne konkrete Anhaltspunkte einer Rechtsverletzung nicht zumutbar. Eine Haftung für Schäden, die ggf. durch das Aufrufen dieser Seiten, bzw. deren Inhalte entstehen, wird vom HTC nicht übernommen. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Links umgehend entfernen.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h3 class="font-semibold text-gray-900 mt-4 mb-2">Urheberrecht</h3>
|
<h3 class="font-semibold text-gray-900 mt-4 mb-2">
|
||||||
|
Urheberrecht
|
||||||
|
</h3>
|
||||||
<p class="text-gray-700 mb-4">
|
<p class="text-gray-700 mb-4">
|
||||||
Die durch die Seitenbetreiber erstellten Inhalte und Werke auf diesen Seiten unterliegen dem deutschen Urheberrecht. Die Vervielfältigung, Bearbeitung, Verbreitung und jede Art der Verwertung außerhalb der Grenzen des Urheberrechtes bedürfen der schriftlichen Zustimmung des jeweiligen Autors bzw. Erstellers. Downloads und Kopien dieser Seite sind nur für den privaten, nicht kommerziellen Gebrauch gestattet. Soweit die Inhalte auf dieser Seite nicht vom Betreiber erstellt wurden, werden die Urheberrechte Dritter beachtet. Insbesondere werden Inhalte Dritter als solche gekennzeichnet. Sollten Sie trotzdem auf eine Urheberrechtsverletzung aufmerksam werden, bitten wir um einen entsprechenden Hinweis. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Inhalte umgehend entfernen.
|
Die durch die Seitenbetreiber erstellten Inhalte und Werke auf diesen Seiten unterliegen dem deutschen Urheberrecht. Die Vervielfältigung, Bearbeitung, Verbreitung und jede Art der Verwertung außerhalb der Grenzen des Urheberrechtes bedürfen der schriftlichen Zustimmung des jeweiligen Autors bzw. Erstellers. Downloads und Kopien dieser Seite sind nur für den privaten, nicht kommerziellen Gebrauch gestattet. Soweit die Inhalte auf dieser Seite nicht vom Betreiber erstellt wurden, werden die Urheberrechte Dritter beachtet. Insbesondere werden Inhalte Dritter als solche gekennzeichnet. Sollten Sie trotzdem auf eine Urheberrechtsverletzung aufmerksam werden, bitten wir um einen entsprechenden Hinweis. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Inhalte umgehend entfernen.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h2 class="text-xl font-display font-bold text-gray-900 mb-2">Datenschutzerklärung</h2>
|
<h2 class="text-xl font-display font-bold text-gray-900 mb-2">
|
||||||
|
Datenschutzerklärung
|
||||||
|
</h2>
|
||||||
|
|
||||||
<h3 class="font-semibold text-gray-900 mt-4 mb-2">Datenschutz</h3>
|
<h3 class="font-semibold text-gray-900 mt-4 mb-2">
|
||||||
|
Datenschutz
|
||||||
|
</h3>
|
||||||
<p class="text-gray-700 mb-4">
|
<p class="text-gray-700 mb-4">
|
||||||
Die Betreiber dieser Seiten nehmen den Schutz Ihrer persönlichen Daten sehr ernst. Wir behandeln Ihre personenbezogenen Daten vertraulich und entsprechend der gesetzlichen Datenschutzvorschriften sowie dieser Datenschutzerklärung. Die Nutzung unserer Website ist in der Regel ohne Angabe personenbezogener Daten möglich. Soweit auf unseren Seiten personenbezogene Daten (beispielsweise Name, Anschrift oder E-Mail-Adressen) erhoben werden, erfolgt dies, soweit möglich, stets auf freiwilliger Basis. Diese Daten werden ohne Ihre ausdrückliche Zustimmung nicht an Dritte weitergegeben. Wir weisen darauf hin, dass die Datenübertragung im Internet (z.B. bei der Kommunikation per E-Mail) Sicherheitslücken aufweisen kann. Ein lückenloser Schutz der Daten vor dem Zugriff durch Dritte ist nicht möglich.
|
Die Betreiber dieser Seiten nehmen den Schutz Ihrer persönlichen Daten sehr ernst. Wir behandeln Ihre personenbezogenen Daten vertraulich und entsprechend der gesetzlichen Datenschutzvorschriften sowie dieser Datenschutzerklärung. Die Nutzung unserer Website ist in der Regel ohne Angabe personenbezogener Daten möglich. Soweit auf unseren Seiten personenbezogene Daten (beispielsweise Name, Anschrift oder E-Mail-Adressen) erhoben werden, erfolgt dies, soweit möglich, stets auf freiwilliger Basis. Diese Daten werden ohne Ihre ausdrückliche Zustimmung nicht an Dritte weitergegeben. Wir weisen darauf hin, dass die Datenübertragung im Internet (z.B. bei der Kommunikation per E-Mail) Sicherheitslücken aufweisen kann. Ein lückenloser Schutz der Daten vor dem Zugriff durch Dritte ist nicht möglich.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h3 class="font-semibold text-gray-900 mt-4 mb-2">Widerspruch Werbe-Mails</h3>
|
<h3 class="font-semibold text-gray-900 mt-4 mb-2">
|
||||||
|
Widerspruch Werbe-Mails
|
||||||
|
</h3>
|
||||||
<p class="text-gray-700">
|
<p class="text-gray-700">
|
||||||
Der Nutzung von im Rahmen der Impressumspflicht veröffentlichten Kontaktdaten zur Übersendung von nicht ausdrücklich angeforderter Werbung und Informationsmaterialien wird hiermit widersprochen. Die Betreiber der Seiten behalten sich ausdrücklich rechtliche Schritte im Falle der unverlangten Zusendung von Werbeinformationen, etwa durch Spam-E-Mails, vor.
|
Der Nutzung von im Rahmen der Impressumspflicht veröffentlichten Kontaktdaten zur Übersendung von nicht ausdrücklich angeforderter Werbung und Informationsmaterialien wird hiermit widersprochen. Die Betreiber der Seiten behalten sich ausdrücklich rechtliche Schritte im Falle der unverlangten Zusendung von Werbeinformationen, etwa durch Spam-E-Mails, vor.
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -11,10 +11,16 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-white rounded-xl shadow-lg p-8">
|
<div class="bg-white rounded-xl shadow-lg p-8">
|
||||||
<form @submit.prevent="handleLogin" class="space-y-6">
|
<form
|
||||||
|
class="space-y-6"
|
||||||
|
@submit.prevent="handleLogin"
|
||||||
|
>
|
||||||
<!-- Email -->
|
<!-- Email -->
|
||||||
<div>
|
<div>
|
||||||
<label for="email" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="email"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
E-Mail-Adresse
|
E-Mail-Adresse
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -26,12 +32,15 @@
|
|||||||
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-600 focus:border-transparent transition-all"
|
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-600 focus:border-transparent transition-all"
|
||||||
:class="{ 'border-red-500': errorMessage }"
|
:class="{ 'border-red-500': errorMessage }"
|
||||||
placeholder="ihre-email@example.com"
|
placeholder="ihre-email@example.com"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Password -->
|
<!-- Password -->
|
||||||
<div>
|
<div>
|
||||||
<label for="password" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="password"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
Passwort
|
Passwort
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -43,21 +52,33 @@
|
|||||||
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-600 focus:border-transparent transition-all"
|
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-600 focus:border-transparent transition-all"
|
||||||
:class="{ 'border-red-500': errorMessage }"
|
:class="{ 'border-red-500': errorMessage }"
|
||||||
placeholder="••••••••"
|
placeholder="••••••••"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Error Message -->
|
<!-- Error Message -->
|
||||||
<div v-if="errorMessage" class="bg-red-50 border border-red-200 rounded-lg p-4">
|
<div
|
||||||
|
v-if="errorMessage"
|
||||||
|
class="bg-red-50 border border-red-200 rounded-lg p-4"
|
||||||
|
>
|
||||||
<p class="text-sm text-red-800 flex items-center">
|
<p class="text-sm text-red-800 flex items-center">
|
||||||
<AlertCircle :size="18" class="mr-2" />
|
<AlertCircle
|
||||||
|
:size="18"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
{{ errorMessage }}
|
{{ errorMessage }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Success Message -->
|
<!-- Success Message -->
|
||||||
<div v-if="successMessage" class="bg-green-50 border border-green-200 rounded-lg p-4">
|
<div
|
||||||
|
v-if="successMessage"
|
||||||
|
class="bg-green-50 border border-green-200 rounded-lg p-4"
|
||||||
|
>
|
||||||
<p class="text-sm text-green-800 flex items-center">
|
<p class="text-sm text-green-800 flex items-center">
|
||||||
<Check :size="18" class="mr-2" />
|
<Check
|
||||||
|
:size="18"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
{{ successMessage }}
|
{{ successMessage }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -68,7 +89,11 @@
|
|||||||
:disabled="isLoading"
|
:disabled="isLoading"
|
||||||
class="w-full px-6 py-3 bg-primary-600 hover:bg-primary-700 disabled:bg-gray-400 text-white font-semibold rounded-lg transition-colors flex items-center justify-center"
|
class="w-full px-6 py-3 bg-primary-600 hover:bg-primary-700 disabled:bg-gray-400 text-white font-semibold rounded-lg transition-colors flex items-center justify-center"
|
||||||
>
|
>
|
||||||
<Loader2 v-if="isLoading" :size="20" class="mr-2 animate-spin" />
|
<Loader2
|
||||||
|
v-if="isLoading"
|
||||||
|
:size="20"
|
||||||
|
class="mr-2 animate-spin"
|
||||||
|
/>
|
||||||
<span>{{ isLoading ? 'Anmeldung läuft...' : 'Anmelden' }}</span>
|
<span>{{ isLoading ? 'Anmeldung läuft...' : 'Anmelden' }}</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
@@ -87,7 +112,10 @@
|
|||||||
<!-- Info Box -->
|
<!-- Info Box -->
|
||||||
<div class="bg-primary-50 border border-primary-100 rounded-lg p-4">
|
<div class="bg-primary-50 border border-primary-100 rounded-lg p-4">
|
||||||
<p class="text-sm text-primary-800 text-center">
|
<p class="text-sm text-primary-800 text-center">
|
||||||
<Lock :size="16" class="inline mr-1" />
|
<Lock
|
||||||
|
:size="16"
|
||||||
|
class="inline mr-1"
|
||||||
|
/>
|
||||||
Nur für Vereinsmitglieder. Kein Zugang? Kontaktieren Sie den Vorstand.
|
Nur für Vereinsmitglieder. Kein Zugang? Kontaktieren Sie den Vorstand.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,39 +1,46 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="min-h-full py-16 bg-gray-50">
|
<div class="min-h-full py-16 bg-gray-50">
|
||||||
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<div v-if="mannschaft" class="space-y-8">
|
<div
|
||||||
|
v-if="mannschaft"
|
||||||
|
class="space-y-8"
|
||||||
|
>
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div class="bg-gradient-to-r from-primary-600 to-primary-700 rounded-xl p-8 text-white">
|
<div class="bg-gradient-to-r from-primary-600 to-primary-700 rounded-xl p-8 text-white">
|
||||||
<h1 class="text-4xl font-display font-bold mb-2">
|
<h1 class="text-4xl font-display font-bold mb-2">
|
||||||
{{ mannschaft.mannschaft }}
|
{{ mannschaft.mannschaft }}
|
||||||
</h1>
|
</h1>
|
||||||
<p class="text-primary-100 text-xl">{{ mannschaft.liga }}</p>
|
<p class="text-primary-100 text-xl">
|
||||||
|
{{ mannschaft.liga }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Liga-Info -->
|
<!-- Liga-Info -->
|
||||||
<div class="bg-white rounded-xl shadow-lg p-6">
|
<div class="bg-white rounded-xl shadow-lg p-6">
|
||||||
<h2 class="text-2xl font-semibold text-gray-900 mb-6">Liga-Informationen</h2>
|
<h2 class="text-2xl font-semibold text-gray-900 mb-6">
|
||||||
|
Liga-Informationen
|
||||||
|
</h2>
|
||||||
<div class="grid md:grid-cols-2 gap-6">
|
<div class="grid md:grid-cols-2 gap-6">
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<div class="flex items-center space-x-3">
|
<div class="flex items-center space-x-3">
|
||||||
<div class="w-2 h-2 bg-primary-600 rounded-full"></div>
|
<div class="w-2 h-2 bg-primary-600 rounded-full" />
|
||||||
<span class="text-gray-600">Staffelleiter:</span>
|
<span class="text-gray-600">Staffelleiter:</span>
|
||||||
<span class="font-semibold text-gray-900">{{ mannschaft.staffelleiter }}</span>
|
<span class="font-semibold text-gray-900">{{ mannschaft.staffelleiter }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center space-x-3">
|
<div class="flex items-center space-x-3">
|
||||||
<div class="w-2 h-2 bg-primary-600 rounded-full"></div>
|
<div class="w-2 h-2 bg-primary-600 rounded-full" />
|
||||||
<span class="text-gray-600">Telefon:</span>
|
<span class="text-gray-600">Telefon:</span>
|
||||||
<span class="font-semibold text-gray-900">{{ mannschaft.telefon }}</span>
|
<span class="font-semibold text-gray-900">{{ mannschaft.telefon }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<div class="flex items-center space-x-3">
|
<div class="flex items-center space-x-3">
|
||||||
<div class="w-2 h-2 bg-primary-600 rounded-full"></div>
|
<div class="w-2 h-2 bg-primary-600 rounded-full" />
|
||||||
<span class="text-gray-600">Heimspieltag:</span>
|
<span class="text-gray-600">Heimspieltag:</span>
|
||||||
<span class="font-semibold text-gray-900">{{ mannschaft.heimspieltag }}</span>
|
<span class="font-semibold text-gray-900">{{ mannschaft.heimspieltag }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center space-x-3">
|
<div class="flex items-center space-x-3">
|
||||||
<div class="w-2 h-2 bg-primary-600 rounded-full"></div>
|
<div class="w-2 h-2 bg-primary-600 rounded-full" />
|
||||||
<span class="text-gray-600">Spielsystem:</span>
|
<span class="text-gray-600">Spielsystem:</span>
|
||||||
<span class="font-semibold text-gray-900">{{ mannschaft.spielsystem }}</span>
|
<span class="font-semibold text-gray-900">{{ mannschaft.spielsystem }}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -53,8 +60,13 @@
|
|||||||
class="bg-gray-50 rounded-lg p-4 text-center"
|
class="bg-gray-50 rounded-lg p-4 text-center"
|
||||||
:class="spieler === mannschaft.mannschaftsfuehrer ? 'ring-2 ring-primary-500 bg-primary-50' : ''"
|
:class="spieler === mannschaft.mannschaftsfuehrer ? 'ring-2 ring-primary-500 bg-primary-50' : ''"
|
||||||
>
|
>
|
||||||
<div class="font-semibold text-gray-900">{{ spieler }}</div>
|
<div class="font-semibold text-gray-900">
|
||||||
<div v-if="spieler === mannschaft.mannschaftsfuehrer" class="text-xs text-primary-600 font-medium mt-1">
|
{{ spieler }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="spieler === mannschaft.mannschaftsfuehrer"
|
||||||
|
class="text-xs text-primary-600 font-medium mt-1"
|
||||||
|
>
|
||||||
Mannschaftsführer
|
Mannschaftsführer
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -63,7 +75,9 @@
|
|||||||
|
|
||||||
<!-- Links -->
|
<!-- Links -->
|
||||||
<div class="bg-white rounded-xl shadow-lg p-6">
|
<div class="bg-white rounded-xl shadow-lg p-6">
|
||||||
<h2 class="text-2xl font-semibold text-gray-900 mb-6">Weitere Informationen</h2>
|
<h2 class="text-2xl font-semibold text-gray-900 mb-6">
|
||||||
|
Weitere Informationen
|
||||||
|
</h2>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<a
|
<a
|
||||||
v-if="mannschaft.weitere_informationen_link && mannschaft.weitere_informationen_link !== ''"
|
v-if="mannschaft.weitere_informationen_link && mannschaft.weitere_informationen_link !== ''"
|
||||||
@@ -71,7 +85,10 @@
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
class="inline-flex items-center px-8 py-4 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors"
|
class="inline-flex items-center px-8 py-4 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors"
|
||||||
>
|
>
|
||||||
<BarChart :size="24" class="mr-3" />
|
<BarChart
|
||||||
|
:size="24"
|
||||||
|
class="mr-3"
|
||||||
|
/>
|
||||||
Weitere Informationen
|
Weitere Informationen
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -95,9 +112,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else class="text-center py-16">
|
<div
|
||||||
<h1 class="text-4xl font-display font-bold text-gray-900 mb-4">Mannschaft nicht gefunden</h1>
|
v-else
|
||||||
<p class="text-gray-600 mb-8">Die angeforderte Mannschaft konnte nicht gefunden werden.</p>
|
class="text-center py-16"
|
||||||
|
>
|
||||||
|
<h1 class="text-4xl font-display font-bold text-gray-900 mb-4">
|
||||||
|
Mannschaft nicht gefunden
|
||||||
|
</h1>
|
||||||
|
<p class="text-gray-600 mb-8">
|
||||||
|
Die angeforderte Mannschaft konnte nicht gefunden werden.
|
||||||
|
</p>
|
||||||
<NuxtLink
|
<NuxtLink
|
||||||
to="/mannschaften"
|
to="/mannschaften"
|
||||||
class="inline-flex items-center px-6 py-3 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors"
|
class="inline-flex items-center px-6 py-3 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors"
|
||||||
|
|||||||
@@ -7,12 +7,20 @@
|
|||||||
<div class="w-24 h-1 bg-primary-600 mb-8" />
|
<div class="w-24 h-1 bg-primary-600 mb-8" />
|
||||||
|
|
||||||
<div class="bg-white p-8 rounded-xl shadow-lg">
|
<div class="bg-white p-8 rounded-xl shadow-lg">
|
||||||
<h3 class="text-2xl font-display font-bold text-gray-900 mb-4">1. Damen</h3>
|
<h3 class="text-2xl font-display font-bold text-gray-900 mb-4">
|
||||||
<p class="text-gray-600 mb-4">Liga: Bezirksliga</p>
|
1. Damen
|
||||||
<p class="text-gray-600 mb-6">Mannschaftsführerin: Name folgt</p>
|
</h3>
|
||||||
|
<p class="text-gray-600 mb-4">
|
||||||
|
Liga: Bezirksliga
|
||||||
|
</p>
|
||||||
|
<p class="text-gray-600 mb-6">
|
||||||
|
Mannschaftsführerin: Name folgt
|
||||||
|
</p>
|
||||||
|
|
||||||
<div class="mt-8">
|
<div class="mt-8">
|
||||||
<h4 class="text-lg font-semibold text-gray-900 mb-4">Wir suchen Verstärkung!</h4>
|
<h4 class="text-lg font-semibold text-gray-900 mb-4">
|
||||||
|
Wir suchen Verstärkung!
|
||||||
|
</h4>
|
||||||
<p class="text-gray-600 mb-4">
|
<p class="text-gray-600 mb-4">
|
||||||
Unsere Damenmannschaft freut sich über neue Spielerinnen. Interessiert? Dann melde dich bei uns!
|
Unsere Damenmannschaft freut sich über neue Spielerinnen. Interessiert? Dann melde dich bei uns!
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -8,21 +8,39 @@
|
|||||||
|
|
||||||
<div class="space-y-8">
|
<div class="space-y-8">
|
||||||
<div class="bg-white p-8 rounded-xl shadow-lg">
|
<div class="bg-white p-8 rounded-xl shadow-lg">
|
||||||
<h3 class="text-2xl font-display font-bold text-gray-900 mb-4">1. Herren</h3>
|
<h3 class="text-2xl font-display font-bold text-gray-900 mb-4">
|
||||||
<p class="text-gray-600 mb-4">Liga: Bezirksoberliga</p>
|
1. Herren
|
||||||
<p class="text-gray-600">Mannschaftsführer: Name folgt</p>
|
</h3>
|
||||||
|
<p class="text-gray-600 mb-4">
|
||||||
|
Liga: Bezirksoberliga
|
||||||
|
</p>
|
||||||
|
<p class="text-gray-600">
|
||||||
|
Mannschaftsführer: Name folgt
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-white p-8 rounded-xl shadow-lg">
|
<div class="bg-white p-8 rounded-xl shadow-lg">
|
||||||
<h3 class="text-2xl font-display font-bold text-gray-900 mb-4">2. Herren</h3>
|
<h3 class="text-2xl font-display font-bold text-gray-900 mb-4">
|
||||||
<p class="text-gray-600 mb-4">Liga: Bezirksliga</p>
|
2. Herren
|
||||||
<p class="text-gray-600">Mannschaftsführer: Name folgt</p>
|
</h3>
|
||||||
|
<p class="text-gray-600 mb-4">
|
||||||
|
Liga: Bezirksliga
|
||||||
|
</p>
|
||||||
|
<p class="text-gray-600">
|
||||||
|
Mannschaftsführer: Name folgt
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-white p-8 rounded-xl shadow-lg">
|
<div class="bg-white p-8 rounded-xl shadow-lg">
|
||||||
<h3 class="text-2xl font-display font-bold text-gray-900 mb-4">3. Herren</h3>
|
<h3 class="text-2xl font-display font-bold text-gray-900 mb-4">
|
||||||
<p class="text-gray-600 mb-4">Liga: Kreisliga</p>
|
3. Herren
|
||||||
<p class="text-gray-600">Mannschaftsführer: Name folgt</p>
|
</h3>
|
||||||
|
<p class="text-gray-600 mb-4">
|
||||||
|
Liga: Kreisliga
|
||||||
|
</p>
|
||||||
|
<p class="text-gray-600">
|
||||||
|
Mannschaftsführer: Name folgt
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -14,18 +14,18 @@
|
|||||||
|
|
||||||
<div class="mt-16">
|
<div class="mt-16">
|
||||||
<div class="bg-primary-50 p-8 rounded-xl border border-primary-100">
|
<div class="bg-primary-50 p-8 rounded-xl border border-primary-100">
|
||||||
<h3 class="text-2xl font-display font-bold text-gray-900 mb-4">
|
<h3 class="text-2xl font-display font-bold text-gray-900 mb-4">
|
||||||
Spielpläne & Ergebnisse
|
Spielpläne & Ergebnisse
|
||||||
</h3>
|
</h3>
|
||||||
<p class="text-gray-600 mb-6">
|
<p class="text-gray-600 mb-6">
|
||||||
Alle aktuellen Spielpläne und Ergebnisse unserer Mannschaften finden Sie hier.
|
Alle aktuellen Spielpläne und Ergebnisse unserer Mannschaften finden Sie hier.
|
||||||
</p>
|
</p>
|
||||||
<NuxtLink
|
<NuxtLink
|
||||||
to="/mannschaften/spielplaene"
|
to="/mannschaften/spielplaene"
|
||||||
class="inline-flex items-center px-6 py-3 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors"
|
class="inline-flex items-center px-6 py-3 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors"
|
||||||
>
|
>
|
||||||
Zu den Spielplänen
|
Zu den Spielplänen
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,15 +8,27 @@
|
|||||||
|
|
||||||
<div class="space-y-8">
|
<div class="space-y-8">
|
||||||
<div class="bg-white p-8 rounded-xl shadow-lg">
|
<div class="bg-white p-8 rounded-xl shadow-lg">
|
||||||
<h3 class="text-2xl font-display font-bold text-gray-900 mb-4">Jugend 1 (U18)</h3>
|
<h3 class="text-2xl font-display font-bold text-gray-900 mb-4">
|
||||||
<p class="text-gray-600 mb-4">Liga: Bezirksliga</p>
|
Jugend 1 (U18)
|
||||||
<p class="text-gray-600">Betreuer: Name folgt</p>
|
</h3>
|
||||||
|
<p class="text-gray-600 mb-4">
|
||||||
|
Liga: Bezirksliga
|
||||||
|
</p>
|
||||||
|
<p class="text-gray-600">
|
||||||
|
Betreuer: Name folgt
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-white p-8 rounded-xl shadow-lg">
|
<div class="bg-white p-8 rounded-xl shadow-lg">
|
||||||
<h3 class="text-2xl font-display font-bold text-gray-900 mb-4">Jugend 2 (U15)</h3>
|
<h3 class="text-2xl font-display font-bold text-gray-900 mb-4">
|
||||||
<p class="text-gray-600 mb-4">Liga: Kreisliga</p>
|
Jugend 2 (U15)
|
||||||
<p class="text-gray-600">Betreuer: Name folgt</p>
|
</h3>
|
||||||
|
<p class="text-gray-600 mb-4">
|
||||||
|
Liga: Kreisliga
|
||||||
|
</p>
|
||||||
|
<p class="text-gray-600">
|
||||||
|
Betreuer: Name folgt
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-primary-50 p-8 rounded-xl border border-primary-100">
|
<div class="bg-primary-50 p-8 rounded-xl border border-primary-100">
|
||||||
@@ -24,7 +36,7 @@
|
|||||||
Jugendtraining
|
Jugendtraining
|
||||||
</h3>
|
</h3>
|
||||||
<p class="text-gray-600 mb-6">
|
<p class="text-gray-600 mb-6">
|
||||||
<strong>Dienstag & Donnerstag:</strong> 17:00 - 19:00 Uhr<br />
|
<strong>Dienstag & Donnerstag:</strong> 17:00 - 19:00 Uhr<br>
|
||||||
Für Kinder und Jugendliche von 8-18 Jahren
|
Für Kinder und Jugendliche von 8-18 Jahren
|
||||||
</p>
|
</p>
|
||||||
<NuxtLink
|
<NuxtLink
|
||||||
|
|||||||
@@ -5,8 +5,12 @@
|
|||||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<h1 class="text-3xl font-bold text-gray-900">Spielpläne</h1>
|
<h1 class="text-3xl font-bold text-gray-900">
|
||||||
<p class="mt-2 text-gray-600">Alle Spielpläne der Mannschaften</p>
|
Spielpläne
|
||||||
|
</h1>
|
||||||
|
<p class="mt-2 text-gray-600">
|
||||||
|
Alle Spielpläne der Mannschaften
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -21,36 +25,58 @@
|
|||||||
<div class="flex flex-col sm:flex-row sm:items-center gap-4">
|
<div class="flex flex-col sm:flex-row sm:items-center gap-4">
|
||||||
<!-- Wettbewerbs-Filter -->
|
<!-- Wettbewerbs-Filter -->
|
||||||
<div class="flex items-center space-x-2">
|
<div class="flex items-center space-x-2">
|
||||||
<label for="wettbewerb-select" class="text-sm font-medium text-gray-700">
|
<label
|
||||||
|
for="wettbewerb-select"
|
||||||
|
class="text-sm font-medium text-gray-700"
|
||||||
|
>
|
||||||
Wettbewerb:
|
Wettbewerb:
|
||||||
</label>
|
</label>
|
||||||
<select
|
<select
|
||||||
id="wettbewerb-select"
|
id="wettbewerb-select"
|
||||||
v-model="selectedWettbewerb"
|
v-model="selectedWettbewerb"
|
||||||
@change="filterData"
|
|
||||||
class="px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500 bg-white text-sm"
|
class="px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500 bg-white text-sm"
|
||||||
|
@change="filterData"
|
||||||
>
|
>
|
||||||
<option value="punktrunde">Punktrunde</option>
|
<option value="punktrunde">
|
||||||
<option value="pokal">Pokal</option>
|
Punktrunde
|
||||||
<option value="alle">Alle</option>
|
</option>
|
||||||
|
<option value="pokal">
|
||||||
|
Pokal
|
||||||
|
</option>
|
||||||
|
<option value="alle">
|
||||||
|
Alle
|
||||||
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Mannschafts-Filter -->
|
<!-- Mannschafts-Filter -->
|
||||||
<div class="flex items-center space-x-2">
|
<div class="flex items-center space-x-2">
|
||||||
<label for="filter-select" class="text-sm font-medium text-gray-700">
|
<label
|
||||||
|
for="filter-select"
|
||||||
|
class="text-sm font-medium text-gray-700"
|
||||||
|
>
|
||||||
Mannschaft:
|
Mannschaft:
|
||||||
</label>
|
</label>
|
||||||
<select
|
<select
|
||||||
id="filter-select"
|
id="filter-select"
|
||||||
v-model="selectedFilter"
|
v-model="selectedFilter"
|
||||||
@change="filterData"
|
|
||||||
class="px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500 bg-white text-sm"
|
class="px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500 bg-white text-sm"
|
||||||
|
@change="filterData"
|
||||||
>
|
>
|
||||||
<option value="all">Gesamt</option>
|
<option value="all">
|
||||||
<option value="erwachsene">Erwachsene</option>
|
Gesamt
|
||||||
<option value="nachwuchs">Nachwuchs</option>
|
</option>
|
||||||
<option v-for="mannschaft in mannschaften" :key="mannschaft" :value="mannschaft">
|
<option value="erwachsene">
|
||||||
|
Erwachsene
|
||||||
|
</option>
|
||||||
|
<option value="nachwuchs">
|
||||||
|
Nachwuchs
|
||||||
|
</option>
|
||||||
|
<option
|
||||||
|
v-for="mannschaft in mannschaften"
|
||||||
|
:key="mannschaft"
|
||||||
|
:value="mannschaft"
|
||||||
|
>
|
||||||
{{ mannschaft }}
|
{{ mannschaft }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
@@ -59,12 +85,22 @@
|
|||||||
|
|
||||||
<!-- Download Button -->
|
<!-- Download Button -->
|
||||||
<button
|
<button
|
||||||
@click="downloadPDF"
|
|
||||||
:disabled="isLoading || !filteredData.length"
|
:disabled="isLoading || !filteredData.length"
|
||||||
class="inline-flex items-center px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors disabled:bg-gray-400"
|
class="inline-flex items-center px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors disabled:bg-gray-400"
|
||||||
|
@click="downloadPDF"
|
||||||
>
|
>
|
||||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
class="w-4 h-4 mr-2"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
PDF Download
|
PDF Download
|
||||||
</button>
|
</button>
|
||||||
@@ -88,38 +124,95 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Loading State -->
|
<!-- Loading State -->
|
||||||
<div v-if="isLoading" class="text-center py-12">
|
<div
|
||||||
<svg class="w-8 h-8 text-gray-400 mx-auto mb-4 animate-spin" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
v-if="isLoading"
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
class="text-center py-12"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="w-8 h-8 text-gray-400 mx-auto mb-4 animate-spin"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<p class="text-gray-600">Spielpläne werden geladen...</p>
|
<p class="text-gray-600">
|
||||||
|
Spielpläne werden geladen...
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Error State -->
|
<!-- Error State -->
|
||||||
<div v-else-if="error" class="bg-red-50 border border-red-200 rounded-lg p-6 text-center">
|
<div
|
||||||
<svg class="w-12 h-12 text-red-400 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
v-else-if="error"
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z" />
|
class="bg-red-50 border border-red-200 rounded-lg p-6 text-center"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="w-12 h-12 text-red-400 mx-auto mb-4"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<h3 class="text-lg font-medium text-red-800 mb-2">Fehler beim Laden</h3>
|
<h3 class="text-lg font-medium text-red-800 mb-2">
|
||||||
<p class="text-red-600 mb-4">{{ error }}</p>
|
Fehler beim Laden
|
||||||
<button @click="loadData" class="px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors">
|
</h3>
|
||||||
|
<p class="text-red-600 mb-4">
|
||||||
|
{{ error }}
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
class="px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors"
|
||||||
|
@click="loadData"
|
||||||
|
>
|
||||||
Erneut versuchen
|
Erneut versuchen
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Empty State -->
|
<!-- Empty State -->
|
||||||
<div v-else-if="!spielplanData || spielplanData.length === 0" class="text-center py-12 bg-white rounded-xl shadow-lg">
|
<div
|
||||||
<svg class="w-12 h-12 text-gray-400 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
v-else-if="!spielplanData || spielplanData.length === 0"
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
|
class="text-center py-12 bg-white rounded-xl shadow-lg"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="w-12 h-12 text-gray-400 mx-auto mb-4"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M9 5H7a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<h3 class="text-lg font-medium text-gray-900 mb-2">Keine Spielpläne verfügbar</h3>
|
<h3 class="text-lg font-medium text-gray-900 mb-2">
|
||||||
<p class="text-gray-600">Es wurden noch keine Spielplandaten hochgeladen.</p>
|
Keine Spielpläne verfügbar
|
||||||
|
</h3>
|
||||||
|
<p class="text-gray-600">
|
||||||
|
Es wurden noch keine Spielplandaten hochgeladen.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Spielplan Table -->
|
<!-- Spielplan Table -->
|
||||||
<div v-else class="bg-white rounded-xl shadow-lg overflow-hidden">
|
<div
|
||||||
|
v-else
|
||||||
|
class="bg-white rounded-xl shadow-lg overflow-hidden"
|
||||||
|
>
|
||||||
<div class="px-6 py-4 border-b border-gray-200">
|
<div class="px-6 py-4 border-b border-gray-200">
|
||||||
<h2 class="text-xl font-semibold text-gray-900">Spielplan</h2>
|
<h2 class="text-xl font-semibold text-gray-900">
|
||||||
|
Spielplan
|
||||||
|
</h2>
|
||||||
<p class="text-sm text-gray-600 mt-1">
|
<p class="text-sm text-gray-600 mt-1">
|
||||||
{{ getWettbewerbText() }} - {{ filteredData.length }} von {{ spielplanData.length }} Einträgen
|
{{ getWettbewerbText() }} - {{ filteredData.length }} von {{ spielplanData.length }} Einträgen
|
||||||
</p>
|
</p>
|
||||||
@@ -129,24 +222,42 @@
|
|||||||
<table class="min-w-full divide-y divide-gray-200">
|
<table class="min-w-full divide-y divide-gray-200">
|
||||||
<thead class="bg-gray-50">
|
<thead class="bg-gray-50">
|
||||||
<tr>
|
<tr>
|
||||||
<th v-for="header in headers" :key="header"
|
<th
|
||||||
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
v-for="header in headers"
|
||||||
|
:key="header"
|
||||||
|
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
|
||||||
|
>
|
||||||
{{ formatHeader(header) }}
|
{{ formatHeader(header) }}
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="bg-white divide-y divide-gray-200">
|
<tbody class="bg-white divide-y divide-gray-200">
|
||||||
<tr v-for="(row, index) in filteredData" :key="index"
|
<tr
|
||||||
:class="getRowClass(row)">
|
v-for="(row, index) in filteredData"
|
||||||
<td v-for="header in headers" :key="header"
|
:key="index"
|
||||||
class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
|
:class="getRowClass(row)"
|
||||||
<span v-if="header.toLowerCase().includes('datum')" class="font-mono">
|
>
|
||||||
|
<td
|
||||||
|
v-for="header in headers"
|
||||||
|
:key="header"
|
||||||
|
class="px-6 py-4 whitespace-nowrap text-sm text-gray-900"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
v-if="header.toLowerCase().includes('datum')"
|
||||||
|
class="font-mono"
|
||||||
|
>
|
||||||
{{ formatDate(row[getOriginalHeader(header)]) }}
|
{{ formatDate(row[getOriginalHeader(header)]) }}
|
||||||
</span>
|
</span>
|
||||||
<span v-else-if="header.toLowerCase().includes('uhrzeit')" class="font-mono">
|
<span
|
||||||
|
v-else-if="header.toLowerCase().includes('uhrzeit')"
|
||||||
|
class="font-mono"
|
||||||
|
>
|
||||||
{{ formatTime(row[getOriginalHeader(header)]) }}
|
{{ formatTime(row[getOriginalHeader(header)]) }}
|
||||||
</span>
|
</span>
|
||||||
<span v-else-if="header.toLowerCase().includes('mannschaft')" class="font-medium">
|
<span
|
||||||
|
v-else-if="header.toLowerCase().includes('mannschaft')"
|
||||||
|
class="font-medium"
|
||||||
|
>
|
||||||
{{ row[getOriginalHeader(header)] || '-' }}
|
{{ row[getOriginalHeader(header)] || '-' }}
|
||||||
</span>
|
</span>
|
||||||
<span v-else-if="header.toLowerCase().includes('runde')">
|
<span v-else-if="header.toLowerCase().includes('runde')">
|
||||||
|
|||||||
@@ -13,19 +13,27 @@
|
|||||||
|
|
||||||
<!-- Authentication Info -->
|
<!-- Authentication Info -->
|
||||||
<div class="bg-blue-50 border-l-4 border-blue-500 p-6 rounded-lg mb-8">
|
<div class="bg-blue-50 border-l-4 border-blue-500 p-6 rounded-lg mb-8">
|
||||||
<h2 class="text-xl font-semibold text-blue-900 mb-2">Authentifizierung</h2>
|
<h2 class="text-xl font-semibold text-blue-900 mb-2">
|
||||||
|
Authentifizierung
|
||||||
|
</h2>
|
||||||
<p class="text-blue-800 mb-4">
|
<p class="text-blue-800 mb-4">
|
||||||
Alle API-Endpoints erfordern Authentifizierung (außer Login). Es werden zwei Methoden unterstützt:
|
Alle API-Endpoints erfordern Authentifizierung (außer Login). Es werden zwei Methoden unterstützt:
|
||||||
</p>
|
</p>
|
||||||
<div class="space-y-3">
|
<div class="space-y-3">
|
||||||
<div>
|
<div>
|
||||||
<strong class="text-blue-900">1. Cookie-basiert:</strong>
|
<strong class="text-blue-900">1. Cookie-basiert:</strong>
|
||||||
<p class="text-blue-700 text-sm mt-1">Nach dem Login über <code>/api/auth/login</code> wird automatisch ein Cookie gesetzt.</p>
|
<p class="text-blue-700 text-sm mt-1">
|
||||||
|
Nach dem Login über <code>/api/auth/login</code> wird automatisch ein Cookie gesetzt.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<strong class="text-blue-900">2. Authorization Header:</strong>
|
<strong class="text-blue-900">2. Authorization Header:</strong>
|
||||||
<p class="text-blue-700 text-sm mt-1">Header: <code>Authorization: Bearer <token></code></p>
|
<p class="text-blue-700 text-sm mt-1">
|
||||||
<p class="text-blue-700 text-sm">Der Token wird im Login-Response im Feld <code>token</code> zurückgegeben.</p>
|
Header: <code>Authorization: Bearer <token></code>
|
||||||
|
</p>
|
||||||
|
<p class="text-blue-700 text-sm">
|
||||||
|
Der Token wird im Login-Response im Feld <code>token</code> zurückgegeben.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -34,19 +42,27 @@
|
|||||||
<div class="space-y-8">
|
<div class="space-y-8">
|
||||||
<!-- Authentication Endpoints -->
|
<!-- Authentication Endpoints -->
|
||||||
<section class="bg-white rounded-xl shadow-lg p-6">
|
<section class="bg-white rounded-xl shadow-lg p-6">
|
||||||
<h2 class="text-2xl font-display font-bold text-gray-900 mb-6">Authentifizierung</h2>
|
<h2 class="text-2xl font-display font-bold text-gray-900 mb-6">
|
||||||
|
Authentifizierung
|
||||||
|
</h2>
|
||||||
|
|
||||||
<div class="space-y-6">
|
<div class="space-y-6">
|
||||||
<!-- Login -->
|
<!-- Login -->
|
||||||
<div class="border-l-4 border-primary-600 pl-4">
|
<div class="border-l-4 border-primary-600 pl-4">
|
||||||
<div class="flex items-center justify-between mb-2">
|
<div class="flex items-center justify-between mb-2">
|
||||||
<h3 class="text-lg font-semibold text-gray-900">POST /api/auth/login</h3>
|
<h3 class="text-lg font-semibold text-gray-900">
|
||||||
|
POST /api/auth/login
|
||||||
|
</h3>
|
||||||
<span class="px-2 py-1 text-xs font-medium bg-green-100 text-green-800 rounded">Öffentlich</span>
|
<span class="px-2 py-1 text-xs font-medium bg-green-100 text-green-800 rounded">Öffentlich</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-gray-600 mb-3">Benutzer einloggen und Token erhalten</p>
|
<p class="text-gray-600 mb-3">
|
||||||
|
Benutzer einloggen und Token erhalten
|
||||||
|
</p>
|
||||||
|
|
||||||
<div class="bg-gray-50 rounded-lg p-4 mb-3">
|
<div class="bg-gray-50 rounded-lg p-4 mb-3">
|
||||||
<p class="text-sm font-medium text-gray-700 mb-2">Request Body:</p>
|
<p class="text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Request Body:
|
||||||
|
</p>
|
||||||
<pre class="text-xs bg-gray-900 text-gray-100 p-3 rounded overflow-x-auto"><code>{
|
<pre class="text-xs bg-gray-900 text-gray-100 p-3 rounded overflow-x-auto"><code>{
|
||||||
"email": "benutzer@example.com",
|
"email": "benutzer@example.com",
|
||||||
"password": "passwort"
|
"password": "passwort"
|
||||||
@@ -54,7 +70,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-gray-50 rounded-lg p-4">
|
<div class="bg-gray-50 rounded-lg p-4">
|
||||||
<p class="text-sm font-medium text-gray-700 mb-2">Response:</p>
|
<p class="text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Response:
|
||||||
|
</p>
|
||||||
<pre class="text-xs bg-gray-900 text-gray-100 p-3 rounded overflow-x-auto"><code>{
|
<pre class="text-xs bg-gray-900 text-gray-100 p-3 rounded overflow-x-auto"><code>{
|
||||||
"success": true,
|
"success": true,
|
||||||
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||||||
@@ -71,13 +89,19 @@
|
|||||||
<!-- Logout -->
|
<!-- Logout -->
|
||||||
<div class="border-l-4 border-primary-600 pl-4">
|
<div class="border-l-4 border-primary-600 pl-4">
|
||||||
<div class="flex items-center justify-between mb-2">
|
<div class="flex items-center justify-between mb-2">
|
||||||
<h3 class="text-lg font-semibold text-gray-900">POST /api/auth/logout</h3>
|
<h3 class="text-lg font-semibold text-gray-900">
|
||||||
|
POST /api/auth/logout
|
||||||
|
</h3>
|
||||||
<span class="px-2 py-1 text-xs font-medium bg-yellow-100 text-yellow-800 rounded">Auth erforderlich</span>
|
<span class="px-2 py-1 text-xs font-medium bg-yellow-100 text-yellow-800 rounded">Auth erforderlich</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-gray-600 mb-3">Benutzer ausloggen</p>
|
<p class="text-gray-600 mb-3">
|
||||||
|
Benutzer ausloggen
|
||||||
|
</p>
|
||||||
|
|
||||||
<div class="bg-gray-50 rounded-lg p-4">
|
<div class="bg-gray-50 rounded-lg p-4">
|
||||||
<p class="text-sm font-medium text-gray-700 mb-2">Response:</p>
|
<p class="text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Response:
|
||||||
|
</p>
|
||||||
<pre class="text-xs bg-gray-900 text-gray-100 p-3 rounded overflow-x-auto"><code>{
|
<pre class="text-xs bg-gray-900 text-gray-100 p-3 rounded overflow-x-auto"><code>{
|
||||||
"success": true,
|
"success": true,
|
||||||
"message": "Erfolgreich ausgeloggt"
|
"message": "Erfolgreich ausgeloggt"
|
||||||
@@ -88,13 +112,19 @@
|
|||||||
<!-- Auth Status -->
|
<!-- Auth Status -->
|
||||||
<div class="border-l-4 border-primary-600 pl-4">
|
<div class="border-l-4 border-primary-600 pl-4">
|
||||||
<div class="flex items-center justify-between mb-2">
|
<div class="flex items-center justify-between mb-2">
|
||||||
<h3 class="text-lg font-semibold text-gray-900">GET /api/auth/status</h3>
|
<h3 class="text-lg font-semibold text-gray-900">
|
||||||
|
GET /api/auth/status
|
||||||
|
</h3>
|
||||||
<span class="px-2 py-1 text-xs font-medium bg-yellow-100 text-yellow-800 rounded">Auth erforderlich</span>
|
<span class="px-2 py-1 text-xs font-medium bg-yellow-100 text-yellow-800 rounded">Auth erforderlich</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-gray-600 mb-3">Aktuellen Authentifizierungsstatus abrufen</p>
|
<p class="text-gray-600 mb-3">
|
||||||
|
Aktuellen Authentifizierungsstatus abrufen
|
||||||
|
</p>
|
||||||
|
|
||||||
<div class="bg-gray-50 rounded-lg p-4">
|
<div class="bg-gray-50 rounded-lg p-4">
|
||||||
<p class="text-sm font-medium text-gray-700 mb-2">Response:</p>
|
<p class="text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Response:
|
||||||
|
</p>
|
||||||
<pre class="text-xs bg-gray-900 text-gray-100 p-3 rounded overflow-x-auto"><code>{
|
<pre class="text-xs bg-gray-900 text-gray-100 p-3 rounded overflow-x-auto"><code>{
|
||||||
"isLoggedIn": true,
|
"isLoggedIn": true,
|
||||||
"user": {
|
"user": {
|
||||||
@@ -112,19 +142,27 @@
|
|||||||
|
|
||||||
<!-- Members Endpoints -->
|
<!-- Members Endpoints -->
|
||||||
<section class="bg-white rounded-xl shadow-lg p-6">
|
<section class="bg-white rounded-xl shadow-lg p-6">
|
||||||
<h2 class="text-2xl font-display font-bold text-gray-900 mb-6">Mitglieder</h2>
|
<h2 class="text-2xl font-display font-bold text-gray-900 mb-6">
|
||||||
|
Mitglieder
|
||||||
|
</h2>
|
||||||
|
|
||||||
<div class="space-y-6">
|
<div class="space-y-6">
|
||||||
<!-- Get Members -->
|
<!-- Get Members -->
|
||||||
<div class="border-l-4 border-primary-600 pl-4">
|
<div class="border-l-4 border-primary-600 pl-4">
|
||||||
<div class="flex items-center justify-between mb-2">
|
<div class="flex items-center justify-between mb-2">
|
||||||
<h3 class="text-lg font-semibold text-gray-900">GET /api/members</h3>
|
<h3 class="text-lg font-semibold text-gray-900">
|
||||||
|
GET /api/members
|
||||||
|
</h3>
|
||||||
<span class="px-2 py-1 text-xs font-medium bg-yellow-100 text-yellow-800 rounded">Auth erforderlich</span>
|
<span class="px-2 py-1 text-xs font-medium bg-yellow-100 text-yellow-800 rounded">Auth erforderlich</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-gray-600 mb-3">Alle Mitglieder abrufen (mit Merge aus registrierten Benutzern)</p>
|
<p class="text-gray-600 mb-3">
|
||||||
|
Alle Mitglieder abrufen (mit Merge aus registrierten Benutzern)
|
||||||
|
</p>
|
||||||
|
|
||||||
<div class="bg-gray-50 rounded-lg p-4">
|
<div class="bg-gray-50 rounded-lg p-4">
|
||||||
<p class="text-sm font-medium text-gray-700 mb-2">Response:</p>
|
<p class="text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Response:
|
||||||
|
</p>
|
||||||
<pre class="text-xs bg-gray-900 text-gray-100 p-3 rounded overflow-x-auto"><code>{
|
<pre class="text-xs bg-gray-900 text-gray-100 p-3 rounded overflow-x-auto"><code>{
|
||||||
"success": true,
|
"success": true,
|
||||||
"members": [
|
"members": [
|
||||||
@@ -148,13 +186,19 @@
|
|||||||
<!-- Post Members -->
|
<!-- Post Members -->
|
||||||
<div class="border-l-4 border-red-500 pl-4">
|
<div class="border-l-4 border-red-500 pl-4">
|
||||||
<div class="flex items-center justify-between mb-2">
|
<div class="flex items-center justify-between mb-2">
|
||||||
<h3 class="text-lg font-semibold text-gray-900">POST /api/members</h3>
|
<h3 class="text-lg font-semibold text-gray-900">
|
||||||
|
POST /api/members
|
||||||
|
</h3>
|
||||||
<span class="px-2 py-1 text-xs font-medium bg-red-100 text-red-800 rounded">admin/vorstand</span>
|
<span class="px-2 py-1 text-xs font-medium bg-red-100 text-red-800 rounded">admin/vorstand</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-gray-600 mb-3">Neues Mitglied hinzufügen oder bestehendes bearbeiten</p>
|
<p class="text-gray-600 mb-3">
|
||||||
|
Neues Mitglied hinzufügen oder bestehendes bearbeiten
|
||||||
|
</p>
|
||||||
|
|
||||||
<div class="bg-gray-50 rounded-lg p-4 mb-3">
|
<div class="bg-gray-50 rounded-lg p-4 mb-3">
|
||||||
<p class="text-sm font-medium text-gray-700 mb-2">Request Body:</p>
|
<p class="text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Request Body:
|
||||||
|
</p>
|
||||||
<pre class="text-xs bg-gray-900 text-gray-100 p-3 rounded overflow-x-auto"><code>{
|
<pre class="text-xs bg-gray-900 text-gray-100 p-3 rounded overflow-x-auto"><code>{
|
||||||
"id": "optional-für-update",
|
"id": "optional-für-update",
|
||||||
"firstName": "Max",
|
"firstName": "Max",
|
||||||
@@ -168,7 +212,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-gray-50 rounded-lg p-4 mb-3">
|
<div class="bg-gray-50 rounded-lg p-4 mb-3">
|
||||||
<p class="text-sm font-medium text-gray-700 mb-2">Response:</p>
|
<p class="text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Response:
|
||||||
|
</p>
|
||||||
<pre class="text-xs bg-gray-900 text-gray-100 p-3 rounded overflow-x-auto"><code>{
|
<pre class="text-xs bg-gray-900 text-gray-100 p-3 rounded overflow-x-auto"><code>{
|
||||||
"success": true,
|
"success": true,
|
||||||
"message": "Mitglied erfolgreich gespeichert."
|
"message": "Mitglied erfolgreich gespeichert."
|
||||||
@@ -185,13 +231,19 @@
|
|||||||
<!-- Bulk Import Members -->
|
<!-- Bulk Import Members -->
|
||||||
<div class="border-l-4 border-red-500 pl-4">
|
<div class="border-l-4 border-red-500 pl-4">
|
||||||
<div class="flex items-center justify-between mb-2">
|
<div class="flex items-center justify-between mb-2">
|
||||||
<h3 class="text-lg font-semibold text-gray-900">POST /api/members/bulk</h3>
|
<h3 class="text-lg font-semibold text-gray-900">
|
||||||
|
POST /api/members/bulk
|
||||||
|
</h3>
|
||||||
<span class="px-2 py-1 text-xs font-medium bg-red-100 text-red-800 rounded">admin/vorstand</span>
|
<span class="px-2 py-1 text-xs font-medium bg-red-100 text-red-800 rounded">admin/vorstand</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-gray-600 mb-3">Mehrere Mitglieder auf einmal importieren (Bulk-Import)</p>
|
<p class="text-gray-600 mb-3">
|
||||||
|
Mehrere Mitglieder auf einmal importieren (Bulk-Import)
|
||||||
|
</p>
|
||||||
|
|
||||||
<div class="bg-gray-50 rounded-lg p-4 mb-3">
|
<div class="bg-gray-50 rounded-lg p-4 mb-3">
|
||||||
<p class="text-sm font-medium text-gray-700 mb-2">Request Body:</p>
|
<p class="text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Request Body:
|
||||||
|
</p>
|
||||||
<pre class="text-xs bg-gray-900 text-gray-100 p-3 rounded overflow-x-auto"><code>{
|
<pre class="text-xs bg-gray-900 text-gray-100 p-3 rounded overflow-x-auto"><code>{
|
||||||
"members": [
|
"members": [
|
||||||
{
|
{
|
||||||
@@ -214,7 +266,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-gray-50 rounded-lg p-4 mb-3">
|
<div class="bg-gray-50 rounded-lg p-4 mb-3">
|
||||||
<p class="text-sm font-medium text-gray-700 mb-2">Response:</p>
|
<p class="text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Response:
|
||||||
|
</p>
|
||||||
<pre class="text-xs bg-gray-900 text-gray-100 p-3 rounded overflow-x-auto"><code>{
|
<pre class="text-xs bg-gray-900 text-gray-100 p-3 rounded overflow-x-auto"><code>{
|
||||||
"success": true,
|
"success": true,
|
||||||
"summary": {
|
"summary": {
|
||||||
@@ -253,20 +307,28 @@
|
|||||||
<!-- Delete Members -->
|
<!-- Delete Members -->
|
||||||
<div class="border-l-4 border-red-500 pl-4">
|
<div class="border-l-4 border-red-500 pl-4">
|
||||||
<div class="flex items-center justify-between mb-2">
|
<div class="flex items-center justify-between mb-2">
|
||||||
<h3 class="text-lg font-semibold text-gray-900">DELETE /api/members</h3>
|
<h3 class="text-lg font-semibold text-gray-900">
|
||||||
|
DELETE /api/members
|
||||||
|
</h3>
|
||||||
<span class="px-2 py-1 text-xs font-medium bg-red-100 text-red-800 rounded">admin/vorstand</span>
|
<span class="px-2 py-1 text-xs font-medium bg-red-100 text-red-800 rounded">admin/vorstand</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-gray-600 mb-3">Mitglied löschen</p>
|
<p class="text-gray-600 mb-3">
|
||||||
|
Mitglied löschen
|
||||||
|
</p>
|
||||||
|
|
||||||
<div class="bg-gray-50 rounded-lg p-4 mb-3">
|
<div class="bg-gray-50 rounded-lg p-4 mb-3">
|
||||||
<p class="text-sm font-medium text-gray-700 mb-2">Request Body:</p>
|
<p class="text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Request Body:
|
||||||
|
</p>
|
||||||
<pre class="text-xs bg-gray-900 text-gray-100 p-3 rounded overflow-x-auto"><code>{
|
<pre class="text-xs bg-gray-900 text-gray-100 p-3 rounded overflow-x-auto"><code>{
|
||||||
"id": "member-id"
|
"id": "member-id"
|
||||||
}</code></pre>
|
}</code></pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-gray-50 rounded-lg p-4">
|
<div class="bg-gray-50 rounded-lg p-4">
|
||||||
<p class="text-sm font-medium text-gray-700 mb-2">Response:</p>
|
<p class="text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Response:
|
||||||
|
</p>
|
||||||
<pre class="text-xs bg-gray-900 text-gray-100 p-3 rounded overflow-x-auto"><code>{
|
<pre class="text-xs bg-gray-900 text-gray-100 p-3 rounded overflow-x-auto"><code>{
|
||||||
"success": true,
|
"success": true,
|
||||||
"message": "Mitglied erfolgreich gelöscht."
|
"message": "Mitglied erfolgreich gelöscht."
|
||||||
@@ -278,28 +340,40 @@
|
|||||||
|
|
||||||
<!-- News Endpoints -->
|
<!-- News Endpoints -->
|
||||||
<section class="bg-white rounded-xl shadow-lg p-6">
|
<section class="bg-white rounded-xl shadow-lg p-6">
|
||||||
<h2 class="text-2xl font-display font-bold text-gray-900 mb-6">News</h2>
|
<h2 class="text-2xl font-display font-bold text-gray-900 mb-6">
|
||||||
|
News
|
||||||
|
</h2>
|
||||||
|
|
||||||
<div class="space-y-6">
|
<div class="space-y-6">
|
||||||
<!-- Get News -->
|
<!-- Get News -->
|
||||||
<div class="border-l-4 border-primary-600 pl-4">
|
<div class="border-l-4 border-primary-600 pl-4">
|
||||||
<div class="flex items-center justify-between mb-2">
|
<div class="flex items-center justify-between mb-2">
|
||||||
<h3 class="text-lg font-semibold text-gray-900">GET /api/news</h3>
|
<h3 class="text-lg font-semibold text-gray-900">
|
||||||
|
GET /api/news
|
||||||
|
</h3>
|
||||||
<span class="px-2 py-1 text-xs font-medium bg-yellow-100 text-yellow-800 rounded">Auth erforderlich</span>
|
<span class="px-2 py-1 text-xs font-medium bg-yellow-100 text-yellow-800 rounded">Auth erforderlich</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-gray-600 mb-3">Alle News abrufen (inkl. interner News)</p>
|
<p class="text-gray-600 mb-3">
|
||||||
|
Alle News abrufen (inkl. interner News)
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Post News -->
|
<!-- Post News -->
|
||||||
<div class="border-l-4 border-red-500 pl-4">
|
<div class="border-l-4 border-red-500 pl-4">
|
||||||
<div class="flex items-center justify-between mb-2">
|
<div class="flex items-center justify-between mb-2">
|
||||||
<h3 class="text-lg font-semibold text-gray-900">POST /api/news</h3>
|
<h3 class="text-lg font-semibold text-gray-900">
|
||||||
|
POST /api/news
|
||||||
|
</h3>
|
||||||
<span class="px-2 py-1 text-xs font-medium bg-red-100 text-red-800 rounded">admin/vorstand</span>
|
<span class="px-2 py-1 text-xs font-medium bg-red-100 text-red-800 rounded">admin/vorstand</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-gray-600 mb-3">Neue News erstellen oder bestehende bearbeiten</p>
|
<p class="text-gray-600 mb-3">
|
||||||
|
Neue News erstellen oder bestehende bearbeiten
|
||||||
|
</p>
|
||||||
|
|
||||||
<div class="bg-gray-50 rounded-lg p-4 mb-3">
|
<div class="bg-gray-50 rounded-lg p-4 mb-3">
|
||||||
<p class="text-sm font-medium text-gray-700 mb-2">Request Body:</p>
|
<p class="text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Request Body:
|
||||||
|
</p>
|
||||||
<pre class="text-xs bg-gray-900 text-gray-100 p-3 rounded overflow-x-auto"><code>{
|
<pre class="text-xs bg-gray-900 text-gray-100 p-3 rounded overflow-x-auto"><code>{
|
||||||
"id": "optional-für-update",
|
"id": "optional-für-update",
|
||||||
"title": "Titel der News",
|
"title": "Titel der News",
|
||||||
@@ -314,13 +388,19 @@
|
|||||||
<!-- Delete News -->
|
<!-- Delete News -->
|
||||||
<div class="border-l-4 border-red-500 pl-4">
|
<div class="border-l-4 border-red-500 pl-4">
|
||||||
<div class="flex items-center justify-between mb-2">
|
<div class="flex items-center justify-between mb-2">
|
||||||
<h3 class="text-lg font-semibold text-gray-900">DELETE /api/news</h3>
|
<h3 class="text-lg font-semibold text-gray-900">
|
||||||
|
DELETE /api/news
|
||||||
|
</h3>
|
||||||
<span class="px-2 py-1 text-xs font-medium bg-red-100 text-red-800 rounded">admin/vorstand</span>
|
<span class="px-2 py-1 text-xs font-medium bg-red-100 text-red-800 rounded">admin/vorstand</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-gray-600 mb-3">News löschen</p>
|
<p class="text-gray-600 mb-3">
|
||||||
|
News löschen
|
||||||
|
</p>
|
||||||
|
|
||||||
<div class="bg-gray-50 rounded-lg p-4 mb-3">
|
<div class="bg-gray-50 rounded-lg p-4 mb-3">
|
||||||
<p class="text-sm font-medium text-gray-700 mb-2">Request Body:</p>
|
<p class="text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Request Body:
|
||||||
|
</p>
|
||||||
<pre class="text-xs bg-gray-900 text-gray-100 p-3 rounded overflow-x-auto"><code>{
|
<pre class="text-xs bg-gray-900 text-gray-100 p-3 rounded overflow-x-auto"><code>{
|
||||||
"id": "news-id"
|
"id": "news-id"
|
||||||
}</code></pre>
|
}</code></pre>
|
||||||
@@ -331,28 +411,40 @@
|
|||||||
|
|
||||||
<!-- Termine Endpoints -->
|
<!-- Termine Endpoints -->
|
||||||
<section class="bg-white rounded-xl shadow-lg p-6">
|
<section class="bg-white rounded-xl shadow-lg p-6">
|
||||||
<h2 class="text-2xl font-display font-bold text-gray-900 mb-6">Termine</h2>
|
<h2 class="text-2xl font-display font-bold text-gray-900 mb-6">
|
||||||
|
Termine
|
||||||
|
</h2>
|
||||||
|
|
||||||
<div class="space-y-6">
|
<div class="space-y-6">
|
||||||
<!-- Get Termine -->
|
<!-- Get Termine -->
|
||||||
<div class="border-l-4 border-red-500 pl-4">
|
<div class="border-l-4 border-red-500 pl-4">
|
||||||
<div class="flex items-center justify-between mb-2">
|
<div class="flex items-center justify-between mb-2">
|
||||||
<h3 class="text-lg font-semibold text-gray-900">GET /api/termine-manage</h3>
|
<h3 class="text-lg font-semibold text-gray-900">
|
||||||
|
GET /api/termine-manage
|
||||||
|
</h3>
|
||||||
<span class="px-2 py-1 text-xs font-medium bg-red-100 text-red-800 rounded">admin/vorstand</span>
|
<span class="px-2 py-1 text-xs font-medium bg-red-100 text-red-800 rounded">admin/vorstand</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-gray-600 mb-3">Alle Termine abrufen (für Verwaltung)</p>
|
<p class="text-gray-600 mb-3">
|
||||||
|
Alle Termine abrufen (für Verwaltung)
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Post Termine -->
|
<!-- Post Termine -->
|
||||||
<div class="border-l-4 border-red-500 pl-4">
|
<div class="border-l-4 border-red-500 pl-4">
|
||||||
<div class="flex items-center justify-between mb-2">
|
<div class="flex items-center justify-between mb-2">
|
||||||
<h3 class="text-lg font-semibold text-gray-900">POST /api/termine-manage</h3>
|
<h3 class="text-lg font-semibold text-gray-900">
|
||||||
|
POST /api/termine-manage
|
||||||
|
</h3>
|
||||||
<span class="px-2 py-1 text-xs font-medium bg-red-100 text-red-800 rounded">admin/vorstand</span>
|
<span class="px-2 py-1 text-xs font-medium bg-red-100 text-red-800 rounded">admin/vorstand</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-gray-600 mb-3">Neuen Termin erstellen</p>
|
<p class="text-gray-600 mb-3">
|
||||||
|
Neuen Termin erstellen
|
||||||
|
</p>
|
||||||
|
|
||||||
<div class="bg-gray-50 rounded-lg p-4 mb-3">
|
<div class="bg-gray-50 rounded-lg p-4 mb-3">
|
||||||
<p class="text-sm font-medium text-gray-700 mb-2">Request Body:</p>
|
<p class="text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Request Body:
|
||||||
|
</p>
|
||||||
<pre class="text-xs bg-gray-900 text-gray-100 p-3 rounded overflow-x-auto"><code>{
|
<pre class="text-xs bg-gray-900 text-gray-100 p-3 rounded overflow-x-auto"><code>{
|
||||||
"datum": "2025-12-25",
|
"datum": "2025-12-25",
|
||||||
"uhrzeit": "19:00",
|
"uhrzeit": "19:00",
|
||||||
@@ -366,13 +458,19 @@
|
|||||||
<!-- Delete Termine -->
|
<!-- Delete Termine -->
|
||||||
<div class="border-l-4 border-red-500 pl-4">
|
<div class="border-l-4 border-red-500 pl-4">
|
||||||
<div class="flex items-center justify-between mb-2">
|
<div class="flex items-center justify-between mb-2">
|
||||||
<h3 class="text-lg font-semibold text-gray-900">DELETE /api/termine-manage</h3>
|
<h3 class="text-lg font-semibold text-gray-900">
|
||||||
|
DELETE /api/termine-manage
|
||||||
|
</h3>
|
||||||
<span class="px-2 py-1 text-xs font-medium bg-red-100 text-red-800 rounded">admin/vorstand</span>
|
<span class="px-2 py-1 text-xs font-medium bg-red-100 text-red-800 rounded">admin/vorstand</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-gray-600 mb-3">Termin löschen</p>
|
<p class="text-gray-600 mb-3">
|
||||||
|
Termin löschen
|
||||||
|
</p>
|
||||||
|
|
||||||
<div class="bg-gray-50 rounded-lg p-4 mb-3">
|
<div class="bg-gray-50 rounded-lg p-4 mb-3">
|
||||||
<p class="text-sm font-medium text-gray-700 mb-2">Query Parameters:</p>
|
<p class="text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Query Parameters:
|
||||||
|
</p>
|
||||||
<pre class="text-xs bg-gray-900 text-gray-100 p-3 rounded overflow-x-auto"><code>?datum=2025-12-25&uhrzeit=19:00&titel=Weihnachtsfeier&beschreibung=...&kategorie=...</code></pre>
|
<pre class="text-xs bg-gray-900 text-gray-100 p-3 rounded overflow-x-auto"><code>?datum=2025-12-25&uhrzeit=19:00&titel=Weihnachtsfeier&beschreibung=...&kategorie=...</code></pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -381,29 +479,43 @@
|
|||||||
|
|
||||||
<!-- Config Endpoints -->
|
<!-- Config Endpoints -->
|
||||||
<section class="bg-white rounded-xl shadow-lg p-6">
|
<section class="bg-white rounded-xl shadow-lg p-6">
|
||||||
<h2 class="text-2xl font-display font-bold text-gray-900 mb-6">Konfiguration</h2>
|
<h2 class="text-2xl font-display font-bold text-gray-900 mb-6">
|
||||||
|
Konfiguration
|
||||||
|
</h2>
|
||||||
|
|
||||||
<div class="space-y-6">
|
<div class="space-y-6">
|
||||||
<!-- Get Config -->
|
<!-- Get Config -->
|
||||||
<div class="border-l-4 border-red-500 pl-4">
|
<div class="border-l-4 border-red-500 pl-4">
|
||||||
<div class="flex items-center justify-between mb-2">
|
<div class="flex items-center justify-between mb-2">
|
||||||
<h3 class="text-lg font-semibold text-gray-900">GET /api/config</h3>
|
<h3 class="text-lg font-semibold text-gray-900">
|
||||||
|
GET /api/config
|
||||||
|
</h3>
|
||||||
<span class="px-2 py-1 text-xs font-medium bg-red-100 text-red-800 rounded">admin/vorstand</span>
|
<span class="px-2 py-1 text-xs font-medium bg-red-100 text-red-800 rounded">admin/vorstand</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-gray-600 mb-3">Vereinskonfiguration abrufen</p>
|
<p class="text-gray-600 mb-3">
|
||||||
|
Vereinskonfiguration abrufen
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Put Config -->
|
<!-- Put Config -->
|
||||||
<div class="border-l-4 border-red-500 pl-4">
|
<div class="border-l-4 border-red-500 pl-4">
|
||||||
<div class="flex items-center justify-between mb-2">
|
<div class="flex items-center justify-between mb-2">
|
||||||
<h3 class="text-lg font-semibold text-gray-900">PUT /api/config</h3>
|
<h3 class="text-lg font-semibold text-gray-900">
|
||||||
|
PUT /api/config
|
||||||
|
</h3>
|
||||||
<span class="px-2 py-1 text-xs font-medium bg-red-100 text-red-800 rounded">admin/vorstand</span>
|
<span class="px-2 py-1 text-xs font-medium bg-red-100 text-red-800 rounded">admin/vorstand</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-gray-600 mb-3">Vereinskonfiguration aktualisieren</p>
|
<p class="text-gray-600 mb-3">
|
||||||
|
Vereinskonfiguration aktualisieren
|
||||||
|
</p>
|
||||||
|
|
||||||
<div class="bg-gray-50 rounded-lg p-4 mb-3">
|
<div class="bg-gray-50 rounded-lg p-4 mb-3">
|
||||||
<p class="text-sm font-medium text-gray-700 mb-2">Request Body:</p>
|
<p class="text-sm font-medium text-gray-700 mb-2">
|
||||||
<p class="text-xs text-gray-600">Komplettes Config-Objekt mit allen Einstellungen</p>
|
Request Body:
|
||||||
|
</p>
|
||||||
|
<p class="text-xs text-gray-600">
|
||||||
|
Komplettes Config-Objekt mit allen Einstellungen
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -412,11 +524,15 @@
|
|||||||
|
|
||||||
<!-- Example Usage -->
|
<!-- Example Usage -->
|
||||||
<div class="mt-12 bg-white rounded-xl shadow-lg p-6">
|
<div class="mt-12 bg-white rounded-xl shadow-lg p-6">
|
||||||
<h2 class="text-2xl font-display font-bold text-gray-900 mb-6">Beispiel-Usage</h2>
|
<h2 class="text-2xl font-display font-bold text-gray-900 mb-6">
|
||||||
|
Beispiel-Usage
|
||||||
|
</h2>
|
||||||
|
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-lg font-semibold text-gray-900 mb-2">cURL Beispiel:</h3>
|
<h3 class="text-lg font-semibold text-gray-900 mb-2">
|
||||||
|
cURL Beispiel:
|
||||||
|
</h3>
|
||||||
<pre class="text-xs bg-gray-900 text-gray-100 p-4 rounded overflow-x-auto"><code># Login und Token erhalten
|
<pre class="text-xs bg-gray-900 text-gray-100 p-4 rounded overflow-x-auto"><code># Login und Token erhalten
|
||||||
curl -X POST http://localhost:3100/api/auth/login \
|
curl -X POST http://localhost:3100/api/auth/login \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
@@ -457,7 +573,9 @@ curl -X POST http://localhost:3100/api/members/bulk \
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-lg font-semibold text-gray-900 mb-2">JavaScript/Fetch Beispiel:</h3>
|
<h3 class="text-lg font-semibold text-gray-900 mb-2">
|
||||||
|
JavaScript/Fetch Beispiel:
|
||||||
|
</h3>
|
||||||
<pre class="text-xs bg-gray-900 text-gray-100 p-4 rounded overflow-x-auto"><code>// Login
|
<pre class="text-xs bg-gray-900 text-gray-100 p-4 rounded overflow-x-auto"><code>// Login
|
||||||
const loginResponse = await fetch('/api/auth/login', {
|
const loginResponse = await fetch('/api/auth/login', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -516,7 +634,9 @@ const result = await bulkResponse.json()
|
|||||||
|
|
||||||
<!-- Role Legend -->
|
<!-- Role Legend -->
|
||||||
<div class="mt-8 bg-gray-50 rounded-xl p-6">
|
<div class="mt-8 bg-gray-50 rounded-xl p-6">
|
||||||
<h2 class="text-xl font-semibold text-gray-900 mb-4">Legende</h2>
|
<h2 class="text-xl font-semibold text-gray-900 mb-4">
|
||||||
|
Legende
|
||||||
|
</h2>
|
||||||
<div class="grid md:grid-cols-3 gap-4">
|
<div class="grid md:grid-cols-3 gap-4">
|
||||||
<div class="flex items-center space-x-2">
|
<div class="flex items-center space-x-2">
|
||||||
<span class="px-2 py-1 text-xs font-medium bg-green-100 text-green-800 rounded">Öffentlich</span>
|
<span class="px-2 py-1 text-xs font-medium bg-green-100 text-green-800 rounded">Öffentlich</span>
|
||||||
|
|||||||
@@ -14,9 +14,14 @@
|
|||||||
>
|
>
|
||||||
<div class="flex items-center mb-4">
|
<div class="flex items-center mb-4">
|
||||||
<div class="w-12 h-12 bg-primary-100 rounded-lg flex items-center justify-center group-hover:bg-primary-600 transition-colors">
|
<div class="w-12 h-12 bg-primary-100 rounded-lg flex items-center justify-center group-hover:bg-primary-600 transition-colors">
|
||||||
<User :size="24" class="text-primary-600 group-hover:text-white" />
|
<User
|
||||||
|
:size="24"
|
||||||
|
class="text-primary-600 group-hover:text-white"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="ml-4 text-xl font-semibold text-gray-900">Mein Profil</h2>
|
<h2 class="ml-4 text-xl font-semibold text-gray-900">
|
||||||
|
Mein Profil
|
||||||
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-gray-600">
|
<p class="text-gray-600">
|
||||||
Persönliche Daten und Passwort verwalten
|
Persönliche Daten und Passwort verwalten
|
||||||
@@ -30,9 +35,14 @@
|
|||||||
>
|
>
|
||||||
<div class="flex items-center mb-4">
|
<div class="flex items-center mb-4">
|
||||||
<div class="w-12 h-12 bg-primary-100 rounded-lg flex items-center justify-center group-hover:bg-primary-600 transition-colors">
|
<div class="w-12 h-12 bg-primary-100 rounded-lg flex items-center justify-center group-hover:bg-primary-600 transition-colors">
|
||||||
<Users :size="24" class="text-primary-600 group-hover:text-white" />
|
<Users
|
||||||
|
:size="24"
|
||||||
|
class="text-primary-600 group-hover:text-white"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="ml-4 text-xl font-semibold text-gray-900">Mitglieder</h2>
|
<h2 class="ml-4 text-xl font-semibold text-gray-900">
|
||||||
|
Mitglieder
|
||||||
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-gray-600">
|
<p class="text-gray-600">
|
||||||
Kontaktdaten der Vereinsmitglieder
|
Kontaktdaten der Vereinsmitglieder
|
||||||
@@ -46,9 +56,14 @@
|
|||||||
>
|
>
|
||||||
<div class="flex items-center mb-4">
|
<div class="flex items-center mb-4">
|
||||||
<div class="w-12 h-12 bg-primary-100 rounded-lg flex items-center justify-center group-hover:bg-primary-600 transition-colors">
|
<div class="w-12 h-12 bg-primary-100 rounded-lg flex items-center justify-center group-hover:bg-primary-600 transition-colors">
|
||||||
<Newspaper :size="24" class="text-primary-600 group-hover:text-white" />
|
<Newspaper
|
||||||
|
:size="24"
|
||||||
|
class="text-primary-600 group-hover:text-white"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="ml-4 text-xl font-semibold text-gray-900">News</h2>
|
<h2 class="ml-4 text-xl font-semibold text-gray-900">
|
||||||
|
News
|
||||||
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-gray-600">
|
<p class="text-gray-600">
|
||||||
Neuigkeiten und Ankündigungen
|
Neuigkeiten und Ankündigungen
|
||||||
@@ -66,19 +81,31 @@
|
|||||||
</p>
|
</p>
|
||||||
<div class="grid sm:grid-cols-2 gap-4">
|
<div class="grid sm:grid-cols-2 gap-4">
|
||||||
<div class="flex items-start">
|
<div class="flex items-start">
|
||||||
<Check :size="20" class="text-primary-600 mr-2 mt-0.5" />
|
<Check
|
||||||
|
:size="20"
|
||||||
|
class="text-primary-600 mr-2 mt-0.5"
|
||||||
|
/>
|
||||||
<span class="text-gray-700">Zugriff auf Mitgliederliste mit Kontaktdaten</span>
|
<span class="text-gray-700">Zugriff auf Mitgliederliste mit Kontaktdaten</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-start">
|
<div class="flex items-start">
|
||||||
<Check :size="20" class="text-primary-600 mr-2 mt-0.5" />
|
<Check
|
||||||
|
:size="20"
|
||||||
|
class="text-primary-600 mr-2 mt-0.5"
|
||||||
|
/>
|
||||||
<span class="text-gray-700">Vereinsnews und Ankündigungen</span>
|
<span class="text-gray-700">Vereinsnews und Ankündigungen</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-start">
|
<div class="flex items-start">
|
||||||
<Check :size="20" class="text-primary-600 mr-2 mt-0.5" />
|
<Check
|
||||||
|
:size="20"
|
||||||
|
class="text-primary-600 mr-2 mt-0.5"
|
||||||
|
/>
|
||||||
<span class="text-gray-700">Profilverwaltung und Passwort ändern</span>
|
<span class="text-gray-700">Profilverwaltung und Passwort ändern</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-start">
|
<div class="flex items-start">
|
||||||
<Check :size="20" class="text-primary-600 mr-2 mt-0.5" />
|
<Check
|
||||||
|
:size="20"
|
||||||
|
class="text-primary-600 mr-2 mt-0.5"
|
||||||
|
/>
|
||||||
<span class="text-gray-700">Weitere Funktionen folgen in Kürze</span>
|
<span class="text-gray-700">Weitere Funktionen folgen in Kürze</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -10,80 +10,151 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex items-center space-x-3">
|
<div class="flex items-center space-x-3">
|
||||||
<button
|
<button
|
||||||
@click="viewMode = viewMode === 'cards' ? 'table' : 'cards'"
|
|
||||||
class="flex items-center px-4 py-2 bg-gray-100 hover:bg-gray-200 text-gray-700 font-semibold rounded-lg transition-colors"
|
class="flex items-center px-4 py-2 bg-gray-100 hover:bg-gray-200 text-gray-700 font-semibold rounded-lg transition-colors"
|
||||||
|
@click="viewMode = viewMode === 'cards' ? 'table' : 'cards'"
|
||||||
>
|
>
|
||||||
<component :is="viewMode === 'cards' ? Table2 : Grid3x3" :size="20" class="mr-2" />
|
<component
|
||||||
|
:is="viewMode === 'cards' ? Table2 : Grid3x3"
|
||||||
|
:size="20"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
{{ viewMode === 'cards' ? 'Tabelle' : 'Karten' }}
|
{{ viewMode === 'cards' ? 'Tabelle' : 'Karten' }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="canEdit"
|
v-if="canEdit"
|
||||||
@click="showBulkImportModal = true"
|
|
||||||
class="flex items-center px-4 py-2 bg-green-600 hover:bg-green-700 text-white font-semibold rounded-lg transition-colors"
|
class="flex items-center px-4 py-2 bg-green-600 hover:bg-green-700 text-white font-semibold rounded-lg transition-colors"
|
||||||
|
@click="showBulkImportModal = true"
|
||||||
>
|
>
|
||||||
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"></path>
|
class="w-5 h-5 mr-2"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
Bulk-Import
|
Bulk-Import
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="canEdit"
|
v-if="canEdit"
|
||||||
@click="openAddModal"
|
|
||||||
class="flex items-center px-4 py-2 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors"
|
class="flex items-center px-4 py-2 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors"
|
||||||
|
@click="openAddModal"
|
||||||
>
|
>
|
||||||
<UserPlus :size="20" class="mr-2" />
|
<UserPlus
|
||||||
|
:size="20"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
Mitglied hinzufügen
|
Mitglied hinzufügen
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Loading State -->
|
<!-- Loading State -->
|
||||||
<div v-if="isLoading" class="flex items-center justify-center py-12">
|
<div
|
||||||
<Loader2 :size="40" class="animate-spin text-primary-600" />
|
v-if="isLoading"
|
||||||
|
class="flex items-center justify-center py-12"
|
||||||
|
>
|
||||||
|
<Loader2
|
||||||
|
:size="40"
|
||||||
|
class="animate-spin text-primary-600"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Table View -->
|
<!-- Table View -->
|
||||||
<div v-else-if="viewMode === 'table'" class="bg-white rounded-xl shadow-lg overflow-hidden">
|
<div
|
||||||
|
v-else-if="viewMode === 'table'"
|
||||||
|
class="bg-white rounded-xl shadow-lg overflow-hidden"
|
||||||
|
>
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="min-w-full divide-y divide-gray-200">
|
<table class="min-w-full divide-y divide-gray-200">
|
||||||
<thead class="bg-gray-50">
|
<thead class="bg-gray-50">
|
||||||
<tr>
|
<tr>
|
||||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Name</th>
|
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">E-Mail</th>
|
Name
|
||||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Telefon</th>
|
</th>
|
||||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Mannschaft</th>
|
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
|
E-Mail
|
||||||
<th v-if="canEdit" class="px-4 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">Aktionen</th>
|
</th>
|
||||||
|
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||||
|
Telefon
|
||||||
|
</th>
|
||||||
|
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||||
|
Mannschaft
|
||||||
|
</th>
|
||||||
|
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||||
|
Status
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
v-if="canEdit"
|
||||||
|
class="px-4 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider"
|
||||||
|
>
|
||||||
|
Aktionen
|
||||||
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="bg-white divide-y divide-gray-200">
|
<tbody class="bg-white divide-y divide-gray-200">
|
||||||
<tr v-for="member in members" :key="member.id" class="hover:bg-gray-50">
|
<tr
|
||||||
|
v-for="member in members"
|
||||||
|
:key="member.id"
|
||||||
|
class="hover:bg-gray-50"
|
||||||
|
>
|
||||||
<td class="px-4 py-3 whitespace-nowrap">
|
<td class="px-4 py-3 whitespace-nowrap">
|
||||||
<div class="text-sm font-medium text-gray-900">{{ member.name }}</div>
|
<div class="text-sm font-medium text-gray-900">
|
||||||
<div v-if="member.notes" class="text-xs text-gray-500">{{ member.notes }}</div>
|
{{ member.name }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="member.notes"
|
||||||
|
class="text-xs text-gray-500"
|
||||||
|
>
|
||||||
|
{{ member.notes }}
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="px-4 py-3 whitespace-nowrap">
|
<td class="px-4 py-3 whitespace-nowrap">
|
||||||
<template v-if="canViewContactData">
|
<template v-if="canViewContactData">
|
||||||
<a v-if="member.email" :href="`mailto:${member.email}`" class="text-sm text-primary-600 hover:text-primary-800">
|
<a
|
||||||
|
v-if="member.email"
|
||||||
|
:href="`mailto:${member.email}`"
|
||||||
|
class="text-sm text-primary-600 hover:text-primary-800"
|
||||||
|
>
|
||||||
{{ member.email }}
|
{{ member.email }}
|
||||||
</a>
|
</a>
|
||||||
<span v-else class="text-sm text-gray-400">-</span>
|
<span
|
||||||
|
v-else
|
||||||
|
class="text-sm text-gray-400"
|
||||||
|
>-</span>
|
||||||
</template>
|
</template>
|
||||||
<span v-else class="text-sm text-gray-400">Nur für Vorstand</span>
|
<span
|
||||||
|
v-else
|
||||||
|
class="text-sm text-gray-400"
|
||||||
|
>Nur für Vorstand</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="px-4 py-3 whitespace-nowrap">
|
<td class="px-4 py-3 whitespace-nowrap">
|
||||||
<template v-if="canViewContactData">
|
<template v-if="canViewContactData">
|
||||||
<a v-if="member.phone" :href="`tel:${member.phone}`" class="text-sm text-primary-600 hover:text-primary-800">
|
<a
|
||||||
|
v-if="member.phone"
|
||||||
|
:href="`tel:${member.phone}`"
|
||||||
|
class="text-sm text-primary-600 hover:text-primary-800"
|
||||||
|
>
|
||||||
{{ member.phone }}
|
{{ member.phone }}
|
||||||
</a>
|
</a>
|
||||||
<span v-else class="text-sm text-gray-400">-</span>
|
<span
|
||||||
|
v-else
|
||||||
|
class="text-sm text-gray-400"
|
||||||
|
>-</span>
|
||||||
</template>
|
</template>
|
||||||
<span v-else class="text-sm text-gray-400">Nur für Vorstand</span>
|
<span
|
||||||
|
v-else
|
||||||
|
class="text-sm text-gray-400"
|
||||||
|
>Nur für Vorstand</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="px-4 py-3 whitespace-nowrap">
|
<td class="px-4 py-3 whitespace-nowrap">
|
||||||
<button
|
<button
|
||||||
v-if="canEdit"
|
v-if="canEdit"
|
||||||
@click="toggleMannschaftsspieler(member)"
|
|
||||||
:class="[
|
:class="[
|
||||||
'px-2 py-1 text-xs font-medium rounded-full transition-colors',
|
'px-2 py-1 text-xs font-medium rounded-full transition-colors',
|
||||||
member.isMannschaftsspieler
|
member.isMannschaftsspieler
|
||||||
@@ -91,6 +162,7 @@
|
|||||||
: 'bg-gray-100 text-gray-600 hover:bg-gray-200'
|
: 'bg-gray-100 text-gray-600 hover:bg-gray-200'
|
||||||
]"
|
]"
|
||||||
title="Klicken zum Umschalten"
|
title="Klicken zum Umschalten"
|
||||||
|
@click="toggleMannschaftsspieler(member)"
|
||||||
>
|
>
|
||||||
{{ member.isMannschaftsspieler ? 'Ja' : 'Nein' }}
|
{{ member.isMannschaftsspieler ? 'Ja' : 'Nein' }}
|
||||||
</button>
|
</button>
|
||||||
@@ -122,37 +194,52 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td v-if="canEdit" class="px-4 py-3 whitespace-nowrap text-right text-sm font-medium">
|
<td
|
||||||
<div v-if="member.editable" class="flex justify-end space-x-2">
|
v-if="canEdit"
|
||||||
|
class="px-4 py-3 whitespace-nowrap text-right text-sm font-medium"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-if="member.editable"
|
||||||
|
class="flex justify-end space-x-2"
|
||||||
|
>
|
||||||
<button
|
<button
|
||||||
@click="openEditModal(member)"
|
|
||||||
class="text-blue-600 hover:text-blue-900"
|
class="text-blue-600 hover:text-blue-900"
|
||||||
title="Bearbeiten"
|
title="Bearbeiten"
|
||||||
|
@click="openEditModal(member)"
|
||||||
>
|
>
|
||||||
<Edit :size="18" />
|
<Edit :size="18" />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@click="confirmDelete(member)"
|
|
||||||
class="text-red-600 hover:text-red-900"
|
class="text-red-600 hover:text-red-900"
|
||||||
title="Löschen"
|
title="Löschen"
|
||||||
|
@click="confirmDelete(member)"
|
||||||
>
|
>
|
||||||
<Trash2 :size="18" />
|
<Trash2 :size="18" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<span v-else class="text-gray-400 text-xs">Nicht editierbar</span>
|
<span
|
||||||
|
v-else
|
||||||
|
class="text-gray-400 text-xs"
|
||||||
|
>Nicht editierbar</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="members.length === 0" class="text-center py-12 text-gray-500">
|
<div
|
||||||
|
v-if="members.length === 0"
|
||||||
|
class="text-center py-12 text-gray-500"
|
||||||
|
>
|
||||||
Keine Mitglieder gefunden.
|
Keine Mitglieder gefunden.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Cards View -->
|
<!-- Cards View -->
|
||||||
<div v-else class="space-y-4">
|
<div
|
||||||
|
v-else
|
||||||
|
class="space-y-4"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
v-for="member in members"
|
v-for="member in members"
|
||||||
:key="member.id"
|
:key="member.id"
|
||||||
@@ -161,7 +248,9 @@
|
|||||||
<div class="flex justify-between items-start">
|
<div class="flex justify-between items-start">
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<div class="flex items-center mb-2">
|
<div class="flex items-center mb-2">
|
||||||
<h3 class="text-xl font-semibold text-gray-900">{{ member.name }}</h3>
|
<h3 class="text-xl font-semibold text-gray-900">
|
||||||
|
{{ member.name }}
|
||||||
|
</h3>
|
||||||
<span
|
<span
|
||||||
v-if="member.hasLogin"
|
v-if="member.hasLogin"
|
||||||
class="ml-3 px-2 py-1 bg-green-100 text-green-800 text-xs font-medium rounded-full"
|
class="ml-3 px-2 py-1 bg-green-100 text-green-800 text-xs font-medium rounded-full"
|
||||||
@@ -182,7 +271,6 @@
|
|||||||
</span>
|
</span>
|
||||||
<button
|
<button
|
||||||
v-if="canEdit"
|
v-if="canEdit"
|
||||||
@click="toggleMannschaftsspieler(member)"
|
|
||||||
:class="[
|
:class="[
|
||||||
'ml-2 px-2 py-1 text-xs font-medium rounded-full transition-colors',
|
'ml-2 px-2 py-1 text-xs font-medium rounded-full transition-colors',
|
||||||
member.isMannschaftsspieler
|
member.isMannschaftsspieler
|
||||||
@@ -190,6 +278,7 @@
|
|||||||
: 'bg-gray-100 text-gray-600 hover:bg-gray-200'
|
: 'bg-gray-100 text-gray-600 hover:bg-gray-200'
|
||||||
]"
|
]"
|
||||||
title="Klicken zum Umschalten"
|
title="Klicken zum Umschalten"
|
||||||
|
@click="toggleMannschaftsspieler(member)"
|
||||||
>
|
>
|
||||||
Mannschaftsspieler: {{ member.isMannschaftsspieler ? 'Ja' : 'Nein' }}
|
Mannschaftsspieler: {{ member.isMannschaftsspieler ? 'Ja' : 'Nein' }}
|
||||||
</button>
|
</button>
|
||||||
@@ -208,46 +297,91 @@
|
|||||||
|
|
||||||
<div class="grid sm:grid-cols-2 gap-3 text-gray-600">
|
<div class="grid sm:grid-cols-2 gap-3 text-gray-600">
|
||||||
<template v-if="canViewContactData">
|
<template v-if="canViewContactData">
|
||||||
<div v-if="member.email" class="flex items-center">
|
<div
|
||||||
<Mail :size="16" class="mr-2 text-primary-600" />
|
v-if="member.email"
|
||||||
<a :href="`mailto:${member.email}`" class="hover:text-primary-600">{{ member.email }}</a>
|
class="flex items-center"
|
||||||
|
>
|
||||||
|
<Mail
|
||||||
|
:size="16"
|
||||||
|
class="mr-2 text-primary-600"
|
||||||
|
/>
|
||||||
|
<a
|
||||||
|
:href="`mailto:${member.email}`"
|
||||||
|
class="hover:text-primary-600"
|
||||||
|
>{{ member.email }}</a>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="member.phone" class="flex items-center">
|
<div
|
||||||
<Phone :size="16" class="mr-2 text-primary-600" />
|
v-if="member.phone"
|
||||||
<a :href="`tel:${member.phone}`" class="hover:text-primary-600">{{ member.phone }}</a>
|
class="flex items-center"
|
||||||
|
>
|
||||||
|
<Phone
|
||||||
|
:size="16"
|
||||||
|
class="mr-2 text-primary-600"
|
||||||
|
/>
|
||||||
|
<a
|
||||||
|
:href="`tel:${member.phone}`"
|
||||||
|
class="hover:text-primary-600"
|
||||||
|
>{{ member.phone }}</a>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div v-else class="col-span-2 flex items-center text-gray-500 text-sm italic">
|
<div
|
||||||
<Mail :size="16" class="mr-2" />
|
v-else
|
||||||
|
class="col-span-2 flex items-center text-gray-500 text-sm italic"
|
||||||
|
>
|
||||||
|
<Mail
|
||||||
|
:size="16"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
Kontaktdaten nur für Vorstand sichtbar
|
Kontaktdaten nur für Vorstand sichtbar
|
||||||
</div>
|
</div>
|
||||||
<div v-if="member.address" class="flex items-start col-span-2">
|
<div
|
||||||
<MapPin :size="16" class="mr-2 text-primary-600 mt-0.5" />
|
v-if="member.address"
|
||||||
|
class="flex items-start col-span-2"
|
||||||
|
>
|
||||||
|
<MapPin
|
||||||
|
:size="16"
|
||||||
|
class="mr-2 text-primary-600 mt-0.5"
|
||||||
|
/>
|
||||||
<span>{{ member.address }}</span>
|
<span>{{ member.address }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="member.notes" class="flex items-start col-span-2">
|
<div
|
||||||
<FileText :size="16" class="mr-2 text-primary-600 mt-0.5" />
|
v-if="member.notes"
|
||||||
|
class="flex items-start col-span-2"
|
||||||
|
>
|
||||||
|
<FileText
|
||||||
|
:size="16"
|
||||||
|
class="mr-2 text-primary-600 mt-0.5"
|
||||||
|
/>
|
||||||
<span>{{ member.notes }}</span>
|
<span>{{ member.notes }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="member.lastLogin" class="flex items-center col-span-2 text-sm text-gray-500">
|
<div
|
||||||
<Clock :size="16" class="mr-2" />
|
v-if="member.lastLogin"
|
||||||
|
class="flex items-center col-span-2 text-sm text-gray-500"
|
||||||
|
>
|
||||||
|
<Clock
|
||||||
|
:size="16"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
Letzter Login: {{ formatDate(member.lastLogin) }}
|
Letzter Login: {{ formatDate(member.lastLogin) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="canEdit && member.editable" class="flex space-x-2 ml-4">
|
<div
|
||||||
|
v-if="canEdit && member.editable"
|
||||||
|
class="flex space-x-2 ml-4"
|
||||||
|
>
|
||||||
<button
|
<button
|
||||||
@click="openEditModal(member)"
|
|
||||||
class="p-2 text-blue-600 hover:bg-blue-50 rounded-lg transition-colors"
|
class="p-2 text-blue-600 hover:bg-blue-50 rounded-lg transition-colors"
|
||||||
title="Bearbeiten"
|
title="Bearbeiten"
|
||||||
|
@click="openEditModal(member)"
|
||||||
>
|
>
|
||||||
<Edit :size="20" />
|
<Edit :size="20" />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@click="confirmDelete(member)"
|
|
||||||
class="p-2 text-red-600 hover:bg-red-50 rounded-lg transition-colors"
|
class="p-2 text-red-600 hover:bg-red-50 rounded-lg transition-colors"
|
||||||
title="Löschen"
|
title="Löschen"
|
||||||
|
@click="confirmDelete(member)"
|
||||||
>
|
>
|
||||||
<Trash2 :size="20" />
|
<Trash2 :size="20" />
|
||||||
</button>
|
</button>
|
||||||
@@ -255,7 +389,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="members.length === 0" class="text-center py-12 text-gray-500">
|
<div
|
||||||
|
v-if="members.length === 0"
|
||||||
|
class="text-center py-12 text-gray-500"
|
||||||
|
>
|
||||||
Keine Mitglieder gefunden.
|
Keine Mitglieder gefunden.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -271,7 +408,10 @@
|
|||||||
{{ editingMember ? 'Mitglied bearbeiten' : 'Mitglied hinzufügen' }}
|
{{ editingMember ? 'Mitglied bearbeiten' : 'Mitglied hinzufügen' }}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<form @submit.prevent="saveMember" class="space-y-4">
|
<form
|
||||||
|
class="space-y-4"
|
||||||
|
@submit.prevent="saveMember"
|
||||||
|
>
|
||||||
<div class="grid grid-cols-2 gap-4">
|
<div class="grid grid-cols-2 gap-4">
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Vorname *</label>
|
<label class="block text-sm font-medium text-gray-700 mb-2">Vorname *</label>
|
||||||
@@ -281,7 +421,7 @@
|
|||||||
required
|
required
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||||
:disabled="isSaving"
|
:disabled="isSaving"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Nachname *</label>
|
<label class="block text-sm font-medium text-gray-700 mb-2">Nachname *</label>
|
||||||
@@ -291,7 +431,7 @@
|
|||||||
required
|
required
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||||
:disabled="isSaving"
|
:disabled="isSaving"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -303,8 +443,10 @@
|
|||||||
required
|
required
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||||
:disabled="isSaving"
|
:disabled="isSaving"
|
||||||
/>
|
>
|
||||||
<p class="text-xs text-gray-500 mt-1">Wird zur eindeutigen Identifizierung benötigt</p>
|
<p class="text-xs text-gray-500 mt-1">
|
||||||
|
Wird zur eindeutigen Identifizierung benötigt
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@@ -314,7 +456,7 @@
|
|||||||
type="email"
|
type="email"
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||||
:disabled="isSaving"
|
:disabled="isSaving"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@@ -324,7 +466,7 @@
|
|||||||
type="tel"
|
type="tel"
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||||
:disabled="isSaving"
|
:disabled="isSaving"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@@ -334,7 +476,7 @@
|
|||||||
type="text"
|
type="text"
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||||
:disabled="isSaving"
|
:disabled="isSaving"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@@ -349,28 +491,37 @@
|
|||||||
|
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<input
|
<input
|
||||||
|
id="isMannschaftsspieler"
|
||||||
v-model="formData.isMannschaftsspieler"
|
v-model="formData.isMannschaftsspieler"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
id="isMannschaftsspieler"
|
|
||||||
class="h-4 w-4 text-primary-600 focus:ring-primary-500 border-gray-300 rounded"
|
class="h-4 w-4 text-primary-600 focus:ring-primary-500 border-gray-300 rounded"
|
||||||
:disabled="isSaving"
|
:disabled="isSaving"
|
||||||
/>
|
>
|
||||||
<label for="isMannschaftsspieler" class="ml-2 block text-sm font-medium text-gray-700">
|
<label
|
||||||
|
for="isMannschaftsspieler"
|
||||||
|
class="ml-2 block text-sm font-medium text-gray-700"
|
||||||
|
>
|
||||||
Mannschaftsspieler
|
Mannschaftsspieler
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="errorMessage" class="flex items-center p-3 rounded-md bg-red-50 text-red-700 text-sm">
|
<div
|
||||||
<AlertCircle :size="20" class="mr-2" />
|
v-if="errorMessage"
|
||||||
|
class="flex items-center p-3 rounded-md bg-red-50 text-red-700 text-sm"
|
||||||
|
>
|
||||||
|
<AlertCircle
|
||||||
|
:size="20"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
{{ errorMessage }}
|
{{ errorMessage }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-end space-x-4 pt-4">
|
<div class="flex justify-end space-x-4 pt-4">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@click="closeModal"
|
|
||||||
class="px-6 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
|
class="px-6 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
|
||||||
:disabled="isSaving"
|
:disabled="isSaving"
|
||||||
|
@click="closeModal"
|
||||||
>
|
>
|
||||||
Abbrechen
|
Abbrechen
|
||||||
</button>
|
</button>
|
||||||
@@ -379,7 +530,11 @@
|
|||||||
class="px-6 py-2 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors flex items-center"
|
class="px-6 py-2 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors flex items-center"
|
||||||
:disabled="isSaving"
|
:disabled="isSaving"
|
||||||
>
|
>
|
||||||
<Loader2 v-if="isSaving" :size="20" class="animate-spin mr-2" />
|
<Loader2
|
||||||
|
v-if="isSaving"
|
||||||
|
:size="20"
|
||||||
|
class="animate-spin mr-2"
|
||||||
|
/>
|
||||||
<span>{{ isSaving ? 'Speichert...' : 'Speichern' }}</span>
|
<span>{{ isSaving ? 'Speichert...' : 'Speichern' }}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -402,33 +557,54 @@
|
|||||||
<div class="mb-6">
|
<div class="mb-6">
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">CSV-Datei hochladen</label>
|
<label class="block text-sm font-medium text-gray-700 mb-2">CSV-Datei hochladen</label>
|
||||||
<div
|
<div
|
||||||
|
class="border-2 border-dashed border-gray-300 rounded-lg p-8 text-center hover:border-primary-400 hover:bg-primary-50 transition-colors cursor-pointer"
|
||||||
|
:class="{ 'border-primary-400 bg-primary-50': isDragOver }"
|
||||||
@click="triggerBulkFileInput"
|
@click="triggerBulkFileInput"
|
||||||
@dragover.prevent
|
@dragover.prevent
|
||||||
@dragenter.prevent="isDragOver = true"
|
@dragenter.prevent="isDragOver = true"
|
||||||
@dragleave.prevent="isDragOver = false"
|
@dragleave.prevent="isDragOver = false"
|
||||||
@drop.prevent="handleBulkFileDrop"
|
@drop.prevent="handleBulkFileDrop"
|
||||||
class="border-2 border-dashed border-gray-300 rounded-lg p-8 text-center hover:border-primary-400 hover:bg-primary-50 transition-colors cursor-pointer"
|
|
||||||
:class="{ 'border-primary-400 bg-primary-50': isDragOver }"
|
|
||||||
>
|
>
|
||||||
<svg class="w-12 h-12 text-gray-400 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"></path>
|
class="w-12 h-12 text-gray-400 mx-auto mb-4"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<p class="text-lg font-medium text-gray-900 mb-2">CSV-Datei hochladen</p>
|
<p class="text-lg font-medium text-gray-900 mb-2">
|
||||||
<p class="text-sm text-gray-600 mb-4">Klicken Sie hier oder ziehen Sie eine CSV-Datei hierher</p>
|
CSV-Datei hochladen
|
||||||
<p v-if="bulkSelectedFile" class="text-sm text-primary-600 font-medium">{{ bulkSelectedFile.name }}</p>
|
</p>
|
||||||
|
<p class="text-sm text-gray-600 mb-4">
|
||||||
|
Klicken Sie hier oder ziehen Sie eine CSV-Datei hierher
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
v-if="bulkSelectedFile"
|
||||||
|
class="text-sm text-primary-600 font-medium"
|
||||||
|
>
|
||||||
|
{{ bulkSelectedFile.name }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
ref="bulkFileInput"
|
ref="bulkFileInput"
|
||||||
type="file"
|
type="file"
|
||||||
accept=".csv"
|
accept=".csv"
|
||||||
@change="handleBulkFileSelect"
|
|
||||||
class="hidden"
|
class="hidden"
|
||||||
/>
|
@change="handleBulkFileSelect"
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- CSV Format Info -->
|
<!-- CSV Format Info -->
|
||||||
<div class="bg-blue-50 border-l-4 border-blue-500 p-4 rounded-lg mb-6">
|
<div class="bg-blue-50 border-l-4 border-blue-500 p-4 rounded-lg mb-6">
|
||||||
<h4 class="text-sm font-medium text-blue-800 mb-2">Erwartetes CSV-Format:</h4>
|
<h4 class="text-sm font-medium text-blue-800 mb-2">
|
||||||
|
Erwartetes CSV-Format:
|
||||||
|
</h4>
|
||||||
<div class="text-xs text-blue-700 space-y-1">
|
<div class="text-xs text-blue-700 space-y-1">
|
||||||
<p>• Erste Zeile: Spaltenüberschriften (firstName, lastName, geburtsdatum, email, phone, address, notes)</p>
|
<p>• Erste Zeile: Spaltenüberschriften (firstName, lastName, geburtsdatum, email, phone, address, notes)</p>
|
||||||
<p>• <strong>Pflichtfelder:</strong> firstName, lastName, geburtsdatum</p>
|
<p>• <strong>Pflichtfelder:</strong> firstName, lastName, geburtsdatum</p>
|
||||||
@@ -438,65 +614,126 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Preview Section -->
|
<!-- Preview Section -->
|
||||||
<div v-if="bulkPreviewData.length > 0" class="mb-6">
|
<div
|
||||||
<h3 class="text-lg font-semibold text-gray-900 mb-4">Vorschau ({{ bulkPreviewData.length }} Einträge)</h3>
|
v-if="bulkPreviewData.length > 0"
|
||||||
|
class="mb-6"
|
||||||
|
>
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900 mb-4">
|
||||||
|
Vorschau ({{ bulkPreviewData.length }} Einträge)
|
||||||
|
</h3>
|
||||||
<div class="max-h-64 overflow-y-auto border border-gray-200 rounded-lg">
|
<div class="max-h-64 overflow-y-auto border border-gray-200 rounded-lg">
|
||||||
<table class="min-w-full divide-y divide-gray-200 text-sm">
|
<table class="min-w-full divide-y divide-gray-200 text-sm">
|
||||||
<thead class="bg-gray-50 sticky top-0">
|
<thead class="bg-gray-50 sticky top-0">
|
||||||
<tr>
|
<tr>
|
||||||
<th class="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase">Vorname</th>
|
<th class="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase">
|
||||||
<th class="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase">Nachname</th>
|
Vorname
|
||||||
<th class="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase">Geburtsdatum</th>
|
</th>
|
||||||
<th class="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase">E-Mail</th>
|
<th class="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase">
|
||||||
|
Nachname
|
||||||
|
</th>
|
||||||
|
<th class="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase">
|
||||||
|
Geburtsdatum
|
||||||
|
</th>
|
||||||
|
<th class="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase">
|
||||||
|
E-Mail
|
||||||
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="bg-white divide-y divide-gray-200">
|
<tbody class="bg-white divide-y divide-gray-200">
|
||||||
<tr v-for="(row, index) in bulkPreviewData.slice(0, 10)" :key="index" class="hover:bg-gray-50">
|
<tr
|
||||||
<td class="px-3 py-2">{{ row.firstName || '-' }}</td>
|
v-for="(row, index) in bulkPreviewData.slice(0, 10)"
|
||||||
<td class="px-3 py-2">{{ row.lastName || '-' }}</td>
|
:key="index"
|
||||||
<td class="px-3 py-2">{{ row.geburtsdatum || '-' }}</td>
|
class="hover:bg-gray-50"
|
||||||
<td class="px-3 py-2">{{ row.email || '-' }}</td>
|
>
|
||||||
|
<td class="px-3 py-2">
|
||||||
|
{{ row.firstName || '-' }}
|
||||||
|
</td>
|
||||||
|
<td class="px-3 py-2">
|
||||||
|
{{ row.lastName || '-' }}
|
||||||
|
</td>
|
||||||
|
<td class="px-3 py-2">
|
||||||
|
{{ row.geburtsdatum || '-' }}
|
||||||
|
</td>
|
||||||
|
<td class="px-3 py-2">
|
||||||
|
{{ row.email || '-' }}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<div v-if="bulkPreviewData.length > 10" class="px-3 py-2 text-xs text-gray-500 bg-gray-50 text-center">
|
<div
|
||||||
|
v-if="bulkPreviewData.length > 10"
|
||||||
|
class="px-3 py-2 text-xs text-gray-500 bg-gray-50 text-center"
|
||||||
|
>
|
||||||
... und {{ bulkPreviewData.length - 10 }} weitere
|
... und {{ bulkPreviewData.length - 10 }} weitere
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Import Results -->
|
<!-- Import Results -->
|
||||||
<div v-if="bulkImportResults" class="mb-6">
|
<div
|
||||||
|
v-if="bulkImportResults"
|
||||||
|
class="mb-6"
|
||||||
|
>
|
||||||
<div class="bg-gray-50 rounded-lg p-4">
|
<div class="bg-gray-50 rounded-lg p-4">
|
||||||
<h3 class="text-lg font-semibold text-gray-900 mb-3">Import-Ergebnisse</h3>
|
<h3 class="text-lg font-semibold text-gray-900 mb-3">
|
||||||
|
Import-Ergebnisse
|
||||||
|
</h3>
|
||||||
<div class="grid grid-cols-3 gap-4 mb-4">
|
<div class="grid grid-cols-3 gap-4 mb-4">
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<div class="text-2xl font-bold text-green-600">{{ bulkImportResults.summary.imported }}</div>
|
<div class="text-2xl font-bold text-green-600">
|
||||||
<div class="text-sm text-gray-600">Importiert</div>
|
{{ bulkImportResults.summary.imported }}
|
||||||
|
</div>
|
||||||
|
<div class="text-sm text-gray-600">
|
||||||
|
Importiert
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<div class="text-2xl font-bold text-yellow-600">{{ bulkImportResults.summary.duplicates }}</div>
|
<div class="text-2xl font-bold text-yellow-600">
|
||||||
<div class="text-sm text-gray-600">Duplikate</div>
|
{{ bulkImportResults.summary.duplicates }}
|
||||||
|
</div>
|
||||||
|
<div class="text-sm text-gray-600">
|
||||||
|
Duplikate
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<div class="text-2xl font-bold text-red-600">{{ bulkImportResults.summary.errors }}</div>
|
<div class="text-2xl font-bold text-red-600">
|
||||||
<div class="text-sm text-gray-600">Fehler</div>
|
{{ bulkImportResults.summary.errors }}
|
||||||
|
</div>
|
||||||
|
<div class="text-sm text-gray-600">
|
||||||
|
Fehler
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="bulkImportResults.results.duplicates.length > 0" class="mt-4">
|
<div
|
||||||
<h4 class="text-sm font-medium text-gray-700 mb-2">Duplikate:</h4>
|
v-if="bulkImportResults.results.duplicates.length > 0"
|
||||||
|
class="mt-4"
|
||||||
|
>
|
||||||
|
<h4 class="text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Duplikate:
|
||||||
|
</h4>
|
||||||
<div class="text-xs text-gray-600 space-y-1 max-h-32 overflow-y-auto">
|
<div class="text-xs text-gray-600 space-y-1 max-h-32 overflow-y-auto">
|
||||||
<div v-for="dup in bulkImportResults.results.duplicates" :key="dup.index">
|
<div
|
||||||
|
v-for="dup in bulkImportResults.results.duplicates"
|
||||||
|
:key="dup.index"
|
||||||
|
>
|
||||||
Zeile {{ dup.index }}: {{ dup.member.firstName }} {{ dup.member.lastName }} - {{ dup.reason }}
|
Zeile {{ dup.index }}: {{ dup.member.firstName }} {{ dup.member.lastName }} - {{ dup.reason }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="bulkImportResults.results.errors.length > 0" class="mt-4">
|
<div
|
||||||
<h4 class="text-sm font-medium text-gray-700 mb-2">Fehler:</h4>
|
v-if="bulkImportResults.results.errors.length > 0"
|
||||||
|
class="mt-4"
|
||||||
|
>
|
||||||
|
<h4 class="text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Fehler:
|
||||||
|
</h4>
|
||||||
<div class="text-xs text-red-600 space-y-1 max-h-32 overflow-y-auto">
|
<div class="text-xs text-red-600 space-y-1 max-h-32 overflow-y-auto">
|
||||||
<div v-for="err in bulkImportResults.results.errors" :key="err.index">
|
<div
|
||||||
|
v-for="err in bulkImportResults.results.errors"
|
||||||
|
:key="err.index"
|
||||||
|
>
|
||||||
Zeile {{ err.index }}: {{ err.error }}
|
Zeile {{ err.index }}: {{ err.error }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -507,18 +744,22 @@
|
|||||||
<div class="flex justify-end space-x-4 pt-4">
|
<div class="flex justify-end space-x-4 pt-4">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@click="closeBulkImportModal"
|
|
||||||
class="px-6 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
|
class="px-6 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
|
||||||
:disabled="isBulkImporting"
|
:disabled="isBulkImporting"
|
||||||
|
@click="closeBulkImportModal"
|
||||||
>
|
>
|
||||||
Schließen
|
Schließen
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@click="processBulkImport"
|
|
||||||
:disabled="!bulkPreviewData.length || isBulkImporting"
|
:disabled="!bulkPreviewData.length || isBulkImporting"
|
||||||
class="px-6 py-2 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors flex items-center disabled:bg-gray-400"
|
class="px-6 py-2 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors flex items-center disabled:bg-gray-400"
|
||||||
|
@click="processBulkImport"
|
||||||
>
|
>
|
||||||
<Loader2 v-if="isBulkImporting" :size="20" class="animate-spin mr-2" />
|
<Loader2
|
||||||
|
v-if="isBulkImporting"
|
||||||
|
:size="20"
|
||||||
|
class="animate-spin mr-2"
|
||||||
|
/>
|
||||||
<span>{{ isBulkImporting ? 'Importiert...' : 'Importieren' }}</span>
|
<span>{{ isBulkImporting ? 'Importiert...' : 'Importieren' }}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -10,21 +10,33 @@
|
|||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
v-if="canWrite"
|
v-if="canWrite"
|
||||||
@click="openAddModal"
|
|
||||||
class="flex items-center px-4 py-2 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors"
|
class="flex items-center px-4 py-2 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors"
|
||||||
|
@click="openAddModal"
|
||||||
>
|
>
|
||||||
<Plus :size="20" class="mr-2" />
|
<Plus
|
||||||
|
:size="20"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
News erstellen
|
News erstellen
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Loading State -->
|
<!-- Loading State -->
|
||||||
<div v-if="isLoading" class="flex items-center justify-center py-12">
|
<div
|
||||||
<Loader2 :size="40" class="animate-spin text-primary-600" />
|
v-if="isLoading"
|
||||||
|
class="flex items-center justify-center py-12"
|
||||||
|
>
|
||||||
|
<Loader2
|
||||||
|
:size="40"
|
||||||
|
class="animate-spin text-primary-600"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- News List -->
|
<!-- News List -->
|
||||||
<div v-else class="space-y-6">
|
<div
|
||||||
|
v-else
|
||||||
|
class="space-y-6"
|
||||||
|
>
|
||||||
<article
|
<article
|
||||||
v-for="item in news"
|
v-for="item in news"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
@@ -40,52 +52,76 @@
|
|||||||
v-if="item.isPublic"
|
v-if="item.isPublic"
|
||||||
class="px-3 py-1 bg-blue-100 text-blue-800 text-xs font-semibold rounded-full flex items-center"
|
class="px-3 py-1 bg-blue-100 text-blue-800 text-xs font-semibold rounded-full flex items-center"
|
||||||
>
|
>
|
||||||
<Globe :size="14" class="mr-1" />
|
<Globe
|
||||||
|
:size="14"
|
||||||
|
class="mr-1"
|
||||||
|
/>
|
||||||
Öffentlich
|
Öffentlich
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
v-if="item.isHidden"
|
v-if="item.isHidden"
|
||||||
class="px-3 py-1 bg-yellow-100 text-yellow-800 text-xs font-semibold rounded-full flex items-center"
|
class="px-3 py-1 bg-yellow-100 text-yellow-800 text-xs font-semibold rounded-full flex items-center"
|
||||||
>
|
>
|
||||||
<EyeOff :size="14" class="mr-1" />
|
<EyeOff
|
||||||
|
:size="14"
|
||||||
|
class="mr-1"
|
||||||
|
/>
|
||||||
Ausgeblendet
|
Ausgeblendet
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
v-if="item.expiresAt && isExpired(item.expiresAt)"
|
v-if="item.expiresAt && isExpired(item.expiresAt)"
|
||||||
class="px-3 py-1 bg-red-100 text-red-800 text-xs font-semibold rounded-full flex items-center"
|
class="px-3 py-1 bg-red-100 text-red-800 text-xs font-semibold rounded-full flex items-center"
|
||||||
>
|
>
|
||||||
<Calendar :size="14" class="mr-1" />
|
<Calendar
|
||||||
|
:size="14"
|
||||||
|
class="mr-1"
|
||||||
|
/>
|
||||||
Abgelaufen
|
Abgelaufen
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center text-sm text-gray-500 space-x-4">
|
<div class="flex items-center text-sm text-gray-500 space-x-4">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<User :size="16" class="mr-1" />
|
<User
|
||||||
|
:size="16"
|
||||||
|
class="mr-1"
|
||||||
|
/>
|
||||||
{{ item.author }}
|
{{ item.author }}
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<Calendar :size="16" class="mr-1" />
|
<Calendar
|
||||||
|
:size="16"
|
||||||
|
class="mr-1"
|
||||||
|
/>
|
||||||
{{ formatDate(item.created) }}
|
{{ formatDate(item.created) }}
|
||||||
</div>
|
</div>
|
||||||
<div v-if="item.updated !== item.created" class="flex items-center">
|
<div
|
||||||
<Edit :size="16" class="mr-1" />
|
v-if="item.updated !== item.created"
|
||||||
|
class="flex items-center"
|
||||||
|
>
|
||||||
|
<Edit
|
||||||
|
:size="16"
|
||||||
|
class="mr-1"
|
||||||
|
/>
|
||||||
Aktualisiert: {{ formatDate(item.updated) }}
|
Aktualisiert: {{ formatDate(item.updated) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="canWrite" class="flex space-x-2 ml-4">
|
<div
|
||||||
|
v-if="canWrite"
|
||||||
|
class="flex space-x-2 ml-4"
|
||||||
|
>
|
||||||
<button
|
<button
|
||||||
@click="openEditModal(item)"
|
|
||||||
class="p-2 text-blue-600 hover:bg-blue-50 rounded-lg transition-colors"
|
class="p-2 text-blue-600 hover:bg-blue-50 rounded-lg transition-colors"
|
||||||
title="Bearbeiten"
|
title="Bearbeiten"
|
||||||
|
@click="openEditModal(item)"
|
||||||
>
|
>
|
||||||
<Edit :size="20" />
|
<Edit :size="20" />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@click="confirmDelete(item)"
|
|
||||||
class="p-2 text-red-600 hover:bg-red-50 rounded-lg transition-colors"
|
class="p-2 text-red-600 hover:bg-red-50 rounded-lg transition-colors"
|
||||||
title="Löschen"
|
title="Löschen"
|
||||||
|
@click="confirmDelete(item)"
|
||||||
>
|
>
|
||||||
<Trash2 :size="20" />
|
<Trash2 :size="20" />
|
||||||
</button>
|
</button>
|
||||||
@@ -97,10 +133,21 @@
|
|||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
<div v-if="news.length === 0" class="text-center py-12">
|
<div
|
||||||
<Newspaper :size="48" class="mx-auto text-gray-400 mb-4" />
|
v-if="news.length === 0"
|
||||||
<p class="text-gray-500 text-lg">Noch keine News vorhanden.</p>
|
class="text-center py-12"
|
||||||
<p v-if="canWrite" class="text-gray-400 text-sm mt-2">
|
>
|
||||||
|
<Newspaper
|
||||||
|
:size="48"
|
||||||
|
class="mx-auto text-gray-400 mb-4"
|
||||||
|
/>
|
||||||
|
<p class="text-gray-500 text-lg">
|
||||||
|
Noch keine News vorhanden.
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
v-if="canWrite"
|
||||||
|
class="text-gray-400 text-sm mt-2"
|
||||||
|
>
|
||||||
Klicken Sie auf "News erstellen", um die erste News zu veröffentlichen.
|
Klicken Sie auf "News erstellen", um die erste News zu veröffentlichen.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -117,7 +164,10 @@
|
|||||||
{{ editingNews ? 'News bearbeiten' : 'News erstellen' }}
|
{{ editingNews ? 'News bearbeiten' : 'News erstellen' }}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<form @submit.prevent="saveNews" class="space-y-4">
|
<form
|
||||||
|
class="space-y-4"
|
||||||
|
@submit.prevent="saveNews"
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Titel *</label>
|
<label class="block text-sm font-medium text-gray-700 mb-2">Titel *</label>
|
||||||
<input
|
<input
|
||||||
@@ -126,7 +176,7 @@
|
|||||||
required
|
required
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||||
:disabled="isSaving"
|
:disabled="isSaving"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@@ -147,10 +197,16 @@
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
class="w-5 h-5 text-primary-600 border-gray-300 rounded focus:ring-primary-500"
|
class="w-5 h-5 text-primary-600 border-gray-300 rounded focus:ring-primary-500"
|
||||||
:disabled="isSaving"
|
:disabled="isSaving"
|
||||||
/>
|
>
|
||||||
<label for="isPublic" class="text-sm font-medium text-gray-900 cursor-pointer flex-1">
|
<label
|
||||||
|
for="isPublic"
|
||||||
|
class="text-sm font-medium text-gray-900 cursor-pointer flex-1"
|
||||||
|
>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<Globe :size="18" class="mr-2 text-blue-600" />
|
<Globe
|
||||||
|
:size="18"
|
||||||
|
class="mr-2 text-blue-600"
|
||||||
|
/>
|
||||||
<span>Öffentliche News (auf Startseite anzeigen)</span>
|
<span>Öffentliche News (auf Startseite anzeigen)</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-xs text-gray-600 mt-1 ml-6">
|
<p class="text-xs text-gray-600 mt-1 ml-6">
|
||||||
@@ -159,7 +215,10 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="formData.isPublic" class="space-y-4">
|
<div
|
||||||
|
v-if="formData.isPublic"
|
||||||
|
class="space-y-4"
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">Ablaufdatum (optional)</label>
|
<label class="block text-sm font-medium text-gray-700 mb-2">Ablaufdatum (optional)</label>
|
||||||
<input
|
<input
|
||||||
@@ -167,7 +226,7 @@
|
|||||||
type="datetime-local"
|
type="datetime-local"
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||||
:disabled="isSaving"
|
:disabled="isSaving"
|
||||||
/>
|
>
|
||||||
<p class="text-xs text-gray-600 mt-1">
|
<p class="text-xs text-gray-600 mt-1">
|
||||||
Nach diesem Datum wird die News automatisch nicht mehr auf der Startseite angezeigt.
|
Nach diesem Datum wird die News automatisch nicht mehr auf der Startseite angezeigt.
|
||||||
</p>
|
</p>
|
||||||
@@ -180,10 +239,16 @@
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
class="w-5 h-5 text-primary-600 border-gray-300 rounded focus:ring-primary-500"
|
class="w-5 h-5 text-primary-600 border-gray-300 rounded focus:ring-primary-500"
|
||||||
:disabled="isSaving"
|
:disabled="isSaving"
|
||||||
/>
|
>
|
||||||
<label for="isHidden" class="text-sm font-medium text-gray-900 cursor-pointer flex-1">
|
<label
|
||||||
|
for="isHidden"
|
||||||
|
class="text-sm font-medium text-gray-900 cursor-pointer flex-1"
|
||||||
|
>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<EyeOff :size="18" class="mr-2 text-yellow-600" />
|
<EyeOff
|
||||||
|
:size="18"
|
||||||
|
class="mr-2 text-yellow-600"
|
||||||
|
/>
|
||||||
<span>News ausblenden</span>
|
<span>News ausblenden</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-xs text-gray-600 mt-1 ml-6">
|
<p class="text-xs text-gray-600 mt-1 ml-6">
|
||||||
@@ -193,17 +258,23 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="errorMessage" class="flex items-center p-3 rounded-md bg-red-50 text-red-700 text-sm">
|
<div
|
||||||
<AlertCircle :size="20" class="mr-2" />
|
v-if="errorMessage"
|
||||||
|
class="flex items-center p-3 rounded-md bg-red-50 text-red-700 text-sm"
|
||||||
|
>
|
||||||
|
<AlertCircle
|
||||||
|
:size="20"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
{{ errorMessage }}
|
{{ errorMessage }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-end space-x-4 pt-4">
|
<div class="flex justify-end space-x-4 pt-4">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@click="closeModal"
|
|
||||||
class="px-6 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
|
class="px-6 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
|
||||||
:disabled="isSaving"
|
:disabled="isSaving"
|
||||||
|
@click="closeModal"
|
||||||
>
|
>
|
||||||
Abbrechen
|
Abbrechen
|
||||||
</button>
|
</button>
|
||||||
@@ -212,7 +283,11 @@
|
|||||||
class="px-6 py-2 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors flex items-center"
|
class="px-6 py-2 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors flex items-center"
|
||||||
:disabled="isSaving"
|
:disabled="isSaving"
|
||||||
>
|
>
|
||||||
<Loader2 v-if="isSaving" :size="20" class="animate-spin mr-2" />
|
<Loader2
|
||||||
|
v-if="isSaving"
|
||||||
|
:size="20"
|
||||||
|
class="animate-spin mr-2"
|
||||||
|
/>
|
||||||
<span>{{ isSaving ? 'Speichert...' : 'Speichern' }}</span>
|
<span>{{ isSaving ? 'Speichert...' : 'Speichern' }}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,15 +8,28 @@
|
|||||||
|
|
||||||
<div class="bg-white rounded-xl shadow-lg p-8 border border-gray-100">
|
<div class="bg-white rounded-xl shadow-lg p-8 border border-gray-100">
|
||||||
<!-- Loading State -->
|
<!-- Loading State -->
|
||||||
<div v-if="isLoading" class="flex items-center justify-center py-12">
|
<div
|
||||||
<Loader2 :size="40" class="animate-spin text-primary-600" />
|
v-if="isLoading"
|
||||||
|
class="flex items-center justify-center py-12"
|
||||||
|
>
|
||||||
|
<Loader2
|
||||||
|
:size="40"
|
||||||
|
class="animate-spin text-primary-600"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Profile Form -->
|
<!-- Profile Form -->
|
||||||
<form v-else @submit.prevent="handleSave" class="space-y-6">
|
<form
|
||||||
|
v-else
|
||||||
|
class="space-y-6"
|
||||||
|
@submit.prevent="handleSave"
|
||||||
|
>
|
||||||
<!-- Name -->
|
<!-- Name -->
|
||||||
<div>
|
<div>
|
||||||
<label for="name" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="name"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
Name
|
Name
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -26,12 +39,15 @@
|
|||||||
required
|
required
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
:disabled="isSaving"
|
:disabled="isSaving"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- E-Mail -->
|
<!-- E-Mail -->
|
||||||
<div>
|
<div>
|
||||||
<label for="email" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="email"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
E-Mail-Adresse
|
E-Mail-Adresse
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -41,12 +57,15 @@
|
|||||||
required
|
required
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
:disabled="isSaving"
|
:disabled="isSaving"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Telefon -->
|
<!-- Telefon -->
|
||||||
<div>
|
<div>
|
||||||
<label for="phone" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="phone"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
Telefonnummer
|
Telefonnummer
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -55,16 +74,21 @@
|
|||||||
type="tel"
|
type="tel"
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
:disabled="isSaving"
|
:disabled="isSaving"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Passwort ändern -->
|
<!-- Passwort ändern -->
|
||||||
<div class="border-t border-gray-200 pt-6 mt-6">
|
<div class="border-t border-gray-200 pt-6 mt-6">
|
||||||
<h3 class="text-lg font-semibold text-gray-900 mb-4">Passwort ändern</h3>
|
<h3 class="text-lg font-semibold text-gray-900 mb-4">
|
||||||
|
Passwort ändern
|
||||||
|
</h3>
|
||||||
|
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<div>
|
<div>
|
||||||
<label for="currentPassword" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="currentPassword"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
Aktuelles Passwort
|
Aktuelles Passwort
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -73,11 +97,14 @@
|
|||||||
type="password"
|
type="password"
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
:disabled="isSaving"
|
:disabled="isSaving"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for="newPassword" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="newPassword"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
Neues Passwort
|
Neues Passwort
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -86,11 +113,14 @@
|
|||||||
type="password"
|
type="password"
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
:disabled="isSaving"
|
:disabled="isSaving"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for="confirmPassword" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="confirmPassword"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
Passwort bestätigen
|
Passwort bestätigen
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -99,19 +129,31 @@
|
|||||||
type="password"
|
type="password"
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
:disabled="isSaving"
|
:disabled="isSaving"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Error/Success Messages -->
|
<!-- Error/Success Messages -->
|
||||||
<div v-if="errorMessage" class="flex items-center p-3 rounded-md bg-red-50 text-red-700 text-sm">
|
<div
|
||||||
<AlertCircle :size="20" class="mr-2" />
|
v-if="errorMessage"
|
||||||
|
class="flex items-center p-3 rounded-md bg-red-50 text-red-700 text-sm"
|
||||||
|
>
|
||||||
|
<AlertCircle
|
||||||
|
:size="20"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
{{ errorMessage }}
|
{{ errorMessage }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="successMessage" class="flex items-center p-3 rounded-md bg-green-50 text-green-700 text-sm">
|
<div
|
||||||
<Check :size="20" class="mr-2" />
|
v-if="successMessage"
|
||||||
|
class="flex items-center p-3 rounded-md bg-green-50 text-green-700 text-sm"
|
||||||
|
>
|
||||||
|
<Check
|
||||||
|
:size="20"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
{{ successMessage }}
|
{{ successMessage }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -119,9 +161,9 @@
|
|||||||
<div class="flex justify-end space-x-4">
|
<div class="flex justify-end space-x-4">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@click="loadProfile"
|
|
||||||
class="px-6 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
|
class="px-6 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
|
||||||
:disabled="isSaving"
|
:disabled="isSaving"
|
||||||
|
@click="loadProfile"
|
||||||
>
|
>
|
||||||
Zurücksetzen
|
Zurücksetzen
|
||||||
</button>
|
</button>
|
||||||
@@ -130,7 +172,11 @@
|
|||||||
class="px-6 py-2 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors flex items-center"
|
class="px-6 py-2 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors flex items-center"
|
||||||
:disabled="isSaving"
|
:disabled="isSaving"
|
||||||
>
|
>
|
||||||
<Loader2 v-if="isSaving" :size="20" class="animate-spin mr-2" />
|
<Loader2
|
||||||
|
v-if="isSaving"
|
||||||
|
:size="20"
|
||||||
|
class="animate-spin mr-2"
|
||||||
|
/>
|
||||||
<span>{{ isSaving ? 'Speichert...' : 'Speichern' }}</span>
|
<span>{{ isSaving ? 'Speichert...' : 'Speichern' }}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,11 +4,14 @@
|
|||||||
<h1 class="text-4xl sm:text-5xl font-display font-bold text-gray-900 mb-2">
|
<h1 class="text-4xl sm:text-5xl font-display font-bold text-gray-900 mb-2">
|
||||||
Mitgliedschaft
|
Mitgliedschaft
|
||||||
</h1>
|
</h1>
|
||||||
<div class="w-24 h-1 bg-primary-600 mb-4"></div>
|
<div class="w-24 h-1 bg-primary-600 mb-4" />
|
||||||
|
|
||||||
<!-- Mitgliedschaftspläne (ohne "Noch Fragen" Box) -->
|
<!-- Mitgliedschaftspläne (ohne "Noch Fragen" Box) -->
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<section id="membership" class="py-8 sm:py-12 bg-gradient-to-b from-gray-50 to-white">
|
<section
|
||||||
|
id="membership"
|
||||||
|
class="py-8 sm:py-12 bg-gradient-to-b from-gray-50 to-white"
|
||||||
|
>
|
||||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<div class="text-center mb-8">
|
<div class="text-center mb-8">
|
||||||
<p class="text-xl text-gray-600 max-w-3xl mx-auto">
|
<p class="text-xl text-gray-600 max-w-3xl mx-auto">
|
||||||
@@ -36,12 +39,24 @@
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
class="inline-flex items-center px-6 py-3 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors"
|
class="inline-flex items-center px-6 py-3 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors"
|
||||||
>
|
>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" size="20" class="lucide lucide-file-text-icon mr-2">
|
<svg
|
||||||
<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"></path>
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
<path d="M14 2v4a2 2 0 0 0 2 2h4"></path>
|
width="20"
|
||||||
<path d="M10 9H8"></path>
|
height="20"
|
||||||
<path d="M16 13H8"></path>
|
viewBox="0 0 24 24"
|
||||||
<path d="M16 17H8"></path>
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
size="20"
|
||||||
|
class="lucide lucide-file-text-icon mr-2"
|
||||||
|
>
|
||||||
|
<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" />
|
||||||
|
<path d="M14 2v4a2 2 0 0 0 2 2h4" />
|
||||||
|
<path d="M10 9H8" />
|
||||||
|
<path d="M16 13H8" />
|
||||||
|
<path d="M16 17H8" />
|
||||||
</svg>
|
</svg>
|
||||||
Satzung herunterladen (PDF)
|
Satzung herunterladen (PDF)
|
||||||
</a>
|
</a>
|
||||||
@@ -50,9 +65,25 @@
|
|||||||
href="/satzung"
|
href="/satzung"
|
||||||
class="inline-flex items-center px-6 py-3 bg-gray-100 hover:bg-gray-200 text-gray-900 font-semibold rounded-lg transition-colors"
|
class="inline-flex items-center px-6 py-3 bg-gray-100 hover:bg-gray-200 text-gray-900 font-semibold rounded-lg transition-colors"
|
||||||
>
|
>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" size="20" class="lucide lucide-eye-icon mr-2">
|
<svg
|
||||||
<path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z"></path>
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
<circle cx="12" cy="12" r="3"></circle>
|
width="20"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
size="20"
|
||||||
|
class="lucide lucide-eye-icon mr-2"
|
||||||
|
>
|
||||||
|
<path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z" />
|
||||||
|
<circle
|
||||||
|
cx="12"
|
||||||
|
cy="12"
|
||||||
|
r="3"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
Online ansehen
|
Online ansehen
|
||||||
</a>
|
</a>
|
||||||
@@ -73,16 +104,35 @@
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
class="inline-flex items-center px-4 py-2 bg-gray-100 hover:bg-gray-200 text-gray-900 font-semibold rounded-lg transition-colors"
|
class="inline-flex items-center px-4 py-2 bg-gray-100 hover:bg-gray-200 text-gray-900 font-semibold rounded-lg transition-colors"
|
||||||
>
|
>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="mr-2">
|
<svg
|
||||||
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
<polyline points="7,10 12,15 17,10"></polyline>
|
width="16"
|
||||||
<line x1="12" y1="15" x2="12" y2="3"></line>
|
height="16"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
class="mr-2"
|
||||||
|
>
|
||||||
|
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
|
||||||
|
<polyline points="7,10 12,15 17,10" />
|
||||||
|
<line
|
||||||
|
x1="12"
|
||||||
|
y1="15"
|
||||||
|
x2="12"
|
||||||
|
y2="3"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
Mitgliedsantrag herunterladen
|
Mitgliedsantrag herunterladen
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form id="membershipForm" class="space-y-8">
|
<form
|
||||||
|
id="membershipForm"
|
||||||
|
class="space-y-8"
|
||||||
|
>
|
||||||
<!-- Persönliche Daten -->
|
<!-- Persönliche Daten -->
|
||||||
<div class="space-y-6">
|
<div class="space-y-6">
|
||||||
<h3 class="text-xl font-semibold text-gray-900 border-b border-gray-200 pb-2">
|
<h3 class="text-xl font-semibold text-gray-900 border-b border-gray-200 pb-2">
|
||||||
@@ -91,53 +141,73 @@
|
|||||||
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
<div>
|
<div>
|
||||||
<label for="nachname" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="nachname"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
Nachname
|
Nachname
|
||||||
</label>
|
</label>
|
||||||
<p class="text-xs text-gray-500 italic mb-2">Pflichtfeld</p>
|
<p class="text-xs text-gray-500 italic mb-2">
|
||||||
|
Pflichtfeld
|
||||||
|
</p>
|
||||||
<input
|
<input
|
||||||
id="nachname"
|
id="nachname"
|
||||||
name="nachname"
|
name="nachname"
|
||||||
type="text"
|
type="text"
|
||||||
required
|
required
|
||||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="vorname" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="vorname"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
Vorname
|
Vorname
|
||||||
</label>
|
</label>
|
||||||
<p class="text-xs text-gray-500 italic mb-2">Pflichtfeld</p>
|
<p class="text-xs text-gray-500 italic mb-2">
|
||||||
|
Pflichtfeld
|
||||||
|
</p>
|
||||||
<input
|
<input
|
||||||
id="vorname"
|
id="vorname"
|
||||||
name="vorname"
|
name="vorname"
|
||||||
type="text"
|
type="text"
|
||||||
required
|
required
|
||||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for="strasse" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="strasse"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
Straße und Hausnummer
|
Straße und Hausnummer
|
||||||
</label>
|
</label>
|
||||||
<p class="text-xs text-gray-500 italic mb-2">Pflichtfeld</p>
|
<p class="text-xs text-gray-500 italic mb-2">
|
||||||
|
Pflichtfeld
|
||||||
|
</p>
|
||||||
<input
|
<input
|
||||||
id="strasse"
|
id="strasse"
|
||||||
name="strasse"
|
name="strasse"
|
||||||
type="text"
|
type="text"
|
||||||
required
|
required
|
||||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
<div>
|
<div>
|
||||||
<label for="plz" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="plz"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
PLZ
|
PLZ
|
||||||
</label>
|
</label>
|
||||||
<p class="text-xs text-gray-500 italic mb-2">Pflichtfeld</p>
|
<p class="text-xs text-gray-500 italic mb-2">
|
||||||
|
Pflichtfeld
|
||||||
|
</p>
|
||||||
<input
|
<input
|
||||||
id="plz"
|
id="plz"
|
||||||
name="plz"
|
name="plz"
|
||||||
@@ -145,39 +215,52 @@
|
|||||||
required
|
required
|
||||||
pattern="[0-9]{5}"
|
pattern="[0-9]{5}"
|
||||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="ort" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="ort"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
Wohnort
|
Wohnort
|
||||||
</label>
|
</label>
|
||||||
<p class="text-xs text-gray-500 italic mb-2">Pflichtfeld</p>
|
<p class="text-xs text-gray-500 italic mb-2">
|
||||||
|
Pflichtfeld
|
||||||
|
</p>
|
||||||
<input
|
<input
|
||||||
id="ort"
|
id="ort"
|
||||||
name="ort"
|
name="ort"
|
||||||
type="text"
|
type="text"
|
||||||
required
|
required
|
||||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
<div>
|
<div>
|
||||||
<label for="geburtsdatum" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="geburtsdatum"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
Geburtsdatum
|
Geburtsdatum
|
||||||
</label>
|
</label>
|
||||||
<p class="text-xs text-gray-500 italic mb-2">Pflichtfeld</p>
|
<p class="text-xs text-gray-500 italic mb-2">
|
||||||
|
Pflichtfeld
|
||||||
|
</p>
|
||||||
<input
|
<input
|
||||||
id="geburtsdatum"
|
id="geburtsdatum"
|
||||||
name="geburtsdatum"
|
name="geburtsdatum"
|
||||||
type="date"
|
type="date"
|
||||||
required
|
required
|
||||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="telefon_privat" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="telefon_privat"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
Telefon (privat)
|
Telefon (privat)
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -185,26 +268,34 @@
|
|||||||
name="telefon_privat"
|
name="telefon_privat"
|
||||||
type="tel"
|
type="tel"
|
||||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
<div>
|
<div>
|
||||||
<label for="email" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="email"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
E-Mail
|
E-Mail
|
||||||
</label>
|
</label>
|
||||||
<p class="text-xs text-gray-500 italic mb-2">Pflichtfeld</p>
|
<p class="text-xs text-gray-500 italic mb-2">
|
||||||
|
Pflichtfeld
|
||||||
|
</p>
|
||||||
<input
|
<input
|
||||||
id="email"
|
id="email"
|
||||||
name="email"
|
name="email"
|
||||||
type="email"
|
type="email"
|
||||||
required
|
required
|
||||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="telefon_mobil" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="telefon_mobil"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
Telefon (Mobil)
|
Telefon (Mobil)
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -212,7 +303,7 @@
|
|||||||
name="telefon_mobil"
|
name="telefon_mobil"
|
||||||
type="tel"
|
type="tel"
|
||||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -230,7 +321,7 @@
|
|||||||
value="aktiv"
|
value="aktiv"
|
||||||
checked
|
checked
|
||||||
class="mr-3 text-primary-600 focus:ring-primary-500"
|
class="mr-3 text-primary-600 focus:ring-primary-500"
|
||||||
/>
|
>
|
||||||
<span class="text-gray-700">Aktives Mitglied</span>
|
<span class="text-gray-700">Aktives Mitglied</span>
|
||||||
</label>
|
</label>
|
||||||
<label class="flex items-center">
|
<label class="flex items-center">
|
||||||
@@ -239,7 +330,7 @@
|
|||||||
type="radio"
|
type="radio"
|
||||||
value="passiv"
|
value="passiv"
|
||||||
class="mr-3 text-primary-600 focus:ring-primary-500"
|
class="mr-3 text-primary-600 focus:ring-primary-500"
|
||||||
/>
|
>
|
||||||
<span class="text-gray-700">Passives Mitglied</span>
|
<span class="text-gray-700">Passives Mitglied</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
@@ -269,7 +360,7 @@
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
required
|
required
|
||||||
class="mr-3 mt-1 text-primary-600 focus:ring-primary-500"
|
class="mr-3 mt-1 text-primary-600 focus:ring-primary-500"
|
||||||
/>
|
>
|
||||||
<div>
|
<div>
|
||||||
<span class="text-gray-700">
|
<span class="text-gray-700">
|
||||||
Hierzu erteile ich das beigefügte SEPA-Lastschriftmandat.
|
Hierzu erteile ich das beigefügte SEPA-Lastschriftmandat.
|
||||||
@@ -286,24 +377,34 @@
|
|||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for="kontoinhaber" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="kontoinhaber"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
Kontoinhaber (Vorname und Name)
|
Kontoinhaber (Vorname und Name)
|
||||||
</label>
|
</label>
|
||||||
<p class="text-xs text-gray-500 italic mb-2">Pflichtfeld</p>
|
<p class="text-xs text-gray-500 italic mb-2">
|
||||||
|
Pflichtfeld
|
||||||
|
</p>
|
||||||
<input
|
<input
|
||||||
id="kontoinhaber"
|
id="kontoinhaber"
|
||||||
name="kontoinhaber"
|
name="kontoinhaber"
|
||||||
type="text"
|
type="text"
|
||||||
required
|
required
|
||||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for="iban" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="iban"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
IBAN
|
IBAN
|
||||||
</label>
|
</label>
|
||||||
<p class="text-xs text-gray-500 italic mb-2">Pflichtfeld</p>
|
<p class="text-xs text-gray-500 italic mb-2">
|
||||||
|
Pflichtfeld
|
||||||
|
</p>
|
||||||
<input
|
<input
|
||||||
id="iban"
|
id="iban"
|
||||||
name="iban"
|
name="iban"
|
||||||
@@ -311,11 +412,14 @@
|
|||||||
required
|
required
|
||||||
placeholder="DE89 3704 0044 0532 0130 00"
|
placeholder="DE89 3704 0044 0532 0130 00"
|
||||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for="bic" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="bic"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
BIC
|
BIC
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -324,11 +428,14 @@
|
|||||||
type="text"
|
type="text"
|
||||||
placeholder="COBADEFFXXX"
|
placeholder="COBADEFFXXX"
|
||||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for="bank" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="bank"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
Kreditinstitut
|
Kreditinstitut
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -336,7 +443,7 @@
|
|||||||
name="bank"
|
name="bank"
|
||||||
type="text"
|
type="text"
|
||||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -356,7 +463,7 @@
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
required
|
required
|
||||||
class="mr-3 mt-1 text-primary-600 focus:ring-primary-500"
|
class="mr-3 mt-1 text-primary-600 focus:ring-primary-500"
|
||||||
/>
|
>
|
||||||
<div>
|
<div>
|
||||||
<span class="text-sm text-gray-700">
|
<span class="text-sm text-gray-700">
|
||||||
Ich bestätige das Vorstehende zur Kenntnis genommen zu haben und willige ein, dass der Harheimer Tischtennis-Club 1954 e.V. allgemeine Daten zu meiner Person (Name, Fotografien, Mannschaft, Leistungsergebnisse, Turnierteilnahmen, Lizenzen u.ä.) auf der Homepage des Vereins veröffentlichen darf.
|
Ich bestätige das Vorstehende zur Kenntnis genommen zu haben und willige ein, dass der Harheimer Tischtennis-Club 1954 e.V. allgemeine Daten zu meiner Person (Name, Fotografien, Mannschaft, Leistungsergebnisse, Turnierteilnahmen, Lizenzen u.ä.) auf der Homepage des Vereins veröffentlichen darf.
|
||||||
@@ -378,7 +485,7 @@
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
required
|
required
|
||||||
class="mr-3 mt-1 text-primary-600 focus:ring-primary-500"
|
class="mr-3 mt-1 text-primary-600 focus:ring-primary-500"
|
||||||
/>
|
>
|
||||||
<div>
|
<div>
|
||||||
<span class="text-gray-700">
|
<span class="text-gray-700">
|
||||||
Ich erkenne die Vereinssatzung (erhältlich beim Vorstand bzw. auf der Vereinshomepage) an.
|
Ich erkenne die Vereinssatzung (erhältlich beim Vorstand bzw. auf der Vereinshomepage) an.
|
||||||
@@ -390,7 +497,9 @@
|
|||||||
|
|
||||||
<!-- Hinweise -->
|
<!-- Hinweise -->
|
||||||
<div class="bg-yellow-50 p-4 rounded-lg border border-yellow-200">
|
<div class="bg-yellow-50 p-4 rounded-lg border border-yellow-200">
|
||||||
<h4 class="font-semibold text-gray-900 mb-2">Wichtige Hinweise:</h4>
|
<h4 class="font-semibold text-gray-900 mb-2">
|
||||||
|
Wichtige Hinweise:
|
||||||
|
</h4>
|
||||||
<ul class="text-sm text-gray-700 space-y-1">
|
<ul class="text-sm text-gray-700 space-y-1">
|
||||||
<li>• Die Mitgliedschaft im Harheimer Tischtennis-Club erlangt erst nach Bestätigung durch den Vorstand Wirksamkeit.</li>
|
<li>• Die Mitgliedschaft im Harheimer Tischtennis-Club erlangt erst nach Bestätigung durch den Vorstand Wirksamkeit.</li>
|
||||||
<li>• Die Beitragspflicht beginnt mit dem darauf folgenden Monat.</li>
|
<li>• Die Beitragspflicht beginnt mit dem darauf folgenden Monat.</li>
|
||||||
@@ -401,13 +510,30 @@
|
|||||||
<!-- Submit Button -->
|
<!-- Submit Button -->
|
||||||
<div class="flex justify-center pt-6">
|
<div class="flex justify-center pt-6">
|
||||||
<button
|
<button
|
||||||
type="submit"
|
|
||||||
id="submitBtn"
|
id="submitBtn"
|
||||||
|
type="submit"
|
||||||
class="px-8 py-3 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors flex items-center justify-center"
|
class="px-8 py-3 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors flex items-center justify-center"
|
||||||
>
|
>
|
||||||
<svg v-if="isGenerating" class="animate-spin -ml-1 mr-3 h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
<svg
|
||||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
v-if="isGenerating"
|
||||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
class="animate-spin -ml-1 mr-3 h-5 w-5 text-white"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<circle
|
||||||
|
class="opacity-25"
|
||||||
|
cx="12"
|
||||||
|
cy="12"
|
||||||
|
r="10"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="4"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
class="opacity-75"
|
||||||
|
fill="currentColor"
|
||||||
|
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
Beitrittsformular erstellen
|
Beitrittsformular erstellen
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -2,19 +2,47 @@
|
|||||||
<div class="min-h-full py-16 bg-gray-50">
|
<div class="min-h-full py-16 bg-gray-50">
|
||||||
<div class="max-w-2xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div class="max-w-2xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<div class="bg-white rounded-xl shadow-lg p-8 text-center">
|
<div class="bg-white rounded-xl shadow-lg p-8 text-center">
|
||||||
<div v-if="loading" class="py-12">
|
<div
|
||||||
|
v-if="loading"
|
||||||
|
class="py-12"
|
||||||
|
>
|
||||||
<div class="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-6">
|
<div class="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-6">
|
||||||
<svg class="w-8 h-8 text-blue-600 animate-spin" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
class="w-8 h-8 text-blue-600 animate-spin"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<p class="text-lg text-gray-600">Newsletter-Anmeldung wird bestätigt...</p>
|
<p class="text-lg text-gray-600">
|
||||||
|
Newsletter-Anmeldung wird bestätigt...
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else-if="error" class="py-12">
|
<div
|
||||||
|
v-else-if="error"
|
||||||
|
class="py-12"
|
||||||
|
>
|
||||||
<div class="w-16 h-16 bg-red-100 rounded-full flex items-center justify-center mx-auto mb-6">
|
<div class="w-16 h-16 bg-red-100 rounded-full flex items-center justify-center mx-auto mb-6">
|
||||||
<svg class="w-8 h-8 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
class="w-8 h-8 text-red-600"
|
||||||
|
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>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<h1 class="text-3xl font-display font-bold text-gray-900 mb-4">
|
<h1 class="text-3xl font-display font-bold text-gray-900 mb-4">
|
||||||
|
|||||||
@@ -3,8 +3,18 @@
|
|||||||
<div class="max-w-2xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div class="max-w-2xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<div class="bg-white rounded-xl shadow-lg p-8 text-center">
|
<div class="bg-white rounded-xl shadow-lg p-8 text-center">
|
||||||
<div class="w-16 h-16 bg-green-100 rounded-full flex items-center justify-center mx-auto mb-6">
|
<div class="w-16 h-16 bg-green-100 rounded-full flex items-center justify-center mx-auto mb-6">
|
||||||
<svg class="w-8 h-8 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
class="w-8 h-8 text-green-600"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M5 13l4 4L19 7"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -7,31 +7,55 @@
|
|||||||
</h1>
|
</h1>
|
||||||
<div class="w-24 h-1 bg-primary-600 mb-8" />
|
<div class="w-24 h-1 bg-primary-600 mb-8" />
|
||||||
|
|
||||||
<div v-if="loadingGroups" class="text-center py-8">
|
<div
|
||||||
<p class="text-gray-600">Lade verfügbare Newsletter...</p>
|
v-if="loadingGroups"
|
||||||
|
class="text-center py-8"
|
||||||
|
>
|
||||||
|
<p class="text-gray-600">
|
||||||
|
Lade verfügbare Newsletter...
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form v-else @submit.prevent="subscribe" class="space-y-6">
|
<form
|
||||||
|
v-else
|
||||||
|
class="space-y-6"
|
||||||
|
@submit.prevent="subscribe"
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<label for="groupId" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="groupId"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
Newsletter auswählen *
|
Newsletter auswählen *
|
||||||
</label>
|
</label>
|
||||||
<select
|
<select
|
||||||
id="groupId"
|
id="groupId"
|
||||||
v-model="form.groupId"
|
v-model="form.groupId"
|
||||||
required
|
required
|
||||||
@change="checkSubscription"
|
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||||
|
@change="checkSubscription"
|
||||||
>
|
>
|
||||||
<option value="">Bitte wählen Sie einen Newsletter</option>
|
<option value="">
|
||||||
<option v-for="group in groups" :key="group.id" :value="group.id">
|
Bitte wählen Sie einen Newsletter
|
||||||
|
</option>
|
||||||
|
<option
|
||||||
|
v-for="group in groups"
|
||||||
|
:key="group.id"
|
||||||
|
:value="group.id"
|
||||||
|
>
|
||||||
{{ group.name }}
|
{{ group.name }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
<p v-if="selectedGroup?.description" class="mt-2 text-sm text-gray-600">
|
<p
|
||||||
|
v-if="selectedGroup?.description"
|
||||||
|
class="mt-2 text-sm text-gray-600"
|
||||||
|
>
|
||||||
{{ selectedGroup.description }}
|
{{ selectedGroup.description }}
|
||||||
</p>
|
</p>
|
||||||
<div v-if="alreadySubscribed" class="mt-2 p-3 bg-blue-50 border border-blue-200 rounded-lg">
|
<div
|
||||||
|
v-if="alreadySubscribed"
|
||||||
|
class="mt-2 p-3 bg-blue-50 border border-blue-200 rounded-lg"
|
||||||
|
>
|
||||||
<p class="text-sm text-blue-700">
|
<p class="text-sm text-blue-700">
|
||||||
✓ Sie sind bereits für diesen Newsletter angemeldet.
|
✓ Sie sind bereits für diesen Newsletter angemeldet.
|
||||||
</p>
|
</p>
|
||||||
@@ -39,7 +63,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for="email" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="email"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
E-Mail-Adresse *
|
E-Mail-Adresse *
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -47,14 +74,17 @@
|
|||||||
v-model="form.email"
|
v-model="form.email"
|
||||||
type="email"
|
type="email"
|
||||||
required
|
required
|
||||||
@blur="checkSubscription"
|
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||||
placeholder="ihre.email@example.com"
|
placeholder="ihre.email@example.com"
|
||||||
/>
|
@blur="checkSubscription"
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for="name" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="name"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
Name (optional)
|
Name (optional)
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -63,14 +93,20 @@
|
|||||||
type="text"
|
type="text"
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||||
placeholder="Ihr Name"
|
placeholder="Ihr Name"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="error" class="p-4 bg-red-50 border border-red-200 rounded-lg text-red-700">
|
<div
|
||||||
|
v-if="error"
|
||||||
|
class="p-4 bg-red-50 border border-red-200 rounded-lg text-red-700"
|
||||||
|
>
|
||||||
{{ error }}
|
{{ error }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="success" class="p-4 bg-green-50 border border-green-200 rounded-lg text-green-700">
|
<div
|
||||||
|
v-if="success"
|
||||||
|
class="p-4 bg-green-50 border border-green-200 rounded-lg text-green-700"
|
||||||
|
>
|
||||||
{{ success }}
|
{{ success }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -7,13 +7,25 @@
|
|||||||
</h1>
|
</h1>
|
||||||
<div class="w-24 h-1 bg-primary-600 mb-8" />
|
<div class="w-24 h-1 bg-primary-600 mb-8" />
|
||||||
|
|
||||||
<div v-if="loadingGroups" class="text-center py-8">
|
<div
|
||||||
<p class="text-gray-600">Lade verfügbare Newsletter...</p>
|
v-if="loadingGroups"
|
||||||
|
class="text-center py-8"
|
||||||
|
>
|
||||||
|
<p class="text-gray-600">
|
||||||
|
Lade verfügbare Newsletter...
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form v-else @submit.prevent="unsubscribe" class="space-y-6">
|
<form
|
||||||
|
v-else
|
||||||
|
class="space-y-6"
|
||||||
|
@submit.prevent="unsubscribe"
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<label for="groupId" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="groupId"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
Newsletter auswählen *
|
Newsletter auswählen *
|
||||||
</label>
|
</label>
|
||||||
<select
|
<select
|
||||||
@@ -22,18 +34,30 @@
|
|||||||
required
|
required
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||||
>
|
>
|
||||||
<option value="">Bitte wählen Sie einen Newsletter</option>
|
<option value="">
|
||||||
<option v-for="group in groups" :key="group.id" :value="group.id">
|
Bitte wählen Sie einen Newsletter
|
||||||
|
</option>
|
||||||
|
<option
|
||||||
|
v-for="group in groups"
|
||||||
|
:key="group.id"
|
||||||
|
:value="group.id"
|
||||||
|
>
|
||||||
{{ group.name }}
|
{{ group.name }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
<p v-if="selectedGroup?.description" class="mt-2 text-sm text-gray-600">
|
<p
|
||||||
|
v-if="selectedGroup?.description"
|
||||||
|
class="mt-2 text-sm text-gray-600"
|
||||||
|
>
|
||||||
{{ selectedGroup.description }}
|
{{ selectedGroup.description }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for="email" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="email"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
E-Mail-Adresse *
|
E-Mail-Adresse *
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -43,14 +67,20 @@
|
|||||||
required
|
required
|
||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500"
|
||||||
placeholder="ihre.email@example.com"
|
placeholder="ihre.email@example.com"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="error" class="p-4 bg-red-50 border border-red-200 rounded-lg text-red-700">
|
<div
|
||||||
|
v-if="error"
|
||||||
|
class="p-4 bg-red-50 border border-red-200 rounded-lg text-red-700"
|
||||||
|
>
|
||||||
{{ error }}
|
{{ error }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="success" class="p-4 bg-green-50 border border-green-200 rounded-lg text-green-700">
|
<div
|
||||||
|
v-if="success"
|
||||||
|
class="p-4 bg-green-50 border border-green-200 rounded-lg text-green-700"
|
||||||
|
>
|
||||||
{{ success }}
|
{{ success }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,18 @@
|
|||||||
<div class="max-w-2xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div class="max-w-2xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<div class="bg-white rounded-xl shadow-lg p-8 text-center">
|
<div class="bg-white rounded-xl shadow-lg p-8 text-center">
|
||||||
<div class="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-6">
|
<div class="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-6">
|
||||||
<svg class="w-8 h-8 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636" />
|
class="w-8 h-8 text-blue-600"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -11,10 +11,16 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-white rounded-xl shadow-lg p-8">
|
<div class="bg-white rounded-xl shadow-lg p-8">
|
||||||
<form @submit.prevent="handleReset" class="space-y-6">
|
<form
|
||||||
|
class="space-y-6"
|
||||||
|
@submit.prevent="handleReset"
|
||||||
|
>
|
||||||
<!-- Email -->
|
<!-- Email -->
|
||||||
<div>
|
<div>
|
||||||
<label for="email" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="email"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
E-Mail-Adresse
|
E-Mail-Adresse
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -26,21 +32,33 @@
|
|||||||
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-600 focus:border-transparent transition-all"
|
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-600 focus:border-transparent transition-all"
|
||||||
:class="{ 'border-red-500': errorMessage }"
|
:class="{ 'border-red-500': errorMessage }"
|
||||||
placeholder="ihre-email@example.com"
|
placeholder="ihre-email@example.com"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Error Message -->
|
<!-- Error Message -->
|
||||||
<div v-if="errorMessage" class="bg-red-50 border border-red-200 rounded-lg p-4">
|
<div
|
||||||
|
v-if="errorMessage"
|
||||||
|
class="bg-red-50 border border-red-200 rounded-lg p-4"
|
||||||
|
>
|
||||||
<p class="text-sm text-red-800 flex items-center">
|
<p class="text-sm text-red-800 flex items-center">
|
||||||
<AlertCircle :size="18" class="mr-2" />
|
<AlertCircle
|
||||||
|
:size="18"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
{{ errorMessage }}
|
{{ errorMessage }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Success Message -->
|
<!-- Success Message -->
|
||||||
<div v-if="successMessage" class="bg-green-50 border border-green-200 rounded-lg p-4">
|
<div
|
||||||
|
v-if="successMessage"
|
||||||
|
class="bg-green-50 border border-green-200 rounded-lg p-4"
|
||||||
|
>
|
||||||
<p class="text-sm text-green-800 flex items-center">
|
<p class="text-sm text-green-800 flex items-center">
|
||||||
<Check :size="18" class="mr-2" />
|
<Check
|
||||||
|
:size="18"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
{{ successMessage }}
|
{{ successMessage }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -51,7 +69,11 @@
|
|||||||
:disabled="isLoading"
|
:disabled="isLoading"
|
||||||
class="w-full px-6 py-3 bg-primary-600 hover:bg-primary-700 disabled:bg-gray-400 text-white font-semibold rounded-lg transition-colors flex items-center justify-center"
|
class="w-full px-6 py-3 bg-primary-600 hover:bg-primary-700 disabled:bg-gray-400 text-white font-semibold rounded-lg transition-colors flex items-center justify-center"
|
||||||
>
|
>
|
||||||
<Loader2 v-if="isLoading" :size="20" class="mr-2 animate-spin" />
|
<Loader2
|
||||||
|
v-if="isLoading"
|
||||||
|
:size="20"
|
||||||
|
class="mr-2 animate-spin"
|
||||||
|
/>
|
||||||
<span>{{ isLoading ? 'Wird gesendet...' : 'Passwort zurücksetzen' }}</span>
|
<span>{{ isLoading ? 'Wird gesendet...' : 'Passwort zurücksetzen' }}</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
|||||||
@@ -11,10 +11,16 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-white rounded-xl shadow-lg p-8">
|
<div class="bg-white rounded-xl shadow-lg p-8">
|
||||||
<form @submit.prevent="handleRegister" class="space-y-6">
|
<form
|
||||||
|
class="space-y-6"
|
||||||
|
@submit.prevent="handleRegister"
|
||||||
|
>
|
||||||
<!-- Name -->
|
<!-- Name -->
|
||||||
<div>
|
<div>
|
||||||
<label for="name" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="name"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
Vollständiger Name
|
Vollständiger Name
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -25,12 +31,15 @@
|
|||||||
autocomplete="name"
|
autocomplete="name"
|
||||||
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-600 focus:border-transparent transition-all"
|
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-600 focus:border-transparent transition-all"
|
||||||
placeholder="Max Mustermann"
|
placeholder="Max Mustermann"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Email -->
|
<!-- Email -->
|
||||||
<div>
|
<div>
|
||||||
<label for="email" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="email"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
E-Mail-Adresse
|
E-Mail-Adresse
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -41,12 +50,15 @@
|
|||||||
autocomplete="email"
|
autocomplete="email"
|
||||||
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-600 focus:border-transparent transition-all"
|
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-600 focus:border-transparent transition-all"
|
||||||
placeholder="ihre-email@example.com"
|
placeholder="ihre-email@example.com"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Phone -->
|
<!-- Phone -->
|
||||||
<div>
|
<div>
|
||||||
<label for="phone" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="phone"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
Telefonnummer (optional)
|
Telefonnummer (optional)
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -56,12 +68,15 @@
|
|||||||
autocomplete="tel"
|
autocomplete="tel"
|
||||||
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-600 focus:border-transparent transition-all"
|
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-600 focus:border-transparent transition-all"
|
||||||
placeholder="069-12345678"
|
placeholder="069-12345678"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Password -->
|
<!-- Password -->
|
||||||
<div>
|
<div>
|
||||||
<label for="password" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="password"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
Passwort
|
Passwort
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -72,7 +87,7 @@
|
|||||||
autocomplete="new-password"
|
autocomplete="new-password"
|
||||||
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-600 focus:border-transparent transition-all"
|
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-600 focus:border-transparent transition-all"
|
||||||
placeholder="••••••••"
|
placeholder="••••••••"
|
||||||
/>
|
>
|
||||||
<p class="mt-1 text-xs text-gray-500">
|
<p class="mt-1 text-xs text-gray-500">
|
||||||
Mindestens 8 Zeichen
|
Mindestens 8 Zeichen
|
||||||
</p>
|
</p>
|
||||||
@@ -80,7 +95,10 @@
|
|||||||
|
|
||||||
<!-- Confirm Password -->
|
<!-- Confirm Password -->
|
||||||
<div>
|
<div>
|
||||||
<label for="confirmPassword" class="block text-sm font-medium text-gray-700 mb-2">
|
<label
|
||||||
|
for="confirmPassword"
|
||||||
|
class="block text-sm font-medium text-gray-700 mb-2"
|
||||||
|
>
|
||||||
Passwort bestätigen
|
Passwort bestätigen
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -91,21 +109,33 @@
|
|||||||
autocomplete="new-password"
|
autocomplete="new-password"
|
||||||
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-600 focus:border-transparent transition-all"
|
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-600 focus:border-transparent transition-all"
|
||||||
placeholder="••••••••"
|
placeholder="••••••••"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Error Message -->
|
<!-- Error Message -->
|
||||||
<div v-if="errorMessage" class="bg-red-50 border border-red-200 rounded-lg p-4">
|
<div
|
||||||
|
v-if="errorMessage"
|
||||||
|
class="bg-red-50 border border-red-200 rounded-lg p-4"
|
||||||
|
>
|
||||||
<p class="text-sm text-red-800 flex items-center">
|
<p class="text-sm text-red-800 flex items-center">
|
||||||
<AlertCircle :size="18" class="mr-2" />
|
<AlertCircle
|
||||||
|
:size="18"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
{{ errorMessage }}
|
{{ errorMessage }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Success Message -->
|
<!-- Success Message -->
|
||||||
<div v-if="successMessage" class="bg-green-50 border border-green-200 rounded-lg p-4">
|
<div
|
||||||
|
v-if="successMessage"
|
||||||
|
class="bg-green-50 border border-green-200 rounded-lg p-4"
|
||||||
|
>
|
||||||
<p class="text-sm text-green-800 flex items-center">
|
<p class="text-sm text-green-800 flex items-center">
|
||||||
<Check :size="18" class="mr-2" />
|
<Check
|
||||||
|
:size="18"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
{{ successMessage }}
|
{{ successMessage }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -116,7 +146,11 @@
|
|||||||
:disabled="isLoading"
|
:disabled="isLoading"
|
||||||
class="w-full px-6 py-3 bg-primary-600 hover:bg-primary-700 disabled:bg-gray-400 text-white font-semibold rounded-lg transition-colors flex items-center justify-center"
|
class="w-full px-6 py-3 bg-primary-600 hover:bg-primary-700 disabled:bg-gray-400 text-white font-semibold rounded-lg transition-colors flex items-center justify-center"
|
||||||
>
|
>
|
||||||
<Loader2 v-if="isLoading" :size="20" class="mr-2 animate-spin" />
|
<Loader2
|
||||||
|
v-if="isLoading"
|
||||||
|
:size="20"
|
||||||
|
class="mr-2 animate-spin"
|
||||||
|
/>
|
||||||
<span>{{ isLoading ? 'Wird gesendet...' : 'Registrierung beantragen' }}</span>
|
<span>{{ isLoading ? 'Wird gesendet...' : 'Registrierung beantragen' }}</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
@@ -135,7 +169,10 @@
|
|||||||
<!-- Info Box -->
|
<!-- Info Box -->
|
||||||
<div class="bg-yellow-50 border border-yellow-200 rounded-lg p-4">
|
<div class="bg-yellow-50 border border-yellow-200 rounded-lg p-4">
|
||||||
<p class="text-sm text-yellow-800">
|
<p class="text-sm text-yellow-800">
|
||||||
<Info :size="16" class="inline mr-1" />
|
<Info
|
||||||
|
:size="16"
|
||||||
|
class="inline mr-1"
|
||||||
|
/>
|
||||||
<strong>Hinweis:</strong> Ihre Registrierung muss vom Vorstand freigegeben werden.
|
<strong>Hinweis:</strong> Ihre Registrierung muss vom Vorstand freigegeben werden.
|
||||||
Sie erhalten eine E-Mail, sobald Ihr Zugang aktiviert wurde.
|
Sie erhalten eine E-Mail, sobald Ihr Zugang aktiviert wurde.
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -14,7 +14,9 @@
|
|||||||
<div class="prose prose-lg max-w-none">
|
<div class="prose prose-lg max-w-none">
|
||||||
<div class="space-y-8">
|
<div class="space-y-8">
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">§ 1 Name, Sitz und Geschäftsjahr</h3>
|
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">
|
||||||
|
§ 1 Name, Sitz und Geschäftsjahr
|
||||||
|
</h3>
|
||||||
<div class="space-y-2 text-gray-700">
|
<div class="space-y-2 text-gray-700">
|
||||||
<p><strong>(1)</strong> Der Verein führt den Namen "Harheimer Tischtennis-Club 1954 e.V." (HTC).</p>
|
<p><strong>(1)</strong> Der Verein führt den Namen "Harheimer Tischtennis-Club 1954 e.V." (HTC).</p>
|
||||||
<p><strong>(2)</strong> Der Verein hat seinen Sitz in Frankfurt am Main.</p>
|
<p><strong>(2)</strong> Der Verein hat seinen Sitz in Frankfurt am Main.</p>
|
||||||
@@ -23,7 +25,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">§ 2 Zweck des Vereins</h3>
|
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">
|
||||||
|
§ 2 Zweck des Vereins
|
||||||
|
</h3>
|
||||||
<div class="space-y-2 text-gray-700">
|
<div class="space-y-2 text-gray-700">
|
||||||
<p><strong>(1)</strong> Der Verein bezweckt die Förderung des Tischtennissports und die Pflege der Geselligkeit seiner Mitglieder.</p>
|
<p><strong>(1)</strong> Der Verein bezweckt die Förderung des Tischtennissports und die Pflege der Geselligkeit seiner Mitglieder.</p>
|
||||||
<p><strong>(2)</strong> Der Verein ist selbstlos tätig; er verfolgt nicht in erster Linie eigenwirtschaftliche Zwecke.</p>
|
<p><strong>(2)</strong> Der Verein ist selbstlos tätig; er verfolgt nicht in erster Linie eigenwirtschaftliche Zwecke.</p>
|
||||||
@@ -31,7 +35,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">§ 3 Mitgliedschaft</h3>
|
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">
|
||||||
|
§ 3 Mitgliedschaft
|
||||||
|
</h3>
|
||||||
<div class="space-y-2 text-gray-700">
|
<div class="space-y-2 text-gray-700">
|
||||||
<p><strong>(1)</strong> Mitglied des Vereins kann jede natürliche Person werden, die die Ziele des Vereins unterstützt.</p>
|
<p><strong>(1)</strong> Mitglied des Vereins kann jede natürliche Person werden, die die Ziele des Vereins unterstützt.</p>
|
||||||
<p><strong>(2)</strong> Der Antrag auf Mitgliedschaft ist schriftlich an den Vorstand zu richten.</p>
|
<p><strong>(2)</strong> Der Antrag auf Mitgliedschaft ist schriftlich an den Vorstand zu richten.</p>
|
||||||
@@ -40,7 +46,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">§ 4 Rechte und Pflichten der Mitglieder</h3>
|
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">
|
||||||
|
§ 4 Rechte und Pflichten der Mitglieder
|
||||||
|
</h3>
|
||||||
<div class="space-y-2 text-gray-700">
|
<div class="space-y-2 text-gray-700">
|
||||||
<p><strong>(1)</strong> Die Mitglieder haben das Recht, an den Veranstaltungen des Vereins teilzunehmen und die Einrichtungen des Vereins zu benutzen.</p>
|
<p><strong>(1)</strong> Die Mitglieder haben das Recht, an den Veranstaltungen des Vereins teilzunehmen und die Einrichtungen des Vereins zu benutzen.</p>
|
||||||
<p><strong>(2)</strong> Die Mitglieder sind verpflichtet, die Satzung und die Beschlüsse der Vereinsorgane zu beachten und den Mitgliedsbeitrag zu entrichten.</p>
|
<p><strong>(2)</strong> Die Mitglieder sind verpflichtet, die Satzung und die Beschlüsse der Vereinsorgane zu beachten und den Mitgliedsbeitrag zu entrichten.</p>
|
||||||
@@ -48,7 +56,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">§ 5 Mitgliedsbeiträge</h3>
|
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">
|
||||||
|
§ 5 Mitgliedsbeiträge
|
||||||
|
</h3>
|
||||||
<div class="space-y-2 text-gray-700">
|
<div class="space-y-2 text-gray-700">
|
||||||
<p><strong>(1)</strong> Die Höhe der Mitgliedsbeiträge wird von der Mitgliederversammlung festgesetzt.</p>
|
<p><strong>(1)</strong> Die Höhe der Mitgliedsbeiträge wird von der Mitgliederversammlung festgesetzt.</p>
|
||||||
<p><strong>(2)</strong> Die Mitgliedsbeiträge sind im Voraus zu entrichten.</p>
|
<p><strong>(2)</strong> Die Mitgliedsbeiträge sind im Voraus zu entrichten.</p>
|
||||||
@@ -56,7 +66,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">§ 6 Beendigung der Mitgliedschaft</h3>
|
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">
|
||||||
|
§ 6 Beendigung der Mitgliedschaft
|
||||||
|
</h3>
|
||||||
<div class="space-y-2 text-gray-700">
|
<div class="space-y-2 text-gray-700">
|
||||||
<p><strong>(1)</strong> Die Mitgliedschaft endet durch Austritt, Ausschluss oder Tod.</p>
|
<p><strong>(1)</strong> Die Mitgliedschaft endet durch Austritt, Ausschluss oder Tod.</p>
|
||||||
<p><strong>(2)</strong> Der Austritt erfolgt durch schriftliche Erklärung gegenüber dem Vorstand.</p>
|
<p><strong>(2)</strong> Der Austritt erfolgt durch schriftliche Erklärung gegenüber dem Vorstand.</p>
|
||||||
@@ -65,7 +77,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">§ 7 Organe des Vereins</h3>
|
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">
|
||||||
|
§ 7 Organe des Vereins
|
||||||
|
</h3>
|
||||||
<div class="space-y-2 text-gray-700">
|
<div class="space-y-2 text-gray-700">
|
||||||
<p>Organe des Vereins sind:</p>
|
<p>Organe des Vereins sind:</p>
|
||||||
<ul class="list-disc list-inside ml-4 space-y-1">
|
<ul class="list-disc list-inside ml-4 space-y-1">
|
||||||
@@ -76,7 +90,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">§ 8 Mitgliederversammlung</h3>
|
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">
|
||||||
|
§ 8 Mitgliederversammlung
|
||||||
|
</h3>
|
||||||
<div class="space-y-2 text-gray-700">
|
<div class="space-y-2 text-gray-700">
|
||||||
<p><strong>(1)</strong> Die Mitgliederversammlung ist das oberste Organ des Vereins.</p>
|
<p><strong>(1)</strong> Die Mitgliederversammlung ist das oberste Organ des Vereins.</p>
|
||||||
<p><strong>(2)</strong> Sie wird vom Vorsitzenden mindestens einmal im Jahr einberufen.</p>
|
<p><strong>(2)</strong> Sie wird vom Vorsitzenden mindestens einmal im Jahr einberufen.</p>
|
||||||
@@ -85,7 +101,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">§ 9 Vorstand</h3>
|
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">
|
||||||
|
§ 9 Vorstand
|
||||||
|
</h3>
|
||||||
<div class="space-y-2 text-gray-700">
|
<div class="space-y-2 text-gray-700">
|
||||||
<p><strong>(1)</strong> Der Vorstand besteht aus:</p>
|
<p><strong>(1)</strong> Der Vorstand besteht aus:</p>
|
||||||
<ul class="list-disc list-inside ml-4 space-y-1">
|
<ul class="list-disc list-inside ml-4 space-y-1">
|
||||||
@@ -100,14 +118,18 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">§ 10 Satzungsänderungen</h3>
|
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">
|
||||||
|
§ 10 Satzungsänderungen
|
||||||
|
</h3>
|
||||||
<div class="space-y-2 text-gray-700">
|
<div class="space-y-2 text-gray-700">
|
||||||
<p>Satzungsänderungen können nur in einer Mitgliederversammlung mit einer Mehrheit von zwei Dritteln der anwesenden Mitglieder beschlossen werden.</p>
|
<p>Satzungsänderungen können nur in einer Mitgliederversammlung mit einer Mehrheit von zwei Dritteln der anwesenden Mitglieder beschlossen werden.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">§ 11 Auflösung des Vereins</h3>
|
<h3 class="text-xl font-display font-bold text-gray-900 mb-3">
|
||||||
|
§ 11 Auflösung des Vereins
|
||||||
|
</h3>
|
||||||
<div class="space-y-2 text-gray-700">
|
<div class="space-y-2 text-gray-700">
|
||||||
<p><strong>(1)</strong> Die Auflösung des Vereins kann nur in einer Mitgliederversammlung mit einer Mehrheit von drei Vierteln der anwesenden Mitglieder beschlossen werden.</p>
|
<p><strong>(1)</strong> Die Auflösung des Vereins kann nur in einer Mitgliederversammlung mit einer Mehrheit von drei Vierteln der anwesenden Mitglieder beschlossen werden.</p>
|
||||||
<p><strong>(2)</strong> Bei Auflösung des Vereins fällt das Vereinsvermögen an eine gemeinnützige Organisation.</p>
|
<p><strong>(2)</strong> Bei Auflösung des Vereins fällt das Vereinsvermögen an eine gemeinnützige Organisation.</p>
|
||||||
@@ -118,7 +140,9 @@
|
|||||||
<div class="mt-12 p-6 bg-primary-50 rounded-lg border border-primary-200">
|
<div class="mt-12 p-6 bg-primary-50 rounded-lg border border-primary-200">
|
||||||
<div class="flex flex-col sm:flex-row gap-4 items-center justify-between">
|
<div class="flex flex-col sm:flex-row gap-4 items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<h4 class="text-lg font-semibold text-primary-800 mb-2">Satzung als PDF herunterladen</h4>
|
<h4 class="text-lg font-semibold text-primary-800 mb-2">
|
||||||
|
Satzung als PDF herunterladen
|
||||||
|
</h4>
|
||||||
<p class="text-primary-700 text-sm">
|
<p class="text-primary-700 text-sm">
|
||||||
Laden Sie die vollständige Satzung als PDF-Dokument herunter.
|
Laden Sie die vollständige Satzung als PDF-Dokument herunter.
|
||||||
</p>
|
</p>
|
||||||
@@ -128,7 +152,10 @@
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
class="inline-flex items-center px-6 py-3 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors"
|
class="inline-flex items-center px-6 py-3 bg-primary-600 hover:bg-primary-700 text-white font-semibold rounded-lg transition-colors"
|
||||||
>
|
>
|
||||||
<FileText :size="20" class="mr-2" />
|
<FileText
|
||||||
|
:size="20"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
PDF herunterladen
|
PDF herunterladen
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,18 +5,46 @@
|
|||||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<h1 class="text-3xl font-bold text-gray-900">Spielplan</h1>
|
<h1 class="text-3xl font-bold text-gray-900">
|
||||||
<p class="mt-2 text-gray-600">Aktuelle Termine und Spiele des Vereins</p>
|
Spielplan
|
||||||
|
</h1>
|
||||||
|
<p class="mt-2 text-gray-600">
|
||||||
|
Aktuelle Termine und Spiele des Vereins
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center space-x-4">
|
<div class="flex items-center space-x-4">
|
||||||
<button @click="refreshData"
|
<button
|
||||||
:disabled="isLoading"
|
:disabled="isLoading"
|
||||||
class="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors disabled:bg-gray-400">
|
class="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors disabled:bg-gray-400"
|
||||||
<svg v-if="isLoading" class="w-4 h-4 animate-spin" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
@click="refreshData"
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
>
|
||||||
|
<svg
|
||||||
|
v-if="isLoading"
|
||||||
|
class="w-4 h-4 animate-spin"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<svg v-else class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
v-else
|
||||||
|
class="w-4 h-4"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
Aktualisieren
|
Aktualisieren
|
||||||
</button>
|
</button>
|
||||||
@@ -28,60 +56,134 @@
|
|||||||
<!-- Content -->
|
<!-- Content -->
|
||||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||||
<!-- Loading State -->
|
<!-- Loading State -->
|
||||||
<div v-if="isLoading" class="text-center py-12">
|
<div
|
||||||
<svg class="w-8 h-8 text-gray-400 mx-auto mb-4 animate-spin" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
v-if="isLoading"
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
class="text-center py-12"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="w-8 h-8 text-gray-400 mx-auto mb-4 animate-spin"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<p class="text-gray-600">Spielplan wird geladen...</p>
|
<p class="text-gray-600">
|
||||||
|
Spielplan wird geladen...
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Error State -->
|
<!-- Error State -->
|
||||||
<div v-else-if="error" class="bg-red-50 border border-red-200 rounded-lg p-6 text-center">
|
<div
|
||||||
<svg class="w-12 h-12 text-red-400 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
v-else-if="error"
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z" />
|
class="bg-red-50 border border-red-200 rounded-lg p-6 text-center"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="w-12 h-12 text-red-400 mx-auto mb-4"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<h3 class="text-lg font-medium text-red-800 mb-2">Fehler beim Laden</h3>
|
<h3 class="text-lg font-medium text-red-800 mb-2">
|
||||||
<p class="text-red-600 mb-4">{{ error }}</p>
|
Fehler beim Laden
|
||||||
<button @click="loadData" class="px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors">
|
</h3>
|
||||||
|
<p class="text-red-600 mb-4">
|
||||||
|
{{ error }}
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
class="px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors"
|
||||||
|
@click="loadData"
|
||||||
|
>
|
||||||
Erneut versuchen
|
Erneut versuchen
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Empty State -->
|
<!-- Empty State -->
|
||||||
<div v-else-if="!spielplanData || spielplanData.length === 0" class="text-center py-12 bg-white rounded-xl shadow-lg">
|
<div
|
||||||
<svg class="w-12 h-12 text-gray-400 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
v-else-if="!spielplanData || spielplanData.length === 0"
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
|
class="text-center py-12 bg-white rounded-xl shadow-lg"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="w-12 h-12 text-gray-400 mx-auto mb-4"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M9 5H7a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
<h3 class="text-lg font-medium text-gray-900 mb-2">Kein Spielplan verfügbar</h3>
|
<h3 class="text-lg font-medium text-gray-900 mb-2">
|
||||||
<p class="text-gray-600">Es wurden noch keine Spielplandaten hochgeladen.</p>
|
Kein Spielplan verfügbar
|
||||||
|
</h3>
|
||||||
|
<p class="text-gray-600">
|
||||||
|
Es wurden noch keine Spielplandaten hochgeladen.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Spielplan Table -->
|
<!-- Spielplan Table -->
|
||||||
<div v-else class="bg-white rounded-xl shadow-lg overflow-hidden">
|
<div
|
||||||
|
v-else
|
||||||
|
class="bg-white rounded-xl shadow-lg overflow-hidden"
|
||||||
|
>
|
||||||
<div class="px-6 py-4 border-b border-gray-200">
|
<div class="px-6 py-4 border-b border-gray-200">
|
||||||
<h2 class="text-xl font-semibold text-gray-900">Aktuelle Spiele</h2>
|
<h2 class="text-xl font-semibold text-gray-900">
|
||||||
<p class="text-sm text-gray-600 mt-1">{{ spielplanData.length }} Einträge</p>
|
Aktuelle Spiele
|
||||||
|
</h2>
|
||||||
|
<p class="text-sm text-gray-600 mt-1">
|
||||||
|
{{ spielplanData.length }} Einträge
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="min-w-full divide-y divide-gray-200">
|
<table class="min-w-full divide-y divide-gray-200">
|
||||||
<thead class="bg-gray-50">
|
<thead class="bg-gray-50">
|
||||||
<tr>
|
<tr>
|
||||||
<th v-for="header in headers" :key="header"
|
<th
|
||||||
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
v-for="header in headers"
|
||||||
|
:key="header"
|
||||||
|
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
|
||||||
|
>
|
||||||
{{ formatHeader(header) }}
|
{{ formatHeader(header) }}
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="bg-white divide-y divide-gray-200">
|
<tbody class="bg-white divide-y divide-gray-200">
|
||||||
<tr v-for="(row, index) in spielplanData" :key="index"
|
<tr
|
||||||
:class="index % 2 === 0 ? 'bg-white' : 'bg-gray-50'">
|
v-for="(row, index) in spielplanData"
|
||||||
<td v-for="header in headers" :key="header"
|
:key="index"
|
||||||
class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
|
:class="index % 2 === 0 ? 'bg-white' : 'bg-gray-50'"
|
||||||
<span v-if="header.toLowerCase().includes('datum')" class="font-mono">
|
>
|
||||||
|
<td
|
||||||
|
v-for="header in headers"
|
||||||
|
:key="header"
|
||||||
|
class="px-6 py-4 whitespace-nowrap text-sm text-gray-900"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
v-if="header.toLowerCase().includes('datum')"
|
||||||
|
class="font-mono"
|
||||||
|
>
|
||||||
{{ formatDate(row[header]) }}
|
{{ formatDate(row[header]) }}
|
||||||
</span>
|
</span>
|
||||||
<span v-else-if="header.toLowerCase().includes('uhrzeit')" class="font-mono">
|
<span
|
||||||
|
v-else-if="header.toLowerCase().includes('uhrzeit')"
|
||||||
|
class="font-mono"
|
||||||
|
>
|
||||||
{{ formatTime(row[header]) }}
|
{{ formatTime(row[header]) }}
|
||||||
</span>
|
</span>
|
||||||
<span v-else>
|
<span v-else>
|
||||||
|
|||||||
@@ -15,31 +15,34 @@
|
|||||||
<button
|
<button
|
||||||
v-for="kategorie in verfuegbareKategorien"
|
v-for="kategorie in verfuegbareKategorien"
|
||||||
:key="kategorie"
|
:key="kategorie"
|
||||||
@click="selectedCategory = kategorie"
|
|
||||||
:class="[
|
:class="[
|
||||||
'px-4 py-2 rounded-lg font-medium transition-colors',
|
'px-4 py-2 rounded-lg font-medium transition-colors',
|
||||||
selectedCategory === kategorie
|
selectedCategory === kategorie
|
||||||
? 'bg-primary-600 text-white'
|
? 'bg-primary-600 text-white'
|
||||||
: 'bg-white text-gray-700 hover:bg-gray-100 border border-gray-300'
|
: 'bg-white text-gray-700 hover:bg-gray-100 border border-gray-300'
|
||||||
]"
|
]"
|
||||||
|
@click="selectedCategory = kategorie"
|
||||||
>
|
>
|
||||||
{{ kategorie }}
|
{{ kategorie }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@click="selectedCategory = 'alle'"
|
|
||||||
:class="[
|
:class="[
|
||||||
'px-4 py-2 rounded-lg font-medium transition-colors',
|
'px-4 py-2 rounded-lg font-medium transition-colors',
|
||||||
selectedCategory === 'alle'
|
selectedCategory === 'alle'
|
||||||
? 'bg-primary-600 text-white'
|
? 'bg-primary-600 text-white'
|
||||||
: 'bg-white text-gray-700 hover:bg-gray-100 border border-gray-300'
|
: 'bg-white text-gray-700 hover:bg-gray-100 border border-gray-300'
|
||||||
]"
|
]"
|
||||||
|
@click="selectedCategory = 'alle'"
|
||||||
>
|
>
|
||||||
Alle Kategorien
|
Alle Kategorien
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Spielsysteme -->
|
<!-- Spielsysteme -->
|
||||||
<div v-if="filteredSystems.length > 0" class="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
|
<div
|
||||||
|
v-if="filteredSystems.length > 0"
|
||||||
|
class="grid md:grid-cols-2 lg:grid-cols-3 gap-6"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
v-for="system in filteredSystems"
|
v-for="system in filteredSystems"
|
||||||
:key="system.name"
|
:key="system.name"
|
||||||
@@ -51,7 +54,10 @@
|
|||||||
{{ system.name }}
|
{{ system.name }}
|
||||||
</h3>
|
</h3>
|
||||||
<div class="flex items-center mb-3">
|
<div class="flex items-center mb-3">
|
||||||
<Users :size="16" class="text-primary-600 mr-2" />
|
<Users
|
||||||
|
:size="16"
|
||||||
|
class="text-primary-600 mr-2"
|
||||||
|
/>
|
||||||
<span class="text-sm font-medium text-gray-600">{{ system.mannschaftsgroesse }}</span>
|
<span class="text-sm font-medium text-gray-600">{{ system.mannschaftsgroesse }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -70,31 +76,60 @@
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="space-y-2 text-sm">
|
<div class="space-y-2 text-sm">
|
||||||
<div v-if="system.spielabfolge" class="flex items-center">
|
<div
|
||||||
<Calendar :size="14" class="text-primary-600 mr-2 flex-shrink-0" />
|
v-if="system.spielabfolge"
|
||||||
|
class="flex items-center"
|
||||||
|
>
|
||||||
|
<Calendar
|
||||||
|
:size="14"
|
||||||
|
class="text-primary-600 mr-2 flex-shrink-0"
|
||||||
|
/>
|
||||||
<span class="text-gray-600"><strong>Spielabfolge:</strong> {{ system.spielabfolge }}</span>
|
<span class="text-gray-600"><strong>Spielabfolge:</strong> {{ system.spielabfolge }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="system.anzahl_spiele" class="flex items-center">
|
<div
|
||||||
<Hash :size="14" class="text-primary-600 mr-2 flex-shrink-0" />
|
v-if="system.anzahl_spiele"
|
||||||
|
class="flex items-center"
|
||||||
|
>
|
||||||
|
<Hash
|
||||||
|
:size="14"
|
||||||
|
class="text-primary-600 mr-2 flex-shrink-0"
|
||||||
|
/>
|
||||||
<span class="text-gray-600"><strong>Anzahl Spiele:</strong> {{ system.anzahl_spiele }}</span>
|
<span class="text-gray-600"><strong>Anzahl Spiele:</strong> {{ system.anzahl_spiele }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="system.besonderheiten" class="flex items-center">
|
<div
|
||||||
<Star :size="14" class="text-primary-600 mr-2 flex-shrink-0" />
|
v-if="system.besonderheiten"
|
||||||
|
class="flex items-center"
|
||||||
|
>
|
||||||
|
<Star
|
||||||
|
:size="14"
|
||||||
|
class="text-primary-600 mr-2 flex-shrink-0"
|
||||||
|
/>
|
||||||
<span class="text-gray-600"><strong>Besonderheiten:</strong> {{ system.besonderheiten }}</span>
|
<span class="text-gray-600"><strong>Besonderheiten:</strong> {{ system.besonderheiten }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else class="text-center py-12 bg-white rounded-xl shadow-lg">
|
<div
|
||||||
<Settings :size="48" class="text-gray-400 mx-auto mb-4" />
|
v-else
|
||||||
<p class="text-gray-600">Keine Spielsysteme für die ausgewählte Kategorie gefunden.</p>
|
class="text-center py-12 bg-white rounded-xl shadow-lg"
|
||||||
|
>
|
||||||
|
<Settings
|
||||||
|
:size="48"
|
||||||
|
class="text-gray-400 mx-auto mb-4"
|
||||||
|
/>
|
||||||
|
<p class="text-gray-600">
|
||||||
|
Keine Spielsysteme für die ausgewählte Kategorie gefunden.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Zusätzliche Informationen -->
|
<!-- Zusätzliche Informationen -->
|
||||||
<div class="mt-12 bg-gradient-to-r from-primary-600 to-primary-700 rounded-xl p-8 text-white">
|
<div class="mt-12 bg-gradient-to-r from-primary-600 to-primary-700 rounded-xl p-8 text-white">
|
||||||
<h3 class="text-2xl font-display font-bold mb-6 flex items-center">
|
<h3 class="text-2xl font-display font-bold mb-6 flex items-center">
|
||||||
<BookOpen :size="28" class="mr-3" />
|
<BookOpen
|
||||||
|
:size="28"
|
||||||
|
class="mr-3"
|
||||||
|
/>
|
||||||
Weitere Informationen
|
Weitere Informationen
|
||||||
</h3>
|
</h3>
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
@@ -112,13 +147,15 @@
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
class="inline-flex items-center px-6 py-3 bg-white text-primary-600 font-semibold rounded-lg hover:bg-gray-100 transition-colors"
|
class="inline-flex items-center px-6 py-3 bg-white text-primary-600 font-semibold rounded-lg hover:bg-gray-100 transition-colors"
|
||||||
>
|
>
|
||||||
<ExternalLink :size="20" class="mr-2" />
|
<ExternalLink
|
||||||
|
:size="20"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
Detaillierte Erklärungen auf Wikiwand
|
Detaillierte Erklärungen auf Wikiwand
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -11,7 +11,10 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="naechsteTermine.length > 0" class="space-y-4">
|
<div
|
||||||
|
v-if="naechsteTermine.length > 0"
|
||||||
|
class="space-y-4"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
v-for="(termin, index) in naechsteTermine"
|
v-for="(termin, index) in naechsteTermine"
|
||||||
:key="index"
|
:key="index"
|
||||||
@@ -25,14 +28,22 @@
|
|||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<div class="flex items-start justify-between">
|
<div class="flex items-start justify-between">
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-xl font-semibold text-gray-900 mb-1">{{ termin.titel }}</h3>
|
<h3 class="text-xl font-semibold text-gray-900 mb-1">
|
||||||
<p class="text-gray-600 mb-2">{{ termin.beschreibung }}</p>
|
{{ termin.titel }}
|
||||||
<p class="text-sm text-gray-500">{{ formatFullDateTime(termin.datum, termin.uhrzeit) }}</p>
|
</h3>
|
||||||
|
<p class="text-gray-600 mb-2">
|
||||||
|
{{ termin.beschreibung }}
|
||||||
|
</p>
|
||||||
|
<p class="text-sm text-gray-500">
|
||||||
|
{{ formatFullDateTime(termin.datum, termin.uhrzeit) }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<span :class="[
|
<span
|
||||||
'px-3 py-1 text-sm font-medium rounded-full',
|
:class="[
|
||||||
termin.kategorie === 'Turnier' ? 'bg-yellow-100 text-yellow-800' : 'bg-blue-100 text-blue-800'
|
'px-3 py-1 text-sm font-medium rounded-full',
|
||||||
]">
|
termin.kategorie === 'Turnier' ? 'bg-yellow-100 text-yellow-800' : 'bg-blue-100 text-blue-800'
|
||||||
|
]"
|
||||||
|
>
|
||||||
{{ termin.kategorie }}
|
{{ termin.kategorie }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -41,9 +52,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else class="text-center py-16 bg-white rounded-xl shadow-lg">
|
<div
|
||||||
<Calendar :size="64" class="text-gray-400 mx-auto mb-4" />
|
v-else
|
||||||
<h3 class="text-2xl font-semibold text-gray-900 mb-2">Keine kommenden Termine</h3>
|
class="text-center py-16 bg-white rounded-xl shadow-lg"
|
||||||
|
>
|
||||||
|
<Calendar
|
||||||
|
:size="64"
|
||||||
|
class="text-gray-400 mx-auto mb-4"
|
||||||
|
/>
|
||||||
|
<h3 class="text-2xl font-semibold text-gray-900 mb-2">
|
||||||
|
Keine kommenden Termine
|
||||||
|
</h3>
|
||||||
<p class="text-gray-600">
|
<p class="text-gray-600">
|
||||||
Aktuell sind keine Termine geplant. Schauen Sie bald wieder vorbei!
|
Aktuell sind keine Termine geplant. Schauen Sie bald wieder vorbei!
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -17,37 +17,63 @@
|
|||||||
</h3>
|
</h3>
|
||||||
<ul class="space-y-3">
|
<ul class="space-y-3">
|
||||||
<li class="flex items-start">
|
<li class="flex items-start">
|
||||||
<Check :size="24" class="text-primary-600 mr-3 flex-shrink-0 mt-0.5" />
|
<Check
|
||||||
|
:size="24"
|
||||||
|
class="text-primary-600 mr-3 flex-shrink-0 mt-0.5"
|
||||||
|
/>
|
||||||
<span class="text-gray-700">Keine Vorkenntnisse nötig</span>
|
<span class="text-gray-700">Keine Vorkenntnisse nötig</span>
|
||||||
</li>
|
</li>
|
||||||
<li class="flex items-start">
|
<li class="flex items-start">
|
||||||
<Check :size="24" class="text-primary-600 mr-3 flex-shrink-0 mt-0.5" />
|
<Check
|
||||||
|
:size="24"
|
||||||
|
class="text-primary-600 mr-3 flex-shrink-0 mt-0.5"
|
||||||
|
/>
|
||||||
<span class="text-gray-700">Schläger und Material werden gestellt</span>
|
<span class="text-gray-700">Schläger und Material werden gestellt</span>
|
||||||
</li>
|
</li>
|
||||||
<li class="flex items-start">
|
<li class="flex items-start">
|
||||||
<Check :size="24" class="text-primary-600 mr-3 flex-shrink-0 mt-0.5" />
|
<Check
|
||||||
|
:size="24"
|
||||||
|
class="text-primary-600 mr-3 flex-shrink-0 mt-0.5"
|
||||||
|
/>
|
||||||
<span class="text-gray-700">Sportkleidung und Hallenschuhe mitbringen</span>
|
<span class="text-gray-700">Sportkleidung und Hallenschuhe mitbringen</span>
|
||||||
</li>
|
</li>
|
||||||
<li class="flex items-start">
|
<li class="flex items-start">
|
||||||
<Check :size="24" class="text-primary-600 mr-3 flex-shrink-0 mt-0.5" />
|
<Check
|
||||||
|
:size="24"
|
||||||
|
class="text-primary-600 mr-3 flex-shrink-0 mt-0.5"
|
||||||
|
/>
|
||||||
<span class="text-gray-700">3x kostenlos Probetraining</span>
|
<span class="text-gray-700">3x kostenlos Probetraining</span>
|
||||||
</li>
|
</li>
|
||||||
<li class="flex items-start">
|
<li class="flex items-start">
|
||||||
<Check :size="24" class="text-primary-600 mr-3 flex-shrink-0 mt-0.5" />
|
<Check
|
||||||
|
:size="24"
|
||||||
|
class="text-primary-600 mr-3 flex-shrink-0 mt-0.5"
|
||||||
|
/>
|
||||||
<span class="text-gray-700">Einstieg jederzeit möglich</span>
|
<span class="text-gray-700">Einstieg jederzeit möglich</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="config" class="bg-primary-50 p-8 rounded-xl border border-primary-100 not-prose">
|
<div
|
||||||
|
v-if="config"
|
||||||
|
class="bg-primary-50 p-8 rounded-xl border border-primary-100 not-prose"
|
||||||
|
>
|
||||||
<h3 class="text-2xl font-display font-bold text-gray-900 mb-4">
|
<h3 class="text-2xl font-display font-bold text-gray-900 mb-4">
|
||||||
Anfängergruppen
|
Anfängergruppen
|
||||||
</h3>
|
</h3>
|
||||||
<div class="space-y-4 mb-6">
|
<div class="space-y-4 mb-6">
|
||||||
<div v-for="(zeiten, gruppe) in groupedZeiten" :key="gruppe">
|
<div
|
||||||
<h4 class="font-semibold text-gray-900 mb-1">{{ gruppe }}</h4>
|
v-for="(zeiten, gruppe) in groupedZeiten"
|
||||||
|
:key="gruppe"
|
||||||
|
>
|
||||||
|
<h4 class="font-semibold text-gray-900 mb-1">
|
||||||
|
{{ gruppe }}
|
||||||
|
</h4>
|
||||||
<div class="text-gray-600">
|
<div class="text-gray-600">
|
||||||
<p v-for="zeit in zeiten" :key="zeit.id">
|
<p
|
||||||
|
v-for="zeit in zeiten"
|
||||||
|
:key="zeit.id"
|
||||||
|
>
|
||||||
{{ zeit.tag }}, {{ zeit.von }} - {{ zeit.bis }} Uhr
|
{{ zeit.tag }}, {{ zeit.von }} - {{ zeit.bis }} Uhr
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,22 +7,37 @@
|
|||||||
<div class="w-24 h-1 bg-primary-600 mb-8" />
|
<div class="w-24 h-1 bg-primary-600 mb-8" />
|
||||||
|
|
||||||
<!-- Trainingsort -->
|
<!-- Trainingsort -->
|
||||||
<div v-if="config" class="bg-white rounded-xl shadow-lg p-8 mb-12">
|
<div
|
||||||
|
v-if="config"
|
||||||
|
class="bg-white rounded-xl shadow-lg p-8 mb-12"
|
||||||
|
>
|
||||||
<div class="flex items-start space-x-4 mb-6">
|
<div class="flex items-start space-x-4 mb-6">
|
||||||
<MapPin :size="32" class="text-primary-600 flex-shrink-0" />
|
<MapPin
|
||||||
|
:size="32"
|
||||||
|
class="text-primary-600 flex-shrink-0"
|
||||||
|
/>
|
||||||
<div>
|
<div>
|
||||||
<h2 class="text-2xl font-display font-bold text-gray-900 mb-4">Trainingsort</h2>
|
<h2 class="text-2xl font-display font-bold text-gray-900 mb-4">
|
||||||
|
Trainingsort
|
||||||
|
</h2>
|
||||||
<h3 class="text-lg font-semibold text-gray-900 mb-2">
|
<h3 class="text-lg font-semibold text-gray-900 mb-2">
|
||||||
{{ config.training.ort.name }}
|
{{ config.training.ort.name }}
|
||||||
</h3>
|
</h3>
|
||||||
<p class="text-gray-700 mb-1">{{ config.training.ort.strasse }}</p>
|
<p class="text-gray-700 mb-1">
|
||||||
<p class="text-gray-700 mb-4">{{ config.training.ort.plz }} {{ config.training.ort.ort }}</p>
|
{{ config.training.ort.strasse }}
|
||||||
|
</p>
|
||||||
|
<p class="text-gray-700 mb-4">
|
||||||
|
{{ config.training.ort.plz }} {{ config.training.ort.ort }}
|
||||||
|
</p>
|
||||||
<a
|
<a
|
||||||
:href="`https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(config.training.ort.strasse + ' ' + config.training.ort.plz + ' ' + config.training.ort.ort)}`"
|
:href="`https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(config.training.ort.strasse + ' ' + config.training.ort.plz + ' ' + config.training.ort.ort)}`"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
class="inline-flex items-center px-4 py-2 bg-primary-600 hover:bg-primary-700 text-white font-medium rounded-lg transition-colors text-sm"
|
class="inline-flex items-center px-4 py-2 bg-primary-600 hover:bg-primary-700 text-white font-medium rounded-lg transition-colors text-sm"
|
||||||
>
|
>
|
||||||
<MapPin :size="16" class="mr-2" />
|
<MapPin
|
||||||
|
:size="16"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
Anfahrtsplan anzeigen
|
Anfahrtsplan anzeigen
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -34,7 +49,10 @@
|
|||||||
Trainingszeiten
|
Trainingszeiten
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<div v-if="config" class="grid gap-6 mb-12">
|
<div
|
||||||
|
v-if="config"
|
||||||
|
class="grid gap-6 mb-12"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
v-for="(zeiten, gruppe) in groupedZeiten"
|
v-for="(zeiten, gruppe) in groupedZeiten"
|
||||||
:key="gruppe"
|
:key="gruppe"
|
||||||
@@ -42,7 +60,9 @@
|
|||||||
>
|
>
|
||||||
<div class="flex items-start justify-between">
|
<div class="flex items-start justify-between">
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-xl font-display font-bold text-gray-900 mb-2">{{ gruppe }}</h3>
|
<h3 class="text-xl font-display font-bold text-gray-900 mb-2">
|
||||||
|
{{ gruppe }}
|
||||||
|
</h3>
|
||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
<div
|
<div
|
||||||
v-for="zeit in zeiten"
|
v-for="zeit in zeiten"
|
||||||
@@ -51,13 +71,19 @@
|
|||||||
<p class="text-lg font-semibold text-primary-600">
|
<p class="text-lg font-semibold text-primary-600">
|
||||||
{{ zeit.tag }}: {{ zeit.von }} - {{ zeit.bis }} Uhr
|
{{ zeit.tag }}: {{ zeit.von }} - {{ zeit.bis }} Uhr
|
||||||
</p>
|
</p>
|
||||||
<p v-if="zeit.info" class="text-sm text-gray-600 mt-1 italic">
|
<p
|
||||||
|
v-if="zeit.info"
|
||||||
|
class="text-sm text-gray-600 mt-1 italic"
|
||||||
|
>
|
||||||
{{ zeit.info }}
|
{{ zeit.info }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Clock :size="32" class="text-primary-600" />
|
<Clock
|
||||||
|
:size="32"
|
||||||
|
class="text-primary-600"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -10,29 +10,38 @@
|
|||||||
Erfahrene und qualifizierte Trainer für alle Leistungsstufen
|
Erfahrene und qualifizierte Trainer für alle Leistungsstufen
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div v-if="config" class="grid md:grid-cols-3 gap-8">
|
<div
|
||||||
|
v-if="config"
|
||||||
|
class="grid md:grid-cols-3 gap-8"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
v-for="trainer in config.trainer"
|
v-for="trainer in config.trainer"
|
||||||
:key="trainer.id"
|
:key="trainer.id"
|
||||||
class="bg-white p-8 rounded-xl shadow-lg"
|
class="bg-white p-8 rounded-xl shadow-lg"
|
||||||
>
|
>
|
||||||
<div v-if="trainer.imageFilename" class="mb-4 flex justify-center">
|
<div
|
||||||
|
v-if="trainer.imageFilename"
|
||||||
|
class="mb-4 flex justify-center"
|
||||||
|
>
|
||||||
<img
|
<img
|
||||||
:src="`/api/personen/${trainer.imageFilename}?width=200&height=200`"
|
:src="`/api/personen/${trainer.imageFilename}?width=200&height=200`"
|
||||||
:alt="trainer.name"
|
:alt="trainer.name"
|
||||||
class="w-32 h-32 object-cover rounded-full border-4 border-primary-100 shadow-md"
|
class="w-32 h-32 object-cover rounded-full border-4 border-primary-100 shadow-md"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
<h3 class="text-2xl font-display font-bold text-gray-900 mb-2">{{ trainer.lizenz }}</h3>
|
<h3 class="text-2xl font-display font-bold text-gray-900 mb-2">
|
||||||
<p class="text-gray-600 mb-4">{{ trainer.name }}</p>
|
{{ trainer.lizenz }}
|
||||||
|
</h3>
|
||||||
|
<p class="text-gray-600 mb-4">
|
||||||
|
{{ trainer.name }}
|
||||||
|
</p>
|
||||||
<p class="text-sm text-gray-500">
|
<p class="text-sm text-gray-500">
|
||||||
Lizenz: {{ trainer.lizenz }}<br />
|
Lizenz: {{ trainer.lizenz }}<br>
|
||||||
Schwerpunkt: {{ trainer.schwerpunkt }}<span v-if="trainer.zusatz"><br />{{ trainer.zusatz }}</span>
|
Schwerpunkt: {{ trainer.schwerpunkt }}<span v-if="trainer.zusatz"><br>{{ trainer.zusatz }}</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -16,11 +16,18 @@
|
|||||||
<div class="bg-white rounded-xl shadow-lg p-8 border border-gray-100 flex flex-col h-full">
|
<div class="bg-white rounded-xl shadow-lg p-8 border border-gray-100 flex flex-col h-full">
|
||||||
<div class="flex items-center mb-6">
|
<div class="flex items-center mb-6">
|
||||||
<div class="w-12 h-12 bg-gradient-to-br from-blue-500 to-blue-600 rounded-xl flex items-center justify-center mr-4">
|
<div class="w-12 h-12 bg-gradient-to-br from-blue-500 to-blue-600 rounded-xl flex items-center justify-center mr-4">
|
||||||
<Globe :size="24" class="text-white" />
|
<Globe
|
||||||
|
:size="24"
|
||||||
|
class="text-white"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h2 class="text-2xl font-display font-bold text-gray-900">Offizielles ITTF-Reglement</h2>
|
<h2 class="text-2xl font-display font-bold text-gray-900">
|
||||||
<p class="text-gray-600">Internationale Tischtennis-Regeln</p>
|
Offizielles ITTF-Reglement
|
||||||
|
</h2>
|
||||||
|
<p class="text-gray-600">
|
||||||
|
Internationale Tischtennis-Regeln
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -52,11 +59,18 @@
|
|||||||
<div class="bg-white rounded-xl shadow-lg p-8 border border-gray-100 flex flex-col h-full">
|
<div class="bg-white rounded-xl shadow-lg p-8 border border-gray-100 flex flex-col h-full">
|
||||||
<div class="flex items-center mb-6">
|
<div class="flex items-center mb-6">
|
||||||
<div class="w-12 h-12 bg-gradient-to-br from-primary-500 to-primary-600 rounded-xl flex items-center justify-center mr-4">
|
<div class="w-12 h-12 bg-gradient-to-br from-primary-500 to-primary-600 rounded-xl flex items-center justify-center mr-4">
|
||||||
<FileText :size="24" class="text-white" />
|
<FileText
|
||||||
|
:size="24"
|
||||||
|
class="text-white"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h2 class="text-2xl font-display font-bold text-gray-900">Tischtennis-Regeln Light</h2>
|
<h2 class="text-2xl font-display font-bold text-gray-900">
|
||||||
<p class="text-gray-600">Vereinfachte Übersicht</p>
|
Tischtennis-Regeln Light
|
||||||
|
</h2>
|
||||||
|
<p class="text-gray-600">
|
||||||
|
Vereinfachte Übersicht
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -91,9 +105,14 @@
|
|||||||
<div class="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
|
<div class="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
<div class="text-center p-6 bg-gray-50 rounded-lg">
|
<div class="text-center p-6 bg-gray-50 rounded-lg">
|
||||||
<div class="w-16 h-16 bg-primary-100 rounded-full flex items-center justify-center mx-auto mb-4">
|
<div class="w-16 h-16 bg-primary-100 rounded-full flex items-center justify-center mx-auto mb-4">
|
||||||
<Target :size="32" class="text-primary-600" />
|
<Target
|
||||||
|
:size="32"
|
||||||
|
class="text-primary-600"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h3 class="text-xl font-semibold text-gray-900 mb-2">Spielfeld</h3>
|
<h3 class="text-xl font-semibold text-gray-900 mb-2">
|
||||||
|
Spielfeld
|
||||||
|
</h3>
|
||||||
<p class="text-gray-600 text-sm">
|
<p class="text-gray-600 text-sm">
|
||||||
Tisch: 2,74m × 1,525m, Höhe: 76cm<br>
|
Tisch: 2,74m × 1,525m, Höhe: 76cm<br>
|
||||||
Netz: 15,25cm hoch
|
Netz: 15,25cm hoch
|
||||||
@@ -102,9 +121,14 @@
|
|||||||
|
|
||||||
<div class="text-center p-6 bg-gray-50 rounded-lg">
|
<div class="text-center p-6 bg-gray-50 rounded-lg">
|
||||||
<div class="w-16 h-16 bg-primary-100 rounded-full flex items-center justify-center mx-auto mb-4">
|
<div class="w-16 h-16 bg-primary-100 rounded-full flex items-center justify-center mx-auto mb-4">
|
||||||
<Circle :size="32" class="text-primary-600" />
|
<Circle
|
||||||
|
:size="32"
|
||||||
|
class="text-primary-600"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h3 class="text-xl font-semibold text-gray-900 mb-2">Ball</h3>
|
<h3 class="text-xl font-semibold text-gray-900 mb-2">
|
||||||
|
Ball
|
||||||
|
</h3>
|
||||||
<p class="text-gray-600 text-sm">
|
<p class="text-gray-600 text-sm">
|
||||||
Durchmesser: 40mm<br>
|
Durchmesser: 40mm<br>
|
||||||
Gewicht: 2,7g
|
Gewicht: 2,7g
|
||||||
@@ -113,9 +137,14 @@
|
|||||||
|
|
||||||
<div class="text-center p-6 bg-gray-50 rounded-lg">
|
<div class="text-center p-6 bg-gray-50 rounded-lg">
|
||||||
<div class="w-16 h-16 bg-primary-100 rounded-full flex items-center justify-center mx-auto mb-4">
|
<div class="w-16 h-16 bg-primary-100 rounded-full flex items-center justify-center mx-auto mb-4">
|
||||||
<Zap :size="32" class="text-primary-600" />
|
<Zap
|
||||||
|
:size="32"
|
||||||
|
class="text-primary-600"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h3 class="text-xl font-semibold text-gray-900 mb-2">Schläger</h3>
|
<h3 class="text-xl font-semibold text-gray-900 mb-2">
|
||||||
|
Schläger
|
||||||
|
</h3>
|
||||||
<p class="text-gray-600 text-sm">
|
<p class="text-gray-600 text-sm">
|
||||||
Belag: schwarz + farbig<br>
|
Belag: schwarz + farbig<br>
|
||||||
(rot, grün, pink, blau, gelb, lila)<br>
|
(rot, grün, pink, blau, gelb, lila)<br>
|
||||||
@@ -125,9 +154,14 @@
|
|||||||
|
|
||||||
<div class="text-center p-6 bg-gray-50 rounded-lg">
|
<div class="text-center p-6 bg-gray-50 rounded-lg">
|
||||||
<div class="w-16 h-16 bg-primary-100 rounded-full flex items-center justify-center mx-auto mb-4">
|
<div class="w-16 h-16 bg-primary-100 rounded-full flex items-center justify-center mx-auto mb-4">
|
||||||
<Play :size="32" class="text-primary-600" />
|
<Play
|
||||||
|
:size="32"
|
||||||
|
class="text-primary-600"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h3 class="text-xl font-semibold text-gray-900 mb-2">Aufschlag</h3>
|
<h3 class="text-xl font-semibold text-gray-900 mb-2">
|
||||||
|
Aufschlag
|
||||||
|
</h3>
|
||||||
<p class="text-gray-600 text-sm">
|
<p class="text-gray-600 text-sm">
|
||||||
Ball muss sichtbar hochgeworfen werden<br>
|
Ball muss sichtbar hochgeworfen werden<br>
|
||||||
Mindestens 16cm Höhe
|
Mindestens 16cm Höhe
|
||||||
@@ -136,9 +170,14 @@
|
|||||||
|
|
||||||
<div class="text-center p-6 bg-gray-50 rounded-lg">
|
<div class="text-center p-6 bg-gray-50 rounded-lg">
|
||||||
<div class="w-16 h-16 bg-primary-100 rounded-full flex items-center justify-center mx-auto mb-4">
|
<div class="w-16 h-16 bg-primary-100 rounded-full flex items-center justify-center mx-auto mb-4">
|
||||||
<Trophy :size="32" class="text-primary-600" />
|
<Trophy
|
||||||
|
:size="32"
|
||||||
|
class="text-primary-600"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h3 class="text-xl font-semibold text-gray-900 mb-2">Satz</h3>
|
<h3 class="text-xl font-semibold text-gray-900 mb-2">
|
||||||
|
Satz
|
||||||
|
</h3>
|
||||||
<p class="text-gray-600 text-sm">
|
<p class="text-gray-600 text-sm">
|
||||||
Gewinn bei 11 Punkten<br>
|
Gewinn bei 11 Punkten<br>
|
||||||
Mindestens 2 Punkte Vorsprung
|
Mindestens 2 Punkte Vorsprung
|
||||||
@@ -147,9 +186,14 @@
|
|||||||
|
|
||||||
<div class="text-center p-6 bg-gray-50 rounded-lg">
|
<div class="text-center p-6 bg-gray-50 rounded-lg">
|
||||||
<div class="w-16 h-16 bg-primary-100 rounded-full flex items-center justify-center mx-auto mb-4">
|
<div class="w-16 h-16 bg-primary-100 rounded-full flex items-center justify-center mx-auto mb-4">
|
||||||
<Users :size="32" class="text-primary-600" />
|
<Users
|
||||||
|
:size="32"
|
||||||
|
class="text-primary-600"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h3 class="text-xl font-semibold text-gray-900 mb-2">Spiel</h3>
|
<h3 class="text-xl font-semibold text-gray-900 mb-2">
|
||||||
|
Spiel
|
||||||
|
</h3>
|
||||||
<p class="text-gray-600 text-sm">
|
<p class="text-gray-600 text-sm">
|
||||||
Best of 5 oder 7 Sätze<br>
|
Best of 5 oder 7 Sätze<br>
|
||||||
Wechsel alle 2 Punkte
|
Wechsel alle 2 Punkte
|
||||||
@@ -161,7 +205,10 @@
|
|||||||
<!-- Zusätzliche Informationen -->
|
<!-- Zusätzliche Informationen -->
|
||||||
<div class="bg-gradient-to-r from-primary-600 to-primary-700 rounded-xl p-8 text-white">
|
<div class="bg-gradient-to-r from-primary-600 to-primary-700 rounded-xl p-8 text-white">
|
||||||
<h3 class="text-2xl font-display font-bold mb-6 flex items-center">
|
<h3 class="text-2xl font-display font-bold mb-6 flex items-center">
|
||||||
<BookOpen :size="28" class="mr-3" />
|
<BookOpen
|
||||||
|
:size="28"
|
||||||
|
class="mr-3"
|
||||||
|
/>
|
||||||
Weitere Informationen
|
Weitere Informationen
|
||||||
</h3>
|
</h3>
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
@@ -172,7 +219,11 @@
|
|||||||
</p>
|
</p>
|
||||||
<p class="text-primary-100 leading-relaxed">
|
<p class="text-primary-100 leading-relaxed">
|
||||||
Bei Fragen zu spezifischen Regeln wenden Sie sich an den
|
Bei Fragen zu spezifischen Regeln wenden Sie sich an den
|
||||||
<a href="https://www.tischtennis.de" target="_blank" class="underline hover:text-white">
|
<a
|
||||||
|
href="https://www.tischtennis.de"
|
||||||
|
target="_blank"
|
||||||
|
class="underline hover:text-white"
|
||||||
|
>
|
||||||
Deutschen Tischtennis-Bund (DTTB)
|
Deutschen Tischtennis-Bund (DTTB)
|
||||||
</a> oder Ihren regionalen Verband.
|
</a> oder Ihren regionalen Verband.
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -6,12 +6,22 @@
|
|||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<!-- Galerie-Grid -->
|
<!-- Galerie-Grid -->
|
||||||
<div v-if="loading" class="text-center py-12">
|
<div
|
||||||
<p class="text-gray-500">Bilder werden geladen...</p>
|
v-if="loading"
|
||||||
|
class="text-center py-12"
|
||||||
|
>
|
||||||
|
<p class="text-gray-500">
|
||||||
|
Bilder werden geladen...
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else-if="images.length === 0" class="text-center py-12">
|
<div
|
||||||
<p class="text-gray-500">Noch keine Bilder in der Galerie.</p>
|
v-else-if="images.length === 0"
|
||||||
|
class="text-center py-12"
|
||||||
|
>
|
||||||
|
<p class="text-gray-500">
|
||||||
|
Noch keine Bilder in der Galerie.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else>
|
<div v-else>
|
||||||
@@ -32,10 +42,15 @@
|
|||||||
class="object-cover group-hover:scale-105 transition-transform duration-300 pointer-events-none"
|
class="object-cover group-hover:scale-105 transition-transform duration-300 pointer-events-none"
|
||||||
style="max-width: 150px; max-height: 150px; width: auto; height: auto;"
|
style="max-width: 150px; max-height: 150px; width: auto; height: auto;"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
<h3 class="font-semibold text-gray-900 mb-1 cursor-pointer" @click="openModal(image)">{{ image.title }}</h3>
|
<h3
|
||||||
|
class="font-semibold text-gray-900 mb-1 cursor-pointer"
|
||||||
|
@click="openModal(image)"
|
||||||
|
>
|
||||||
|
{{ image.title }}
|
||||||
|
</h3>
|
||||||
<div class="mt-2 flex items-center justify-between">
|
<div class="mt-2 flex items-center justify-between">
|
||||||
<span
|
<span
|
||||||
v-if="!image.isPublic"
|
v-if="!image.isPublic"
|
||||||
@@ -50,9 +65,9 @@
|
|||||||
<!-- Lösch-Button für Admins -->
|
<!-- Lösch-Button für Admins -->
|
||||||
<button
|
<button
|
||||||
v-if="isAdmin || isVorstand"
|
v-if="isAdmin || isVorstand"
|
||||||
@click.stop="deleteImage(image.id)"
|
|
||||||
:disabled="deleting === image.id"
|
:disabled="deleting === image.id"
|
||||||
class="mt-2 w-full px-3 py-1.5 text-sm bg-red-600 text-white rounded hover:bg-red-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
class="mt-2 w-full px-3 py-1.5 text-sm bg-red-600 text-white rounded hover:bg-red-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
||||||
|
@click.stop="deleteImage(image.id)"
|
||||||
>
|
>
|
||||||
{{ deleting === image.id ? 'Wird gelöscht...' : 'Löschen' }}
|
{{ deleting === image.id ? 'Wird gelöscht...' : 'Löschen' }}
|
||||||
</button>
|
</button>
|
||||||
@@ -61,11 +76,14 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Pagination -->
|
<!-- Pagination -->
|
||||||
<div v-if="pagination.totalPages > 1" class="flex justify-center items-center space-x-2 mb-8">
|
<div
|
||||||
|
v-if="pagination.totalPages > 1"
|
||||||
|
class="flex justify-center items-center space-x-2 mb-8"
|
||||||
|
>
|
||||||
<button
|
<button
|
||||||
@click="changePage(pagination.page - 1)"
|
|
||||||
:disabled="pagination.page === 1"
|
:disabled="pagination.page === 1"
|
||||||
class="px-4 py-2 border border-gray-300 rounded-lg hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
class="px-4 py-2 border border-gray-300 rounded-lg hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
||||||
|
@click="changePage(pagination.page - 1)"
|
||||||
>
|
>
|
||||||
Zurück
|
Zurück
|
||||||
</button>
|
</button>
|
||||||
@@ -73,9 +91,9 @@
|
|||||||
Seite {{ pagination.page }} von {{ pagination.totalPages }} ({{ pagination.total }} Bilder)
|
Seite {{ pagination.page }} von {{ pagination.totalPages }} ({{ pagination.total }} Bilder)
|
||||||
</span>
|
</span>
|
||||||
<button
|
<button
|
||||||
@click="changePage(pagination.page + 1)"
|
|
||||||
:disabled="pagination.page >= pagination.totalPages"
|
:disabled="pagination.page >= pagination.totalPages"
|
||||||
class="px-4 py-2 border border-gray-300 rounded-lg hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
class="px-4 py-2 border border-gray-300 rounded-lg hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
||||||
|
@click="changePage(pagination.page + 1)"
|
||||||
>
|
>
|
||||||
Weiter
|
Weiter
|
||||||
</button>
|
</button>
|
||||||
@@ -83,12 +101,17 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Upload-Bereich für Admins (Collapsible) -->
|
<!-- Upload-Bereich für Admins (Collapsible) -->
|
||||||
<div v-if="isAdmin || isVorstand" class="mt-12">
|
<div
|
||||||
|
v-if="isAdmin || isVorstand"
|
||||||
|
class="mt-12"
|
||||||
|
>
|
||||||
<button
|
<button
|
||||||
@click="showUploadForm = !showUploadForm"
|
|
||||||
class="w-full flex items-center justify-between p-4 bg-gray-50 rounded-lg border-2 border-dashed border-gray-300 hover:bg-gray-100 transition-colors"
|
class="w-full flex items-center justify-between p-4 bg-gray-50 rounded-lg border-2 border-dashed border-gray-300 hover:bg-gray-100 transition-colors"
|
||||||
|
@click="showUploadForm = !showUploadForm"
|
||||||
>
|
>
|
||||||
<h2 class="text-xl font-semibold text-gray-900">Bild hochladen</h2>
|
<h2 class="text-xl font-semibold text-gray-900">
|
||||||
|
Bild hochladen
|
||||||
|
</h2>
|
||||||
<svg
|
<svg
|
||||||
class="w-6 h-6 text-gray-600 transition-transform"
|
class="w-6 h-6 text-gray-600 transition-transform"
|
||||||
:class="{ 'rotate-180': showUploadForm }"
|
:class="{ 'rotate-180': showUploadForm }"
|
||||||
@@ -96,23 +119,34 @@
|
|||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
>
|
>
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M19 9l-7 7-7-7"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<div v-if="showUploadForm" class="mt-4 p-6 bg-gray-50 rounded-lg border border-gray-300">
|
<div
|
||||||
<form @submit.prevent="uploadImage" class="space-y-4">
|
v-if="showUploadForm"
|
||||||
|
class="mt-4 p-6 bg-gray-50 rounded-lg border border-gray-300"
|
||||||
|
>
|
||||||
|
<form
|
||||||
|
class="space-y-4"
|
||||||
|
@submit.prevent="uploadImage"
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">
|
<label class="block text-sm font-medium text-gray-700 mb-2">
|
||||||
Bilddatei
|
Bilddatei
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="file"
|
|
||||||
ref="fileInput"
|
ref="fileInput"
|
||||||
@change="handleFileSelect"
|
type="file"
|
||||||
accept="image/jpeg,image/jpg,image/png,image/gif,image/webp"
|
accept="image/jpeg,image/jpg,image/png,image/gif,image/webp"
|
||||||
class="block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-lg file:border-0 file:text-sm file:font-semibold file:bg-primary-600 file:text-white hover:file:bg-primary-700"
|
class="block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-lg file:border-0 file:text-sm file:font-semibold file:bg-primary-600 file:text-white hover:file:bg-primary-700"
|
||||||
required
|
required
|
||||||
/>
|
@change="handleFileSelect"
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">
|
<label class="block text-sm font-medium text-gray-700 mb-2">
|
||||||
@@ -124,7 +158,7 @@
|
|||||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent"
|
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent"
|
||||||
placeholder="Titel des Bildes"
|
placeholder="Titel des Bildes"
|
||||||
required
|
required
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-2">
|
<label class="block text-sm font-medium text-gray-700 mb-2">
|
||||||
@@ -139,12 +173,15 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<input
|
<input
|
||||||
|
id="isPublic"
|
||||||
v-model="uploadForm.isPublic"
|
v-model="uploadForm.isPublic"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
id="isPublic"
|
|
||||||
class="h-4 w-4 text-primary-600 focus:ring-primary-500 border-gray-300 rounded"
|
class="h-4 w-4 text-primary-600 focus:ring-primary-500 border-gray-300 rounded"
|
||||||
/>
|
>
|
||||||
<label for="isPublic" class="ml-2 block text-sm text-gray-700">
|
<label
|
||||||
|
for="isPublic"
|
||||||
|
class="ml-2 block text-sm text-gray-700"
|
||||||
|
>
|
||||||
Öffentlich sichtbar (für alle Besucher)
|
Öffentlich sichtbar (für alle Besucher)
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
@@ -155,8 +192,18 @@
|
|||||||
>
|
>
|
||||||
{{ uploading ? 'Wird hochgeladen...' : 'Bild hochladen' }}
|
{{ uploading ? 'Wird hochgeladen...' : 'Bild hochladen' }}
|
||||||
</button>
|
</button>
|
||||||
<p v-if="uploadError" class="text-red-600 text-sm">{{ uploadError }}</p>
|
<p
|
||||||
<p v-if="uploadSuccess" class="text-green-600 text-sm">{{ uploadSuccess }}</p>
|
v-if="uploadError"
|
||||||
|
class="text-red-600 text-sm"
|
||||||
|
>
|
||||||
|
{{ uploadError }}
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
v-if="uploadSuccess"
|
||||||
|
class="text-green-600 text-sm"
|
||||||
|
>
|
||||||
|
{{ uploadSuccess }}
|
||||||
|
</p>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -167,38 +214,71 @@
|
|||||||
class="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-90 p-4"
|
class="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-90 p-4"
|
||||||
@click="closeModal"
|
@click="closeModal"
|
||||||
>
|
>
|
||||||
<div class="relative max-w-5xl max-h-full w-full" @click.stop>
|
<div
|
||||||
|
class="relative max-w-5xl max-h-full w-full"
|
||||||
|
@click.stop
|
||||||
|
>
|
||||||
<!-- Schließen-Button -->
|
<!-- Schließen-Button -->
|
||||||
<button
|
<button
|
||||||
@click="closeModal"
|
|
||||||
class="absolute top-4 right-4 text-white hover:text-gray-300 z-10 bg-black bg-opacity-50 rounded-full p-2"
|
class="absolute top-4 right-4 text-white hover:text-gray-300 z-10 bg-black bg-opacity-50 rounded-full p-2"
|
||||||
|
@click="closeModal"
|
||||||
>
|
>
|
||||||
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
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>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!-- Vorheriges Bild Button -->
|
<!-- Vorheriges Bild Button -->
|
||||||
<button
|
<button
|
||||||
v-if="hasPreviousImage"
|
v-if="hasPreviousImage"
|
||||||
@click.stop="showPreviousImage"
|
|
||||||
class="absolute left-4 top-1/2 -translate-y-1/2 text-white hover:text-gray-300 z-10 bg-black bg-opacity-50 rounded-full p-3"
|
class="absolute left-4 top-1/2 -translate-y-1/2 text-white hover:text-gray-300 z-10 bg-black bg-opacity-50 rounded-full p-3"
|
||||||
aria-label="Vorheriges Bild"
|
aria-label="Vorheriges Bild"
|
||||||
|
@click.stop="showPreviousImage"
|
||||||
>
|
>
|
||||||
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
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="M15 19l-7-7 7-7"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!-- Nächstes Bild Button -->
|
<!-- Nächstes Bild Button -->
|
||||||
<button
|
<button
|
||||||
v-if="hasNextImage"
|
v-if="hasNextImage"
|
||||||
@click.stop="showNextImage"
|
|
||||||
class="absolute right-4 top-1/2 -translate-y-1/2 text-white hover:text-gray-300 z-10 bg-black bg-opacity-50 rounded-full p-3"
|
class="absolute right-4 top-1/2 -translate-y-1/2 text-white hover:text-gray-300 z-10 bg-black bg-opacity-50 rounded-full p-3"
|
||||||
aria-label="Nächstes Bild"
|
aria-label="Nächstes Bild"
|
||||||
|
@click.stop="showNextImage"
|
||||||
>
|
>
|
||||||
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
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="M9 5l7 7-7 7"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
@@ -206,10 +286,15 @@
|
|||||||
:src="`/api/galerie/${selectedImage.id}`"
|
:src="`/api/galerie/${selectedImage.id}`"
|
||||||
:alt="selectedImage.title"
|
:alt="selectedImage.title"
|
||||||
class="max-w-[90%] max-h-[90vh] object-contain mx-auto"
|
class="max-w-[90%] max-h-[90vh] object-contain mx-auto"
|
||||||
/>
|
>
|
||||||
<div class="mt-4 text-white text-center">
|
<div class="mt-4 text-white text-center">
|
||||||
<h3 class="text-xl font-semibold">{{ selectedImage.title }}</h3>
|
<h3 class="text-xl font-semibold">
|
||||||
<p v-if="selectedImage.description" class="mt-2 text-gray-300">
|
{{ selectedImage.title }}
|
||||||
|
</h3>
|
||||||
|
<p
|
||||||
|
v-if="selectedImage.description"
|
||||||
|
class="mt-2 text-gray-300"
|
||||||
|
>
|
||||||
{{ selectedImage.description }}
|
{{ selectedImage.description }}
|
||||||
</p>
|
</p>
|
||||||
<p class="mt-2 text-sm text-gray-400">
|
<p class="mt-2 text-sm text-gray-400">
|
||||||
|
|||||||
@@ -4,7 +4,10 @@
|
|||||||
<h1 class="text-4xl sm:text-5xl font-display font-bold text-gray-900 mb-6">
|
<h1 class="text-4xl sm:text-5xl font-display font-bold text-gray-900 mb-6">
|
||||||
Geschichte
|
Geschichte
|
||||||
</h1>
|
</h1>
|
||||||
<div class="prose prose-lg max-w-none" v-html="content" />
|
<div
|
||||||
|
class="prose prose-lg max-w-none"
|
||||||
|
v-html="content"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -5,17 +5,35 @@
|
|||||||
Satzung
|
Satzung
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div class="prose prose-lg max-w-none mb-8" v-html="content" />
|
<div
|
||||||
|
class="prose prose-lg max-w-none mb-8"
|
||||||
|
v-html="content"
|
||||||
|
/>
|
||||||
|
|
||||||
<div v-if="pdfUrl" class="mt-8 p-6 bg-gray-50 rounded-lg">
|
<div
|
||||||
<h3 class="text-lg font-semibold mb-4">PDF-Download</h3>
|
v-if="pdfUrl"
|
||||||
|
class="mt-8 p-6 bg-gray-50 rounded-lg"
|
||||||
|
>
|
||||||
|
<h3 class="text-lg font-semibold mb-4">
|
||||||
|
PDF-Download
|
||||||
|
</h3>
|
||||||
<a
|
<a
|
||||||
:href="pdfUrl"
|
:href="pdfUrl"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
class="inline-flex items-center px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700"
|
class="inline-flex items-center px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700"
|
||||||
>
|
>
|
||||||
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
class="w-5 h-5 mr-2"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
Satzung als PDF herunterladen
|
Satzung als PDF herunterladen
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -4,7 +4,10 @@
|
|||||||
<h1 class="text-4xl sm:text-5xl font-display font-bold text-gray-900 mb-6">
|
<h1 class="text-4xl sm:text-5xl font-display font-bold text-gray-900 mb-6">
|
||||||
TT-Regeln
|
TT-Regeln
|
||||||
</h1>
|
</h1>
|
||||||
<div class="prose prose-lg max-w-none" v-html="content" />
|
<div
|
||||||
|
class="prose prose-lg max-w-none"
|
||||||
|
v-html="content"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -4,10 +4,12 @@
|
|||||||
<h1 class="text-4xl sm:text-5xl font-display font-bold text-gray-900 mb-6">
|
<h1 class="text-4xl sm:text-5xl font-display font-bold text-gray-900 mb-6">
|
||||||
Über uns
|
Über uns
|
||||||
</h1>
|
</h1>
|
||||||
<div class="prose prose-lg max-w-none" v-html="content" />
|
<div
|
||||||
|
class="prose prose-lg max-w-none"
|
||||||
|
v-html="content"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
|||||||
@@ -15,54 +15,70 @@
|
|||||||
<button
|
<button
|
||||||
v-for="jahr in verfuegbareJahre"
|
v-for="jahr in verfuegbareJahre"
|
||||||
:key="jahr"
|
:key="jahr"
|
||||||
@click="selectedYear = jahr"
|
|
||||||
:class="[
|
:class="[
|
||||||
'px-4 py-2 rounded-lg font-medium transition-colors',
|
'px-4 py-2 rounded-lg font-medium transition-colors',
|
||||||
selectedYear === jahr
|
selectedYear === jahr
|
||||||
? 'bg-primary-600 text-white'
|
? 'bg-primary-600 text-white'
|
||||||
: 'bg-white text-gray-700 hover:bg-gray-100 border border-gray-300'
|
: 'bg-white text-gray-700 hover:bg-gray-100 border border-gray-300'
|
||||||
]"
|
]"
|
||||||
|
@click="selectedYear = jahr"
|
||||||
>
|
>
|
||||||
{{ jahr }}
|
{{ jahr }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@click="selectedYear = 'alle'"
|
|
||||||
:class="[
|
:class="[
|
||||||
'px-4 py-2 rounded-lg font-medium transition-colors',
|
'px-4 py-2 rounded-lg font-medium transition-colors',
|
||||||
selectedYear === 'alle'
|
selectedYear === 'alle'
|
||||||
? 'bg-primary-600 text-white'
|
? 'bg-primary-600 text-white'
|
||||||
: 'bg-white text-gray-700 hover:bg-gray-100 border border-gray-300'
|
: 'bg-white text-gray-700 hover:bg-gray-100 border border-gray-300'
|
||||||
]"
|
]"
|
||||||
|
@click="selectedYear = 'alle'"
|
||||||
>
|
>
|
||||||
Alle Jahre
|
Alle Jahre
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Ergebnisse -->
|
<!-- Ergebnisse -->
|
||||||
<div v-if="filteredResults.length > 0" class="space-y-8">
|
<div
|
||||||
|
v-if="filteredResults.length > 0"
|
||||||
|
class="space-y-8"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
v-for="jahr in sortedJahre"
|
v-for="jahr in sortedJahre"
|
||||||
:key="jahr"
|
:key="jahr"
|
||||||
class="bg-white rounded-xl shadow-lg p-6"
|
class="bg-white rounded-xl shadow-lg p-6"
|
||||||
>
|
>
|
||||||
<h2 class="text-2xl font-display font-bold text-gray-900 mb-6 flex items-center">
|
<h2 class="text-2xl font-display font-bold text-gray-900 mb-6 flex items-center">
|
||||||
<Trophy :size="28" class="text-primary-600 mr-3" />
|
<Trophy
|
||||||
|
:size="28"
|
||||||
|
class="text-primary-600 mr-3"
|
||||||
|
/>
|
||||||
{{ jahr }}
|
{{ jahr }}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<!-- Besondere Bemerkungen -->
|
<!-- Besondere Bemerkungen -->
|
||||||
<div v-if="sortedGroupedResults[jahr]?.bemerkungen" class="mb-6 p-4 bg-yellow-50 border border-yellow-200 rounded-lg">
|
<div
|
||||||
<p class="text-yellow-800 font-medium">{{ sortedGroupedResults[jahr].bemerkungen }}</p>
|
v-if="sortedGroupedResults[jahr]?.bemerkungen"
|
||||||
|
class="mb-6 p-4 bg-yellow-50 border border-yellow-200 rounded-lg"
|
||||||
|
>
|
||||||
|
<p class="text-yellow-800 font-medium">
|
||||||
|
{{ sortedGroupedResults[jahr].bemerkungen }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Kategorien -->
|
<!-- Kategorien -->
|
||||||
<div v-if="sortedGroupedResults[jahr]?.kategorien" class="space-y-6">
|
<div
|
||||||
|
v-if="sortedGroupedResults[jahr]?.kategorien"
|
||||||
|
class="space-y-6"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
v-for="(kategorieData, kategorie) in sortedGroupedResults[jahr].kategorien"
|
v-for="(kategorieData, kategorie) in sortedGroupedResults[jahr].kategorien"
|
||||||
:key="kategorie"
|
:key="kategorie"
|
||||||
class="border-l-4 border-primary-600 pl-4"
|
class="border-l-4 border-primary-600 pl-4"
|
||||||
>
|
>
|
||||||
<h3 class="text-xl font-semibold text-gray-900 mb-4">{{ kategorie }}</h3>
|
<h3 class="text-xl font-semibold text-gray-900 mb-4">
|
||||||
|
{{ kategorie }}
|
||||||
|
</h3>
|
||||||
|
|
||||||
<div class="grid gap-3">
|
<div class="grid gap-3">
|
||||||
<div
|
<div
|
||||||
@@ -89,21 +105,30 @@
|
|||||||
{{ ergebnis.platz }}
|
{{ ergebnis.platz }}
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<div v-if="ergebnis.imageFilename1" class="flex-shrink-0">
|
<div
|
||||||
|
v-if="ergebnis.imageFilename1"
|
||||||
|
class="flex-shrink-0"
|
||||||
|
>
|
||||||
<img
|
<img
|
||||||
:src="`/api/personen/${ergebnis.imageFilename1}?width=40&height=40`"
|
:src="`/api/personen/${ergebnis.imageFilename1}?width=40&height=40`"
|
||||||
:alt="ergebnis.spieler1"
|
: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"
|
class="w-10 h-10 rounded-full object-cover border-2 border-gray-300 cursor-pointer hover:border-primary-500 transition-colors"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
@click="openLightbox(ergebnis.imageFilename1, ergebnis.spieler1)"
|
@click="openLightbox(ergebnis.imageFilename1, ergebnis.spieler1)"
|
||||||
/>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span class="font-semibold text-gray-900">
|
<span class="font-semibold text-gray-900">
|
||||||
{{ ergebnis.spieler1 }}
|
{{ ergebnis.spieler1 }}
|
||||||
</span>
|
</span>
|
||||||
<span v-if="ergebnis.spieler2" class="text-gray-600">
|
<span
|
||||||
<span v-if="ergebnis.imageFilename2" class="ml-2 inline-flex items-center gap-2">
|
v-if="ergebnis.spieler2"
|
||||||
|
class="text-gray-600"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
v-if="ergebnis.imageFilename2"
|
||||||
|
class="ml-2 inline-flex items-center gap-2"
|
||||||
|
>
|
||||||
/
|
/
|
||||||
<img
|
<img
|
||||||
:src="`/api/personen/${ergebnis.imageFilename2}?width=40&height=40`"
|
:src="`/api/personen/${ergebnis.imageFilename2}?width=40&height=40`"
|
||||||
@@ -111,10 +136,13 @@
|
|||||||
class="w-10 h-10 rounded-full object-cover border-2 border-gray-300 cursor-pointer hover:border-primary-500 transition-colors"
|
class="w-10 h-10 rounded-full object-cover border-2 border-gray-300 cursor-pointer hover:border-primary-500 transition-colors"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
@click="openLightbox(ergebnis.imageFilename2, ergebnis.spieler2)"
|
@click="openLightbox(ergebnis.imageFilename2, ergebnis.spieler2)"
|
||||||
/>
|
>
|
||||||
{{ ergebnis.spieler2 }}
|
{{ ergebnis.spieler2 }}
|
||||||
</span>
|
</span>
|
||||||
<span v-else class="text-gray-600">
|
<span
|
||||||
|
v-else
|
||||||
|
class="text-gray-600"
|
||||||
|
>
|
||||||
/ {{ ergebnis.spieler2 }}
|
/ {{ ergebnis.spieler2 }}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
@@ -131,26 +159,48 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else class="text-center py-12 bg-white rounded-xl shadow-lg">
|
<div
|
||||||
<Trophy :size="48" class="text-gray-400 mx-auto mb-4" />
|
v-else
|
||||||
<p class="text-gray-600">Keine Ergebnisse für das ausgewählte Jahr gefunden.</p>
|
class="text-center py-12 bg-white rounded-xl shadow-lg"
|
||||||
|
>
|
||||||
|
<Trophy
|
||||||
|
:size="48"
|
||||||
|
class="text-gray-400 mx-auto mb-4"
|
||||||
|
/>
|
||||||
|
<p class="text-gray-600">
|
||||||
|
Keine Ergebnisse für das ausgewählte Jahr gefunden.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Statistik -->
|
<!-- Statistik -->
|
||||||
<div class="mt-12 bg-gradient-to-r from-primary-600 to-primary-700 rounded-xl p-8 text-white">
|
<div class="mt-12 bg-gradient-to-r from-primary-600 to-primary-700 rounded-xl p-8 text-white">
|
||||||
<h3 class="text-2xl font-display font-bold mb-6">Statistik</h3>
|
<h3 class="text-2xl font-display font-bold mb-6">
|
||||||
|
Statistik
|
||||||
|
</h3>
|
||||||
<div class="grid md:grid-cols-3 gap-6">
|
<div class="grid md:grid-cols-3 gap-6">
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<div class="text-3xl font-bold mb-2">{{ verfuegbareJahre.length }}</div>
|
<div class="text-3xl font-bold mb-2">
|
||||||
<div class="text-primary-100">Jahre mit Meisterschaften</div>
|
{{ verfuegbareJahre.length }}
|
||||||
|
</div>
|
||||||
|
<div class="text-primary-100">
|
||||||
|
Jahre mit Meisterschaften
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<div class="text-3xl font-bold mb-2">{{ totalWinners }}</div>
|
<div class="text-3xl font-bold mb-2">
|
||||||
<div class="text-primary-100">Einzelgewinner</div>
|
{{ totalWinners }}
|
||||||
|
</div>
|
||||||
|
<div class="text-primary-100">
|
||||||
|
Einzelgewinner
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<div class="text-3xl font-bold mb-2">{{ totalDoubles }}</div>
|
<div class="text-3xl font-bold mb-2">
|
||||||
<div class="text-primary-100">Doppelgewinner</div>
|
{{ totalDoubles }}
|
||||||
|
</div>
|
||||||
|
<div class="text-primary-100">
|
||||||
|
Doppelgewinner
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -159,7 +209,10 @@
|
|||||||
<div class="mt-8 text-center">
|
<div class="mt-8 text-center">
|
||||||
<div class="bg-white rounded-xl shadow-lg p-8 border-l-4 border-primary-600">
|
<div class="bg-white rounded-xl shadow-lg p-8 border-l-4 border-primary-600">
|
||||||
<h3 class="text-2xl font-display font-bold text-gray-900 mb-4 flex items-center justify-center">
|
<h3 class="text-2xl font-display font-bold text-gray-900 mb-4 flex items-center justify-center">
|
||||||
<Trophy :size="32" class="text-primary-600 mr-3" />
|
<Trophy
|
||||||
|
:size="32"
|
||||||
|
class="text-primary-600 mr-3"
|
||||||
|
/>
|
||||||
Herzlichen Glückwunsch!
|
Herzlichen Glückwunsch!
|
||||||
</h3>
|
</h3>
|
||||||
<p class="text-lg text-gray-700 leading-relaxed">
|
<p class="text-lg text-gray-700 leading-relaxed">
|
||||||
@@ -176,19 +229,32 @@
|
|||||||
<div
|
<div
|
||||||
v-if="lightboxImage"
|
v-if="lightboxImage"
|
||||||
class="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-90 p-4"
|
class="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-90 p-4"
|
||||||
@click="closeLightbox"
|
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
|
@click="closeLightbox"
|
||||||
@keydown="handleLightboxKeydown"
|
@keydown="handleLightboxKeydown"
|
||||||
>
|
>
|
||||||
<div class="relative max-w-5xl max-h-full" @click.stop>
|
<div
|
||||||
|
class="relative max-w-5xl max-h-full"
|
||||||
|
@click.stop
|
||||||
|
>
|
||||||
<!-- Close Button -->
|
<!-- Close Button -->
|
||||||
<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"
|
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"
|
aria-label="Schließen"
|
||||||
|
@click="closeLightbox"
|
||||||
>
|
>
|
||||||
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
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>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
@@ -196,9 +262,11 @@
|
|||||||
:src="`/api/personen/${lightboxImage.filename}`"
|
:src="`/api/personen/${lightboxImage.filename}`"
|
||||||
:alt="lightboxImage.name"
|
:alt="lightboxImage.name"
|
||||||
class="max-w-[90%] max-h-[90vh] object-contain mx-auto"
|
class="max-w-[90%] max-h-[90vh] object-contain mx-auto"
|
||||||
/>
|
>
|
||||||
<div class="mt-4 text-white text-center">
|
<div class="mt-4 text-white text-center">
|
||||||
<h3 class="text-xl font-semibold">{{ lightboxImage.name }}</h3>
|
<h3 class="text-xl font-semibold">
|
||||||
|
{{ lightboxImage.name }}
|
||||||
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -11,7 +11,10 @@
|
|||||||
Unser engagiertes Vorstandsteam leitet den Harheimer TC mit Herz und Sachverstand.
|
Unser engagiertes Vorstandsteam leitet den Harheimer TC mit Herz und Sachverstand.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div v-if="config" class="grid md:grid-cols-2 gap-8 not-prose">
|
<div
|
||||||
|
v-if="config"
|
||||||
|
class="grid md:grid-cols-2 gap-8 not-prose"
|
||||||
|
>
|
||||||
<!-- Vorsitzender -->
|
<!-- Vorsitzender -->
|
||||||
<PersonCard
|
<PersonCard
|
||||||
v-if="config.vorstand.vorsitzender.vorname"
|
v-if="config.vorstand.vorsitzender.vorname"
|
||||||
@@ -19,11 +22,20 @@
|
|||||||
:name="`${config.vorstand.vorsitzender.vorname} ${config.vorstand.vorsitzender.nachname}`"
|
:name="`${config.vorstand.vorsitzender.vorname} ${config.vorstand.vorsitzender.nachname}`"
|
||||||
:image-filename="config.vorstand.vorsitzender.imageFilename"
|
:image-filename="config.vorstand.vorsitzender.imageFilename"
|
||||||
>
|
>
|
||||||
<p v-if="config.vorstand.vorsitzender.strasse">{{ config.vorstand.vorsitzender.strasse }}</p>
|
<p v-if="config.vorstand.vorsitzender.strasse">
|
||||||
<p v-if="config.vorstand.vorsitzender.plz">{{ config.vorstand.vorsitzender.plz }} {{ config.vorstand.vorsitzender.ort }}</p>
|
{{ config.vorstand.vorsitzender.strasse }}
|
||||||
<p v-if="config.vorstand.vorsitzender.telefon">Tel. {{ config.vorstand.vorsitzender.telefon }}</p>
|
</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">
|
<p v-if="config.vorstand.vorsitzender.email">
|
||||||
<a :href="`mailto:${config.vorstand.vorsitzender.email}`" class="text-primary-600 hover:underline">
|
<a
|
||||||
|
:href="`mailto:${config.vorstand.vorsitzender.email}`"
|
||||||
|
class="text-primary-600 hover:underline"
|
||||||
|
>
|
||||||
{{ config.vorstand.vorsitzender.email }}
|
{{ config.vorstand.vorsitzender.email }}
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
@@ -36,11 +48,20 @@
|
|||||||
:name="`${config.vorstand.stellvertreter.vorname} ${config.vorstand.stellvertreter.nachname}`"
|
:name="`${config.vorstand.stellvertreter.vorname} ${config.vorstand.stellvertreter.nachname}`"
|
||||||
:image-filename="config.vorstand.stellvertreter.imageFilename"
|
:image-filename="config.vorstand.stellvertreter.imageFilename"
|
||||||
>
|
>
|
||||||
<p v-if="config.vorstand.stellvertreter.strasse">{{ config.vorstand.stellvertreter.strasse }}</p>
|
<p v-if="config.vorstand.stellvertreter.strasse">
|
||||||
<p v-if="config.vorstand.stellvertreter.plz">{{ config.vorstand.stellvertreter.plz }} {{ config.vorstand.stellvertreter.ort }}</p>
|
{{ config.vorstand.stellvertreter.strasse }}
|
||||||
<p v-if="config.vorstand.stellvertreter.telefon">Tel. {{ config.vorstand.stellvertreter.telefon }}</p>
|
</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">
|
<p v-if="config.vorstand.stellvertreter.email">
|
||||||
<a :href="`mailto:${config.vorstand.stellvertreter.email}`" class="text-primary-600 hover:underline">
|
<a
|
||||||
|
:href="`mailto:${config.vorstand.stellvertreter.email}`"
|
||||||
|
class="text-primary-600 hover:underline"
|
||||||
|
>
|
||||||
{{ config.vorstand.stellvertreter.email }}
|
{{ config.vorstand.stellvertreter.email }}
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
@@ -53,11 +74,20 @@
|
|||||||
:name="`${config.vorstand.kassenwart.vorname} ${config.vorstand.kassenwart.nachname}`"
|
:name="`${config.vorstand.kassenwart.vorname} ${config.vorstand.kassenwart.nachname}`"
|
||||||
:image-filename="config.vorstand.kassenwart.imageFilename"
|
:image-filename="config.vorstand.kassenwart.imageFilename"
|
||||||
>
|
>
|
||||||
<p v-if="config.vorstand.kassenwart.strasse">{{ config.vorstand.kassenwart.strasse }}</p>
|
<p v-if="config.vorstand.kassenwart.strasse">
|
||||||
<p v-if="config.vorstand.kassenwart.plz">{{ config.vorstand.kassenwart.plz }} {{ config.vorstand.kassenwart.ort }}</p>
|
{{ config.vorstand.kassenwart.strasse }}
|
||||||
<p v-if="config.vorstand.kassenwart.telefon">Tel. {{ config.vorstand.kassenwart.telefon }}</p>
|
</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">
|
<p v-if="config.vorstand.kassenwart.email">
|
||||||
<a :href="`mailto:${config.vorstand.kassenwart.email}`" class="text-primary-600 hover:underline">
|
<a
|
||||||
|
:href="`mailto:${config.vorstand.kassenwart.email}`"
|
||||||
|
class="text-primary-600 hover:underline"
|
||||||
|
>
|
||||||
{{ config.vorstand.kassenwart.email }}
|
{{ config.vorstand.kassenwart.email }}
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
@@ -70,11 +100,20 @@
|
|||||||
:name="`${config.vorstand.schriftfuehrer.vorname} ${config.vorstand.schriftfuehrer.nachname}`"
|
:name="`${config.vorstand.schriftfuehrer.vorname} ${config.vorstand.schriftfuehrer.nachname}`"
|
||||||
:image-filename="config.vorstand.schriftfuehrer.imageFilename"
|
:image-filename="config.vorstand.schriftfuehrer.imageFilename"
|
||||||
>
|
>
|
||||||
<p v-if="config.vorstand.schriftfuehrer.strasse">{{ config.vorstand.schriftfuehrer.strasse }}</p>
|
<p v-if="config.vorstand.schriftfuehrer.strasse">
|
||||||
<p v-if="config.vorstand.schriftfuehrer.plz">{{ config.vorstand.schriftfuehrer.plz }} {{ config.vorstand.schriftfuehrer.ort }}</p>
|
{{ config.vorstand.schriftfuehrer.strasse }}
|
||||||
<p v-if="config.vorstand.schriftfuehrer.telefon">Tel. {{ config.vorstand.schriftfuehrer.telefon }}</p>
|
</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">
|
<p v-if="config.vorstand.schriftfuehrer.email">
|
||||||
<a :href="`mailto:${config.vorstand.schriftfuehrer.email}`" class="text-primary-600 hover:underline">
|
<a
|
||||||
|
:href="`mailto:${config.vorstand.schriftfuehrer.email}`"
|
||||||
|
class="text-primary-600 hover:underline"
|
||||||
|
>
|
||||||
{{ config.vorstand.schriftfuehrer.email }}
|
{{ config.vorstand.schriftfuehrer.email }}
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
@@ -87,11 +126,20 @@
|
|||||||
:name="`${config.vorstand.sportwart.vorname} ${config.vorstand.sportwart.nachname}`"
|
:name="`${config.vorstand.sportwart.vorname} ${config.vorstand.sportwart.nachname}`"
|
||||||
:image-filename="config.vorstand.sportwart.imageFilename"
|
:image-filename="config.vorstand.sportwart.imageFilename"
|
||||||
>
|
>
|
||||||
<p v-if="config.vorstand.sportwart.strasse">{{ config.vorstand.sportwart.strasse }}</p>
|
<p v-if="config.vorstand.sportwart.strasse">
|
||||||
<p v-if="config.vorstand.sportwart.plz">{{ config.vorstand.sportwart.plz }} {{ config.vorstand.sportwart.ort }}</p>
|
{{ config.vorstand.sportwart.strasse }}
|
||||||
<p v-if="config.vorstand.sportwart.telefon">Tel. {{ config.vorstand.sportwart.telefon }}</p>
|
</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">
|
<p v-if="config.vorstand.sportwart.email">
|
||||||
<a :href="`mailto:${config.vorstand.sportwart.email}`" class="text-primary-600 hover:underline">
|
<a
|
||||||
|
:href="`mailto:${config.vorstand.sportwart.email}`"
|
||||||
|
class="text-primary-600 hover:underline"
|
||||||
|
>
|
||||||
{{ config.vorstand.sportwart.email }}
|
{{ config.vorstand.sportwart.email }}
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
@@ -104,11 +152,20 @@
|
|||||||
:name="`${config.vorstand.jugendwart.vorname} ${config.vorstand.jugendwart.nachname}`"
|
:name="`${config.vorstand.jugendwart.vorname} ${config.vorstand.jugendwart.nachname}`"
|
||||||
:image-filename="config.vorstand.jugendwart.imageFilename"
|
:image-filename="config.vorstand.jugendwart.imageFilename"
|
||||||
>
|
>
|
||||||
<p v-if="config.vorstand.jugendwart.strasse">{{ config.vorstand.jugendwart.strasse }}</p>
|
<p v-if="config.vorstand.jugendwart.strasse">
|
||||||
<p v-if="config.vorstand.jugendwart.plz">{{ config.vorstand.jugendwart.plz }} {{ config.vorstand.jugendwart.ort }}</p>
|
{{ config.vorstand.jugendwart.strasse }}
|
||||||
<p v-if="config.vorstand.jugendwart.telefon">Tel. {{ config.vorstand.jugendwart.telefon }}</p>
|
</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">
|
<p v-if="config.vorstand.jugendwart.email">
|
||||||
<a :href="`mailto:${config.vorstand.jugendwart.email}`" class="text-primary-600 hover:underline">
|
<a
|
||||||
|
:href="`mailto:${config.vorstand.jugendwart.email}`"
|
||||||
|
class="text-primary-600 hover:underline"
|
||||||
|
>
|
||||||
{{ config.vorstand.jugendwart.email }}
|
{{ config.vorstand.jugendwart.email }}
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
Reference in New Issue
Block a user