diff options
| author | Ariel Costas Guerrero <94913521+arielcostas@users.noreply.github.com> | 2025-03-03 22:54:36 +0100 |
|---|---|---|
| committer | Ariel Costas Guerrero <94913521+arielcostas@users.noreply.github.com> | 2025-03-03 22:54:36 +0100 |
| commit | 2e90c813d0cf924bb9e8b383c1202aae15b14684 (patch) | |
| tree | d7dac941a482a8f0ef82645d0ffd05e1efc68e5e /src | |
| parent | 797c5f551b1bb6ddb139704eb9e8953c3bc1a8c8 (diff) | |
Add theme provider and errorBoundary
Diffstat (limited to 'src')
| -rw-r--r-- | src/ErrorBoundary.tsx | 34 | ||||
| -rw-r--r-- | src/Layout.css | 2 | ||||
| -rw-r--r-- | src/Layout.tsx | 6 | ||||
| -rw-r--r-- | src/ThemeContext.tsx | 44 | ||||
| -rw-r--r-- | src/main.tsx | 8 |
5 files changed, 88 insertions, 6 deletions
diff --git a/src/ErrorBoundary.tsx b/src/ErrorBoundary.tsx new file mode 100644 index 0000000..d3f5a60 --- /dev/null +++ b/src/ErrorBoundary.tsx @@ -0,0 +1,34 @@ +import React, { Component, ReactNode } from 'react'; + +interface ErrorBoundaryProps { + children: ReactNode; +} + +interface ErrorBoundaryState { + hasError: boolean; +} + +class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> { + constructor(props: ErrorBoundaryProps) { + super(props); + this.state = { hasError: false }; + } + + static getDerivedStateFromError(_: Error): ErrorBoundaryState { + return { hasError: true }; + } + + componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { + console.error("Uncaught error:", error, errorInfo); + } + + render() { + if (this.state.hasError) { + return <h1>Something went wrong.</h1>; + } + + return this.props.children; + } +} + +export default ErrorBoundary;
\ No newline at end of file diff --git a/src/Layout.css b/src/Layout.css index 7af97b8..0148da4 100644 --- a/src/Layout.css +++ b/src/Layout.css @@ -37,7 +37,7 @@ color: #616161; text-decoration: none; width: 33.3%; - font-size: 12px; + font-size: 14px; } .nav-item.active { diff --git a/src/Layout.tsx b/src/Layout.tsx index 34f5dbf..30db47b 100644 --- a/src/Layout.tsx +++ b/src/Layout.tsx @@ -1,6 +1,7 @@ import { ReactNode } from 'react'; import { Link, useLocation } from 'react-router'; import { MapPin, Map, Info } from 'lucide-react'; +import { useTheme } from './ThemeContext'; import './Layout.css'; interface LayoutProps { @@ -30,17 +31,14 @@ export function Layout({ children }: LayoutProps) { return ( <div className="app-container"> - {/* Main content area */} <main className="main-content"> {children} </main> - - {/* Android style bottom navigation bar */} <nav className="nav-bar"> {navItems.map(item => { const Icon = item.icon; const isActive = location.pathname.startsWith(item.path); - + return ( <Link key={item.name} diff --git a/src/ThemeContext.tsx b/src/ThemeContext.tsx new file mode 100644 index 0000000..203b70a --- /dev/null +++ b/src/ThemeContext.tsx @@ -0,0 +1,44 @@ +import { createContext, useContext, useEffect, useState, ReactNode } from 'react'; + +type Theme = 'light' | 'dark'; + +interface ThemeContextProps { + theme: Theme; + toggleTheme: () => void; +} + +const ThemeContext = createContext<ThemeContextProps | undefined>(undefined); + +export const ThemeProvider = ({ children }: { children: ReactNode }) => { + const [theme, setTheme] = useState<Theme>(() => { + const savedTheme = localStorage.getItem('theme'); + if (savedTheme) { + return savedTheme as Theme; + } + const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches; + return prefersDark ? 'dark' : 'light'; + }); + + useEffect(() => { + document.documentElement.setAttribute('data-theme', theme); + localStorage.setItem('theme', theme); + }, [theme]); + + const toggleTheme = () => { + setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light')); + }; + + return ( + <ThemeContext.Provider value={{ theme, toggleTheme }}> + {children} + </ThemeContext.Provider> + ); +}; + +export const useTheme = () => { + const context = useContext(ThemeContext); + if (!context) { + throw new Error('useTheme must be used within a ThemeProvider'); + } + return context; +};
\ No newline at end of file diff --git a/src/main.tsx b/src/main.tsx index 496acc8..762aa0d 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -8,6 +8,8 @@ import { Estimates } from './pages/Estimates.tsx' import { StopMap } from './pages/Map.tsx' import { Layout } from './Layout.tsx' import { About } from './pages/About.tsx' +import { ThemeProvider } from './ThemeContext' +import ErrorBoundary from './ErrorBoundary' const router = createBrowserRouter([ { @@ -33,5 +35,9 @@ const router = createBrowserRouter([ ]) createRoot(document.getElementById('root')!).render( - <RouterProvider router={router} />, + <ErrorBoundary> + <ThemeProvider> + <RouterProvider router={router} /> + </ThemeProvider> + </ErrorBoundary> ) |
