Study/src/components/ui/Navbar.tsx
2026-07-11 13:48:02 -07:00

107 lines
4.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { useState } from "react";
import { useRouter, usePathname } from "next/navigation";
import Link from "next/link";
import { ThemeToggle } from "./ThemeToggle";
function Mark() {
return (
<span className="grid h-9 w-9 place-items-center rounded-xl bg-primary text-sm font-extrabold text-white shadow-[0_8px_22px_color-mix(in_srgb,var(--theme-primary)_28%,transparent)]">
S
</span>
);
}
export function Navbar() {
const router = useRouter();
const pathname = usePathname();
const [open, setOpen] = useState(false);
const parts = pathname.split("/").filter(Boolean);
const classSlug = parts[0] && parts[0] !== "shared" ? parts[0] : null;
async function handleLogout() {
await fetch("/api/auth/logout", { method: "POST" });
router.push("/login");
router.refresh();
}
const nav = (
<>
<Link href="/" onClick={() => setOpen(false)} className="mb-9 flex items-center gap-3">
<Mark />
<span>
<span className="block text-[11px] font-bold uppercase tracking-[0.2em] text-text-muted">Your</span>
<span className="editorial-title block text-xl leading-none text-text-heading">Study Desk</span>
</span>
</Link>
<nav className="space-y-1" aria-label="Primary navigation">
<Link
href="/"
onClick={() => setOpen(false)}
className={`flex min-h-11 items-center gap-3 rounded-xl px-3 text-sm font-semibold transition-colors ${pathname === "/" ? "bg-primary text-white shadow-sm" : "text-text-secondary hover:bg-bg-surface-alt hover:text-text-heading"}`}
>
<span aria-hidden className="text-lg"></span> Library
</Link>
{classSlug && (
<div className="pt-6">
<p className="mb-2 px-3 text-[10px] font-bold uppercase tracking-[0.18em] text-text-muted">Current class</p>
<Link
href={`/${classSlug}/flashcards`}
onClick={() => setOpen(false)}
className={`flex min-h-11 items-center gap-3 rounded-xl px-3 text-sm font-semibold transition-colors ${pathname.includes("/flashcards") ? "bg-bg-callout text-primary" : "text-text-secondary hover:bg-bg-surface-alt hover:text-text-heading"}`}
>
<span aria-hidden></span> Flashcards
</Link>
<Link
href={`/${classSlug}/quizzes`}
onClick={() => setOpen(false)}
className={`mt-1 flex min-h-11 items-center gap-3 rounded-xl px-3 text-sm font-semibold transition-colors ${pathname.includes("/quizzes") ? "bg-bg-callout text-primary" : "text-text-secondary hover:bg-bg-surface-alt hover:text-text-heading"}`}
>
<span aria-hidden></span> Quizzes
</Link>
</div>
)}
</nav>
<div className="mt-auto border-t border-border-light pt-4">
<div className="flex items-center justify-between rounded-xl px-2 py-1.5">
<span className="text-xs font-semibold text-text-muted">Appearance</span>
<ThemeToggle />
</div>
<button onClick={handleLogout} className="mt-1 flex min-h-11 w-full items-center gap-3 rounded-xl px-3 text-left text-sm font-semibold text-text-secondary transition-colors hover:bg-error-bg hover:text-error">
<span aria-hidden></span> Sign out
</button>
</div>
</>
);
return (
<>
<aside className="fixed inset-y-0 left-0 z-30 hidden w-60 flex-col border-r border-border-light bg-bg-surface/88 px-4 py-5 backdrop-blur-xl md:flex">
{nav}
</aside>
<header className="sticky top-0 z-40 flex h-16 items-center justify-between border-b border-border-light bg-bg-surface/88 px-4 backdrop-blur-xl md:hidden">
<Link href="/" className="flex items-center gap-2.5">
<Mark />
<span className="editorial-title text-lg text-text-heading">Study Desk</span>
</Link>
<button onClick={() => setOpen(true)} className="grid h-11 w-11 place-items-center rounded-xl border border-border-light bg-bg-surface-alt text-xl text-text-heading" aria-label="Open navigation" aria-expanded={open}>
</button>
</header>
{open && (
<div className="fixed inset-0 z-50 md:hidden">
<button className="absolute inset-0 bg-black/45 backdrop-blur-sm" onClick={() => setOpen(false)} aria-label="Close navigation" />
<aside className="animate-slide-up absolute inset-y-0 right-0 flex w-[min(86vw,21rem)] flex-col border-l border-border-light bg-bg-surface p-5 shadow-[var(--shadow-modal)]">
<button onClick={() => setOpen(false)} className="absolute right-4 top-4 grid h-10 w-10 place-items-center rounded-xl text-xl text-text-muted hover:bg-bg-surface-alt" aria-label="Close navigation">×</button>
{nav}
</aside>
</div>
)}
</>
);
}