flagon-io/g1t

public

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

g1t/apps/sudo/app/root.tsx

126 lines4,963 bytesCodeBlame
1import { Boxes, Building2, CreditCard, ShieldCheck } from "lucide-react";
2import { isRouteErrorResponse, Link, Links, Meta, Outlet, useLocation, useRouteLoaderData } from "react-router";
3
4import type { Route } from "./+types/root";
5import "./app.css";
6import { Logo } from "./components/logo";
7import { ButtonLink } from "./components/ui";
8import { requireStaff } from "./lib/staff";
9
10export const links: Route.LinksFunction = () => [
11 { rel: "icon", type: "image/svg+xml", href: "/favicon.svg" },
12 { rel: "preconnect", href: "https://fonts.googleapis.com" },
13 { rel: "preconnect", href: "https://fonts.gstatic.com", crossOrigin: "anonymous" },
14 {
15 rel: "stylesheet",
16 href: "https://fonts.googleapis.com/css2?family=Inter:opsz,wght@14..32,400..700&family=JetBrains+Mono:wght@400;500;600&display=swap",
17 },
18];
19
20export const meta: Route.MetaFunction = () => [
21 { title: "sudo · g1t" },
22 { name: "robots", content: "noindex, nofollow" },
23];
24
25export async function loader({ context }: Route.LoaderArgs) {
26 return { email: requireStaff(context).email };
27}
28
29/** A top-level section; it stays lit on the pages beneath it. */
30function NavItem({ to, active, children }: { to: string; active: (path: string) => boolean; children: React.ReactNode }) {
31 const { pathname } = useLocation();
32 const isActive = active(pathname);
33 return (
34 <Link
35 to={to}
36 aria-current={isActive ? "page" : undefined}
37 className={`inline-flex items-center gap-1.5 rounded-md px-2.5 py-1.5 text-sm transition-colors hover:bg-raised hover:text-fg ${
38 isActive ? "bg-raised/60 text-fg" : "text-muted"
39 }`}
40 >
41 {children}
42 </Link>
43 );
44}
45
46export function Layout({ children }: { children: React.ReactNode }) {
47 const root = useRouteLoaderData<typeof loader>("root");
48 return (
49 <html lang="en">
50 <head>
51 <meta charSet="utf-8" />
52 <meta name="viewport" content="width=device-width, initial-scale=1" />
53 <meta name="theme-color" content="#0f0f11" />
54 <Meta />
55 <Links />
56 </head>
57 <body className="flex min-h-screen flex-col">
58 <header className="sticky top-0 z-40 border-b border-line bg-surface/90 backdrop-blur">
59 <div className="mx-auto flex h-14 max-w-6xl items-center gap-2 px-4">
60 <Link to="/" aria-label="sudo home" className="mr-1 sm:mr-3">
61 <Logo />
62 </Link>
63 <nav className="flex items-center gap-0.5">
64 <NavItem to="/" active={(path) => path === "/" || path.startsWith("/workspaces")}>
65 <Boxes size={14} className="hidden sm:block" />
66 Workspaces
67 </NavItem>
68 <NavItem to="/enterprises" active={(path) => path.startsWith("/enterprises")}>
69 <Building2 size={14} className="hidden sm:block" />
70 Enterprises
71 </NavItem>
72 <NavItem to="/stripe" active={(path) => path.startsWith("/stripe")}>
73 <CreditCard size={14} className="hidden sm:block" />
74 Stripe
75 </NavItem>
76 </nav>
77 {root?.email && (
78 <span
79 title="Signed in through Cloudflare Access"
80 className="ml-auto hidden items-center gap-1.5 truncate rounded-md border border-line px-2 py-1 font-mono text-xs text-muted md:inline-flex"
81 >
82 <ShieldCheck size={13} className="text-merged" />
83 {root.email}
84 </span>
85 )}
86 </div>
87 </header>
88 <div className="grow">{children}</div>
89 <footer className="border-t border-line">
90 <p className="mx-auto max-w-6xl px-4 py-5 text-xs text-faint">
91 g1t staff only. Every change is recorded with who made it.
92 {root?.email && <span className="md:hidden"> Signed in as {root.email}.</span>}
93 </p>
94 </footer>
95 {/* No <Scripts />: sudo ships no JavaScript, and its policy allows none. */}
96 </body>
97 </html>
98 );
99}
100
101export default function App() {
102 return <Outlet />;
103}
104
105export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) {
106 let title = "Something went wrong";
107 let details = "An unexpected error occurred.";
108 if (isRouteErrorResponse(error)) {
109 title = error.status === 404 ? "Not found" : `Error ${error.status}`;
110 details = typeof error.data === "string" && error.data ? error.data : error.statusText || details;
111 } else if (error instanceof Error) {
112 // Staff only: the real reason helps more than a polite one.
113 details = error.message;
114 }
115 return (
116 <main className="mx-auto max-w-xl px-4 py-24 text-center">
117 <h1 className="text-2xl font-semibold tracking-tight">{title}</h1>
118 <p className="mt-3 break-words text-muted">{details}</p>
119 <div className="mt-8">
120 <ButtonLink to="/" variant="quiet">
121 Back to workspaces
122 </ButtonLink>
123 </div>
124 </main>
125 );
126}