leaderboard-raderna i overlay är tätare igen

This commit is contained in:
larssand
2026-03-15 15:23:41 +01:00
parent 604ec28030
commit a13a649267
2 changed files with 79 additions and 61 deletions

View File

@@ -1083,6 +1083,7 @@ let selectedTeamEditId = null;
let quickAddDraft = null; let quickAddDraft = null;
let overlaySyncTimer = null; let overlaySyncTimer = null;
let overlayRotationTimer = null; let overlayRotationTimer = null;
let overlayLiveRefreshTimer = null;
let overlayRotationIndex = 0; let overlayRotationIndex = 0;
let overlayEvents = []; let overlayEvents = [];
let lastOverlayLeaderKeyBySession = {}; let lastOverlayLeaderKeyBySession = {};
@@ -1131,6 +1132,7 @@ async function init() {
if (overlayMode) { if (overlayMode) {
startOverlaySync(); startOverlaySync();
startOverlayRotation(); startOverlayRotation();
startOverlayLiveRefresh();
if (state.settings.wsUrl) { if (state.settings.wsUrl) {
connectDecoder(); connectDecoder();
} }
@@ -1704,6 +1706,15 @@ function startOverlayRotation() {
}, 8000); }, 8000);
} }
function startOverlayLiveRefresh() {
clearInterval(overlayLiveRefreshTimer);
overlayLiveRefreshTimer = setInterval(() => {
if (currentView === "overlay" && ["leaderboard", "tv", "team"].includes(overlayViewMode)) {
renderOverlay();
}
}, 250);
}
function renderNav() { function renderNav() {
if (overlayMode) { if (overlayMode) {
dom.nav.innerHTML = ""; dom.nav.innerHTML = "";
@@ -5679,16 +5690,20 @@ function buildLeaderboard(session) {
const distanceToTargetMs = Math.abs(targetMs - totalElapsedMs); const distanceToTargetMs = Math.abs(targetMs - totalElapsedMs);
const seedMetric = getCompetitorSeedMetric(session, row); const seedMetric = getCompetitorSeedMetric(session, row);
const passings = getCompetitorPassings(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 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 = 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 = const predictionBaseMs =
Number(row.lastLapMs || 0) > 0 lastLapMs > 0
? Number(row.lastLapMs) ? lastLapMs
: Number(row.bestLapMs || 0) > 0 : bestLapMs > 0
? Number(row.bestLapMs) ? bestLapMs
: null; : 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 predictedRemainingMs = predictionBaseMs ? Math.max(0, predictionBaseMs - currentLapElapsedMs) : null;
const predictedProgress = predictionBaseMs ? Math.min(1.25, currentLapElapsedMs / predictionBaseMs) : 0; const predictedProgress = predictionBaseMs ? Math.min(1.25, currentLapElapsedMs / predictionBaseMs) : 0;
const predictionTone = const predictionTone =
@@ -5699,6 +5714,9 @@ function buildLeaderboard(session) {
: "late"; : "late";
return { return {
...row, ...row,
lastLapMs,
bestLapMs,
lastTimestamp: lastPassingTs || row.lastTimestamp,
totalElapsedMs, totalElapsedMs,
distanceToTargetMs, distanceToTargetMs,
seedMetric, seedMetric,

View File

@@ -780,7 +780,7 @@ select:focus {
.overlay-shell { .overlay-shell {
min-height: 100vh; min-height: 100vh;
padding: 14px; padding: 10px;
background: background:
radial-gradient(circle at 15% 0%, rgba(225, 6, 0, 0.18), transparent 30%), 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%), radial-gradient(circle at 100% 80%, rgba(37, 59, 103, 0.22), transparent 30%),
@@ -790,15 +790,15 @@ select:focus {
.overlay-header { .overlay-header {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
gap: 10px; gap: 8px;
align-items: center; align-items: center;
margin-bottom: 8px; margin-bottom: 6px;
} }
.overlay-header-main { .overlay-header-main {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px; gap: 8px;
min-width: 0; min-width: 0;
} }
@@ -809,15 +809,15 @@ select:focus {
.overlay-kicker-row { .overlay-kicker-row {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 6px; gap: 4px;
flex-wrap: wrap; flex-wrap: wrap;
margin-bottom: 2px; margin-bottom: 1px;
} }
.overlay-header h1 { .overlay-header h1 {
margin: 0; margin: 0;
font-family: Orbitron, sans-serif; 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; line-height: 1.02;
} }
@@ -826,13 +826,13 @@ select:focus {
color: var(--muted); color: var(--muted);
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.08em; letter-spacing: 0.08em;
font-size: 0.62rem; font-size: 0.56rem;
} }
.overlay-header-sub { .overlay-header-sub {
margin: 3px 0 0; margin: 1px 0 0;
color: var(--muted); color: var(--muted);
font-size: 0.74rem; font-size: 0.66rem;
} }
.overlay-meta { .overlay-meta {
@@ -844,7 +844,7 @@ select:focus {
.overlay-clock { .overlay-clock {
font-family: Orbitron, sans-serif; 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; font-weight: 800;
} }
@@ -856,13 +856,13 @@ select:focus {
color: var(--muted); color: var(--muted);
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.08em; letter-spacing: 0.08em;
font-size: 0.62rem; font-size: 0.56rem;
} }
.overlay-board { .overlay-board {
display: grid; display: grid;
grid-template-columns: minmax(0, 1.85fr) minmax(210px, 0.38fr); grid-template-columns: minmax(0, 1.92fr) minmax(180px, 0.31fr);
gap: 10px; gap: 8px;
} }
.overlay-board-tv { .overlay-board-tv {
@@ -964,12 +964,12 @@ select:focus {
} }
.overlay-table-wrap { .overlay-table-wrap {
padding: 6px 8px 8px; padding: 4px 6px 6px;
} }
.overlay-display-wrap { .overlay-display-wrap {
display: grid; display: grid;
gap: 8px; gap: 6px;
} }
.overlay-fastest-banner, .overlay-fastest-banner,
@@ -984,8 +984,8 @@ select:focus {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: end; align-items: end;
gap: 12px; gap: 8px;
padding: 10px 12px; padding: 7px 10px;
background: background:
linear-gradient(135deg, rgba(225, 6, 0, 0.18), rgba(225, 6, 0, 0.04)), linear-gradient(135deg, rgba(225, 6, 0, 0.18), rgba(225, 6, 0, 0.04)),
rgba(7, 12, 20, 0.92); rgba(7, 12, 20, 0.92);
@@ -1002,20 +1002,20 @@ select:focus {
display: block; display: block;
margin-top: 2px; margin-top: 2px;
font-family: Orbitron, sans-serif; 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 { .overlay-leaderboard-card {
padding: 8px; padding: 5px;
} }
.overlay-leaderboard-card-tv { .overlay-leaderboard-card-tv {
min-height: calc(100vh - 152px); min-height: calc(100vh - 118px);
} }
.overlay-shell-dense .overlay-logo { .overlay-shell-dense .overlay-logo {
width: 44px; width: 34px;
height: 44px; height: 34px;
} }
.overlay-fastest-banner-dense { .overlay-fastest-banner-dense {
@@ -1027,13 +1027,13 @@ select:focus {
} }
.overlay-fastest-driver { .overlay-fastest-driver {
font-size: 0.9rem; font-size: 0.76rem;
text-align: right; text-align: right;
} }
.overlay-fastest-meta { .overlay-fastest-meta {
color: var(--muted); color: var(--muted);
font-size: 0.66rem; font-size: 0.58rem;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.06em; letter-spacing: 0.06em;
white-space: nowrap; white-space: nowrap;
@@ -1045,24 +1045,24 @@ select:focus {
.overlay-race-metric strong, .overlay-race-metric strong,
.overlay-race-best 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; line-height: 1.05;
} }
.overlay-race-pos .pos-pill { .overlay-race-pos .pos-pill {
min-width: 32px; min-width: 26px;
height: 32px; height: 26px;
font-size: 0.9rem; font-size: 0.76rem;
} }
.overlay-shell-dense .pill { .overlay-shell-dense .pill {
padding: 4px 8px; padding: 3px 6px;
font-size: 0.62rem; font-size: 0.54rem;
} }
.overlay-shell-dense .btn.overlay-fullscreen-btn { .overlay-shell-dense .btn.overlay-fullscreen-btn {
padding: 8px 10px; padding: 6px 8px;
font-size: 0.72rem; font-size: 0.66rem;
} }
.overlay-section-head { .overlay-section-head {
@@ -1105,28 +1105,28 @@ select:focus {
.overlay-side { .overlay-side {
display: grid; display: grid;
gap: 8px; gap: 6px;
font-size: 0.84rem; font-size: 0.78rem;
} }
.overlay-side-card { .overlay-side-card {
padding: 8px; padding: 6px;
} }
.overlay-rotating-card { .overlay-rotating-card {
min-height: 220px; min-height: 180px;
} }
.overlay-side-card h3 { .overlay-side-card h3 {
margin: 0 0 4px; margin: 0 0 3px;
font-size: 0.86rem; font-size: 0.78rem;
} }
.overlay-passing { .overlay-passing {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
gap: 6px; gap: 5px;
padding: 4px 0; padding: 3px 0;
border-bottom: 1px solid var(--line); border-bottom: 1px solid var(--line);
} }
@@ -1135,35 +1135,35 @@ select:focus {
} }
.overlay-side-card .overlay-passing strong { .overlay-side-card .overlay-passing strong {
font-size: 0.8rem; font-size: 0.72rem;
line-height: 1.15; line-height: 1.15;
} }
.overlay-side-card .overlay-passing span { .overlay-side-card .overlay-passing span {
font-family: Orbitron, sans-serif; font-family: Orbitron, sans-serif;
font-size: 0.72rem; font-size: 0.64rem;
color: var(--text); color: var(--text);
white-space: nowrap; white-space: nowrap;
} }
.overlay-side-card .pill { .overlay-side-card .pill {
padding: 3px 7px; padding: 3px 7px;
font-size: 0.58rem; font-size: 0.54rem;
} }
.overlay-race-list { .overlay-race-list {
display: grid; display: grid;
gap: 6px; gap: 4px;
} }
.overlay-race-row { .overlay-race-row {
display: grid; display: grid;
grid-template-columns: 48px minmax(200px, 1.55fr) repeat(3, minmax(102px, 0.7fr)) minmax(110px, 0.72fr); grid-template-columns: 38px minmax(170px, 1.72fr) repeat(3, minmax(90px, 0.62fr)) minmax(95px, 0.66fr);
gap: 8px; gap: 6px;
align-items: center; align-items: center;
padding: 8px 10px; padding: 5px 7px;
border: 1px solid rgba(255, 255, 255, 0.06); border: 1px solid rgba(255, 255, 255, 0.06);
border-radius: 10px; border-radius: 8px;
background: rgba(255, 255, 255, 0.03); background: rgba(255, 255, 255, 0.03);
} }
@@ -1179,7 +1179,7 @@ select:focus {
} }
.overlay-race-driver strong { .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; line-height: 1.05;
} }
@@ -1187,32 +1187,32 @@ select:focus {
.overlay-race-metric label, .overlay-race-metric label,
.overlay-race-best label { .overlay-race-best label {
color: var(--muted); color: var(--muted);
font-size: 0.62rem; font-size: 0.54rem;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.06em; letter-spacing: 0.06em;
} }
.overlay-prediction { .overlay-prediction {
margin-top: 4px; margin-top: 2px;
} }
.overlay-prediction-meta { .overlay-prediction-meta {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
gap: 8px; gap: 8px;
margin-bottom: 3px; margin-bottom: 2px;
} }
.overlay-prediction-meta label, .overlay-prediction-meta label,
.overlay-prediction-meta span { .overlay-prediction-meta span {
color: var(--muted); color: var(--muted);
font-size: 0.58rem; font-size: 0.5rem;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.06em; letter-spacing: 0.06em;
} }
.overlay-prediction-track { .overlay-prediction-track {
height: 3px; height: 2px;
border-radius: 999px; border-radius: 999px;
overflow: hidden; overflow: hidden;
background: rgba(255, 255, 255, 0.08); background: rgba(255, 255, 255, 0.08);