final touches for beta skymoney (at least i think)
This commit is contained in:
102
web/src/components/NavBar.tsx
Normal file
102
web/src/components/NavBar.tsx
Normal file
@@ -0,0 +1,102 @@
|
||||
import { NavLink, useLocation, useNavigate } from "react-router-dom";
|
||||
import { useEffect, useState } from "react";
|
||||
import ThemeToggle from "./ThemeToggle";
|
||||
|
||||
export default function NavBar({
|
||||
hideOn = ["/onboarding", "/login", "/register"],
|
||||
}: {
|
||||
hideOn?: string[];
|
||||
}) {
|
||||
const navigate = useNavigate();
|
||||
const { pathname } = useLocation();
|
||||
const [menuOpen, setMenuOpen] = useState(false);
|
||||
const linkClass = ({ isActive }: { isActive: boolean }) =>
|
||||
"nav-link " + (isActive ? "nav-link-active" : "");
|
||||
const mobileLinkClass = ({ isActive }: { isActive: boolean }) =>
|
||||
"nav-link text-[--color-text] " +
|
||||
(isActive ? "nav-link-active" : "hover:bg-[--color-ink]/20");
|
||||
|
||||
useEffect(() => {
|
||||
setMenuOpen(false);
|
||||
}, [pathname]);
|
||||
|
||||
if (hideOn.some((p) => pathname.startsWith(p))) return null;
|
||||
|
||||
return (
|
||||
<header
|
||||
className="topnav sticky top-0 z-40 border-b"
|
||||
style={{ backdropFilter: "blur(8px)" }}
|
||||
aria-label="Primary"
|
||||
>
|
||||
<div className="container h-14 min-h-14 flex items-center gap-2 flex-nowrap">
|
||||
{/* Brand */}
|
||||
<button
|
||||
onClick={() => navigate("/")}
|
||||
className="brand row items-center shrink-0 px-2 py-1 rounded-lg hover:bg-[--color-panel] transition-all"
|
||||
aria-label="Go to dashboard"
|
||||
>
|
||||
<span className="font-bold text-xl tracking-wide">SkyMoney</span>
|
||||
</button>
|
||||
|
||||
{/* Links */}
|
||||
<nav className="ml-2 topnav-links items-center gap-1 flex-1 overflow-x-auto whitespace-nowrap hide-scrollbar">
|
||||
<NavLink to="/" className={linkClass} end>Dashboard</NavLink>
|
||||
<NavLink to="/spend" className={linkClass}>Transactions</NavLink>
|
||||
<NavLink to="/income" className={linkClass}>Income</NavLink>
|
||||
<NavLink to="/transactions" className={linkClass}>Records</NavLink>
|
||||
<NavLink to="/settings" className={linkClass}>Settings</NavLink>
|
||||
</nav>
|
||||
|
||||
{/* Actions */}
|
||||
<div className="ml-auto row gap-2 items-center shrink-0">
|
||||
<div className="topnav-theme items-center gap-2">
|
||||
<ThemeToggle size="sm" />
|
||||
</div>
|
||||
|
||||
{/* Mobile menu */}
|
||||
<div className="topnav-mobile relative">
|
||||
<button
|
||||
type="button"
|
||||
className={
|
||||
"rounded-xl border border-[--color-border] bg-[--color-panel] px-3 py-2 text-[--color-text] transition " +
|
||||
(menuOpen ? "shadow-md" : "hover:bg-[--color-ink]/10")
|
||||
}
|
||||
aria-expanded={menuOpen}
|
||||
aria-controls="mobile-menu"
|
||||
onClick={() => setMenuOpen((open) => !open)}
|
||||
>
|
||||
<span className="sr-only">Open menu</span>
|
||||
<span className="grid gap-1">
|
||||
<span className="h-0.5 w-5 bg-current transition-all" />
|
||||
<span className="h-0.5 w-5 bg-current transition-all" />
|
||||
<span className="h-0.5 w-5 bg-current transition-all" />
|
||||
</span>
|
||||
</button>
|
||||
<div
|
||||
id="mobile-menu"
|
||||
className={
|
||||
"absolute right-0 top-full mt-2 w-64 origin-top-right rounded-2xl border bg-[--color-surface] p-3 shadow-lg transition-all duration-200 ease-out " +
|
||||
(menuOpen
|
||||
? "opacity-100 translate-y-0"
|
||||
: "pointer-events-none opacity-0 -translate-y-2")
|
||||
}
|
||||
role="menu"
|
||||
aria-hidden={!menuOpen}
|
||||
>
|
||||
<div className="flex flex-col gap-1">
|
||||
<NavLink to="/" className={mobileLinkClass} end>Dashboard</NavLink>
|
||||
<NavLink to="/spend" className={mobileLinkClass}>Transactions</NavLink>
|
||||
<NavLink to="/income" className={mobileLinkClass}>Income</NavLink>
|
||||
<NavLink to="/transactions" className={mobileLinkClass}>Records</NavLink>
|
||||
<NavLink to="/settings" className={mobileLinkClass}>Settings</NavLink>
|
||||
</div>
|
||||
<div className="mt-3 border-t border-[--color-border] pt-3 flex items-center justify-between">
|
||||
<ThemeToggle size="sm" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user