${tabs.map((tab) => {
const isActive = active === tab.key;
// "All" gets a full row on mobile (basis-full) and normal sizing on
// sm+. The others use basis-20 so longer labels stay comfortable and
// flex-wrap drops them to a second line when needed.
const basis =
tab.key === "all" ? "basis-full sm:basis-20" : "basis-20";
return html`
`;
})}
`;
}
// Group consecutive games by their start day. Cached against the `games`
// reference; `load()` always assigns a fresh array, so identity comparison
// is safe.
if (this.groupedFor !== this.games) {
this.grouped = groupByDay(this.games);
this.groupedFor = this.games;
}
const groups = this.grouped;
return html`
`;
}
// Sentinel drives auto-load; the spinner sits adjacent to it (not *as* it)
// so the sentinel node identity stays stable across pages — otherwise every
// fetch tears down and recreates the IntersectionObserver.
return html`
${this.loadingMore ? renderLoadingSpinner() : ""}
`;
}
private renderGameRow(game: PublicPlayerGame): TemplateResult {
// getMapData() throws for unknown map values — guard so an unmapped server
// response doesn't tank the whole history view.
let mapWebpPath: string | null = null;
if (game.map) {
try {
mapWebpPath = terrainMapFileLoader.getMapData(
game.map as GameMapType,
).webpPath;
} catch {
mapWebpPath = null;
}
}
const mapDisplayName = game.map ? (getMapName(game.map) ?? game.map) : null;
return html`
`;
}
// The player's own outcome. "incomplete" (no recorded winner) gets a neutral
// badge rather than collapsing into Defeat, so an unfinished game isn't
// mislabelled as a loss in a personal history.
private renderResultBadge(game: PublicPlayerGame): TemplateResult {
let label: string;
let tint: string;
if (game.result === "victory") {
label = translateText("clan_modal.history_result_victory");
tint = "text-white bg-green-600 border-green-500";
} else if (game.result === "defeat") {
label = translateText("clan_modal.history_result_defeat");
tint = "text-white bg-red-600 border-red-500";
} else {
label = translateText("account_modal.games_result_incomplete");
tint = "text-white bg-gray-500 border-gray-400";
}
return html`${label}`;
}
}