From e8d864e531b16d86dabdccaf881316de65d7096a Mon Sep 17 00:00:00 2001 From: Liam Date: Thu, 12 Sep 2024 19:09:54 +0100 Subject: [PATCH] add player stat badges --- src/components/player/player-header.tsx | 48 ++++++++------ src/components/player/player-rank-chart.tsx | 2 +- src/components/player/player-stats.tsx | 71 +++++++++++++++++++++ src/components/stat-value.tsx | 16 ++++- tailwind.config.ts | 2 +- 5 files changed, 114 insertions(+), 25 deletions(-) create mode 100644 src/components/player/player-stats.tsx diff --git a/src/components/player/player-header.tsx b/src/components/player/player-header.tsx index 440f92c..4a21adc 100644 --- a/src/components/player/player-header.tsx +++ b/src/components/player/player-header.tsx @@ -5,6 +5,7 @@ import Card from "../card"; import CountryFlag from "../country-flag"; import { Avatar, AvatarImage } from "../ui/avatar"; import ClaimProfile from "./claim-profile"; +import PlayerStats from "./player-stats"; const playerData = [ { @@ -40,33 +41,38 @@ type Props = { export default function PlayerHeader({ player }: Props) { return ( -
+
-
-

{player.name}

-
-
- {player.inactive &&

Inactive Account

} - {player.banned &&

Banned Account

} -
-
- {playerData.map((subName, index) => { - // Check if the player is inactive or banned and if the data should be shown - if (!subName.showWhenInactiveOrBanned && (player.inactive || player.banned)) { - return null; - } +
+
+

{player.name}

+
+
+ {player.inactive &&

Inactive Account

} + {player.banned &&

Banned Account

} +
+
+ {playerData.map((subName, index) => { + // Check if the player is inactive or banned and if the data should be shown + if (!subName.showWhenInactiveOrBanned && (player.inactive || player.banned)) { + return null; + } - return ( -
- {subName.icon && subName.icon(player)} - {subName.render && subName.render(player)} -
- ); - })} + return ( +
+ {subName.icon && subName.icon(player)} + {subName.render && subName.render(player)} +
+ ); + })} +
+ + +
diff --git a/src/components/player/player-rank-chart.tsx b/src/components/player/player-rank-chart.tsx index 3023b79..7a5f070 100644 --- a/src/components/player/player-rank-chart.tsx +++ b/src/components/player/player-rank-chart.tsx @@ -97,7 +97,7 @@ export default function PlayerRankChart({ player }: Props) { lineTension: 0.5, data: playerRankHistory, label: "Rank", - borderColor: "#c084fc", + borderColor: "#a147fa", fill: false, color: "#fff", }, diff --git a/src/components/player/player-stats.tsx b/src/components/player/player-stats.tsx new file mode 100644 index 0000000..24b550c --- /dev/null +++ b/src/components/player/player-stats.tsx @@ -0,0 +1,71 @@ +import ScoreSaberPlayer from "@/common/data-fetcher/types/scoresaber/scoresaber-player"; +import { formatNumberWithCommas } from "@/common/number-utils"; +import StatValue from "@/components/stat-value"; +import { ClassValue } from "clsx"; + +type Badge = { + name: string; + color?: ClassValue; + create: (player: ScoreSaberPlayer) => string | React.ReactNode | undefined; +}; + +const badges: Badge[] = [ + { + name: "Ranked Play Count", + color: "bg-pp", + create: (player: ScoreSaberPlayer) => { + return formatNumberWithCommas(player.scoreStats.rankedPlayCount); + }, + }, + { + name: "Total Ranked Score", + color: "bg-pp", + create: (player: ScoreSaberPlayer) => { + return formatNumberWithCommas(player.scoreStats.totalRankedScore); + }, + }, + { + name: "Average Ranked Accuracy", + color: "bg-pp", + create: (player: ScoreSaberPlayer) => { + return player.scoreStats.averageRankedAccuracy.toFixed(2) + "%"; + }, + }, + { + name: "Total Play Count", + create: (player: ScoreSaberPlayer) => { + return formatNumberWithCommas(player.scoreStats.totalPlayCount); + }, + }, + { + name: "Total Score", + create: (player: ScoreSaberPlayer) => { + return formatNumberWithCommas(player.scoreStats.totalScore); + }, + }, + { + name: "Total Replays Watched", + create: (player: ScoreSaberPlayer) => { + return formatNumberWithCommas(player.scoreStats.replaysWatched); + }, + }, +]; + +type Props = { + player: ScoreSaberPlayer; +}; + +export default function PlayerStats({ player }: Props) { + return ( +
+ {badges.map((badge, index) => { + const toRender = badge.create(player); + if (toRender === undefined) { + return
; + } + + return ; + })} +
+ ); +} diff --git a/src/components/stat-value.tsx b/src/components/stat-value.tsx index 1a63871..cafb08b 100644 --- a/src/components/stat-value.tsx +++ b/src/components/stat-value.tsx @@ -1,18 +1,30 @@ +import clsx, { ClassValue } from "clsx"; + type Props = { /** * The stat name. */ name?: string; + /** + * The background color of the stat. + */ + color?: ClassValue; + /** * The value of the stat. */ value: React.ReactNode; }; -export default function StatValue({ name, value }: Props) { +export default function StatValue({ name, color, value }: Props) { return ( -
+
{name && ( <>

{name}

diff --git a/tailwind.config.ts b/tailwind.config.ts index b67ee41..4b5a9cc 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -10,7 +10,7 @@ const config: Config = { theme: { extend: { colors: { - pp: "#c084fc", + pp: "#a147fa", background: "hsl(var(--background))", foreground: "hsl(var(--foreground))", card: {