70 lines
3.0 KiB
JavaScript
70 lines
3.0 KiB
JavaScript
import React from 'react'
|
|
import LevelBadge from '../xp/LevelBadge'
|
|
|
|
const PODIUM_STYLES = {
|
|
1: 'border-yellow-300/40 bg-[linear-gradient(180deg,rgba(250,204,21,0.18),rgba(15,23,42,0.84))]',
|
|
2: 'border-slate-300/30 bg-[linear-gradient(180deg,rgba(226,232,240,0.16),rgba(15,23,42,0.84))]',
|
|
3: 'border-amber-700/40 bg-[linear-gradient(180deg,rgba(180,83,9,0.22),rgba(15,23,42,0.84))]',
|
|
}
|
|
|
|
function cx(...parts) {
|
|
return parts.filter(Boolean).join(' ')
|
|
}
|
|
|
|
function formatScore(score) {
|
|
return new Intl.NumberFormat().format(Math.round(Number(score || 0)))
|
|
}
|
|
|
|
export default function LeaderboardItem({ item, type, highlight = false }) {
|
|
const entity = item?.entity || {}
|
|
const rank = Number(item?.rank || 0)
|
|
const tone = highlight ? PODIUM_STYLES[rank] || PODIUM_STYLES[3] : 'border-white/10 bg-white/[0.03]'
|
|
const image = entity.avatar || entity.image || null
|
|
|
|
return (
|
|
<article className={cx('rounded-3xl border p-4 shadow-lg transition', tone)}>
|
|
<div className="flex items-start gap-4">
|
|
<div className={cx('flex shrink-0 items-center justify-center rounded-2xl border font-black', highlight ? 'h-14 w-14 text-xl' : 'h-11 w-11 text-base', 'border-white/10 bg-slate-950/70 text-white')}>
|
|
#{rank}
|
|
</div>
|
|
|
|
<div className="min-w-0 flex-1">
|
|
<div className="flex items-start justify-between gap-3">
|
|
<div className="min-w-0">
|
|
<a href={entity.url || '#'} className="block text-lg font-semibold text-white hover:text-sky-300 transition">
|
|
{entity.name || 'Unknown'}
|
|
</a>
|
|
{entity.creator_name ? (
|
|
<a href={entity.creator_url || '#'} className="mt-1 block text-sm text-slate-400 hover:text-sky-300 transition">
|
|
by {entity.creator_name}
|
|
</a>
|
|
) : null}
|
|
{entity.username ? <p className="mt-1 text-sm text-slate-500">@{entity.username}</p> : null}
|
|
</div>
|
|
|
|
<div className="text-right">
|
|
<p className="text-[11px] uppercase tracking-[0.24em] text-slate-500">Score</p>
|
|
<p className="mt-1 text-2xl font-black text-white">{formatScore(item?.score)}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="mt-4 flex flex-wrap items-center gap-3">
|
|
{type === 'creator' ? <LevelBadge level={entity.level} rank={entity.rank} compact /> : null}
|
|
{type !== 'creator' && entity.creator_name ? (
|
|
<span className="rounded-full border border-white/10 bg-white/5 px-3 py-1 text-[11px] uppercase tracking-[0.14em] text-slate-300">
|
|
{type}
|
|
</span>
|
|
) : null}
|
|
</div>
|
|
</div>
|
|
|
|
{image ? (
|
|
<a href={entity.url || '#'} className={cx('block shrink-0 overflow-hidden rounded-2xl border border-white/10 bg-slate-900', type === 'creator' ? 'h-16 w-16' : 'h-20 w-24')}>
|
|
<img src={image} alt={entity.name || 'Leaderboard item'} className="h-full w-full object-cover" loading="lazy" />
|
|
</a>
|
|
) : null}
|
|
</div>
|
|
</article>
|
|
)
|
|
}
|