From 7e13ecd4acea27f211fad8396a9d997bc07fb922 Mon Sep 17 00:00:00 2001 From: larssand Date: Sun, 15 Mar 2026 13:20:57 +0100 Subject: [PATCH] Polish timing layout and add TV overlay --- src/app.js | 144 ++++++++++++++++++++++++++++++++++--------------- src/styles.css | 89 ++++++++++++++++++++++++++++++ 2 files changed, 190 insertions(+), 43 deletions(-) diff --git a/src/app.js b/src/app.js index 59e7170..542e495 100644 --- a/src/app.js +++ b/src/app.js @@ -265,6 +265,7 @@ const TRANSLATIONS = { "timing.open_overlay": "Öppna overlay", "timing.open_speaker_overlay": "Speaker overlay", "timing.open_results_overlay": "Result overlay", + "timing.open_tv_overlay": "TV overlay", "timing.close_details": "Stang", "timing.detail_title": "Leaderboard-detaljer", "timing.lap_history": "Varvhistorik", @@ -459,6 +460,7 @@ const TRANSLATIONS = { "overlay.mode_leaderboard": "Leaderboard", "overlay.mode_speaker": "Speaker", "overlay.mode_results": "Resultat", + "overlay.mode_tv": "TV", "overlay.fastest_lap": "Snabbaste varv", "overlay.fullscreen": "Fullscreen", "overlay.leaderboard_live": "Live leaderboard", @@ -747,6 +749,7 @@ const TRANSLATIONS = { "timing.open_overlay": "Open overlay", "timing.open_speaker_overlay": "Speaker overlay", "timing.open_results_overlay": "Results overlay", + "timing.open_tv_overlay": "TV overlay", "timing.close_details": "Close", "timing.detail_title": "Leaderboard details", "timing.lap_history": "Lap history", @@ -941,6 +944,7 @@ const TRANSLATIONS = { "overlay.mode_leaderboard": "Leaderboard", "overlay.mode_speaker": "Speaker", "overlay.mode_results": "Results", + "overlay.mode_tv": "TV", "overlay.fastest_lap": "Fastest Lap", "overlay.fullscreen": "Fullscreen", "overlay.leaderboard_live": "Live leaderboard", @@ -984,7 +988,7 @@ const TRANSLATIONS = { const urlParams = new URLSearchParams(window.location.search); const overlayMode = urlParams.get("view") === "overlay"; -const overlayViewMode = ["leaderboard", "speaker", "results"].includes(String(urlParams.get("overlayMode") || "").toLowerCase()) +const overlayViewMode = ["leaderboard", "speaker", "results", "tv"].includes(String(urlParams.get("overlayMode") || "").toLowerCase()) ? String(urlParams.get("overlayMode")).toLowerCase() : "leaderboard"; const state = loadState(); @@ -3556,52 +3560,73 @@ function renderTiming() { dom.view.innerHTML = `

${t("timing.decoder_connection")}

-
- - - - -
-
-

${t("timing.status")}: ${state.decoder.connected ? t("timing.connected") : t("timing.disconnected")}

-

${t("timing.last_message")}: ${state.decoder.lastMessageAt ? new Date(state.decoder.lastMessageAt).toLocaleString() : "-"}

-

${escapeHtml(state.decoder.lastError || "")}

+
+
+ + +
+ + + +
+
+
+ ${t("timing.status")} + ${state.decoder.connected ? t("timing.connected") : t("timing.disconnected")} + ${t("timing.last_message")}: ${state.decoder.lastMessageAt ? new Date(state.decoder.lastMessageAt).toLocaleString() : "-"} +

${escapeHtml(state.decoder.lastError || "")}

+

${t("timing.control")}

-
- - - - - - - - +
+
+ + +
+ + + + +
+
+
+ ${t("overlay.title")} +
+ + + + +
+
-
+
${ active - ? `

${escapeHtml(active.name)} (${escapeHtml(getSessionTypeLabel(active.type))}) • ${escapeHtml( - getEventName(active.eventId) - )}

-

${t("timing.status")}: ${escapeHtml(getStatusLabel(active.status))} • ${t("timing.started")}: ${active.startedAt ? new Date(active.startedAt).toLocaleTimeString() : "-"}

-

${t("table.start_mode")}: ${escapeHtml(getStartModeLabel(active.startMode))} • ${t("timing.seeding_mode")}: ${ - active.seedBestLapCount > 0 ? `${active.seedBestLapCount}` : "-" - }

-

${clockLabel}: ${clockValue}

-

${t("timing.total_passings")}: ${result.passings.length}

+ ? `
+ ${escapeHtml(active.name)} + ${escapeHtml(getSessionTypeLabel(active.type))} + ${escapeHtml(getEventName(active.eventId))} + ${escapeHtml(getStatusLabel(active.status))} +
+
+
${clockLabel}${clockValue}
+
${t("timing.started")}${active.startedAt ? new Date(active.startedAt).toLocaleTimeString() : "-"}
+
${t("table.start_mode")}${escapeHtml(getStartModeLabel(active.startMode))}
+
${t("timing.seeding_mode")}${active.seedBestLapCount > 0 ? `${active.seedBestLapCount}` : "-"}
+
${t("timing.total_passings")}${result.passings.length}
+
${ active.type === "free_practice" ? `

${t("events.free_practice_note")}

` @@ -3822,6 +3847,7 @@ function renderTiming() { document.getElementById("openOverlay")?.addEventListener("click", openOverlayWindow); document.getElementById("openSpeakerOverlay")?.addEventListener("click", () => openOverlayWindow("speaker")); document.getElementById("openResultsOverlay")?.addEventListener("click", () => openOverlayWindow("results")); + document.getElementById("openTvOverlay")?.addEventListener("click", () => openOverlayWindow("tv")); document.querySelectorAll("[data-speaker-setting]").forEach((node) => { node.addEventListener("change", (event) => { const input = event.currentTarget; @@ -4123,6 +4149,38 @@ function renderOverlay() {
` + : overlayViewMode === "tv" + ? ` +
+
+
+
+ ${t("overlay.fastest_lap")} + ${formatLap(fastestRow?.bestLapMs)} +
+
${escapeHtml(fastestRow?.driverName || "-")}
+
+
+
+ ${t("table.laps")} + ${topRow?.laps || 0} + ${escapeHtml(topRow?.driverName || "-")} +
+
+ ${t("timing.total_passings")} + ${result?.passings.length || 0} + ${sessionTiming?.untimed ? t("timing.elapsed") : t("timing.remaining")} +
+
+
+
+

${t("overlay.leaderboard_live")}

+
+ ${renderOverlayLeaderboard(leaderboard)} +
+
+
+ ` : `
@@ -4471,7 +4529,7 @@ function renderSettings() { dom.view.innerHTML = `

${t("settings.decoder")}

-
+

${t("settings.audio")}

-
+