"Event des Jahres": Aktivieren-Schalter, leer bis befuellt, Detail-Fenster
Nutzer-Wunsch 20.08.2026: "diese zwei kisten sollen leer sein solang wie ich nichts rein setze, am besten sollen die sogar immer nur erscheinen wenn ich was rein setze und sie aktiviere ... wen ich drauf druecke dass dann ein kleines fenster aufgeht wo das bild bissl groesser ist mit einem groesseren text und beschreibung, und mit einem link ... die kacheln sollen auch bissl spezieller sein." - Kein hartkodierter Standardinhalt mehr auf der Startseite -- die Kachel UND der ganze Abschnitt bleiben komplett unsichtbar, bis mindestens ein Event in der Verwaltung ausgefuellt UND ueber einen neuen "Aktiv"-Schalter freigeschaltet ist. Genau 1 aktives Event -> zentrierte Einzelkachel statt halbleerem Zwei-Spalten-Raster. - Klick auf eine Kachel oeffnet jetzt ein Detail-Fenster (groesseres Bild, groesserer Titel/Text, optionaler direkter Link) statt sofort wegzunavigieren. - Kacheln bekommen einen goldenen Trophaeen-Akzent + dezenten wandernden Lichtschimmer statt der neutralen Standardkarten-Optik. - Bugfix unterwegs gefunden (Playwright-Screenshot): .jahres-event-card blieb trotz [hidden]-Attribut sichtbar (dieselbe Ursache wie der frühere .jahres-event-bild-Bug: display:block ueberschreibt die eingebaute [hidden]-Regel bei gleicher Spezifitaet) -- explizite [hidden]-Regel ergaenzt. - Backend: server-internal/routes/events.js liefert oeffentlich NUR noch aktivierte Slots aus (getEventsPublic), neuer authentifizierter Endpunkt getEventsAdmin liefert der Verwaltung auch Entwuerfe zum Vorausfuellen. 10 automatisierte Tests gegen eine Fake-DB bestanden. Backend-Teil (server-internal/) noch ohne Deploy-Zugriff -- Dogi muss ihn manuell auf dogiintern ausrollen, sonst bleibt die Startseite beim alten Verhalten (immer beide Slots zeigen, kein Aktiv-Schalter in der Verwaltung). Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
+34
-11
@@ -19,10 +19,10 @@
|
||||
<link rel="apple-touch-icon" href="assets/img/apple-touch-icon-admin.png" />
|
||||
<meta name="apple-mobile-web-app-title" content="DogiCrew-Verwaltung" />
|
||||
<meta name="theme-color" content="#0e0a16" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820e" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820e" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820e" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820e" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820f" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820f" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820f" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820f" />
|
||||
<style>
|
||||
/* =====================================================================
|
||||
verwaltung.html — Dogis privater Command-Center-Bereich.
|
||||
@@ -977,8 +977,8 @@
|
||||
</main>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/main.js?v=20260820e"></script>
|
||||
<script src="assets/js/admin-auth.js?v=20260820e"></script>
|
||||
<script src="assets/js/main.js?v=20260820f"></script>
|
||||
<script src="assets/js/admin-auth.js?v=20260820f"></script>
|
||||
<script>
|
||||
(function () {
|
||||
const API_BASE_URL = "https://postfach.dogfather-universe.com";
|
||||
@@ -1082,7 +1082,10 @@
|
||||
function eventKarteHtml(slot) {
|
||||
return `
|
||||
<div class="card vw-card vw-shine-card vw-noise" style="padding:1.5rem;">
|
||||
<h3 style="margin-top:0;">Event ${slot}</h3>
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:.8rem;">
|
||||
<h3 style="margin:0;">Event ${slot}</h3>
|
||||
<span class="vw-overview-chip" id="event-${slot}-status-chip">Entwurf</span>
|
||||
</div>
|
||||
<div style="margin-bottom:1rem;">
|
||||
<img id="event-${slot}-vorschau" alt="" style="width:100%;aspect-ratio:16/9;object-fit:cover;border-radius:10px;background:var(--bg-alt);display:none;" />
|
||||
</div>
|
||||
@@ -1106,6 +1109,14 @@
|
||||
<label for="event-${slot}-link">Link (optional, muss mit https:// beginnen)</label>
|
||||
<input type="url" id="event-${slot}-link" placeholder="https://…" />
|
||||
</div>
|
||||
<label style="display:flex;align-items:center;gap:.6rem;margin:1rem 0;cursor:pointer;">
|
||||
<input type="checkbox" id="event-${slot}-aktiv" style="width:1.2rem;height:1.2rem;" />
|
||||
<span>Aktiv — auf der Startseite sichtbar</span>
|
||||
</label>
|
||||
<p class="small muted" style="margin:-.4rem 0 1rem;">
|
||||
Ohne Häkchen bleibt die Kachel auf der Startseite unsichtbar (Entwurf), auch wenn hier
|
||||
schon alles ausgefüllt ist — so kannst du in Ruhe vorbereiten und erst dann live schalten.
|
||||
</p>
|
||||
<button type="button" class="btn btn-primary" id="event-${slot}-speichern" style="width:100%;">Speichern</button>
|
||||
<p class="small" id="event-${slot}-status" style="margin-top:.6rem;"></p>
|
||||
</div>`;
|
||||
@@ -1117,9 +1128,8 @@
|
||||
|
||||
let aktuelleDaten = [null, null];
|
||||
try {
|
||||
const res = await fetch(`${API_BASE_URL}/events-of-year`, { cache: "no-store" });
|
||||
const data = await res.json();
|
||||
if (data?.ok) aktuelleDaten = data.events;
|
||||
const res = await window.AdminAuth.apiCall(API_BASE_URL, "/admin/events/list", {});
|
||||
if (res.ok) aktuelleDaten = res.events;
|
||||
} catch {
|
||||
/* Formular bleibt leer, Speichern funktioniert trotzdem — kein Blocker. */
|
||||
}
|
||||
@@ -1128,18 +1138,28 @@
|
||||
const eintrag = aktuelleDaten[i];
|
||||
const bildInput = document.getElementById(`event-${slot}-bild-input`);
|
||||
const vorschau = document.getElementById(`event-${slot}-vorschau`);
|
||||
const statusChip = document.getElementById(`event-${slot}-status-chip`);
|
||||
let hochgeladenesBild = eintrag?.bild || null;
|
||||
|
||||
const aktualisiereStatusChip = (aktiv) => {
|
||||
statusChip.textContent = aktiv ? "🟢 Live" : "⚪ Entwurf";
|
||||
};
|
||||
|
||||
if (eintrag) {
|
||||
document.getElementById(`event-${slot}-datum`).value = eintrag.datum || "";
|
||||
document.getElementById(`event-${slot}-titel`).value = eintrag.titel?.de || "";
|
||||
document.getElementById(`event-${slot}-text`).value = eintrag.text?.de || "";
|
||||
document.getElementById(`event-${slot}-link`).value = eintrag.link || "";
|
||||
document.getElementById(`event-${slot}-aktiv`).checked = !!eintrag.aktiv;
|
||||
aktualisiereStatusChip(!!eintrag.aktiv);
|
||||
if (eintrag.bild) {
|
||||
vorschau.src = eintrag.bild;
|
||||
vorschau.style.display = "";
|
||||
}
|
||||
} else {
|
||||
aktualisiereStatusChip(false);
|
||||
}
|
||||
document.getElementById(`event-${slot}-aktiv`).addEventListener("change", (e) => aktualisiereStatusChip(e.target.checked));
|
||||
|
||||
// Bild wird SOFORT bei Auswahl hochgeladen (nicht erst beim
|
||||
// "Speichern"-Klick) — einfacher nachvollziehbar für Dogi/VanVan: die
|
||||
@@ -1187,6 +1207,7 @@
|
||||
}
|
||||
statusEl.textContent = "Wird gespeichert und übersetzt …";
|
||||
statusEl.style.color = "";
|
||||
const aktiv = document.getElementById(`event-${slot}-aktiv`).checked;
|
||||
const res = await window.AdminAuth.apiCall(API_BASE_URL, "/admin/events/save", {
|
||||
slot,
|
||||
datum: document.getElementById(`event-${slot}-datum`).value.trim(),
|
||||
@@ -1194,13 +1215,15 @@
|
||||
text,
|
||||
link: document.getElementById(`event-${slot}-link`).value.trim(),
|
||||
bild: hochgeladenesBild,
|
||||
aktiv,
|
||||
});
|
||||
if (!res.ok) {
|
||||
statusEl.textContent = res.error || "Speichern fehlgeschlagen.";
|
||||
statusEl.style.color = "#ff6b6b";
|
||||
return;
|
||||
}
|
||||
statusEl.textContent = "✅ Gespeichert — auf der Startseite live.";
|
||||
aktualisiereStatusChip(aktiv);
|
||||
statusEl.textContent = aktiv ? "✅ Gespeichert — auf der Startseite live." : "✅ Als Entwurf gespeichert (noch nicht sichtbar).";
|
||||
statusEl.style.color = "#baf7d6";
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user