feat: implement Open-Meteo weather integration with backfill scripts and updated lake data models.
continuous-integration/drone/push Build encountered an error
continuous-integration/drone/push Build encountered an error
This commit is contained in:
+22
-18
@@ -1,4 +1,5 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Routes, Route, useParams, useLocation, useNavigate, Navigate } from 'react-router-dom';
|
||||
import LakeDetail from './components/LakeDetail';
|
||||
import LakesOverview from './components/LakesOverview';
|
||||
import LakeMap from './components/LakeMap';
|
||||
@@ -6,14 +7,23 @@ import Sidebar from './components/Sidebar';
|
||||
import Topbar from './components/Topbar';
|
||||
import SettingsModal from './components/SettingsModal';
|
||||
import { type Language } from './translations';
|
||||
import { lakesConfig } from '../scripts/lakesConfig';
|
||||
import { slugify } from './utils/slugify';
|
||||
import './App.css';
|
||||
|
||||
const LakeDetailWrapper = ({ language }: { language: Language }) => {
|
||||
const { slug } = useParams();
|
||||
const lake = lakesConfig.find(l => slugify(l.text) === slug);
|
||||
|
||||
if (!lake) return <Navigate to="/" replace />;
|
||||
|
||||
return <LakeDetail language={language} lakeId={lake.id} />;
|
||||
};
|
||||
|
||||
function App() {
|
||||
const [language, setLanguage] = useState<Language>('en');
|
||||
const [theme, setTheme] = useState<'dark' | 'light'>('dark');
|
||||
const [isSettingsOpen, setIsSettingsOpen] = useState(false);
|
||||
const [activeView, setActiveView] = useState<'overview' | 'detail' | 'map'>('overview');
|
||||
const [activeLakeId, setActiveLakeId] = useState<string | null>(null);
|
||||
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -22,19 +32,13 @@ function App() {
|
||||
} else {
|
||||
document.body.classList.remove('light-mode');
|
||||
}
|
||||
|
||||
// Clean up empty hash from URL (e.g. if the user clicked an empty anchor)
|
||||
if (window.location.href.endsWith('#')) {
|
||||
window.history.replaceState(null, '', window.location.href.slice(0, -1));
|
||||
}
|
||||
}, [theme]);
|
||||
|
||||
const handleSelectLake = (id: string) => {
|
||||
setActiveLakeId(id);
|
||||
setActiveView('detail');
|
||||
setIsMobileMenuOpen(false);
|
||||
};
|
||||
|
||||
const handleNavigate = (view: 'overview' | 'detail' | 'map') => {
|
||||
setActiveView(view);
|
||||
setIsMobileMenuOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="dashboard-container">
|
||||
{/* Mobile overlay */}
|
||||
@@ -48,17 +52,17 @@ function App() {
|
||||
<Sidebar
|
||||
language={language}
|
||||
onOpenSettings={() => setIsSettingsOpen(true)}
|
||||
activeView={activeView}
|
||||
onNavigate={handleNavigate}
|
||||
isMobileMenuOpen={isMobileMenuOpen}
|
||||
onCloseMobileMenu={() => setIsMobileMenuOpen(false)}
|
||||
/>
|
||||
|
||||
<div className="main-content">
|
||||
<Topbar language={language} onToggleMobileMenu={() => setIsMobileMenuOpen(!isMobileMenuOpen)} />
|
||||
{activeView === 'overview' && <LakesOverview language={language} onSelectLake={handleSelectLake} />}
|
||||
{activeView === 'detail' && <LakeDetail language={language} lakeId={activeLakeId} />}
|
||||
{activeView === 'map' && <LakeMap language={language} onSelectLake={handleSelectLake} />}
|
||||
<Routes>
|
||||
<Route path="/" element={<LakesOverview language={language} />} />
|
||||
<Route path="/map" element={<LakeMap language={language} />} />
|
||||
<Route path="/:slug" element={<LakeDetailWrapper language={language} />} />
|
||||
</Routes>
|
||||
</div>
|
||||
|
||||
{isSettingsOpen && (
|
||||
|
||||
Reference in New Issue
Block a user