This commit is contained in:
parent
6c809696ea
commit
63199cace6
@ -5,6 +5,7 @@ import Card from "@/components/Card";
|
||||
import Container from "@/components/Container";
|
||||
import Label from "@/components/Label";
|
||||
import Pagination from "@/components/Pagination";
|
||||
import PlayerChart from "@/components/PlayerChart";
|
||||
import ScoreStatLabel from "@/components/ScoreStatLabel";
|
||||
import { Spinner } from "@/components/Spinner";
|
||||
import { ScoresaberPlayer } from "@/schemas/scoresaber/player";
|
||||
@ -135,7 +136,7 @@ export default function Player({ params }: { params: { id: string } }) {
|
||||
<Avatar url={playerData.profilePicture} label="Avatar" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-1 flex flex-col items-center gap-2 xs:items-start">
|
||||
<div className="mt-1 flex w-full flex-col items-center gap-2 xs:items-start">
|
||||
<p className="text-2xl">{playerData.name}</p>
|
||||
|
||||
<div className="flex gap-3 text-xl">
|
||||
@ -184,6 +185,8 @@ export default function Player({ params }: { params: { id: string } }) {
|
||||
value={formatNumber(playerData.scoreStats.replaysWatched)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<PlayerChart scoresaber={player.player} />
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
121
src/components/PlayerChart.tsx
Normal file
121
src/components/PlayerChart.tsx
Normal file
@ -0,0 +1,121 @@
|
||||
import { ScoresaberPlayer } from "@/schemas/scoresaber/player";
|
||||
import { formatNumber } from "@/utils/number";
|
||||
import {
|
||||
CategoryScale,
|
||||
Chart as ChartJS,
|
||||
Legend,
|
||||
LineElement,
|
||||
LinearScale,
|
||||
PointElement,
|
||||
Title,
|
||||
Tooltip,
|
||||
} from "chart.js";
|
||||
import { Line } from "react-chartjs-2";
|
||||
|
||||
ChartJS.register(
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
PointElement,
|
||||
LineElement,
|
||||
Title,
|
||||
Tooltip,
|
||||
Legend,
|
||||
);
|
||||
|
||||
type PlayerChartProps = {
|
||||
className?: string;
|
||||
scoresaber: ScoresaberPlayer;
|
||||
};
|
||||
|
||||
export const options: any = {
|
||||
maintainAspectRatio: false,
|
||||
aspectRatio: 1,
|
||||
interaction: {
|
||||
mode: "index",
|
||||
intersect: false,
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
ticks: {
|
||||
autoSkip: true,
|
||||
maxTicksLimit: 4,
|
||||
},
|
||||
reverse: true,
|
||||
},
|
||||
x: {
|
||||
ticks: {
|
||||
autoSkip: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
elements: {
|
||||
point: {
|
||||
radius: 0,
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
position: "top" as const,
|
||||
labels: {
|
||||
color: "white",
|
||||
},
|
||||
},
|
||||
title: {
|
||||
display: false,
|
||||
},
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
label(context: any) {
|
||||
switch (context.dataset.label) {
|
||||
case "Rank": {
|
||||
return `Rank #${formatNumber(context.parsed.y.toFixed(0))}`;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default function PlayerChart({
|
||||
className,
|
||||
scoresaber,
|
||||
}: PlayerChartProps) {
|
||||
const history: number[] = scoresaber.histories
|
||||
.split(",")
|
||||
.map(function (item) {
|
||||
return parseInt(item);
|
||||
});
|
||||
|
||||
let labels = [];
|
||||
for (let i = history.length; i > 0; i--) {
|
||||
let label = `${i} days ago`;
|
||||
if (i === 1) {
|
||||
label = "now";
|
||||
}
|
||||
if (i === 2) {
|
||||
label = "yesterday";
|
||||
}
|
||||
labels.push(label);
|
||||
}
|
||||
|
||||
const data = {
|
||||
labels,
|
||||
datasets: [
|
||||
{
|
||||
lineTension: 0.4,
|
||||
data: history,
|
||||
label: "Rank",
|
||||
borderColor: "#3e95cd",
|
||||
fill: false,
|
||||
color: "#fff",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="h-[280px] w-full">
|
||||
<Line className={className} options={options} data={data} />
|
||||
</div>
|
||||
);
|
||||
}
|
@ -22,6 +22,7 @@ export default function SearchPlayer() {
|
||||
}, [search]);
|
||||
|
||||
async function searchPlayer(search: string) {
|
||||
// Check if the search is a profile link
|
||||
if (search.startsWith("https://scoresaber.com/u/")) {
|
||||
const id = search.split("/").pop();
|
||||
if (id == undefined) return;
|
||||
@ -31,6 +32,8 @@ export default function SearchPlayer() {
|
||||
|
||||
setPlayers([player]);
|
||||
}
|
||||
|
||||
// Search by name
|
||||
const players = await searchByName(search);
|
||||
if (players == undefined) return;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user