feat: Stats-Bar ueber Karussell, Pfeil-Navigation, Count-Up

- Stats (Artikel/Quellen/Faktenchecks) als prominente Bar ueber dem
  Karussell mit Count-Up-Animation und gruener Live-Pulse-Anzeige
- Pfeil-Buttons links/rechts fuer Karussell-Navigation
- Text-Card breiter (860px)
- Stats nicht mehr in der Card

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dieser Commit ist enthalten in:
Claude Code
2026-04-06 18:39:28 +02:00
Ursprung 128d26056d
Commit 747ea0f5e4
3 geänderte Dateien mit 64 neuen und 25 gelöschten Zeilen

Datei anzeigen

@@ -130,14 +130,29 @@ a { color:inherit; text-decoration:none; }
.feature-card h3 { font-size:1rem; font-weight:700; color:var(--navy); margin-bottom:8px; } .feature-card h3 { font-size:1rem; font-weight:700; color:var(--navy); margin-bottom:8px; }
.feature-card p { font-size:0.88rem; color:var(--text-light); line-height:1.6; } .feature-card p { font-size:0.88rem; color:var(--text-light); line-height:1.6; }
/* ==================== LIVE STATS BAR ==================== */
.live-stats-bar { display:flex; justify-content:center; align-items:center; gap:48px; margin-bottom:40px; flex-wrap:wrap; }
.live-stat { text-align:center; }
.live-stat-value { display:block; font-size:2.8rem; font-weight:700; color:var(--navy); line-height:1.1; letter-spacing:-0.02em; }
.live-stat-label { display:block; font-size:0.8rem; color:var(--text-light); text-transform:uppercase; letter-spacing:0.08em; margin-top:4px; }
.live-stat-updated { font-size:0.82rem; color:var(--text-light); display:flex; align-items:center; gap:6px; }
.live-stat-updated::before { content:''; width:8px; height:8px; border-radius:50%; background:#4CAF50; animation:livePulse 2s infinite; }
@keyframes livePulse { 0%,100%{opacity:1} 50%{opacity:0.4} }
/* ==================== 3D CAROUSEL ==================== */ /* ==================== 3D CAROUSEL ==================== */
.carousel-viewport { overflow:hidden; padding:40px 0 20px; } .carousel-viewport { overflow:hidden; padding:20px 0; position:relative; }
.carousel-track { display:flex; justify-content:center; align-items:center; position:relative; min-height:440px; } .carousel-track { display:flex; justify-content:center; align-items:center; position:relative; min-height:440px; }
.carousel-card { width:720px; flex-shrink:0; background:var(--white); border-radius:var(--radius-lg); padding:28px 24px; box-shadow:var(--shadow); position:absolute; display:flex; flex-direction:column; transition:all 0.6s cubic-bezier(0.4,0,0.2,1); cursor:pointer; transform-style:preserve-3d; } .carousel-card { width:860px; flex-shrink:0; background:var(--white); border-radius:var(--radius-lg); padding:28px 24px; box-shadow:var(--shadow); position:absolute; display:flex; flex-direction:column; transition:all 0.6s cubic-bezier(0.4,0,0.2,1); cursor:pointer; transform-style:preserve-3d; }
.carousel-card.active { transform:scale(1) translateX(0) rotateY(0); z-index:3; opacity:1; pointer-events:all; } .carousel-card.active { transform:scale(1) translateX(0) rotateY(0); z-index:3; opacity:1; pointer-events:all; }
.carousel-card.left { transform:scale(0.78) translateX(-110%) rotateY(12deg); z-index:1; opacity:0.5; pointer-events:all; } .carousel-card.left { transform:scale(0.78) translateX(-110%) rotateY(12deg); z-index:1; opacity:0.5; pointer-events:all; }
.carousel-card.right { transform:scale(0.78) translateX(110%) rotateY(-12deg); z-index:1; opacity:0.5; pointer-events:all; } .carousel-card.right { transform:scale(0.78) translateX(110%) rotateY(-12deg); z-index:1; opacity:0.5; pointer-events:all; }
.carousel-card.hidden { transform:scale(0.6) translateX(0); z-index:0; opacity:0; pointer-events:none; } .carousel-card.hidden { transform:scale(0.6) translateX(0); z-index:0; opacity:0; pointer-events:none; }
/* Carousel arrows */
.carousel-arrow { position:absolute; top:50%; transform:translateY(-50%); z-index:10; width:44px; height:44px; border-radius:50%; border:2px solid var(--gray-200); background:var(--white); color:var(--navy); font-size:1.6rem; cursor:pointer; display:flex; align-items:center; justify-content:center; transition:all 0.2s; box-shadow:var(--shadow); line-height:1; }
.carousel-arrow:hover { border-color:var(--gold); color:var(--gold); box-shadow:var(--shadow-lg); }
.carousel-prev { left:8px; }
.carousel-next { right:8px; }
.carousel-nav { display:flex; justify-content:center; gap:10px; margin-top:24px; } .carousel-nav { display:flex; justify-content:center; gap:10px; margin-top:24px; }
.carousel-dot { width:10px; height:10px; border-radius:50%; border:2px solid var(--gold); background:transparent; cursor:pointer; transition:all 0.3s; padding:0; } .carousel-dot { width:10px; height:10px; border-radius:50%; border:2px solid var(--gold); background:transparent; cursor:pointer; transition:all 0.3s; padding:0; }
.carousel-dot.active { background:var(--gold); } .carousel-dot.active { background:var(--gold); }
@@ -147,10 +162,6 @@ a { color:inherit; text-decoration:none; }
.badge-soon { background:var(--gray-100); color:var(--gray-400); } .badge-soon { background:var(--gray-100); color:var(--gray-400); }
.demo-title { font-size:1.25rem; font-weight:700; color:var(--navy); margin-bottom:16px; } .demo-title { font-size:1.25rem; font-weight:700; color:var(--navy); margin-bottom:16px; }
.demo-stats { display:grid; grid-template-columns:repeat(3,1fr); gap:10px; margin-bottom:16px; }
.demo-stat { text-align:center; padding:10px 6px; background:var(--alt-solid); border-radius:var(--radius); }
.stat-value { display:block; font-size:1.4rem; font-weight:700; color:var(--navy); line-height:1.2; }
.stat-label { display:block; font-size:0.72rem; color:var(--text-light); margin-top:3px; }
.demo-excerpt { margin-bottom:16px; } .demo-excerpt { margin-bottom:16px; }
.excerpt-text { font-size:0.88rem; color:var(--text); line-height:1.65; } .excerpt-text { font-size:0.88rem; color:var(--text); line-height:1.65; }
@@ -160,7 +171,6 @@ a { color:inherit; text-decoration:none; }
.excerpt-text p { margin-bottom:10px; } .excerpt-text p { margin-bottom:10px; }
.excerpt-text ul { margin:8px 0 12px 20px; } .excerpt-text ul { margin:8px 0 12px 20px; }
.excerpt-text li { margin-bottom:4px; font-size:0.88rem; color:var(--text); } .excerpt-text li { margin-bottom:4px; font-size:0.88rem; color:var(--text); }
.demo-updated { font-size:0.82rem; color:var(--text-light); margin-bottom:16px; }
.placeholder-title { color:var(--gray-400); } .placeholder-title { color:var(--gray-400); }
.placeholder-text { font-size:0.95rem; color:var(--gray-400); flex:1; display:flex; align-items:center; justify-content:center; min-height:180px; } .placeholder-text { font-size:0.95rem; color:var(--gray-400); flex:1; display:flex; align-items:center; justify-content:center; min-height:180px; }

Datei anzeigen

@@ -112,31 +112,36 @@
<h2 class="section-title">Sehen Sie den Monitor in Aktion</h2> <h2 class="section-title">Sehen Sie den Monitor in Aktion</h2>
<p class="section-subtitle">Echte Lagebilder, erstellt vom AegisSight Monitor. Live und ohne Bearbeitung.</p> <p class="section-subtitle">Echte Lagebilder, erstellt vom AegisSight Monitor. Live und ohne Bearbeitung.</p>
<!-- Live Stats Bar -->
<div class="live-stats-bar">
<div class="live-stat">
<span class="live-stat-value" id="stat-articles">...</span>
<span class="live-stat-label">Artikel</span>
</div>
<div class="live-stat">
<span class="live-stat-value" id="stat-sources">...</span>
<span class="live-stat-label">Quellen</span>
</div>
<div class="live-stat">
<span class="live-stat-value" id="stat-factchecks">...</span>
<span class="live-stat-label">Faktenchecks</span>
</div>
<div class="live-stat-updated" id="demo-updated">Daten werden geladen...</div>
</div>
<!-- 3D Carousel --> <!-- 3D Carousel -->
<div class="carousel-viewport"> <div class="carousel-viewport">
<button class="carousel-arrow carousel-prev" aria-label="Vorherige Lage">&#8249;</button>
<button class="carousel-arrow carousel-next" aria-label="Nächste Lage">&#8250;</button>
<div class="carousel-track" id="carousel"> <div class="carousel-track" id="carousel">
<!-- Iran Card --> <!-- Iran Card -->
<div class="carousel-card card-live active" data-index="0"> <div class="carousel-card card-live active" data-index="0">
<div class="demo-badge">LIVE</div> <div class="demo-badge">LIVE</div>
<h3 class="demo-title">Iran-Konflikt</h3> <h3 class="demo-title">Iran-Konflikt</h3>
<div class="demo-stats" id="demo-stats-iran">
<div class="demo-stat">
<span class="stat-value" id="stat-articles">...</span>
<span class="stat-label">Artikel</span>
</div>
<div class="demo-stat">
<span class="stat-value" id="stat-sources">...</span>
<span class="stat-label">Quellen</span>
</div>
<div class="demo-stat">
<span class="stat-value" id="stat-factchecks">...</span>
<span class="stat-label">Faktenchecks</span>
</div>
</div>
<div class="demo-excerpt" id="demo-excerpt"> <div class="demo-excerpt" id="demo-excerpt">
<div class="excerpt-text" id="excerpt-text">Lagebild wird geladen...</div> <div class="excerpt-text" id="excerpt-text">Lagebild wird geladen...</div>
</div> </div>
<div class="demo-updated" id="demo-updated">Daten werden geladen...</div>
<a href="/lagen/iran-konflikt/" class="btn btn-primary btn-block">Vollständiges Lagebild öffnen</a> <a href="/lagen/iran-konflikt/" class="btn btn-primary btn-block">Vollständiges Lagebild öffnen</a>
</div> </div>
<!-- Placeholder 2 --> <!-- Placeholder 2 -->

Datei anzeigen

@@ -102,6 +102,16 @@
positionCards(0); positionCards(0);
// Arrow navigation
var prevBtn = document.querySelector('.carousel-prev');
var nextBtn = document.querySelector('.carousel-next');
if (prevBtn) prevBtn.addEventListener('click', function () {
positionCards((activeIndex - 1 + cards.length) % cards.length);
});
if (nextBtn) nextBtn.addEventListener('click', function () {
positionCards((activeIndex + 1) % cards.length);
});
/* ==================== SIMPLE MARKDOWN ==================== */ /* ==================== SIMPLE MARKDOWN ==================== */
function mdToHtml(md) { function mdToHtml(md) {
if (!md) return ''; if (!md) return '';
@@ -140,9 +150,23 @@
var es = document.getElementById('stat-sources'); var es = document.getElementById('stat-sources');
var ef = document.getElementById('stat-factchecks'); var ef = document.getElementById('stat-factchecks');
var eu = document.getElementById('demo-updated'); var eu = document.getElementById('demo-updated');
if (ea) ea.textContent = inc.article_count || 0; function countUp(el, target) {
if (es) es.textContent = inc.source_count || 0; if (!el || !target) return;
if (ef) ef.textContent = inc.factcheck_count || 0; var start = 0;
var duration = 1200;
var startTime = null;
function step(ts) {
if (!startTime) startTime = ts;
var progress = Math.min((ts - startTime) / duration, 1);
var ease = 1 - Math.pow(1 - progress, 3);
el.textContent = Math.floor(ease * target).toLocaleString('de-DE');
if (progress < 1) requestAnimationFrame(step);
}
requestAnimationFrame(step);
}
countUp(ea, inc.article_count);
countUp(es, inc.source_count);
countUp(ef, inc.factcheck_count);
if (eu && data.updated_at) eu.textContent = timeAgo(data.updated_at); if (eu && data.updated_at) eu.textContent = timeAgo(data.updated_at);
// Excerpt: pre-extracted in summary.json // Excerpt: pre-extracted in summary.json