Merge pull request #280 from blockworks-foundation/leaderboard-tweaks

leaderboard: more responsive/consistent layout
This commit is contained in:
tjshipe 2022-05-18 16:33:02 -04:00 committed by GitHub
commit b7f095ebc6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 80 additions and 172 deletions

View File

@ -1,10 +1,13 @@
import { useEffect, useMemo, useState } from 'react'
import dayjs from 'dayjs'
import { Table, Td, Th, TrBody, TrHead } from './TableElements'
import { usdFormatter } from '../utils'
import { AwardIcon, MedalIcon, ProfileIcon, TrophyIcon } from './icons'
import { MedalIcon, ProfileIcon } from './icons'
import { useTranslation } from 'next-i18next'
import { ChartPieIcon, TrendingUpIcon } from '@heroicons/react/outline'
import {
ChartPieIcon,
ExternalLinkIcon,
TrendingUpIcon,
} from '@heroicons/react/outline'
import { getProfilePicture } from '@solflare-wallet/pfp'
import useMangoStore from '../stores/useMangoStore'
import { connectionSelector } from '../stores/selectors'
@ -13,7 +16,6 @@ const utc = require('dayjs/plugin/utc')
dayjs.extend(utc)
const LeaderboardTable = ({ range = '29' }) => {
const { t } = useTranslation('common')
const [pnlLeaderboardData, setPnlLeaderboardData] = useState<any[]>([])
const [perpPnlLeaderboardData, setPerpPnlLeaderboardData] = useState<any[]>(
[]
@ -87,164 +89,67 @@ const LeaderboardTable = ({ range = '29' }) => {
return (
<div className="grid grid-cols-12 gap-6">
<div className="col-span-12 flex space-x-3 lg:col-span-4 lg:flex-col lg:space-y-4 lg:space-x-0">
<div className="col-span-12 flex space-x-3 lg:col-span-4 lg:flex-col lg:space-y-2 lg:space-x-0">
<LeaderboardTypeButton
leaderboardType={leaderboardType}
setLeaderboardType={setLeaderboardType}
range={range}
label="total-pnl"
icon={<ChartPieIcon className="mr-2 hidden h-6 w-6 lg:block" />}
icon={<ChartPieIcon className="mr-3 hidden h-6 w-6 lg:block" />}
/>
<LeaderboardTypeButton
leaderboardType={leaderboardType}
setLeaderboardType={setLeaderboardType}
range={range}
label="futures-only"
icon={<TrendingUpIcon className="mr-2 hidden h-6 w-6 lg:block" />}
icon={<TrendingUpIcon className="mr-3 hidden h-6 w-6 lg:block" />}
/>
</div>
<div className="col-span-12 lg:col-span-8">
{loading ? (
<div className="mb-6 space-y-2">
<div className="h-24 w-full animate-pulse rounded-lg bg-th-bkg-3" />
<div className="h-24 w-full animate-pulse rounded-lg bg-th-bkg-3" />
<div className="h-24 w-full animate-pulse rounded-lg bg-th-bkg-3" />
{!loading ? (
<div className="space-y-2">
{leaderboardData.map((acc, i) => (
<AccountCard
rank={i + 1}
acc={acc.mango_account}
key={acc.mango_account}
pnl={
leaderboardType === 'total-pnl'
? acc.pnl.toLocaleString('en-US', {
style: 'currency',
currency: 'USD',
maximumFractionDigits: 0,
})
: usdFormatter(acc.perp_pnl)
}
pfp={acc.pfp}
/>
))}
</div>
) : leaderboardData.length > 0 ? (
<div className="mb-6 space-y-2">
<TopThreeCard
rank={1}
acc={leaderboardData[0].mango_account}
pnl={
leaderboardType === 'total-pnl'
? usdFormatter(leaderboardData[0].pnl)
: usdFormatter(leaderboardData[0].perp_pnl)
}
pfp={leaderboardData[0].pfp}
/>
<TopThreeCard
rank={2}
acc={leaderboardData[1].mango_account}
pnl={
leaderboardType === 'total-pnl'
? usdFormatter(leaderboardData[1].pnl)
: usdFormatter(leaderboardData[1].perp_pnl)
}
pfp={leaderboardData[0].pfp}
/>
<TopThreeCard
rank={3}
acc={leaderboardData[2].mango_account}
pnl={
leaderboardType === 'total-pnl'
? usdFormatter(leaderboardData[2].pnl)
: usdFormatter(leaderboardData[2].perp_pnl)
}
pfp={leaderboardData[0].pfp}
/>
) : (
<div className="space-y-2">
<div className="h-20 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-20 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-20 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-20 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-20 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-20 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-20 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-20 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-20 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-20 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-20 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-20 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-20 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-20 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-20 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-20 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-20 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-20 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-20 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-20 w-full animate-pulse rounded-md bg-th-bkg-3" />
</div>
) : null}
<div className={`overflow-x-auto sm:-mx-6 lg:-mx-8`}>
<div
className={`inline-block min-w-full align-middle sm:px-6 lg:px-8`}
>
{!loading ? (
<div className={`overflow-hidden`}>
<Table>
<thead>
<TrHead>
<Th>{t('rank')}</Th>
<Th>{t('account')}</Th>
<Th>{t('pnl')}</Th>
</TrHead>
</thead>
<tbody>
{leaderboardData.slice(3).map((acc, index) => {
const rank = index + 4
return (
<TrBody key={acc.mango_account}>
<Td className="w-1/10">
<div className="flex items-center">
{rank}
{rank === 1 ? (
<TrophyIcon className="ml-1.5 h-5 w-5 text-th-primary" />
) : null}
{rank === 2 || rank === 3 ? (
<AwardIcon className="ml-1.5 h-5 w-5 text-th-primary-dark" />
) : null}
</div>
</Td>
<Td className="w-1/3">
<div className="flex items-center">
<div className="mr-2 flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full bg-th-bkg-4">
{acc.pfp?.isAvailable ? (
<img
alt=""
src={acc.pfp.url}
className={`default-transition h-8 w-8 rounded-full hover:opacity-60
`}
/>
) : (
<ProfileIcon
className={`h-5 w-5 text-th-fgd-3`}
/>
)}
</div>
{`${acc.mango_account.slice(
0,
5
)}...${acc.mango_account.slice(-5)}`}
</div>
</Td>
<Td className="w-1/3">
{leaderboardType === 'total-pnl'
? usdFormatter(acc.pnl)
: usdFormatter(acc.perp_pnl)}
</Td>
<Td className="w-1/5">
<div className="flex justify-end">
<a
href={`https://trade.mango.markets/account?pubkey=${acc.mango_account}`}
target="_blank"
rel="noopener noreferrer"
className="default-transition text-th-fgd-3 hover:text-th-fgd-4"
>
{t('view-account')}
</a>
</div>
</Td>
</TrBody>
)
})}
</tbody>
</Table>
</div>
) : (
<div className="space-y-1">
<div className="h-8 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-16 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-16 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-16 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-16 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-16 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-16 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-16 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-16 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-16 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-16 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-16 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-16 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-16 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-16 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-16 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-16 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-16 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-16 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-16 w-full animate-pulse rounded-md bg-th-bkg-3" />
</div>
)}
</div>
</div>
)}
</div>
</div>
)
@ -252,8 +157,7 @@ const LeaderboardTable = ({ range = '29' }) => {
export default LeaderboardTable
const TopThreeCard = ({ rank, acc, pnl, pfp }) => {
const { t } = useTranslation('common')
const AccountCard = ({ rank, acc, pnl, pfp }) => {
const medalColors =
rank === 1
? {
@ -276,43 +180,47 @@ const TopThreeCard = ({ rank, acc, pnl, pfp }) => {
lightest: '#EFBF8D',
}
return (
<div className="flex items-center rounded-lg border border-th-bkg-4 p-4">
<p className="mb-0 mr-4">{rank}</p>
<div className="relative mr-3 flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-full bg-th-bkg-4">
<MedalIcon
className="absolute -top-2 -left-2 h-5 w-auto drop-shadow-lg"
colors={medalColors}
/>
<a
href={`https://trade.mango.markets/account?pubkey=${acc}`}
target="_blank"
rel="noopener noreferrer"
className="default-transition flex items-center rounded-lg p-4 ring-1 ring-inset ring-th-bkg-4 hover:bg-th-bkg-3"
>
<p className="mb-0 mr-4 font-bold">{rank}</p>
<div className="relative mr-3 flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-th-bkg-4">
{rank < 4 ? (
<MedalIcon
className="absolute -top-2 -left-2 h-5 w-auto drop-shadow-lg"
colors={medalColors}
/>
) : null}
{pfp?.isAvailable ? (
<img
alt=""
src={pfp.url}
className={`default-transition h-10 w-10 rounded-full hover:opacity-60
className={`default-transition h-12 w-12 rounded-full hover:opacity-60
`}
/>
) : (
<ProfileIcon className={`h-6 w-6 text-th-fgd-3`} />
<ProfileIcon className={`h-7 w-7 text-th-fgd-3`} />
)}
</div>
<div className="flex w-full flex-col sm:flex-row sm:items-center sm:justify-between">
<div>
<p className="mb-0">{`${acc.slice(0, 5)}...${acc.slice(-5)}`}</p>
<span className="text-base font-bold text-th-fgd-1 sm:text-lg">
{pnl}
</span>
<p className="mb-0 text-th-fgd-2">{`${acc.slice(0, 5)}...${acc.slice(
-5
)}`}</p>
</div>
<div>
<a
href={`https://trade.mango.markets/account?pubkey=${acc}`}
target="_blank"
rel="noopener noreferrer"
className="default-transition block text-th-fgd-3 hover:text-th-fgd-4"
>
{t('view-account')}
</a>
<div className="flex items-center">
<span className={`text-base font-bold text-th-fgd-2 sm:text-lg`}>
{pnl}
</span>
</div>
</div>
</div>
</div>
<ExternalLinkIcon className="ml-3 h-4 w-4 flex-shrink-0 text-th-fgd-3" />
</a>
)
}
@ -326,7 +234,7 @@ const LeaderboardTypeButton = ({
const { t } = useTranslation('common')
return (
<button
className={`relative flex w-full items-center justify-center rounded-md p-4 text-center lg:justify-start lg:text-left ${
className={`relative flex w-full items-center justify-center rounded-md p-4 text-center lg:h-20 lg:justify-start lg:text-left ${
leaderboardType === label
? 'bg-th-bkg-4 text-th-fgd-1 after:absolute after:top-[100%] after:left-1/2 after:-translate-x-1/2 after:transform after:border-l-[12px] after:border-r-[12px] after:border-t-[12px] after:border-l-transparent after:border-t-th-bkg-4 after:border-r-transparent lg:after:left-[100%] lg:after:top-1/2 lg:after:-translate-x-0 lg:after:-translate-y-1/2 lg:after:border-r-0 lg:after:border-b-[12px] lg:after:border-t-transparent lg:after:border-b-transparent lg:after:border-l-th-bkg-4'
: 'bg-th-bkg-3 text-th-fgd-4 hover:bg-th-bkg-4'
@ -335,7 +243,7 @@ const LeaderboardTypeButton = ({
>
{icon}
<div>
<div className="font-bold sm:text-base">{t(label)}</div>
<div className="font-bold sm:text-lg">{t(label)}</div>
<span className="text-th-fgd-4">
{range === '9999'
? 'All-time'