-
Notifications
You must be signed in to change notification settings - Fork 70
Expand file tree
/
Copy pathroot.tsx
More file actions
87 lines (80 loc) · 2.8 KB
/
root.tsx
File metadata and controls
87 lines (80 loc) · 2.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import { useTranslation } from "react-i18next"
import type { LinksFunction } from "react-router"
import { isRouteErrorResponse, Links, Meta, Outlet, Scripts, ScrollRestoration, useRouteError } from "react-router"
import { useChangeLanguage } from "remix-i18next/react"
import type { Route } from "./+types/root"
import { LanguageSwitcher } from "./library/language-switcher"
import { ClientHintCheck, getHints } from "./services/client-hints"
import tailwindcss from "./tailwind.css?url"
export async function loader({ context, request }: Route.LoaderArgs) {
const { lang, clientEnv } = context
const hints = getHints(request)
return { lang, clientEnv, hints }
}
export const links: LinksFunction = () => [{ rel: "stylesheet", href: tailwindcss }]
export const handle = {
i18n: "common",
}
export default function App({ loaderData }: Route.ComponentProps) {
const { lang, clientEnv } = loaderData
useChangeLanguage(lang)
return (
<>
<Outlet />
{/* biome-ignore lint/security/noDangerouslySetInnerHtml: We set the window.env variable to the client env */}
<script dangerouslySetInnerHTML={{ __html: `window.env = ${JSON.stringify(clientEnv)}` }} />
</>
)
}
export const Layout = ({ children }: { children: React.ReactNode }) => {
const { i18n } = useTranslation()
return (
<html className="overflow-y-auto overflow-x-hidden" lang={i18n.language} dir={i18n.dir()}>
<head>
<ClientHintCheck />
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<Meta />
<Links />
</head>
<body className="h-full w-full">
<LanguageSwitcher />
{children}
<ScrollRestoration />
<Scripts />
</body>
</html>
)
}
export const ErrorBoundary = () => {
const error = useRouteError()
const { t } = useTranslation()
// Constrain the generic type so we don't provide a non-existent key
const statusCode = () => {
if (!isRouteErrorResponse(error)) {
return "500"
}
// Supported error code messages
switch (error.status) {
case 200:
return "200"
case 403:
return "403"
case 404:
return "404"
default:
return "500"
}
}
const errorStatusCode = statusCode()
return (
<div className="relative flex h-full min-h-screen w-screen items-center justify-center bg-gradient-to-b from-gray-50 to-gray-100 placeholder-index sm:pt-8 sm:pb-16 dark:bg-white dark:from-blue-950 dark:to-blue-900">
<div className="relative mx-auto max-w-[90rem] sm:px-6 lg:px-8">
<div className="relative flex min-h-72 flex-col justify-center p-1 sm:overflow-hidden sm:rounded-2xl md:p-4 lg:p-6">
<h1 className="w-full pb-2 text-center text-2xl text-red-600">{t(`error.${errorStatusCode}.title`)}</h1>
<p className="w-full text-center text-lg dark:text-white">{t(`error.${errorStatusCode}.description`)}</p>
</div>
</div>
</div>
)
}