182 lines
5.0 KiB
TypeScript
182 lines
5.0 KiB
TypeScript
import {
|
||
ChakraProvider,
|
||
Container,
|
||
cookieStorageManagerSSR,
|
||
Heading,
|
||
Link,
|
||
Text,
|
||
} from "@chakra-ui/react";
|
||
import { ClientStyleContext, ServerStyleContext } from "./context.js";
|
||
import fontStyle from "@fontsource/plus-jakarta-sans/index.css";
|
||
import Forbidden from "../components/Forbidden.js";
|
||
import globalStyles from "../index.css";
|
||
import {
|
||
Links,
|
||
LiveReload,
|
||
Meta,
|
||
Outlet,
|
||
Scripts,
|
||
useCatch,
|
||
useLoaderData,
|
||
} from "@remix-run/react";
|
||
import { LinksFunction } from "@remix-run/cloudflare";
|
||
import Login from "../components/Login.js";
|
||
import Navigation from "../components/Navigation.js";
|
||
|
||
import { type ReactNode, StrictMode, useContext, useEffect } from "react";
|
||
import theme from "../theme.js";
|
||
import { withEmotionCache } from "@emotion/react";
|
||
|
||
export function CatchBoundary() {
|
||
const { status } = useCatch();
|
||
|
||
switch (status) {
|
||
case 303:
|
||
return "";
|
||
|
||
case 401:
|
||
return getMarkup({ hide: true }, <Login />);
|
||
|
||
case 403:
|
||
return getMarkup({ hide: true }, <Forbidden />);
|
||
|
||
case 404:
|
||
return getMarkup(
|
||
{ hide: true },
|
||
<Container maxW="container.lg" pt="8vh" textAlign="left">
|
||
<Heading size="4xl">404</Heading>
|
||
<br />
|
||
<Text fontSize="xl">There is nothing to find here.</Text>
|
||
<br />
|
||
<br />
|
||
<br />
|
||
<Link color="#646cff" onClick={() => history.go(-1)}>
|
||
Go back
|
||
</Link>
|
||
</Container>
|
||
);
|
||
|
||
default:
|
||
return getMarkup(
|
||
{ hide: true },
|
||
<Container maxW="container.lg" pt="8vh" textAlign="left">
|
||
<Heading size="4xl">500</Heading>
|
||
<br />
|
||
<Text fontSize="xl">S̶̡͈̠̗̠͖͙̭o̶̶͕͚̥͍̪̤m̸̨͏͈͔̖͚̖̰̱͞e҉̵͖͚͇̀t̕͟͠͏͎̺̯̲̱̣̤̠̟͙̠̙̫̬ḩ̸̭͓̬͎̙̀į̞̮͉͖̰̥̹͚̫̙̪̗̜̳̕ͅn҉͔̯̪̗̝̝͖̲͇͍͎̲̲̤̖̫͈̪͡g̴̰̻̙̝͉̭͇̖̰̝̙͕̼͙͘͜ ̵̶̫̥̳̲̘̻̗͈͕̭̲͇̘̜̺̟̥̖̥b̴̙̭̹͕̞͠r̞͎̠̩͈̖̰̞̯̯͢͢͠ͅo̝̯̗̹̳͍̰͉͕̘̰̠̺̥̰͔̕ͅk̵̸̻̠͕̺̦̦͖̲̺̦̞̝̞͞͡e̶͏̤̼̼͔̘̰̰̭͈̀͞͡</Text>
|
||
<br />
|
||
<br />
|
||
<br />
|
||
<Link color="#646cff" onClick={() => location.reload()}>
|
||
Reload
|
||
</Link>
|
||
</Container>
|
||
);
|
||
}
|
||
}
|
||
|
||
export const links: LinksFunction = () => {
|
||
return [
|
||
{ href: "/favicon.ico", rel: "icon" },
|
||
{ href: "/files/logo192.png", rel: "apple-touch-icon", type: "image/png" },
|
||
{ href: fontStyle, rel: "stylesheet " },
|
||
{ href: globalStyles, rel: "stylesheet" },
|
||
];
|
||
};
|
||
|
||
export async function loader({
|
||
context,
|
||
}: {
|
||
context: RequestContext;
|
||
}): Promise<{ [k: string]: any }> {
|
||
let data: { [k: string]: string } = {};
|
||
|
||
if (context.data.current_user) data = { ...context.data.current_user };
|
||
if (context.env.DSN) data.dsn = context.env.DSN;
|
||
if (context.data.theme) data.theme = context.data.theme;
|
||
|
||
return data;
|
||
}
|
||
|
||
export function meta() {
|
||
return {
|
||
title: "Car Crushers",
|
||
};
|
||
}
|
||
|
||
function getMarkup(
|
||
loaderData: { [k: string]: any },
|
||
child: ReactNode
|
||
): JSX.Element {
|
||
const Document = withEmotionCache(
|
||
({ children }: { children: ReactNode }, emotionCache) => {
|
||
const serverStyleData = useContext(ServerStyleContext);
|
||
const clientStyleData = useContext(ClientStyleContext);
|
||
|
||
useEffect(() => {
|
||
emotionCache.sheet.container = document.head;
|
||
const tags = emotionCache.sheet.tags;
|
||
|
||
emotionCache.sheet.flush();
|
||
tags.forEach((tag) => {
|
||
(emotionCache.sheet as any)._insertTag(tag);
|
||
});
|
||
|
||
clientStyleData?.reset();
|
||
}, []);
|
||
|
||
const body = (
|
||
<StrictMode>
|
||
<ChakraProvider
|
||
colorModeManager={cookieStorageManagerSSR(
|
||
typeof document === "undefined" ? "" : document.cookie
|
||
)}
|
||
theme={theme}
|
||
>
|
||
<div className="App">
|
||
<Navigation {...loaderData} />
|
||
{children}
|
||
<Scripts />
|
||
<LiveReload />
|
||
</div>
|
||
</ChakraProvider>
|
||
</StrictMode>
|
||
);
|
||
|
||
return (
|
||
<html lang="en-US">
|
||
<head>
|
||
<Links />
|
||
{serverStyleData?.map(({ key, ids, css }) => (
|
||
<style
|
||
key={key}
|
||
data-emotion={`${key} ${ids.join(" ")}`}
|
||
dangerouslySetInnerHTML={{ __html: css }}
|
||
/>
|
||
))}
|
||
<meta charSet="UTF-8" />
|
||
{loaderData.dsn ? (
|
||
<meta name="dsn" content={loaderData.dsn} />
|
||
) : null}
|
||
<meta name="style-nonce" content={loaderData.nonce} />
|
||
<meta name="theme-color" content="#00a8f8" />
|
||
<meta
|
||
name="viewport"
|
||
content="width=device-width, initial-scale=1.0"
|
||
/>
|
||
<Meta />
|
||
</head>
|
||
<body>{body}</body>
|
||
</html>
|
||
);
|
||
}
|
||
);
|
||
|
||
return <Document>{child}</Document>;
|
||
}
|
||
|
||
export default function () {
|
||
const loaderData = useLoaderData<typeof loader>();
|
||
|
||
return getMarkup(loaderData, <Outlet />);
|
||
}
|