made the player page look much nicer
All checks were successful
Deploy Website / docker (ubuntu-latest) (push) Successful in 2m23s

This commit is contained in:
Lee 2024-10-28 16:22:33 +00:00
parent f156b7f582
commit 1c2214a659
8 changed files with 112 additions and 81 deletions

@ -21,7 +21,7 @@ export function HandAccuracyBadge({ score, hand }: HandAccuracyProps) {
const formattedHand = capitalizeFirstLetter(hand);
return (
<div className="flex flex-col items-center justify-center">
<div className="flex gap-1 items-center justify-center">
<Tooltip
display={
<>

@ -1,9 +1,7 @@
import { formatNumberWithCommas } from "@ssr/common/utils/number-utils";
import { PauseIcon } from "@heroicons/react/24/solid";
import { ScoreBadgeProps } from "@/components/score/badges/badge-props";
import { ScoreMissesTooltip } from "@/components/score/score-misses-tooltip";
import { Misses } from "@ssr/common/model/additional-score-data/misses";
import Tooltip from "@/components/tooltip";
type ScoreMissesBadgeProps = ScoreBadgeProps & {
/**
@ -33,6 +31,7 @@ export default function ScoreMissesAndPausesBadge({ score, hideXMark }: ScoreMis
const pauses = additionalData?.pauses;
return (
<div className="flex flex-col justify-center items-center w-full">
<div className="flex items-center gap-1">
<div className="flex items-center gap-1">
<ScoreMissesTooltip
missedNotes={score.missedNotes}
@ -41,33 +40,12 @@ export default function ScoreMissesAndPausesBadge({ score, hideXMark }: ScoreMis
wallsHit={misses?.wallsHit}
fullCombo={score.fullCombo}
>
<div className="flex items-center">
<p>
{score.fullCombo ? <span className="text-green-400">FC</span> : formatNumberWithCommas(score.misses)}
{!hideXMark && !score.fullCombo && <span>x</span>}
</p>
</div>
</ScoreMissesTooltip>
{additionalData && !!pauses && pauses > 0 && (
<>
<p>|</p>
<Tooltip
display={
<p>
{pauses}x Pause{pauses > 1 ? "s" : ""}
</p>
}
>
<div className="flex gap-1 items-center">
<p>{pauses && pauses}</p>
<PauseIcon className="w-4 h-4" />
</div>
</Tooltip>
</>
)}
</div>
{additionalData && previousScoreMisses && scoreImprovement && misses && isMissImprovement && (
<div className="flex gap-2 items-center justify-center">
<ScoreMissesTooltip
missedNotes={previousScoreMisses.missedNotes}
badCuts={previousScoreMisses.badCuts}
@ -75,28 +53,61 @@ export default function ScoreMissesAndPausesBadge({ score, hideXMark }: ScoreMis
wallsHit={previousScoreMisses.wallsHit}
fullCombo={previousScoreFc}
>
<div className="flex gap-1 items-center text-xs">
{previousScoreFc ? (
<p className="text-green-400">FC</p>
) : (
formatNumberWithCommas(previousScoreMisses.misses)
)}
<div className="text-xs flex flex-row gap-1">
<p>(vs {previousScoreFc ? "FC" : formatNumberWithCommas(previousScoreMisses.misses)}x)</p>
</div>
</ScoreMissesTooltip>
<p>-&gt;</p>
<ScoreMissesTooltip
missedNotes={misses.missedNotes}
badCuts={misses.badCuts}
bombCuts={misses.bombCuts}
wallsHit={misses.wallsHit}
fullCombo={additionalData.fullCombo}
>
<div className="flex gap-1 items-center text-xs">
{additionalData.fullCombo ? <p className="text-green-400">FC</p> : formatNumberWithCommas(misses.misses)}
</div>
</ScoreMissesTooltip>
</div>
)}
</div>
{/*{additionalData && !!pauses && pauses > 0 && (*/}
{/* <>*/}
{/* <p>|</p>*/}
{/* <Tooltip*/}
{/* display={*/}
{/* <p>*/}
{/* {pauses}x Pause{pauses > 1 ? "s" : ""}*/}
{/* </p>*/}
{/* }*/}
{/* >*/}
{/* <div className="flex gap-1 items-center">*/}
{/* <p>{pauses && pauses}</p>*/}
{/* <PauseIcon className="w-4 h-4" />*/}
{/* </div>*/}
{/* </Tooltip>*/}
{/* </>*/}
{/*)}*/}
</div>
{/*{additionalData && previousScoreMisses && scoreImprovement && misses && isMissImprovement && (*/}
{/* <div className="flex gap-2 items-center justify-center">*/}
{/* <ScoreMissesTooltip*/}
{/* missedNotes={previousScoreMisses.missedNotes}*/}
{/* badCuts={previousScoreMisses.badCuts}*/}
{/* bombCuts={previousScoreMisses.bombCuts}*/}
{/* wallsHit={previousScoreMisses.wallsHit}*/}
{/* fullCombo={previousScoreFc}*/}
{/* >*/}
{/* <div className="flex gap-1 items-center text-xs">*/}
{/* {previousScoreFc ? (*/}
{/* <p className="text-green-400">FC</p>*/}
{/* ) : (*/}
{/* formatNumberWithCommas(previousScoreMisses.misses)*/}
{/* )}*/}
{/* </div>*/}
{/* </ScoreMissesTooltip>*/}
{/* <p>-&gt;</p>*/}
{/* <ScoreMissesTooltip*/}
{/* missedNotes={misses.missedNotes}*/}
{/* badCuts={misses.badCuts}*/}
{/* bombCuts={misses.bombCuts}*/}
{/* wallsHit={misses.wallsHit}*/}
{/* fullCombo={additionalData.fullCombo}*/}
{/* >*/}
{/* <div className="flex gap-1 items-center text-xs">*/}
{/* {additionalData.fullCombo ? <p className="text-green-400">FC</p> : formatNumberWithCommas(misses.misses)}*/}
{/* </div>*/}
{/* </ScoreMissesTooltip>*/}
{/* </div>*/}
{/*)}*/}
</div>
);
}

@ -1,6 +1,6 @@
import StatValue from "@/components/stat-value";
import { ScoreSaberScore } from "@ssr/common/model/score/impl/scoresaber-score";
import ScoreSaberLeaderboard from "@ssr/common/model/leaderboard/impl/scoresaber-leaderboard";
import clsx from "clsx";
/**
* A badge to display in the score stats.
@ -27,6 +27,19 @@ export function ScoreBadges({ badges, score, leaderboard }: ScoreBadgeProps) {
if (toRender === undefined) {
return <div key={index} />;
}
return <StatValue key={index} color={color} value={toRender} />;
return (
<div
key={index}
className={clsx(
"flex h-fit p-1 items-center justify-center rounded-md text-sm cursor-default",
color ? color : "bg-accent"
)}
style={{
backgroundColor: (!color?.includes("bg") && color) || undefined,
}}
>
{toRender}
</div>
);
});
}

@ -63,7 +63,7 @@ export default function ScoreSongInfo({ leaderboard, beatSaverMap }: Props) {
>
{leaderboard.songName} {leaderboard.songSubName}
</Link>
<div className="flex flex-col text-sm">
<div className="flex flex-row text-sm gap-2">
<p className="text-gray-400">{leaderboard.songAuthorName}</p>
<FallbackLink
href={mappersProfile}

@ -72,8 +72,10 @@ type Props = {
export default function ScoreStats({ score, leaderboard }: Props) {
return (
<div className={`grid grid-cols-3 grid-rows-2 gap-1 ml-0 lg:ml-2 `}>
<div className="flex flex-col justify-center h-full">
<div className={`grid grid-cols-3 gap-1 ml-0 lg:ml-2 justify-center`}>
<ScoreBadges badges={badges} score={score} leaderboard={leaderboard} />
</div>
</div>
);
}

@ -120,12 +120,12 @@ export default function Score({ leaderboard, beatSaverMap, score, settings, high
};
const gridColsClass = settings?.noScoreButtons
? "grid-cols-[20px 1fr_1fr] lg:grid-cols-[0.5fr_4fr_300px]" // Fewer columns if no buttons
: "grid-cols-[20px 1fr_1fr] lg:grid-cols-[0.5fr_4fr_1fr_300px]"; // Original with buttons
? "grid-cols-[20px 1fr_1fr] lg:grid-cols-[0.5fr_4fr_350px]" // Fewer columns if no buttons
: "grid-cols-[20px 1fr_1fr] lg:grid-cols-[0.5fr_4fr_1fr_350px]"; // Original with buttons
return (
<div className="pb-2 pt-2">
<div className={`grid w-full gap-2 lg:gap-0 ${gridColsClass}`}>
<div className="pb-2 pt-2 w-full h-full">
<div className={`grid w-full h-full gap-2 lg:gap-0 ${gridColsClass}`}>
<ScoreRankInfo score={score} leaderboard={leaderboard} />
<ScoreSongInfo leaderboard={leaderboard} beatSaverMap={beatSaverMap} />
{!settings?.noScoreButtons && (

@ -16,18 +16,24 @@ type Props = {
*/
color?: string;
/**
* The additional classes for the stat.
*/
className?: string;
/**
* The value of the stat.
*/
value: React.ReactNode;
};
export default function StatValue({ name, icon, color, value }: Props) {
export default function StatValue({ name, icon, color, className, value }: Props) {
return (
<div
className={clsx(
"flex min-w-16 gap-2 h-full p-1 items-center justify-center rounded-md text-sm cursor-default",
color ? color : "bg-accent"
color ? color : "bg-accent",
className
)}
style={{
backgroundColor: (!color?.includes("bg") && color) || undefined,

@ -2,7 +2,7 @@
import { Tooltip as ShadCnTooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip";
import { useState } from "react";
import { cn } from "@/common/utils";
import { clsx } from "clsx";
type Props = {
/**
@ -36,16 +36,15 @@ export default function Tooltip({ children, display, asChild = true, side = "top
return (
<ShadCnTooltip open={open}>
<TooltipTrigger className={className} asChild={asChild}>
<div
className={cn("cursor-default", className)}
<TooltipTrigger
className={clsx("cursor-default", className)}
asChild={asChild}
onMouseEnter={() => setOpen(true)}
onMouseLeave={() => setOpen(false)}
onTouchStart={() => setOpen(!open)}
onTouchEnd={() => setOpen(!open)}
>
{children}
</div>
</TooltipTrigger>
<TooltipContent className="max-w-[350px]" side={side}>
{display}