Files
gutscheintracker/app/components/shell.tsx
T

111 lines
3.6 KiB
TypeScript

"use client";
import Link from "next/link";
import { usePathname, useRouter } from "next/navigation";
import type { ReactNode } from "react";
const NAV = [
{ href: "/", label: "Gutscheine" },
{ href: "/vouchers/new", label: "Neu" },
{ href: "/contacts", label: "Kontakte" },
{ href: "/settings", label: "Einstellungen" },
] as const;
function isActive(pathname: string, href: string) {
if (href === "/") return pathname === "/";
return pathname === href || pathname.startsWith(`${href}/`);
}
export default function Shell({ children }: { children: ReactNode }) {
const pathname = usePathname();
const router = useRouter();
async function logout() {
await fetch("/api/auth/logout", { method: "POST" }).catch(() => {});
router.push("/login");
router.refresh();
}
return (
<div className="min-h-dvh md:flex">
<aside className="hidden w-60 shrink-0 flex-col border-r border-line bg-white px-4 py-6 md:flex">
<p className="flex items-center gap-2.5 px-2 text-[15px] font-semibold tracking-tight">
<span
aria-hidden="true"
className="grid h-8 w-8 place-items-center rounded-[10px] bg-brand-100 text-[15px] font-bold text-brand-800"
>
G
</span>
Gutscheintracker
</p>
<nav aria-label="Hauptmenü" className="mt-7 flex flex-col gap-1">
{NAV.map((item) => (
<Link
key={item.href}
href={item.href}
aria-current={isActive(pathname, item.href) ? "page" : undefined}
className={`rounded-[10px] px-3 py-2 text-sm font-medium transition-colors ${
isActive(pathname, item.href)
? "bg-brand-50 text-brand-800"
: "text-ink hover:bg-wash"
}`}
>
{item.label}
</Link>
))}
</nav>
<button
type="button"
onClick={logout}
className="mt-auto rounded-[10px] px-3 py-2 text-left text-sm font-medium text-muted transition-colors hover:bg-wash hover:text-ink"
>
Abmelden
</button>
</aside>
<div className="min-w-0 flex-1">
<header className="sticky top-0 flex items-center justify-between border-b border-line bg-white/95 px-4 py-3 backdrop-blur md:hidden">
<p className="flex items-center gap-2 text-sm font-semibold tracking-tight">
<span
aria-hidden="true"
className="grid h-7 w-7 place-items-center rounded-lg bg-brand-100 text-[13px] font-bold text-brand-800"
>
G
</span>
Gutscheintracker
</p>
<button
type="button"
onClick={logout}
className="rounded-lg px-3 py-1.5 text-sm font-medium text-muted hover:text-ink"
>
Abmelden
</button>
</header>
<div className="mx-auto w-full max-w-3xl px-4 pb-28 pt-6 md:px-6 md:pb-12">
{children}
</div>
<nav
aria-label="Hauptmenü"
className="fixed inset-x-0 bottom-0 grid grid-cols-4 border-t border-line bg-white/95 backdrop-blur md:hidden"
>
{NAV.map((item) => (
<Link
key={item.href}
href={item.href}
aria-current={isActive(pathname, item.href) ? "page" : undefined}
className={`px-1 py-2.5 text-center text-xs font-medium ${
isActive(pathname, item.href) ? "text-brand-700" : "text-muted"
}`}
>
{item.label}
</Link>
))}
</nav>
</div>
</div>
);
}