aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPinapelz <yukais@pinapelz.com>2025-08-02 18:34:57 -0700
committerPinapelz <yukais@pinapelz.com>2025-08-02 18:34:57 -0700
commit3d924d70f3d0d16fbb4ae8828c7010f87bcb1951 (patch)
treeb84e7bc15bc2816c2940cc1e1a2ea66ac81dfd73
parentb136869448339b24dd95560c77222e544d152a3e (diff)
preliminary song info display for individual charts
-rw-r--r--frontend/src/components/modals/SongInfoDisplay.tsx125
-rw-r--r--frontend/src/pages/Chart.tsx15
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>
);
};
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage