shellphone.app/app/root.tsx

144 lines
3.5 KiB
TypeScript
Raw Normal View History

2022-06-01 21:56:37 +00:00
import type { FunctionComponent, PropsWithChildren } from "react";
2022-06-26 15:01:55 +00:00
import { type LinksFunction, type LoaderFunction, json } from "@remix-run/node";
import {
Link,
Links,
LiveReload,
Meta,
Outlet,
Scripts,
ScrollRestoration,
useCatch,
useLoaderData,
} from "@remix-run/react";
2022-05-14 10:22:06 +00:00
2022-06-26 15:01:55 +00:00
import config from "~/config/config.server";
2022-06-26 18:57:44 +00:00
import usePanelbear from "~/features/core/hooks/use-panelbear";
2022-05-14 10:22:06 +00:00
import Logo from "~/features/core/components/logo";
import styles from "./styles/tailwind.css";
export const links: LinksFunction = () => [{ rel: "stylesheet", href: styles }];
2022-05-14 10:22:06 +00:00
2022-06-26 15:01:55 +00:00
type LoaderData = {
2022-06-26 18:57:44 +00:00
shellphoneConfig: {
sentry: {
dsn: string;
};
panelbear: {
siteId: string;
};
};
2022-06-26 15:01:55 +00:00
};
export const loader: LoaderFunction = () => {
return json<LoaderData>({
2022-06-26 18:57:44 +00:00
shellphoneConfig: {
2022-06-26 15:01:55 +00:00
sentry: {
dsn: config.sentry.dsn,
},
2022-06-26 18:57:44 +00:00
panelbear: {
siteId: config.panelBear.siteId,
},
},
2022-06-26 15:01:55 +00:00
});
};
2022-05-14 10:22:06 +00:00
export default function App() {
2022-06-26 15:01:55 +00:00
const { shellphoneConfig } = useLoaderData<LoaderData>();
2022-06-26 18:57:44 +00:00
usePanelbear(shellphoneConfig.panelbear.siteId);
2022-05-14 10:22:06 +00:00
return (
<Document>
<Outlet />
2022-06-26 15:01:55 +00:00
<script
suppressHydrationWarning
dangerouslySetInnerHTML={{
2022-06-26 18:57:44 +00:00
__html: `window.shellphoneConfig=${JSON.stringify(shellphoneConfig)};`,
2022-06-26 15:01:55 +00:00
}}
/>
2022-05-14 10:22:06 +00:00
</Document>
);
}
// https://remix.run/docs/en/v1/api/conventions#errorboundary
export function ErrorBoundary({ error }: { error: Error }) {
console.error(error);
return (
<Document>
<div>
<h1>There was an error</h1>
<p>{error.message}</p>
</div>
</Document>
);
}
// https://remix.run/docs/en/v1/api/conventions#catchboundary
export function CatchBoundary() {
const caught = useCatch();
let message;
switch (caught.status) {
case 401:
message = <p>Oops! Looks like you tried to visit a page that you do not have access to.</p>;
break;
case 404:
message = <p>Oops! Looks like you tried to visit a page that does not exist.</p>;
break;
default:
throw new Error(caught.data || caught.statusText);
}
return (
<Document>
<header>
<Link to="/">
<div className="p-4">
<Logo className="w-8" />
</div>
</Link>
</header>
<main>
<h1>
{caught.status}: {caught.statusText}
</h1>
{message}
</main>
</Document>
);
}
const Document: FunctionComponent<PropsWithChildren<{}>> = ({ children }) => (
2022-05-14 10:22:06 +00:00
<html lang="en" className="h-full">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-title" content="Shellphone" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="mobile-web-app-capable" content="yes" />
<meta name="application-name" content="Shellphone" />
<meta name="theme-color" content="#F4F4F5" />
<meta name="msapplication-navbutton-color" content="#F4F4F5" />
<meta name="msapplication-starturl" content="/messages" />
<meta name="msapplication-TileColor" content="#F4F4F5" />
<link rel="apple-touch-icon" sizes="180x180" href="/icons/apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="32x32" href="/icons/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/icons/favicon-16x16.png" />
<link rel="mask-icon" href="/icons/safari-pinned-tab.svg" color="#F4F4F5" />
<link rel="manifest" href="/manifest.webmanifest" />
2022-05-14 10:22:06 +00:00
<Meta />
<Links />
</head>
<body className="h-full">
{children}
<ScrollRestoration />
<Scripts />
<LiveReload />
</body>
</html>
);