feat(navbar): add modular navbar components and color variables
This commit is contained in:
parent
6dbc16f23d
commit
6c4ef371c1
7 changed files with 154 additions and 48 deletions
40
apps/web/src/components/navbar/NavAuth.tsx
Normal file
40
apps/web/src/components/navbar/NavAuth.tsx
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import { Link, useNavigate } from "@tanstack/react-router";
|
||||
import { useSession, signOut } from "../../lib/auth-client";
|
||||
|
||||
const NavAuth = () => {
|
||||
const { data: session } = useSession();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleSignOut = () => {
|
||||
void signOut()
|
||||
.then(() => void navigate({ to: "/" }))
|
||||
.catch((err) => console.error("Sign out error:", err));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="ml-auto">
|
||||
{session ? (
|
||||
<button
|
||||
onClick={handleSignOut}
|
||||
className="text-sm text-(--color-text-muted) transition-colors duration-200
|
||||
hover:text-(--color-primary)"
|
||||
>
|
||||
Sign out{" "}
|
||||
<span className="text-(--color-accent)">{session.user.name}</span>
|
||||
</button>
|
||||
) : (
|
||||
<Link
|
||||
to="/login"
|
||||
className="text-sm font-medium px-4 py-1.5 rounded-full
|
||||
text-white bg-(--color-primary)
|
||||
hover:bg-(--color-primary-dark)
|
||||
transition-colors duration-200"
|
||||
>
|
||||
Sign in
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default NavAuth;
|
||||
18
apps/web/src/components/navbar/NavBar.tsx
Normal file
18
apps/web/src/components/navbar/NavBar.tsx
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import NavAuth from "./NavAuth";
|
||||
import NavLinks from "./NavLinks";
|
||||
|
||||
const Navbar = () => {
|
||||
return (
|
||||
<header className="sticky top-0 z-50 w-full bg-(--color-surface) border-b border-(--color-primary-light)">
|
||||
<div className="max-w-5xl mx-auto px-6 h-14 flex items-center gap-8">
|
||||
<span className="text-sm font-bold tracking-tight text-(--color-primary)">
|
||||
lila
|
||||
</span>
|
||||
<NavLinks />
|
||||
<NavAuth />
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
};
|
||||
|
||||
export default Navbar;
|
||||
26
apps/web/src/components/navbar/NavLink.tsx
Normal file
26
apps/web/src/components/navbar/NavLink.tsx
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import { Link } from "@tanstack/react-router";
|
||||
|
||||
type NavLinkProps = { to: string; children: React.ReactNode };
|
||||
|
||||
const NavLink = ({ to, children }: NavLinkProps) => {
|
||||
return (
|
||||
<Link
|
||||
to={to}
|
||||
className="relative text-sm font-medium text-(--color-text-muted) transition-colors duration-200
|
||||
hover:text-(--color-primary)
|
||||
[&.active]:text-(--color-primary)
|
||||
[&.active]:after:absolute
|
||||
[&.active]:after:-bottom-1
|
||||
[&.active]:after:left-0
|
||||
[&.active]:after:w-full
|
||||
[&.active]:after:h-0.5
|
||||
[&.active]:after:bg-(--color-accent)
|
||||
[&.active]:after:rounded-full
|
||||
[&.active]:after:content-['']"
|
||||
>
|
||||
{children}
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
export default NavLink;
|
||||
21
apps/web/src/components/navbar/NavLinks.tsx
Normal file
21
apps/web/src/components/navbar/NavLinks.tsx
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import NavLink from "./NavLink";
|
||||
|
||||
const links = [
|
||||
{ to: "/", label: "Home" },
|
||||
{ to: "/play", label: "Play" },
|
||||
{ to: "/multiplayer", label: "Multiplayer" },
|
||||
];
|
||||
|
||||
const NavLinks = () => {
|
||||
return (
|
||||
<nav className="flex items-center gap-6">
|
||||
{links.map(({ to, label }) => (
|
||||
<NavLink key={to} to={to}>
|
||||
{label}
|
||||
</NavLink>
|
||||
))}
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
|
||||
export default NavLinks;
|
||||
17
apps/web/src/components/navbar/NavLogin.tsx
Normal file
17
apps/web/src/components/navbar/NavLogin.tsx
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { Link } from "@tanstack/react-router";
|
||||
|
||||
const NavLogin = () => {
|
||||
return (
|
||||
<Link
|
||||
to="/login"
|
||||
className="text-sm font-medium px-4 py-1.5 rounded-full
|
||||
text-white bg-(--color-primary)
|
||||
hover:bg-(--color-primary-dark)
|
||||
transition-colors duration-200"
|
||||
>
|
||||
Sign in
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
export default NavLogin;
|
||||
26
apps/web/src/components/navbar/NavLogout.tsx
Normal file
26
apps/web/src/components/navbar/NavLogout.tsx
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import { useNavigate } from "@tanstack/react-router";
|
||||
import { signOut } from "../../lib/auth-client";
|
||||
|
||||
type NavLogoutProps = { name: string };
|
||||
|
||||
const NavLogout = ({ name }: NavLogoutProps) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleLogout = () => {
|
||||
void signOut()
|
||||
.then(() => void navigate({ to: "/" }))
|
||||
.catch((err) => console.error("logout error:", err));
|
||||
};
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={handleLogout}
|
||||
className="text-sm text-(--color-text-muted) transition-colors duration-200
|
||||
hover:text-(--color-primary)"
|
||||
>
|
||||
logout <span className="text-(--color-accent)">{name}</span>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
export default NavLogout;
|
||||
|
|
@ -1,56 +1,14 @@
|
|||
import {
|
||||
createRootRoute,
|
||||
Link,
|
||||
Outlet,
|
||||
useNavigate,
|
||||
} from "@tanstack/react-router";
|
||||
import { createRootRoute, Outlet } from "@tanstack/react-router";
|
||||
import { TanStackRouterDevtools } from "@tanstack/react-router-devtools";
|
||||
import { useSession, signOut } from "../lib/auth-client";
|
||||
import Navbar from "../components/navbar/NavBar";
|
||||
|
||||
const RootLayout = () => {
|
||||
const { data: session } = useSession();
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="p-2 flex gap-2 items-center">
|
||||
<Link to="/" className="[&.active]:font-bold">
|
||||
Home
|
||||
</Link>
|
||||
<Link to="/play" className="[&.active]:font-bold">
|
||||
Play
|
||||
</Link>
|
||||
<Link to="/multiplayer" className="[&.active]:font-bold">
|
||||
Multiplayer
|
||||
</Link>
|
||||
<div className="ml-auto">
|
||||
{session ? (
|
||||
<button
|
||||
className="text-sm text-gray-600 hover:text-gray-900"
|
||||
onClick={() => {
|
||||
void signOut()
|
||||
.then(() => {
|
||||
void navigate({ to: "/" });
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("Sign out error:", err);
|
||||
});
|
||||
}}
|
||||
>
|
||||
Sign out ({session.user.name})
|
||||
</button>
|
||||
) : (
|
||||
<Link
|
||||
to="/login"
|
||||
className="text-sm text-blue-600 hover:text-blue-800"
|
||||
>
|
||||
Sign in
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<Outlet />
|
||||
<Navbar />
|
||||
<main className="max-w-5xl mx-auto px-6 py-8">
|
||||
<Outlet />
|
||||
</main>
|
||||
<TanStackRouterDevtools />
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue