@@ -36,7 +36,11 @@ import {
3636} from './components/ui/dropdown-menu.tsx'
3737import { Icon , href as iconsHref } from './components/ui/icon.tsx'
3838import { EpicToaster } from './components/ui/sonner.tsx'
39- import { ThemeSwitch , useTheme } from './routes/resources+/theme-switch.tsx'
39+ import {
40+ ThemeSwitch ,
41+ useOptionalTheme ,
42+ useTheme ,
43+ } from './routes/resources+/theme-switch.tsx'
4044import tailwindStyleSheetUrl from './styles/tailwind.css?url'
4145import { getUserId , logout } from './utils/auth.server.ts'
4246import { ClientHintCheck , getHints } from './utils/client-hints.tsx'
@@ -153,14 +157,14 @@ function Document({
153157 nonce,
154158 theme = 'light' ,
155159 env = { } ,
156- allowIndexing = true ,
157160} : {
158161 children : React . ReactNode
159162 nonce : string
160163 theme ?: Theme
161164 env ?: Record < string , string | undefined >
162165 allowIndexing ?: boolean
163166} ) {
167+ const allowIndexing = ENV . ALLOW_INDEXING !== 'false'
164168 return (
165169 < html lang = "en" className = { `${ theme } h-full overflow-x-hidden` } >
166170 < head >
@@ -188,24 +192,29 @@ function Document({
188192 )
189193}
190194
195+ export function Layout ( { children } : { children : React . ReactNode } ) {
196+ // if there was an error running the loader, data could be missing
197+ const data = useLoaderData < typeof loader | null > ( )
198+ const nonce = useNonce ( )
199+ const theme = useOptionalTheme ( )
200+ return (
201+ < Document nonce = { nonce } theme = { theme } env = { data ?. ENV } >
202+ { children }
203+ </ Document >
204+ )
205+ }
206+
191207function App ( ) {
192208 const data = useLoaderData < typeof loader > ( )
193- const nonce = useNonce ( )
194209 const user = useOptionalUser ( )
195210 const theme = useTheme ( )
196211 const matches = useMatches ( )
197212 const isOnSearchPage = matches . find ( ( m ) => m . id === 'routes/users+/index' )
198213 const searchBar = isOnSearchPage ? null : < SearchBar status = "idle" />
199- const allowIndexing = data . ENV . ALLOW_INDEXING !== 'false'
200214 useToast ( data . toast )
201215
202216 return (
203- < Document
204- nonce = { nonce }
205- theme = { theme }
206- allowIndexing = { allowIndexing }
207- env = { data . ENV }
208- >
217+ < >
209218 < div className = "flex h-screen flex-col justify-between" >
210219 < header className = "container py-6" >
211220 < nav className = "flex flex-wrap items-center justify-between gap-4 sm:flex-nowrap md:gap-8" >
@@ -237,7 +246,7 @@ function App() {
237246 </ div >
238247 < EpicToaster closeButton position = "top-center" theme = { theme } />
239248 < EpicProgress />
240- </ Document >
249+ </ >
241250 )
242251}
243252
@@ -326,21 +335,6 @@ function UserDropdown() {
326335 )
327336}
328337
329- export function ErrorBoundary ( ) {
330- // the nonce doesn't rely on the loader so we can access that
331- const nonce = useNonce ( )
332-
333- // NOTE: you cannot use useLoaderData in an ErrorBoundary because the loader
334- // likely failed to run so we have to do the best we can.
335- // We could probably do better than this (it's possible the loader did run).
336- // This would require a change in Remix.
337-
338- // Just make sure your root route never errors out and you'll always be able
339- // to give the user a better UX.
340-
341- return (
342- < Document nonce = { nonce } >
343- < GeneralErrorBoundary />
344- </ Document >
345- )
346- }
338+ // this is a last resort error boundary. There's not much useful information we
339+ // can offer at this level.
340+ export const ErrorBoundary = GeneralErrorBoundary
0 commit comments