From a13a6492672c43750888df09f54f37418f8600f7 Mon Sep 17 00:00:00 2001 From: larssand Date: Sun, 15 Mar 2026 15:23:41 +0100 Subject: [PATCH] =?UTF-8?q?leaderboard-raderna=20i=20overlay=20=C3=A4r=20t?= =?UTF-8?q?=C3=A4tare=20igen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app.js | 30 +++++++++++--- src/styles.css | 110 ++++++++++++++++++++++++------------------------- 2 files changed, 79 insertions(+), 61 deletions(-) diff --git a/src/app.js b/src/app.js index 4f0fc06..3174f76 100644 --- a/src/app.js +++ b/src/app.js @@ -1083,6 +1083,7 @@ let selectedTeamEditId = null; let quickAddDraft = null; let overlaySyncTimer = null; let overlayRotationTimer = null; +let overlayLiveRefreshTimer = null; let overlayRotationIndex = 0; let overlayEvents = []; let lastOverlayLeaderKeyBySession = {}; @@ -1131,6 +1132,7 @@ async function init() { if (overlayMode) { startOverlaySync(); startOverlayRotation(); + startOverlayLiveRefresh(); if (state.settings.wsUrl) { connectDecoder(); } @@ -1704,6 +1706,15 @@ function startOverlayRotation() { }, 8000); } +function startOverlayLiveRefresh() { + clearInterval(overlayLiveRefreshTimer); + overlayLiveRefreshTimer = setInterval(() => { + if (currentView === "overlay" && ["leaderboard", "tv", "team"].includes(overlayViewMode)) { + renderOverlay(); + } + }, 250); +} + function renderNav() { if (overlayMode) { dom.nav.innerHTML = ""; @@ -5679,16 +5690,20 @@ function buildLeaderboard(session) { const distanceToTargetMs = Math.abs(targetMs - totalElapsedMs); const seedMetric = getCompetitorSeedMetric(session, row); const passings = getCompetitorPassings(session, row); + const latestPassing = passings.length ? passings[passings.length - 1] : null; const previousLapMs = passings.length >= 2 ? Number(passings[passings.length - 2].lapMs || 0) : null; + const lastLapMs = latestPassing ? Number(latestPassing.lapMs || 0) : Number(row.lastLapMs || 0) || 0; + const bestLapMs = Number(row.bestLapMs || 0) || 0; + const lastPassingTs = latestPassing ? Number(latestPassing.timestamp || 0) : Number(row.lastTimestamp || 0) || 0; const lapDeltaMs = - row.lastLapMs && previousLapMs && row.lastLapMs > 0 && previousLapMs > 0 ? row.lastLapMs - previousLapMs : null; + lastLapMs && previousLapMs && lastLapMs > 0 && previousLapMs > 0 ? lastLapMs - previousLapMs : null; const predictionBaseMs = - Number(row.lastLapMs || 0) > 0 - ? Number(row.lastLapMs) - : Number(row.bestLapMs || 0) > 0 - ? Number(row.bestLapMs) + lastLapMs > 0 + ? lastLapMs + : bestLapMs > 0 + ? bestLapMs : null; - const currentLapElapsedMs = row.lastTimestamp ? Math.max(0, nowTs - row.lastTimestamp) : 0; + const currentLapElapsedMs = lastPassingTs ? Math.max(0, nowTs - lastPassingTs) : 0; const predictedRemainingMs = predictionBaseMs ? Math.max(0, predictionBaseMs - currentLapElapsedMs) : null; const predictedProgress = predictionBaseMs ? Math.min(1.25, currentLapElapsedMs / predictionBaseMs) : 0; const predictionTone = @@ -5699,6 +5714,9 @@ function buildLeaderboard(session) { : "late"; return { ...row, + lastLapMs, + bestLapMs, + lastTimestamp: lastPassingTs || row.lastTimestamp, totalElapsedMs, distanceToTargetMs, seedMetric, diff --git a/src/styles.css b/src/styles.css index cb27a36..60f9fea 100644 --- a/src/styles.css +++ b/src/styles.css @@ -780,7 +780,7 @@ select:focus { .overlay-shell { min-height: 100vh; - padding: 14px; + padding: 10px; background: radial-gradient(circle at 15% 0%, rgba(225, 6, 0, 0.18), transparent 30%), radial-gradient(circle at 100% 80%, rgba(37, 59, 103, 0.22), transparent 30%), @@ -790,15 +790,15 @@ select:focus { .overlay-header { display: flex; justify-content: space-between; - gap: 10px; + gap: 8px; align-items: center; - margin-bottom: 8px; + margin-bottom: 6px; } .overlay-header-main { display: flex; align-items: center; - gap: 10px; + gap: 8px; min-width: 0; } @@ -809,15 +809,15 @@ select:focus { .overlay-kicker-row { display: flex; align-items: center; - gap: 6px; + gap: 4px; flex-wrap: wrap; - margin-bottom: 2px; + margin-bottom: 1px; } .overlay-header h1 { margin: 0; font-family: Orbitron, sans-serif; - font-size: clamp(1.05rem, 1.7vw, 1.6rem); + font-size: clamp(0.92rem, 1.35vw, 1.25rem); line-height: 1.02; } @@ -826,13 +826,13 @@ select:focus { color: var(--muted); text-transform: uppercase; letter-spacing: 0.08em; - font-size: 0.62rem; + font-size: 0.56rem; } .overlay-header-sub { - margin: 3px 0 0; + margin: 1px 0 0; color: var(--muted); - font-size: 0.74rem; + font-size: 0.66rem; } .overlay-meta { @@ -844,7 +844,7 @@ select:focus { .overlay-clock { font-family: Orbitron, sans-serif; - font-size: clamp(1.35rem, 2.3vw, 2.2rem); + font-size: clamp(1.12rem, 1.9vw, 1.7rem); font-weight: 800; } @@ -856,13 +856,13 @@ select:focus { color: var(--muted); text-transform: uppercase; letter-spacing: 0.08em; - font-size: 0.62rem; + font-size: 0.56rem; } .overlay-board { display: grid; - grid-template-columns: minmax(0, 1.85fr) minmax(210px, 0.38fr); - gap: 10px; + grid-template-columns: minmax(0, 1.92fr) minmax(180px, 0.31fr); + gap: 8px; } .overlay-board-tv { @@ -964,12 +964,12 @@ select:focus { } .overlay-table-wrap { - padding: 6px 8px 8px; + padding: 4px 6px 6px; } .overlay-display-wrap { display: grid; - gap: 8px; + gap: 6px; } .overlay-fastest-banner, @@ -984,8 +984,8 @@ select:focus { display: flex; justify-content: space-between; align-items: end; - gap: 12px; - padding: 10px 12px; + gap: 8px; + padding: 7px 10px; background: linear-gradient(135deg, rgba(225, 6, 0, 0.18), rgba(225, 6, 0, 0.04)), rgba(7, 12, 20, 0.92); @@ -1002,20 +1002,20 @@ select:focus { display: block; margin-top: 2px; font-family: Orbitron, sans-serif; - font-size: clamp(1.25rem, 2.3vw, 1.9rem); + font-size: clamp(1.02rem, 1.7vw, 1.45rem); } .overlay-leaderboard-card { - padding: 8px; + padding: 5px; } .overlay-leaderboard-card-tv { - min-height: calc(100vh - 152px); + min-height: calc(100vh - 118px); } .overlay-shell-dense .overlay-logo { - width: 44px; - height: 44px; + width: 34px; + height: 34px; } .overlay-fastest-banner-dense { @@ -1027,13 +1027,13 @@ select:focus { } .overlay-fastest-driver { - font-size: 0.9rem; + font-size: 0.76rem; text-align: right; } .overlay-fastest-meta { color: var(--muted); - font-size: 0.66rem; + font-size: 0.58rem; text-transform: uppercase; letter-spacing: 0.06em; white-space: nowrap; @@ -1045,24 +1045,24 @@ select:focus { .overlay-race-metric strong, .overlay-race-best strong { - font-size: clamp(0.88rem, 1.15vw, 1.02rem); + font-size: clamp(0.78rem, 0.98vw, 0.92rem); line-height: 1.05; } .overlay-race-pos .pos-pill { - min-width: 32px; - height: 32px; - font-size: 0.9rem; + min-width: 26px; + height: 26px; + font-size: 0.76rem; } .overlay-shell-dense .pill { - padding: 4px 8px; - font-size: 0.62rem; + padding: 3px 6px; + font-size: 0.54rem; } .overlay-shell-dense .btn.overlay-fullscreen-btn { - padding: 8px 10px; - font-size: 0.72rem; + padding: 6px 8px; + font-size: 0.66rem; } .overlay-section-head { @@ -1105,28 +1105,28 @@ select:focus { .overlay-side { display: grid; - gap: 8px; - font-size: 0.84rem; + gap: 6px; + font-size: 0.78rem; } .overlay-side-card { - padding: 8px; + padding: 6px; } .overlay-rotating-card { - min-height: 220px; + min-height: 180px; } .overlay-side-card h3 { - margin: 0 0 4px; - font-size: 0.86rem; + margin: 0 0 3px; + font-size: 0.78rem; } .overlay-passing { display: flex; justify-content: space-between; - gap: 6px; - padding: 4px 0; + gap: 5px; + padding: 3px 0; border-bottom: 1px solid var(--line); } @@ -1135,35 +1135,35 @@ select:focus { } .overlay-side-card .overlay-passing strong { - font-size: 0.8rem; + font-size: 0.72rem; line-height: 1.15; } .overlay-side-card .overlay-passing span { font-family: Orbitron, sans-serif; - font-size: 0.72rem; + font-size: 0.64rem; color: var(--text); white-space: nowrap; } .overlay-side-card .pill { padding: 3px 7px; - font-size: 0.58rem; + font-size: 0.54rem; } .overlay-race-list { display: grid; - gap: 6px; + gap: 4px; } .overlay-race-row { display: grid; - grid-template-columns: 48px minmax(200px, 1.55fr) repeat(3, minmax(102px, 0.7fr)) minmax(110px, 0.72fr); - gap: 8px; + grid-template-columns: 38px minmax(170px, 1.72fr) repeat(3, minmax(90px, 0.62fr)) minmax(95px, 0.66fr); + gap: 6px; align-items: center; - padding: 8px 10px; + padding: 5px 7px; border: 1px solid rgba(255, 255, 255, 0.06); - border-radius: 10px; + border-radius: 8px; background: rgba(255, 255, 255, 0.03); } @@ -1179,7 +1179,7 @@ select:focus { } .overlay-race-driver strong { - font-size: clamp(0.98rem, 1.35vw, 1.18rem); + font-size: clamp(0.82rem, 1.04vw, 0.96rem); line-height: 1.05; } @@ -1187,32 +1187,32 @@ select:focus { .overlay-race-metric label, .overlay-race-best label { color: var(--muted); - font-size: 0.62rem; + font-size: 0.54rem; text-transform: uppercase; letter-spacing: 0.06em; } .overlay-prediction { - margin-top: 4px; + margin-top: 2px; } .overlay-prediction-meta { display: flex; justify-content: space-between; gap: 8px; - margin-bottom: 3px; + margin-bottom: 2px; } .overlay-prediction-meta label, .overlay-prediction-meta span { color: var(--muted); - font-size: 0.58rem; + font-size: 0.5rem; text-transform: uppercase; letter-spacing: 0.06em; } .overlay-prediction-track { - height: 3px; + height: 2px; border-radius: 999px; overflow: hidden; background: rgba(255, 255, 255, 0.08);