modda layoten för obs overlay

This commit is contained in:
larssand
2026-03-22 20:26:11 +01:00
parent 5f4c64e576
commit a578edaf20
2 changed files with 197 additions and 109 deletions

View File

@@ -6472,26 +6472,30 @@ function renderOverlay() {
${
active
? `
<header class="overlay-header">
<div class="overlay-header-main">
${branding.logoDataUrl ? `<img class="overlay-logo" src="${escapeHtml(branding.logoDataUrl)}" alt="logo" />` : ""}
<div class="overlay-header-copy">
<div class="overlay-kicker-row">
<p class="overlay-kicker">${escapeHtml(getEventName(active.eventId))}</p>
<span class="pill">${escapeHtml(getSessionTypeLabel(active.type))}</span>
${overlayViewMode !== "tv" ? `<span class="pill">${escapeHtml(getStartModeLabel(active.startMode))}</span>` : ""}
<span class="pill">${escapeHtml(modeLabel)}</span>
</div>
<h1>${escapeHtml(active.name)}</h1>
<p class="overlay-header-sub">${escapeHtml(branding.brandName || "JMK RB RaceController")}</p>
</div>
</div>
<div class="overlay-meta">
<button id="overlayFullscreen" class="btn overlay-fullscreen-btn" type="button">${t("overlay.fullscreen")}</button>
${overlayViewMode === "obs" && obsConfig && !obsConfig.showClock ? "" : `<div class="overlay-clock">${overlayClock}</div>`}
<div class="overlay-status">${escapeHtml(overlayStatusLabel)}</div>
</div>
</header>
${
overlayViewMode === "obs"
? ""
: `<header class="overlay-header">
<div class="overlay-header-main">
${branding.logoDataUrl ? `<img class="overlay-logo" src="${escapeHtml(branding.logoDataUrl)}" alt="logo" />` : ""}
<div class="overlay-header-copy">
<div class="overlay-kicker-row">
<p class="overlay-kicker">${escapeHtml(getEventName(active.eventId))}</p>
<span class="pill">${escapeHtml(getSessionTypeLabel(active.type))}</span>
${overlayViewMode !== "tv" ? `<span class="pill">${escapeHtml(getStartModeLabel(active.startMode))}</span>` : ""}
<span class="pill">${escapeHtml(modeLabel)}</span>
</div>
<h1>${escapeHtml(active.name)}</h1>
<p class="overlay-header-sub">${escapeHtml(branding.brandName || "JMK RB RaceController")}</p>
</div>
</div>
<div class="overlay-meta">
<button id="overlayFullscreen" class="btn overlay-fullscreen-btn" type="button">${t("overlay.fullscreen")}</button>
${overlayViewMode === "obs" && obsConfig && !obsConfig.showClock ? "" : `<div class="overlay-clock">${overlayClock}</div>`}
<div class="overlay-status">${escapeHtml(overlayStatusLabel)}</div>
</div>
</header>`
}
${
overlayViewMode === "speaker"
@@ -6646,6 +6650,8 @@ function renderObsOverlay(active, leaderboard, result, sessionTiming, branding)
const readyPositionGrid = active && active.status === "ready" && normalizeStartMode(active.startMode) === "position";
const showStartGrid = obsConfig.showGrid && readyPositionGrid;
const leadRow = compactRows[0] || null;
const fastestRow =
[...compactRows].filter((row) => Number.isFinite(row.bestLapMs)).sort((left, right) => left.bestLapMs - right.bestLapMs)[0] || null;
const visiblePassings = getVisiblePassings(result);
const elapsedOrRemaining = sessionTiming?.untimed
? formatElapsedClock(sessionTiming?.elapsedMs ?? 0)
@@ -6716,104 +6722,67 @@ function renderObsOverlay(active, leaderboard, result, sessionTiming, branding)
`;
}
const towerRowsHtml = showStartGrid
? getSessionGridEntries(active)
.slice(0, obsConfig.rows)
.map((entry, idx) => {
const posClass = idx === 0 ? "pos-1" : idx === 1 ? "pos-2" : idx === 2 ? "pos-3" : "";
return `
<article class="overlay-obs-tower-row ${idx === 0 ? "overlay-obs-row-leader" : ""}">
<span class="pos-pill ${posClass}">${entry.slot}</span>
<div class="overlay-obs-tower-driver">
<strong>${escapeHtml(entry.name)}</strong>
<span>${escapeHtml(entry.meta || "-")}</span>
</div>
</article>
`;
})
.join("")
: compactRows
.map((row, idx) => {
const posClass = idx === 0 ? "pos-1" : idx === 1 ? "pos-2" : idx === 2 ? "pos-3" : "";
const trail = [
obsConfig.showLaps ? `<span>${row.laps ?? 0}L</span>` : "",
obsConfig.showResult ? `<span>${escapeHtml(row.resultDisplay)}</span>` : "",
obsConfig.showBest ? `<span>${formatLap(row.bestLapMs)}</span>` : "",
obsConfig.showGap ? `<span>${escapeHtml(row.gapDisplay || row.gapAhead || "-")}</span>` : "",
]
.filter(Boolean)
.join("");
return `
<article class="overlay-obs-tower-row ${idx === 0 ? "overlay-obs-row-leader" : ""}">
<span class="pos-pill ${posClass}">${idx + 1}</span>
<div class="overlay-obs-tower-driver">
<strong>${escapeHtml(row.displayName || row.driverName)}</strong>
<span>${escapeHtml(row.teamId ? formatTeamActiveMemberLabel(row) : row.subLabel || row.transponder || "-")}</span>
</div>
${trail ? `<div class="overlay-obs-tower-trail">${trail}</div>` : ""}
</article>
`;
})
.join("");
return `
<section class="overlay-obs-layout">
<div class="overlay-obs-main">
<div class="overlay-obs-brandline">
<section class="overlay-obs-tower">
<div class="overlay-obs-tower-head">
<div class="overlay-obs-tower-brand">
${branding.logoDataUrl ? `<img class="overlay-logo overlay-obs-logo" src="${escapeHtml(branding.logoDataUrl)}" alt="logo" />` : ""}
<div>
<p class="overlay-kicker">${escapeHtml(getEventName(active.eventId))}</p>
<h2>${escapeHtml(active.name)}</h2>
<div class="overlay-obs-meta">
<span>${escapeHtml(getSessionTypeLabel(active.type))}</span>
<span>${escapeHtml(getStartModeLabel(active.startMode))}</span>
<span>${t("table.laps")}: ${leadRow?.laps || 0}</span>
<span>${t("timing.total_passings")}: ${visiblePassings.length || 0}</span>
</div>
</div>
</div>
${obsConfig.showClock ? `
<div class="overlay-obs-clockblock">
<strong>${elapsedOrRemaining}</strong>
<span>${escapeHtml(sessionTiming?.followUpActive ? t("timing.follow_up_active") : getStatusLabel(active.status))}</span>
</div>
` : ""}
${obsConfig.showClock ? `<div class="overlay-obs-tower-clock">${elapsedOrRemaining}</div>` : ""}
</div>
<div class="overlay-obs-content">
<section class="overlay-obs-feature">
${showStartGrid
? `
<div class="overlay-section-head">
<h3>${t("events.start_grid")}</h3>
<span class="pill">${escapeHtml(getStartModeLabel(active.startMode))}</span>
</div>
${renderPositionGrid(active)}
`
: obsConfig.showFastest
? `
<div class="overlay-section-head">
<h3>${t("overlay.fastest_lap")}</h3>
<span class="pill">${t("overlay.mode_obs")}</span>
</div>
<div class="overlay-fastest-banner overlay-fastest-banner-dense overlay-fastest-banner-obs">
<div class="overlay-fastest-banner-copy">
<span>${t("overlay.fastest_lap")}</span>
<strong>${formatLap(leadRow?.bestLapMs)}</strong>
</div>
<div class="overlay-fastest-driver">${escapeHtml(leadRow?.displayName || leadRow?.driverName || "-")}</div>
<div class="overlay-fastest-meta">${escapeHtml(branding.brandName || "JMK RB RaceController")}</div>
</div>
<div class="overlay-obs-gridhint">
<strong>${t("events.position_grid")}</strong>
<span>${t("overlay.leaderboard_live")}</span>
</div>
`
: `
<div class="overlay-section-head">
<h3>${escapeHtml(branding.brandName || "JMK RB RaceController")}</h3>
<span class="pill">${t("overlay.mode_obs")}</span>
</div>
<div class="overlay-obs-gridhint">
<strong>${escapeHtml(getEventName(active.eventId))}</strong>
<span>${escapeHtml(active.name)}</span>
</div>
`}
</section>
<section class="overlay-obs-standings">
${compactRows.length ? compactRows.map((row, idx) => {
const posClass = idx === 0 ? "pos-1" : idx === 1 ? "pos-2" : idx === 2 ? "pos-3" : "";
return `
<article class="overlay-obs-row ${idx === 0 ? "overlay-obs-row-leader" : ""}">
<span class="pos-pill ${posClass}">${idx + 1}</span>
<div class="overlay-obs-driver">
<strong>${escapeHtml(row.displayName || row.driverName)}</strong>
<span>${escapeHtml(row.teamId ? formatTeamActiveMemberLabel(row) : row.subLabel || row.transponder || "-")}</span>
</div>
${obsConfig.showLaps ? `
<div class="overlay-obs-metric">
<label>${t("table.laps")}</label>
<strong>${row.laps ?? 0}</strong>
</div>` : ""}
${obsConfig.showResult ? `
<div class="overlay-obs-metric">
<label>${t("table.result")}</label>
<strong>${escapeHtml(row.resultDisplay)}</strong>
</div>` : ""}
${obsConfig.showBest ? `
<div class="overlay-obs-metric">
<label>${t("table.best_lap")}</label>
<strong>${formatLap(row.bestLapMs)}</strong>
</div>` : ""}
${obsConfig.showGap ? `
<div class="overlay-obs-metric">
<label>${t("table.gap")}</label>
<strong>${escapeHtml(row.gapDisplay || row.gapAhead || "-")}</strong>
</div>` : ""}
</article>
`;
}).join("") : `<p>${t("timing.no_laps")}</p>`}
</section>
<div class="overlay-obs-tower-meta">
<span>${escapeHtml(getSessionTypeLabel(active.type))}</span>
<span>${escapeHtml(getStartModeLabel(active.startMode))}</span>
${showStartGrid ? `<span>${t("events.start_grid")}</span>` : ""}
${!showStartGrid && obsConfig.showFastest ? `<span>${t("overlay.fastest_lap")}: ${formatLap(fastestRow?.bestLapMs)}</span>` : ""}
</div>
<section class="overlay-obs-tower-standings">
${towerRowsHtml || `<p>${t("timing.no_laps")}</p>`}
</section>
</section>
`;
}