diff options
| -rw-r--r-- | frontend/src/components/modals/SongInfoDisplay.tsx | 125 | ||||
| -rw-r--r-- | frontend/src/pages/Chart.tsx | 15 |
2 files changed, 132 insertions, 8 deletions
diff --git a/frontend/src/components/modals/SongInfoDisplay.tsx b/frontend/src/components/modals/SongInfoDisplay.tsx new file mode 100644 index 0000000..946b209 --- /dev/null +++ b/frontend/src/components/modals/SongInfoDisplay.tsx @@ -0,0 +1,125 @@ +import { useEffect, useState, useCallback } from "react"; + +interface ChartInfo { + title: string; + artist: string; + notes?: number; + game?: string; + difficulties: DifficultyInfo[]; +} + +interface DifficultyInfo { + difficulty: string; + level?: number; +} + +interface SongInfoDisplayProps { + scores?: Record<string, unknown>[]; +} + +const SongInfoDisplay = ({ + scores = [], +}: SongInfoDisplayProps) => { + const [chartInfo, setChartInfo] = useState<ChartInfo | null>(null); + + const extractInfoFromScores = useCallback(() => { + if (scores.length === 0) { + setChartInfo(null); + return; + } + + const firstScore = scores[0]; + const title = firstScore.title as string || "Unknown Title"; + const artist = firstScore.artist as string || "Unknown Artist"; + const notes = firstScore.notes as number; + const game = firstScore.game as string; + + const difficultyMap = new Map<string, DifficultyInfo>(); + + scores.forEach(score => { + if (score.difficulty !== undefined) { + const diffKey = (score.diff_lamp as string) || (score.difficulty as string).toString(); + if (!difficultyMap.has(diffKey)) { + difficultyMap.set(diffKey, { + difficulty: diffKey, + level: score.difficulty as number, + }); + } + } + }); + + const difficulties = Array.from(difficultyMap.values()).sort((a, b) => { + if (a.level !== undefined && b.level !== undefined) { + return a.level - b.level; + } + return a.difficulty.localeCompare(b.difficulty); + }); + + setChartInfo({ + title, + artist, + notes, + game, + difficulties + }); + }, [scores]); + + useEffect(() => { + extractInfoFromScores(); + }, [extractInfoFromScores]); + + if (!chartInfo) return null; + + return ( + <div className="bg-slate-900/80 backdrop-blur-sm rounded-xl border border-slate-700 p-6 mb-8"> + <div className="grid grid-cols-1 lg:grid-cols-3 gap-6"> + {/* Left - Song Details */} + <div className="lg:col-span-2 space-y-4"> + {chartInfo.game && ( + <div className="text-center"> + <span className="text-sm font-medium text-slate-300 uppercase tracking-wide"> + {chartInfo.game} + </span> + </div> + )} + + <div className="text-center"> + <h3 className="text-2xl font-bold text-white mb-2"> + {chartInfo.title} + </h3> + <p className="text-lg text-slate-300"> + {chartInfo.artist} + </p> + </div> + + {chartInfo.notes && ( + <div className="text-center mt-4"> + <span className="block text-xs text-slate-400 mb-1">Notes</span> + <span className="text-sm text-white">{chartInfo.notes}</span> + </div> + )} + </div> + + {/* Right - Charts */} + <div> + <h4 className="text-sm font-semibold text-white mb-3 text-center">Known Difficulties</h4> + <div className="space-y-2"> + {chartInfo.difficulties.map((diff, index) => ( + <div + key={index} + className="bg-slate-800/50 rounded-lg p-3 border border-slate-600 text-center" + > + <div className="font-medium text-white text-sm"> + {diff.difficulty.toUpperCase()} + {diff.level !== undefined && ` ${diff.level}`} + </div> + </div> + ))} + </div> + </div> + </div> + </div> + ); +}; + +export default SongInfoDisplay; diff --git a/frontend/src/pages/Chart.tsx b/frontend/src/pages/Chart.tsx index 4271abe..78f6d76 100644 --- a/frontend/src/pages/Chart.tsx +++ b/frontend/src/pages/Chart.tsx @@ -5,6 +5,7 @@ import { NavBar } from "../components/NavBar"; import SessionExpiredPopup from "../components/SessionExpiredPopup"; import ScoreDisplay from "../components/displays/GenericScoreDisplay"; import DancerushScoreDisplay from "../components/displays/DancerushScoreDisplay"; +import SongInfoDisplay from "../components/modals/SongInfoDisplay"; type SortField = string; type SortDirection = "asc" | "desc"; @@ -22,6 +23,7 @@ const Chart = () => { const [sortField, setSortField] = useState<SortField>(""); const [sortDirection, setSortDirection] = useState<SortDirection>("asc"); const [requestOrder, setRequestOrder] = useState<string>("timestamp"); + const chartIdHash = new URLSearchParams(window.location.search).get("chartId") || ""; if (!chartIdHash) { navigate("/home"); @@ -130,16 +132,12 @@ const Chart = () => { <div className="min-h-screen bg-gradient-to-br from-slate-950 via-slate-900 to-slate-950 text-white"> <NavBar user={user} handleLogout={handleLogout} currentPage="score" /> <main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12"> + <SongInfoDisplay + scores={scores} + /> <div className="mb-12"> <div className="flex items-center justify-between mb-4"> - <div> - <h1 className="text-4xl font-bold bg-gradient-to-r from-violet-400 to-violet-600 bg-clip-text text-transparent"> - {scores.length === 0 ? "Unknown Chart" : scores[0].title} - </h1> - <h2 className="text-xl text-slate-300 mt-2"> - {scores.length === 0 ? "Unknown Artist" : scores[0].artist} - </h2> - </div> + <div className="flex-1"/> <div className="flex items-center space-x-2 bg-slate-900/50 backdrop-blur-sm rounded-xl p-1 border border-slate-800/50"> <button onClick={() => setViewMode("cards")} @@ -224,6 +222,7 @@ const Chart = () => { Displaying {scores.length} scores • Page {currentPage} of {numPages} </p> </main> + </div> ); }; |
