Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | 19x 19x 19x 19x 19x 19x 3x 3x 19x 12x 19x | import { useRouterState } from "@tanstack/react-router";
import { type ReactNode, useCallback, useMemo, useRef, useState } from "react";
import { useAuth } from "../../lib/auth-context";
import { ThemeSwitcher } from "../ui/theme-switcher";
import { ADMIN_NAV, NAV_STORAGE_KEYS, resolveNav } from "./nav-config";
import { NavRail } from "./nav-rail";
import { TopBar } from "./top-bar";
type AdminLayoutProps = {
children: ReactNode;
};
export function AdminLayout({ children }: AdminLayoutProps) {
const [navOpen, setNavOpen] = useState(false);
const menuButtonRef = useRef<HTMLButtonElement>(null);
const { signOut, user, hasProAccess } = useAuth();
const currentPath = useRouterState().location.pathname;
const openNav = useCallback(() => setNavOpen(true), []);
const closeNav = useCallback(() => {
setNavOpen(false);
menuButtonRef.current?.focus();
}, []);
const entries = useMemo(
// isAdmin is implied: this layout only mounts behind AdminGuard.
() => resolveNav(ADMIN_NAV, { isAdmin: true, hasProAccess }),
[hasProAccess],
);
return (
<div className="flex h-screen flex-col overflow-hidden bg-background-base">
<a
href="#main-content"
className="sr-only focus:not-sr-only focus:absolute focus:top-4 focus:left-4 focus:z-50 focus:rounded-md focus:bg-background-elevated focus:p-4 focus:text-foreground-default focus:shadow-lg"
>
Skip to main content
</a>
<header className="z-30 flex-none">
<TopBar
onOpenNav={openNav}
navOpen={navOpen}
menuButtonRef={menuButtonRef}
label="Admin"
>
<ThemeSwitcher variant="icon" size="sm" />
</TopBar>
</header>
<div className="flex min-h-0 flex-1">
{navOpen && (
<button
type="button"
aria-label="Close sidebar overlay"
className="fixed inset-0 z-40 cursor-default bg-overlay-light lg:hidden"
onClick={closeNav}
/>
)}
<NavRail
entries={entries}
currentPath={currentPath}
storageKey={NAV_STORAGE_KEYS.admin}
ariaLabel="Admin navigation"
identity={{
name: user?.name ?? "",
meta: "Platform admin",
}}
onSignOut={signOut}
isOpen={navOpen}
onClose={closeNav}
/>
<div
className="flex min-w-0 flex-1 flex-col overflow-hidden"
aria-hidden={navOpen || undefined}
>
<main id="main-content" className="flex-1 overflow-auto">
<div className="p-4 sm:p-6 lg:p-8">{children}</div>
</main>
</div>
</div>
</div>
);
}
|