feat: add LMC Points column fetched from BCP league cY0LeCAPfyiG
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -73,6 +73,7 @@
|
||||
<th class="w-12">#</th>
|
||||
<th class="cursor-pointer select-none" data-sort="name">Player</th>
|
||||
<th class="text-right cursor-pointer select-none" data-sort="pts">ITC Points</th>
|
||||
<th class="text-right hidden sm:table-cell cursor-pointer select-none" data-sort="lmc">LMC Points</th>
|
||||
<th class="text-right hidden sm:table-cell cursor-pointer select-none" data-sort="wlt">W–L–T</th>
|
||||
<th class="text-right hidden sm:table-cell cursor-pointer select-none" data-sort="wpct">Win %</th>
|
||||
<th class="text-right hidden sm:table-cell cursor-pointer select-none" data-sort="rank">ITC Rank</th>
|
||||
|
||||
+43
-8
@@ -40,9 +40,10 @@ loadHTML('/footer.html', 'footer');
|
||||
CONFIG — the only block you edit
|
||||
============================================================ */
|
||||
const CONFIG = {
|
||||
teamId: "2iGDVMgX0a",
|
||||
leagueId: "BYaaUfKum7z0",
|
||||
regionId: "VgQKgqmTPU",
|
||||
teamId: "2iGDVMgX0a",
|
||||
leagueId: "BYaaUfKum7z0",
|
||||
regionId: "VgQKgqmTPU",
|
||||
lmcLeagueId: "cY0LeCAPfyiG",
|
||||
|
||||
// Fallback roster if the team endpoint requires auth.
|
||||
memberIds: [],
|
||||
@@ -156,6 +157,7 @@ const sortCols = {
|
||||
wlt: { key: r => (+r.wins||0) * 10000 - (+r.losses||0) * 100 - (+r.ties||0), defaultDir: 'desc' },
|
||||
wpct: { key: r => { const g=(+r.wins||0)+(+r.losses||0)+(+r.ties||0); return g?(+r.wins||0)/g:-1; }, defaultDir: 'desc' },
|
||||
rank: { key: r => +(r.placing || Infinity), defaultDir: 'asc' },
|
||||
lmc: { key: r => { const uid = r.userId || r.user?.id; return uid && lmcPoints[uid] != null ? lmcPoints[uid] : -Infinity; }, defaultDir: 'desc' },
|
||||
elo: { key: r => { const e = findElo(fullName(r.user || {}), r.userId || r.user?.id); return e?.elo ?? -Infinity; }, defaultDir: 'desc' },
|
||||
};
|
||||
|
||||
@@ -218,10 +220,31 @@ async function getMemberIds(force) {
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- LMC Points data ---- */
|
||||
const lmcPoints = {}; // userId → number
|
||||
let lmcLoaded = false;
|
||||
|
||||
async function loadLmcData(ids) {
|
||||
lmcLoaded = false;
|
||||
try {
|
||||
for await (const page of streamPlacings(CONFIG.lmcLeagueId)) {
|
||||
for (const rec of page) {
|
||||
const uid = rec.userId || rec.user?.id;
|
||||
if (uid && ids.has(uid)) lmcPoints[uid] = +(rec.ITCPoints || 0);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('LMC data load failed:', e);
|
||||
} finally {
|
||||
lmcLoaded = true;
|
||||
if (lastState) render(lastState);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- Standings (cursor-paginated, circular-cursor safe) ---- */
|
||||
async function* streamPlacings() {
|
||||
const base = `${API}/placings?placingsType=player&leagueId=${CONFIG.leagueId}` +
|
||||
`®ionId=${CONFIG.regionId}&sortAscending=false&limit=1000`;
|
||||
async function* streamPlacings(leagueId, regionId) {
|
||||
let base = `${API}/placings?placingsType=player&leagueId=${leagueId}&sortAscending=false&limit=1000`;
|
||||
if (regionId) base += `®ionId=${regionId}`;
|
||||
|
||||
let nextKey = null;
|
||||
let prevNextKey = undefined;
|
||||
@@ -325,8 +348,15 @@ function render(state) {
|
||||
: `<span class="block text-xs opacity-40">${fmtWpct(d.w, d.l, d.t)} career</span>`;
|
||||
const mobilePct = `<span class="block text-xs opacity-40 sm:hidden">${fmtWpct(r.wins, r.losses, r.ties)} win rate</span>`;
|
||||
const mobileElo = eloMatch ? `<span class="block text-xs opacity-40 sm:hidden">ELO ${Math.round(eloMatch.elo)}</span>` : '';
|
||||
const mobileLmc = (uid && lmcLoaded && lmcPoints[uid] != null) ? `<span class="block text-xs opacity-40 sm:hidden">LMC ${fmtPts(lmcPoints[uid])}</span>` : '';
|
||||
const lmcCell = (() => {
|
||||
if (!lmcLoaded) return `<td class="text-right font-mono hidden sm:table-cell"><span class="opacity-20">…</span></td>`;
|
||||
const pts = uid ? lmcPoints[uid] : undefined;
|
||||
return `<td class="text-right font-mono hidden sm:table-cell">${pts != null ? fmtPts(pts) : '<span class="text-base-content/40">—</span>'}</td>`;
|
||||
})();
|
||||
return `<td class="text-right font-mono font-bold">${fmtPts(r.ITCPoints)}` +
|
||||
mobilePct + mobileElo + `</td>` +
|
||||
mobilePct + mobileLmc + mobileElo + `</td>` +
|
||||
lmcCell +
|
||||
`<td class="text-right font-mono hidden sm:table-cell">` +
|
||||
`<span class="text-success">${r.wins || 0}</span>–<span class="text-error">${r.losses || 0}</span>–${r.ties || 0}` +
|
||||
careerSub + `</td>` +
|
||||
@@ -376,7 +406,11 @@ async function load(force) {
|
||||
const { ids, live } = await getMemberIds(force);
|
||||
const allRows = [];
|
||||
|
||||
for await (const page of streamPlacings()) {
|
||||
// Reset and kick off LMC fetch non-blocking
|
||||
Object.keys(lmcPoints).forEach(k => delete lmcPoints[k]);
|
||||
loadLmcData(ids);
|
||||
|
||||
for await (const page of streamPlacings(CONFIG.leagueId, CONFIG.regionId)) {
|
||||
allRows.push(...page);
|
||||
// Render incrementally so results appear as pages arrive
|
||||
const kept = build(allRows, ids);
|
||||
@@ -403,6 +437,7 @@ function showSkeleton() {
|
||||
`<td><div class="skeleton h-4 w-5"></div></td>` +
|
||||
`<td><div class="skeleton h-4 w-3/5"></div><div class="skeleton h-3 w-2/5 mt-1 sm:hidden"></div></td>` +
|
||||
`<td><div class="skeleton h-4 w-12 ml-auto"></div><div class="skeleton h-3 w-10 mt-1 ml-auto sm:hidden"></div></td>` +
|
||||
`<td class="hidden sm:table-cell"><div class="skeleton h-4 w-12 ml-auto"></div></td>` +
|
||||
`<td class="hidden sm:table-cell"><div class="skeleton h-4 w-14 ml-auto"></div></td>` +
|
||||
`<td class="hidden sm:table-cell"><div class="skeleton h-4 w-12 ml-auto"></div></td>` +
|
||||
`<td class="hidden sm:table-cell"><div class="skeleton h-4 w-10 ml-auto"></div></td>` +
|
||||
|
||||
Reference in New Issue
Block a user