Added more to guild stats sidebar

This commit is contained in:
2025-09-27 19:43:07 +02:00
parent b2fb358bb0
commit 0b4747da4a
4 changed files with 138 additions and 3 deletions

View File

@@ -1,19 +1,102 @@
import { GenericProgress } from "@/app/(stats)/player/[ign]/_components/generic-progress"
import { ReplaceLinks } from "@/components/link-replace" import { ReplaceLinks } from "@/components/link-replace"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Separator } from "@/components/ui/separator" import { Separator } from "@/components/ui/separator"
import { getColor } from "@/lib/colors" import { getColor } from "@/lib/colors"
import { formatDate, formatNumber } from "@/lib/formatters"
import { getGame } from "@/lib/hypixel/general/status"
import { getGuildExp, getGuildLevel } from "@/lib/hypixel/guild/level"
import { Guild } from "@/lib/schema/guild" import { Guild } from "@/lib/schema/guild"
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils"
type SidebarProps = { guild: Guild["guild"] } type SidebarProps = { guild: Guild["guild"] }
export default function Sidebar({ guild }: SidebarProps) { export default function Sidebar({ guild }: SidebarProps) {
const tagColor = getColor(guild.tagColor, "text", "gray") const textColor = getColor(guild.tagColor, "text", "gray")
const bgColor = getColor(guild.tagColor, "bg", "gray")
const level = getGuildLevel(guild.exp)
function LevelingProgress() {
const percent = (level - Math.floor(level)) * 100
const currentXp = getGuildExp(Math.floor(level))
const nextXp = getGuildExp(Math.floor(level) + 1)
return (
<div>
<p className="font-bold">Leveling Progress</p>
<div className="flex gap-2 items-center mt-2">
<p className={textColor}>{Math.floor(level)}</p>
<GenericProgress
percent={percent}
tooltipId="guild-level-progress"
tooltipContent={`${formatNumber(guild.exp - currentXp)}/${formatNumber(nextXp - currentXp)} GEXP`}
className={bgColor}
/>
<p className={textColor}>{Math.floor(level) + 1}</p>
</div>
</div>
)
}
function GeneralInfo() {
return (
<div>
<p>
<span className="font-bold">{"Level: "}</span>
<span>{formatNumber(level)}</span>
</p>
<p>
<span className="font-bold">{"Created: "}</span>
<span>{formatDate(guild.created)}</span>
</p>
<p>
<span className="font-bold">{"Legacy Rank: "}</span>
<span>{guild.legacyRanking !== undefined ? formatNumber(guild.legacyRanking) : "None"}</span>
</p>
</div>
)
}
function Other() {
return (
<div>
<p>
<span className="font-bold">{"Members: "}</span>
<span>{guild.members.length}</span>
</p>
<p>
<span className="font-bold">{"Publicly Listed: "}</span>
<span>{guild.publiclyListed === true ? "Yes" : "No"}</span>
</p>
<p>
<span className="font-bold">{"Publicly Joinable: "}</span>
<span>{guild.joinable === true ? "Yes" : "No"}</span>
</p>
</div>
)
}
function PreferedGames() {
return (
<div>
<p>
<span className="font-bold">{"Preferred Games: "}</span>
{guild.preferredGames === undefined ? <span>No prefered games</span> : (
<span>
{guild.preferredGames.map(g => {
const game = getGame(g)
return game?.name || null
}).filter(g => g !== null).sort().join(", ")}
</span>
)}
</p>
</div>
)
}
return ( return (
<Card className="mx-auto w-full lg:mx-0 lg:w-1/4 max-w-120 md:max-w-3/10"> <Card className="mx-auto w-full lg:mx-0 lg:w-1/4 max-w-120 md:max-w-3/10">
<CardHeader className="flex justify-center"> <CardHeader className="flex justify-center">
<CardTitle className={cn("text-4xl", guild.tag && tagColor)}> <CardTitle className={cn("text-4xl", guild.tag && textColor)}>
{guild.tag !== undefined ? `[${guild.tag}]` : "No Guild Tag"} {guild.tag !== undefined ? `[${guild.tag}]` : "No Guild Tag"}
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>
@@ -22,6 +105,14 @@ export default function Sidebar({ guild }: SidebarProps) {
<ReplaceLinks text={guild.description} /> : <ReplaceLinks text={guild.description} /> :
<p>No guild description.</p>} <p>No guild description.</p>}
<Separator className="my-4" /> <Separator className="my-4" />
<LevelingProgress />
<Separator className="my-4" />
<GeneralInfo />
<Separator className="my-4" />
<Other />
<Separator className="my-4" />
<PreferedGames />
<Separator className="my-4" />
</CardContent> </CardContent>
</Card> </Card>
) )

17
src/data/hypixel/guild.ts Normal file
View File

@@ -0,0 +1,17 @@
export const EXP = [
100000,
150000,
250000,
500000,
750000,
1000000,
1250000,
1500000,
2000000,
2500000,
2500000,
2500000,
2500000,
2500000,
3000000
] as const

View File

@@ -0,0 +1,21 @@
import { EXP } from "@/data/hypixel/guild"
export function getGuildLevel(xp: number) {
let xpRemaining = xp
let level = 0
let xpToLevelUp = EXP[level]
while (xpRemaining >= xpToLevelUp) {
xpRemaining -= xpToLevelUp
level++
xpToLevelUp = EXP[level > 14 ? 14 : level]
}
return level + xpRemaining / xpToLevelUp
}
export function getGuildExp(lvl: number) {
let xp = 0
for (let i = 0; i < lvl; i++) {
xp += EXP[i > 14 ? 14 : i]
}
return xp
}

View File

@@ -6,6 +6,9 @@ export const guildSchema = z.object({
name: z.string().min(1), name: z.string().min(1),
tag: z.string().optional(), tag: z.string().optional(),
tagColor: z.string().optional(), tagColor: z.string().optional(),
exp: z.number().default(0),
created: z.number(),
legacyRanking: z.number().optional(),
members: z.array(z.object({ members: z.array(z.object({
uuid: z.string(), uuid: z.string(),
rank: z.string(), rank: z.string(),
@@ -20,7 +23,10 @@ export const guildSchema = z.object({
created: z.number(), created: z.number(),
priority: z.number() priority: z.number()
})).optional(), })).optional(),
description: z.string().optional() description: z.string().optional(),
joinable: z.boolean().default(false),
publiclyListed: z.boolean().default(false),
preferredGames: z.array(z.string()).optional()
}) })
}) })