Die drei Fußzeilen-Spaltentitel (Filipe, Dogi&Hasi & Manager, Mehr) waren <h4>, obwohl der Hauptinhalt bei h2/h3 endet -- ein Sprung in der Überschriftenordnung (h2 -> h4) auf jeder Seite. Für Bildschirmleser ist die Überschriftenliste das Inhaltsverzeichnis; eine übersprungene Ebene stört die Orientierung. Jetzt <h2> (eigenständige Abschnitte unter der Seiten-h1). Die Optik bleibt exakt: Der CSS-Selektor .footer-grid h4 wurde zu .footer-grid h2 umgezogen, die kleine, gedämpfte Darstellung (.85rem, uppercase, Akzentfarbe) überschreibt weiterhin die große globale h2-Größe. Teil des Barrierefreiheits-Durchgangs (pruef-barrierefrei.mjs). Behebt die reinen Fußzeilen-Fälle; die Hauptinhalt-Überschriften folgen separat. Co-Authored-By: Claude Opus 5 <[email protected]>
505 lines
27 KiB
HTML
505 lines
27 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="de" data-theme="dogfather">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<title>DOGFATHER UNIVERSE — Streamer. Community. HasiDog. Manager.</title>
|
||
<meta name="description" content="DOGFATHER UNIVERSE: die Heimat von DogFather als Streamer, der HasiDog-Community und Manager DogFather bei Spicy Media." />
|
||
<link rel="icon" type="image/png" href="assets/img/favicon.png" />
|
||
<link rel="manifest" href="/manifest.json" />
|
||
<meta name="theme-color" content="#0b0d10" />
|
||
<meta property="og:type" content="website" />
|
||
<meta property="og:site_name" content="DOGFATHER UNIVERSE" />
|
||
<meta property="og:title" content="DOGFATHER UNIVERSE — Streamer. Community. HasiDog. Manager." />
|
||
<meta property="og:description" content="DOGFATHER UNIVERSE: die Heimat von DogFather als Streamer, der HasiDog-Community und Manager DogFather bei Spicy Media." />
|
||
<meta property="og:image" content="https://dogfather-universe.com/assets/img/og-cover.jpg" />
|
||
<meta property="og:url" content="https://dogfather-universe.com/index.html" />
|
||
<meta name="twitter:card" content="summary_large_image" />
|
||
<meta name="twitter:title" content="DOGFATHER UNIVERSE — Streamer. Community. HasiDog. Manager." />
|
||
<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=20260828a" />
|
||
<link rel="stylesheet" href="assets/css/theme-dogfather.css?v=20260828a" />
|
||
<link rel="stylesheet" href="assets/css/theme-hasidog.css?v=20260828a" />
|
||
<link rel="stylesheet" href="assets/css/theme-spicymedia.css?v=20260828a" />
|
||
</head>
|
||
<body class="start-seite">
|
||
<div id="site-header"></div>
|
||
|
||
<main>
|
||
<!-- ================= HERO ================= -->
|
||
<section class="hero hero-cinematic">
|
||
<!-- Großes Trio-Artwork als Kino-Hintergrund (DogFather · Dogi · HasiDog) -->
|
||
<div class="hero-artwork" aria-hidden="true"></div>
|
||
|
||
<div class="hero-atmosphere" aria-hidden="true">
|
||
<span class="atmosphere-blend"></span>
|
||
|
||
<!-- Zone 1: Polarlicht oben -->
|
||
<span class="aurora-band a1"></span>
|
||
<span class="aurora-band a2"></span>
|
||
<span class="aurora-band a3"></span>
|
||
|
||
<!-- Zone 2: Rauch in der Mitte -->
|
||
<span class="smoke-blob" style="width:380px;height:380px;top:26%;left:4%;"></span>
|
||
<span class="smoke-blob" style="width:300px;height:300px;top:38%;right:6%;animation-delay:-11s;"></span>
|
||
<span class="smoke-blob" style="width:260px;height:260px;top:48%;left:38%;animation-delay:-22s;"></span>
|
||
|
||
<!-- Zone 3: Nebel unten -->
|
||
<span class="fog-ground"></span>
|
||
</div>
|
||
<div class="container">
|
||
<span class="eyebrow">🩵 DOGFATHER UNIVERSE</span>
|
||
<h1 data-i18n="idx_hero_h1">Streamer. Community. HasiDog. Manager.<br>Gemeinsam stark.</h1>
|
||
<p class="lead worlds" data-i18n="idx_hero_lead">Drei Welten, eine Familie: Team Dogi.</p>
|
||
|
||
<div class="card" style="max-width:420px;margin:1.4rem auto 0;padding:1rem 1.4rem;">
|
||
<span class="badge rank-1"><span class="live-dot is-unknown" id="live-dot"></span><span id="live-text" data-i18n="idx_live_loading">Status wird geladen …</span></span>
|
||
<p class="small" data-i18n="idx_live_info" style="margin:.5rem 0 0;">DogFather geht <strong>jeden Tag ab 20 Uhr</strong> live — oft schon tagsüber, zu wechselnden Zeiten. <a href="streamplan.html">Streamplan ansehen →</a></p>
|
||
</div>
|
||
|
||
<div class="btn-row" style="justify-content:center;">
|
||
<a class="btn btn-primary" href="links.html" data-i18n="idx_hero_btn_links">Alle Links 🩵</a>
|
||
<a class="btn btn-outline" href="bewerben.html" data-i18n="idx_hero_btn_team">Teil vom Team werden</a>
|
||
</div>
|
||
|
||
<div class="hero-grid">
|
||
<a class="card" href="dogfather.html" data-theme="dogfather">
|
||
<span class="tag" data-i18n="idx_hero_card1_tag">Welt 1</span>
|
||
<h3>DogFather</h3>
|
||
<p data-i18n="idx_hero_card1_desc">Streamer, Entertainer, das Herz hinter dem Kanal. Halligalli, Humor und ein offenes Ohr für die Community.</p>
|
||
</a>
|
||
<a class="card" href="hasidog.html" data-theme="hasidog">
|
||
<span class="tag" data-i18n="idx_hero_card2_tag">Welt 2</span>
|
||
<h3>HasiDog</h3>
|
||
<p data-i18n="idx_hero_card2_desc">Die Community, das Maskottchen und Husky Casper — die verspielte, familiäre Seite von Team Dogi.</p>
|
||
</a>
|
||
<a class="card" href="manager.html" data-theme="spicymedia">
|
||
<span class="tag" data-i18n="idx_hero_card3_tag">Welt 3</span>
|
||
<h3 data-i18n="idx_hero_card3_h3">Manager DogFather</h3>
|
||
<p data-i18n="idx_hero_card3_desc">Als Manager bei Spicy Media: Scouts, Creator und faire Zusammenarbeit auf Augenhöhe.</p>
|
||
</a>
|
||
</div>
|
||
|
||
<!-- "Event des Jahres": volle Breite wie die 3 Welt-Kacheln zusammen. Seit
|
||
20.08.2026 (Nutzer-Wunsch) NUR sichtbar, wenn Dogi/VanVan mindestens ein
|
||
Event in der Verwaltung ausgefüllt UND aktiviert haben -- kein
|
||
Standard-/Platzhalterinhalt mehr, kompletter Abschnitt bleibt bis dahin
|
||
unsichtbar (siehe zeigeJahresEvents() weiter unten). Klick öffnet ein
|
||
großes Detail-Fenster (Bild/Titel/Text größer, optionaler direkter Link)
|
||
statt sofort wegzunavigieren. -->
|
||
<div class="jahres-events" id="jahres-events" hidden>
|
||
<div class="jahres-events-head">
|
||
<span class="tag" data-i18n="idx_jahres_events_tag">🏆 Event des Jahres</span>
|
||
</div>
|
||
<div class="jahres-events-grid" id="jahres-events-grid">
|
||
<button type="button" class="jahres-event-card" id="jahres-event-1" data-slot="1" hidden>
|
||
<span class="jahres-event-shine" aria-hidden="true"></span>
|
||
<img class="jahres-event-bild" alt="" hidden />
|
||
<span class="jahres-event-datum"></span>
|
||
<h3></h3>
|
||
<p></p>
|
||
<span class="jahres-event-mehr" data-i18n="idx_jahres_events_mehr">Mehr erfahren →</span>
|
||
</button>
|
||
<button type="button" class="jahres-event-card" id="jahres-event-2" data-slot="2" hidden>
|
||
<span class="jahres-event-shine" aria-hidden="true"></span>
|
||
<img class="jahres-event-bild" alt="" hidden />
|
||
<span class="jahres-event-datum"></span>
|
||
<h3></h3>
|
||
<p></p>
|
||
<span class="jahres-event-mehr" data-i18n="idx_jahres_events_mehr">Mehr erfahren →</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Detail-Fenster für "Event des Jahres" -- bewusst außerhalb der Hero-Sektion
|
||
(die hat eigene transform-/overflow-Effekte für die Polarlicht-/Nebel-
|
||
Animation, die ein position:fixed-Fenster aus der Zentrierung bringen
|
||
könnten). -->
|
||
<div class="jahres-event-modal-overlay" id="jahres-event-modal-overlay" hidden>
|
||
<div class="jahres-event-modal" role="dialog" aria-modal="true" aria-labelledby="jahres-event-modal-titel">
|
||
<button type="button" class="jahres-event-modal-close" id="jahres-event-modal-close" aria-label="Schließen">✕</button>
|
||
<img class="jahres-event-modal-bild" id="jahres-event-modal-bild" alt="" hidden />
|
||
<div class="jahres-event-modal-body">
|
||
<span class="jahres-event-modal-datum" id="jahres-event-modal-datum"></span>
|
||
<h2 id="jahres-event-modal-titel"></h2>
|
||
<p id="jahres-event-modal-text"></p>
|
||
<a class="btn btn-primary jahres-event-modal-link" id="jahres-event-modal-link" href="#" target="_blank" rel="noopener" hidden></a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ================= CHARAKTERE: DOGFATHER-HUSKY & HASIDOG-HASE ================= -->
|
||
<section class="section-tight">
|
||
<div class="container text-center">
|
||
<span class="eyebrow" data-i18n="idx_char_eyebrow">🩵 Die Gesichter der Welten</span>
|
||
<h2>DogFather & HasiDog</h2>
|
||
<p class="lead" data-i18n="idx_char_lead" style="max-width:52ch;margin:0 auto 2.4rem;">Zwei Charaktere, ein Universum — klick dich in ihre Welt.</p>
|
||
|
||
<div class="char-showcase">
|
||
<a class="char-card dogfather" href="streamer.html">
|
||
<img src="assets/img/char-dogfather.jpg" width="599" height="1212"
|
||
alt="DogFather — Husky mit blauem Hoodie und Cap" />
|
||
<span class="char-meta">
|
||
<span class="char-name">DogFather</span>
|
||
<span class="char-sub" data-i18n="idx_char1_sub">Streamer · Entertainer · Welt 1</span>
|
||
<span class="char-go" data-i18n="idx_char_go">Zur Welt →</span>
|
||
</span>
|
||
</a>
|
||
<a class="char-card hasidog" href="hasidog.html">
|
||
<img src="assets/img/char-hasidog.jpg" width="599" height="1212"
|
||
alt="HasiDog — grauer Hase mit schwarzem Hoodie und Cap" />
|
||
<span class="char-meta">
|
||
<span class="char-name">HasiDog</span>
|
||
<span class="char-sub" data-i18n="idx_char2_sub">Community · Maskottchen · Welt 2</span>
|
||
<span class="char-go" data-i18n="idx_char_go">Zur Welt →</span>
|
||
</span>
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ================= FOTO-COLLAGE: DOGFATHER & CASPER ================= -->
|
||
<section class="section-tight">
|
||
<div class="container text-center">
|
||
<span class="eyebrow" data-i18n="idx_collage_eyebrow">🩵 Gesichter hinter dem Universum</span>
|
||
<h2>DogFather & Casper</h2>
|
||
<div class="collage-wrap" id="collage-wrap">
|
||
<div class="collage-item">
|
||
<div class="collage-photo"><img class="collage-img" data-fallback="DogFather" src="assets/img/dogfather-portrait.jpg" alt="DogFather" style="object-position:center top;"></div>
|
||
<p class="collage-caption">DogFather 🩵</p>
|
||
</div>
|
||
<div class="collage-item">
|
||
<div class="collage-photo frame-lila"><img class="collage-img" data-fallback="Casper" src="assets/img/casper-1.jpg" alt="Casper" style="object-position:center top;"></div>
|
||
<p class="collage-caption">Casper 🐾</p>
|
||
</div>
|
||
<div class="collage-item">
|
||
<div class="collage-photo frame-silver"><img class="collage-img" data-fallback="DogFather & Casper" src="assets/img/dogfather-casper-1.jpg" alt="DogFather und Casper zusammen" style="object-position:center 18%;"></div>
|
||
<p class="collage-caption" data-i18n="idx_collage_cap_team">Team 🩵🐾</p>
|
||
</div>
|
||
<div class="collage-item">
|
||
<div class="collage-photo frame-gold"><img class="collage-img" data-fallback="Casper" src="assets/img/casper-2.jpg" alt="Casper"></div>
|
||
<p class="collage-caption" data-i18n="idx_collage_cap_huskylife">Husky-Life</p>
|
||
</div>
|
||
<div class="collage-item">
|
||
<div class="collage-photo frame-tuerkis"><img class="collage-img" data-fallback="DogFather & Casper" src="assets/img/dogfather-casper-2.jpg" alt="DogFather und Casper Nase an Nase"></div>
|
||
<p class="collage-caption" data-i18n="idx_collage_cap_nose">Nase an Nase 🩵</p>
|
||
</div>
|
||
</div>
|
||
<p class="small muted" data-i18n="idx_collage_footer" style="max-width:50ch;margin:0 auto;">DogFather & Casper — die zwei Gesichter hinter dem ganzen Universum. 🩵🐾</p>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ================= STATS ================= -->
|
||
<section class="section-tight">
|
||
<div class="container">
|
||
<div class="grid grid-4" id="stats-bar">
|
||
<div class="card text-center"><h3 id="stat-team">–</h3><p class="small muted" data-i18n="idx_stats_team">Menschen im Team Dogi</p></div>
|
||
<div class="card text-center"><h3 data-i18n="idx_stats_daily_label">Täglich</h3><p class="small muted" data-i18n="idx_stats_daily_desc">live ab 20 Uhr</p></div>
|
||
<div class="card text-center"><h3>3</h3><p class="small muted" data-i18n="idx_stats_worlds">Welten, eine Familie</p></div>
|
||
<div class="card text-center"><h3>🩵</h3><p class="small muted" data-i18n="idx_stats_family">Team Dogi ist Familie</p></div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ================= WAS DICH ERWARTET ================= -->
|
||
<section>
|
||
<div class="container">
|
||
<span class="eyebrow text-center" data-i18n="idx_expect_eyebrow" style="display:block;text-align:center;">Ein bisschen von allem</span>
|
||
<h2 class="text-center" data-i18n="idx_expect_h2">Was dich im Universum erwartet</h2>
|
||
<div class="grid grid-4">
|
||
<a class="card" href="streamer.html"><h3 data-i18n="idx_expect_c1_h3">🎥 Streamer</h3><p class="small" data-i18n="idx_expect_c1_p">Halligalli, Humor & Hasencontent.</p></a>
|
||
<a class="card" href="zeitreise.html"><h3 data-i18n="idx_expect_c2_h3">🕰️ Zeitreise</h3><p class="small" data-i18n="idx_expect_c2_p">Die Geschichte von DogFather & Team Dogi.</p></a>
|
||
<a class="card" href="community.html"><h3 data-i18n="idx_expect_c3_h3">🩵 Community</h3><p class="small" data-i18n="idx_expect_c3_p">Team Dogi ist Familie.</p></a>
|
||
<a class="card" href="casper.html"><h3 data-i18n="idx_expect_c4_h3">🐾 Casper</h3><p class="small" data-i18n="idx_expect_c4_p">Der Husky an DogFathers Seite.</p></a>
|
||
<a class="card" href="team-modis.html"><h3 data-i18n="idx_expect_c5_h3">🧑🤝🧑 Modi-Team</h3><p class="small" data-i18n="idx_expect_c5_p">VanVan, Diene & Co.</p></a>
|
||
<a class="card" href="medien-dogfather.html"><h3 data-i18n="idx_expect_c6_h3">🖼️ Medien: DogFather</h3><p class="small" data-i18n="idx_expect_media_p">Fotos, Videos & Events.</p></a>
|
||
<a class="card" href="medien-hasidog.html"><h3 data-i18n="idx_expect_c7_h3">🐰 Medien: HasiDog</h3><p class="small" data-i18n="idx_expect_media_p">Fotos, Videos & Events.</p></a>
|
||
<a class="card" href="medien-casper.html"><h3 data-i18n="idx_expect_c8_h3">🐺 Medien: Casper</h3><p class="small" data-i18n="idx_expect_media_p">Fotos, Videos & Events.</p></a>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ================= TEAM PREVIEW ================= -->
|
||
<section class="section-tight team-bg">
|
||
<div class="container">
|
||
<h2 class="text-center" data-i18n="idx_team_h2">Team Dogi 🩵</h2>
|
||
<p class="lead text-center" data-i18n="idx_team_lead" style="max-width:60ch;margin:0 auto;">VanVan & Modis — die Menschen, die DOGFATHER UNIVERSE tragen.</p>
|
||
<!-- Nutzer-Wunsch 21.08.2026: die vier Personen-Kacheln (VanVan/Diene/
|
||
Funny/Miss) hier auf der Startseite entfernt -- Überschrift, Text
|
||
und der Knopf zum Modi-Team bleiben. Die Kacheln selbst gibt es
|
||
weiterhin vollständig auf team-modis.html. -->
|
||
<div class="btn-row" style="justify-content:center;">
|
||
<a class="btn btn-outline" href="team-modis.html" data-i18n="idx_team_btn_modi">Modi-Team ansehen</a>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Nutzer-Wunsch 21.08.2026: der "Was gerade läuft"-Aktionen-Teaser
|
||
(Überschrift + Button "Alle Aktionen & Projekte", direkt hier davor)
|
||
wurde entfernt. data-aktionen.js/aktion-detail.html bleiben unangetastet,
|
||
nur die Startseiten-Vorschau ist weg. -->
|
||
|
||
<!-- ================= GALERIE TEASER ================= -->
|
||
<section class="section-tight">
|
||
<div class="container">
|
||
<h2 class="text-center" data-i18n="idx_galerie_h2">Impressionen</h2>
|
||
<div class="grid grid-4">
|
||
<div class="collage-photo" style="aspect-ratio:1;border-radius:var(--radius);"><img src="assets/img/casper-3.jpg" alt="Casper" style="width:100%;height:100%;object-fit:cover;object-position:center 20%;" /></div>
|
||
<div class="collage-photo frame-lila" style="aspect-ratio:1;border-radius:var(--radius);"><img src="assets/img/card-vanvan.jpg" alt="VanVan" style="width:100%;height:100%;object-fit:cover;" /></div>
|
||
<div class="collage-photo frame-silver" style="aspect-ratio:1;border-radius:var(--radius);"><img src="assets/img/casper-4.jpg" alt="Casper" style="width:100%;height:100%;object-fit:cover;object-position:42% center;" /></div>
|
||
<div class="collage-photo frame-gold" style="aspect-ratio:1;border-radius:var(--radius);"><img src="assets/img/card-dogfather.jpg" alt="DogFather" style="width:100%;height:100%;object-fit:cover;" /></div>
|
||
</div>
|
||
<div class="btn-row" style="justify-content:center;">
|
||
<a class="btn btn-outline" href="medien-dogfather.html" data-i18n="idx_galerie_btn">Zur ganzen Galerie</a>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ================= TESTIMONIAL ================= -->
|
||
<section>
|
||
<div class="container text-center">
|
||
<span class="eyebrow" data-i18n="idx_testimonial_eyebrow">Was andere sagen</span>
|
||
<div class="card" style="max-width:640px;margin:1rem auto 0;">
|
||
<p class="quote" data-i18n="idx_testimonial_quote" style="font-size:1.15rem;">„Hier stehen bald echte Stimmen aus der Community. 🩵"</p>
|
||
<p class="small muted" data-i18n="idx_testimonial_attrib">— Team Dogi</p>
|
||
</div>
|
||
<div class="btn-row" style="justify-content:center;">
|
||
<a class="btn btn-outline" href="stimmen.html" data-i18n="idx_testimonial_btn">Mehr Stimmen</a>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
|
||
|
||
<!-- ================= FINALER CTA ================= -->
|
||
<section class="hero">
|
||
<div class="container text-center">
|
||
<span class="eyebrow" data-i18n="idx_cta_eyebrow">🩵 Bereit?</span>
|
||
<h2 data-i18n="idx_cta_h2">Werde Teil von DOGFATHER UNIVERSE</h2>
|
||
<p class="lead" data-i18n="idx_cta_lead" style="max-width:56ch;margin:0 auto;">Als Zuschauer:in, Creator, Scout oder Kooperationspartner — hier ist für jeden Platz.</p>
|
||
<div class="btn-row" style="justify-content:center;">
|
||
<a class="btn btn-primary" href="links.html" data-i18n="idx_cta_btn_links">Alle Links 🩵</a>
|
||
<a class="btn btn-secondary" href="bewerben.html" data-i18n="idx_cta_btn_bewerben">Jetzt bewerben</a>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</main>
|
||
|
||
<div id="site-footer"></div>
|
||
<script src="assets/js/data-modis.js?v=20260828a"></script>
|
||
<script src="assets/js/data-scouts.js?v=20260828a"></script>
|
||
<script src="assets/js/i18n-index.js?v=20260828a"></script>
|
||
<script src="assets/js/main.js?v=20260828a"></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.
|
||
const API_BASE_URL = "https://postfach.dogfather-universe.com";
|
||
|
||
document.addEventListener("DOMContentLoaded", () => {
|
||
// Foto-Collage: solange echte Fotos fehlen, hübschen Platzhalter statt
|
||
// kaputtem Bild-Icon zeigen. Sobald ein Foto unter dem passenden Pfad
|
||
// (assets/img/dogfather-portrait.jpg etc.) liegt, taucht es automatisch auf.
|
||
document.querySelectorAll(".collage-img").forEach((img) => {
|
||
img.addEventListener(
|
||
"error",
|
||
() => {
|
||
const div = document.createElement("div");
|
||
div.className = "img-placeholder";
|
||
const fotoFolgtText = window.dogiUebersetzen ? window.dogiUebersetzen("idx_foto_folgt") : "Foto folgt";
|
||
div.innerHTML = `${img.dataset.fallback}<br><span class="small">${fotoFolgtText}</span>`;
|
||
img.replaceWith(div);
|
||
},
|
||
{ once: true }
|
||
);
|
||
});
|
||
|
||
// Live-Status: grün = läuft gerade, rot = offline.
|
||
// Der Wert kommt automatisch von TikTok (Cron im Worker prüft jede Minute).
|
||
// Die Seite fragt alle 30 Sekunden nach, damit der Punkt ohne Neuladen umspringt.
|
||
const liveDot = document.getElementById("live-dot");
|
||
const liveText = document.getElementById("live-text");
|
||
|
||
if (API_BASE_URL && liveDot && liveText) {
|
||
// Übersetzter Text hängt vom Live-Zustand ab (nicht per data-i18n
|
||
// abbildbar) — letzten bekannten Zustand merken, damit ein
|
||
// Sprachwechsel den Text sofort neu übersetzen kann, ohne auf den
|
||
// nächsten 30s-Poll warten zu müssen.
|
||
let letzterZustand = { status: "loading" };
|
||
|
||
const texteNeuSetzen = () => {
|
||
if (letzterZustand.status === "live") {
|
||
liveText.textContent = letzterZustand.titel
|
||
? window.dogiUebersetzen("idx_live_now", { titel: letzterZustand.titel })
|
||
: window.dogiUebersetzen("idx_live_now_generic");
|
||
} else if (letzterZustand.status === "offline") {
|
||
liveText.textContent = window.dogiUebersetzen("idx_live_offline");
|
||
} else if (letzterZustand.status === "error") {
|
||
liveText.textContent = window.dogiUebersetzen("idx_live_error");
|
||
} else {
|
||
liveText.textContent = window.dogiUebersetzen("idx_live_loading");
|
||
}
|
||
};
|
||
|
||
liveDot.classList.add("is-unknown");
|
||
texteNeuSetzen();
|
||
document.addEventListener("dogi-sprache-geaendert", texteNeuSetzen);
|
||
|
||
const applyLiveStatus = (data) => {
|
||
const isLive = !!(data && data.live);
|
||
liveDot.classList.remove("is-unknown");
|
||
liveDot.classList.toggle("is-live", isLive);
|
||
letzterZustand = isLive ? { status: "live", titel: data.title } : { status: "offline" };
|
||
texteNeuSetzen();
|
||
};
|
||
|
||
const refreshLiveStatus = () =>
|
||
fetch(`${API_BASE_URL}/live-status`, { cache: "no-store" })
|
||
.then((res) => res.json())
|
||
.then(applyLiveStatus)
|
||
.catch(() => {
|
||
liveDot.classList.remove("is-live");
|
||
liveDot.classList.add("is-unknown");
|
||
letzterZustand = { status: "error" };
|
||
texteNeuSetzen();
|
||
});
|
||
|
||
refreshLiveStatus();
|
||
setInterval(refreshLiveStatus, 30000);
|
||
// Beim Zurückwechseln zum Tab sofort aktualisieren statt bis zu 30 s warten.
|
||
document.addEventListener("visibilitychange", () => {
|
||
if (!document.hidden) refreshLiveStatus();
|
||
});
|
||
}
|
||
|
||
/* "Event des Jahres": seit 20.08.2026 in der Verwaltung pflegbar (Bild,
|
||
Text, Link, Aktiv-Schalter je Slot, siehe verwaltung.html +
|
||
server-internal/routes/events.js). Nutzer-Wunsch 20.08.2026: "die
|
||
kisten sollen leer sein solang wie ich nichts rein setze, am besten
|
||
sollen die sogar immer nur erscheinen wenn ich was rein setze und sie
|
||
aktiviere" — der Server liefert über /events-of-year ohnehin NUR
|
||
aktivierte Slots (inaktive/leere kommen als null), hier also einfach:
|
||
kein Eintrag -> Kachel bleibt versteckt, kompletter Abschnitt bleibt
|
||
versteckt, wenn beide Slots leer sind. Klick öffnet ein großes
|
||
Detail-Fenster statt sofort zu navigieren. */
|
||
const feldJahresEvent = (x) => (window.dogiFeld ? window.dogiFeld(x) : x || "");
|
||
let jahresEventsDaten = [null, null];
|
||
|
||
function zeigeJahresEventKachel(slot, daten) {
|
||
const karte = document.getElementById(`jahres-event-${slot}`);
|
||
if (!karte) return;
|
||
if (!daten) {
|
||
karte.hidden = true;
|
||
return;
|
||
}
|
||
const bild = karte.querySelector(".jahres-event-bild");
|
||
if (daten.bild) {
|
||
bild.src = daten.bild;
|
||
bild.alt = feldJahresEvent(daten.titel);
|
||
bild.hidden = false;
|
||
} else {
|
||
bild.hidden = true;
|
||
}
|
||
karte.querySelector(".jahres-event-datum").textContent = daten.datum || "";
|
||
karte.querySelector("h3").textContent = feldJahresEvent(daten.titel);
|
||
karte.querySelector("p").textContent = feldJahresEvent(daten.text);
|
||
karte.hidden = false;
|
||
}
|
||
|
||
function aktualisiereJahresEventsSichtbarkeit() {
|
||
const aktiveSlots = jahresEventsDaten.filter(Boolean).length;
|
||
const abschnitt = document.getElementById("jahres-events");
|
||
const grid = document.getElementById("jahres-events-grid");
|
||
abschnitt.hidden = aktiveSlots === 0;
|
||
// Genau 1 aktives Event: Kachel zentriert und etwas größer statt halb
|
||
// leerem Raster (Nutzer-Wunsch: "kacheln sollen bissl spezieller sein").
|
||
grid.classList.toggle("jahres-events-grid-einzeln", aktiveSlots === 1);
|
||
}
|
||
|
||
function jahresEventModalOeffnen(slot) {
|
||
const daten = jahresEventsDaten[slot - 1];
|
||
if (!daten) return;
|
||
const bild = document.getElementById("jahres-event-modal-bild");
|
||
if (daten.bild) {
|
||
bild.src = daten.bild;
|
||
bild.alt = feldJahresEvent(daten.titel);
|
||
bild.hidden = false;
|
||
} else {
|
||
bild.hidden = true;
|
||
}
|
||
document.getElementById("jahres-event-modal-datum").textContent = daten.datum || "";
|
||
document.getElementById("jahres-event-modal-titel").textContent = feldJahresEvent(daten.titel);
|
||
document.getElementById("jahres-event-modal-text").textContent = feldJahresEvent(daten.text);
|
||
const linkEl = document.getElementById("jahres-event-modal-link");
|
||
if (daten.link) {
|
||
linkEl.href = daten.link;
|
||
linkEl.textContent = feldJahresEvent(window.I18N_PAGE?.idx_jahres_event_modal_link) || "Direkt ansehen →";
|
||
linkEl.hidden = false;
|
||
} else {
|
||
linkEl.hidden = true;
|
||
}
|
||
const overlay = document.getElementById("jahres-event-modal-overlay");
|
||
overlay.hidden = false;
|
||
requestAnimationFrame(() => overlay.classList.add("offen"));
|
||
document.body.classList.add("modal-offen");
|
||
}
|
||
|
||
function jahresEventModalSchliessen() {
|
||
const overlay = document.getElementById("jahres-event-modal-overlay");
|
||
overlay.classList.remove("offen");
|
||
document.body.classList.remove("modal-offen");
|
||
setTimeout(() => { overlay.hidden = true; }, 220);
|
||
}
|
||
|
||
document.getElementById("jahres-event-1")?.addEventListener("click", () => jahresEventModalOeffnen(1));
|
||
document.getElementById("jahres-event-2")?.addEventListener("click", () => jahresEventModalOeffnen(2));
|
||
document.getElementById("jahres-event-modal-close")?.addEventListener("click", jahresEventModalSchliessen);
|
||
document.getElementById("jahres-event-modal-overlay")?.addEventListener("click", (e) => {
|
||
if (e.target.id === "jahres-event-modal-overlay") jahresEventModalSchliessen();
|
||
});
|
||
document.addEventListener("keydown", (e) => {
|
||
if (e.key === "Escape" && !document.getElementById("jahres-event-modal-overlay").hidden) jahresEventModalSchliessen();
|
||
});
|
||
|
||
if (API_BASE_URL) {
|
||
const ladeJahresEvents = () =>
|
||
fetch(`${API_BASE_URL}/events-of-year`, { cache: "no-store" })
|
||
.then((res) => res.json())
|
||
.then((data) => {
|
||
if (!data?.ok) return;
|
||
jahresEventsDaten = data.events;
|
||
zeigeJahresEventKachel(1, data.events[0]);
|
||
zeigeJahresEventKachel(2, data.events[1]);
|
||
aktualisiereJahresEventsSichtbarkeit();
|
||
})
|
||
.catch(() => {
|
||
/* Kein Fehler nötig -- der Abschnitt bleibt einfach unsichtbar. */
|
||
});
|
||
ladeJahresEvents();
|
||
// Bei Sprachwechsel mit den zuletzt geladenen Daten neu rendern (kein
|
||
// erneuter Server-Aufruf nötig) — Titel/Text stehen ja bereits in allen
|
||
// Sprachen im geladenen Objekt.
|
||
document.addEventListener("dogi-sprache-geaendert", () => {
|
||
zeigeJahresEventKachel(1, jahresEventsDaten[0]);
|
||
zeigeJahresEventKachel(2, jahresEventsDaten[1]);
|
||
});
|
||
}
|
||
|
||
// Stats: Team-Größe aus den Datenobjekten berechnen
|
||
const teamCount = (window.MODIS || []).length + (window.SCOUTS || []).length;
|
||
const statTeam = document.getElementById("stat-team");
|
||
if (statTeam) statTeam.textContent = teamCount > 0 ? `${teamCount}+` : "–";
|
||
|
||
// Nutzer-Wunsch 21.08.2026: die Team-Vorschau (vier Personen-Kacheln unter
|
||
// "Team Dogi 🩵") wurde entfernt -- der zugehörige Render-Code stand hier.
|
||
// data-modis.js/data-scouts.js bleiben eingebunden, weil die Statistik-Zeile
|
||
// weiter oben ("Menschen im Team Dogi") sie weiterhin auszählt.
|
||
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|