spb/autoscholar
Public
1import Link from "next/link";2import { redirect } from "next/navigation";3import type { ReactNode } from "react";4import { ThemeToggle } from "@/components/ThemeToggle";5import { currentSession } from "@/lib/server/session";6import { AdminNav } from "./AdminNav";7import { LogoutButton } from "./LogoutButton";89export const NAV: Array<[string, string, string]> = [10 ["/admin", "Overview", "⌂"],11 ["/admin/new", "New research", "+"],12 ["/admin/projects", "Projects", "▤"],13 ["/admin/runs", "Runs", "▶"],14 ["/admin/maclustr", "MacLustr", "◧"],15 ["/admin/manuscripts", "Manuscripts", "¶"],16 ["/admin/quality", "Quality", "✓"],17 ["/admin/publications", "Publications", "⊕"],18 ["/admin/templates", "Templates", "≡"],19 ["/admin/settings", "Settings & security", "⚙"],20];2122export default async function ConsoleLayout({ children }: { children: ReactNode }) {23 const sess = await currentSession();24 if (!sess) redirect("/admin/login");25 if (sess.mustChangePassword) redirect("/admin/change-password");26 return (27 <div className="min-h-dvh md:grid md:grid-cols-[15rem_1fr]">28 <a href="#admin-main" className="skip-link">29 Skip to content30 </a>31 <aside32 className="sticky top-0 z-30 border-b hairline md:h-dvh md:overflow-y-auto md:border-r md:border-b-0"33 style={{ background: "var(--bg-muted)", paddingTop: "var(--safe-t)" }}34 >35 <div className="flex items-center justify-between gap-2 px-4 py-3">36 <Link href="/admin" className="flex items-center gap-2 no-underline">37 <span38 aria-hidden="true"39 className="grid h-7 w-7 place-items-center rounded-md text-[11px] font-semibold"40 style={{ background: "var(--fg)", color: "var(--bg)", fontFamily: "var(--font-serif)" }}41 >42 As43 </span>44 <span className="serif font-medium">45 AutoScholar <span className="subtle text-xs font-normal">admin</span>46 </span>47 </Link>48 <div className="flex items-center gap-1">49 <ThemeToggle />50 <AdminNav items={NAV.map(([href, label]) => [href, label])} mobileOnly />51 </div>52 </div>53 <div className="hidden md:block">54 <AdminNav items={NAV.map(([href, label]) => [href, label])} />55 <div className="muted mt-4 border-t px-4 py-4 text-xs hairline">56 Signed in as <strong>{sess.username}</strong>57 <div className="mt-2">58 <LogoutButton />59 </div>60 <div className="mt-3">61 <Link href="/" className="text-xs">62 ← Public site63 </Link>64 </div>65 </div>66 </div>67 </aside>68 <main69 id="admin-main"70 className="min-w-0 px-4 py-6 sm:px-6 lg:px-8"71 style={{ paddingBottom: "calc(1.5rem + var(--safe-b))" }}72 >73 {children}74 </main>75 </div>76 );77}78