pr_01m47d15m3e54sn21z27rpy5n9/apps/sudo/app/root.tsx

74 lines2,600 bytesCodeBlame
1import { isRouteErrorResponse, Links, Meta, Outlet, useRouteLoaderData } from "react-router";
2
3import type { Route } from "./+types/root";
4import "./app.css";
5import { MobileBar, Sidebar } from "./components/shell";
6import { ButtonLink } from "./components/ui";
7import { requireStaff } from "./lib/staff";
8
9export const links: Route.LinksFunction = () => [
10 { rel: "icon", type: "image/svg+xml", href: "/favicon.svg" },
11 { rel: "preconnect", href: "https://fonts.googleapis.com" },
12 { rel: "preconnect", href: "https://fonts.gstatic.com", crossOrigin: "anonymous" },
13 {
14 rel: "stylesheet",
15 href: "https://fonts.googleapis.com/css2?family=Inter:opsz,wght@14..32,400..700&family=JetBrains+Mono:wght@400;500;600&display=swap",
16 },
17];
18
19export const meta: Route.MetaFunction = () => [
20 { title: "sudo · g1t" },
21 { name: "robots", content: "noindex, nofollow" },
22];
23
24export async function loader({ context }: Route.LoaderArgs) {
25 return { email: requireStaff(context).email };
26}
27
28export function Layout({ children }: { children: React.ReactNode }) {
29 const root = useRouteLoaderData<typeof loader>("root");
30 return (
31 <html lang="en">
32 <head>
33 <meta charSet="utf-8" />
34 <meta name="viewport" content="width=device-width, initial-scale=1" />
35 <meta name="theme-color" content="#0f0f11" />
36 <Meta />
37 <Links />
38 </head>
39 <body className="min-h-screen">
40 <Sidebar email={root?.email} />
41 <MobileBar email={root?.email} />
42 <div className="lg:pl-60">{children}</div>
43 {/* No <Scripts />: sudo ships no JavaScript, and its policy allows none. */}
44 </body>
45 </html>
46 );
47}
48
49export default function App() {
50 return <Outlet />;
51}
52
53export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) {
54 let title = "Something went wrong";
55 let details = "An unexpected error occurred.";
56 if (isRouteErrorResponse(error)) {
57 title = error.status === 404 ? "Not found" : `Error ${error.status}`;
58 details = typeof error.data === "string" && error.data ? error.data : error.statusText || details;
59 } else if (error instanceof Error) {
60 // Staff only: the real reason helps more than a polite one.
61 details = error.message;
62 }
63 return (
64 <main className="mx-auto max-w-xl px-4 py-24 text-center">
65 <h1 className="text-2xl font-semibold tracking-tight">{title}</h1>
66 <p className="mt-3 break-words text-muted">{details}</p>
67 <div className="mt-8">
68 <ButtonLink to="/" variant="quiet">
69 Back to the overview
70 </ButtonLink>
71 </div>
72 </main>
73 );
74}