use prettier formatting

This commit is contained in:
2026-03-13 17:07:06 +01:00
parent 6a0bb9061d
commit d597c6545e
45 changed files with 1909 additions and 861 deletions

View File

@@ -33,10 +33,7 @@ export const load: PageServerLoad = async () => {
elo: r.elo,
wins: r.wins,
losses: r.losses,
winRate:
r.wins + r.losses > 0
? ((r.wins / (r.wins + r.losses)) * 100).toFixed(1)
: '—'
winRate: r.wins + r.losses > 0 ? ((r.wins / (r.wins + r.losses)) * 100).toFixed(1) : '—'
};
})
);
@@ -49,10 +46,7 @@ export const load: PageServerLoad = async () => {
wins: sql<number>`count(*)`.as('wins')
})
.from(match)
.where(and(
sql`${match.winnerId} IS NOT NULL`,
eq(match.state, 'FINISHED')
))
.where(and(sql`${match.winnerId} IS NOT NULL`, eq(match.state, 'FINISHED')))
.groupBy(match.winnerId)
.orderBy(sql`count(*) DESC`)
.limit(15);
@@ -92,10 +86,7 @@ export const load: PageServerLoad = async () => {
const recentHighScores = await db
.select()
.from(matchGameScore)
.orderBy(
sql`${matchGameScore.pp} DESC NULLS LAST`,
desc(matchGameScore.score)
)
.orderBy(sql`${matchGameScore.pp} DESC NULLS LAST`, desc(matchGameScore.score))
.limit(15)
.then((rows) =>
Promise.all(

View File

@@ -45,7 +45,7 @@
<div class="mx-auto max-w-4xl">
<div>
<h1 class="text-2xl font-700 tracking-tight">Leaderboard</h1>
<h1 class="font-700 text-2xl tracking-tight">Leaderboard</h1>
<p class="mt-1 text-sm text-text-secondary">Rankings and top performances</p>
</div>
@@ -54,7 +54,7 @@
{#each tabs as tab}
<button
onclick={() => (activeTab = tab.id)}
class="flex flex-1 items-center justify-center gap-2 rounded-md px-4 py-2 text-sm font-600 transition-colors {activeTab ===
class="font-600 flex flex-1 items-center justify-center gap-2 rounded-md px-4 py-2 text-sm transition-colors {activeTab ===
tab.id
? 'bg-accent text-surface-900'
: 'text-text-secondary hover:text-text-primary'}"
@@ -75,7 +75,7 @@
{:else}
<table class="w-full">
<thead>
<tr class="border-b border-border text-left text-xs font-600 text-text-secondary">
<tr class="font-600 border-b border-border text-left text-xs text-text-secondary">
<th class="w-10 py-3 pl-4 text-center">#</th>
<th class="w-10 py-3"></th>
<th class="py-3">Player</th>
@@ -87,25 +87,43 @@
<tbody>
{#each data.topPlayers as p}
{@const medal = rankBadge(p.rank)}
<tr class="border-b border-border/50 last:border-b-0 {p.rank <= 3 ? 'bg-accent/[0.02]' : ''}">
<td class="py-3 pl-4 text-center text-sm font-700 tabular-nums {medal?.color ?? 'text-text-secondary'}">
<tr
class="border-b border-border/50 last:border-b-0 {p.rank <= 3
? 'bg-accent/[0.02]'
: ''}"
>
<td
class="font-700 py-3 pl-4 text-center text-sm tabular-nums {medal?.color ??
'text-text-secondary'}"
>
{medal ? medal.emoji : p.rank}
</td>
<td class="py-3">
{#if p.image}
<img src={p.image} alt="" class="h-8 w-8 rounded-full" />
{:else}
<div class="flex h-8 w-8 items-center justify-center rounded-full bg-surface-600 text-xs font-700 text-text-secondary">
<div
class="font-700 flex h-8 w-8 items-center justify-center rounded-full bg-surface-600 text-xs text-text-secondary"
>
{p.name.charAt(0).toUpperCase()}
</div>
{/if}
</td>
<td class="py-3 text-sm font-600">{p.name}</td>
<td class="py-3 pr-4 text-right text-sm font-700 tabular-nums {eloColor(p.elo)}">{p.elo}</td>
<td class="py-3 pr-4 text-right text-xs tabular-nums text-text-secondary">
<span class="text-green-400">{p.wins}</span>/<span class="text-red-400">{p.losses}</span>
<td class="font-600 py-3 text-sm">{p.name}</td>
<td class="font-700 py-3 pr-4 text-right text-sm tabular-nums {eloColor(p.elo)}"
>{p.elo}</td
>
<td class="py-3 pr-4 text-right text-xs text-text-secondary tabular-nums">
<span class="text-green-400">{p.wins}</span>/<span class="text-red-400"
>{p.losses}</span
>
</td>
<td class="py-3 pr-4 text-right text-xs font-600 tabular-nums {p.winRate !== '—' && parseFloat(p.winRate) >= 50 ? 'text-green-400' : 'text-text-secondary'}">
<td
class="font-600 py-3 pr-4 text-right text-xs tabular-nums {p.winRate !== '—' &&
parseFloat(p.winRate) >= 50
? 'text-green-400'
: 'text-text-secondary'}"
>
{p.winRate}{p.winRate !== '—' ? '%' : ''}
</td>
</tr>
@@ -126,7 +144,7 @@
{:else}
<table class="w-full">
<thead>
<tr class="border-b border-border text-left text-xs font-600 text-text-secondary">
<tr class="font-600 border-b border-border text-left text-xs text-text-secondary">
<th class="w-10 py-3 pl-4 text-center">#</th>
<th class="w-10 py-3"></th>
<th class="py-3">Team</th>
@@ -137,28 +155,43 @@
<tbody>
{#each data.topTeams as t}
{@const medal = rankBadge(t.rank)}
<tr class="border-b border-border/50 last:border-b-0 {t.rank <= 3 ? 'bg-accent/[0.02]' : ''}">
<td class="py-3 pl-4 text-center text-sm font-700 tabular-nums {medal?.color ?? 'text-text-secondary'}">
<tr
class="border-b border-border/50 last:border-b-0 {t.rank <= 3
? 'bg-accent/[0.02]'
: ''}"
>
<td
class="font-700 py-3 pl-4 text-center text-sm tabular-nums {medal?.color ??
'text-text-secondary'}"
>
{medal ? medal.emoji : t.rank}
</td>
<td class="py-3">
{#if t.avatarUrl}
<img src={t.avatarUrl} alt="" class="h-8 w-8 rounded-full" />
{:else}
<div class="flex h-8 w-8 items-center justify-center rounded-full bg-surface-600 text-xs font-700 text-text-secondary">
<div
class="font-700 flex h-8 w-8 items-center justify-center rounded-full bg-surface-600 text-xs text-text-secondary"
>
{t.name.charAt(0).toUpperCase()}
</div>
{/if}
</td>
<td class="py-3">
<span class="text-sm font-600">{t.name}</span>
<span class="font-600 text-sm">{t.name}</span>
{#if t.isPersonal}
<span class="ml-1 text-[10px] text-text-secondary">(solo)</span>
{/if}
<p class="text-xs text-text-secondary">{t.memberCount} member{t.memberCount !== 1 ? 's' : ''}</p>
<p class="text-xs text-text-secondary">
{t.memberCount} member{t.memberCount !== 1 ? 's' : ''}
</p>
</td>
<td class="py-3 pr-4 text-right text-sm font-700 tabular-nums text-green-400">{t.wins}</td>
<td class="py-3 pr-4 text-right text-xs tabular-nums text-text-secondary">{t.totalMatches}</td>
<td class="font-700 py-3 pr-4 text-right text-sm text-green-400 tabular-nums"
>{t.wins}</td
>
<td class="py-3 pr-4 text-right text-xs text-text-secondary tabular-nums"
>{t.totalMatches}</td
>
</tr>
{/each}
</tbody>
@@ -175,12 +208,14 @@
<p class="text-sm text-text-secondary">No scores recorded yet.</p>
</div>
{:else}
<div class="px-4 py-2.5 border-b border-border">
<p class="text-xs text-text-secondary">Ranked by pp (performance points) when available, then score</p>
<div class="border-b border-border px-4 py-2.5">
<p class="text-xs text-text-secondary">
Ranked by pp (performance points) when available, then score
</p>
</div>
<table class="w-full">
<thead>
<tr class="border-b border-border text-left text-xs font-600 text-text-secondary">
<tr class="font-600 border-b border-border text-left text-xs text-text-secondary">
<th class="w-10 py-3 pl-4 text-center">#</th>
<th class="w-10 py-3"></th>
<th class="py-3">Player</th>
@@ -193,35 +228,51 @@
<tbody>
{#each data.highScores as s}
{@const medal = rankBadge(s.rank)}
<tr class="border-b border-border/50 last:border-b-0 {s.rank <= 3 ? 'bg-accent/[0.02]' : ''}">
<td class="py-3 pl-4 text-center text-sm font-700 tabular-nums {medal?.color ?? 'text-text-secondary'}">
<tr
class="border-b border-border/50 last:border-b-0 {s.rank <= 3
? 'bg-accent/[0.02]'
: ''}"
>
<td
class="font-700 py-3 pl-4 text-center text-sm tabular-nums {medal?.color ??
'text-text-secondary'}"
>
{medal ? medal.emoji : s.rank}
</td>
<td class="py-3">
{#if s.playerImage}
<img src={s.playerImage} alt="" class="h-8 w-8 rounded-full" />
{:else}
<div class="flex h-8 w-8 items-center justify-center rounded-full bg-surface-600 text-xs font-700 text-text-secondary">
<div
class="font-700 flex h-8 w-8 items-center justify-center rounded-full bg-surface-600 text-xs text-text-secondary"
>
{s.playerName.charAt(0).toUpperCase()}
</div>
{/if}
</td>
<td class="py-3">
<span class="text-sm font-600">{s.playerName}</span>
<span class="font-600 text-sm">{s.playerName}</span>
<p class="truncate text-xs text-text-secondary">
<a href="/matches/{s.matchId}" class="hover:text-accent">{s.matchName}</a>
</p>
</td>
<td class="py-3 pr-4 text-right text-xs font-600 {catColors[s.mapCategory] ?? 'text-text-secondary'}">
<td
class="font-600 py-3 pr-4 text-right text-xs {catColors[s.mapCategory] ??
'text-text-secondary'}"
>
{s.mapCategory}{s.mapOrder}
</td>
<td class="py-3 pr-4 text-right text-sm font-700 tabular-nums {s.pp != null ? 'text-accent' : 'text-text-secondary/40'}">
<td
class="font-700 py-3 pr-4 text-right text-sm tabular-nums {s.pp != null
? 'text-accent'
: 'text-text-secondary/40'}"
>
{s.pp != null ? `${Math.round(s.pp)}pp` : '—'}
</td>
<td class="py-3 pr-4 text-right text-sm font-700 tabular-nums text-text-primary">
<td class="font-700 py-3 pr-4 text-right text-sm text-text-primary tabular-nums">
{s.score.toLocaleString()}
</td>
<td class="py-3 pr-4 text-right text-xs tabular-nums text-text-secondary">
<td class="py-3 pr-4 text-right text-xs text-text-secondary tabular-nums">
{s.accuracy > 0 ? `${(s.accuracy * 100).toFixed(1)}%` : '—'}
</td>
</tr>
@@ -234,13 +285,12 @@
<!-- ELO Explanation -->
<div class="mt-6 rounded-lg border border-border bg-surface-800 p-5">
<h2 class="text-sm font-600">How ELO Works</h2>
<p class="mt-2 text-xs text-text-secondary leading-relaxed">
Your initial rating is seeded from your osu! global rank. Winning gains ELO and
losing drops it, but the amount depends on your opponent's rating — beating a
stronger player earns more points. New players' ratings shift faster to help
find your true skill level quickly. Queue matchmaking pairs players with similar
ELO for fair matches.
<h2 class="font-600 text-sm">How ELO Works</h2>
<p class="mt-2 text-xs leading-relaxed text-text-secondary">
Your initial rating is seeded from your osu! global rank. Winning gains ELO and losing drops
it, but the amount depends on your opponent's rating — beating a stronger player earns more
points. New players' ratings shift faster to help find your true skill level quickly. Queue
matchmaking pairs players with similar ELO for fair matches.
</p>
</div>
</div>