Updated bedears stats

This commit is contained in:
2025-08-19 19:39:36 +02:00
parent ecc0098fb8
commit f8a54dc4b6
13 changed files with 276 additions and 187 deletions

View File

@@ -0,0 +1,24 @@
import { getBedwarsStar, getTextColor } from "@/lib/hypixel/bedwars"
import { getBWLevelForExp } from "@/lib/hypixel/bedwarsLevel"
import { bedwarsLevelColors } from "@/lib/hypixelFormatters"
import Multicolored from "../../_components/Multicolored"
export function BedwarsLevel({ xp }: { xp: number }) {
const level = getBWLevelForExp(xp)
const color = bedwarsLevelColors(level)
const star = getBedwarsStar(level)
const val = `[${level}${star}]`
return <Multicolored val={val} color={color} />
}
export function BedwarsProgress({ level, percent }: { level: number, percent: number }) {
return (
<div className="flex items-center mb-10">
<div className={`mr-2 text-mc-${getTextColor(level)}`}>{level}</div>
<div className={`h-5 bg-mc-${getTextColor(level)} rounded-l-md`} style={{ width: `${percent}%` }}></div>
<div className="flex-1 h-5 rounded-r-md bg-background"></div>
<div className={`ml-2 text-mc-${getTextColor(level)}`}>{level + 1}</div>
</div>
)
}

View File

@@ -2,15 +2,15 @@
import { Card, CardContent } from "@/components/ui/card" import { Card, CardContent } from "@/components/ui/card"
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible" import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible"
import { getBedwarsStar } from "@/lib/hypixel/bedwars" import { getBedwarsStar, getPrestigeName, getTextColor } from "@/lib/hypixel/bedwars"
import { getBWLevelForExp } from "@/lib/hypixel/bedwarsLevel" import { getBWLevelForExp, getTotalExpForLevel } from "@/lib/hypixel/bedwarsLevel"
import { bedwarsLevelColors } from "@/lib/hypixelFormatters" import { getProgress } from "@/lib/hypixel/general"
import { Player } from "@/lib/schema/player" import { Player } from "@/lib/schema/player"
import { Separator } from "@radix-ui/react-separator" import { Separator } from "@radix-ui/react-separator"
import { ChevronDown, ChevronUp, Menu } from "lucide-react" import { ChevronDown, ChevronUp, Menu } from "lucide-react"
import { useEffect, useRef, useState } from "react" import { useEffect, useRef, useState } from "react"
import CollapsedStats from "../CollapsedStats" import CollapsedStats from "../../_components/CollapsedStats"
import Multicolored from "../Multicolored" import { BedwarsLevel, BedwarsProgress } from "./bedwars-components"
export default function BedwarsStats({ stats }: { stats: Player["player"]["stats"]["Bedwars"] }) { export default function BedwarsStats({ stats }: { stats: Player["player"]["stats"]["Bedwars"] }) {
const ref = useRef<HTMLDivElement>(null) const ref = useRef<HTMLDivElement>(null)
@@ -42,6 +42,13 @@ export default function BedwarsStats({ stats }: { stats: Player["player"]["stats
const fkd = (stats.final_kills_bedwars / stats.final_deaths_bedwars).toFixed(2) const fkd = (stats.final_kills_bedwars / stats.final_deaths_bedwars).toFixed(2)
const wl = (stats.wins_bedwars / stats.losses_bedwars).toFixed(2) const wl = (stats.wins_bedwars / stats.losses_bedwars).toFixed(2)
const bbl = (stats.beds_broken_bedwars / stats.beds_lost_bedwars).toFixed(2) const bbl = (stats.beds_broken_bedwars / stats.beds_lost_bedwars).toFixed(2)
const level = getBWLevelForExp(stats.Experience)
const percent = getProgress(
getTotalExpForLevel(level),
stats.Experience,
getTotalExpForLevel(level + 1)
)
return ( return (
<Card> <Card>
@@ -88,18 +95,32 @@ export default function BedwarsStats({ stats }: { stats: Player["player"]["stats
</div> </div>
<CollapsibleContent> <CollapsibleContent>
<Separator className="my-4" /> <Separator className="my-4" />
<BedwarsProgress level={level} percent={percent} />
<div>
<div>
<div>
<p>
<span className="font-bold">{"Level: "}</span>
<span>{`${level}.${percent.toFixed(0)}`}</span>
</p>
<p>
<span className="font-bold">{"Prestige: "}</span>
<span className={`text-mc-${getTextColor(level)}`}>
{`${getPrestigeName(level)} ${getBedwarsStar(level)}`}
</span>
</p>
<p>
<span className="font-bold">{"Tokens: "}</span>
<span className="text-mc-dark-green">{}</span>
</p>
</div>
</div>
<div></div>
<div></div>
</div>
</CollapsibleContent> </CollapsibleContent>
</Collapsible> </Collapsible>
</CardContent> </CardContent>
</Card> </Card>
) )
} }
function BedwarsLevel({ xp }: { xp: number }) {
const level = getBWLevelForExp(xp)
const color = bedwarsLevelColors(level)
const star = getBedwarsStar(level)
const val = `[${level}${star}]`
return <Multicolored val={val} color={color} />
}

View File

@@ -4,7 +4,7 @@ import { getUuid } from "@/lib/hypixel/api/mojang"
import { getPlayer } from "@/lib/hypixel/api/player" import { getPlayer } from "@/lib/hypixel/api/player"
import { getExactLevel } from "@/lib/hypixel/level" import { getExactLevel } from "@/lib/hypixel/level"
import Sidebar from "./_components/Sidebar" import Sidebar from "./_components/Sidebar"
import BedwarsStats from "./_components/stats/bedewars" import BedwarsStats from "./_stats/bedwars/bedwars"
export default async function PlayerPage({ export default async function PlayerPage({
params params

View File

@@ -4,138 +4,137 @@
@custom-variant dark (&:is(.dark *)); @custom-variant dark (&:is(.dark *));
@theme inline { @theme inline {
--color-mc-black: #000000; --color-mc-black: #000000;
--color-mc-dark-blue: #0000AA; --color-mc-dark-blue: #0000AA;
--color-mc-dark-green: #00AA00; --color-mc-dark-green: #00AA00;
--color-mc-dark-aqua: #00AAAA; --color-mc-dark-aqua: #00AAAA;
--color-mc-dark-red: #AA0000; --color-mc-dark-red: #AA0000;
--color-mc-dark-purple: #AA00AA; --color-mc-dark-purple: #AA00AA;
--color-mc-gold: #FFAA00; --color-mc-gold: #FFAA00;
--color-mc-gray: #AAAAAA; --color-mc-gray: #AAAAAA;
--color-mc-light-gray: #C6C6C6; --color-mc-dark-gray: #555555;
--color-mc-dark-gray: #555555; --color-mc-blue: #5555FF;
--color-mc-blue: #5555FF; --color-mc-green: #55FF55;
--color-mc-green: #55FF55; --color-mc-aqua: #55FFFF;
--color-mc-aqua: #55FFFF; --color-mc-red: #FF5555;
--color-mc-red: #FF5555; --color-mc-light-purple: #FF55FF;
--color-mc-light-purple: #FF55FF; --color-mc-yellow: #FFFF55;
--color-mc-yellow: #FFFF55; --color-mc-white: #FFFFFF;
--color-mc-white: #FFFFFF;
} }
@theme inline { @theme inline {
--radius-sm: calc(var(--radius) - 4px); --radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px); --radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius); --radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px); --radius-xl: calc(var(--radius) + 4px);
--color-background: var(--background); --color-background: var(--background);
--color-foreground: var(--foreground); --color-foreground: var(--foreground);
--color-card: var(--card); --color-card: var(--card);
--color-card-foreground: var(--card-foreground); --color-card-foreground: var(--card-foreground);
--color-popover: var(--popover); --color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground); --color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary); --color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground); --color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary); --color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground); --color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted); --color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground); --color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent); --color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground); --color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive); --color-destructive: var(--destructive);
--color-border: var(--border); --color-border: var(--border);
--color-input: var(--input); --color-input: var(--input);
--color-ring: var(--ring); --color-ring: var(--ring);
--color-chart-1: var(--chart-1); --color-chart-1: var(--chart-1);
--color-chart-2: var(--chart-2); --color-chart-2: var(--chart-2);
--color-chart-3: var(--chart-3); --color-chart-3: var(--chart-3);
--color-chart-4: var(--chart-4); --color-chart-4: var(--chart-4);
--color-chart-5: var(--chart-5); --color-chart-5: var(--chart-5);
--color-sidebar: var(--sidebar); --color-sidebar: var(--sidebar);
--color-sidebar-foreground: var(--sidebar-foreground); --color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary); --color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground); --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-accent: var(--sidebar-accent); --color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground); --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border); --color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring); --color-sidebar-ring: var(--sidebar-ring);
} }
:root { :root {
--radius: 0.625rem; --radius: 0.625rem;
--background: oklch(1 0 0); --background: oklch(1 0 0);
--foreground: oklch(0.145 0 0); --foreground: oklch(0.145 0 0);
--card: oklch(1 0 0); --card: oklch(1 0 0);
--card-foreground: oklch(0.145 0 0); --card-foreground: oklch(0.145 0 0);
--popover: oklch(1 0 0); --popover: oklch(1 0 0);
--popover-foreground: oklch(0.145 0 0); --popover-foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0); --primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0); --primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.97 0 0); --secondary: oklch(0.97 0 0);
--secondary-foreground: oklch(0.205 0 0); --secondary-foreground: oklch(0.205 0 0);
--muted: oklch(0.97 0 0); --muted: oklch(0.97 0 0);
--muted-foreground: oklch(0.556 0 0); --muted-foreground: oklch(0.556 0 0);
--accent: oklch(0.97 0 0); --accent: oklch(0.97 0 0);
--accent-foreground: oklch(0.205 0 0); --accent-foreground: oklch(0.205 0 0);
--destructive: oklch(0.577 0.245 27.325); --destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.922 0 0); --border: oklch(0.922 0 0);
--input: oklch(0.922 0 0); --input: oklch(0.922 0 0);
--ring: oklch(0.708 0 0); --ring: oklch(0.708 0 0);
--chart-1: oklch(0.646 0.222 41.116); --chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704); --chart-2: oklch(0.6 0.118 184.704);
--chart-3: oklch(0.398 0.07 227.392); --chart-3: oklch(0.398 0.07 227.392);
--chart-4: oklch(0.828 0.189 84.429); --chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08); --chart-5: oklch(0.769 0.188 70.08);
--sidebar: oklch(0.985 0 0); --sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0); --sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.205 0 0); --sidebar-primary: oklch(0.205 0 0);
--sidebar-primary-foreground: oklch(0.985 0 0); --sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.97 0 0); --sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0); --sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0); --sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0); --sidebar-ring: oklch(0.708 0 0);
} }
.dark { .dark {
--background: oklch(0.145 0 0); --background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0); --foreground: oklch(0.985 0 0);
--card: oklch(0.205 0 0); --card: oklch(0.205 0 0);
--card-foreground: oklch(0.985 0 0); --card-foreground: oklch(0.985 0 0);
--popover: oklch(0.205 0 0); --popover: oklch(0.205 0 0);
--popover-foreground: oklch(0.985 0 0); --popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.922 0 0); --primary: oklch(0.922 0 0);
--primary-foreground: oklch(0.205 0 0); --primary-foreground: oklch(0.205 0 0);
--secondary: oklch(0.269 0 0); --secondary: oklch(0.269 0 0);
--secondary-foreground: oklch(0.985 0 0); --secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.269 0 0); --muted: oklch(0.269 0 0);
--muted-foreground: oklch(0.708 0 0); --muted-foreground: oklch(0.708 0 0);
--accent: oklch(0.269 0 0); --accent: oklch(0.269 0 0);
--accent-foreground: oklch(0.985 0 0); --accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.704 0.191 22.216); --destructive: oklch(0.704 0.191 22.216);
--border: oklch(1 0 0 / 10%); --border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%); --input: oklch(1 0 0 / 15%);
--ring: oklch(0.556 0 0); --ring: oklch(0.556 0 0);
--chart-1: oklch(0.488 0.243 264.376); --chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48); --chart-2: oklch(0.696 0.17 162.48);
--chart-3: oklch(0.769 0.188 70.08); --chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9); --chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439); --chart-5: oklch(0.645 0.246 16.439);
--sidebar: oklch(0.205 0 0); --sidebar: oklch(0.205 0 0);
--sidebar-foreground: oklch(0.985 0 0); --sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376); --sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0 0); --sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.269 0 0); --sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0); --sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%); --sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.556 0 0); --sidebar-ring: oklch(0.556 0 0);
} }
@layer base { @layer base {
* { * {
@apply border-border outline-ring/50; @apply border-border outline-ring/50;
} }
body { body {
@apply bg-background text-foreground; @apply bg-background text-foreground;
} }
} }

View File

@@ -6,7 +6,7 @@ export function getColor(color?: string, type: "text" | "bg" = "text", defaultCo
return type === "text" ? "text-mc-red" : "bg-mc-red" return type === "text" ? "text-mc-red" : "bg-mc-red"
case "GOLD": case "GOLD":
return type === "text" ? "text-mc-gold" : "bg-mc-gold" return type === "text" ? "text-mc-gold" : "bg-mc-gold"
case "LIME": case "GREEN":
return type === "text" ? "text-mc-green" : "bg-mc-green" return type === "text" ? "text-mc-green" : "bg-mc-green"
case "YELLOW": case "YELLOW":
return type === "text" ? "text-mc-yellow" : "bg-mc-yellow" return type === "text" ? "text-mc-yellow" : "bg-mc-yellow"
@@ -16,12 +16,12 @@ export function getColor(color?: string, type: "text" | "bg" = "text", defaultCo
return type === "text" ? "text-mc-white" : "bg-mc-white" return type === "text" ? "text-mc-white" : "bg-mc-white"
case "BLUE": case "BLUE":
return type === "text" ? "text-mc-blue" : "bg-mc-blue" return type === "text" ? "text-mc-blue" : "bg-mc-blue"
case "GREEN":
return type === "text" ? "text-mc-green" : "bg-mc-green"
case "DARK_RED":
return type === "text" ? "text-mc-dark-red" : "bg-mc-dark-red"
case "DARK_GREEN": case "DARK_GREEN":
return type === "text" ? "text-mc-dark-green" : "bg-mc-dark-green" return type === "text" ? "text-mc-dark-green" : "bg-mc-dark-green"
case "DARK_RED":
return type === "text" ? "text-mc-dark-red" : "bg-mc-dark-red"
case "DARK_AQUA":
return type === "text" ? "text-mc-dark-aqua" : "bg-mc-dark-red"
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":
@@ -30,6 +30,8 @@ export function getColor(color?: string, type: "text" | "bg" = "text", defaultCo
return type === "text" ? "text-mc-black" : "bg-mc-black" return type === "text" ? "text-mc-black" : "bg-mc-black"
case "DARK_BLUE": case "DARK_BLUE":
return type === "text" ? "text-mc-dark-blue" : "bg-mc-dark-blue" return type === "text" ? "text-mc-dark-blue" : "bg-mc-dark-blue"
case "GRAY":
return type === "text" ? "text-mc-gray" : "bg-mc-gray"
default: default:
return type === "text" ? `text-mc-${defaultColor}` : `bg-mc-${defaultColor}` return type === "text" ? `text-mc-${defaultColor}` : `bg-mc-${defaultColor}`
} }

View File

@@ -4,10 +4,10 @@ export const PRESTIGES = [
{ level: 100, colormap: "f", color: "white", name: "Iron" }, { level: 100, colormap: "f", color: "white", name: "Iron" },
{ level: 200, colormap: "6", color: "gold", name: "Gold" }, { level: 200, colormap: "6", color: "gold", name: "Gold" },
{ level: 300, colormap: "b", color: "aqua", name: "Diamond" }, { level: 300, colormap: "b", color: "aqua", name: "Diamond" },
{ level: 400, colormap: "2", color: "darkgreen", name: "Emerald" }, { level: 400, colormap: "2", color: "dark-green", name: "Emerald" },
{ level: 500, colormap: "3", color: "darkaqua", name: "Sapphire" }, { level: 500, colormap: "3", color: "dark-aqua", name: "Sapphire" },
{ level: 600, colormap: "4", color: "darkred", name: "Ruby" }, { level: 600, colormap: "4", color: "dark-red", name: "Ruby" },
{ level: 700, colormap: "d", color: "pink", name: "Crystal" }, { level: 700, colormap: "d", color: "light-purple", name: "Crystal" },
{ level: 800, colormap: "9", color: "blue", name: "Opal" }, { level: 800, colormap: "9", color: "blue", name: "Opal" },
{ level: 900, colormap: "5", color: "purple", name: "Amethyst" }, { level: 900, colormap: "5", color: "purple", name: "Amethyst" },
{ level: 1000, colormap: "c6eabd5", color: "rainbow", name: "Rainbow" }, { level: 1000, colormap: "c6eabd5", color: "rainbow", name: "Rainbow" },
@@ -15,9 +15,9 @@ export const PRESTIGES = [
{ level: 1200, colormap: "7eeee67", color: "yellow", name: "Gold Prime" }, { level: 1200, colormap: "7eeee67", color: "yellow", name: "Gold Prime" },
{ level: 1300, colormap: "7bbbb37", color: "aqua", name: "Diamond Prime" }, { level: 1300, colormap: "7bbbb37", color: "aqua", name: "Diamond Prime" },
{ level: 1400, colormap: "7aaaa27", color: "green", name: "Emerald Prime" }, { level: 1400, colormap: "7aaaa27", color: "green", name: "Emerald Prime" },
{ level: 1500, colormap: "7333397", color: "darkaqua", name: "Sapphire Prime" }, { level: 1500, colormap: "7333397", color: "dark-aqua", name: "Sapphire Prime" },
{ level: 1600, colormap: "7cccc47", color: "red", name: "Ruby Prime" }, { level: 1600, colormap: "7cccc47", color: "red", name: "Ruby Prime" },
{ level: 1700, colormap: "7dddd57", color: "pink", name: "Crystal Prime" }, { level: 1700, colormap: "7dddd57", color: "light-purple", name: "Crystal Prime" },
{ level: 1800, colormap: "7999917", color: "blue", name: "Opal Prime" }, { level: 1800, colormap: "7999917", color: "blue", name: "Opal Prime" },
{ level: 1900, colormap: "7555587", color: "purple", name: "Amethyst Prime" }, { level: 1900, colormap: "7555587", color: "purple", name: "Amethyst Prime" },
{ level: 2000, colormap: "87ff778", color: "white", name: "Mirror" }, { level: 2000, colormap: "87ff778", color: "white", name: "Mirror" },
@@ -26,31 +26,31 @@ export const PRESTIGES = [
{ level: 2300, colormap: "55dd6ee", color: "purple", name: "Dusk" }, { level: 2300, colormap: "55dd6ee", color: "purple", name: "Dusk" },
{ level: 2400, colormap: "bbff778", color: "white", name: "Air" }, { level: 2400, colormap: "bbff778", color: "white", name: "Air" },
{ level: 2500, colormap: "ffaa222", color: "green", name: "Wind" }, { level: 2500, colormap: "ffaa222", color: "green", name: "Wind" },
{ level: 2600, colormap: "44ccdd5", color: "darkred", name: "Nebula" }, { level: 2600, colormap: "44ccdd5", color: "dark-red", name: "Nebula" },
{ level: 2700, colormap: "eeff777", color: "yellow", name: "Thunder" }, { level: 2700, colormap: "eeff777", color: "yellow", name: "Thunder" },
{ level: 2800, colormap: "aa2266e", color: "darkgreen", name: "Earth" }, { level: 2800, colormap: "aa2266e", color: "dark-green", name: "Earth" },
{ level: 2900, colormap: "bb33991", color: "blue", name: "Water" }, { level: 2900, colormap: "bb33991", color: "blue", name: "Water" },
{ level: 3000, colormap: "ee66cc4", color: "red", name: "Fire" }, { level: 3000, colormap: "ee66cc4", color: "red", name: "Fire" },
{ level: 3100, colormap: "993366e", color: "blue", name: "Sunshine" }, { level: 3100, colormap: "993366e", color: "blue", name: "Sunshine" },
{ level: 3200, colormap: "c4774cc", color: "darkred", name: "Eclipse" }, { level: 3200, colormap: "c4774cc", color: "dark-red", name: "Eclipse" },
{ level: 3300, colormap: "999dcc4", color: "blue", name: "Gamma" }, { level: 3300, colormap: "999dcc4", color: "blue", name: "Gamma" },
{ level: 3400, colormap: "2add552", color: "green", name: "Majestic" }, { level: 3400, colormap: "2add552", color: "green", name: "Majestic" },
{ level: 3500, colormap: "cc442aa", color: "red", name: "Andesine" }, { level: 3500, colormap: "cc442aa", color: "red", name: "Andesine" },
{ level: 3600, colormap: "aaab991", color: "green", name: "Marine" }, { level: 3600, colormap: "aaab991", color: "green", name: "Marine" },
{ level: 3700, colormap: "44ccb33", color: "darkred", name: "Element" }, { level: 3700, colormap: "44ccb33", color: "dark-red", name: "Element" },
{ level: 3800, colormap: "11955d1", color: "darkblue", name: "Galaxy" }, { level: 3800, colormap: "11955d1", color: "dark-blue", name: "Galaxy" },
{ level: 3900, colormap: "ccaa399", color: "red", name: "Atomic" }, { level: 3900, colormap: "ccaa399", color: "red", name: "Atomic" },
{ level: 4000, colormap: "55cc66e", color: "purple", name: "Sunset" }, { level: 4000, colormap: "55cc66e", color: "purple", name: "Sunset" },
{ level: 4100, colormap: "ee6cdd5", color: "yellow", name: "Time" }, { level: 4100, colormap: "ee6cdd5", color: "yellow", name: "Time" },
{ level: 4200, colormap: "193bf77", color: "blue", name: "Winter" }, { level: 4200, colormap: "193bf77", color: "blue", name: "Winter" },
{ level: 4300, colormap: "0588550", color: "purple", name: "Obsidian" }, { level: 4300, colormap: "0588550", color: "purple", name: "Obsidian" },
{ level: 4400, colormap: "22ae65d", color: "darkgreen", name: "Spring" }, { level: 4400, colormap: "22ae65d", color: "dark-green", name: "Spring" },
{ level: 4500, colormap: "ffbb333", color: "white", name: "Ice" }, { level: 4500, colormap: "ffbb333", color: "white", name: "Ice" },
{ level: 4600, colormap: "3bee6d5", color: "aqua", name: "Summer" }, { level: 4600, colormap: "3bee6d5", color: "aqua", name: "Summer" },
{ level: 4700, colormap: "f4cc919", color: "darkred", name: "Spinel" }, { level: 4700, colormap: "f4cc919", color: "dark-red", name: "Spinel" },
{ level: 4800, colormap: "55c6eb3", color: "purple", name: "Autumn" }, { level: 4800, colormap: "55c6eb3", color: "purple", name: "Autumn" },
{ level: 4900, colormap: "2affaa2", color: "green", name: "Mystic" }, { level: 4900, colormap: "2affaa2", color: "green", name: "Mystic" },
{ level: 5000, colormap: "4459910", color: "darkred", name: "Eternal" } { level: 5000, colormap: "4459910", color: "dark-red", name: "Eternal" }
] ]
export const PRESTIGE_ICONS = [ export const PRESTIGE_ICONS = [
{ level: 0, symbol: "✫" }, { level: 0, symbol: "✫" },

View File

@@ -1,20 +1,20 @@
const numberFormatter = new Intl.NumberFormat(undefined, { const numberFormatter = new Intl.NumberFormat(undefined, {
maximumFractionDigits: 2, maximumFractionDigits: 2,
minimumFractionDigits: 0, minimumFractionDigits: 0
}); })
const dateFormatter = new Intl.DateTimeFormat(undefined, { const dateFormatter = new Intl.DateTimeFormat(undefined, {
year: 'numeric', year: "numeric",
month: '2-digit', month: "2-digit",
day: '2-digit', day: "2-digit",
hour: '2-digit', hour: "2-digit",
minute: '2-digit', minute: "2-digit",
hour12: false, hour12: false
}); })
export function formatNumber(num: number): string { export function formatNumber(num: number): string {
return numberFormatter.format(num); return numberFormatter.format(num)
} }
export function formatDate(timestamp: number): string { export function formatDate(timestamp: number): string {
return dateFormatter.format(new Date(timestamp)); return dateFormatter.format(new Date(timestamp))
} }

View File

@@ -17,4 +17,5 @@ export async function getPlayer(uuid: string) {
if (!success) return null if (!success) return null
return data.player return data.player
} }

View File

@@ -1,4 +1,5 @@
import { PRESTIGE_ICONS } from "@/data/hypixel/bedwars" import { PRESTIGE_ICONS, PRESTIGES } from "@/data/hypixel/bedwars"
import { floorLevel } from "./formatters"
export function getBedwarsStar(level: number) { export function getBedwarsStar(level: number) {
if (level < 1100) { if (level < 1100) {
@@ -15,3 +16,23 @@ export function getBedwarsStar(level: number) {
return PRESTIGE_ICONS[3].symbol return PRESTIGE_ICONS[3].symbol
} }
export function getTextColor(level: number) {
const floored = floorLevel(level, 100)
if (level > 5000) {
return PRESTIGES[PRESTIGES.length - 1].color
}
return PRESTIGES.find(l => l.level === floored)!.color
}
export function getPrestigeName(level: number) {
const floored = floorLevel(level, 100)
if (level > 5000) {
return PRESTIGES[PRESTIGES.length - 1].name
}
return PRESTIGES.find(p => p.level === floored)!.name
}

View File

@@ -7,7 +7,7 @@ const XP_PER_PRESTIGE = 96 * 5000 + EASY_LEVELS_XP
const LEVELS_PER_PRESTIGE = 100 const LEVELS_PER_PRESTIGE = 100
const HIGHEST_PRESTIGE = 10 const HIGHEST_PRESTIGE = 10
export function getBWLevel(level: number) { function getBWLevel(level: number) {
if (level > HIGHEST_PRESTIGE * LEVELS_PER_PRESTIGE) { if (level > HIGHEST_PRESTIGE * LEVELS_PER_PRESTIGE) {
return level - HIGHEST_PRESTIGE * LEVELS_PER_PRESTIGE return level - HIGHEST_PRESTIGE * LEVELS_PER_PRESTIGE
} }
@@ -15,7 +15,7 @@ export function getBWLevel(level: number) {
return level % LEVELS_PER_PRESTIGE return level % LEVELS_PER_PRESTIGE
} }
export function getBWExpForLevel(level: number) { function getBWExpForLevel(level: number) {
if (level === 0) return 0 if (level === 0) return 0
const respectedLevel = getBWLevel(level) const respectedLevel = getBWLevel(level)
@@ -53,3 +53,17 @@ export function getBWLevelForExp(exp: number) {
} }
return level + Math.floor(expWithoutPrestiges / 5000) return level + Math.floor(expWithoutPrestiges / 5000)
} }
export function getTotalExpForLevel(level: number): number {
if (level === 0) return 0
const prestiges = Math.floor(level / LEVELS_PER_PRESTIGE)
let totalExp = prestiges * XP_PER_PRESTIGE
const remainingLevels = level % LEVELS_PER_PRESTIGE
for (let i = 1; i <= remainingLevels; i += 1) {
totalExp += getBWExpForLevel(i)
}
return totalExp
}

View File

@@ -0,0 +1,7 @@
export function getProgress(min: number, mid: number, max: number) {
if (max === min) return 100
const diff = max - min
const progress = mid - min
return progress / diff * 100
}

View File

@@ -2,18 +2,18 @@ import z from "zod"
export const playerSchema = z.looseObject({ export const playerSchema = z.looseObject({
player: z.looseObject({ player: z.looseObject({
displayname: z.string(), displayname: z.string().optional(),
uuid: z.string(), uuid: z.string().optional(),
newPackageRank: z.literal("VIP").or(z.literal("VIP_PLUS").or(z.literal("MVP")).or(z.literal("MVP_PLUS"))).optional(), newPackageRank: z.string().optional(),
monthlyPackageRank: z.string().optional(), monthlyPackageRank: z.string().optional(),
rankPlusColor: z.string().optional(), rankPlusColor: z.string().optional(),
monthlyRankColor: z.literal("GOLD").or(z.literal("AQUA")).optional(), monthlyRankColor: z.string().optional(),
networkExp: z.number(), networkExp: z.number().default(0),
karma: z.number(), karma: z.number().default(0),
achievementPoints: z.number().optional(), achievementPoints: z.number().default(0),
stats: z.looseObject({ stats: z.looseObject({
Bedwars: z.looseObject({ Bedwars: z.looseObject({
Experience: z.number(), Experience: z.number().default(0),
winstreak: z.number().optional(), winstreak: z.number().optional(),
kills_bedwars: z.number().default(0), kills_bedwars: z.number().default(0),
deaths_bedwars: z.number().default(0), deaths_bedwars: z.number().default(0),
@@ -33,11 +33,11 @@ export const playerSchema = z.looseObject({
time: z.number() time: z.number()
}).optional() }).optional()
).optional() ).optional()
}) }).optional()
), ).optional(),
challenges: z.looseObject({ challenges: z.looseObject({
all_time: z.record(z.string(), z.number()) all_time: z.record(z.string(), z.number())
}), }).optional(),
lastClaimedReward: z.number().optional(), lastClaimedReward: z.number().optional(),
rewardHighScore: z.number().optional(), rewardHighScore: z.number().optional(),
rewardStreak: z.number().optional(), rewardStreak: z.number().optional(),
@@ -55,8 +55,8 @@ export const playerSchema = z.looseObject({
HYPIXEL: z.string().optional(), HYPIXEL: z.string().optional(),
TWITTER: z.string().optional(), TWITTER: z.string().optional(),
YOUTUBE: z.string().optional() YOUTUBE: z.string().optional()
}) }).optional()
}) }).optional()
}) })
}) })

View File

@@ -1,6 +1,6 @@
import { clsx, type ClassValue } from "clsx" import { type ClassValue, clsx } from "clsx"
import { twMerge } from "tailwind-merge" import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) { export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs)) return twMerge(clsx(inputs))
} }