g1t/apps/web/app/root.tsx

117 lines3,409 bytesCodeBlame

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Initial g1t: services, event bus, intents and attempts1import {
2 Form,
3 isRouteErrorResponse,
4 Link,
5 Links,
6 Meta,
7 Outlet,
8 Scripts,
9 ScrollRestoration,
10 useRouteLoaderData,
11} from "react-router";
12
13import type { Route } from "./+types/root";
14import "./app.css";
15import { Logo } from "./components/logo";
16import { getViewer, viewerMiddleware } from "./lib/session.server";
17
18export const links: Route.LinksFunction = () => [
19 { rel: "icon", type: "image/svg+xml", href: "/favicon.svg" },
20 { rel: "preconnect", href: "https://fonts.googleapis.com" },
21 {
22 rel: "preconnect",
23 href: "https://fonts.gstatic.com",
24 crossOrigin: "anonymous",
25 },
26 {
27 rel: "stylesheet",
28 href: "https://fonts.googleapis.com/css2?family=Inter:opsz,wght@14..32,400..700&family=JetBrains+Mono:wght@400;600&display=swap",
29 },
30];
31
32export const middleware: Route.MiddlewareFunction[] = [viewerMiddleware];
33
34export function loader({ context }: Route.LoaderArgs) {
35 return { user: getViewer(context) };
36}
37
38export function Layout({ children }: { children: React.ReactNode }) {
39 // Undefined when the root loader itself failed.
40 const user = useRouteLoaderData<typeof loader>("root")?.user;
41 return (
42 <html lang="en">
43 <head>
44 <meta charSet="utf-8" />
45 <meta name="viewport" content="width=device-width, initial-scale=1" />
46 <Meta />
47 <Links />
48 </head>
49 <body>
50 <header className="border-b border-line">
51 <nav className="mx-auto flex max-w-5xl items-center px-4 py-3">
52 <Link to="/" aria-label="g1t home">
53 <Logo />
54 </Link>
55 <div className="ml-auto flex items-center gap-4 text-sm text-muted">
56 {user ? (
57 <>
58 <Link to="/new" className="hover:text-fg">
59 New repository
60 </Link>
61 <Link to="/settings" className="font-mono hover:text-fg">
62 {user.username}
63 </Link>
64 <Form method="post" action="/logout">
65 <button type="submit" className="hover:text-fg">
66 Sign out
67 </button>
68 </Form>
69 </>
70 ) : (
71 <Link to="/login" className="hover:text-fg">
72 Sign in
73 </Link>
74 )}
75 </div>
76 </nav>
77 </header>
78 {children}
79 <ScrollRestoration />
80 <Scripts />
81 </body>
82 </html>
83 );
84}
85
86export default function App() {
87 return <Outlet />;
88}
89
90export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) {
91 let message = "Oops!";
92 let details = "An unexpected error occurred.";
93 let stack: string | undefined;
94
95 if (isRouteErrorResponse(error)) {
96 message = error.status === 404 ? "404" : "Error";
97 details =
98 error.status === 404
99 ? "The requested page could not be found."
100 : error.statusText || details;
101 } else if (import.meta.env.DEV && error && error instanceof Error) {
102 details = error.message;
103 stack = error.stack;
104 }
105
106 return (
107 <main className="mx-auto max-w-5xl px-4 pt-16">
108 <h1 className="font-mono text-2xl font-semibold">{message}</h1>
109 <p className="mt-2 text-muted">{details}</p>
110 {stack && (
111 <pre className="mt-4 w-full overflow-x-auto p-4">
112 <code>{stack}</code>
113 </pre>
114 )}
115 </main>
116 );
117}