diff --git a/lagebild/lagebild.css b/lagebild/lagebild.css index 97d6297..93c18a3 100644 --- a/lagebild/lagebild.css +++ b/lagebild/lagebild.css @@ -301,7 +301,7 @@ scroll-behavior: smooth; padding: 4px 0; scrollbar-width: thin; - scrollbar-color: var(--lb-border) transparent; + scrollbar-color: rgba(200, 168, 81, 0.4) rgba(200, 168, 81, 0.08); } .timeline-strip::-webkit-scrollbar { height: 4px; @@ -389,60 +389,137 @@ margin-top: 2px; } -/* Timeline Dropdown */ +/* Timeline Dropdown (Horizontal Timeline) */ .timeline-dropdown { display: none; background: var(--lb-bg-secondary); border: 1px solid var(--lb-border); border-top: none; border-radius: 0 0 var(--radius-sm, 4px) var(--radius-sm, 4px); - padding: 10px 14px; + padding: 8px 0; margin-top: 4px; + overflow-x: auto; + scrollbar-width: thin; + scrollbar-color: rgba(200, 168, 81, 0.4) rgba(200, 168, 81, 0.08); } .timeline-dropdown.open { display: block; } -.timeline-dropdown-header { - font-size: 0.78rem; - color: var(--lb-text-sec); - margin-bottom: 8px; - font-weight: 500; +.timeline-dropdown::-webkit-scrollbar { + height: 6px; } -.timeline-snap-list { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); - gap: 6px; +.timeline-dropdown::-webkit-scrollbar-track { + background: rgba(200, 168, 81, 0.08); + border-radius: 3px; } -.timeline-snap-item { - display: inline-flex; +.timeline-dropdown::-webkit-scrollbar-thumb { + background: rgba(200, 168, 81, 0.35); + border-radius: 3px; +} +.timeline-dropdown::-webkit-scrollbar-thumb:hover { + background: rgba(200, 168, 81, 0.55); +} +.h-timeline-track { + display: flex; + align-items: flex-start; + min-width: min-content; + padding: 4px 24px; + gap: 32px; +} +.h-timeline-point { + display: flex; + flex-direction: column; align-items: center; - gap: 8px; - padding: 6px 12px; - border-radius: var(--radius-sm, 4px); - border: 1px solid var(--lb-border); - background: transparent; - color: var(--lb-text-sec); - font-size: 0.78rem; + flex: 0 0 auto; + min-width: 70px; + position: relative; cursor: pointer; + padding: 4px 0; + background: none; + border: none; font-family: inherit; transition: all 0.2s; } -.timeline-snap-item:hover { - background: var(--lb-bg-card); - border-color: rgba(200, 168, 81, 0.4); +/* Connecting line through dot center */ +.h-timeline-point::before { + content: ''; + position: absolute; + top: 29px; + left: -16px; + right: -16px; + height: 2px; + background: rgba(200, 168, 81, 0.2); + z-index: 0; +} +.h-timeline-point:first-child::before { + left: 50%; + right: -16px; +} +.h-timeline-point:last-child::before { + left: -16px; + right: 50%; +} +.h-timeline-point:only-child::before { + display: none; +} +.h-timeline-time { + font-size: 0.75rem; + font-weight: 600; + color: var(--lb-text-sec); + margin-bottom: 8px; + line-height: 1; + transition: color 0.2s; +} +.h-timeline-dot { + width: 10px; + height: 10px; + border-radius: 50%; + background: rgba(200, 168, 81, 0.35); + z-index: 1; + position: relative; + transition: all 0.2s; + box-shadow: 0 0 4px rgba(200, 168, 81, 0.1); +} +.h-timeline-meta { + font-size: 0.65rem; + color: var(--lb-text-sec); + line-height: 1.4; + margin-top: 2px; + transition: color 0.2s; + white-space: normal; + text-align: center; +} +.h-timeline-meta:first-of-type { + margin-top: 8px; +} +/* Hover */ +.h-timeline-point:hover .h-timeline-time { color: var(--lb-text); } -.timeline-snap-item.active { - background: rgba(200, 168, 81, 0.1); - border-color: var(--lb-accent); +.h-timeline-point:hover .h-timeline-dot { + background: var(--lb-accent); + box-shadow: 0 0 8px var(--lb-glow-soft); + transform: scale(1.2); +} +/* Active */ +.h-timeline-point.active .h-timeline-time { color: var(--lb-accent); } -.timeline-snap-time { - font-weight: 600; +.h-timeline-point.active .h-timeline-dot { + width: 12px; + height: 12px; + margin: -1px 0; + background: var(--lb-accent); + box-shadow: 0 0 12px var(--lb-glow); + animation: h-timeline-pulse 2s infinite; } -.timeline-snap-meta { - font-size: 0.7rem; - opacity: 0.7; +@keyframes h-timeline-pulse { + 0%, 100% { box-shadow: 0 0 12px var(--lb-glow); transform: scale(1); } + 50% { box-shadow: 0 0 20px var(--lb-glow), 0 0 6px var(--lb-accent); transform: scale(1.15); } +} +.h-timeline-point.active .h-timeline-meta { + color: var(--lb-accent); + font-weight: 600; } /* Tab Navigation */ @@ -1377,15 +1454,19 @@ a.source-detail-article-title:hover { font-size: 0.95rem; } .timeline-dropdown { - padding: 8px 10px; + padding: 6px 0; } - .timeline-snap-list { - grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); - gap: 4px; + .h-timeline-track { + padding: 4px 12px; } - .timeline-snap-item { - padding: 5px 10px; - font-size: 0.72rem; + .h-timeline-point { + min-width: 64px; + } + .h-timeline-time { + font-size: 0.68rem; + } + .h-timeline-meta { + font-size: 0.6rem; } .tab-nav { overflow-x: auto; diff --git a/lagebild/lagebild.js b/lagebild/lagebild.js index 4052197..7fd9fcb 100644 --- a/lagebild/lagebild.js +++ b/lagebild/lagebild.js @@ -164,7 +164,7 @@ var Lagebild = { var statsHtml = ''; statsHtml += this.statCard(this.icons.fileText, '0', 'Artikel'); statsHtml += this.statCard(this.icons.globe, '0', 'Quellen'); - statsHtml += this.statCard(this.icons.shieldCheck, '0', 'Faktenchecks'); + statsHtml += this.statCard(this.icons.shieldCheck, '0', 'Faktenchecks'); document.getElementById('hero-stats').innerHTML = statsHtml; // Start count-up animations @@ -237,13 +237,13 @@ var Lagebild = { for (var j = 0; j < dates.length; j++) { var date = dates[j]; var daySnaps = groups[date]; - var latest = daySnaps[0]; var isActive = (j === dates.length - 1); + var defaultSnap = isActive ? daySnaps[0] : daySnaps[daySnaps.length - 1]; var d = new Date(date + 'T12:00:00Z'); h += ''; } h += ''; dropdown.innerHTML = h; dropdown.classList.add('open'); + + // Scroll to active point + var activePoint = dropdown.querySelector('.h-timeline-point.active'); + if (activePoint) { + setTimeout(function() { + activePoint.scrollIntoView({ behavior: 'smooth', inline: 'center', block: 'nearest' }); + }, 50); + } }, toDateKey: function(iso) { @@ -394,7 +403,7 @@ var Lagebild = { sources_json: sj || [], updated_at: sd.created_at, articles: this.data.articles, - fact_checks: this.data.fact_checks + fact_checks: this.getFactChecksAtTime(sd.created_at) }; this.allSnapshots[id] = this.currentView; this.renderCurrentView(); @@ -410,6 +419,12 @@ var Lagebild = { if (document.getElementById('panel-karte').classList.contains('active')) { this.renderMap(); } + // Faktencheck-Zaehler aktualisieren (Badge + Hero) + var fcCount = (this.currentView.fact_checks || []).length; + var fcBadge = document.getElementById('tab-badge-faktenchecks'); + if (fcBadge) fcBadge.textContent = fcCount; + var heroFc = document.getElementById('hero-fc-count'); + if (heroFc) heroFc.textContent = fcCount.toLocaleString('de-DE'); }, /* ===== TAB: LAGEBILD ===== */ @@ -943,6 +958,42 @@ var Lagebild = { } }, + /* ===== FAKTENCHECK-FILTER NACH ZEITRAUM ===== */ + getFactChecksAtTime: function(cutoff) { + var allFCs = this.data.fact_checks || []; + if (!cutoff) return allFCs; + var cutoffTime = new Date(this.toUTC(cutoff)).getTime(); + var filtered = []; + for (var i = 0; i < allFCs.length; i++) { + var fc = allFCs[i]; + var hist = fc.status_history || []; + if (!hist.length) continue; + // Erster Eintrag = Erstellungszeitpunkt des Faktenchecks + var firstAt = new Date(this.toUTC(hist[0].at)).getTime(); + if (firstAt > cutoffTime) continue; + // Status zum gewaehlten Zeitpunkt ermitteln + var statusAtTime = hist[0].status; + for (var j = 0; j < hist.length; j++) { + var stepTime = new Date(this.toUTC(hist[j].at)).getTime(); + if (stepTime <= cutoffTime) { + statusAtTime = hist[j].status; + } + } + // Kopie mit angepasstem Status und getrimmter History + var copy = {}; + for (var key in fc) { if (fc.hasOwnProperty(key)) copy[key] = fc[key]; } + copy.status = statusAtTime; + copy.status_history = []; + for (var j = 0; j < hist.length; j++) { + if (new Date(this.toUTC(hist[j].at)).getTime() <= cutoffTime) { + copy.status_history.push(hist[j]); + } + } + filtered.push(copy); + } + return filtered; + }, + /* ===== HILFSFUNKTIONEN ===== */ extractDomain: function(url) { if (!url) return null;