@@ -27,38 +27,50 @@ import { TailwindIndicator } from "./components/tailwind-indicator";
27
27
import { metaDetails } from "./constants" ;
28
28
import { themeSessionResolver } from "./sessions.server" ;
29
29
import { getEnv } from "./utils/env.server" ;
30
- import { useNonce } from "./utils/nonce-provider" ;
31
30
32
- export const links : LinksFunction = ( ) => [
33
- {
34
- rel : "apple-touch-icon" ,
35
- sizes : "180x180" ,
36
- href : "/apple-touch-icon.png" ,
37
- } ,
38
- {
39
- rel : "icon" ,
40
- type : "image/png" ,
41
- sizes : "32x32" ,
42
- href : "/favicon-32x32.png" ,
43
- } ,
44
- {
45
- rel : "icon" ,
46
- type : "image/png" ,
47
- sizes : "16x16" ,
48
- href : "/favicon-16x16.png" ,
49
- } ,
50
- {
51
- rel : "mask-icon" ,
52
- href : "/safari-pinned-tab.svg" ,
53
- color : "#fb7f44" ,
54
- } ,
55
- {
56
- rel : "manifest" ,
57
- href : "/site.webmanifest" ,
58
- crossOrigin : "use-credentials" ,
59
- } ,
60
- { rel : "stylesheet" , href : styles } ,
61
- ] ;
31
+ export const links : LinksFunction = ( ) => {
32
+ const preloadedFonts = [
33
+ "GeistVariableVF.woff2" ,
34
+ "JetBrainsMono[wght].woff2" ,
35
+ "JetBrainsMono-Italic[wght].woff2" ,
36
+ ] ;
37
+ return [
38
+ {
39
+ rel : "apple-touch-icon" ,
40
+ sizes : "180x180" ,
41
+ href : "/apple-touch-icon.png" ,
42
+ } ,
43
+ {
44
+ rel : "icon" ,
45
+ type : "image/png" ,
46
+ sizes : "32x32" ,
47
+ href : "/favicon-32x32.png" ,
48
+ } ,
49
+ {
50
+ rel : "icon" ,
51
+ type : "image/png" ,
52
+ sizes : "16x16" ,
53
+ href : "/favicon-16x16.png" ,
54
+ } ,
55
+ {
56
+ rel : "mask-icon" ,
57
+ href : "/safari-pinned-tab.svg" ,
58
+ color : "#fb7f44" ,
59
+ } ,
60
+ {
61
+ rel : "manifest" ,
62
+ href : "/site.webmanifest" ,
63
+ crossOrigin : "use-credentials" ,
64
+ } ,
65
+ { rel : "stylesheet" , href : styles } ,
66
+ ...preloadedFonts . map ( ( font ) => ( {
67
+ rel : "preload" ,
68
+ as : "font" ,
69
+ href : `/fonts/${ font } ` ,
70
+ crossOrigin : "anonymous" as const ,
71
+ } ) ) ,
72
+ ] ;
73
+ } ;
62
74
63
75
export const meta : MetaFunction = ( ) => [
64
76
{
@@ -93,24 +105,25 @@ export async function loader({ request }: LoaderFunctionArgs) {
93
105
} ;
94
106
}
95
107
96
- export function Layout ( props : { children : React . ReactNode } ) {
108
+ export default function App ( ) {
97
109
const data = useLoaderData < typeof loader > ( ) ;
98
110
return (
99
111
< ThemeProvider
100
112
specifiedTheme = { data . theme }
101
113
themeAction = "/action/set-theme"
102
114
>
103
- < LayoutInner > { props . children } </ LayoutInner >
115
+ < LayoutInner >
116
+ < Outlet />
117
+ </ LayoutInner >
104
118
</ ThemeProvider >
105
119
) ;
106
120
}
107
121
108
122
export function LayoutInner ( props : { children : React . ReactNode } ) {
109
123
const data = useLoaderData < typeof loader > ( ) ;
110
124
const [ theme ] = useTheme ( ) ;
111
- const nonce = useNonce ( ) ;
112
125
113
- const isProduction = data . ENV . STAGE === "production" ;
126
+ const isProduction = data . ENV . VERCEL_ENV === "production" ;
114
127
115
128
return (
116
129
< html
@@ -137,59 +150,44 @@ export function LayoutInner(props: { children: React.ReactNode }) {
137
150
</ div >
138
151
</ div >
139
152
< TailwindIndicator />
140
- { isProduction && < VercelAnalytics /> }
141
- { isProduction && < SpeedInsights /> }
142
153
< Toaster />
143
154
< GlobalLoader />
144
155
< script
145
- nonce = { nonce }
146
156
// biome-ignore lint/security/noDangerouslySetInnerHtml: <explanation>
147
157
dangerouslySetInnerHTML = { {
148
158
__html : `window.ENV = ${ JSON . stringify ( ENV ) } ` ,
149
159
} }
150
160
/>
151
- < ScrollRestoration nonce = { nonce } />
152
- < Scripts nonce = { nonce } />
161
+ < ScrollRestoration />
162
+ < Scripts />
163
+ { isProduction && < VercelAnalytics /> }
164
+ { isProduction && < SpeedInsights /> }
153
165
</ body >
154
166
</ html >
155
167
) ;
156
168
}
157
169
158
- function App ( ) {
159
- return < Outlet /> ;
160
- }
161
-
162
- export default App ;
163
-
164
170
export function ErrorBoundary ( ) {
165
171
const error = useRouteError ( ) ;
166
172
167
173
return (
168
- < Layout >
169
- < ErrorComp />
170
- </ Layout >
171
- ) ;
172
- }
173
-
174
- function ErrorComp ( ) {
175
- const error = useRouteError ( ) ;
176
- let status = 500 ;
177
- let message = "An unexpected error occurred." ;
178
- if ( isRouteErrorResponse ( error ) ) {
179
- status = error . status ;
180
- switch ( error . status ) {
181
- case 404 :
182
- message = "Page Not Found" ;
183
- break ;
184
- }
185
- } else {
186
- console . error ( error ) ;
187
- }
188
-
189
- return (
190
- < div className = "container prose py-8" >
191
- < h1 > { status } </ h1 >
192
- < p > { message } </ p >
193
- </ div >
174
+ < html lang = "en" >
175
+ < head >
176
+ < title > Oops!</ title >
177
+ < Meta />
178
+ < Links />
179
+ </ head >
180
+ < body >
181
+ < h1 >
182
+ { isRouteErrorResponse ( error )
183
+ ? `${ error . status } ${ error . statusText } `
184
+ : error instanceof Error
185
+ ? error . message
186
+ : "Unknown Error" }
187
+ </ h1 >
188
+ < Outlet />
189
+ < Scripts />
190
+ </ body >
191
+ </ html >
194
192
) ;
195
193
}
0 commit comments