wish me luck
Some checks failed
Deploy / deploy (push) Failing after 1m22s

This commit is contained in:
Lee
2024-09-28 05:57:35 +01:00
parent 39526dde41
commit 2f18f0f096
25 changed files with 1812 additions and 85 deletions

View File

@ -35,7 +35,7 @@ export default function PlayerData({
});
if (data && (!isLoading || !isError)) {
player = data;
player = data.player;
}
return (
@ -55,7 +55,7 @@ export default function PlayerData({
page={page}
/>
</article>
<aside className="w-[550px] hidden xl:flex flex-col gap-2">
<aside className="w-[550px] hidden 2xl:flex flex-col gap-2">
<Mini type="Global" player={player} />
<Mini type="Country" player={player} />
</aside>

View File

@ -14,6 +14,7 @@ import {
} from "chart.js";
import { Line } from "react-chartjs-2";
import ScoreSaberPlayer from "@/common/model/player/impl/scoresaber-player";
import { getDaysAgo, parseDate } from "@/common/time-utils";
Chart.register(
LinearScale,
@ -25,6 +26,104 @@ Chart.register(
Legend,
);
/**
* A ChartJS axis
*/
type Axis = {
id: string;
position: "left" | "right";
display: boolean;
grid?: { color?: string; drawOnChartArea?: boolean };
title?: { display: boolean; text: string; color?: string };
ticks?: {
stepSize: number;
};
reverse: boolean;
};
/**
* A ChartJS dataset
*/
type Dataset = {
label: string;
data: number[];
borderColor: string;
fill: boolean;
lineTension: number;
spanGaps: boolean;
yAxisID: string;
};
/**
* Generate an axis
*
* @param id the id of the axis
* @param display if the axis should be displayed
* @param position the position of the axis
* @param displayName the optional name to display for the axis
*/
const generateAxis = (
id: string,
display: boolean,
position: "right" | "left",
displayName: string,
): Axis => ({
id,
position,
display,
grid: {
drawOnChartArea: id === "y",
color: id === "y" ? "#252525" : "",
},
title: {
display: true,
text: displayName,
color: "#ffffff",
},
ticks: {
stepSize: 10,
},
reverse: true,
});
/**
* Create the axes
*/
const createAxes = () => ({
x: {
grid: {
color: "#252525", // gray grid lines
},
reverse: true,
},
y: generateAxis("y", true, "left", "Global Rank"), // Rank axis with display name
y1: generateAxis("y1", false, "left", "Country Rank"), // Country Rank axis with display name
y2: generateAxis("y2", true, "right", "PP"), // PP axis with display name
});
/**
* Generate a dataset
*
* @param label the label of the dataset
* @param data the data of the dataset
* @param borderColor the border color of the dataset
* @param yAxisID the ID of the y-axis
*/
const generateDataset = (
label: string,
data: number[],
borderColor: string,
yAxisID: string,
): Dataset => ({
label,
data,
borderColor,
fill: false,
lineTension: 0.5,
spanGaps: true,
yAxisID,
});
export const options: any = {
maintainAspectRatio: false,
aspectRatio: 1,
@ -32,29 +131,7 @@ export const options: any = {
mode: "index",
intersect: false,
},
scales: {
y: {
ticks: {
autoSkip: true,
maxTicksLimit: 8,
stepSize: 1,
},
grid: {
// gray grid lines
color: "#252525",
},
reverse: true,
},
x: {
ticks: {
autoSkip: true,
},
grid: {
// gray grid lines
color: "#252525",
},
},
},
scales: createAxes(), // Use createAxes to configure axes
elements: {
point: {
radius: 0,
@ -67,9 +144,6 @@ export const options: any = {
color: "white",
},
},
title: {
display: false,
},
tooltip: {
callbacks: {
label(context: any) {
@ -77,6 +151,12 @@ export const options: any = {
case "Rank": {
return `Rank #${formatNumberWithCommas(Number(context.parsed.y))}`;
}
case "Country Rank": {
return `Country Rank #${formatNumberWithCommas(Number(context.parsed.y))}`;
}
case "PP": {
return `PP ${formatNumberWithCommas(Number(context.parsed.y))}pp`;
}
}
},
},
@ -89,30 +169,50 @@ type Props = {
};
export default function PlayerRankChart({ player }: Props) {
const labels = [];
for (let i = player.rankHistory.length; i > 0; i--) {
let label = `${i} days ago`;
if (i === 1) {
label = "now";
}
if (i === 2) {
label = "yesterday";
}
labels.push(label);
if (
player.statisticHistory === undefined ||
Object.keys(player.statisticHistory).length === 0
) {
return (
<div className="flex justify-center">
<p>Unable to load player rank chart, missing data...</p>
</div>
);
}
const labels: string[] = [];
const histories: Record<"rank" | "countryRank" | "pp", number[]> = {
rank: [],
countryRank: [],
pp: [],
};
// Create labels and history data
for (const [dateString, history] of Object.entries(player.statisticHistory)) {
const daysAgo = getDaysAgo(parseDate(dateString));
// Create labels based on days ago
if (daysAgo === 0) {
labels.push("Today");
} else if (daysAgo === 1) {
labels.push("Yesterday");
} else {
labels.push(`${daysAgo} days ago`);
}
history.rank && histories.rank.push(history.rank);
history.countryRank && histories.countryRank.push(history.countryRank);
history.pp && histories.pp.push(history.pp);
}
const datasets: Dataset[] = [
generateDataset("Rank", histories["rank"], "#3EC1D3", "y"),
generateDataset("Country Rank", histories["countryRank"], "#FFEA00", "y1"),
generateDataset("PP", histories["pp"], "#606fff", "y2"),
];
const data = {
labels,
datasets: [
{
lineTension: 0.5,
data: player.rankHistory,
label: "Rank",
borderColor: "#606fff",
fill: false,
color: "#fff",
},
],
datasets,
};
return (

View File

@ -12,7 +12,7 @@ import { Avatar, AvatarImage } from "../ui/avatar";
import ScoreSaberPlayer from "@/common/model/player/impl/scoresaber-player";
const REFRESH_INTERVAL = 5 * 60 * 1000; // 5 minutes
const PLAYER_NAME_MAX_LENGTH = 14;
const PLAYER_NAME_MAX_LENGTH = 18;
type MiniProps = {
type: "Global" | "Country";