Zweite Live-Uhr fuer "spezielles Live-Event" + mehr Farbe im Radar
Nutzer-Wunsch 20.08.2026: "wuensch mir nur noch bissl farbe und sehr wichtig ist dass ich auch spezielle live events da auch eintragen kann in der verwaltungsseite so dass da eine zweite uhr erscheint wo die zeit dann fuer dieses spezielle event laeuft." - Neue Verwaltungs-Sektion "Spezielles Live-Event": Titel (Deutsch, wird automatisch uebersetzt), echtes Datum+Uhrzeit, optionaler Link, Aktiv- Schalter -- nur mit Titel + Zukunftsdatum aktivierbar. - Zweite Uhr auf streamplan.html (Magenta/Violett statt Cyan/Gold, direkt neben der bestehenden), nur sichtbar wenn ein Event aktiviert ist und das Zieldatum noch nicht vorbei ist. Echter Countdown inkl. Tage (z.B. "2T 03:14:59"), "Jetzt"-Zeiger zeigt wie bei Uhr 1 die tatsaechliche Uhrzeit, der magentafarbene Fixpunkt markiert die Tageszeit des Events. Zieldatum wird als UTC gespeichert -- jede besuchende Person sieht den exakt richtigen Countdown in ihrer eigenen Zeitzone. - "Bissl Farbe": bunter Farbverlauf (Cyan/Violett/Gold) auf dem aeusseren Ring statt reinem Grauton, kraeftigerer Sweep-Farbschein. - Backend: neue routes/special-event.js (getSpecialEventPublic nur bei aktiv+zukuenftig, getSpecialEventAdmin fuer Entwuerfe, saveSpecialEvent mit Validierung), 13 automatisierte Tests gegen eine Fake-DB bestanden. - Bugfix unterwegs gefunden (Playwright-Screenshot, wiederholtes Muster auf dieser Seite): .stream-radar-wrap blieb trotz [hidden]-Attribut sichtbar (display:block ueberschreibt die eingebaute [hidden]-Regel bei gleicher Spezifitaet) -- explizite Regel ergaenzt, per Playwright erneut verifiziert (display:none bestaetigt). Backend-Teil (server-internal/) noch ohne Deploy-Zugriff -- Dogi muss ihn manuell auf dogiintern ausrollen, sonst bleibt die zweite Uhr unsichtbar. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -18,10 +18,10 @@
|
||||
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||||
<meta name="robots" content="noindex" />
|
||||
<title>Seite nicht gefunden — DOGFATHER UNIVERSE</title>
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="site-header"></div>
|
||||
@@ -41,7 +41,7 @@
|
||||
</main>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/i18n-404.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/i18n-404.js?v=20260820j"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+7
-7
@@ -19,10 +19,10 @@
|
||||
<meta name="twitter:description" content="Unterstütze Dogfather dauerhaft mit der DogiCrew 🩵 und sammle exklusive Treueprämien — die Teddy-Kollektion entsteht in Kooperation mit VanVan." />
|
||||
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
<style>
|
||||
/* =====================================================================
|
||||
Preis-/Anmelde-Kiste — komplett neu gestaltet (Nutzer-Feedback
|
||||
@@ -454,9 +454,9 @@
|
||||
</main>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/i18n-abonnieren.js?v=20260820i"></script>
|
||||
<script src="assets/js/supporter.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/i18n-abonnieren.js?v=20260820j"></script>
|
||||
<script src="assets/js/supporter.js?v=20260820j"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
<script>
|
||||
(function () {
|
||||
const S = window.DogiSupporter;
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||||
<meta name="robots" content="noindex" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="site-header"></div>
|
||||
@@ -134,6 +134,6 @@
|
||||
</main>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+7
-7
@@ -19,10 +19,10 @@
|
||||
<meta name="twitter:description" content="Detailansicht einer Aktion oder eines Projekts von Team Dogi." />
|
||||
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="site-header"></div>
|
||||
@@ -51,9 +51,9 @@
|
||||
</main>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/data-aktionen.js?v=20260820i"></script>
|
||||
<script src="assets/js/i18n-aktion-detail.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/data-aktionen.js?v=20260820j"></script>
|
||||
<script src="assets/js/i18n-aktion-detail.js?v=20260820j"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const params = new URLSearchParams(location.search);
|
||||
|
||||
+44
-4
@@ -3591,7 +3591,23 @@ body.start-seite .music-toggle:focus-visible {
|
||||
sonst zählt ein echter Sekunden-Countdown zum nächsten 20-Uhr-Termin
|
||||
runter. Bewusst augenschonend: gedeckte Farben, langsame, sanfte
|
||||
Animation, kompletter Stillstand bei prefers-reduced-motion. ================================================================= */
|
||||
.stream-radar-wrap { display: flex; flex-direction: column; align-items: center; margin: 1.4rem auto 0; }
|
||||
/* Reihe für 1-2 Uhren nebeneinander (20.08.2026: zweite Uhr für ein
|
||||
"spezielles Live-Event", siehe assets/js/streamplan.js) — bricht auf
|
||||
schmalen Bildschirmen automatisch untereinander um. */
|
||||
.stream-radar-reihe {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
gap: 2.4rem;
|
||||
margin-top: 1.4rem;
|
||||
}
|
||||
/* .stream-radar-wrap setzt selbst "display", das schlägt bei gleicher
|
||||
Spezifität die eingebaute [hidden]-Regel des Browsers (identisches,
|
||||
inzwischen mehrfach gefundenes Muster auf dieser Seite) — deshalb hier
|
||||
explizit VOR der Klassenregel. */
|
||||
.stream-radar-wrap[hidden] { display: none; }
|
||||
.stream-radar-wrap { display: flex; flex-direction: column; align-items: center; margin: 0 auto; }
|
||||
.stream-radar {
|
||||
position: relative;
|
||||
width: min(300px, 70vw);
|
||||
@@ -3603,15 +3619,28 @@ body.start-seite .music-toggle:focus-visible {
|
||||
inset: -6%;
|
||||
border-radius: 50%;
|
||||
background: conic-gradient(from 0deg,
|
||||
transparent 0deg, rgba(143, 217, 234, .16) 40deg, transparent 90deg,
|
||||
transparent 260deg, rgba(139, 92, 246, .14) 300deg, transparent 340deg, transparent 360deg);
|
||||
transparent 0deg, rgba(143, 217, 234, .28) 40deg, transparent 90deg,
|
||||
transparent 200deg, rgba(232, 196, 101, .22) 250deg, transparent 300deg,
|
||||
transparent 320deg, rgba(139, 92, 246, .24) 350deg, transparent 360deg);
|
||||
animation: stream-radar-rotate 16s linear infinite;
|
||||
pointer-events: none;
|
||||
}
|
||||
/* Farbvariante fürs spezielle Live-Event (Nutzer-Wunsch "bissl Farbe") —
|
||||
Magenta/Violett/Gold statt Cyan/Violett/Gold, damit die zweite Uhr auch
|
||||
auf den ersten Blick als "etwas Besonderes" erkennbar ist. */
|
||||
.stream-radar.event-spezial .stream-radar-sweep {
|
||||
background: conic-gradient(from 0deg,
|
||||
transparent 0deg, rgba(255, 92, 180, .26) 40deg, transparent 90deg,
|
||||
transparent 200deg, rgba(232, 196, 101, .22) 250deg, transparent 300deg,
|
||||
transparent 320deg, rgba(139, 92, 246, .28) 350deg, transparent 360deg);
|
||||
}
|
||||
@keyframes stream-radar-rotate { to { transform: rotate(360deg); } }
|
||||
@media (prefers-reduced-motion: reduce) { .stream-radar-sweep { animation: none; } }
|
||||
.stream-radar-dial { position: relative; width: 100%; height: 100%; display: block; }
|
||||
.radar-ring-outer { fill: none; stroke: rgba(255, 255, 255, .12); stroke-width: 1.5; }
|
||||
/* Bunter Verlauf statt reinem Grau-Ton auf dem äußeren Ring (Nutzer-Wunsch
|
||||
"bissl Farbe") — Farbverlauf steckt als <linearGradient> direkt im SVG
|
||||
jeder Uhr (siehe streamplan.html), hier nur die Basiswerte/Deckkraft. */
|
||||
.radar-ring-outer { fill: none; stroke-width: 2; opacity: .8; }
|
||||
.radar-ring-inner { fill: rgba(255, 255, 255, .02); stroke: rgba(255, 255, 255, .07); stroke-width: 1; }
|
||||
.radar-tick { stroke: rgba(255, 255, 255, .22); stroke-width: 1.5; }
|
||||
.radar-tick-major { stroke: rgba(255, 255, 255, .5); stroke-width: 2.2; }
|
||||
@@ -3670,6 +3699,17 @@ body.start-seite .music-toggle:focus-visible {
|
||||
}
|
||||
.stream-radar.ist-live .stream-radar-countdown { color: #ff5c72; }
|
||||
.stream-radar-sub { font-size: .74rem; color: var(--text-muted); }
|
||||
/* Farbvariante fürs spezielle Live-Event: der Fixpunkt ist hier nicht der
|
||||
tägliche 20-Uhr-Termin, sondern der eigene Zieltermin -- Magenta statt
|
||||
Gold, damit man beide Uhren auf einen Blick unterscheidet. */
|
||||
.stream-radar.event-spezial .radar-fixmarker-dot {
|
||||
fill: #ff5cb8;
|
||||
filter: drop-shadow(0 0 6px rgba(255, 92, 184, .9)) drop-shadow(0 0 14px rgba(255, 92, 184, .5));
|
||||
}
|
||||
.stream-radar.event-spezial:not(.ist-live) .radar-now-hand,
|
||||
.stream-radar.event-spezial:not(.ist-live) .radar-now-dot { stroke: #c9a6ff; fill: #c9a6ff; filter: drop-shadow(0 0 5px rgba(201, 166, 255, .8)); }
|
||||
.stream-radar.event-spezial:not(.ist-live) .stream-radar-countdown { color: #ff5cb8; }
|
||||
.stream-radar-titel { font-size: .95rem; font-weight: 800; color: #ff9ed4; margin-bottom: .3rem; }
|
||||
/* .btn setzt selbst "display", das schlägt bei gleicher Spezifität die
|
||||
eingebaute [hidden]-Regel des Browsers (identisches Muster wie bei
|
||||
.jahres-event-card weiter oben) — deshalb hier explizit. */
|
||||
|
||||
@@ -50,6 +50,14 @@ window.I18N_PAGE = {
|
||||
de: "Alle Zeiten in deiner Ortszeit.", "de-CH": "Alli Ziite in dinere Ortsziit.",
|
||||
en: "All times shown in your local time.", fr: "Tous les horaires affichés dans ton fuseau local.", pt: "Todos os horários na sua hora local.",
|
||||
},
|
||||
sp_radar_hinweis_spezial: {
|
||||
de: "Spezielles Live-Event", "de-CH": "Spezielles Live-Event",
|
||||
en: "Special live event", fr: "Événement en direct spécial", pt: "Evento ao vivo especial",
|
||||
},
|
||||
sp_radar_mehr_erfahren: {
|
||||
de: "Mehr erfahren →", "de-CH": "Mehr erfahre →",
|
||||
en: "Learn more →", fr: "En savoir plus →", pt: "Saiba mais →",
|
||||
},
|
||||
sp_card1_tag: {
|
||||
de: "Fixer Termin", "de-CH": "Fixe Termin",
|
||||
en: "Fixed Time", fr: "Rendez-vous fixe", pt: "Horário Fixo",
|
||||
|
||||
+209
-110
@@ -1,25 +1,24 @@
|
||||
/* =====================================================================
|
||||
streamplan.js — "Live-Radar" NUR für streamplan.html (20.08.2026,
|
||||
Nutzer-Wunsch: "soll viel geiler und spezieller sein, überrasch mich").
|
||||
Nutzer-Wunsch: "soll viel geiler und spezieller sein, überrasch mich",
|
||||
ergänzt um eine zweite Uhr für ein "spezielles Live-Event": "sehr
|
||||
wichtig ist dass ich auch spezielle live events da auch eintragen kann
|
||||
in der verwaltungsseite so dass da eine zweite uhr erscheint wo die
|
||||
zeit dann für dieses spezielle event läuft").
|
||||
|
||||
Ein 24-Stunden-Ziffernblatt (reines SVG, keine Bild-Assets nötig): der
|
||||
feste 20-Uhr-Termin leuchtet dauerhaft als Fixpunkt, ein "Jetzt"-Zeiger
|
||||
bewegt sich mit der echten Uhrzeit der besuchenden Person mit. Nutzt
|
||||
denselben /live-status-Endpunkt wie die Startseite (main.js lädt
|
||||
window.dogiUebersetzen/dogiSprache VOR dieser Datei, siehe <script>-
|
||||
Reihenfolge in streamplan.html) — läuft DogFather laut TikTok gerade
|
||||
wirklich, schaltet das ganze Radar auf Rot/Puls um und zeigt einen
|
||||
"Jetzt anschauen"-Knopf, sonst zählt ein echter Sekunden-Countdown zum
|
||||
nächsten lokalen 20-Uhr-Termin runter. ===================================================================== */
|
||||
Zwei 24-Stunden-Ziffernblätter (reines SVG, keine Bild-Assets nötig):
|
||||
- Uhr 1 (immer sichtbar): der feste 20-Uhr-Termin leuchtet dauerhaft als
|
||||
Fixpunkt, ein "Jetzt"-Zeiger bewegt sich mit der echten Uhrzeit der
|
||||
besuchenden Person mit. Live laut /live-status -> Rot/Puls +
|
||||
"Jetzt anschauen".
|
||||
- Uhr 2 (nur wenn in der Verwaltung aktiviert): zählt zu einem exakten
|
||||
Zieldatum+Uhrzeit runter (Tage möglich, nicht nur Stunden), Magenta/
|
||||
Violett statt Cyan/Gold, damit beide Uhren auf einen Blick
|
||||
unterscheidbar sind ("bissl Farbe"). ===================================================================== */
|
||||
(function () {
|
||||
const API_BASE_URL = "https://postfach.dogfather-universe.com";
|
||||
const FIX_STUNDE = 20; // täglicher Fix-Termin, in der Ortszeit der besuchenden Person
|
||||
|
||||
const radar = document.getElementById("stream-radar");
|
||||
if (!radar) return; // Datei ist nur auf streamplan.html eingebunden
|
||||
|
||||
const CX = 150, CY = 150, R_OUT = 130, R_TICK_IN = 116, R_TICK_MAJOR_IN = 106, R_HAND = 100;
|
||||
const SVG_NS = "http://www.w3.org/2000/svg";
|
||||
const CX = 150, CY = 150, R_OUT = 130, R_TICK_IN = 116, R_TICK_MAJOR_IN = 106, R_HAND = 100;
|
||||
|
||||
function polar(r, stundenAnteil) {
|
||||
const winkel = (stundenAnteil / 24) * 360 - 90; // 0 Uhr oben, im Uhrzeigersinn
|
||||
@@ -27,105 +26,205 @@
|
||||
return { x: CX + r * Math.cos(rad), y: CY + r * Math.sin(rad) };
|
||||
}
|
||||
|
||||
// ---------- 24 Stundenstriche (alle 6 Std. etwas länger/heller) ----------
|
||||
const ticksHost = document.getElementById("radar-ticks");
|
||||
for (let h = 0; h < 24; h++) {
|
||||
const major = h % 6 === 0;
|
||||
const p1 = polar(R_OUT, h);
|
||||
const p2 = polar(major ? R_TICK_MAJOR_IN : R_TICK_IN, h);
|
||||
const line = document.createElementNS(SVG_NS, "line");
|
||||
line.setAttribute("x1", p1.x); line.setAttribute("y1", p1.y);
|
||||
line.setAttribute("x2", p2.x); line.setAttribute("y2", p2.y);
|
||||
line.setAttribute("class", major ? "radar-tick radar-tick-major" : "radar-tick");
|
||||
ticksHost.appendChild(line);
|
||||
}
|
||||
|
||||
// ---------- Fixmarkierung beim täglichen 20-Uhr-Termin ----------
|
||||
const fixHost = document.getElementById("radar-fixmarker");
|
||||
const fixPos = polar(R_OUT + 11, FIX_STUNDE);
|
||||
const fixDot = document.createElementNS(SVG_NS, "circle");
|
||||
fixDot.setAttribute("cx", fixPos.x); fixDot.setAttribute("cy", fixPos.y);
|
||||
fixDot.setAttribute("r", 6.5);
|
||||
fixDot.setAttribute("class", "radar-fixmarker-dot");
|
||||
fixHost.appendChild(fixDot);
|
||||
|
||||
// ---------- "Jetzt"-Zeiger: bewegt sich mit der echten Uhrzeit mit ----------
|
||||
const nowHand = document.getElementById("radar-now-hand");
|
||||
const nowDot = document.getElementById("radar-now-dot");
|
||||
function zeigerAktualisieren() {
|
||||
const jetzt = new Date();
|
||||
const stundenAnteil = jetzt.getHours() + jetzt.getMinutes() / 60 + jetzt.getSeconds() / 3600;
|
||||
const spitze = polar(R_HAND, stundenAnteil);
|
||||
nowHand.setAttribute("x2", spitze.x); nowHand.setAttribute("y2", spitze.y);
|
||||
nowDot.setAttribute("cx", spitze.x); nowDot.setAttribute("cy", spitze.y);
|
||||
}
|
||||
zeigerAktualisieren();
|
||||
setInterval(zeigerAktualisieren, 15000); // alle 15s reicht für eine sichtbare, ruhige Bewegung
|
||||
|
||||
// ---------- Countdown zum nächsten lokalen 20-Uhr-Termin ----------
|
||||
function naechsterFixTermin() {
|
||||
const jetzt = new Date();
|
||||
const ziel = new Date(jetzt);
|
||||
ziel.setHours(FIX_STUNDE, 0, 0, 0);
|
||||
if (ziel <= jetzt) ziel.setDate(ziel.getDate() + 1);
|
||||
return ziel;
|
||||
}
|
||||
function zweistellig(n) { return String(n).padStart(2, "0"); }
|
||||
|
||||
const countdownEl = document.getElementById("radar-countdown");
|
||||
const statusText = document.getElementById("radar-status-text");
|
||||
const statusSub = document.getElementById("radar-status-sub");
|
||||
const watchBtn = document.getElementById("radar-watch-btn");
|
||||
|
||||
let istLive = false;
|
||||
let letzterTitel = null;
|
||||
|
||||
function countdownTick() {
|
||||
if (istLive) return; // im Live-Zustand zeigt der Countdown-Platz die Uhrzeit/den Titel, siehe unten
|
||||
const diffMs = naechsterFixTermin() - new Date();
|
||||
const gesamtSek = Math.max(0, Math.floor(diffMs / 1000));
|
||||
const std = Math.floor(gesamtSek / 3600);
|
||||
const min = Math.floor((gesamtSek % 3600) / 60);
|
||||
const sek = gesamtSek % 60;
|
||||
countdownEl.textContent = `${zweistellig(std)}:${zweistellig(min)}:${zweistellig(sek)}`;
|
||||
}
|
||||
setInterval(countdownTick, 1000);
|
||||
|
||||
function texteNeuSetzen() {
|
||||
const t = window.dogiUebersetzen || ((k) => k);
|
||||
if (istLive) {
|
||||
statusText.textContent = t("sp_radar_live");
|
||||
countdownEl.textContent = letzterTitel || t("sp_radar_live_generic");
|
||||
statusSub.textContent = "";
|
||||
watchBtn.hidden = false;
|
||||
} else {
|
||||
statusText.textContent = t("sp_radar_offline");
|
||||
statusSub.textContent = t("sp_radar_countdown_label");
|
||||
watchBtn.hidden = true;
|
||||
countdownTick();
|
||||
/** Zeichnet die 24 Stundenstriche + einen Fixpunkt-Leuchtpunkt bei
|
||||
"fixStunde" (kann eine Dezimalzahl sein, z.B. 19.5 = 19:30) in die
|
||||
übergebenen <g>-Container. Läuft einmalig pro Uhr. */
|
||||
function zeichneZiffernblatt(ticksHost, fixHost, fixStunde) {
|
||||
ticksHost.innerHTML = "";
|
||||
for (let h = 0; h < 24; h++) {
|
||||
const major = h % 6 === 0;
|
||||
const p1 = polar(R_OUT, h);
|
||||
const p2 = polar(major ? R_TICK_MAJOR_IN : R_TICK_IN, h);
|
||||
const line = document.createElementNS(SVG_NS, "line");
|
||||
line.setAttribute("x1", p1.x); line.setAttribute("y1", p1.y);
|
||||
line.setAttribute("x2", p2.x); line.setAttribute("y2", p2.y);
|
||||
line.setAttribute("class", major ? "radar-tick radar-tick-major" : "radar-tick");
|
||||
ticksHost.appendChild(line);
|
||||
}
|
||||
fixHost.innerHTML = "";
|
||||
if (fixStunde != null) {
|
||||
const fixPos = polar(R_OUT + 11, fixStunde);
|
||||
const fixDot = document.createElementNS(SVG_NS, "circle");
|
||||
fixDot.setAttribute("cx", fixPos.x); fixDot.setAttribute("cy", fixPos.y);
|
||||
fixDot.setAttribute("r", 6.5);
|
||||
fixDot.setAttribute("class", "radar-fixmarker-dot");
|
||||
fixHost.appendChild(fixDot);
|
||||
}
|
||||
}
|
||||
|
||||
function liveStatusAnwenden(data) {
|
||||
istLive = !!(data && data.live);
|
||||
letzterTitel = data && data.title ? data.title : null;
|
||||
radar.classList.toggle("ist-live", istLive);
|
||||
texteNeuSetzen();
|
||||
function zeigerAktualisieren(handEl, dotEl, stundenAnteil) {
|
||||
const spitze = polar(R_HAND, stundenAnteil);
|
||||
handEl.setAttribute("x2", spitze.x); handEl.setAttribute("y2", spitze.y);
|
||||
dotEl.setAttribute("cx", spitze.x); dotEl.setAttribute("cy", spitze.y);
|
||||
}
|
||||
|
||||
function liveStatusLaden() {
|
||||
return fetch(`${API_BASE_URL}/live-status`, { cache: "no-store" })
|
||||
.then((res) => res.json())
|
||||
.then(liveStatusAnwenden)
|
||||
.catch(() => {
|
||||
istLive = false;
|
||||
radar.classList.remove("ist-live");
|
||||
texteNeuSetzen();
|
||||
});
|
||||
function zweistellig(n) { return String(n).padStart(2, "0"); }
|
||||
|
||||
/* ===================================================================
|
||||
Uhr 1: täglicher 20-Uhr-Fixtermin (bereits bestehend, unverändert im
|
||||
Verhalten) ================================================================= */
|
||||
const radar = document.getElementById("stream-radar");
|
||||
if (radar) {
|
||||
const FIX_STUNDE = 20;
|
||||
zeichneZiffernblatt(document.getElementById("radar-ticks"), document.getElementById("radar-fixmarker"), FIX_STUNDE);
|
||||
|
||||
const nowHand = document.getElementById("radar-now-hand");
|
||||
const nowDot = document.getElementById("radar-now-dot");
|
||||
function zeigerTick() {
|
||||
const jetzt = new Date();
|
||||
zeigerAktualisieren(nowHand, nowDot, jetzt.getHours() + jetzt.getMinutes() / 60 + jetzt.getSeconds() / 3600);
|
||||
}
|
||||
zeigerTick();
|
||||
setInterval(zeigerTick, 15000);
|
||||
|
||||
function naechsterFixTermin() {
|
||||
const jetzt = new Date();
|
||||
const ziel = new Date(jetzt);
|
||||
ziel.setHours(FIX_STUNDE, 0, 0, 0);
|
||||
if (ziel <= jetzt) ziel.setDate(ziel.getDate() + 1);
|
||||
return ziel;
|
||||
}
|
||||
|
||||
const countdownEl = document.getElementById("radar-countdown");
|
||||
const statusText = document.getElementById("radar-status-text");
|
||||
const statusSub = document.getElementById("radar-status-sub");
|
||||
const watchBtn = document.getElementById("radar-watch-btn");
|
||||
|
||||
let istLive = false;
|
||||
let letzterTitel = null;
|
||||
|
||||
function countdownTick() {
|
||||
if (istLive) return;
|
||||
const diffMs = naechsterFixTermin() - new Date();
|
||||
const gesamtSek = Math.max(0, Math.floor(diffMs / 1000));
|
||||
const std = Math.floor(gesamtSek / 3600);
|
||||
const min = Math.floor((gesamtSek % 3600) / 60);
|
||||
const sek = gesamtSek % 60;
|
||||
countdownEl.textContent = `${zweistellig(std)}:${zweistellig(min)}:${zweistellig(sek)}`;
|
||||
}
|
||||
setInterval(countdownTick, 1000);
|
||||
|
||||
function texteNeuSetzen() {
|
||||
const t = window.dogiUebersetzen || ((k) => k);
|
||||
if (istLive) {
|
||||
statusText.textContent = t("sp_radar_live");
|
||||
countdownEl.textContent = letzterTitel || t("sp_radar_live_generic");
|
||||
statusSub.textContent = "";
|
||||
watchBtn.hidden = false;
|
||||
} else {
|
||||
statusText.textContent = t("sp_radar_offline");
|
||||
statusSub.textContent = t("sp_radar_countdown_label");
|
||||
watchBtn.hidden = true;
|
||||
countdownTick();
|
||||
}
|
||||
}
|
||||
|
||||
function liveStatusAnwenden(data) {
|
||||
istLive = !!(data && data.live);
|
||||
letzterTitel = data && data.title ? data.title : null;
|
||||
radar.classList.toggle("ist-live", istLive);
|
||||
texteNeuSetzen();
|
||||
}
|
||||
|
||||
function liveStatusLaden() {
|
||||
return fetch(`${API_BASE_URL}/live-status`, { cache: "no-store" })
|
||||
.then((res) => res.json())
|
||||
.then(liveStatusAnwenden)
|
||||
.catch(() => {
|
||||
istLive = false;
|
||||
radar.classList.remove("ist-live");
|
||||
texteNeuSetzen();
|
||||
});
|
||||
}
|
||||
|
||||
liveStatusLaden();
|
||||
setInterval(liveStatusLaden, 30000);
|
||||
document.addEventListener("visibilitychange", () => { if (!document.hidden) liveStatusLaden(); });
|
||||
document.addEventListener("dogi-sprache-geaendert", texteNeuSetzen);
|
||||
}
|
||||
|
||||
liveStatusLaden();
|
||||
setInterval(liveStatusLaden, 30000);
|
||||
document.addEventListener("visibilitychange", () => { if (!document.hidden) liveStatusLaden(); });
|
||||
document.addEventListener("dogi-sprache-geaendert", texteNeuSetzen);
|
||||
/* ===================================================================
|
||||
Uhr 2: "spezielles Live-Event" aus der Verwaltung (20.08.2026, neu).
|
||||
Nur sichtbar, wenn /special-event ein aktives, noch bevorstehendes
|
||||
Event liefert. Zieluhrzeit kann Tage entfernt sein -> Countdown zeigt
|
||||
bei Bedarf "Xd HH:MM:SS" statt nur HH:MM:SS. ================================================================= */
|
||||
const seWrap = document.getElementById("se-radar-wrap");
|
||||
if (seWrap) {
|
||||
const seRadar = document.getElementById("se-radar");
|
||||
const seNowHand = document.getElementById("se-radar-now-hand");
|
||||
const seNowDot = document.getElementById("se-radar-now-dot");
|
||||
const seCountdown = document.getElementById("se-radar-countdown");
|
||||
const seTitel = document.getElementById("se-radar-titel");
|
||||
const seLink = document.getElementById("se-radar-link");
|
||||
let zielDatum = null;
|
||||
let countdownIntervalId = null;
|
||||
let zeigerIntervalId = null;
|
||||
|
||||
function seCountdownTick() {
|
||||
if (!zielDatum) return;
|
||||
const diffMs = zielDatum - new Date();
|
||||
if (diffMs <= 0) {
|
||||
seRadar.classList.add("ist-live");
|
||||
seCountdown.textContent = window.dogiUebersetzen ? window.dogiUebersetzen("sp_radar_live_generic") : "Live!";
|
||||
clearInterval(countdownIntervalId);
|
||||
return;
|
||||
}
|
||||
const gesamtSek = Math.floor(diffMs / 1000);
|
||||
const tage = Math.floor(gesamtSek / 86400);
|
||||
const std = Math.floor((gesamtSek % 86400) / 3600);
|
||||
const min = Math.floor((gesamtSek % 3600) / 60);
|
||||
const sek = gesamtSek % 60;
|
||||
seCountdown.textContent = tage > 0
|
||||
? `${tage}T ${zweistellig(std)}:${zweistellig(min)}:${zweistellig(sek)}`
|
||||
: `${zweistellig(std)}:${zweistellig(min)}:${zweistellig(sek)}`;
|
||||
}
|
||||
|
||||
// Der "Jetzt"-Zeiger zeigt wie bei Uhr 1 die ECHTE aktuelle Uhrzeit --
|
||||
// der magentafarbene Fixpunkt markiert dagegen die Tageszeit, zu der
|
||||
// das spezielle Event stattfindet. So bleibt die Bildsprache zwischen
|
||||
// beiden Uhren konsistent (nur der Fixpunkt unterscheidet sich).
|
||||
function seZeigerTick() {
|
||||
const jetzt = new Date();
|
||||
zeigerAktualisieren(seNowHand, seNowDot, jetzt.getHours() + jetzt.getMinutes() / 60 + jetzt.getSeconds() / 3600);
|
||||
}
|
||||
|
||||
function specialEventLaden() {
|
||||
return fetch(`${API_BASE_URL}/special-event`, { cache: "no-store" })
|
||||
.then((res) => res.json())
|
||||
.then((data) => {
|
||||
const event = data && data.ok ? data.event : null;
|
||||
if (countdownIntervalId) clearInterval(countdownIntervalId);
|
||||
if (zeigerIntervalId) clearInterval(zeigerIntervalId);
|
||||
if (!event) {
|
||||
seWrap.hidden = true;
|
||||
zielDatum = null;
|
||||
return;
|
||||
}
|
||||
zielDatum = new Date(event.zieldatum);
|
||||
seWrap.hidden = false;
|
||||
seRadar.classList.remove("ist-live");
|
||||
seTitel.textContent = window.dogiFeld ? window.dogiFeld(event.titel) : event.titel?.de || "";
|
||||
zeichneZiffernblatt(document.getElementById("se-radar-ticks"), document.getElementById("se-radar-fixmarker"), zielDatum.getHours() + zielDatum.getMinutes() / 60);
|
||||
seZeigerTick();
|
||||
seCountdownTick();
|
||||
zeigerIntervalId = setInterval(seZeigerTick, 15000);
|
||||
countdownIntervalId = setInterval(seCountdownTick, 1000);
|
||||
if (event.link) {
|
||||
seLink.href = event.link;
|
||||
seLink.hidden = false;
|
||||
} else {
|
||||
seLink.hidden = true;
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
seWrap.hidden = true;
|
||||
});
|
||||
}
|
||||
|
||||
specialEventLaden();
|
||||
setInterval(specialEventLaden, 60000); // reicht -- Aenderungen in der Verwaltung muessen nicht sekundengenau ankommen
|
||||
document.addEventListener("dogi-sprache-geaendert", () => {
|
||||
if (zielDatum) specialEventLaden();
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -19,10 +19,10 @@
|
||||
<meta name="twitter:description" content="Du bist Streamer und suchst einen Manager? Bewirb dich als Creator bei Spicy Media." />
|
||||
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
</head>
|
||||
<body class="mit-hintergrund bewerben-seite" style="--page-bg:url('/assets/img/bg-bewerben-creator.jpg');--page-bg-mobile:url('/assets/img/bg-bewerben-creator-mobile.jpg');">
|
||||
<div id="site-header"></div>
|
||||
@@ -70,8 +70,8 @@
|
||||
</main>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/forms.js?v=20260820i"></script>
|
||||
<script src="assets/js/i18n-bewerben-creator.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/forms.js?v=20260820j"></script>
|
||||
<script src="assets/js/i18n-bewerben-creator.js?v=20260820j"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -22,10 +22,10 @@
|
||||
<meta name="twitter:description" content="Kooperationsanfrage an Manager DogFather / Spicy Media." />
|
||||
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
</head>
|
||||
<body class="mit-hintergrund bewerben-seite" style="--page-bg:url('/assets/img/bg-bewerben.jpg');--page-bg-mobile:url('/assets/img/bg-bewerben-mobile.jpg');">
|
||||
<div id="site-header"></div>
|
||||
@@ -68,8 +68,8 @@
|
||||
</main>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/forms.js?v=20260820i"></script>
|
||||
<script src="assets/js/i18n-bewerben-kooperation.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/forms.js?v=20260820j"></script>
|
||||
<script src="assets/js/i18n-bewerben-kooperation.js?v=20260820j"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+7
-7
@@ -19,10 +19,10 @@
|
||||
<meta name="twitter:description" content="Werde Modi bei Team Dogi — DogFathers persönliches Community-Team." />
|
||||
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
</head>
|
||||
<body class="mit-hintergrund bewerben-seite" style="--page-bg:url('/assets/img/bg-dogfather.jpg');--page-bg-mobile:url('/assets/img/bg-dogfather-mobile.jpg');">
|
||||
<div id="site-header"></div>
|
||||
@@ -79,8 +79,8 @@
|
||||
</main>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/forms.js?v=20260820i"></script>
|
||||
<script src="assets/js/i18n-bewerben-modi.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/forms.js?v=20260820j"></script>
|
||||
<script src="assets/js/i18n-bewerben-modi.js?v=20260820j"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+7
-7
@@ -19,10 +19,10 @@
|
||||
<meta name="twitter:description" content="Werde Scout für DogFather bei der Spicy Media Agentur — finde neue Talente." />
|
||||
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
</head>
|
||||
<body class="mit-hintergrund bewerben-seite" style="--page-bg:url('/assets/img/bg-scouts.jpg');--page-bg-mobile:url('/assets/img/bg-scouts-mobile.jpg');">
|
||||
<div id="site-header"></div>
|
||||
@@ -71,8 +71,8 @@
|
||||
</main>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/forms.js?v=20260820i"></script>
|
||||
<script src="assets/js/i18n-bewerben-scout.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/forms.js?v=20260820j"></script>
|
||||
<script src="assets/js/i18n-bewerben-scout.js?v=20260820j"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+6
-6
@@ -19,10 +19,10 @@
|
||||
<meta name="twitter:description" content="Werde Teil vom Team: Modi bei Team Dogi, Scout oder Creator bei Spicy Media, oder Kooperation anfragen." />
|
||||
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
</head>
|
||||
<body class="mit-hintergrund bewerben-seite" style="--page-bg:url('/assets/img/bg-bewerben-split.jpg');--page-bg-mobile:url('/assets/img/bg-bewerben-split-mobile.jpg');">
|
||||
<div id="site-header"></div>
|
||||
@@ -85,7 +85,7 @@
|
||||
</main>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/i18n-bewerben.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/i18n-bewerben.js?v=20260820j"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+6
-6
@@ -19,10 +19,10 @@
|
||||
<meta name="twitter:description" content="Der Husky an DogFathers Seite — das tierische Gesicht der HasiDog-Welt." />
|
||||
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
</head>
|
||||
<body class="mit-hintergrund" style="--page-bg:url('/assets/img/bg-casper.jpg');--page-bg-mobile:url('/assets/img/bg-casper-mobile.jpg');">
|
||||
<div id="site-header"></div>
|
||||
@@ -85,7 +85,7 @@
|
||||
</main>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/i18n-casper.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/i18n-casper.js?v=20260820j"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+6
-6
@@ -19,10 +19,10 @@
|
||||
<meta name="twitter:description" content="Team Dogi ist Familie — die Community rund um DogFather und HasiDog." />
|
||||
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
</head>
|
||||
<body class="mit-hintergrund" style="--page-bg:url('/assets/img/bg-community.jpg');--page-bg-mobile:url('/assets/img/bg-community-mobile.jpg');">
|
||||
<div id="site-header"></div>
|
||||
@@ -84,7 +84,7 @@
|
||||
</main>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/i18n-community.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/i18n-community.js?v=20260820j"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+7
-7
@@ -19,10 +19,10 @@
|
||||
<meta name="twitter:description" content="Content Creator, die Teil von DogFather / Spicy Media sind." />
|
||||
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
</head>
|
||||
<body class="mit-hintergrund" style="--page-bg:url('/assets/img/bg-creator.jpg');--page-bg-mobile:url('/assets/img/bg-creator-mobile.jpg');">
|
||||
<div id="site-header"></div>
|
||||
@@ -59,9 +59,9 @@
|
||||
</main>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/data-creator.js?v=20260820i"></script>
|
||||
<script src="assets/js/i18n-creator.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/data-creator.js?v=20260820j"></script>
|
||||
<script src="assets/js/i18n-creator.js?v=20260820j"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const grid = document.getElementById("creator-grid");
|
||||
|
||||
+6
-6
@@ -19,10 +19,10 @@
|
||||
<meta name="twitter:description" content="Wer ist DogFather wirklich? Persönlichkeit, Werte und die Geschichte hinter dem Content." />
|
||||
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
</head>
|
||||
<body class="mit-hintergrund" style="--page-bg:url('/assets/img/bg-dogfather-person.jpg');--page-bg-mobile:url('/assets/img/bg-dogfather-person-mobile.jpg');">
|
||||
<div id="site-header"></div>
|
||||
@@ -158,7 +158,7 @@
|
||||
</main>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/i18n-dogfather.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/i18n-dogfather.js?v=20260820j"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||
<meta name="apple-mobile-web-app-title" content="DogFather" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<style>
|
||||
/* =====================================================================
|
||||
Zugangsseite — bewusst kein braves Standard-Login-Formular, sondern
|
||||
|
||||
+6
-6
@@ -19,10 +19,10 @@
|
||||
<meta name="twitter:description" content="HasiDog: Maskottchen, Musikprojekt und die verspielte, familiäre Seite von Team Dogi." />
|
||||
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
</head>
|
||||
<body class="mit-hintergrund" style="--page-bg:url('/assets/img/bg-hasidog.jpg');--page-bg-mobile:url('/assets/img/bg-hasidog-mobile.jpg');">
|
||||
<div id="site-header"></div>
|
||||
@@ -182,7 +182,7 @@
|
||||
</main>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/i18n-hasidog.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/i18n-hasidog.js?v=20260820j"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+9
-9
@@ -19,10 +19,10 @@
|
||||
<meta name="twitter:description" content="DOGFATHER UNIVERSE: die Heimat von DogFather als Streamer, der HasiDog-Community und Manager DogFather bei Spicy Media." />
|
||||
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
</head>
|
||||
<body class="start-seite">
|
||||
<div id="site-header"></div>
|
||||
@@ -293,11 +293,11 @@
|
||||
</main>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/data-modis.js?v=20260820i"></script>
|
||||
<script src="assets/js/data-scouts.js?v=20260820i"></script>
|
||||
<script src="assets/js/data-aktionen.js?v=20260820i"></script>
|
||||
<script src="assets/js/i18n-index.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/data-modis.js?v=20260820j"></script>
|
||||
<script src="assets/js/data-scouts.js?v=20260820j"></script>
|
||||
<script src="assets/js/data-aktionen.js?v=20260820j"></script>
|
||||
<script src="assets/js/i18n-index.js?v=20260820j"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
<script>
|
||||
// Gleiche URL wie in assets/js/forms.js / postfach.html — läuft seit
|
||||
// 05.08.2026 auf dem eigenen Server statt auf Cloudflare Workers.
|
||||
|
||||
+6
-6
@@ -19,10 +19,10 @@
|
||||
<meta name="twitter:description" content="Kontakt, Impressum und Datenschutz von DOGFATHER UNIVERSE." />
|
||||
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="site-header"></div>
|
||||
@@ -126,7 +126,7 @@
|
||||
</main>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/i18n-kontakt.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/i18n-kontakt.js?v=20260820j"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+6
-6
@@ -19,10 +19,10 @@
|
||||
<meta name="twitter:description" content="Alle Social-Media- und Musik-Links von DogFather an einem Ort — plus QR-Codes." />
|
||||
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
<style>
|
||||
/* Rabattcodes: an das Supporter-Abo gekoppelt (Nutzer-Feedback
|
||||
03.08.2026: "verbinde es mit dem Abo... wenn die Leute drauf drücken
|
||||
@@ -140,8 +140,8 @@
|
||||
</main>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/i18n-links.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/i18n-links.js?v=20260820j"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
<script>
|
||||
(function () {
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
|
||||
+6
-6
@@ -19,10 +19,10 @@
|
||||
<meta name="twitter:description" content="DogFather als Manager bei der Spicy Media Agency: Scouts, Creator und faire Zusammenarbeit." />
|
||||
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
</head>
|
||||
<body class="mit-hintergrund" style="--page-bg:url('/assets/img/bg-manager.jpg');--page-bg-mobile:url('/assets/img/bg-manager-mobile.jpg');">
|
||||
<div id="site-header"></div>
|
||||
@@ -126,7 +126,7 @@
|
||||
</main>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/i18n-manager.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/i18n-manager.js?v=20260820j"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+9
-9
@@ -19,10 +19,10 @@
|
||||
<meta name="twitter:description" content="Fotos und Videos rund um Husky Casper an einem Ort." />
|
||||
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
</head>
|
||||
<body class="mit-hintergrund" data-welt="casper" style="--page-bg:url('/assets/img/bg-casper.jpg');--page-bg-mobile:url('/assets/img/bg-casper-mobile.jpg');">
|
||||
<div id="site-header"></div>
|
||||
@@ -59,10 +59,10 @@
|
||||
</div>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/data-media.js?v=20260820i"></script>
|
||||
<script src="assets/js/data-videos.js?v=20260820i"></script>
|
||||
<script src="assets/js/medien-welt.js?v=20260820i"></script>
|
||||
<script src="assets/js/i18n-medien-casper.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/data-media.js?v=20260820j"></script>
|
||||
<script src="assets/js/data-videos.js?v=20260820j"></script>
|
||||
<script src="assets/js/medien-welt.js?v=20260820j"></script>
|
||||
<script src="assets/js/i18n-medien-casper.js?v=20260820j"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+10
-10
@@ -19,10 +19,10 @@
|
||||
<meta name="twitter:description" content="Fotos, Videos und Events aus DogFathers Welt an einem Ort." />
|
||||
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
</head>
|
||||
<body class="mit-hintergrund" data-welt="dogfather" style="--page-bg:url('/assets/img/bg-dogfather.jpg');--page-bg-mobile:url('/assets/img/bg-dogfather-mobile.jpg');">
|
||||
<div id="site-header"></div>
|
||||
@@ -65,11 +65,11 @@
|
||||
</div>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/data-media.js?v=20260820i"></script>
|
||||
<script src="assets/js/data-videos.js?v=20260820i"></script>
|
||||
<script src="assets/js/data-aktionen.js?v=20260820i"></script>
|
||||
<script src="assets/js/medien-welt.js?v=20260820i"></script>
|
||||
<script src="assets/js/i18n-medien-dogfather.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/data-media.js?v=20260820j"></script>
|
||||
<script src="assets/js/data-videos.js?v=20260820j"></script>
|
||||
<script src="assets/js/data-aktionen.js?v=20260820j"></script>
|
||||
<script src="assets/js/medien-welt.js?v=20260820j"></script>
|
||||
<script src="assets/js/i18n-medien-dogfather.js?v=20260820j"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+10
-10
@@ -19,10 +19,10 @@
|
||||
<meta name="twitter:description" content="Fotos, Videos und Events aus der HasiDog-Welt an einem Ort." />
|
||||
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
</head>
|
||||
<body class="mit-hintergrund" data-welt="hasidog" style="--page-bg:url('/assets/img/bg-hasidog.jpg');--page-bg-mobile:url('/assets/img/bg-hasidog-mobile.jpg');">
|
||||
<div id="site-header"></div>
|
||||
@@ -65,11 +65,11 @@
|
||||
</div>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/data-media.js?v=20260820i"></script>
|
||||
<script src="assets/js/data-videos.js?v=20260820i"></script>
|
||||
<script src="assets/js/data-aktionen.js?v=20260820i"></script>
|
||||
<script src="assets/js/medien-welt.js?v=20260820i"></script>
|
||||
<script src="assets/js/i18n-medien-hasidog.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/data-media.js?v=20260820j"></script>
|
||||
<script src="assets/js/data-videos.js?v=20260820j"></script>
|
||||
<script src="assets/js/data-aktionen.js?v=20260820j"></script>
|
||||
<script src="assets/js/medien-welt.js?v=20260820j"></script>
|
||||
<script src="assets/js/i18n-medien-hasidog.js?v=20260820j"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+9
-9
@@ -16,10 +16,10 @@
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="robots" content="noindex" /> <!-- generische URL, echte Team-Seiten verlinken hierher -->
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
<style>
|
||||
.profil-photo { aspect-ratio: 4/5; max-width: 420px; margin: 0 auto; }
|
||||
.profil-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
|
||||
@@ -130,11 +130,11 @@
|
||||
</main>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/data-modis.js?v=20260820i"></script>
|
||||
<script src="assets/js/data-scouts.js?v=20260820i"></script>
|
||||
<script src="assets/js/data-creator.js?v=20260820i"></script>
|
||||
<script src="assets/js/i18n-profil.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/data-modis.js?v=20260820j"></script>
|
||||
<script src="assets/js/data-scouts.js?v=20260820j"></script>
|
||||
<script src="assets/js/data-creator.js?v=20260820j"></script>
|
||||
<script src="assets/js/i18n-profil.js?v=20260820j"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const slug = new URLSearchParams(location.search).get("p") || "";
|
||||
|
||||
+6
-6
@@ -19,10 +19,10 @@
|
||||
<meta name="twitter:description" content="Rabattcodes von Dogis Partnern für Team Dogi — spar bares Geld bei ausgewählten Marken." />
|
||||
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
<style>
|
||||
/* Leere-Zustand-Kachel im "Gutschein"-Look: gestrichelter Rand wie ein
|
||||
ausgeschnittener Coupon, damit auch OHNE echte Codes schon klar ist,
|
||||
@@ -131,8 +131,8 @@
|
||||
</main>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/i18n-rabattcodes.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/i18n-rabattcodes.js?v=20260820j"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
<script>
|
||||
(function () {
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
|
||||
@@ -64,6 +64,7 @@ import {
|
||||
listSupporters, getSupporterDetail, updatePremium, listCollections, upsertCollection, getAdminOverview,
|
||||
} from "./routes/supporter-admin.js";
|
||||
import { getEventsPublic, getEventsAdmin, saveEvent, uploadEventImage } from "./routes/events.js";
|
||||
import { getSpecialEventPublic, getSpecialEventAdmin, saveSpecialEvent } from "./routes/special-event.js";
|
||||
import {
|
||||
createPoll, listPolls, closePoll, reopenPoll, deletePoll, getActivePollPublic, voteOnPoll,
|
||||
} from "./routes/polls.js";
|
||||
@@ -157,6 +158,7 @@ app.post("/submit", wrap(submitApplication));
|
||||
app.get("/live-status", wrap(handleLiveStatusGet));
|
||||
app.post("/auth/login", wrap(login));
|
||||
app.get("/events-of-year", wrap(getEventsPublic));
|
||||
app.get("/special-event", wrap(getSpecialEventPublic));
|
||||
|
||||
app.post("/supporter/register", wrap(registerSupporter));
|
||||
app.post("/supporter/verify-email", wrap(verifySupporterEmail));
|
||||
@@ -194,6 +196,10 @@ app.post("/admin/events/list", requireTeamSession, withSession(getEventsAdmin));
|
||||
app.post("/admin/events/save", requireTeamSession, withSession(saveEvent));
|
||||
app.post("/admin/events/upload-image", requireTeamSession, bildUpload.single("image"), withSession(uploadEventImage));
|
||||
|
||||
// Spezielles Live-Event mit Countdown auf streamplan.html (20.08.2026)
|
||||
app.post("/admin/special-event", requireTeamSession, withSession(getSpecialEventAdmin));
|
||||
app.post("/admin/special-event/save", requireTeamSession, withSession(saveSpecialEvent));
|
||||
|
||||
app.post("/admin/roles/list", requireTeamSession, withSession(listRoles));
|
||||
app.post("/admin/roles/create", requireTeamSession, withSession(createRole));
|
||||
app.post("/admin/roles/update", requireTeamSession, withSession(updateRole));
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/* =====================================================================
|
||||
routes/special-event.js — "Spezielles Live-Event" für streamplan.html
|
||||
(20.08.2026, Nutzer-Wunsch: "sehr wichtig ist dass ich auch spezielle
|
||||
live events da auch eintragen kann in der verwaltungsseite so dass da
|
||||
eine zweite uhr erscheint wo die zeit dann für dieses spezielle event
|
||||
läuft"). Anders als "Event des Jahres" (2 feste Slots) gibt es hier
|
||||
GENAU EIN Event mit einem exakten Zieldatum+Uhrzeit statt nur einem
|
||||
freien Datumstext — daraus lässt sich ein echter Countdown berechnen.
|
||||
Läuft auf derselben app_settings-Tabelle (key/value), kein Schema-Umbau
|
||||
nötig. Gleiche Rechte-/Freigabe-Logik wie "Event des Jahres"
|
||||
(EVENTS_MANAGE, Owner immer erlaubt, öffentlich lesbar, aber nur wenn
|
||||
aktiviert UND das Zieldatum noch in der Zukunft liegt). ===================================================================== */
|
||||
import { db } from "../db.js";
|
||||
import { hasPermission } from "../lib/permissions.js";
|
||||
import { json } from "../lib/http.js";
|
||||
import { logAction } from "../lib/audit.js";
|
||||
import { uebersetzeAlleSprachen } from "../lib/translate.js";
|
||||
|
||||
const SETTINGS_KEY = "special_live_event";
|
||||
|
||||
function can(session, key) {
|
||||
if (!session) return false;
|
||||
if (session.isOwner) return true;
|
||||
return hasPermission(session.permissions, session.overrides, key);
|
||||
}
|
||||
|
||||
function forbidden(res) {
|
||||
return json(res, { ok: false, error: "Keine Berechtigung." }, 403);
|
||||
}
|
||||
|
||||
function laden() {
|
||||
const row = db.prepare(`SELECT value FROM app_settings WHERE key = ?`).get(SETTINGS_KEY);
|
||||
if (!row) return null;
|
||||
try {
|
||||
return JSON.parse(row.value);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Öffentlich, keine Session: nur wenn aktiviert UND das Zieldatum noch
|
||||
nicht vorbei ist (ein abgelaufenes Event soll nicht ewig als "Countdown
|
||||
bei 00:00:00" hängen bleiben, sondern einfach verschwinden). */
|
||||
export async function getSpecialEventPublic(req, res) {
|
||||
const eintrag = laden();
|
||||
const istGueltig = eintrag && eintrag.aktiv && new Date(eintrag.zieldatum) > new Date();
|
||||
return json(res, { ok: true, event: istGueltig ? eintrag : null });
|
||||
}
|
||||
|
||||
/** Für die Verwaltung: liefert den rohen Stand (auch inaktiv/abgelaufen),
|
||||
damit das Formular beim Öffnen alles vorausfüllen kann. */
|
||||
export async function getSpecialEventAdmin(req, res, session) {
|
||||
if (!can(session, "EVENTS_MANAGE")) return forbidden(res);
|
||||
return json(res, { ok: true, event: laden() });
|
||||
}
|
||||
|
||||
export async function saveSpecialEvent(req, res, session) {
|
||||
if (!can(session, "EVENTS_MANAGE")) return forbidden(res);
|
||||
const body = req.body || {};
|
||||
|
||||
const titelDe = String(body.titel || "").trim().slice(0, 120);
|
||||
const zieldatumRoh = String(body.zieldatum || "").trim();
|
||||
const link = String(body.link || "").trim().slice(0, 300) || null;
|
||||
const aktiv = !!body.aktiv;
|
||||
|
||||
if (!titelDe) return json(res, { ok: false, error: "Titel ist Pflicht." }, 400);
|
||||
|
||||
const zieldatum = new Date(zieldatumRoh);
|
||||
if (!zieldatumRoh || Number.isNaN(zieldatum.getTime())) {
|
||||
return json(res, { ok: false, error: "Bitte ein gültiges Datum + Uhrzeit angeben." }, 400);
|
||||
}
|
||||
if (link && !/^https?:\/\//i.test(link)) {
|
||||
return json(res, { ok: false, error: "Link muss mit http:// oder https:// beginnen." }, 400);
|
||||
}
|
||||
if (aktiv && zieldatum <= new Date()) {
|
||||
return json(res, { ok: false, error: "Das Zieldatum liegt in der Vergangenheit — zum Aktivieren muss es in der Zukunft liegen." }, 400);
|
||||
}
|
||||
|
||||
const titel = await uebersetzeAlleSprachen(titelDe);
|
||||
|
||||
const eintrag = {
|
||||
titel,
|
||||
zieldatum: zieldatum.toISOString(),
|
||||
link,
|
||||
aktiv,
|
||||
aktualisiertVon: session.actor,
|
||||
aktualisiertAm: new Date().toISOString(),
|
||||
};
|
||||
|
||||
db.prepare(
|
||||
`INSERT INTO app_settings (key, value, updated_at) VALUES (?, ?, ?)
|
||||
ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at`
|
||||
).run(SETTINGS_KEY, JSON.stringify(eintrag), eintrag.aktualisiertAm);
|
||||
|
||||
logAction(session.actor, "special_event.saved", null, { titel: titelDe, zieldatum: eintrag.zieldatum, aktiv });
|
||||
return json(res, { ok: true, event: eintrag });
|
||||
}
|
||||
+6
-6
@@ -19,10 +19,10 @@
|
||||
<meta name="twitter:description" content="Was die Community und das Team über DogFather sagen." />
|
||||
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
</head>
|
||||
<body class="mit-hintergrund" style="--page-bg:url('/assets/img/bg-stimmen.jpg');--page-bg-mobile:url('/assets/img/bg-stimmen-mobile.jpg');">
|
||||
<div id="site-header"></div>
|
||||
@@ -57,7 +57,7 @@
|
||||
</main>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/i18n-stimmen.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/i18n-stimmen.js?v=20260820j"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+6
-6
@@ -19,10 +19,10 @@
|
||||
<meta name="twitter:description" content="Die persönliche Geschichte hinter DogFather — Filipe, Streamer, Manager bei Spicy Media und Hundepapa von Husky Casper." />
|
||||
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
</head>
|
||||
<body class="mit-hintergrund" style="--page-bg:url('/assets/img/bg-streamer.jpg');--page-bg-mobile:url('/assets/img/bg-streamer-mobile.jpg');">
|
||||
<div id="site-header"></div>
|
||||
@@ -189,7 +189,7 @@
|
||||
</main>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/i18n-streamer.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/i18n-streamer.js?v=20260820j"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+68
-29
@@ -19,17 +19,17 @@
|
||||
<meta name="twitter:description" content="Wann geht DogFather live? Streamplan und Livebereich." />
|
||||
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
</head>
|
||||
<body class="mit-hintergrund" style="--page-bg:url('/assets/img/bg-streamplan.jpg?v=20260820i');--page-bg-mobile:url('/assets/img/bg-streamplan-mobile.jpg?v=20260820i');">
|
||||
<body class="mit-hintergrund" style="--page-bg:url('/assets/img/bg-streamplan.jpg?v=20260820j');--page-bg-mobile:url('/assets/img/bg-streamplan-mobile.jpg?v=20260820j');">
|
||||
<div id="site-header"></div>
|
||||
|
||||
<main>
|
||||
<section class="hero page-bg">
|
||||
<div class="hero-banner"><img src="/assets/img/bg-streamplan.jpg?v=20260820i" alt="" loading="eager" /></div>
|
||||
<div class="hero-banner"><img src="/assets/img/bg-streamplan.jpg?v=20260820j" alt="" loading="eager" /></div>
|
||||
<div class="container">
|
||||
<span class="eyebrow" data-i18n="sp_eyebrow">Welt 1 — DogFather</span>
|
||||
<h1 data-i18n="sp_h1">Streamplan & Livebereich</h1>
|
||||
@@ -37,28 +37,67 @@
|
||||
|
||||
<!-- Live-Radar (20.08.2026, Nutzer-Wunsch "geiler und spezieller"): 24h-Ziffernblatt
|
||||
mit festem 20-Uhr-Leuchtpunkt + echtem "Jetzt"-Zeiger, schaltet live auf Rot/Puls
|
||||
um, sonst zählt es zum nächsten 20-Uhr-Termin runter. Siehe assets/js/streamplan.js. -->
|
||||
<div class="stream-radar-wrap">
|
||||
<div class="stream-radar" id="stream-radar">
|
||||
<div class="stream-radar-sweep" aria-hidden="true"></div>
|
||||
<svg viewBox="0 0 300 300" class="stream-radar-dial" aria-hidden="true">
|
||||
<circle cx="150" cy="150" r="130" class="radar-ring-outer"></circle>
|
||||
<circle cx="150" cy="150" r="94" class="radar-ring-inner"></circle>
|
||||
<g id="radar-ticks"></g>
|
||||
<g id="radar-fixmarker"></g>
|
||||
<line id="radar-now-hand" class="radar-now-hand" x1="150" y1="150" x2="150" y2="50"></line>
|
||||
<circle id="radar-now-dot" class="radar-now-dot" cx="150" cy="50" r="5"></circle>
|
||||
<circle cx="150" cy="150" r="4" class="radar-center-dot"></circle>
|
||||
</svg>
|
||||
<div class="stream-radar-center">
|
||||
<span class="stream-radar-dot" id="radar-status-dot"></span>
|
||||
<span class="stream-radar-status" id="radar-status-text" data-i18n="sp_radar_loading">Lädt …</span>
|
||||
<span class="stream-radar-countdown" id="radar-countdown"></span>
|
||||
<span class="stream-radar-sub" id="radar-status-sub"></span>
|
||||
um, sonst zählt es zum nächsten 20-Uhr-Termin runter. Zweite Uhr (rechts, Magenta/
|
||||
Violett) für ein optionales "spezielles Live-Event" aus der Verwaltung -- nur
|
||||
sichtbar, wenn dort eins aktiviert ist. Siehe assets/js/streamplan.js. -->
|
||||
<div class="stream-radar-reihe">
|
||||
<div class="stream-radar-wrap">
|
||||
<div class="stream-radar" id="stream-radar">
|
||||
<div class="stream-radar-sweep" aria-hidden="true"></div>
|
||||
<svg viewBox="0 0 300 300" class="stream-radar-dial" aria-hidden="true">
|
||||
<defs>
|
||||
<linearGradient id="radarGradTaeglich" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" stop-color="#8fd9ea"></stop>
|
||||
<stop offset="50%" stop-color="#8b5cf6"></stop>
|
||||
<stop offset="100%" stop-color="#e8c465"></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<circle cx="150" cy="150" r="130" class="radar-ring-outer" stroke="url(#radarGradTaeglich)"></circle>
|
||||
<circle cx="150" cy="150" r="94" class="radar-ring-inner"></circle>
|
||||
<g id="radar-ticks"></g>
|
||||
<g id="radar-fixmarker"></g>
|
||||
<line id="radar-now-hand" class="radar-now-hand" x1="150" y1="150" x2="150" y2="50"></line>
|
||||
<circle id="radar-now-dot" class="radar-now-dot" cx="150" cy="50" r="5"></circle>
|
||||
<circle cx="150" cy="150" r="4" class="radar-center-dot"></circle>
|
||||
</svg>
|
||||
<div class="stream-radar-center">
|
||||
<span class="stream-radar-dot" id="radar-status-dot"></span>
|
||||
<span class="stream-radar-status" id="radar-status-text" data-i18n="sp_radar_loading">Lädt …</span>
|
||||
<span class="stream-radar-countdown" id="radar-countdown"></span>
|
||||
<span class="stream-radar-sub" id="radar-status-sub"></span>
|
||||
</div>
|
||||
</div>
|
||||
<a class="btn btn-primary stream-radar-watch-btn" id="radar-watch-btn" href="https://www.tiktok.com/@dogfather0804" target="_blank" rel="noopener" hidden data-i18n="sp_radar_watch_btn">🔴 Jetzt anschauen</a>
|
||||
<p class="small muted stream-radar-hinweis" data-i18n="sp_radar_hinweis">Alle Zeiten in deiner Ortszeit.</p>
|
||||
</div>
|
||||
|
||||
<div class="stream-radar-wrap" id="se-radar-wrap" hidden>
|
||||
<div class="stream-radar event-spezial" id="se-radar">
|
||||
<div class="stream-radar-sweep" aria-hidden="true"></div>
|
||||
<svg viewBox="0 0 300 300" class="stream-radar-dial" aria-hidden="true">
|
||||
<defs>
|
||||
<linearGradient id="radarGradSpezial" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" stop-color="#ff5cb8"></stop>
|
||||
<stop offset="50%" stop-color="#c9a6ff"></stop>
|
||||
<stop offset="100%" stop-color="#e8c465"></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<circle cx="150" cy="150" r="130" class="radar-ring-outer" stroke="url(#radarGradSpezial)"></circle>
|
||||
<circle cx="150" cy="150" r="94" class="radar-ring-inner"></circle>
|
||||
<g id="se-radar-ticks"></g>
|
||||
<g id="se-radar-fixmarker"></g>
|
||||
<line id="se-radar-now-hand" class="radar-now-hand" x1="150" y1="150" x2="150" y2="50"></line>
|
||||
<circle id="se-radar-now-dot" class="radar-now-dot" cx="150" cy="50" r="5"></circle>
|
||||
<circle cx="150" cy="150" r="4" class="radar-center-dot"></circle>
|
||||
</svg>
|
||||
<div class="stream-radar-center">
|
||||
<span class="stream-radar-titel" id="se-radar-titel"></span>
|
||||
<span class="stream-radar-countdown" id="se-radar-countdown"></span>
|
||||
<span class="stream-radar-sub" data-i18n="sp_radar_hinweis_spezial">Spezielles Live-Event</span>
|
||||
</div>
|
||||
</div>
|
||||
<a class="btn btn-primary stream-radar-watch-btn" id="se-radar-link" href="#" target="_blank" rel="noopener" hidden data-i18n="sp_radar_mehr_erfahren">Mehr erfahren →</a>
|
||||
</div>
|
||||
<a class="btn btn-primary stream-radar-watch-btn" id="radar-watch-btn" href="https://www.tiktok.com/@dogfather0804" target="_blank" rel="noopener" hidden data-i18n="sp_radar_watch_btn">🔴 Jetzt anschauen</a>
|
||||
<p class="small muted stream-radar-hinweis" data-i18n="sp_radar_hinweis">Alle Zeiten in deiner Ortszeit.</p>
|
||||
</div>
|
||||
|
||||
<div class="btn-row" style="justify-content:center;">
|
||||
@@ -87,8 +126,8 @@
|
||||
</main>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/i18n-streamplan.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/streamplan.js?v=20260820i"></script>
|
||||
<script src="assets/js/i18n-streamplan.js?v=20260820j"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
<script src="assets/js/streamplan.js?v=20260820j"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+7
-7
@@ -9,10 +9,10 @@
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<meta name="theme-color" content="#0b0d10" />
|
||||
<meta name="robots" content="noindex" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
<style>
|
||||
/* =====================================================================
|
||||
Supporter-Bereich — komplett neu gestaltet (Nutzer-Feedback
|
||||
@@ -416,9 +416,9 @@
|
||||
</main>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/i18n-supporter.js?v=20260820i"></script>
|
||||
<script src="assets/js/supporter.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/i18n-supporter.js?v=20260820j"></script>
|
||||
<script src="assets/js/supporter.js?v=20260820j"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
<script>
|
||||
(function () {
|
||||
const S = window.DogiSupporter;
|
||||
|
||||
+7
-7
@@ -19,10 +19,10 @@
|
||||
<meta name="twitter:description" content="VanVan, Diene, Funny, Miss und Marina — das Modi-/Core-Team von Team Dogi." />
|
||||
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
</head>
|
||||
<body class="mit-hintergrund" style="--page-bg:url('/assets/img/bg-dogfather.jpg');--page-bg-mobile:url('/assets/img/bg-dogfather-mobile.jpg');">
|
||||
<div id="site-header"></div>
|
||||
@@ -66,9 +66,9 @@
|
||||
</main>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/data-modis.js?v=20260820i"></script>
|
||||
<script src="assets/js/i18n-team-modis.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/data-modis.js?v=20260820j"></script>
|
||||
<script src="assets/js/i18n-team-modis.js?v=20260820j"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const grid = document.getElementById("modis-grid");
|
||||
|
||||
+7
-7
@@ -19,10 +19,10 @@
|
||||
<meta name="twitter:description" content="Die Scouts von Team Dogi bei Spicy Media." />
|
||||
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
</head>
|
||||
<body class="mit-hintergrund" style="--page-bg:url('/assets/img/bg-scouts.jpg');--page-bg-mobile:url('/assets/img/bg-scouts-mobile.jpg');">
|
||||
<div id="site-header"></div>
|
||||
@@ -49,9 +49,9 @@
|
||||
</main>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/data-scouts.js?v=20260820i"></script>
|
||||
<script src="assets/js/i18n-team-scouts.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/data-scouts.js?v=20260820j"></script>
|
||||
<script src="assets/js/i18n-team-scouts.js?v=20260820j"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const grid = document.getElementById("scouts-grid");
|
||||
|
||||
+6
-6
@@ -19,10 +19,10 @@
|
||||
<meta name="twitter:description" content="Eine persönliche Widmung von Dogi an Tili — seine TikTok-Muddi, die erste und bis heute einzige Streamerin, die ihm all die Zeit treu geblieben ist." />
|
||||
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
<style>
|
||||
/* Gleiche Anpassung wie vanvan.html: der site-weit etwas größere
|
||||
Fließtext wirkt bei einem so langen persönlichen Brief zu wuchtig —
|
||||
@@ -153,7 +153,7 @@
|
||||
</main>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/i18n-tt-muddi.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/i18n-tt-muddi.js?v=20260820j"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+6
-6
@@ -19,10 +19,10 @@
|
||||
<meta name="twitter:description" content="VanVan erzählt ihre Geschichte: wie sie zu Team Dogi kam, wer sie ist und was DogFather und Team Dogi ihr bedeuten." />
|
||||
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
<style>
|
||||
/* Auf Wunsch: der site-weit vergrößerte Fließtext wirkte auf VanVans
|
||||
eigener Seite zu groß (viel Text am Stück) — hier gezielt wieder
|
||||
@@ -175,7 +175,7 @@
|
||||
</main>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/i18n-vanvan.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/i18n-vanvan.js?v=20260820j"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+111
-6
@@ -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=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
<style>
|
||||
/* =====================================================================
|
||||
verwaltung.html — Dogis privater Command-Center-Bereich.
|
||||
@@ -803,6 +803,47 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===== "Spezielles Live-Event" (Streamplan-Seite) — 20.08.2026,
|
||||
Nutzer-Wunsch: "spezielle live events da auch eintragen ... so dass
|
||||
da eine zweite uhr erscheint wo die zeit dann für dieses spezielle
|
||||
event läuft." Anders als "Event des Jahres" hier ein echtes
|
||||
Datum+Uhrzeit statt eines freien Textes -- daraus baut
|
||||
streamplan.html einen echten Countdown. Nur sichtbar mit derselben
|
||||
EVENTS_MANAGE-Berechtigung. -->
|
||||
<section class="section-tight" id="special-event-root" style="display:none;padding-top:0;">
|
||||
<div class="container">
|
||||
<h2 class="text-center" style="margin-bottom:.3rem;">⚡ Spezielles Live-Event</h2>
|
||||
<p class="small muted text-center" style="max-width:60ch;margin:0 auto 1.4rem;">
|
||||
Erscheint als zweite Uhr auf der Streamplan-Seite, sobald aktiviert. Titel bitte auf
|
||||
Deutsch eintippen, wird beim Speichern automatisch übersetzt.
|
||||
</p>
|
||||
<div class="card vw-card vw-shine-card vw-noise" style="max-width:520px;margin:0 auto;padding:1.5rem;">
|
||||
<div class="field">
|
||||
<label for="se-titel">Titel (Deutsch)</label>
|
||||
<input type="text" id="se-titel" maxlength="120" placeholder="z. B. Großer Q&A-Abend" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="se-datum">Datum & Uhrzeit</label>
|
||||
<input type="datetime-local" id="se-datum" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="se-link">Link (optional, muss mit https:// beginnen)</label>
|
||||
<input type="url" id="se-link" placeholder="https://…" />
|
||||
</div>
|
||||
<label style="display:flex;align-items:center;gap:.6rem;margin:1rem 0;cursor:pointer;">
|
||||
<input type="checkbox" id="se-aktiv" style="width:1.2rem;height:1.2rem;" />
|
||||
<span>Aktiv — zweite Uhr auf der Streamplan-Seite sichtbar</span>
|
||||
</label>
|
||||
<p class="small muted" style="margin:-.4rem 0 1rem;">
|
||||
Nur mit Titel + Datum in der Zukunft aktivierbar. Ist das Datum vorbei, verschwindet
|
||||
die zweite Uhr automatisch wieder.
|
||||
</p>
|
||||
<button type="button" class="btn btn-primary" id="se-speichern" style="width:100%;">Speichern</button>
|
||||
<p class="small" id="se-status" style="margin-top:.6rem;"></p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===== Supporter-Liste ===== -->
|
||||
<section class="section-tight" id="supp-root" style="display:none;padding-top:0;">
|
||||
<div class="container" id="liste-ansicht">
|
||||
@@ -977,8 +1018,8 @@
|
||||
</main>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/admin-auth.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
<script src="assets/js/admin-auth.js?v=20260820j"></script>
|
||||
<script>
|
||||
(function () {
|
||||
const API_BASE_URL = "https://postfach.dogfather-universe.com";
|
||||
@@ -1051,6 +1092,8 @@
|
||||
if (window.AdminAuth.sessionHasPermission(session, "EVENTS_MANAGE")) {
|
||||
document.getElementById("events-root").style.display = "";
|
||||
await ladeUndRenderEvents(session);
|
||||
document.getElementById("special-event-root").style.display = "";
|
||||
await ladeUndRenderSpecialEvent();
|
||||
}
|
||||
const pollsBox = document.getElementById("box-abstimmungen");
|
||||
if (window.AdminAuth.sessionHasPermission(session, "POLLS_MANAGE")) {
|
||||
@@ -1069,6 +1112,7 @@
|
||||
document.getElementById("vw-stats-root").style.display = "none";
|
||||
document.getElementById("supp-root").style.display = "none";
|
||||
document.getElementById("events-root").style.display = "none";
|
||||
document.getElementById("special-event-root").style.display = "none";
|
||||
document.getElementById("box-abstimmungen").style.display = "none";
|
||||
}
|
||||
|
||||
@@ -1372,6 +1416,67 @@
|
||||
});
|
||||
}
|
||||
|
||||
/* ===== "Spezielles Live-Event" — Verwaltung (20.08.2026) =====
|
||||
Datum+Uhrzeit kommt vom Server als UTC-ISO-String, das <input
|
||||
type="datetime-local"> braucht aber "YYYY-MM-DDTHH:mm" in der
|
||||
LOKALEN Zeitzone der Person, die gerade in der Verwaltung sitzt —
|
||||
deshalb hier von Hand umgerechnet statt toISOString() (das würde UTC
|
||||
zurückgeben und beim erneuten Öffnen eine falsche Uhrzeit anzeigen). */
|
||||
function isoZuLokalemDatetimeLocal(iso) {
|
||||
const d = new Date(iso);
|
||||
const pad = (n) => String(n).padStart(2, "0");
|
||||
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;
|
||||
}
|
||||
|
||||
async function ladeUndRenderSpecialEvent() {
|
||||
const statusEl = document.getElementById("se-status");
|
||||
let eintrag = null;
|
||||
try {
|
||||
const res = await window.AdminAuth.apiCall(API_BASE_URL, "/admin/special-event", {});
|
||||
if (res.ok) eintrag = res.event;
|
||||
} catch {
|
||||
/* Formular bleibt leer, Speichern funktioniert trotzdem. */
|
||||
}
|
||||
if (eintrag) {
|
||||
document.getElementById("se-titel").value = eintrag.titel?.de || "";
|
||||
document.getElementById("se-datum").value = isoZuLokalemDatetimeLocal(eintrag.zieldatum);
|
||||
document.getElementById("se-link").value = eintrag.link || "";
|
||||
document.getElementById("se-aktiv").checked = !!eintrag.aktiv;
|
||||
}
|
||||
|
||||
document.getElementById("se-speichern").addEventListener("click", async () => {
|
||||
statusEl.textContent = "";
|
||||
const titel = document.getElementById("se-titel").value.trim();
|
||||
const datumRoh = document.getElementById("se-datum").value; // "YYYY-MM-DDTHH:mm", lokale Zeit
|
||||
if (!titel || !datumRoh) {
|
||||
statusEl.textContent = "Titel und Datum sind Pflicht.";
|
||||
statusEl.style.color = "#ff6b6b";
|
||||
return;
|
||||
}
|
||||
statusEl.textContent = "Wird gespeichert und übersetzt …";
|
||||
statusEl.style.color = "";
|
||||
// new Date("YYYY-MM-DDTHH:mm") interpretiert das als lokale Zeit dieses
|
||||
// Browsers -- .toISOString() macht daraus den korrekten UTC-Zeitpunkt,
|
||||
// den jede besuchende Person später in IHRER eigenen Ortszeit sieht.
|
||||
const zieldatum = new Date(datumRoh).toISOString();
|
||||
const res = await window.AdminAuth.apiCall(API_BASE_URL, "/admin/special-event/save", {
|
||||
titel,
|
||||
zieldatum,
|
||||
link: document.getElementById("se-link").value.trim(),
|
||||
aktiv: document.getElementById("se-aktiv").checked,
|
||||
});
|
||||
if (!res.ok) {
|
||||
statusEl.textContent = res.error || "Speichern fehlgeschlagen.";
|
||||
statusEl.style.color = "#ff6b6b";
|
||||
return;
|
||||
}
|
||||
statusEl.textContent = res.event.aktiv
|
||||
? "✅ Gespeichert — zweite Uhr ist live auf der Streamplan-Seite."
|
||||
: "✅ Als Entwurf gespeichert (noch nicht sichtbar).";
|
||||
statusEl.style.color = "#baf7d6";
|
||||
});
|
||||
}
|
||||
|
||||
// Nutzer-Wunsch 04.08.2026 (6. Runde): zwei getrennte Kisten/Formulare
|
||||
// (Dogi + VanVan) statt einem gemeinsamen Feld — beide rufen denselben
|
||||
// Login-Endpunkt auf, die Fehlermeldung erscheint jeweils nur in der
|
||||
|
||||
+6
-6
@@ -19,10 +19,10 @@
|
||||
<meta name="twitter:description" content="Die Werte, nach denen DogFather als Manager bei Spicy Media arbeitet." />
|
||||
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
</head>
|
||||
<body class="mit-hintergrund" style="--page-bg:url('/assets/img/bg-werte.jpg');--page-bg-mobile:url('/assets/img/bg-werte-mobile.jpg');">
|
||||
<div id="site-header"></div>
|
||||
@@ -113,7 +113,7 @@
|
||||
</main>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/i18n-werte.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/i18n-werte.js?v=20260820j"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+6
-6
@@ -19,10 +19,10 @@
|
||||
<meta name="twitter:description" content="Die Geschichte von DogFather in einer interaktiven Zeitleiste." />
|
||||
<meta name="twitter:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820i" />
|
||||
<link rel="stylesheet" href="assets/css/main.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260820j" />
|
||||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260820j" />
|
||||
</head>
|
||||
<body class="mit-hintergrund" style="--page-bg:url('/assets/img/bg-zeitreise.jpg');--page-bg-mobile:url('/assets/img/bg-zeitreise-mobile.jpg');">
|
||||
<div id="site-header"></div>
|
||||
@@ -219,8 +219,8 @@
|
||||
</main>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="assets/js/i18n-zeitreise.js?v=20260820i"></script>
|
||||
<script src="assets/js/main.js?v=20260820i"></script>
|
||||
<script src="assets/js/i18n-zeitreise.js?v=20260820j"></script>
|
||||
<script src="assets/js/main.js?v=20260820j"></script>
|
||||
<script>
|
||||
/* Wachstums-Reveal: Äste blenden sich beim Scrollen sanft ein — passt
|
||||
zum "wachsenden Baum"-Konzept dieser Seite. Rein page-lokal, betrifft
|
||||
|
||||
Reference in New Issue
Block a user