diff --git a/src/static/css/style.css b/src/static/css/style.css index d38956a..d944697 100644 --- a/src/static/css/style.css +++ b/src/static/css/style.css @@ -2453,25 +2453,25 @@ a.dev-source-pill:hover { /* Achsen-Container */ .ht-axis { position: relative; - height: 150px; + height: 110px; } /* Stündliches Layout: höher wegen Datums-Markern oben */ .ht-axis--hourly { - height: 170px; + height: 130px; } -/* Saeulen-Bereich (ueber der Linie) */ -.ht-bars { +/* Punkte-Bereich (über der Linie) */ +.ht-points { position: absolute; left: 4%; right: 4%; - top: 22px; - bottom: 60px; + top: 0; + height: 56px; } -.ht-axis--hourly .ht-bars { - top: 42px; +.ht-axis--hourly .ht-points { + top: 20px; } /* Achsenlinie */ @@ -2479,14 +2479,13 @@ a.dev-source-pill:hover { position: absolute; left: 2%; right: 2%; - top: 100px; + top: 60px; height: 2px; background: var(--border); - z-index: 3; } .ht-axis--hourly .ht-axis-line { - top: 120px; + top: 80px; } /* Datums-Marker (vertikale Linie + Datum oben, nur bei Stunden-Granularität) */ @@ -2640,12 +2639,12 @@ a.dev-source-pill:hover { position: absolute; left: 4%; right: 4%; - top: 110px; + top: 72px; height: 20px; } .ht-axis--hourly .ht-axis-labels { - top: 130px; + top: 90px; } .ht-axis-label { @@ -2665,206 +2664,6 @@ a.dev-source-pill:hover { color: var(--text-tertiary); } -/* === Säulen-Variante (neuer Stil) === */ -.ht-bar { - position: absolute; - bottom: 0; - width: 12px; - margin-left: -6px; - height: 100%; - cursor: pointer; - z-index: 5; - transition: transform 0.15s ease; -} -.ht-bar:hover { transform: scaleX(1.15); } -.ht-bar-fill { - position: absolute; - bottom: 0; - left: 0; - right: 0; - background: var(--text-disabled); - border-radius: 2px 2px 0 0; - transition: background 0.2s ease, height 0.2s ease; -} -.ht-bar:hover .ht-bar-fill, -.ht-bar.active .ht-bar-fill { background: var(--accent); } -.ht-bar-fill--empty { - height: 4px; - background: var(--border); -} -.ht-bar-snap-cap { - position: absolute; - top: -8px; - left: -2px; - right: -2px; - height: 6px; - background: var(--accent); - border-radius: 2px; - box-shadow: var(--glow-accent); -} -.ht-bars:has(.ht-bar.active) .ht-bar:not(.active) { opacity: 0.45; } - -/* Aktiver Bar: dezenter Marker oben */ -.ht-bar.active::before { - content: ''; - position: absolute; - bottom: 100%; - left: 50%; - transform: translateX(-50%); - width: 0; - height: 0; - border-left: 5px solid transparent; - border-right: 5px solid transparent; - border-top: 5px solid var(--accent); - margin-bottom: 4px; -} - -/* Themen-Label ueber aktiven Buckets */ -.ht-bucket-label { - position: absolute; - bottom: calc(100% + 14px); - left: 50%; - transform: translateX(-50%); - font-size: 10px; - font-family: var(--font-mono); - font-weight: 600; - color: var(--accent); - background: var(--bg-card); - padding: 1px 6px; - border-radius: 8px; - border: 1px solid var(--tint-accent-strong); - white-space: nowrap; - pointer-events: none; - opacity: 0.85; -} - -/* Hover-Vorschaukarte */ -.ht-hover-card { - position: absolute; - bottom: calc(100% + 8px); - left: 50%; - transform: translateX(-50%); - min-width: 240px; - max-width: 320px; - background: var(--bg-card); - border: 1px solid var(--accent); - border-radius: var(--radius); - box-shadow: var(--shadow-md); - padding: 8px 10px; - opacity: 0; - visibility: hidden; - transition: opacity 0.15s ease, visibility 0.15s ease; - pointer-events: none; - z-index: 20; - text-align: left; - white-space: normal; -} -.ht-bar:hover .ht-hover-card { opacity: 1; visibility: visible; } -.ht-hover-card-head { - font-size: 11px; - font-family: var(--font-mono); - color: var(--accent); - font-weight: 600; - margin-bottom: 4px; -} -.ht-hover-card-list { - list-style: none; - margin: 0; - padding: 0; - font-size: 12px; - color: var(--text-primary); - line-height: 1.4; -} -.ht-hover-card-list li { - padding: 2px 0; - border-top: 1px dashed var(--border); -} -.ht-hover-card-list li:first-child { border-top: none; } -.ht-hover-card-more { - margin-top: 4px; - font-size: 11px; - color: var(--text-tertiary); - font-style: italic; -} -.ht-hover-card-snap { - margin-top: 4px; - font-size: 11px; - color: var(--accent); - font-weight: 500; -} - -/* Lagebericht-Linien quer durch die Achse */ -.ht-snapshot-lines { - position: absolute; - left: 4%; - right: 4%; - top: 0; - bottom: 38px; - pointer-events: none; - z-index: 2; -} -.ht-snapshot-line { - position: absolute; - top: 0; - bottom: 0; - width: 1px; - margin-left: -1px; - background: var(--accent); - opacity: 0.35; - cursor: pointer; - pointer-events: auto; - transition: opacity 0.15s ease; -} -.ht-snapshot-line:hover { opacity: 0.85; } -.ht-snapshot-line-cap { - position: absolute; - top: -2px; - left: 50%; - transform: translateX(-50%); - width: 14px; - height: 14px; - background: var(--bg-card); - border: 1px solid var(--accent); - border-radius: 50%; - color: var(--accent); - display: flex; - align-items: center; - justify-content: center; -} - -/* "Heute"-Linie */ -.ht-today-line { - position: absolute; - left: 4%; - top: 0; - bottom: 38px; - width: 1px; - margin-left: -1px; - background: var(--accent); - opacity: 0.5; - border-left: 1px dashed var(--accent); - pointer-events: none; - z-index: 4; -} -.ht-today-label { - position: absolute; - top: 0; - left: 4px; - font-size: 9px; - font-family: var(--font-mono); - font-weight: 700; - color: var(--accent); - background: var(--bg-card); - padding: 0 4px; - border-radius: 2px; -} - -@media (prefers-reduced-motion: reduce) { - .ht-bar { transition: none; } - .ht-bar-fill { transition: none; } - .ht-detail-panel { animation: none; } -} - /* Detail-Panel */ .ht-detail-panel { margin-top: 8px; diff --git a/src/static/js/app.js b/src/static/js/app.js index bae85f8..79f6a02 100644 --- a/src/static/js/app.js +++ b/src/static/js/app.js @@ -1135,26 +1135,27 @@ const App = { entries.sort((a, b) => new Date(a.timestamp || 0) - new Date(b.timestamp || 0)); const granularity = this._calcGranularity(entries, range); - // Bei Filter "Lageberichte" zaehlen Snapshots; bei "Meldungen" nur Artikel; bei "Alle" beides. - const buckets = this._buildBuckets(entries, granularity); + let buckets = this._buildBuckets(entries, granularity); + buckets = this._mergeCloseBuckets(buckets); // Aktiven Index validieren if (this._activePointIndex !== null && this._activePointIndex >= buckets.length) { this._activePointIndex = null; } - // Achsen-Bereich (mit etwas Padding rechts/links, damit Bars nicht abgeschnitten werden) + // Achsen-Bereich const rangeStart = buckets[0].timestamp; const rangeEnd = buckets[buckets.length - 1].timestamp; - const articleMax = Math.max(1, ...buckets.map(b => b.entries.filter(e => e.kind === 'article').length)); + const maxCount = Math.max(...buckets.map(b => b.entries.length)); + // Stunden- vs. Tages-Granularität const isHourly = granularity === 'hour'; - const axisLabels = this._buildAxisLabels(buckets, granularity, isHourly); - const topActiveIdx = new Set(this._pickTopActiveBucketIdx(buckets, 3)); + const axisLabels = this._buildAxisLabels(buckets, granularity, true); - let html = `