use prettier formatting
This commit is contained in:
@@ -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(
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user