diff --git a/src/client/components/leaderboard/LeaderboardClanTable.ts b/src/client/components/leaderboard/LeaderboardClanTable.ts index dd78a8bd6..da2664c89 100644 --- a/src/client/components/leaderboard/LeaderboardClanTable.ts +++ b/src/client/components/leaderboard/LeaderboardClanTable.ts @@ -195,189 +195,208 @@ export class LeaderboardClanTable extends LitElement { const maxGames = Math.max(...clans.map((c) => c.games), 1); return html` -
-
- - - - - - + + + + + `; + })} + +
- ${translateText("leaderboard_modal.rank")} - - ${translateText("leaderboard_modal.clan")} - +
+
+ + + + + + + + + + + - + + - + - + - + - - - - ${sorted.map((clan, index) => { - const displayRank = index + 1; - const rankColor = - displayRank === 1 - ? "text-yellow-400 bg-yellow-400/10 ring-1 ring-yellow-400/20" - : displayRank === 2 - ? "text-slate-300 bg-slate-400/10 ring-1 ring-slate-400/20" - : displayRank === 3 - ? "text-amber-600 bg-amber-600/10 ring-1 ring-amber-600/20" - : "text-white/40 bg-white/5"; - const rankIcon = - displayRank === 1 - ? "👑" - : displayRank === 2 - ? "🥈" - : displayRank === 3 - ? "🥉" - : String(displayRank); + + + + + + ${sorted.map((clan, index) => { + const displayRank = index + 1; + const rankColor = + displayRank === 1 + ? "text-yellow-400 bg-yellow-400/10 ring-1 ring-yellow-400/20" + : displayRank === 2 + ? "text-slate-300 bg-slate-400/10 ring-1 ring-slate-400/20" + : displayRank === 3 + ? "text-amber-600 bg-amber-600/10 ring-1 ring-amber-600/20" + : "text-white/40 bg-white/5"; + const rankIcon = + displayRank === 1 + ? "👑" + : displayRank === 2 + ? "🥈" + : displayRank === 3 + ? "🥉" + : String(displayRank); - return html` - - - - + - - - - - `; - })} - -
+ ${translateText("leaderboard_modal.rank")} + + ${translateText("leaderboard_modal.clan")} + - ${translateText("leaderboard_modal.games")} - ${this.sortBy === "games" - ? this.sortOrder === "asc" - ? "↑" - : "↓" - : "↕"} - - - ${translateText("leaderboard_modal.win_score")} - ${this.sortBy === "winScore" - ? this.sortOrder === "asc" - ? "↑" - : "↓" - : "↕"} - - - ${translateText("leaderboard_modal.loss_score")} - ${this.sortBy === "lossScore" - ? this.sortOrder === "asc" - ? "↑" - : "↓" - : "↕"} - - - + - ${translateText("leaderboard_modal.win_loss_ratio")} - ${this.sortBy === "ratio" - ? this.sortOrder === "asc" - ? "↑" - : "↓" - : "↕"} - -
-
- ${rankIcon} -
-
-
- ${clan.clanTag} -
-
-
- ${clan.games.toLocaleString()} + return html` +
-
+ ${rankIcon}
- -
-
- ${clan.weightedWLRatio.toLocaleString("fullwide", { - maximumFractionDigits: 2, - })} +
+
- ${translateText("leaderboard_modal.ratio")} -
-
+ ${clan.clanTag} +
+ +
+
+ ${clan.games.toLocaleString()} +
+
+
+
+
+ ${clan.weightedWins.toLocaleString(undefined, { + maximumFractionDigits: 1, + })} + + ${clan.weightedLosses.toLocaleString(undefined, { + maximumFractionDigits: 1, + })} + +
+ ${clan.weightedWLRatio.toLocaleString(undefined, { + maximumFractionDigits: 2, + })} + ${translateText("leaderboard_modal.ratio")} +
+
+
`; diff --git a/src/client/components/leaderboard/LeaderboardPlayerList.ts b/src/client/components/leaderboard/LeaderboardPlayerList.ts index 04beae8ea..fcee8f73c 100644 --- a/src/client/components/leaderboard/LeaderboardPlayerList.ts +++ b/src/client/components/leaderboard/LeaderboardPlayerList.ts @@ -1,5 +1,4 @@ -import { virtualize } from "@lit-labs/virtualizer/virtualize.js"; -import { html, LitElement } from "lit"; +import { html, LitElement, nothing } from "lit"; import { customElement, query, state } from "lit/decorators.js"; import { PlayerLeaderboardEntry } from "../../../core/ApiSchemas"; import { RankedType } from "../../../core/game/Game"; @@ -23,7 +22,7 @@ export class LeaderboardPlayerList extends LitElement { private currentUserId: string | null = null; private currentUserIdLoaded = false; - @query(".virtualizer-container") private virtualizerContainer?: HTMLElement; + @query(".scroll-container") private scrollContainer?: HTMLElement; createRenderRoot() { return this; @@ -152,12 +151,12 @@ export class LeaderboardPlayerList extends LitElement { return; } - if (!this.virtualizerContainer || !this.isVisible()) { + if (!this.scrollContainer || !this.isVisible()) { this.showStickyUser = false; return; } - const currentRow = this.virtualizerContainer.querySelector( + const currentRow = this.scrollContainer.querySelector( '[data-current-user="true"]', ) as HTMLElement | null; @@ -166,7 +165,7 @@ export class LeaderboardPlayerList extends LitElement { return; } - const containerRect = this.virtualizerContainer.getBoundingClientRect(); + const containerRect = this.scrollContainer.getBoundingClientRect(); const rowRect = currentRow.getBoundingClientRect(); const isVisible = rowRect.top >= containerRect.top && @@ -188,12 +187,12 @@ export class LeaderboardPlayerList extends LitElement { private maybeLoadMorePlayers() { if (this.isLoading || this.isLoadingMore) return; if (!this.playerHasMore || this.error || this.loadMoreError) return; - if (!this.virtualizerContainer || !this.isVisible()) return; + if (!this.scrollContainer || !this.isVisible()) return; const threshold = 64 * 3; - const scrollTop = this.virtualizerContainer.scrollTop; - const containerHeight = this.virtualizerContainer.clientHeight; - const scrollHeight = this.virtualizerContainer.scrollHeight; + const scrollTop = this.scrollContainer.scrollTop; + const containerHeight = this.scrollContainer.clientHeight; + const scrollHeight = this.scrollContainer.scrollHeight; const nearBottom = scrollTop + containerHeight >= scrollHeight - threshold; if (containerHeight === 0 || scrollHeight === 0) return; // guard @@ -211,7 +210,6 @@ export class LeaderboardPlayerList extends LitElement { private renderPlayerRow(player: PlayerLeaderboardEntry) { const isCurrentUser = this.currentUserEntry?.playerId === player.playerId; const displayRank = player.rank; - const winRate = player.games > 0 ? player.wins / player.games : 0; const rankColor = { @@ -228,60 +226,56 @@ export class LeaderboardPlayerList extends LitElement { }?.[displayRank] ?? String(displayRank); return html` -
-
+
${rankIcon}
-
-
- ${player.username} - ${player.clanTag - ? html`
- ${player.clanTag} -
` - : ""} -
-
-
- ${player.elo} - ${translateText("leaderboard_modal.elo")} + +
+ ${player.clanTag + ? html`
+ ${player.clanTag} +
` + : ""} + ${player.clanTag + ? player.username.replace(/^\[.*?\]\s*/, "") + : player.username}
-
- + + `; } @@ -372,52 +366,61 @@ export class LeaderboardPlayerList extends LitElement { if (this.error) return this.renderError(); return html` -
-
-
- ${translateText("leaderboard_modal.rank")} -
-
- ${translateText("leaderboard_modal.player")} -
-
- ${translateText("leaderboard_modal.elo")} -
- -
- ${translateText("leaderboard_modal.win_loss_ratio")} -
-
-
+
+
this.handleScroll()} > - ${virtualize({ - items: this.playerData, - renderItem: (player) => this.renderPlayerRow(player), - scroller: true, - })} + + + + + + + + + + + + + + + + + + + ${this.playerData.map((player) => this.renderPlayerRow(player))} + +
+ ${translateText("leaderboard_modal.rank")} + + ${translateText("leaderboard_modal.player")} + + ${translateText("leaderboard_modal.elo")} + + ${translateText("leaderboard_modal.games")} + + ${translateText("leaderboard_modal.win_loss_ratio")} +
${this.renderPlayerFooter()}
${this.currentUserEntry ? html` -
+
-
+
@@ -432,10 +435,15 @@ export class LeaderboardPlayerList extends LitElement { )} ${this.currentUserEntry.username}${this.currentUserEntry.clanTag + ? this.currentUserEntry.username.replace( + /^\[.*?\]\s*/, + "", + ) + : this.currentUserEntry.username}
-
+
${this.currentUserEntry.elo}