| import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; |
| import { |
| Outlet, |
| createRootRouteWithContext, |
| useRouter, |
| HeadContent, |
| Scripts, |
| } from "@tanstack/react-router"; |
| import { useEffect, type ReactNode } from "react"; |
|
|
| import appCss from "../styles.css?url"; |
| import { reportLovableError } from "../lib/lovable-error-reporting"; |
| import { SiteHeader } from "@/components/SiteHeader"; |
| import { SiteFooter } from "@/components/SiteFooter"; |
|
|
| function NotFoundComponent() { |
| return ( |
| <div className="flex min-h-screen items-center justify-center bg-background px-4"> |
| <div className="max-w-md text-center"> |
| <h1 className="text-7xl font-bold text-foreground">404</h1> |
| <h2 className="mt-4 text-xl font-semibold text-foreground">Page not found</h2> |
| <p className="mt-2 text-sm text-muted-foreground"> |
| The page you're looking for doesn't exist or has been moved. |
| </p> |
| <div className="mt-6"> |
| <a |
| href="/" |
| className="inline-flex items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90" |
| > |
| Go home |
| </a> |
| </div> |
| </div> |
| </div> |
| ); |
| } |
|
|
| function ErrorComponent({ error, reset }: { error: Error; reset: () => void }) { |
| console.error(error); |
| const router = useRouter(); |
| useEffect(() => { |
| reportLovableError(error, { boundary: "tanstack_root_error_component" }); |
| }, [error]); |
|
|
| return ( |
| <div className="flex min-h-screen items-center justify-center bg-background px-4"> |
| <div className="max-w-md text-center"> |
| <h1 className="text-xl font-semibold tracking-tight text-foreground"> |
| This page didn't load |
| </h1> |
| <p className="mt-2 text-sm text-muted-foreground"> |
| Something went wrong on our end. You can try refreshing or head back home. |
| </p> |
| <div className="mt-6 flex flex-wrap justify-center gap-2"> |
| <button |
| onClick={() => { |
| router.invalidate(); |
| reset(); |
| }} |
| className="inline-flex items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90" |
| > |
| Try again |
| </button> |
| <a |
| href="/" |
| className="inline-flex items-center justify-center rounded-md border border-input bg-background px-4 py-2 text-sm font-medium text-foreground transition-colors hover:bg-accent" |
| > |
| Go home |
| </a> |
| </div> |
| </div> |
| </div> |
| ); |
| } |
|
|
| export const Route = createRootRouteWithContext<{ queryClient: QueryClient }>()({ |
| head: () => ({ |
| meta: [ |
| { charSet: "utf-8" }, |
| { name: "viewport", content: "width=device-width, initial-scale=1" }, |
| { title: "SafeSight — Eyes on the Road. Always." }, |
| { name: "description", content: "SafeSight monitors your driving focus and sends real-time alerts to prevent distracted driving accidents. Drive safer, arrive alive." }, |
| { property: "og:title", content: "SafeSight — Eyes on the Road. Always." }, |
| { property: "og:description", content: "SafeSight monitors your driving focus and sends real-time alerts to prevent distracted driving accidents." }, |
| { property: "og:type", content: "website" }, |
| { property: "og:site_name", content: "SafeSight" }, |
| { name: "twitter:card", content: "summary_large_image" }, |
| { name: "twitter:site", content: "@safesight" }, |
| ], |
| links: [ |
| { rel: "stylesheet", href: appCss }, |
| { rel: "icon", type: "image/png", href: "/favicon.png" }, |
| ], |
| scripts: [ |
| { |
| type: "application/ld+json", |
| children: JSON.stringify({ |
| "@context": "https://schema.org", |
| "@type": "Organization", |
| name: "SafeSight", |
| description: "Driver safety app that monitors focus and prevents distracted driving", |
| url: "/", |
| logo: "/logo.png", |
| sameAs: [], |
| }), |
| }, |
| ], |
| }), |
| shellComponent: RootShell, |
| component: RootComponent, |
| notFoundComponent: NotFoundComponent, |
| errorComponent: ErrorComponent, |
| }); |
|
|
| function RootShell({ children }: { children: ReactNode }) { |
| return ( |
| <html lang="en"> |
| <head> |
| <HeadContent /> |
| </head> |
| <body> |
| {children} |
| <Scripts /> |
| </body> |
| </html> |
| ); |
| } |
|
|
| function RootComponent() { |
| const { queryClient } = Route.useRouteContext(); |
|
|
| return ( |
| <QueryClientProvider client={queryClient}> |
| <div className="flex min-h-screen flex-col"> |
| <SiteHeader /> |
| <main className="flex-1"> |
| <Outlet /> |
| </main> |
| <SiteFooter /> |
| </div> |
| </QueryClientProvider> |
| ); |
| } |
|
|
|
|