add ranks
BIN
public/ranks/foil.png
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
public/ranks/glass2.png
Normal file
|
After Width: | Height: | Size: 7.2 KiB |
BIN
public/ranks/gold.png
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
BIN
public/ranks/holo.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
public/ranks/lucky.png
Normal file
|
After Width: | Height: | Size: 8.5 KiB |
BIN
public/ranks/negative.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
public/ranks/poly.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
public/ranks/steel.png
Normal file
|
After Width: | Height: | Size: 6.9 KiB |
BIN
public/ranks/stone.png
Normal file
|
After Width: | Height: | Size: 9.9 KiB |
@@ -13,9 +13,14 @@ import {
|
|||||||
} from 'react'
|
} from 'react'
|
||||||
|
|
||||||
import { Badge } from '@/components/ui/badge'
|
import { Badge } from '@/components/ui/badge'
|
||||||
import { CardContent } from '@/components/ui/card'
|
|
||||||
import { Input } from '@/components/ui/input'
|
import { Input } from '@/components/ui/input'
|
||||||
import { Label } from '@/components/ui/label'
|
import { Label } from '@/components/ui/label'
|
||||||
|
import {
|
||||||
|
Tooltip,
|
||||||
|
TooltipContent,
|
||||||
|
TooltipProvider,
|
||||||
|
TooltipTrigger,
|
||||||
|
} from '@/components/ui/mobile-tooltip'
|
||||||
import { Slider } from '@/components/ui/slider'
|
import { Slider } from '@/components/ui/slider'
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
@@ -44,11 +49,70 @@ import {
|
|||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { useRouter, useSearchParams } from 'next/navigation'
|
import { useRouter, useSearchParams } from 'next/navigation'
|
||||||
|
|
||||||
const getMedal = (rank: number) => {
|
const RANK_IMAGES = {
|
||||||
if (rank === 1) return <Medal className='h-5 w-5 text-yellow-500' />
|
foil: '/ranks/foil.png',
|
||||||
if (rank === 2) return <Medal className='h-5 w-5 text-slate-400' />
|
glass: '/ranks/glass2.png',
|
||||||
if (rank === 3) return <Medal className='h-5 w-5 text-amber-700' />
|
gold: '/ranks/gold.png',
|
||||||
return null
|
holographic: '/ranks/holo.png',
|
||||||
|
lucky: '/ranks/lucky.png',
|
||||||
|
negative: '/ranks/negative.png',
|
||||||
|
polychrome: '/ranks/poly.png',
|
||||||
|
steel: '/ranks/steel.png',
|
||||||
|
stone: '/ranks/stone.png',
|
||||||
|
}
|
||||||
|
|
||||||
|
const EDITION_THRESHOLD = {
|
||||||
|
FOIL: 50,
|
||||||
|
HOLOGRAPHIC: 10,
|
||||||
|
POLYCHROME: 3,
|
||||||
|
NEGATIVE: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
const ENHANCEMENT_THRESHOLD = {
|
||||||
|
STEEL: 320,
|
||||||
|
GOLD: 420,
|
||||||
|
LUCKY: 560,
|
||||||
|
GLASS: 880,
|
||||||
|
}
|
||||||
|
|
||||||
|
const getMedal = (rank: number, mmr: number) => {
|
||||||
|
let enhancement = RANK_IMAGES.stone
|
||||||
|
let tooltip = 'Stone'
|
||||||
|
if (mmr >= ENHANCEMENT_THRESHOLD.STEEL) {
|
||||||
|
enhancement = RANK_IMAGES.steel
|
||||||
|
tooltip = 'Steel'
|
||||||
|
}
|
||||||
|
if (mmr >= ENHANCEMENT_THRESHOLD.GOLD) {
|
||||||
|
enhancement = RANK_IMAGES.gold
|
||||||
|
tooltip = 'Gold'
|
||||||
|
}
|
||||||
|
if (mmr >= ENHANCEMENT_THRESHOLD.LUCKY) {
|
||||||
|
enhancement = RANK_IMAGES.lucky
|
||||||
|
tooltip = 'Lucky'
|
||||||
|
}
|
||||||
|
if (mmr >= ENHANCEMENT_THRESHOLD.GLASS) {
|
||||||
|
enhancement = RANK_IMAGES.glass
|
||||||
|
tooltip = 'Glass'
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TooltipProvider>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<span className='flex shrink-0 items-center justify-center gap-1.5'>
|
||||||
|
<img
|
||||||
|
src={enhancement}
|
||||||
|
alt={`Rank ${rank}`}
|
||||||
|
className='h-5 text-white'
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>
|
||||||
|
<p>{tooltip}</p>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function LeaderboardPage() {
|
export function LeaderboardPage() {
|
||||||
@@ -238,7 +302,7 @@ interface LeaderboardTableProps {
|
|||||||
sortColumn: string
|
sortColumn: string
|
||||||
sortDirection: 'asc' | 'desc'
|
sortDirection: 'asc' | 'desc'
|
||||||
onSort: (column: string) => void
|
onSort: (column: string) => void
|
||||||
getMedal: (rank: number) => React.ReactNode
|
getMedal: (rank: number, mmr: number) => React.ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
function RawLeaderboardTable({
|
function RawLeaderboardTable({
|
||||||
@@ -398,10 +462,12 @@ function RawLeaderboardTable({
|
|||||||
'transition-colors hover:bg-gray-50 dark:hover:bg-zinc-800/70'
|
'transition-colors hover:bg-gray-50 dark:hover:bg-zinc-800/70'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<TableCell className='w-24 font-medium'>
|
<TableCell className='w-28 font-medium'>
|
||||||
<div className='flex items-center justify-end gap-1.5 pr-4.5 font-mono'>
|
<div className='flex items-center justify-end gap-1.5 pr-4.5 font-mono'>
|
||||||
{getMedal(entry.rank)}
|
<span className={cn(entry.rank < 10 && 'ml-[1ch]')}>
|
||||||
<span>{entry.rank}</span>
|
{entry.rank}
|
||||||
|
</span>
|
||||||
|
{getMedal(entry.rank, entry.mmr)}
|
||||||
</div>
|
</div>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
@@ -414,8 +480,7 @@ function RawLeaderboardTable({
|
|||||||
</span>
|
</span>
|
||||||
{entry.streak >= 3 && (
|
{entry.streak >= 3 && (
|
||||||
<Badge className='bg-orange-500 text-white hover:no-underline'>
|
<Badge className='bg-orange-500 text-white hover:no-underline'>
|
||||||
Can't stop winning
|
<Flame className='h-3 w-3' />
|
||||||
<Flame className='mr-1 h-3 w-3' />
|
|
||||||
</Badge>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||