Remix migration
This commit is contained in:
177
app/root.tsx
Normal file
177
app/root.tsx
Normal file
@ -0,0 +1,177 @@
|
||||
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 { HelmetProvider } from "react-helmet-async";
|
||||
import {
|
||||
Links,
|
||||
LiveReload,
|
||||
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;
|
||||
}
|
||||
|
||||
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 helmetContext: { [k: string]: any } = {};
|
||||
|
||||
const body = (
|
||||
<StrictMode>
|
||||
<ChakraProvider
|
||||
colorModeManager={cookieStorageManagerSSR(
|
||||
typeof document === "undefined" ? "" : document.cookie
|
||||
)}
|
||||
theme={theme}
|
||||
>
|
||||
<HelmetProvider>
|
||||
<div className="App">
|
||||
<Navigation {...loaderData} />
|
||||
{children}
|
||||
<Scripts />
|
||||
<LiveReload />
|
||||
</div>
|
||||
</HelmetProvider>
|
||||
</ChakraProvider>
|
||||
</StrictMode>
|
||||
);
|
||||
|
||||
const { helmet } = helmetContext;
|
||||
|
||||
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="theme-color" content="#00a8f8" />
|
||||
{helmet.meta?.toString()}
|
||||
{helmet.title?.toString() ?? <title>Car Crushers</title>}
|
||||
</head>
|
||||
<body>{body}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
return <Document>{child}</Document>;
|
||||
}
|
||||
|
||||
export default function () {
|
||||
const loaderData = useLoaderData<typeof loader>();
|
||||
|
||||
return getMarkup(loaderData, <Outlet />);
|
||||
}
|
Reference in New Issue
Block a user