This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Papa-Kind-Treff – Projektkontext
|
||||
|
||||
Stand: 2026-08-05
|
||||
Stand: 2026-08-07
|
||||
|
||||
## Kurzbeschreibung
|
||||
Papa-Kind-Treff ist eine PHP-basierte Plattform für Väter. Kernbereiche sind lokale Events, Termine und Treffen, ein Community-Forum, Mitgliederprofile mit optionalen Kinderinfos und ein Moderations-/Adminbereich.
|
||||
@@ -23,6 +23,7 @@ Papa-Kind-Treff ist eine PHP-basierte Plattform für Väter. Kernbereiche sind l
|
||||
- Profiladresse kann per Suche oder Browser-Standort übernommen werden.
|
||||
- Der Bereich `Events` ist wieder auf echte eigene Events und Event-Teilnahmen begrenzt.
|
||||
- Der Bereich `Events` bietet zusätzlich einen manuellen ICS-Export und einen persönlichen abonnierbaren Kalender-Feed für alle eigenen Events und Event-Teilnahmen.
|
||||
- Der Bereich `Events` ist im UI in `Meine Events` und `Synchronisation` getrennt, damit Event-Verwaltung und Kalender-Themen sauberer getrennt bleiben.
|
||||
- Orte und Veranstaltungen als Ausflugsziele sind vorerst in einen separaten Mitgliederbereichspunkt `Ausflugsziele` verschoben.
|
||||
- Die Eingabe im Bereich `Events` soll so einfach wie möglich bleiben und zeigt deshalb nur die für echte Termine relevanten Felder.
|
||||
- Kategorien werden im Mitgliederbereich per Sucheingabe mit bestehenden Vorschlägen und automatischer Neuanlage gepflegt.
|
||||
@@ -39,6 +40,10 @@ Papa-Kind-Treff ist eine PHP-basierte Plattform für Väter. Kernbereiche sind l
|
||||
- Ziel: spätere Unterscheidung zwischen eigenem Event, Partner-Angebot, allgemeinem Ort und redaktionellem Termin
|
||||
- Google ist noch nicht aktiv integriert; das System wird nur vorbereitend über Settings und Datenfelder darauf ausgelegt
|
||||
|
||||
## Vorgemerkte To-dos
|
||||
- Kalender-Integration großer Anbieter soll später zusätzlich zum ICS-Feed kommen, zuerst vor allem für Google und Microsoft/Outlook.
|
||||
- Zielbild dafür ist keine Rücksynchronisierung, sondern ein nutzerseitiges OAuth-Login über Papa-Kind-Treff und danach eine direkte Kalender-Verknüpfung oder Event-Synchronisierung beim jeweiligen Anbieter.
|
||||
|
||||
## Pflegehinweis
|
||||
Bei Änderungen immer auch die parallelen Dateien in `Internal/en/` prüfen und inhaltlich gleichziehen.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Papa-Kind-Treff – Project Context
|
||||
|
||||
Updated: 2026-08-05
|
||||
Updated: 2026-08-07
|
||||
|
||||
## Summary
|
||||
Papa-Kind-Treff is a PHP-based platform for fathers. Core areas are local events, appointments, and meetups, a community forum, member profiles with optional child information, and a moderation/admin area.
|
||||
@@ -23,6 +23,7 @@ Papa-Kind-Treff is a PHP-based platform for fathers. Core areas are local events
|
||||
- Profile address can be completed via address search or browser-based location import.
|
||||
- The `Events` area is limited again to real own events and event participations.
|
||||
- The `Events` area now also provides a manual ICS export and a personal subscribable calendar feed for all own events and event participations.
|
||||
- The `Events` area is now separated in the UI into `My Events` and `Synchronization` so that event management and calendar tasks stay clearly separated.
|
||||
- Places and event-like outing targets were moved for now into a separate member-area section `Outings`.
|
||||
- The `Events` input flow should stay as simple as possible and therefore only shows fields relevant for real scheduled events.
|
||||
- Categories in the member area are handled via a search input with existing suggestions and automatic creation when needed.
|
||||
@@ -39,6 +40,10 @@ Papa-Kind-Treff is a PHP-based platform for fathers. Core areas are local events
|
||||
- Goal: later distinguish between own event, partner offer, general place, and editorial event entry
|
||||
- Google is not integrated productively yet; the system is only being prepared for it via settings and data fields
|
||||
|
||||
## Deferred To-dos
|
||||
- Large calendar-provider integrations should be added later in addition to the ICS feed, starting primarily with Google and Microsoft/Outlook.
|
||||
- The target model is no reverse sync, but a user-side OAuth login through Papa-Kind-Treff followed by a direct calendar connection or event synchronization at the respective provider.
|
||||
|
||||
## Maintenance Note
|
||||
- Whenever one of these files changes, the matching files in `Internal/de/` and `Internal/en/` must be kept aligned.
|
||||
- The root `README.md` acts as the startup document for new chats and should be reviewed alongside major context changes.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Papa-Kind-Treff – Start-Doku
|
||||
|
||||
Stand: 2026-08-05
|
||||
Stand: 2026-08-07
|
||||
|
||||
Diese Datei ist die zentrale Start-Doku für neue Chats und den schnellen Projekteinstieg.
|
||||
|
||||
@@ -42,6 +42,8 @@ Papa-Kind-Treff ist eine PHP-basierte Plattform für Väter mit Fokus auf:
|
||||
- Die Eingabe im Mitgliederbereich ist jetzt bewusst vereinfacht: zuerst nur Pflichtangaben, optionale Angaben in einklappbaren Bereichen
|
||||
- Kategorien werden jetzt über eine Sucheingabe mit bestehenden Vorschlägen gepflegt; neue Kategorien werden automatisch angelegt und sind für Seiten-Admins im Systembereich zusammenführbar
|
||||
- Im Mitgliederbereich `Events` gibt es jetzt zusätzlich einen ICS-Download und einen persönlichen abonnierbaren Kalender-Feed für alle eigenen Events und Event-Teilnahmen
|
||||
- Der Bereich `Events` ist im Mitgliederbereich jetzt zusätzlich in die Tabs `Meine Events` und `Synchronisation` gegliedert
|
||||
- Für später vorgemerkt: direkte Kalender-Anbindung großer Anbieter wie Google und Microsoft/Outlook per OAuth, zusätzlich zum bestehenden ICS-Feed
|
||||
|
||||
## Datenschutz und Sicherheit
|
||||
- sensible Profilfelder werden app-seitig verschlüsselt gespeichert
|
||||
|
||||
@@ -282,75 +282,24 @@ if (!empty($canManageSystemSettings)) {
|
||||
<p class="muted">Hier verwaltest du nur echte eigene Events und Events, an denen du teilnimmst.</p>
|
||||
</div>
|
||||
<div class="account-panel__body">
|
||||
<div class="flex gap-12" style="margin:0 0 16px 0; flex-wrap: wrap;">
|
||||
<div class="flex gap-12" style="margin:0 0 18px 0; flex-wrap: wrap;">
|
||||
<button class="btn" type="button" data-modal-open="modalEvent">Eigenes Event anlegen</button>
|
||||
<?php if (!empty($calendarExportUrl)): ?>
|
||||
<a class="btn ghost" href="<?= htmlspecialchars((string)$calendarExportUrl, ENT_QUOTES) ?>">ICS herunterladen</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php if (!empty($calendarExportUrl) && !empty($calendarFeedUrl)): ?>
|
||||
<div class="account-inline-tabs" role="tablist" aria-label="Event-Bereiche">
|
||||
<button class="account-inline-tabs__button is-active" type="button" role="tab" aria-selected="true" data-event-tab-trigger="my-events">Meine Events</button>
|
||||
<button class="account-inline-tabs__button" type="button" role="tab" aria-selected="false" data-event-tab-trigger="sync">Synchronisation</button>
|
||||
</div>
|
||||
|
||||
<div class="account-inline-tab-panel" data-event-tab-panel="my-events">
|
||||
<div class="card" style="margin-bottom:18px;">
|
||||
<strong>Kalender-Synchronisierung</strong>
|
||||
<p class="muted small" style="margin:8px 0 0;">Exportiert werden immer alle eigenen Events und alle Events, an denen du teilnimmst.</p>
|
||||
<p class="muted small" style="margin:8px 0 0;">„ICS herunterladen“ ist nur eine Momentaufnahme für den manuellen Import. Änderungen, Absagen oder Löschungen in Papa-Kind-Treff werden dadurch später nicht automatisch aus deinem privaten Kalender entfernt.</p>
|
||||
<p class="muted small" style="margin:8px 0 0;">Für automatische Aktualisierungen nutze den persönlichen Kalender-Feed. Dann können unterstützte Kalender gelöschte oder abgesagte Einträge bei der nächsten Synchronisierung übernehmen.</p>
|
||||
<div class="stack gap-6" style="margin-top:12px;">
|
||||
<label class="label" for="calendarFeedUrl">Persönlicher Kalender-Feed</label>
|
||||
<input id="calendarFeedUrl" class="input" type="text" readonly value="<?= htmlspecialchars((string)$calendarFeedUrl, ENT_QUOTES) ?>">
|
||||
</div>
|
||||
<strong>Eigene Events</strong>
|
||||
<p class="muted small" style="margin:8px 0 0;">Von dir organisierte Treffen oder Events mit eigener Teilnahme-Logik.</p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="card" style="margin-bottom:18px;">
|
||||
<strong>Eigene Events</strong>
|
||||
<p class="muted small" style="margin:8px 0 0;">Von dir organisierte Treffen oder Events mit eigener Teilnahme-Logik.</p>
|
||||
</div>
|
||||
<?php if (!$eventsUpcoming): ?>
|
||||
<p class="muted small">Keine zukünftigen eigenen Events angelegt.</p>
|
||||
<?php else: ?>
|
||||
<ul class="dash-list" style="margin-top:10px;">
|
||||
<?php foreach ($eventsUpcoming as $e): ?>
|
||||
<li>
|
||||
<div style="display:flex; justify-content:space-between; gap:12px; align-items:center; flex-wrap: wrap;">
|
||||
<div>
|
||||
<strong><?= htmlspecialchars($e['title'], ENT_QUOTES) ?></strong>
|
||||
<?php if ($e['status'] === 'cancelled'): ?>
|
||||
<span class="badge" style="background:#fee2e2; color:#991b1b;">Abgesagt</span>
|
||||
<?php endif; ?>
|
||||
<div class="muted small" style="margin-top:4px;">
|
||||
<?= htmlspecialchars($e['city'], ENT_QUOTES) ?> · <?= htmlspecialchars($e['starts_at'], ENT_QUOTES) ?> · <?= htmlspecialchars($e['visibility'], ENT_QUOTES) ?>
|
||||
· Anmeldungen: <?= (int)$e['participant_count'] ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-8" style="flex-wrap: wrap;">
|
||||
<a class="btn ghost" href="/dashboard?section=events&edit_event=<?= (int)$e['id'] ?>#events">Bearbeiten</a>
|
||||
<?php if ((int)$e['participant_count'] === 0): ?>
|
||||
<form method="post" action="/dashboard?section=events#events" onsubmit="return confirm('Event wirklich löschen?');">
|
||||
<input type="hidden" name="action" value="event_delete">
|
||||
<input type="hidden" name="event_id" value="<?= (int)$e['id'] ?>">
|
||||
<button class="btn ghost" type="submit">Löschen</button>
|
||||
</form>
|
||||
<?php else: ?>
|
||||
<?php if ($e['status'] !== 'cancelled'): ?>
|
||||
<form method="post" action="/dashboard?section=events#events" onsubmit="return confirm('Event für alle absagen?');">
|
||||
<input type="hidden" name="action" value="event_cancel">
|
||||
<input type="hidden" name="event_id" value="<?= (int)$e['id'] ?>">
|
||||
<button class="btn ghost" type="submit">Absagen</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
<details style="margin-top:12px;">
|
||||
<summary style="cursor:pointer;">Vergangene Events anzeigen</summary>
|
||||
<?php if (!$eventsPast): ?>
|
||||
<p class="muted small">Keine vergangenen Events.</p>
|
||||
<?php if (!$eventsUpcoming): ?>
|
||||
<p class="muted small">Keine zukünftigen eigenen Events angelegt.</p>
|
||||
<?php else: ?>
|
||||
<ul class="dash-list" style="margin-top:10px;">
|
||||
<?php foreach ($eventsPast as $e): ?>
|
||||
<?php foreach ($eventsUpcoming as $e): ?>
|
||||
<li>
|
||||
<div style="display:flex; justify-content:space-between; gap:12px; align-items:center; flex-wrap: wrap;">
|
||||
<div>
|
||||
@@ -363,64 +312,138 @@ if (!empty($canManageSystemSettings)) {
|
||||
· Anmeldungen: <?= (int)$e['participant_count'] ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-8" style="flex-wrap: wrap;">
|
||||
<a class="btn ghost" href="/dashboard?section=events&edit_event=<?= (int)$e['id'] ?>#events">Bearbeiten</a>
|
||||
<?php if ((int)$e['participant_count'] === 0): ?>
|
||||
<form method="post" action="/dashboard?section=events#events" onsubmit="return confirm('Event wirklich löschen?');">
|
||||
<input type="hidden" name="action" value="event_delete">
|
||||
<input type="hidden" name="event_id" value="<?= (int)$e['id'] ?>">
|
||||
<button class="btn ghost" type="submit">Löschen</button>
|
||||
</form>
|
||||
<?php else: ?>
|
||||
<?php if ($e['status'] !== 'cancelled'): ?>
|
||||
<form method="post" action="/dashboard?section=events#events" onsubmit="return confirm('Event für alle absagen?');">
|
||||
<input type="hidden" name="action" value="event_cancel">
|
||||
<input type="hidden" name="event_id" value="<?= (int)$e['id'] ?>">
|
||||
<button class="btn ghost" type="submit">Absagen</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
</details>
|
||||
|
||||
<div class="card" style="margin:22px 0 14px;">
|
||||
<strong>Events mit deiner Teilnahme</strong>
|
||||
<p class="muted small" style="margin:8px 0 0;">Events anderer Nutzer, bei denen du eingetragen bist.</p>
|
||||
</div>
|
||||
<?php if (!$eventsJoinedUpcoming): ?>
|
||||
<p class="muted small">Aktuell nimmst du an keinen zukünftigen Events teil.</p>
|
||||
<?php else: ?>
|
||||
<ul class="dash-list" style="margin-top:10px;">
|
||||
<?php foreach ($eventsJoinedUpcoming as $entry): ?>
|
||||
<li>
|
||||
<div style="display:flex; justify-content:space-between; gap:12px; align-items:center; flex-wrap: wrap;">
|
||||
<div>
|
||||
<strong><?= htmlspecialchars((string)$entry['title'], ENT_QUOTES) ?></strong>
|
||||
<div class="muted small" style="margin-top:4px;">
|
||||
<?= htmlspecialchars(trim(implode(' · ', array_filter([
|
||||
(string)($entry['city'] ?? ''),
|
||||
!empty($entry['starts_at']) ? (string)$entry['starts_at'] : null,
|
||||
!empty($entry['host_name']) ? 'Von ' . (string)$entry['host_name'] : null,
|
||||
!empty($entry['participation_status']) ? 'Status: ' . (string)$entry['participation_status'] : null,
|
||||
]))), ENT_QUOTES) ?>
|
||||
<details style="margin-top:12px;">
|
||||
<summary style="cursor:pointer;">Vergangene Events anzeigen</summary>
|
||||
<?php if (!$eventsPast): ?>
|
||||
<p class="muted small">Keine vergangenen Events.</p>
|
||||
<?php else: ?>
|
||||
<ul class="dash-list" style="margin-top:10px;">
|
||||
<?php foreach ($eventsPast as $e): ?>
|
||||
<li>
|
||||
<div style="display:flex; justify-content:space-between; gap:12px; align-items:center; flex-wrap: wrap;">
|
||||
<div>
|
||||
<strong><?= htmlspecialchars($e['title'], ENT_QUOTES) ?></strong>
|
||||
<?php if ($e['status'] === 'cancelled'): ?>
|
||||
<span class="badge" style="background:#fee2e2; color:#991b1b;">Abgesagt</span>
|
||||
<?php endif; ?>
|
||||
<div class="muted small" style="margin-top:4px;">
|
||||
<?= htmlspecialchars($e['city'], ENT_QUOTES) ?> · <?= htmlspecialchars($e['starts_at'], ENT_QUOTES) ?> · <?= htmlspecialchars($e['visibility'], ENT_QUOTES) ?>
|
||||
· Anmeldungen: <?= (int)$e['participant_count'] ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
<details style="margin-top:12px;">
|
||||
<summary style="cursor:pointer;">Vergangene Teilnahmen anzeigen</summary>
|
||||
<?php if (!$eventsJoinedPast): ?>
|
||||
<p class="muted small">Keine vergangenen Event-Teilnahmen.</p>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
</details>
|
||||
|
||||
<div class="card" style="margin:22px 0 14px;">
|
||||
<strong>Events mit deiner Teilnahme</strong>
|
||||
<p class="muted small" style="margin:8px 0 0;">Events anderer Nutzer, bei denen du eingetragen bist.</p>
|
||||
</div>
|
||||
<?php if (!$eventsJoinedUpcoming): ?>
|
||||
<p class="muted small">Aktuell nimmst du an keinen zukünftigen Events teil.</p>
|
||||
<?php else: ?>
|
||||
<ul class="dash-list" style="margin-top:10px;">
|
||||
<?php foreach ($eventsJoinedPast as $entry): ?>
|
||||
<?php foreach ($eventsJoinedUpcoming as $entry): ?>
|
||||
<li>
|
||||
<div>
|
||||
<strong><?= htmlspecialchars((string)$entry['title'], ENT_QUOTES) ?></strong>
|
||||
<div class="muted small" style="margin-top:4px;">
|
||||
<?= htmlspecialchars(trim(implode(' · ', array_filter([
|
||||
(string)($entry['city'] ?? ''),
|
||||
!empty($entry['starts_at']) ? (string)$entry['starts_at'] : null,
|
||||
!empty($entry['host_name']) ? 'Von ' . (string)$entry['host_name'] : null,
|
||||
!empty($entry['participation_status']) ? 'Status: ' . (string)$entry['participation_status'] : null,
|
||||
]))), ENT_QUOTES) ?>
|
||||
<div style="display:flex; justify-content:space-between; gap:12px; align-items:center; flex-wrap: wrap;">
|
||||
<div>
|
||||
<strong><?= htmlspecialchars((string)$entry['title'], ENT_QUOTES) ?></strong>
|
||||
<div class="muted small" style="margin-top:4px;">
|
||||
<?= htmlspecialchars(trim(implode(' · ', array_filter([
|
||||
(string)($entry['city'] ?? ''),
|
||||
!empty($entry['starts_at']) ? (string)$entry['starts_at'] : null,
|
||||
!empty($entry['host_name']) ? 'Von ' . (string)$entry['host_name'] : null,
|
||||
!empty($entry['participation_status']) ? 'Status: ' . (string)$entry['participation_status'] : null,
|
||||
]))), ENT_QUOTES) ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
</details>
|
||||
<details style="margin-top:12px;">
|
||||
<summary style="cursor:pointer;">Vergangene Teilnahmen anzeigen</summary>
|
||||
<?php if (!$eventsJoinedPast): ?>
|
||||
<p class="muted small">Keine vergangenen Event-Teilnahmen.</p>
|
||||
<?php else: ?>
|
||||
<ul class="dash-list" style="margin-top:10px;">
|
||||
<?php foreach ($eventsJoinedPast as $entry): ?>
|
||||
<li>
|
||||
<div>
|
||||
<strong><?= htmlspecialchars((string)$entry['title'], ENT_QUOTES) ?></strong>
|
||||
<div class="muted small" style="margin-top:4px;">
|
||||
<?= htmlspecialchars(trim(implode(' · ', array_filter([
|
||||
(string)($entry['city'] ?? ''),
|
||||
!empty($entry['starts_at']) ? (string)$entry['starts_at'] : null,
|
||||
!empty($entry['host_name']) ? 'Von ' . (string)$entry['host_name'] : null,
|
||||
!empty($entry['participation_status']) ? 'Status: ' . (string)$entry['participation_status'] : null,
|
||||
]))), ENT_QUOTES) ?>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
</details>
|
||||
</div>
|
||||
|
||||
<div class="account-inline-tab-panel" data-event-tab-panel="sync" hidden>
|
||||
<div class="card">
|
||||
<strong>Kalender-Synchronisierung</strong>
|
||||
<p class="muted small" style="margin:8px 0 0;">Exportiert werden immer alle eigenen Events und alle Events, an denen du teilnimmst.</p>
|
||||
<?php if (!empty($calendarExportUrl)): ?>
|
||||
<div class="flex gap-12" style="margin-top:14px; flex-wrap:wrap;">
|
||||
<a class="btn" href="<?= htmlspecialchars((string)$calendarExportUrl, ENT_QUOTES) ?>">ICS herunterladen</a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="card" style="margin-top:18px;">
|
||||
<strong>Kalender abonnieren</strong>
|
||||
<p class="muted small" style="margin:8px 0 0;">Der persönliche Kalender-Feed ist für Apps gedacht, die Internet-Kalender abonnieren können. So bleiben Änderungen, Absagen oder Löschungen bei der nächsten Synchronisierung aktuell.</p>
|
||||
<div class="stack gap-6" style="margin-top:14px;">
|
||||
<label class="label" for="calendarFeedUrl">Persönlicher Kalender-Feed</label>
|
||||
<input id="calendarFeedUrl" class="input" type="text" readonly value="<?= htmlspecialchars((string)$calendarFeedUrl, ENT_QUOTES) ?>">
|
||||
</div>
|
||||
<div class="stack gap-6" style="margin-top:14px;">
|
||||
<strong style="font-size:15px;">So nutzt du den Feed</strong>
|
||||
<p class="muted small" style="margin:0;">1. Feed-Link kopieren.</p>
|
||||
<p class="muted small" style="margin:0;">2. Im Kalender-Anbieter `Kalender abonnieren` oder `Per URL hinzufügen` wählen.</p>
|
||||
<p class="muted small" style="margin:0;">3. Den Link einfügen und speichern.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card" style="margin-top:18px;">
|
||||
<strong>Wichtiger Unterschied</strong>
|
||||
<p class="muted small" style="margin:8px 0 0;">„ICS herunterladen“ ist nur eine Momentaufnahme für den manuellen Import. Spätere Änderungen in Papa-Kind-Treff werden dadurch nicht automatisch in deinem privaten Kalender nachgezogen.</p>
|
||||
<p class="muted small" style="margin:8px 0 0;">Für laufende Aktualisierungen solltest du deshalb den persönlichen Kalender-Feed abonnieren.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<?php endif; ?>
|
||||
@@ -1309,6 +1332,8 @@ if (!empty($canManageSystemSettings)) {
|
||||
const profileAddressNeedsValidation = document.getElementById('profileAddressNeedsValidation');
|
||||
const profileAddressResults = document.getElementById('profileAddressResults');
|
||||
const profileAddressResultsModal = document.getElementById('modalProfileAddressResults');
|
||||
const eventTabButtons = document.querySelectorAll('[data-event-tab-trigger]');
|
||||
const eventTabPanels = document.querySelectorAll('[data-event-tab-panel]');
|
||||
let map, marker;
|
||||
const existingCategories = <?= json_encode($listingCategories ?? [], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?>;
|
||||
let lastAutoGeocodeQuery = '';
|
||||
@@ -1437,6 +1462,25 @@ if (!empty($canManageSystemSettings)) {
|
||||
categoryInput?.addEventListener('input', syncCategoryInputState);
|
||||
syncCategoryInputState();
|
||||
|
||||
function setEventTab(nextTab) {
|
||||
const activeTab = nextTab || 'my-events';
|
||||
eventTabButtons.forEach((button) => {
|
||||
const isActive = button.getAttribute('data-event-tab-trigger') === activeTab;
|
||||
button.classList.toggle('is-active', isActive);
|
||||
button.setAttribute('aria-selected', isActive ? 'true' : 'false');
|
||||
});
|
||||
eventTabPanels.forEach((panel) => {
|
||||
panel.hidden = panel.getAttribute('data-event-tab-panel') !== activeTab;
|
||||
});
|
||||
}
|
||||
|
||||
eventTabButtons.forEach((button) => {
|
||||
button.addEventListener('click', () => {
|
||||
setEventTab(button.getAttribute('data-event-tab-trigger') || 'my-events');
|
||||
});
|
||||
});
|
||||
setEventTab('my-events');
|
||||
|
||||
function ensureLeaflet(callback) {
|
||||
if (!window.PKTConsent || !window.PKTConsent.has('external_services')) {
|
||||
alert('Für Karten und Adresssuche bitte zuerst die externen Dienste in den Cookie-Einstellungen erlauben.');
|
||||
|
||||
@@ -239,6 +239,11 @@ body {
|
||||
.account-panel__head { padding: 22px 24px; border-bottom: 1px solid var(--color-border); background: #fffdfa; }
|
||||
.account-panel__head h2 { margin: 0 0 6px; }
|
||||
.account-panel__body { padding: 24px; }
|
||||
.account-inline-tabs { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 18px; }
|
||||
.account-inline-tabs__button { appearance: none; border: 1px solid var(--color-border); background: #fff; color: var(--color-text); border-radius: 999px; padding: 11px 16px; font: inherit; font-weight: 700; cursor: pointer; transition: background .15s ease, color .15s ease, border-color .15s ease; }
|
||||
.account-inline-tabs__button:hover { border-color: var(--color-primary); color: var(--color-primary); }
|
||||
.account-inline-tabs__button.is-active { background: var(--color-primary); color: var(--color-primary-contrast); border-color: var(--color-primary); }
|
||||
.account-inline-tab-panel[hidden] { display: none; }
|
||||
.account-kv { display: grid; gap: 10px; margin: 0; }
|
||||
.account-kv div { display: grid; grid-template-columns: 190px minmax(0, 1fr); gap: 14px; }
|
||||
.account-kv--compact { gap: 8px; }
|
||||
|
||||
Reference in New Issue
Block a user