This commit is contained in:
parent
ebb91344bc
commit
6b30c6efed
@ -56,6 +56,7 @@ export default function PlayerScoreAccuracyChart({ scoreStats, leaderboard }: Pr
|
|||||||
axisConfig: {
|
axisConfig: {
|
||||||
reverse: false,
|
reverse: false,
|
||||||
display: true,
|
display: true,
|
||||||
|
hideOnMobile: true,
|
||||||
displayName: "PP",
|
displayName: "PP",
|
||||||
position: "right",
|
position: "right",
|
||||||
},
|
},
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
import BeatSaverLogo from "@/components/logos/beatsaver-logo";
|
||||||
|
import ScoreButton from "@/components/score/button/score-button";
|
||||||
|
import * as React from "react";
|
||||||
|
import { BeatSaverMap } from "@ssr/common/model/beatsaver/map";
|
||||||
|
|
||||||
|
type BeatSaverMapProps = {
|
||||||
|
beatSaverMap: BeatSaverMap;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function BeatSaverMapButton({ beatSaverMap }: BeatSaverMapProps) {
|
||||||
|
return (
|
||||||
|
<ScoreButton
|
||||||
|
onClick={() => {
|
||||||
|
window.open(`https://beatsaver.com/maps/${beatSaverMap.bsr}`, "_blank");
|
||||||
|
}}
|
||||||
|
tooltip={<p>Click to open the map</p>}
|
||||||
|
>
|
||||||
|
<BeatSaverLogo />
|
||||||
|
</ScoreButton>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { copyToClipboard } from "@/common/browser-utils";
|
||||||
|
import ScoreButton from "@/components/score/button/score-button";
|
||||||
|
import { BeatSaverMap } from "@ssr/common/model/beatsaver/map";
|
||||||
|
import * as React from "react";
|
||||||
|
import { toast } from "@/hooks/use-toast";
|
||||||
|
|
||||||
|
type ScoreBsrButtonProps = {
|
||||||
|
beatSaverMap: BeatSaverMap;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function ScoreBsrButton({ beatSaverMap }: ScoreBsrButtonProps) {
|
||||||
|
return (
|
||||||
|
<ScoreButton
|
||||||
|
onClick={() => {
|
||||||
|
toast({
|
||||||
|
title: "Copied!",
|
||||||
|
description: `Copied "!bsr ${beatSaverMap.bsr}" to your clipboard!`,
|
||||||
|
});
|
||||||
|
copyToClipboard(`!bsr ${beatSaverMap.bsr}`);
|
||||||
|
}}
|
||||||
|
tooltip={<p>Click to copy the bsr code</p>}
|
||||||
|
>
|
||||||
|
<p>!</p>
|
||||||
|
</ScoreButton>
|
||||||
|
);
|
||||||
|
}
|
@ -6,8 +6,8 @@ import { Slider } from "@/components/ui/slider";
|
|||||||
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
||||||
import { ResetIcon } from "@radix-ui/react-icons";
|
import { ResetIcon } from "@radix-ui/react-icons";
|
||||||
import Tooltip from "@/components/tooltip";
|
import Tooltip from "@/components/tooltip";
|
||||||
import { ScoreSaberScore } from "@ssr/common/model/score/impl/scoresaber-score";
|
import { ScoreSaberScore } from "@ssr/common/dist/model/score/impl/scoresaber-score.ts";
|
||||||
import ScoreSaberLeaderboard from "@ssr/common/model/leaderboard/impl/scoresaber-leaderboard";
|
import ScoreSaberLeaderboard from "@ssr/common/dist/model/leaderboard/impl/scoresaber-leaderboard.ts";
|
||||||
|
|
||||||
type ScoreEditorButtonProps = {
|
type ScoreEditorButtonProps = {
|
||||||
score: ScoreSaberScore;
|
score: ScoreSaberScore;
|
@ -0,0 +1,21 @@
|
|||||||
|
import BeatSaberPepeLogo from "@/components/logos/beatsaber-pepe-logo";
|
||||||
|
import ScoreButton from "@/components/score/button/score-button";
|
||||||
|
import * as React from "react";
|
||||||
|
import { AdditionalScoreData } from "@ssr/common/model/additional-score-data/additional-score-data";
|
||||||
|
|
||||||
|
type ScoreReplayButton = {
|
||||||
|
additionalData: AdditionalScoreData;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function ScoreReplayButton({ additionalData }: ScoreReplayButton) {
|
||||||
|
return (
|
||||||
|
<ScoreButton
|
||||||
|
onClick={() => {
|
||||||
|
window.open(`https://replay.beatleader.xyz/?scoreId=${additionalData.scoreId}`, "_blank");
|
||||||
|
}}
|
||||||
|
tooltip={<p>Click to view the score replay!</p>}
|
||||||
|
>
|
||||||
|
<BeatSaberPepeLogo />
|
||||||
|
</ScoreButton>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
import { songNameToYouTubeLink } from "@/common/youtube-utils";
|
||||||
|
import YouTubeLogo from "@/components/logos/youtube-logo";
|
||||||
|
import ScoreButton from "@/components/score/button/score-button";
|
||||||
|
import { ScoreSaberLeaderboard } from "@ssr/common/model/leaderboard/impl/scoresaber-leaderboard";
|
||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
type SongOpenInYoutubeButtonProps = {
|
||||||
|
leaderboard: ScoreSaberLeaderboard;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function SongOpenInYoutubeButton({ leaderboard }: SongOpenInYoutubeButtonProps) {
|
||||||
|
return (
|
||||||
|
<ScoreButton
|
||||||
|
onClick={() => {
|
||||||
|
window.open(
|
||||||
|
songNameToYouTubeLink(leaderboard.songName, leaderboard.songSubName, leaderboard.songAuthorName),
|
||||||
|
"_blank"
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
tooltip={<p>Click to open the song in YouTube</p>}
|
||||||
|
>
|
||||||
|
<YouTubeLogo />
|
||||||
|
</ScoreButton>
|
||||||
|
);
|
||||||
|
}
|
@ -1,20 +1,17 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { songNameToYouTubeLink } from "@/common/youtube-utils";
|
|
||||||
import BeatSaverLogo from "@/components/logos/beatsaver-logo";
|
|
||||||
import YouTubeLogo from "@/components/logos/youtube-logo";
|
|
||||||
import { useToast } from "@/hooks/use-toast";
|
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import ScoreButton from "./score-button";
|
|
||||||
import { copyToClipboard } from "@/common/browser-utils";
|
|
||||||
import { ArrowDownIcon, ArrowPathIcon } from "@heroicons/react/24/solid";
|
import { ArrowDownIcon, ArrowPathIcon } from "@heroicons/react/24/solid";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import ScoreEditorButton from "@/components/score/score-editor-button";
|
import ScoreEditorButton from "@/components/score/button/score-editor-button";
|
||||||
|
import { ScoreBsrButton } from "@/components/score/button/score-bsr-button";
|
||||||
|
import { BeatSaverMapButton } from "@/components/score/button/beat-saver-map-button";
|
||||||
|
import { SongOpenInYoutubeButton } from "@/components/score/button/song-open-in-youtube-button";
|
||||||
import { ScoreSaberScore } from "@ssr/common/model/score/impl/scoresaber-score";
|
import { ScoreSaberScore } from "@ssr/common/model/score/impl/scoresaber-score";
|
||||||
import ScoreSaberLeaderboard from "@ssr/common/model/leaderboard/impl/scoresaber-leaderboard";
|
import { ScoreSaberLeaderboard } from "@ssr/common/model/leaderboard/impl/scoresaber-leaderboard";
|
||||||
import { BeatSaverMap } from "@ssr/common/model/beatsaver/map";
|
import { BeatSaverMap } from "@ssr/common/model/beatsaver/map";
|
||||||
import BeatSaberPepeLogo from "@/components/logos/beatsaber-pepe-logo";
|
import { ScoreReplayButton } from "@/components/score/button/score-replay-button";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
score?: ScoreSaberScore;
|
score?: ScoreSaberScore;
|
||||||
@ -33,78 +30,39 @@ export default function ScoreButtons({
|
|||||||
leaderboard,
|
leaderboard,
|
||||||
beatSaverMap,
|
beatSaverMap,
|
||||||
alwaysSingleLine,
|
alwaysSingleLine,
|
||||||
|
setIsLeaderboardExpanded,
|
||||||
|
isLeaderboardLoading,
|
||||||
|
updateScore,
|
||||||
hideLeaderboardDropdown,
|
hideLeaderboardDropdown,
|
||||||
hideAccuracyChanger,
|
hideAccuracyChanger,
|
||||||
isLeaderboardLoading,
|
|
||||||
setIsLeaderboardExpanded,
|
|
||||||
updateScore,
|
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const [leaderboardExpanded, setLeaderboardExpanded] = useState(false);
|
const [leaderboardExpanded, setLeaderboardExpanded] = useState(false);
|
||||||
const { toast } = useToast();
|
|
||||||
|
|
||||||
const additionalData = score?.additionalData;
|
const additionalData = score?.additionalData;
|
||||||
return (
|
return (
|
||||||
<div className={`flex justify-end gap-2 items-center`}>
|
<div className={`flex justify-end gap-2 items-center mr-1`}>
|
||||||
<div
|
<div className={`flex lg:grid grid-cols-3 gap-1 items-center justify-center min-w-[92px]`}>
|
||||||
className={`flex ${alwaysSingleLine ? "flex-nowrap" : "flex-wrap"} items-center lg:items-start justify-center lg:justify-end gap-1`}
|
|
||||||
>
|
|
||||||
{beatSaverMap != undefined && (
|
{beatSaverMap != undefined && (
|
||||||
<>
|
<>
|
||||||
{/* Copy BSR */}
|
<ScoreBsrButton beatSaverMap={beatSaverMap} />
|
||||||
<ScoreButton
|
<BeatSaverMapButton beatSaverMap={beatSaverMap} />
|
||||||
onClick={() => {
|
|
||||||
toast({
|
|
||||||
title: "Copied!",
|
|
||||||
description: `Copied "!bsr ${beatSaverMap.bsr}" to your clipboard!`,
|
|
||||||
});
|
|
||||||
copyToClipboard(`!bsr ${beatSaverMap.bsr}`);
|
|
||||||
}}
|
|
||||||
tooltip={<p>Click to copy the bsr code</p>}
|
|
||||||
>
|
|
||||||
<p>!</p>
|
|
||||||
</ScoreButton>
|
|
||||||
|
|
||||||
{/* Open map in BeatSaver */}
|
|
||||||
<ScoreButton
|
|
||||||
onClick={() => {
|
|
||||||
window.open(`https://beatsaver.com/maps/${beatSaverMap.bsr}`, "_blank");
|
|
||||||
}}
|
|
||||||
tooltip={<p>Click to open the map</p>}
|
|
||||||
>
|
|
||||||
<BeatSaverLogo />
|
|
||||||
</ScoreButton>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Open song in YouTube */}
|
<SongOpenInYoutubeButton leaderboard={leaderboard} />
|
||||||
<ScoreButton
|
|
||||||
onClick={() => {
|
<div className="hidden lg:block" />
|
||||||
window.open(
|
<div className="hidden lg:block" />
|
||||||
songNameToYouTubeLink(leaderboard.songName, leaderboard.songSubName, leaderboard.songAuthorName),
|
|
||||||
"_blank"
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
tooltip={<p>Click to open the song in YouTube</p>}
|
|
||||||
>
|
|
||||||
<YouTubeLogo />
|
|
||||||
</ScoreButton>
|
|
||||||
|
|
||||||
{additionalData != undefined && (
|
{additionalData != undefined && (
|
||||||
<>
|
<>
|
||||||
{/* Open score replay */}
|
<ScoreReplayButton additionalData={additionalData} />
|
||||||
<ScoreButton
|
|
||||||
onClick={() => {
|
|
||||||
window.open(`https://replay.beatleader.xyz/?scoreId=${additionalData.scoreId}`, "_blank");
|
|
||||||
}}
|
|
||||||
tooltip={<p>Click to view the score replay!</p>}
|
|
||||||
>
|
|
||||||
<BeatSaberPepeLogo />
|
|
||||||
</ScoreButton>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={`flex gap-2 ${alwaysSingleLine ? "flex-row" : "flex-row lg:flex-col"} items-center justify-center`}
|
className={`flex gap-2 ${alwaysSingleLine ? "flex-row" : "flex-row lg:flex-col"} items-center justify-center pr-1`}
|
||||||
>
|
>
|
||||||
{/* Edit score button */}
|
{/* Edit score button */}
|
||||||
{score && leaderboard && updateScore && !hideAccuracyChanger && (
|
{score && leaderboard && updateScore && !hideAccuracyChanger && (
|
||||||
|
@ -73,7 +73,7 @@ type Props = {
|
|||||||
export default function ScoreStats({ score, leaderboard }: Props) {
|
export default function ScoreStats({ score, leaderboard }: Props) {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col justify-center h-full">
|
<div className="flex flex-col justify-center h-full">
|
||||||
<div className={`grid grid-cols-3 gap-1 ml-0 lg:ml-2 justify-center`}>
|
<div className={`grid grid-cols-3 gap-1 justify-center`}>
|
||||||
<ScoreBadges badges={badges} score={score} leaderboard={leaderboard} />
|
<ScoreBadges badges={badges} score={score} leaderboard={leaderboard} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,7 +2,7 @@ import { useEffect, useState } from "react";
|
|||||||
|
|
||||||
export function useIsMobile() {
|
export function useIsMobile() {
|
||||||
const checkMobile = () => {
|
const checkMobile = () => {
|
||||||
return window.innerWidth < 768;
|
return window.innerWidth <= 1024;
|
||||||
};
|
};
|
||||||
const [isMobile, setIsMobile] = useState(checkMobile());
|
const [isMobile, setIsMobile] = useState(checkMobile());
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user