Lagebild: Tab-Navigation zu Scroll-Narrative mit Sticky Section-Nav umgebaut

- Alle Sektionen (Lagebild, Karte, Faktenchecks, Artikel) auf einer scrollbaren Seite
- Sticky Section-Nav mit Scroll-Spy (IntersectionObserver) ersetzt Tab-Buttons
- Karte rendert sofort (nicht mehr erst bei Tab-Klick), full-width Layout
- Artikel auf Top 20 limitiert mit Alle anzeigen Button
- Quellen-Tab zu Artikel umbenannt, zitierte Quellen entfernt
- Control-Bar sticky mit Shadow-Effekt beim Scrollen

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Dieser Commit ist enthalten in:
Claude Code
2026-03-07 15:53:44 +01:00
Ursprung 5e5cb0a3b2
Commit dc0792c073
3 geänderte Dateien mit 2107 neuen und 2128 gelöschten Zeilen

Datei anzeigen

@@ -66,28 +66,28 @@
</div> </div>
</section> </section>
<!-- Control Bar: Timeline + Tabs --> <!-- Control Bar: Timeline + Section Nav -->
<div class="control-bar"> <div class="control-bar" id="control-bar">
<div class="container"> <div class="container">
<div class="timeline-wrapper"> <div class="timeline-wrapper">
<div class="timeline-strip" id="timeline-strip"></div> <div class="timeline-strip" id="timeline-strip"></div>
<div class="timeline-dropdown" id="timeline-dropdown"></div> <div class="timeline-dropdown" id="timeline-dropdown"></div>
</div> </div>
<div class="tab-nav" id="tab-nav"> <nav class="section-nav" id="section-nav">
<button class="tab-btn active" data-tab="lagebild">Lagebild</button> <a class="section-nav-link active" href="#section-lagebild" data-section="lagebild">Lagebild</a>
<button class="tab-btn" data-tab="quellen">Quellen <span class="tab-badge" id="tab-badge-quellen"></span></button> <a class="section-nav-link" href="#section-karte" data-section="karte">Karte</a>
<button class="tab-btn" data-tab="karte">Karte</button> <a class="section-nav-link" href="#section-faktenchecks" data-section="faktenchecks">Faktenchecks <span class="section-badge" id="badge-faktenchecks"></span></a>
<button class="tab-btn" data-tab="faktenchecks">Faktenchecks <span class="tab-badge" id="tab-badge-faktenchecks"></span></button> <a class="section-nav-link" href="#section-artikel" data-section="artikel">Artikel <span class="section-badge" id="badge-artikel"></span></a>
</div> </nav>
</div> </div>
</div> </div>
<!-- Main Content --> <!-- Main Content: All sections visible (Scroll-Narrative) -->
<main class="lagebild-main"> <main class="lagebild-main">
<!-- Section: Lagebild -->
<div class="container"> <div class="container">
<!-- Tab: Lagebild --> <section id="section-lagebild" class="content-section">
<div class="tab-panel active" id="panel-lagebild"> <div class="content-card">
<section class="content-card">
<div class="card-header"> <div class="card-header">
<h2 id="lagebild-date-title">Lagebild</h2> <h2 id="lagebild-date-title">Lagebild</h2>
<span class="card-timestamp" id="lagebild-timestamp"></span> <span class="card-timestamp" id="lagebild-timestamp"></span>
@@ -100,49 +100,43 @@
</div> </div>
</div> </div>
<div class="card-footer" id="inline-sources"></div> <div class="card-footer" id="inline-sources"></div>
</section>
</div>
<!-- Tab: Quellen -->
<div class="tab-panel" id="panel-quellen">
<section class="content-card">
<div class="card-header">
<h2>Quellen &amp; Quellenberichte</h2>
<p class="card-description">Alle vom AegisSight Monitor aggregierten Quellen und Artikel</p>
</div>
<div class="card-body">
<div id="sources-cited" class="sources-section"></div>
<h3 class="section-subtitle" id="articles-heading">Alle Artikel</h3>
<div id="articles-content"></div>
</div> </div>
</section> </section>
</div> </div>
<!-- Tab: Karte --> <!-- Section: Karte (full-width) -->
<div class="tab-panel" id="panel-karte"> <section id="section-karte" class="content-section section-karte">
<section class="content-card"> <div class="container">
<div class="card-header"> <div class="section-heading">
<h2>Karte</h2> <h2>Karte</h2>
<p class="card-description">Geografische Einordnung der Meldungen</p> <p class="section-description">Geografische Einordnung der Meldungen</p>
</div> </div>
<div class="card-body">
<div id="map-container" style="height:500px;border-radius:4px;overflow:hidden;"></div>
</div> </div>
<div id="map-container"></div>
</section> </section>
</div>
<!-- Tab: Faktenchecks --> <!-- Section: Faktenchecks -->
<div class="tab-panel" id="panel-faktenchecks"> <div class="container">
<section class="content-card"> <section id="section-faktenchecks" class="content-section">
<div class="content-card">
<div class="card-header"> <div class="card-header">
<h2>Faktenchecks</h2> <h2>Faktenchecks</h2>
<p class="card-description">KI-gestützte Verifizierung aller zentralen Aussagen gegen unabhängige Quellen</p> <p class="card-description">KI-gestützte Verifizierung aller zentralen Aussagen gegen unabhängige Quellen</p>
</div> </div>
<div class="card-body" id="factchecks-content"></div> <div class="card-body" id="factchecks-content"></div>
</section>
</div> </div>
</section>
<!-- CTA --> <!-- Section: Artikel -->
<section id="section-artikel" class="content-section">
<div class="content-card">
<div class="card-header">
<h2 id="articles-heading">Artikel</h2>
<p class="card-description">Alle vom AegisSight Monitor aggregierten Artikel</p>
</div>
<div class="card-body" id="articles-content"></div>
</div>
</section>
</div> </div>
</main> </main>

Datei anzeigen

@@ -1,5 +1,5 @@
/* ========================================================================== /* ==========================================================================
AegisSight Lagebild Page - Dark Theme Design Refresh AegisSight Lagebild Page - Dark Theme / Scroll-Narrative
========================================================================== */ ========================================================================== */
/* ---------- Variables ---------- */ /* ---------- Variables ---------- */
@@ -15,6 +15,7 @@
--lb-success: #10B981; --lb-success: #10B981;
--lb-warning: #F59E0B; --lb-warning: #F59E0B;
--lb-error: #EF4444; --lb-error: #EF4444;
--navbar-height: 72px;
} }
/* ---------- Page Base ---------- */ /* ---------- Page Base ---------- */
@@ -211,11 +212,18 @@
margin-top: 2px; margin-top: 2px;
} }
/* ---------- Control Bar ---------- */ /* ---------- Control Bar (Sticky) ---------- */
.control-bar { .control-bar {
background: var(--lb-bg-card); background: var(--lb-bg-card);
border-bottom: 1px solid var(--lb-border); border-bottom: 1px solid var(--lb-border);
padding: 0 20px; padding: 0 20px;
position: sticky;
top: var(--navbar-height);
z-index: 90;
transition: box-shadow 0.3s;
}
.control-bar.stuck {
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
} }
.control-bar .container { .control-bar .container {
max-width: 1000px; max-width: 1000px;
@@ -376,31 +384,30 @@
opacity: 0.7; opacity: 0.7;
} }
/* Tab Navigation */ /* ---------- Section Navigation (Scroll-Spy) ---------- */
.tab-nav { .section-nav {
display: flex; display: flex;
gap: 0; gap: 0;
} }
.tab-btn { .section-nav-link {
display: inline-block;
padding: 12px 20px; padding: 12px 20px;
border: none;
background: transparent;
cursor: pointer;
font-size: 0.9rem; font-size: 0.9rem;
font-weight: 600; font-weight: 600;
color: var(--lb-text-sec); color: var(--lb-text-sec);
text-decoration: none;
border-bottom: 3px solid transparent; border-bottom: 3px solid transparent;
transition: all 0.2s; transition: all 0.2s;
font-family: inherit; white-space: nowrap;
} }
.tab-btn:hover { .section-nav-link:hover {
color: var(--lb-text); color: var(--lb-text);
} }
.tab-btn.active { .section-nav-link.active {
color: var(--lb-accent); color: var(--lb-accent);
border-bottom-color: var(--lb-accent); border-bottom-color: var(--lb-accent);
} }
.tab-badge { .section-badge {
display: inline-block; display: inline-block;
background: rgba(200, 168, 81, 0.12); background: rgba(200, 168, 81, 0.12);
color: var(--lb-accent); color: var(--lb-accent);
@@ -411,21 +418,24 @@
margin-left: 4px; margin-left: 4px;
vertical-align: middle; vertical-align: middle;
} }
.tab-btn.active .tab-badge { .section-nav-link.active .section-badge {
background: rgba(200, 168, 81, 0.22); background: rgba(200, 168, 81, 0.22);
} }
/* Tab Panels */
.tab-panel { display: none; }
.tab-panel.active { display: block; }
/* ---------- Main Content ---------- */ /* ---------- Main Content ---------- */
.lagebild-main { .lagebild-main {
padding: 2rem 20px 4rem; padding: 2rem 0 4rem;
} }
.lagebild-main .container { .lagebild-main > .container {
max-width: 1000px; max-width: 1000px;
margin: 0 auto; margin: 0 auto;
padding: 0 20px;
}
/* ---------- Content Sections ---------- */
.content-section {
margin-bottom: 3rem;
scroll-margin-top: calc(var(--navbar-height) + 120px);
} }
/* ---------- Content Cards ---------- */ /* ---------- Content Cards ---------- */
@@ -480,6 +490,34 @@
padding-top: 20px; padding-top: 20px;
margin: 0 32px; margin: 0 32px;
} }
.card-footer:empty {
display: none;
}
/* ---------- Karte Section (Full-Width) ---------- */
.section-karte {
padding: 0;
}
.section-karte .section-heading {
margin-bottom: 1.5rem;
}
.section-karte .section-heading h2 {
font-size: 1.3rem;
font-weight: 700;
color: var(--lb-text);
margin: 0 0 4px;
}
.section-description {
font-size: 0.85rem;
color: var(--lb-text-sec);
margin: 0;
}
#map-container {
height: 500px;
background: var(--lb-bg-secondary);
border-top: 1px solid var(--lb-border);
border-bottom: 1px solid var(--lb-border);
}
/* ---------- Lagebild Summary ---------- */ /* ---------- Lagebild Summary ---------- */
#summary-content { #summary-content {
@@ -543,113 +581,6 @@
transition: background 1.5s ease-out; transition: background 1.5s ease-out;
} }
/* Sources List */
.sources-section h3 {
font-size: 1.1rem;
font-weight: 700;
color: var(--lb-text);
margin: 0 0 12px;
}
.section-subtitle {
font-size: 1.1rem;
font-weight: 700;
color: var(--lb-text);
margin: 2rem 0 12px;
padding-top: 1.5rem;
border-top: 1px solid var(--lb-border);
}
.sources-list {
list-style: none;
padding: 0;
margin: 0;
counter-reset: src;
columns: 2;
column-gap: 24px;
}
.sources-list li {
counter-increment: src;
padding: 4px 0;
font-size: 0.88rem;
color: var(--lb-text);
break-inside: avoid;
}
.sources-list li::before {
content: "[" counter(src) "]";
color: var(--lb-accent);
font-weight: 700;
font-size: 0.82rem;
margin-right: 6px;
}
.sources-list a {
color: var(--lb-accent);
text-decoration: none;
}
.sources-list a:hover { text-decoration: underline; }
.source-name {
font-weight: 600;
color: var(--lb-text);
}
/* Inline sources (Lagebild tab footer) - Collapsible */
.inline-sources-toggle {
display: inline-flex;
align-items: center;
gap: 8px;
font-size: 0.9rem;
font-weight: 600;
color: var(--lb-text-sec);
cursor: pointer;
padding: 10px 16px;
user-select: none;
transition: all 0.2s;
background: var(--lb-bg-secondary);
border: 1px solid var(--lb-border);
border-radius: var(--radius-sm, 4px);
}
.inline-sources-toggle:hover {
color: var(--lb-accent);
border-color: rgba(200, 168, 81, 0.4);
background: rgba(200, 168, 81, 0.06);
}
.inline-sources-arrow {
display: inline-flex;
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
font-size: 1.1rem;
transition: transform 0.2s;
color: var(--lb-accent);
}
#inline-sources.open .inline-sources-arrow {
transform: rotate(90deg);
}
.inline-sources-body {
display: none;
padding: 8px 0 0;
font-size: 0.82rem;
line-height: 1.8;
color: var(--lb-text-sec);
}
#inline-sources.open .inline-sources-body {
display: block;
}
.src-inline .src-nr {
color: var(--lb-accent);
font-weight: 700;
}
.src-sep {
color: var(--lb-border);
margin: 0 2px;
}
.inline-sources-body a {
color: var(--lb-accent);
text-decoration: none;
}
.inline-sources-body a:hover {
text-decoration: underline;
}
/* ---------- Article Cards ---------- */ /* ---------- Article Cards ---------- */
.article-card { .article-card {
display: flex; display: flex;
@@ -737,10 +668,29 @@
text-decoration: underline !important; text-decoration: underline !important;
} }
/* ---------- Map ---------- */ /* Show All Button */
#map-container { .show-all-wrapper {
background: var(--lb-bg-secondary); text-align: center;
padding: 24px 0 8px;
} }
.show-all-btn {
display: inline-block;
padding: 10px 28px;
background: transparent;
border: 1px solid var(--lb-accent);
color: var(--lb-accent);
font-size: 0.88rem;
font-weight: 600;
border-radius: var(--radius-sm, 4px);
cursor: pointer;
transition: all 0.2s;
font-family: inherit;
}
.show-all-btn:hover {
background: rgba(200, 168, 81, 0.1);
}
/* ---------- Map ---------- */
.lagebild-page .map-legend { .lagebild-page .map-legend {
background: var(--lb-bg-card) !important; background: var(--lb-bg-card) !important;
color: var(--lb-text) !important; color: var(--lb-text) !important;
@@ -1141,14 +1091,13 @@
padding: 5px 10px; padding: 5px 10px;
font-size: 0.72rem; font-size: 0.72rem;
} }
.tab-nav { .section-nav {
overflow-x: auto; overflow-x: auto;
-webkit-overflow-scrolling: touch; -webkit-overflow-scrolling: touch;
} }
.tab-btn { .section-nav-link {
padding: 10px 14px; padding: 10px 14px;
font-size: 0.82rem; font-size: 0.82rem;
white-space: nowrap;
} }
.card-header { .card-header {
@@ -1162,7 +1111,13 @@
padding: 16px 20px 20px; padding: 16px 20px 20px;
} }
.lagebild-main { .lagebild-main {
padding: 1rem 12px 3rem; padding: 1rem 0 3rem;
}
.lagebild-main > .container {
padding: 0 12px;
}
.content-section {
margin-bottom: 2rem;
} }
.factcheck-header { .factcheck-header {
flex-direction: column; flex-direction: column;
@@ -1197,7 +1152,7 @@
gap: 4px; gap: 4px;
} }
.sources-list { .section-karte .section-heading {
columns: 1; margin-bottom: 1rem;
} }
} }

Datei anzeigen

@@ -1,6 +1,6 @@
/** /**
* AegisSight Lagebild Page - Dark Theme Design Refresh * AegisSight Lagebild Page - Dark Theme / Scroll-Narrative
* Count-Up, Timeline mit Dropdown, Scroll-Reveal, Smooth-Scroll, Favicons * Count-Up, Timeline, Scroll-Spy, Scroll-Reveal, Favicons
*/ */
/** Feste Zeitzone fuer alle Anzeigen - NIEMALS aendern. */ /** Feste Zeitzone fuer alle Anzeigen - NIEMALS aendern. */
@@ -12,6 +12,7 @@ var Lagebild = {
currentView: null, currentView: null,
map: null, map: null,
timelineGroups: null, timelineGroups: null,
articlesShowAll: false,
/* ===== Inline SVG Icons ===== */ /* ===== Inline SVG Icons ===== */
icons: { icons: {
@@ -38,10 +39,11 @@ var Lagebild = {
fact_checks: this.data.fact_checks fact_checks: this.data.fact_checks
}; };
this.render(); this.render();
this.initTabs(); this.initScrollSpy();
this.initLangToggle(); this.initLangToggle();
this.initScrollReveal(); this.initScrollReveal();
this.initFloatingCta(); this.initFloatingCta();
this.initStickyDetect();
} catch (e) { } catch (e) {
console.error('Lagebild laden fehlgeschlagen:', e); console.error('Lagebild laden fehlgeschlagen:', e);
this.showError(); this.showError();
@@ -51,7 +53,7 @@ var Lagebild = {
render: function() { render: function() {
this.renderHero(); this.renderHero();
this.renderTimeline(); this.renderTimeline();
this.renderTabBadges(); this.renderSectionBadges();
this.renderCurrentView(); this.renderCurrentView();
}, },
@@ -60,7 +62,7 @@ var Lagebild = {
var d = this.data; var d = this.data;
document.getElementById('incident-title').innerHTML = document.getElementById('incident-title').innerHTML =
this.esc(this.fixUmlauts(d.incident.title)) + this.esc(this.fixUmlauts(d.incident.title)) +
' <span class="hero-date-info">- Stand: ' + this.fmtDateOnly(d.generated_at) + ', ' + this.fmtTimeOnly(d.generated_at) + ' Uhr</span>'; ' <span class="hero-date-info">\u2013 Stand: ' + this.fmtDateOnly(d.generated_at) + ', ' + this.fmtTimeOnly(d.generated_at) + ' Uhr</span>';
// Stat Cards (3: Artikel, Quellen, Faktenchecks) // Stat Cards (3: Artikel, Quellen, Faktenchecks)
var statsHtml = ''; var statsHtml = '';
@@ -204,7 +206,7 @@ var Lagebild = {
} }
}); });
// Click handler for dropdown snapshot items (delegated, set up once) // Click handler for dropdown snapshot items (delegated)
var dropdown = document.getElementById('timeline-dropdown'); var dropdown = document.getElementById('timeline-dropdown');
dropdown.addEventListener('click', function(e) { dropdown.addEventListener('click', function(e) {
var item = e.target.closest('.timeline-snap-item'); var item = e.target.closest('.timeline-snap-item');
@@ -249,7 +251,7 @@ var Lagebild = {
var d = new Date(dateKey + 'T12:00:00Z'); var d = new Date(dateKey + 'T12:00:00Z');
var dateLabel = d.toLocaleDateString('de-DE', { day: 'numeric', month: 'long', year: 'numeric', timeZone: 'UTC' }); var dateLabel = d.toLocaleDateString('de-DE', { day: 'numeric', month: 'long', year: 'numeric', timeZone: 'UTC' });
var h = '<div class="timeline-dropdown-header">' + dateLabel + ' - ' + snaps.length + ' Updates</div>'; var h = '<div class="timeline-dropdown-header">' + dateLabel + ' \u2013 ' + snaps.length + ' Updates</div>';
h += '<div class="timeline-snap-list">'; h += '<div class="timeline-snap-list">';
for (var i = 0; i < snaps.length; i++) { for (var i = 0; i < snaps.length; i++) {
var snap = snaps[i]; var snap = snaps[i];
@@ -272,11 +274,11 @@ var Lagebild = {
return d.toLocaleDateString('en-CA', { timeZone: TIMEZONE }); return d.toLocaleDateString('en-CA', { timeZone: TIMEZONE });
}, },
/* ===== TAB BADGES ===== */ /* ===== SECTION BADGES ===== */
renderTabBadges: function() { renderSectionBadges: function() {
var quellenBadge = document.getElementById('tab-badge-quellen'); var artikelBadge = document.getElementById('badge-artikel');
var fcBadge = document.getElementById('tab-badge-faktenchecks'); var fcBadge = document.getElementById('badge-faktenchecks');
if (quellenBadge) quellenBadge.textContent = this.data.incident.source_count; if (artikelBadge) artikelBadge.textContent = this.data.incident.article_count;
if (fcBadge) fcBadge.textContent = this.data.incident.factcheck_count; if (fcBadge) fcBadge.textContent = this.data.incident.factcheck_count;
}, },
@@ -308,15 +310,12 @@ var Lagebild = {
renderCurrentView: function() { renderCurrentView: function() {
this.renderSummary(); this.renderSummary();
this.renderInlineSources(); this.renderInlineSources();
this.renderSourcesTab(); this.renderArtikelSection();
this.renderArticlesTab();
this.renderFactChecksTab(); this.renderFactChecksTab();
if (document.getElementById('panel-karte').classList.contains('active')) { if (!this.map) this.renderMap();
this.renderMap();
}
}, },
/* ===== TAB: LAGEBILD ===== */ /* ===== SECTION: LAGEBILD ===== */
renderSummary: function() { renderSummary: function() {
var v = this.currentView; var v = this.currentView;
document.getElementById('lagebild-timestamp').textContent = this.fmtDT(v.updated_at); document.getElementById('lagebild-timestamp').textContent = this.fmtDT(v.updated_at);
@@ -345,32 +344,18 @@ var Lagebild = {
document.getElementById('inline-sources').innerHTML = ''; document.getElementById('inline-sources').innerHTML = '';
}, },
/* ===== TAB: QUELLEN ===== */ /* ===== SECTION: ARTIKEL ===== */
renderSourcesTab: function() { renderArtikelSection: function() {
var sources = this.currentView.sources_json || [];
var articles = this.currentView.articles || []; var articles = this.currentView.articles || [];
var h = ''; var limit = 20;
var showAll = this.articlesShowAll || articles.length <= limit;
var displayArticles = showAll ? articles : articles.slice(0, limit);
h += '<div class="sources-section"><h3>Im Lagebild zitierte Quellen (' + sources.length + ')</h3>'; document.getElementById('articles-heading').textContent = 'Artikel (' + articles.length + ')';
if (sources.length) {
h += '<ol class="sources-list">';
for (var i = 0; i < sources.length; i++) {
var s = sources[i];
if (s.url) {
h += '<li><a href="' + this.esc(s.url) + '" target="_blank" rel="noopener">' + this.esc(s.name || '') + '</a></li>';
} else {
h += '<li><span class="source-name">' + this.esc(s.name || '') + '</span></li>';
}
}
h += '</ol>';
}
h += '</div>';
document.getElementById('sources-cited').innerHTML = h;
document.getElementById('articles-heading').textContent = 'Alle gesammelten Artikel (' + articles.length + ')';
var ah = ''; var ah = '';
for (var i = 0; i < articles.length; i++) { for (var i = 0; i < displayArticles.length; i++) {
var a = articles[i]; var a = displayArticles[i];
var dt = a.published_at || a.collected_at || ''; var dt = a.published_at || a.collected_at || '';
var dObj = dt ? new Date(this.toUTC(dt)) : null; var dObj = dt ? new Date(this.toUTC(dt)) : null;
var hl = this.fixUmlauts(a.headline_de || a.headline || ''); var hl = this.fixUmlauts(a.headline_de || a.headline || '');
@@ -398,12 +383,25 @@ var Lagebild = {
if (a.source_url) ah += '<a class="article-link" href="' + this.esc(a.source_url) + '" target="_blank" rel="noopener">Artikel lesen ' + this.icons.externalLink + '</a>'; if (a.source_url) ah += '<a class="article-link" href="' + this.esc(a.source_url) + '" target="_blank" rel="noopener">Artikel lesen ' + this.icons.externalLink + '</a>';
ah += '</div></div></div>'; ah += '</div></div></div>';
} }
if (!showAll) {
ah += '<div class="show-all-wrapper">';
ah += '<button class="show-all-btn" id="show-all-articles">Alle ' + articles.length + ' Artikel anzeigen</button>';
ah += '</div>';
}
document.getElementById('articles-content').innerHTML = ah; document.getElementById('articles-content').innerHTML = ah;
if (!showAll) {
var self = this;
document.getElementById('show-all-articles').addEventListener('click', function() {
self.articlesShowAll = true;
self.renderArtikelSection();
});
}
}, },
renderArticlesTab: function() {}, /* ===== SECTION: KARTE ===== */
/* ===== TAB: KARTE ===== */
renderMap: function() { renderMap: function() {
if (this.map) { this.map.remove(); this.map = null; } if (this.map) { this.map.remove(); this.map = null; }
this.map = L.map('map-container').setView([33.0, 48.0], 5); this.map = L.map('map-container').setView([33.0, 48.0], 5);
@@ -432,12 +430,12 @@ var Lagebild = {
}); });
var locs = [ var locs = [
{n:'Teheran, Iran',lat:35.6892,lng:51.3890,d:'Hauptziel der US-israelischen Luftschläge. Über 1.000 Tote nach fünf Tagen Krieg.',ic:redIcon}, {n:'Teheran, Iran',lat:35.6892,lng:51.3890,d:'Hauptziel der US-israelischen Luftschl\u00e4ge. \u00dcber 1.000 Tote nach f\u00fcnf Tagen Krieg.',ic:redIcon},
{n:'Beirut, Libanon',lat:33.8938,lng:35.5018,d:'Gleichzeitige US-israelische Luftschläge auf Beirut und Teheran [6].',ic:redIcon}, {n:'Beirut, Libanon',lat:33.8938,lng:35.5018,d:'Gleichzeitige US-israelische Luftschl\u00e4ge auf Beirut und Teheran [6].',ic:redIcon},
{n:'Juffair, Bahrain',lat:26.2235,lng:50.6001,d:'US-Marinebasis - Ziel iranischer Vergeltungsraketen [3].',ic:orangeIcon}, {n:'Juffair, Bahrain',lat:26.2235,lng:50.6001,d:'US-Marinebasis \u2013 Ziel iranischer Vergeltungsraketen [3].',ic:orangeIcon},
{n:'Al Udeid, Katar',lat:25.1173,lng:51.3150,d:'US-Luftwaffenstützpunkt - Ziel iranischer Gegenangriffe.',ic:orangeIcon}, {n:'Al Udeid, Katar',lat:25.1173,lng:51.3150,d:'US-Luftwaffenst\u00fctzpunkt \u2013 Ziel iranischer Gegenangriffe.',ic:orangeIcon},
{n:'Tel Aviv, Israel',lat:32.0853,lng:34.7818,d:'Operationsbasis für israelische Angriffe auf den Iran.',ic:blueIcon}, {n:'Tel Aviv, Israel',lat:32.0853,lng:34.7818,d:'Operationsbasis f\u00fcr israelische Angriffe auf den Iran.',ic:blueIcon},
{n:'Ankara, Türkei',lat:39.9334,lng:32.8597,d:'NATO vermutet iranischen Raketenbeschuss auf Türkei [10]. Keine NATO-Beteiligung geplant.',ic:orangeIcon}, {n:'Ankara, T\u00fcrkei',lat:39.9334,lng:32.8597,d:'NATO vermutet iranischen Raketenbeschuss auf T\u00fcrkei [10]. Keine NATO-Beteiligung geplant.',ic:orangeIcon},
{n:'Bagdad, Irak',lat:33.3152,lng:44.3661,d:'Lage im Irak als Faktor im Kriegsverlauf [2].',ic:blueIcon}, {n:'Bagdad, Irak',lat:33.3152,lng:44.3661,d:'Lage im Irak als Faktor im Kriegsverlauf [2].',ic:blueIcon},
{n:'Persischer Golf',lat:27.0,lng:51.5,d:'Iran greift Energieinfrastruktur und diplomatische Einrichtungen in der Golfregion an.',ic:orangeIcon}, {n:'Persischer Golf',lat:27.0,lng:51.5,d:'Iran greift Energieinfrastruktur und diplomatische Einrichtungen in der Golfregion an.',ic:orangeIcon},
{n:'Dubai, VAE',lat:25.2048,lng:55.2708,d:'US-Botschaft in Dubai durch iranischen Angriff getroffen.',ic:redIcon}, {n:'Dubai, VAE',lat:25.2048,lng:55.2708,d:'US-Botschaft in Dubai durch iranischen Angriff getroffen.',ic:redIcon},
@@ -475,11 +473,11 @@ var Lagebild = {
setTimeout(function() { if (Lagebild.map) Lagebild.map.invalidateSize(); }, 300); setTimeout(function() { if (Lagebild.map) Lagebild.map.invalidateSize(); }, 300);
}, },
/* ===== TAB: FAKTENCHECKS ===== */ /* ===== SECTION: FAKTENCHECKS ===== */
renderFactChecksTab: function() { renderFactChecksTab: function() {
var checks = this.currentView.fact_checks || []; var checks = this.currentView.fact_checks || [];
if (!checks.length) { if (!checks.length) {
document.getElementById('factchecks-content').innerHTML = '<p style="color:#8896AB">Keine Faktenchecks verfügbar.</p>'; document.getElementById('factchecks-content').innerHTML = '<p style="color:#8896AB">Keine Faktenchecks verf\u00fcgbar.</p>';
return; return;
} }
@@ -491,7 +489,7 @@ var Lagebild = {
var h = '<div class="fc-stats">'; var h = '<div class="fc-stats">';
h += '<div class="fc-stat"><span class="fc-stat-num">' + checks.length + '</span><span class="fc-stat-label">Gesamt</span></div>'; h += '<div class="fc-stat"><span class="fc-stat-num">' + checks.length + '</span><span class="fc-stat-label">Gesamt</span></div>';
h += '<div class="fc-stat confirmed"><span class="fc-stat-num">' + (stats.confirmed + stats.established) + '</span><span class="fc-stat-label">Bestätigt</span></div>'; h += '<div class="fc-stat confirmed"><span class="fc-stat-num">' + (stats.confirmed + stats.established) + '</span><span class="fc-stat-label">Best\u00e4tigt</span></div>';
h += '<div class="fc-stat unconfirmed"><span class="fc-stat-num">' + (stats.unconfirmed + stats.developing) + '</span><span class="fc-stat-label">Offen</span></div>'; h += '<div class="fc-stat unconfirmed"><span class="fc-stat-num">' + (stats.unconfirmed + stats.developing) + '</span><span class="fc-stat-label">Offen</span></div>';
if (stats.contradicted + stats.disputed > 0) if (stats.contradicted + stats.disputed > 0)
h += '<div class="fc-stat contradicted"><span class="fc-stat-num">' + (stats.contradicted + stats.disputed) + '</span><span class="fc-stat-label">Widerlegt</span></div>'; h += '<div class="fc-stat contradicted"><span class="fc-stat-num">' + (stats.contradicted + stats.disputed) + '</span><span class="fc-stat-label">Widerlegt</span></div>';
@@ -512,7 +510,7 @@ var Lagebild = {
h += '<div class="factcheck-card' + (hasProg ? ' highlight' : '') + '" data-status="' + status + '">'; h += '<div class="factcheck-card' + (hasProg ? ' highlight' : '') + '" data-status="' + status + '">';
h += '<div class="factcheck-header">'; h += '<div class="factcheck-header">';
h += '<span class="status-badge ' + status + '">' + this.stLabel(status) + '</span>'; h += '<span class="status-badge ' + status + '">' + this.stLabel(status) + '</span>';
h += '<span class="factcheck-sources">' + (fc.sources_count || 0) + ' unabhängige Quellen</span>'; h += '<span class="factcheck-sources">' + (fc.sources_count || 0) + ' unabh\u00e4ngige Quellen</span>';
h += '</div>'; h += '</div>';
h += '<p class="factcheck-claim">' + this.esc(this.fixUmlauts(fc.claim || '')) + '</p>'; h += '<p class="factcheck-claim">' + this.esc(this.fixUmlauts(fc.claim || '')) + '</p>';
@@ -540,29 +538,67 @@ var Lagebild = {
document.getElementById('factchecks-content').innerHTML = h; document.getElementById('factchecks-content').innerHTML = h;
}, },
/* ===== TABS ===== */ /* ===== SCROLL-SPY (Section Navigation) ===== */
initTabs: function() { initScrollSpy: function() {
var btns = document.querySelectorAll('.tab-btn'); var navLinks = document.querySelectorAll('.section-nav-link');
var self = this; var sections = document.querySelectorAll('.content-section');
for (var i = 0; i < btns.length; i++) { var controlBar = document.getElementById('control-bar');
btns[i].addEventListener('click', function() {
var tab = this.getAttribute('data-tab');
for (var j = 0; j < btns.length; j++) btns[j].classList.remove('active');
this.classList.add('active');
var panels = document.querySelectorAll('.tab-panel');
for (var j = 0; j < panels.length; j++) panels[j].classList.remove('active');
var activePanel = document.getElementById('panel-' + tab);
activePanel.classList.add('active');
// Trigger reveal for cards in newly active panel // Smooth scroll on click
var revealCards = activePanel.querySelectorAll('.reveal:not(.revealed)'); for (var i = 0; i < navLinks.length; i++) {
for (var k = 0; k < revealCards.length; k++) { navLinks[i].addEventListener('click', function(e) {
revealCards[k].classList.add('revealed'); e.preventDefault();
var targetId = this.getAttribute('href').substring(1);
var target = document.getElementById(targetId);
if (target) {
var offset = controlBar.offsetHeight + 20;
var navbarH = parseInt(getComputedStyle(document.documentElement).getPropertyValue('--navbar-height')) || 72;
var top = target.getBoundingClientRect().top + window.scrollY - offset - navbarH;
window.scrollTo({ top: top, behavior: 'smooth' });
} }
if (tab === 'karte') self.renderMap();
}); });
} }
// IntersectionObserver for scroll-spy
if (!('IntersectionObserver' in window)) return;
var observer = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
var id = entry.target.id;
for (var j = 0; j < navLinks.length; j++) {
navLinks[j].classList.remove('active');
if (navLinks[j].getAttribute('href') === '#' + id) {
navLinks[j].classList.add('active');
}
}
}
});
}, { rootMargin: '-20% 0px -70% 0px' });
for (var i = 0; i < sections.length; i++) {
observer.observe(sections[i]);
}
},
/* ===== STICKY DETECTION ===== */
initStickyDetect: function() {
var controlBar = document.getElementById('control-bar');
if (!('IntersectionObserver' in window)) return;
// Sentinel element before control-bar
var sentinel = document.createElement('div');
sentinel.style.height = '1px';
sentinel.style.visibility = 'hidden';
controlBar.parentNode.insertBefore(sentinel, controlBar);
var observer = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
controlBar.classList.toggle('stuck', !entry.isIntersecting);
});
}, { threshold: 0 });
observer.observe(sentinel);
}, },
initLangToggle: function() { initLangToggle: function() {
@@ -606,7 +642,7 @@ var Lagebild = {
/* ===== SCROLL REVEAL ===== */ /* ===== SCROLL REVEAL ===== */
initScrollReveal: function() { initScrollReveal: function() {
var cards = document.querySelectorAll('.content-card, .lagebild-cta'); var cards = document.querySelectorAll('.content-card, .section-karte');
if (!('IntersectionObserver' in window)) { if (!('IntersectionObserver' in window)) {
for (var i = 0; i < cards.length; i++) cards[i].classList.add('revealed'); for (var i = 0; i < cards.length; i++) cards[i].classList.add('revealed');
return; return;
@@ -622,14 +658,8 @@ var Lagebild = {
for (var i = 0; i < cards.length; i++) { for (var i = 0; i < cards.length; i++) {
cards[i].classList.add('reveal'); cards[i].classList.add('reveal');
// Immediately reveal cards in the active (visible) tab panel
var panel = cards[i].closest('.tab-panel');
if (!panel || panel.classList.contains('active')) {
cards[i].classList.add('revealed');
} else {
observer.observe(cards[i]); observer.observe(cards[i]);
} }
}
}, },
/* ===== HILFSFUNKTIONEN ===== */ /* ===== HILFSFUNKTIONEN ===== */
@@ -657,7 +687,7 @@ var Lagebild = {
}, },
stLabel: function(s) { stLabel: function(s) {
return { confirmed: 'Bestätigt', unconfirmed: 'Unbestätigt', established: 'Gesichert', return { confirmed: 'Best\u00e4tigt', unconfirmed: 'Unbest\u00e4tigt', established: 'Gesichert',
unverified: 'Nicht verifiziert', contradicted: 'Widerlegt', disputed: 'Umstritten', unverified: 'Nicht verifiziert', contradicted: 'Widerlegt', disputed: 'Umstritten',
developing: 'In Entwicklung', 'false': 'Falsch' }[s] || s; developing: 'In Entwicklung', 'false': 'Falsch' }[s] || s;
}, },
@@ -729,7 +759,7 @@ var Lagebild = {
showError: function() { showError: function() {
document.getElementById('summary-content').innerHTML = document.getElementById('summary-content').innerHTML =
'<div class="lagebild-error"><p>Das Lagebild konnte nicht geladen werden. Bitte versuchen Sie es später erneut.</p></div>'; '<div class="lagebild-error"><p>Das Lagebild konnte nicht geladen werden. Bitte versuchen Sie es sp\u00e4ter erneut.</p></div>';
} }
}; };