modda layoten för obs overlay
This commit is contained in:
187
src/app.js
187
src/app.js
@@ -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>
|
||||
`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user