refactor(layout): replace two-pane split with single-pane navigation
Library and PlayerPanel now display one at a time on all screen sizes. Selecting a song navigates to the player; the back button returns to the library. Removes isMobile breakpoint logic and fixed 340px panel width. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -277,13 +277,10 @@ export function LibraryPanel({ bandId, selectedSongId, onSelectSong }: LibraryPa
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{
|
<div style={{
|
||||||
width: 340,
|
flex: 1,
|
||||||
minWidth: 280,
|
|
||||||
flexShrink: 0,
|
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
background: "#10131f",
|
background: "#10131f",
|
||||||
borderRight: `1px solid ${border}`,
|
|
||||||
height: "100%",
|
height: "100%",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
}}>
|
}}>
|
||||||
|
|||||||
@@ -1,28 +1,9 @@
|
|||||||
import { useState, useEffect } from "react";
|
|
||||||
import { useParams, useSearchParams } from "react-router-dom";
|
import { useParams, useSearchParams } from "react-router-dom";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import { getBand } from "../api/bands";
|
import { getBand } from "../api/bands";
|
||||||
import { LibraryPanel } from "../components/LibraryPanel";
|
import { LibraryPanel } from "../components/LibraryPanel";
|
||||||
import { PlayerPanel } from "../components/PlayerPanel";
|
import { PlayerPanel } from "../components/PlayerPanel";
|
||||||
|
|
||||||
// ── Empty player state ────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
function EmptyPlayer() {
|
|
||||||
return (
|
|
||||||
<div style={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", background: "#0c0e1a", gap: 12, padding: 40 }}>
|
|
||||||
<div style={{ width: 64, height: 64, borderRadius: 20, background: "rgba(139,92,246,0.08)", border: "1px solid rgba(139,92,246,0.15)", display: "flex", alignItems: "center", justifyContent: "center" }}>
|
|
||||||
<svg width="28" height="28" viewBox="0 0 28 28" fill="none">
|
|
||||||
<path d="M7 14c0-4.5 3.5-7 7-7s7 2.5 7 7v5L23 22H5l2-3v-5z" stroke="rgba(139,92,246,0.5)" strokeWidth="1.5" strokeLinejoin="round" />
|
|
||||||
<path d="M10 22a4 4 0 0 0 8 0" stroke="rgba(139,92,246,0.5)" strokeWidth="1.5" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<p style={{ fontSize: 13, color: "rgba(232,233,240,0.28)", margin: 0, textAlign: "center" }}>
|
|
||||||
Select a track from the library to start listening
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── BandPage ──────────────────────────────────────────────────────────────────
|
// ── BandPage ──────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
export function BandPage() {
|
export function BandPage() {
|
||||||
@@ -31,15 +12,6 @@ export function BandPage() {
|
|||||||
// selectedSongId is kept in URL as ?song=<id> so deep-links and browser back work
|
// selectedSongId is kept in URL as ?song=<id> so deep-links and browser back work
|
||||||
const selectedSongId = searchParams.get("song");
|
const selectedSongId = searchParams.get("song");
|
||||||
|
|
||||||
const [isMobile, setIsMobile] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const check = () => setIsMobile(window.innerWidth < 900);
|
|
||||||
check();
|
|
||||||
window.addEventListener("resize", check);
|
|
||||||
return () => window.removeEventListener("resize", check);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const { data: band, isLoading } = useQuery({
|
const { data: band, isLoading } = useQuery({
|
||||||
queryKey: ["band", bandId],
|
queryKey: ["band", bandId],
|
||||||
queryFn: () => getBand(bandId!),
|
queryFn: () => getBand(bandId!),
|
||||||
@@ -57,9 +29,6 @@ export function BandPage() {
|
|||||||
if (isLoading) return <div style={{ color: "rgba(232,233,240,0.35)", padding: 32 }}>Loading…</div>;
|
if (isLoading) return <div style={{ color: "rgba(232,233,240,0.35)", padding: 32 }}>Loading…</div>;
|
||||||
if (!band || !bandId) return <div style={{ color: "#f87171", padding: 32 }}>Band not found</div>;
|
if (!band || !bandId) return <div style={{ color: "#f87171", padding: 32 }}>Band not found</div>;
|
||||||
|
|
||||||
// ── Mobile: show library OR player, not both ──────────────────────────────
|
|
||||||
|
|
||||||
if (isMobile) {
|
|
||||||
if (selectedSongId) {
|
if (selectedSongId) {
|
||||||
return (
|
return (
|
||||||
<div style={{ height: "100%", display: "flex", flexDirection: "column" }}>
|
<div style={{ height: "100%", display: "flex", flexDirection: "column" }}>
|
||||||
@@ -72,6 +41,7 @@ export function BandPage() {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ height: "100%", display: "flex", flexDirection: "column" }}>
|
<div style={{ height: "100%", display: "flex", flexDirection: "column" }}>
|
||||||
<LibraryPanel
|
<LibraryPanel
|
||||||
@@ -82,27 +52,3 @@ export function BandPage() {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Desktop: three-panel (Sidebar is handled by AppShell, we add Library + Player) ──
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div style={{ display: "flex", height: "100%", overflow: "hidden" }}>
|
|
||||||
<LibraryPanel
|
|
||||||
bandId={bandId}
|
|
||||||
selectedSongId={selectedSongId}
|
|
||||||
onSelectSong={selectSong}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{selectedSongId ? (
|
|
||||||
<PlayerPanel
|
|
||||||
key={selectedSongId}
|
|
||||||
songId={selectedSongId}
|
|
||||||
bandId={bandId}
|
|
||||||
onBack={clearSong}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<EmptyPlayer />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user