11import { AnimatePresence } from 'framer-motion' ;
22import React , { useContext , useEffect } from 'react' ;
33import { withEmotionCache } from '@emotion/react' ;
4- import { ChakraProvider } from '@chakra-ui/react' ;
5- import { Links , LiveReload , Meta , Outlet , Scripts , ScrollRestoration , useCatch , useLoaderData } from '@remix-run/react' ;
4+ import { Box , Button , ChakraProvider , Heading , Text , VStack } from '@chakra-ui/react' ;
5+ import { Link , Links , LiveReload , Meta , Outlet , Scripts , ScrollRestoration , useCatch , useLoaderData } from '@remix-run/react' ;
66import { MetaFunction , LinksFunction , json } from '@remix-run/node' ;
77
88import { ServerStyleContext , ClientStyleContext } from './context' ;
9+ import { getBaseUrl } from './utils/routes' ;
910
1011export const meta : MetaFunction = ( ) => ( {
1112 charset : 'utf-8' ,
@@ -33,13 +34,14 @@ export const links: LinksFunction = () => {
3334} ;
3435
3536interface DocumentProps {
37+ head ?: React . ReactNode ;
3638 children : React . ReactNode ;
3739}
3840
39- const Document = withEmotionCache ( ( { children } : DocumentProps , emotionCache ) => {
41+ const Document = withEmotionCache ( ( { children, head } : DocumentProps , emotionCache ) => {
42+ const data = useLoaderData ( ) ;
4043 const serverStyleData = useContext ( ServerStyleContext ) ;
4144 const clientStyleData = useContext ( ClientStyleContext ) ;
42- const data = useLoaderData ( ) ;
4345
4446 // Only executed on client
4547 useEffect ( ( ) => {
@@ -58,18 +60,21 @@ const Document = withEmotionCache(({ children }: DocumentProps, emotionCache) =>
5860 return (
5961 < html lang = "en" >
6062 < head >
63+ { head }
6164 < Meta />
6265 < Links />
6366 { serverStyleData ?. map ( ( { key, ids, css } ) => (
6467 < style key = { key } data-emotion = { `${ key } ${ ids . join ( ' ' ) } ` } dangerouslySetInnerHTML = { { __html : css } } />
6568 ) ) }
6669 </ head >
6770 < body >
68- { children }
69- < script dangerouslySetInnerHTML = { { __html : `window.ENV = ${ JSON . stringify ( data . ENV ) } ` } } />
71+ < ChakraProvider >
72+ { children }
73+ </ ChakraProvider >
74+ < script dangerouslySetInnerHTML = { { __html : `window.ENV = ${ JSON . stringify ( data ?. ENV ) } ` } } />
7075 < ScrollRestoration />
7176 < Scripts />
72- < LiveReload />
77+ { process . env . NODE_ENV === 'development' ? < LiveReload /> : null }
7378 </ body >
7479 </ html >
7580 ) ;
@@ -78,47 +83,102 @@ const Document = withEmotionCache(({ children }: DocumentProps, emotionCache) =>
7883export default function App ( ) {
7984 return (
8085 < Document >
81- < ChakraProvider >
82- < AnimatePresence exitBeforeEnter >
83- < Outlet />
84- </ AnimatePresence >
85- </ ChakraProvider >
86+ < AnimatePresence exitBeforeEnter >
87+ < Outlet />
88+ </ AnimatePresence >
8689 </ Document >
8790 ) ;
8891}
8992
9093export function ErrorBoundary ( { error } : { error : Error } ) {
9194 console . error ( error ) ;
9295 return (
93- < html >
94- < head >
95- < title > Oh no!</ title >
96- < Meta />
97- < Links />
98- </ head >
99- < body >
100- < div > An unexpected error occurred: { error . message } </ div >
101- < Scripts />
102- </ body >
103- </ html >
96+ < Document >
97+ < VStack h = "100vh" justify = "center" >
98+ < Heading > There was an error</ Heading >
99+ < Text > { error . message } </ Text >
100+ < hr />
101+ < Text >
102+ < div > An unexpected error occurred: { error . message } </ div >
103+ </ Text >
104+ </ VStack >
105+ </ Document >
104106 ) ;
105107}
106108
107109export function CatchBoundary ( ) {
108110 const caught = useCatch ( ) ;
111+ let message ;
112+ switch ( caught . status ) {
113+ case 401 : {
114+ message = (
115+ < Box textAlign = "center" py = { 10 } px = { 6 } >
116+ < Heading
117+ display = "inline-block"
118+ as = "h2"
119+ size = "2xl"
120+ bgGradient = "linear(to-r, purple.400, purple.600)"
121+ backgroundClip = "text" >
122+ No Access
123+ </ Heading >
124+ < Text color = { 'gray.500' } mb = { 6 } >
125+ The page you are looking for does not seem to exist
126+ </ Text >
127+
128+ < Button
129+ colorScheme = "purple"
130+ bgGradient = "linear(to-r, purple.400, purple.500, purple.600)"
131+ color = "white"
132+ variant = "solid" >
133+ Go to Home
134+ </ Button >
135+ </ Box >
136+ ) ;
137+ break ;
138+ }
139+ case 404 : {
140+ message = (
141+ < Box textAlign = "center" py = { 10 } px = { 6 } >
142+ < Heading
143+ display = "inline-block"
144+ as = "h1"
145+ size = "4xl"
146+ bgGradient = "linear(to-r, purple.400, purple.600)"
147+ backgroundClip = "text" >
148+ 404
149+ </ Heading >
150+ < Text fontSize = "24px" mt = { 3 } mb = { 2 } >
151+ Page Not Found
152+ </ Text >
153+ < Text color = { 'gray.500' } mb = { 6 } >
154+ The page you are looking for does not seem to exist
155+ </ Text >
156+
157+ < Button
158+ as = { Link }
159+ colorScheme = "purple"
160+ bgGradient = "linear(to-r, purple.400, purple.500, purple.600)"
161+ color = "white"
162+ variant = "solid"
163+ to = { getBaseUrl ( ) }
164+ >
165+ Go to Home
166+ </ Button >
167+ </ Box >
168+ ) ;
169+ break ;
170+ }
171+
172+ default : {
173+ throw new Error ( caught . data || caught . statusText ) ;
174+ }
175+ }
176+
109177 return (
110- < html >
111- < head >
112- < title > Oops!</ title >
113- < Meta />
114- < Links />
115- </ head >
116- < body >
117- < h1 >
118- { caught . status } { caught . statusText }
119- </ h1 >
120- < Scripts />
121- </ body >
122- </ html >
178+ < Document >
179+ < VStack h = "100vh" justify = "center" >
180+ { message }
181+ </ VStack >
182+ </ Document >
123183 ) ;
124184}
0 commit comments