@@ -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,13 @@ 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 >
162- allowIndexing ?: boolean
163165} ) {
166+ const allowIndexing = ENV . ALLOW_INDEXING !== 'false'
164167 return (
165168 < html lang = "en" className = { `${ theme } h-full overflow-x-hidden` } >
166169 < head >
@@ -188,24 +191,29 @@ function Document({
188191 )
189192}
190193
194+ export function Layout ( { children } : { children : React . ReactNode } ) {
195+ // if there was an error running the loader, data could be missing
196+ const data = useLoaderData < typeof loader | null > ( )
197+ const nonce = useNonce ( )
198+ const theme = useOptionalTheme ( )
199+ return (
200+ < Document nonce = { nonce } theme = { theme } env = { data ?. ENV } >
201+ { children }
202+ </ Document >
203+ )
204+ }
205+
191206function App ( ) {
192207 const data = useLoaderData < typeof loader > ( )
193- const nonce = useNonce ( )
194208 const user = useOptionalUser ( )
195209 const theme = useTheme ( )
196210 const matches = useMatches ( )
197211 const isOnSearchPage = matches . find ( ( m ) => m . id === 'routes/users+/index' )
198212 const searchBar = isOnSearchPage ? null : < SearchBar status = "idle" />
199- const allowIndexing = data . ENV . ALLOW_INDEXING !== 'false'
200213 useToast ( data . toast )
201214
202215 return (
203- < Document
204- nonce = { nonce }
205- theme = { theme }
206- allowIndexing = { allowIndexing }
207- env = { data . ENV }
208- >
216+ < >
209217 < div className = "flex h-screen flex-col justify-between" >
210218 < header className = "container py-6" >
211219 < nav className = "flex flex-wrap items-center justify-between gap-4 sm:flex-nowrap md:gap-8" >
@@ -237,7 +245,7 @@ function App() {
237245 </ div >
238246 < EpicToaster closeButton position = "top-center" theme = { theme } />
239247 < EpicProgress />
240- </ Document >
248+ </ >
241249 )
242250}
243251
@@ -326,21 +334,6 @@ function UserDropdown() {
326334 )
327335}
328336
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- }
337+ // this is a last resort error boundary. There's not much useful information we
338+ // can offer at this level.
339+ export const ErrorBoundary = GeneralErrorBoundary
0 commit comments