mirror of
https://github.com/AmanTahiliani/box-box.git
synced 2026-08-07 19:56:18 -04:00
UI Updates and Web App
This commit is contained in:
@@ -600,9 +600,44 @@ function livePage() {
|
||||
},
|
||||
|
||||
get sortedDrivers() {
|
||||
return Object.values(this.drivers)
|
||||
.filter(d => d.Position > 0)
|
||||
.sort((a, b) => a.Position - b.Position);
|
||||
const merged = {};
|
||||
for (const num of Object.keys(this.drivers)) {
|
||||
merged[num] = { ...this.drivers[num] };
|
||||
}
|
||||
for (const num of Object.keys(this.driverInfo)) {
|
||||
if (!merged[num]) {
|
||||
merged[num] = { RacingNumber: num, Position: 0 };
|
||||
}
|
||||
}
|
||||
|
||||
const all = Object.values(merged);
|
||||
|
||||
all.sort((a, b) => {
|
||||
const pi = a.Position || 0;
|
||||
const pj = b.Position || 0;
|
||||
|
||||
if (pi > 0 && pj > 0) return pi - pj;
|
||||
if (pi > 0) return -1;
|
||||
if (pj > 0) return 1;
|
||||
|
||||
const ti = a.BestLapTime || '';
|
||||
const tj = b.BestLapTime || '';
|
||||
if (ti && tj) return ti.localeCompare(tj);
|
||||
if (ti) return -1;
|
||||
if (tj) return 1;
|
||||
|
||||
const ni = parseInt(a.RacingNumber) || 0;
|
||||
const nj = parseInt(b.RacingNumber) || 0;
|
||||
return ni - nj;
|
||||
});
|
||||
|
||||
all.forEach((d, i) => {
|
||||
if (!d.Position) {
|
||||
d.Position = i + 1;
|
||||
}
|
||||
});
|
||||
|
||||
return all;
|
||||
},
|
||||
|
||||
driverTla(num) {
|
||||
|
||||
@@ -142,29 +142,31 @@
|
||||
<div class="skeleton" style="height:36px;margin-bottom:4px;"></div>
|
||||
</template>
|
||||
</div>
|
||||
<table class="data-table" x-show="!resultsLoading && results.length">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>POS</th><th>DRIVER</th><th>TEAM</th><th>TIME / GAP</th><th>PTS</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template x-for="r in results" :key="r.driver_number">
|
||||
<tr :style="`--team-color:#${r.team_colour}`">
|
||||
<td class="pos-cell">
|
||||
<span x-text="r.position||'-'"></span>
|
||||
<span x-show="r.dnf" class="badge dnf">DNF</span>
|
||||
<span x-show="r.dns" class="badge dns">DNS</span>
|
||||
<span x-show="r.dsq" class="badge dsq">DSQ</span>
|
||||
</td>
|
||||
<td><span class="team-swatch"></span><span x-text="r.full_name||r.driver_number"></span></td>
|
||||
<td x-text="r.team_name||'-'"></td>
|
||||
<td x-text="fmtDuration(r.duration)"></td>
|
||||
<td x-text="r.points||0"></td>
|
||||
<div class="table-scroll" x-show="!resultsLoading && results.length">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>POS</th><th>DRIVER</th><th>TEAM</th><th>TIME / GAP</th><th>PTS</th>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template x-for="r in results" :key="r.driver_number">
|
||||
<tr :style="`--team-color:#${r.team_colour}`">
|
||||
<td class="pos-cell">
|
||||
<span x-text="r.position||'-'"></span>
|
||||
<span x-show="r.dnf" class="badge dnf">DNF</span>
|
||||
<span x-show="r.dns" class="badge dns">DNS</span>
|
||||
<span x-show="r.dsq" class="badge dsq">DSQ</span>
|
||||
</td>
|
||||
<td><span class="team-swatch"></span><span x-text="r.full_name||r.driver_number"></span></td>
|
||||
<td x-text="r.team_name||'-'"></td>
|
||||
<td x-text="fmtDuration(r.duration)"></td>
|
||||
<td x-text="r.points||0"></td>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div x-show="!resultsLoading && !results.length" class="empty-msg">No results available.</div>
|
||||
</div>
|
||||
|
||||
@@ -243,31 +245,36 @@
|
||||
<span class="clock" x-text="clockDisplay"></span>
|
||||
</div>
|
||||
|
||||
<table class="timing-tower">
|
||||
<thead>
|
||||
<tr><th>POS</th><th>Δ</th><th>DRIVER</th><th>TYRE</th><th>LAST LAP</th><th>GAP</th><th>BEST</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template x-for="d in sortedDrivers" :key="d.RacingNumber">
|
||||
<tr :class="{in-pit: d.InPit, retired: d.Retired, pit-out: d.PitOut}"
|
||||
:style="`--team-color:#${driverTeamColor(d.RacingNumber)}`">
|
||||
<td class="pos-cell" x-text="d.Position"></td>
|
||||
<td class="pos-delta" x-text="posDelta(d)"></td>
|
||||
<td><span class="team-swatch"></span><span x-text="driverTla(d.RacingNumber)"></span>
|
||||
<span x-show="d.InPit" class="badge pit">PIT</span>
|
||||
<span x-show="d.Retired" class="badge out">OUT</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="tyre-badge" :class="tyreClass(d.RacingNumber)"
|
||||
x-text="tyreLabel(d.RacingNumber)"></span>
|
||||
</td>
|
||||
<td :class="{pb: d.LastLapPB, ob: d.LastLapOB}" x-text="d.LastLapTime||'-'"></td>
|
||||
<td x-text="d.GapToLeader||'-'"></td>
|
||||
<td :class="{ob: d.BestLapOB}" x-text="d.BestLapTime||'-'"></td>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="table-scroll">
|
||||
<table class="timing-tower">
|
||||
<thead>
|
||||
<tr><th>POS</th><th>Δ</th><th>DRIVER</th><th>TYRE</th><th>LAST LAP</th><th>GAP</th><th>BEST</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template x-for="d in sortedDrivers" :key="d.RacingNumber">
|
||||
<tr :class="{in-pit: d.InPit, retired: d.Retired, pit-out: d.PitOut}"
|
||||
:style="`--team-color:#${driverTeamColor(d.RacingNumber)}`">
|
||||
<td class="pos-cell" x-text="d.Position"></td>
|
||||
<td class="pos-delta" x-text="posDelta(d)"></td>
|
||||
<td>
|
||||
<div class="driver-cell">
|
||||
<span class="team-swatch"></span><span x-text="driverTla(d.RacingNumber)"></span>
|
||||
<span x-show="d.InPit" class="badge pit">PIT</span>
|
||||
<span x-show="d.Retired" class="badge out">OUT</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span class="tyre-badge" :class="tyreClass(d.RacingNumber)"
|
||||
x-text="tyreLabel(d.RacingNumber)"></span>
|
||||
</td>
|
||||
<td :class="{pb: d.LastLapPB, ob: d.LastLapOB}" x-text="d.LastLapTime||'-'"></td>
|
||||
<td x-text="d.GapToLeader||'-'"></td>
|
||||
<td :class="{ob: d.BestLapOB}" x-text="d.BestLapTime||'-'"></td>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Race control messages -->
|
||||
<div class="rc-panel" x-show="rcMessages.length">
|
||||
|
||||
@@ -566,8 +566,9 @@ a { color: inherit; text-decoration: none; }
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
.timing-tower {
|
||||
width: calc(100% - 3rem);
|
||||
margin: 0 1.5rem 1.5rem;
|
||||
width: 100%;
|
||||
max-width: 1100px;
|
||||
margin: 0 auto 1.5rem;
|
||||
border-collapse: collapse;
|
||||
font-size: 0.85rem;
|
||||
font-variant-numeric: tabular-nums;
|
||||
@@ -585,7 +586,7 @@ a { color: inherit; text-decoration: none; }
|
||||
}
|
||||
.timing-tower td {
|
||||
border-bottom: 1px solid var(--surface-3);
|
||||
padding: 0.45rem 0.75rem;
|
||||
padding: 0.35rem 0.6rem;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.timing-tower .in-pit td { background: rgba(0,51,102,0.25); }
|
||||
@@ -682,6 +683,7 @@ a { color: inherit; text-decoration: none; }
|
||||
#laps-chart,
|
||||
#telemetry-chart,
|
||||
#track-chart {
|
||||
overflow-x: auto;
|
||||
padding: 0 1.5rem 1.5rem;
|
||||
}
|
||||
#strategy-chart svg,
|
||||
@@ -879,3 +881,79 @@ a { color: inherit; text-decoration: none; }
|
||||
grid-template-columns: 44px 1fr 80px 55px 55px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- Scrollable table wrapper ---- */
|
||||
.table-scroll {
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
margin: 0 1.5rem 1.5rem;
|
||||
}
|
||||
.table-scroll .data-table,
|
||||
.table-scroll .timing-tower {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Mobile responsive overrides (≤ 640px)
|
||||
============================================================ */
|
||||
@media (max-width: 640px) {
|
||||
/* Reduce global horizontal padding */
|
||||
.home-hero { padding: 0.75rem; }
|
||||
.meetings-grid { padding: 0 0.75rem 1.5rem; }
|
||||
.section-label { padding: 0.75rem 0.75rem 0.5rem; }
|
||||
.page-header { padding: 0.75rem 0.75rem 0.5rem; flex-wrap: wrap; gap: 0.5rem; }
|
||||
.year-selector { margin-left: 0; }
|
||||
.session-pills { padding: 0.5rem 0.75rem; }
|
||||
.driver-selector { padding: 0.5rem 0.75rem 0.75rem; }
|
||||
.table-scroll { margin: 0 0.75rem 1.5rem; }
|
||||
.rc-panel { margin: 0 0.75rem 1.5rem; }
|
||||
.standings-table { padding: 0 0.75rem 1.5rem; }
|
||||
.skeleton-wrap { padding: 0.75rem; }
|
||||
.empty-msg { padding: 2rem 0.75rem; }
|
||||
|
||||
/* Charts */
|
||||
#strategy-chart,
|
||||
#laps-chart,
|
||||
#telemetry-chart,
|
||||
#track-chart { padding: 0 0.75rem 1.5rem; }
|
||||
|
||||
/* Nav */
|
||||
.nav { gap: 0.75rem; padding: 0.6rem 0.75rem; }
|
||||
|
||||
/* Tabs — allow horizontal scroll so all tabs are reachable */
|
||||
.tabs { overflow-x: auto; padding: 0 0.75rem; scrollbar-width: none; }
|
||||
.tabs::-webkit-scrollbar { display: none; }
|
||||
.tab { padding: 0.6rem 0.75rem; font-size: 0.78rem; white-space: nowrap; }
|
||||
|
||||
/* Stale banner */
|
||||
.stale-banner { padding: 0.5rem 0.75rem; flex-wrap: wrap; }
|
||||
|
||||
/* Live timing meta row */
|
||||
.live-meta { gap: 0.5rem; padding: 0.5rem 0.75rem; flex-wrap: wrap; }
|
||||
.clock { margin-left: 0; }
|
||||
|
||||
/* Tighten table cell padding */
|
||||
.data-table th,
|
||||
.data-table td { padding: 0.6rem 0.6rem; }
|
||||
.timing-tower th,
|
||||
.timing-tower td { padding: 0.4rem 0.5rem; }
|
||||
|
||||
/* Hide TEAM column in race results table */
|
||||
.data-table th:nth-child(3),
|
||||
.data-table td:nth-child(3) { display: none; }
|
||||
|
||||
/* Hide BEST LAP column in timing tower */
|
||||
.timing-tower th:nth-child(7),
|
||||
.timing-tower td:nth-child(7) { display: none; }
|
||||
|
||||
/* Scale down hero text */
|
||||
.next-race-name { font-size: 1.35rem; }
|
||||
.next-race-countdown { font-size: 1.6rem; }
|
||||
}
|
||||
|
||||
@media (max-width: 420px) {
|
||||
/* Hide position delta column on very small phones to save space */
|
||||
.timing-tower th:nth-child(2),
|
||||
.timing-tower td:nth-child(2) { display: none; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user