Added heads bar
This commit is contained in:
@@ -1,14 +1,84 @@
|
|||||||
import { formatNumber } from "@/lib/formatters"
|
import { formatNumber } from "@/lib/formatters"
|
||||||
import { getPrestigeName, getSkyWarsIcon, getTextColor } from "@/lib/hypixel/skywars"
|
import { getHeadsColor, getPrestigeName, getSkyWarsIcon, getTextColor } from "@/lib/hypixel/skywars"
|
||||||
import { getSkywarsLevel } from "@/lib/hypixel/skyWarsLevel"
|
import { getSkywarsLevel } from "@/lib/hypixel/skyWarsLevel"
|
||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils"
|
||||||
import GenericProgress from "../../_components/GenericProgress"
|
import GenericProgress from "../../_components/GenericProgress"
|
||||||
|
|
||||||
|
type SkywarsHeadsProps = {
|
||||||
|
heads: number
|
||||||
|
heads_special: {
|
||||||
|
eww: number
|
||||||
|
yucky: number
|
||||||
|
meh: number
|
||||||
|
decent: number
|
||||||
|
salty: number
|
||||||
|
tasty: number
|
||||||
|
succulent: number
|
||||||
|
sweet: number
|
||||||
|
divine: number
|
||||||
|
heavenly: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SkywarsHeads({
|
||||||
|
heads,
|
||||||
|
heads_special
|
||||||
|
}: SkywarsHeadsProps) {
|
||||||
|
const total_special = Object.values(heads_special).reduce((a, b) => a + b)
|
||||||
|
const percentages = {
|
||||||
|
heavenly: heads_special.heavenly / heads,
|
||||||
|
divine: heads_special.divine / heads,
|
||||||
|
sweet: heads_special.sweet / heads,
|
||||||
|
succulent: heads_special.succulent / heads,
|
||||||
|
tasty: heads_special.tasty / heads,
|
||||||
|
salty: heads_special.salty / heads,
|
||||||
|
decent: heads_special.decent / heads,
|
||||||
|
meh: heads_special.meh / heads,
|
||||||
|
yucky: heads_special.yucky / heads,
|
||||||
|
eww: heads_special.eww / heads,
|
||||||
|
rest: (heads - total_special) / heads
|
||||||
|
}
|
||||||
|
|
||||||
|
const headsArray = Object.entries(percentages)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
<span className="font-bold">{"Total Heads Gathered: "}</span>
|
||||||
|
<span className="text-mc-gray">{formatNumber(heads)}</span>
|
||||||
|
</p>
|
||||||
|
{total_special > 0 && (
|
||||||
|
<div className="flex mt-2">
|
||||||
|
{headsArray.map(([key, val], index) => {
|
||||||
|
const color = getHeadsColor(key)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={key}
|
||||||
|
className={cn(
|
||||||
|
"h-5",
|
||||||
|
color === null ? "bg-background" : `bg-mc-${color}`,
|
||||||
|
index === 0 ? "rounded-l-md" : undefined,
|
||||||
|
index === headsArray.length - 1 ? "rounded-r-md" : undefined
|
||||||
|
)}
|
||||||
|
style={{
|
||||||
|
width: `${val * 100}%`
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export function AngelOfDeath(
|
export function AngelOfDeath(
|
||||||
{ shards, lifetime_shards, opals, lifetime_opals }: { shards: number, lifetime_shards: number, opals: number, lifetime_opals: number }
|
{ shards, lifetime_shards, opals, lifetime_opals }: { shards: number, lifetime_shards: number, opals: number, lifetime_opals: number }
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
<div className="grid grid-cols-2 grid-rows-2 mt-5">
|
<div className="grid grid-cols-2 grid-rows-2">
|
||||||
<p>
|
<p>
|
||||||
<span className="font-bold">{"Shards: "}</span>
|
<span className="font-bold">{"Shards: "}</span>
|
||||||
<span className="text-mc-aqua">{shards}</span>
|
<span className="text-mc-aqua">{shards}</span>
|
||||||
@@ -32,7 +102,7 @@ export function AngelOfDeath(
|
|||||||
export function ShardProgress({ percent }: { percent: number }) {
|
export function ShardProgress({ percent }: { percent: number }) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h1 className="mb-2 font-bold">Shard Progress</h1>
|
<h1 className="font-bold">Shard Progress</h1>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<GenericProgress percent={percent} className="bg-mc-aqua" />
|
<GenericProgress percent={percent} className="bg-mc-aqua" />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { NonNullStats } from "@/lib/schema/player"
|
|||||||
import { ChevronDown, ChevronUp } from "lucide-react"
|
import { ChevronDown, ChevronUp } from "lucide-react"
|
||||||
import { useEffect, useRef, useState } from "react"
|
import { useEffect, useRef, useState } from "react"
|
||||||
import CollapsedStats from "../../_components/CollapsedStats"
|
import CollapsedStats from "../../_components/CollapsedStats"
|
||||||
import { AngelOfDeath, ShardProgress, SkywarsLevel, SkywarsProgress } from "./components"
|
import { AngelOfDeath, ShardProgress, SkywarsHeads, SkywarsLevel, SkywarsProgress } from "./components"
|
||||||
import SkyWarsGeneralStats from "./stats"
|
import SkyWarsGeneralStats from "./stats"
|
||||||
import SkywarsStatTable from "./table"
|
import SkywarsStatTable from "./table"
|
||||||
|
|
||||||
@@ -93,13 +93,30 @@ export default function SkyWarsStats(
|
|||||||
<Separator className="my-4" />
|
<Separator className="my-4" />
|
||||||
<SkywarsStatTable stats={stats} />
|
<SkywarsStatTable stats={stats} />
|
||||||
<Separator className="my-4" />
|
<Separator className="my-4" />
|
||||||
<ShardProgress percent={shardProgress} />
|
<div className="space-y-2">
|
||||||
<AngelOfDeath
|
<ShardProgress percent={shardProgress} />
|
||||||
shards={stats.shard}
|
<AngelOfDeath
|
||||||
lifetime_shards={achievements_skywars_opal_obsession * 20000 + stats.shard}
|
shards={stats.shard}
|
||||||
opals={stats.opals}
|
lifetime_shards={achievements_skywars_opal_obsession * 20000 + stats.shard}
|
||||||
lifetime_opals={achievements_skywars_opal_obsession}
|
opals={stats.opals}
|
||||||
/>
|
lifetime_opals={achievements_skywars_opal_obsession}
|
||||||
|
/>
|
||||||
|
<SkywarsHeads
|
||||||
|
heads={stats.heads}
|
||||||
|
heads_special={{
|
||||||
|
heavenly: stats.heads_heavenly,
|
||||||
|
divine: stats.heads_divine,
|
||||||
|
decent: stats.heads_decent,
|
||||||
|
eww: stats.heads_eww,
|
||||||
|
meh: stats.heads_meh,
|
||||||
|
salty: stats.heads_salty,
|
||||||
|
succulent: stats.heads_succulent,
|
||||||
|
sweet: stats.heads_sweet,
|
||||||
|
tasty: stats.heads_tasty,
|
||||||
|
yucky: stats.heads_yucky
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</CollapsibleContent>
|
</CollapsibleContent>
|
||||||
</Collapsible>
|
</Collapsible>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export function getColor(color?: string, type: "text" | "bg" = "text", defaultCo
|
|||||||
case "DARK_RED":
|
case "DARK_RED":
|
||||||
return type === "text" ? "text-mc-dark-red" : "bg-mc-dark-red"
|
return type === "text" ? "text-mc-dark-red" : "bg-mc-dark-red"
|
||||||
case "DARK_AQUA":
|
case "DARK_AQUA":
|
||||||
return type === "text" ? "text-mc-dark-aqua" : "bg-mc-dark-red"
|
return type === "text" ? "text-mc-dark-aqua" : "bg-mc-dark-aqua"
|
||||||
case "DARK_PURPLE":
|
case "DARK_PURPLE":
|
||||||
return type === "text" ? "text-mc-dark-purple" : "bg-mc-dark-purple"
|
return type === "text" ? "text-mc-dark-purple" : "bg-mc-dark-purple"
|
||||||
case "DARK_GRAY":
|
case "DARK_GRAY":
|
||||||
|
|||||||
@@ -96,14 +96,14 @@ export const MODES = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
export const HEADS = [
|
export const HEADS = [
|
||||||
{ id: "eww", name: "Eww!", color: "darkgray" },
|
{ id: "eww", name: "Eww!", color: "dark-gray" },
|
||||||
{ id: "yucky", name: "Yucky!", color: "gray" },
|
{ id: "yucky", name: "Yucky!", color: "gray" },
|
||||||
{ id: "meh", name: "Meh", color: "white" },
|
{ id: "meh", name: "Meh", color: "white" },
|
||||||
{ id: "decent", name: "Decent", color: "yellow" },
|
{ id: "decent", name: "Decent", color: "yellow" },
|
||||||
{ id: "salty", name: "Salty", color: "green" },
|
{ id: "salty", name: "Salty", color: "green" },
|
||||||
{ id: "tasty", name: "Tasty", color: "darkaqua" },
|
{ id: "tasty", name: "Tasty", color: "dark-aqua" },
|
||||||
{ id: "succulent", name: "Succulent", color: "pink" },
|
{ id: "succulent", name: "Succulent", color: "light-purple" },
|
||||||
{ id: "sweet", name: "Sweet", color: "aqua" },
|
{ id: "sweet", name: "Sweet", color: "aqua" },
|
||||||
{ id: "divine", name: "Divine", color: "gold" },
|
{ id: "divine", name: "Divine", color: "gold" },
|
||||||
{ id: "heavenly", name: "Heavenly", color: "purple" }
|
{ id: "heavenly", name: "Heavenly", color: "dark-purple" }
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,7 +1,15 @@
|
|||||||
import { ICONS, PRESTIGES } from "@/data/hypixel/skywars"
|
import { HEADS, ICONS, PRESTIGES } from "@/data/hypixel/skywars"
|
||||||
import { floorLevel } from "./formatters"
|
import { floorLevel } from "./formatters"
|
||||||
import { devide } from "./general"
|
import { devide } from "./general"
|
||||||
|
|
||||||
|
export function getHeadsColor(key: string) {
|
||||||
|
const val = HEADS.find(v => v.id === key)?.color
|
||||||
|
|
||||||
|
if (!val) return null
|
||||||
|
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
export function getTextColor(level: number) {
|
export function getTextColor(level: number) {
|
||||||
const floored = floorLevel(level, 5)
|
const floored = floorLevel(level, 5)
|
||||||
|
|
||||||
|
|||||||
@@ -248,5 +248,15 @@ export const skywarsStatsSchema = z.looseObject({
|
|||||||
wins_ranked_normal: z.number().default(0),
|
wins_ranked_normal: z.number().default(0),
|
||||||
losses_ranked_normal: z.number().default(0),
|
losses_ranked_normal: z.number().default(0),
|
||||||
shard: z.number().default(0),
|
shard: z.number().default(0),
|
||||||
opals: z.number().default(0)
|
opals: z.number().default(0),
|
||||||
|
heads_eww: z.number().default(0),
|
||||||
|
heads_yucky: z.number().default(0),
|
||||||
|
heads_meh: z.number().default(0),
|
||||||
|
heads_decent: z.number().default(0),
|
||||||
|
heads_salty: z.number().default(0),
|
||||||
|
heads_tasty: z.number().default(0),
|
||||||
|
heads_succulent: z.number().default(0),
|
||||||
|
heads_sweet: z.number().default(0),
|
||||||
|
heads_divine: z.number().default(0),
|
||||||
|
heads_heavenly: z.number().default(0)
|
||||||
})
|
})
|
||||||
|
|||||||
108
đ
108
đ
@@ -1,108 +0,0 @@
|
|||||||
import DisplayName from "@/components/player/displayname"
|
|
||||||
import { Card, CardContent } from "@/components/ui/card"
|
|
||||||
import { getGuild } from "@/lib/hypixel/api/guild"
|
|
||||||
import { getUuid } from "@/lib/hypixel/api/mojang"
|
|
||||||
import { getPlayer } from "@/lib/hypixel/api/player"
|
|
||||||
import { getExactLevel } from "@/lib/hypixel/level"
|
|
||||||
import { Loader2Icon } from "lucide-react"
|
|
||||||
import { Suspense } from "react"
|
|
||||||
import Sidebar from "./_components/Sidebar"
|
|
||||||
import BedwarsStats from "./_stats/bedwars/bedwars"
|
|
||||||
import SkyWarsStats from "./_stats/skywars/skywars"
|
|
||||||
|
|
||||||
export default async function PlayerPage({
|
|
||||||
params
|
|
||||||
}: {
|
|
||||||
params: Promise<{ ign: string }>
|
|
||||||
}) {
|
|
||||||
const { ign } = await params
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Suspense
|
|
||||||
fallback={
|
|
||||||
<div className="flex flex-col justify-center items-center h-screen">
|
|
||||||
<Loader2Icon className="animate-spin size-30" />
|
|
||||||
<p>{`Loading stats for ${ign}`}</p>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<SuspendedPage ign={ign} />
|
|
||||||
</Suspense>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function SuspendedPage({ ign: pign }: { ign: string }) {
|
|
||||||
const uuid = await getUuid(pign)
|
|
||||||
if (!uuid) {
|
|
||||||
return (
|
|
||||||
<div className="flex flex-col items-center min-h-screen">
|
|
||||||
<h1 className="mt-25">Player not found</h1>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const player = await getPlayer(uuid)
|
|
||||||
|
|
||||||
if (!player) {
|
|
||||||
return (
|
|
||||||
<div className="flex flex-col items-center min-h-screen">
|
|
||||||
<h1 className="mt-25">Player not found</h1>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const guild = await getGuild(uuid)
|
|
||||||
const level = getExactLevel(player.networkExp)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex flex-col items-center">
|
|
||||||
<h1 className="text-3xl font-bold mt-25">
|
|
||||||
<DisplayName
|
|
||||||
ign={player.displayname}
|
|
||||||
rank={player.newPackageRank}
|
|
||||||
monthly={player.monthlyPackageRank}
|
|
||||||
rankColor={player.monthlyRankColor}
|
|
||||||
plusColor={player.rankPlusColor}
|
|
||||||
guildTag={guild?.tag}
|
|
||||||
tagColor={guild?.tagColor}
|
|
||||||
specialRank={player.rank}
|
|
||||||
/>
|
|
||||||
</h1>
|
|
||||||
<h1>
|
|
||||||
{player.uuid}
|
|
||||||
</h1>
|
|
||||||
<div className="flex gap-6 px-6 mt-8 w-full max-w-7xl">
|
|
||||||
<Sidebar
|
|
||||||
level={level}
|
|
||||||
ign={pign}
|
|
||||||
player={player}
|
|
||||||
guild={guild ?? undefined}
|
|
||||||
rank={player.newPackageRank}
|
|
||||||
specialRank={player.rank}
|
|
||||||
eulaCoins={player.eulaCoins}
|
|
||||||
/>
|
|
||||||
{player.stats !== undefined ?
|
|
||||||
(
|
|
||||||
<div className="pb-4 space-y-4 w-3/4">
|
|
||||||
<BedwarsStats stats={player.stats.Bedwars} />
|
|
||||||
<SkyWarsStats
|
|
||||||
stats={player.stats.SkyWars}
|
|
||||||
achievements_skywars_opal_obsession={player.achievements?.["skywars_opal_obsession"] ?? 0}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
) :
|
|
||||||
(
|
|
||||||
<div className="w-3/4">
|
|
||||||
<Card>
|
|
||||||
<CardContent className="flex justify-center">
|
|
||||||
<h1 className="text-xl font-bold">
|
|
||||||
No stats avaiable. If they are staff then they most likely have their api off.
|
|
||||||
</h1>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user