feat: add homepage components and API for settings and spielplan options

- Introduced new Vue components for homepage teasers: HomeLinksTeaser, HomeSpielplanTeamWidget, HomeTrainingTeaser, and HomeVereinsmeisterschaftenTeaser.
- Created XML layout for tablet app window dump.
- Implemented API endpoints for fetching and updating homepage settings.
- Added API for retrieving spielplan options, including team extraction logic.
This commit is contained in:
Torsten Schulz (local)
2026-05-29 15:37:45 +02:00
parent 1ea9596006
commit b8bdbf0a8d
39 changed files with 3867 additions and 163 deletions

View File

@@ -46,7 +46,7 @@
Verfügbare Elemente
</h2>
<p class="text-sm text-gray-600">
Ziehen Sie die Elemente per Drag & Drop oder verwenden Sie die Pfeil-Buttons, um die Reihenfolge zu ändern.
Legen Sie Reihenfolge, Sichtbarkeit und Marker fest (ohne Marker, cookie, eingeloggt).
</p>
</div>
@@ -110,13 +110,33 @@
</span>
</label>
</div>
<!-- Marker -->
<div class="flex items-center">
<label class="text-sm text-gray-700 mr-2">Marker</label>
<select
v-model="section.marker"
class="px-2 py-1 border border-gray-300 rounded-lg text-sm bg-white"
:disabled="isSaving"
>
<option value="">
keiner
</option>
<option value="cookie">
cookie
</option>
<option value="eingeloggt">
eingeloggt
</option>
</select>
</div>
</div>
</div>
<!-- Info Box -->
<div class="mt-6 p-4 bg-blue-50 border border-blue-200 rounded-lg">
<p class="text-sm text-blue-800">
<strong>Hinweis:</strong> Deaktivierte Elemente werden auf der Startseite nicht angezeigt, bleiben aber in der Konfiguration erhalten.
<strong>Hinweis:</strong> Marker steuern die Sichtbarkeit auf der Web-Startseite: cookie zeigt das Element bei vorhandenen Cookies, eingeloggt nur für angemeldete Nutzer.
</p>
</div>
@@ -166,6 +186,30 @@ const availableSections = {
kontakt: {
label: 'Kontakt-Boxen',
description: 'Mitglied werden & Kontakt aufnehmen'
},
training: {
label: 'Training-Teaser',
description: 'Direktzugang zu Training, Trainern und Anfängerbereich'
},
links: {
label: 'Links-Teaser',
description: 'Direktzugang zu den nützlichen Vereinslinks'
},
vereinsmeisterschaften: {
label: 'Vereinsmeisterschaften-Teaser',
description: 'Direktzugang zu Meisterschaftsergebnissen'
}
}
function normalizeMarker(marker) {
return marker === 'cookie' || marker === 'eingeloggt' ? marker : ''
}
function normalizeSection(section) {
return {
id: section?.id,
enabled: section?.enabled !== false,
marker: normalizeMarker(section?.marker)
}
}
@@ -185,17 +229,23 @@ const loadConfig = async () => {
// Standard-Reihenfolge, falls nicht vorhanden
const defaultSections = [
{ id: 'banner', enabled: true },
{ id: 'termine', enabled: true },
{ id: 'spiele', enabled: true },
{ id: 'aktuelles', enabled: true },
{ id: 'kontakt', enabled: true }
{ id: 'banner', enabled: true, marker: '' },
{ id: 'termine', enabled: true, marker: '' },
{ id: 'spiele', enabled: true, marker: '' },
{ id: 'aktuelles', enabled: true, marker: '' },
{ id: 'kontakt', enabled: true, marker: '' },
{ id: 'training', enabled: false, marker: '' },
{ id: 'links', enabled: false, marker: '' },
{ id: 'vereinsmeisterschaften', enabled: false, marker: '' }
]
if (config.homepage && config.homepage.sections && Array.isArray(config.homepage.sections)) {
// Validiere und merge: Nur bekannte IDs verwenden, fehlende hinzufügen
const knownIds = new Set(config.homepage.sections.map(s => s.id))
const merged = [...config.homepage.sections]
const normalized = config.homepage.sections
.filter(s => s?.id)
.map(normalizeSection)
const knownIds = new Set(normalized.map(s => s.id))
const merged = [...normalized]
// Füge fehlende Standard-Elemente hinzu
for (const defaultSection of defaultSections) {
@@ -204,9 +254,9 @@ const loadConfig = async () => {
}
}
sections.value = merged
sections.value = merged.map(normalizeSection)
} else {
sections.value = [...defaultSections]
sections.value = defaultSections.map(normalizeSection)
}
} catch (error) {
console.error('Fehler beim Laden der Konfiguration:', error)
@@ -242,7 +292,7 @@ const saveConfig = async () => {
if (!config.homepage) {
config.homepage = {}
}
config.homepage.sections = sections.value
config.homepage.sections = sections.value.map(normalizeSection)
// Speichere Config
await $fetch('/api/config', {