aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ErrorBoundary.tsx34
-rw-r--r--src/Layout.css2
-rw-r--r--src/Layout.tsx6
-rw-r--r--src/ThemeContext.tsx44
-rw-r--r--src/main.tsx8
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>
)