158 lines
4.9 KiB
TypeScript
158 lines
4.9 KiB
TypeScript
import { useNavigate, useLocation, matchPath } from "react-router-dom";
|
|
import { usePlayerStore } from "../stores/playerStore";
|
|
|
|
// ── Icons (inline SVG) ──────────────────────────────────────────────────────
|
|
function IconLibrary() {
|
|
return (
|
|
<svg width="20" height="20" viewBox="0 0 14 14" fill="currentColor">
|
|
<path d="M2 3.5h10v1.5H2zm0 3h10v1.5H2zm0 3h7v1.5H2z" />
|
|
</svg>
|
|
);
|
|
}
|
|
|
|
function IconPlay() {
|
|
return (
|
|
<svg width="20" height="20" viewBox="0 0 14 14" fill="currentColor">
|
|
<path d="M3 2l9 5-9 5V2z" />
|
|
</svg>
|
|
);
|
|
}
|
|
|
|
|
|
|
|
function IconSettings() {
|
|
return (
|
|
<svg width="20" height="20" viewBox="0 0 14 14" fill="none" stroke="currentColor" strokeWidth="1.3">
|
|
<circle cx="7" cy="7" r="2" />
|
|
<path d="M7 1v1.5M7 11.5V13M1 7h1.5M11.5 7H13" />
|
|
</svg>
|
|
);
|
|
}
|
|
|
|
function IconMembers() {
|
|
return (
|
|
<svg width="20" height="20" viewBox="0 0 14 14" fill="currentColor">
|
|
<circle cx="5" cy="4.5" r="2" />
|
|
<path d="M1 12c0-2.2 1.8-3.5 4-3.5s4 1.3 4 3.5H1z" />
|
|
<circle cx="10.5" cy="4.5" r="1.5" opacity=".6" />
|
|
<path d="M10.5 8.5c1.4 0 2.5 1 2.5 2.5H9.5" opacity=".6" />
|
|
</svg>
|
|
);
|
|
}
|
|
|
|
// ── NavItem ─────────────────────────────────────────────────────────────────
|
|
interface NavItemProps {
|
|
icon: React.ReactNode;
|
|
label: string;
|
|
active: boolean;
|
|
onClick: () => void;
|
|
disabled?: boolean;
|
|
}
|
|
|
|
function NavItem({ icon, label, active, onClick, disabled }: NavItemProps) {
|
|
const color = active ? "#e8a22a" : "rgba(255,255,255,0.5)";
|
|
|
|
return (
|
|
<button
|
|
onClick={onClick}
|
|
disabled={disabled}
|
|
style={{
|
|
flex: 1,
|
|
display: "flex",
|
|
flexDirection: "column",
|
|
alignItems: "center",
|
|
gap: 4,
|
|
padding: "8px 4px",
|
|
background: "transparent",
|
|
border: "none",
|
|
cursor: disabled ? "default" : "pointer",
|
|
color,
|
|
fontSize: 10,
|
|
transition: "color 0.12s",
|
|
fontFamily: "inherit",
|
|
}}
|
|
>
|
|
{icon}
|
|
<span style={{ fontSize: 10 }}>{label}</span>
|
|
</button>
|
|
);
|
|
}
|
|
|
|
// ── BottomNavBar ────────────────────────────────────────────────────────────
|
|
export function BottomNavBar() {
|
|
const navigate = useNavigate();
|
|
const location = useLocation();
|
|
|
|
// Derive current band from URL
|
|
const bandMatch = matchPath("/bands/:bandId/*", location.pathname) ?? matchPath("/bands/:bandId", location.pathname);
|
|
const currentBandId = bandMatch?.params?.bandId || location.state?.fromBandId;
|
|
|
|
// Debug logging for black screen issue
|
|
console.log("BottomNavBar - Current band ID:", currentBandId, "Path:", location.pathname, "State:", location.state);
|
|
|
|
// Derive active states
|
|
const isLibrary = !!matchPath("/bands/:bandId", location.pathname) ||
|
|
!!matchPath("/bands/:bandId/sessions/:sessionId", location.pathname);
|
|
const isSettings = location.pathname.startsWith("/settings");
|
|
|
|
// Player state
|
|
const { currentSongId, currentBandId: playerBandId, isPlaying } = usePlayerStore();
|
|
const hasActiveSong = !!currentSongId && !!playerBandId;
|
|
|
|
return (
|
|
<nav
|
|
style={{
|
|
position: "fixed",
|
|
bottom: 0,
|
|
left: 0,
|
|
right: 0,
|
|
display: "flex",
|
|
background: "#0b0b0e",
|
|
borderTop: "1px solid rgba(255,255,255,0.06)",
|
|
zIndex: 1000,
|
|
padding: "8px 16px",
|
|
}}
|
|
>
|
|
<NavItem
|
|
icon={<IconLibrary />}
|
|
label="Library"
|
|
active={isLibrary}
|
|
onClick={() => {
|
|
console.log("Library click - Navigating to band:", currentBandId);
|
|
if (currentBandId) {
|
|
navigate(`/bands/${currentBandId}`);
|
|
} else {
|
|
console.warn("Library click - No current band ID found!");
|
|
navigate("/bands");
|
|
}
|
|
}}
|
|
/>
|
|
|
|
<NavItem
|
|
icon={<IconPlay />}
|
|
label="Player"
|
|
active={hasActiveSong && isPlaying}
|
|
onClick={() => {
|
|
if (hasActiveSong) {
|
|
navigate(`/bands/${playerBandId}/songs/${currentSongId}`);
|
|
}
|
|
}}
|
|
disabled={!hasActiveSong}
|
|
/>
|
|
|
|
<NavItem
|
|
icon={<IconMembers />}
|
|
label="Members"
|
|
active={false}
|
|
onClick={() => currentBandId ? navigate(`/bands/${currentBandId}/settings/members`) : navigate("/settings", { state: { fromBandId: currentBandId } })}
|
|
/>
|
|
<NavItem
|
|
icon={<IconSettings />}
|
|
label="Settings"
|
|
active={isSettings}
|
|
onClick={() => currentBandId ? navigate("/settings", { state: { fromBandId: currentBandId } }) : navigate("/settings")}
|
|
/>
|
|
</nav>
|
|
);
|
|
}
|