mobile leaderboard fixes and hide diffs that aren't standard (for now)
Some checks failed
Deploy / deploy (push) Has been cancelled

This commit is contained in:
Lee 2024-10-01 20:18:00 +01:00
parent f60f34c0c2
commit 50414d848a
3 changed files with 67 additions and 21 deletions

@ -1,11 +1,19 @@
const diffColors: Record<string, string> = {
easy: "#3CB371",
normal: "#59b0f4",
hard: "#FF6347",
expert: "#bf2a42",
expertplus: "#8f48db",
type Difficulty = {
name: DifficultyName;
gamemode?: string;
color: string;
};
type DifficultyName = "Easy" | "Normal" | "Hard" | "Expert" | "Expert+";
const difficulties: Difficulty[] = [
{ name: "Easy", color: "#59b0f4" },
{ name: "Normal", color: "#59b0f4" },
{ name: "Hard", color: "#FF6347" },
{ name: "Expert", color: "#bf2a42" },
{ name: "Expert+", color: "#8f48db" },
];
export type ScoreBadge = {
name: string;
min: number | null;
@ -14,11 +22,11 @@ export type ScoreBadge = {
};
const scoreBadges: ScoreBadge[] = [
{ name: "SS+", min: 95, max: null, color: diffColors.expertplus },
{ name: "SS", min: 90, max: 95, color: diffColors.expert },
{ name: "S+", min: 85, max: 90, color: diffColors.hard },
{ name: "S", min: 80, max: 85, color: diffColors.normal },
{ name: "A", min: 70, max: 80, color: diffColors.easy },
{ name: "SS+", min: 95, max: null, color: getDifficulty("Expert+")!.color },
{ name: "SS", min: 90, max: 95, color: getDifficulty("Expert")!.color },
{ name: "S+", min: 85, max: 90, color: getDifficulty("Hard")!.color },
{ name: "S", min: 80, max: 85, color: getDifficulty("Normal")!.color },
{ name: "A", min: 70, max: 80, color: getDifficulty("Easy")!.color },
{ name: "-", min: null, max: 70, color: "hsl(var(--accent))" },
];
@ -49,6 +57,39 @@ export function getScoreBadgeFromAccuracy(acc: number): ScoreBadge {
return scoreBadges[scoreBadges.length - 1];
}
/**
* Parses a raw difficulty into a {@link Difficulty}
* Example: _Easy_SoloStandard -> { name: "Easy", type: "Standard", color: "#59b0f4" }
*
* @param rawDifficulty the raw difficulty to parse
* @return the parsed difficulty
*/
export function getDifficultyFromRawDifficulty(rawDifficulty: string): Difficulty {
const [name, ...type] = rawDifficulty
.replace("Plus", "+") // Replaces Plus with + so we can match it to our difficulty names
.replace("Solo", "") // Removes "Solo"
.replace(/^_+|_+$/g, "") // Removes leading and trailing underscores
.split("_");
const difficulty = difficulties.find(d => d.name === name);
if (!difficulty) {
throw new Error(`Unknown difficulty: ${rawDifficulty}`);
}
return {
...difficulty,
gamemode: type.join("_"),
};
}
/**
* Gets a {@link Difficulty} from its name
*
* @param diff the name of the difficulty
* @returns the difficulty
*/
export function getDifficulty(diff: DifficultyName) {
return difficulties.find(d => d.name === diff);
}
/**
* Turns the difficulty of a song into a color
*
@ -56,6 +97,5 @@ export function getScoreBadgeFromAccuracy(acc: number): ScoreBadge {
* @returns the color for the difficulty
*/
export function songDifficultyToColor(diff: string) {
diff = diff.replace("+", "Plus");
return diffColors[diff.toLowerCase() as keyof typeof diffColors];
return getDifficultyFromRawDifficulty(diff).color;
}

@ -48,7 +48,7 @@ export function LeaderboardInfo({ leaderboard, beatSaverMap }: LeaderboardInfoPr
<Image
src={leaderboard.coverImage}
alt={`${leaderboard.songName} Cover Image`}
className="rounded-md w-fit h-fit"
className="rounded-md w-[96px] h-[96px]"
width={96}
height={96}
/>

@ -13,8 +13,8 @@ import LeaderboardScore from "./leaderboard-score";
import { scoreAnimation } from "@/components/score/score-animation";
import ScoreSaberPlayer from "@/common/model/player/impl/scoresaber-player";
import { Button } from "@/components/ui/button";
import { getDifficultyFromScoreSaberDifficulty } from "@/common/scoresaber-utils";
import { clsx } from "clsx";
import { getDifficultyFromRawDifficulty } from "@/common/song-utils";
type LeaderboardScoresProps = {
/**
@ -130,14 +130,14 @@ export default function LeaderboardScores({
* scores when new scores are loaded.
*/
useEffect(() => {
if (topOfScoresRef.current) {
if (topOfScoresRef.current && shouldFetch) {
const topOfScoresPosition = topOfScoresRef.current.getBoundingClientRect().top + window.scrollY;
window.scrollTo({
top: topOfScoresPosition - 75, // Navbar height (plus some padding)
behavior: "smooth",
});
}
}, [currentPage, topOfScoresRef]);
}, [currentPage, topOfScoresRef, shouldFetch]);
if (currentScores === undefined) {
return undefined;
@ -153,18 +153,24 @@ export default function LeaderboardScores({
{currentScores.scores.length === 0 && <p>No scores found. Invalid Page?</p>}
</div>
<div className="flex gap-2 justify-center items-center">
<div className="flex gap-2 justify-center items-center flex-wrap">
{showDifficulties &&
leaderboard.difficulties.map(({ difficulty, leaderboardId }) => {
leaderboard.difficulties.map(({ difficultyRaw, leaderboardId }) => {
const difficulty = getDifficultyFromRawDifficulty(difficultyRaw);
// todo: add support for other gamemodes?
if (difficulty.gamemode !== "Standard") {
return null;
}
return (
<Button
key={difficulty}
key={difficultyRaw}
variant={leaderboardId === selectedLeaderboardId ? "default" : "outline"}
onClick={() => {
handleLeaderboardChange(leaderboardId);
}}
>
{getDifficultyFromScoreSaberDifficulty(difficulty)}
{difficulty.name}
</Button>
);
})}