diff --git a/dashboard/frontend/src/App.jsx b/dashboard/frontend/src/App.jsx index 1389a08..6649836 100644 --- a/dashboard/frontend/src/App.jsx +++ b/dashboard/frontend/src/App.jsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useState, useEffect } from 'react'; import Sidebar from './components/Sidebar'; import CoinsPage from './pages/CoinsPage'; import CoinHistoryPage from './pages/CoinHistoryPage'; @@ -29,34 +29,79 @@ export default function App() { const [page, setPage] = useState('coins'); const [params, setParams] = useState({}); const [refreshInterval, setRefresh] = useState(30_000); + const [isMobile, setIsMobile] = useState(window.innerWidth < 768); + const [sidebarOpen, setSidebarOpen] = useState(window.innerWidth >= 768); + + useEffect(() => { + const handler = () => { + const mobile = window.innerWidth < 768; + setIsMobile(mobile); + if (!mobile) setSidebarOpen(true); + }; + window.addEventListener('resize', handler); + return () => window.removeEventListener('resize', handler); + }, []); const navigate = (newPage, newParams = {}) => { setPage(newPage); setParams(newParams); + if (isMobile) setSidebarOpen(false); }; const Page = PAGES[page] ?? CoinsPage; return (
- navigate(p)} /> -
-
- Refresh - {REFRESH_OPTIONS.map((opt) => ( - - ))} + {/* Mobile backdrop */} + {isMobile && sidebarOpen && ( +
setSidebarOpen(false)} + style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.6)', zIndex: 199 }} + /> + )} + + navigate(p)} + open={sidebarOpen} + isMobile={isMobile} + onClose={() => setSidebarOpen(false)} + /> + +
+
+ {/* Hamburger button */} + + +
+ Refresh + {REFRESH_OPTIONS.map((opt) => ( + + ))} +
diff --git a/dashboard/frontend/src/components/Sidebar.jsx b/dashboard/frontend/src/components/Sidebar.jsx index d321852..d458631 100644 --- a/dashboard/frontend/src/components/Sidebar.jsx +++ b/dashboard/frontend/src/components/Sidebar.jsx @@ -11,7 +11,7 @@ const NAV = [ { id: 'poolcompare', label: 'Compare Pools', icon: CompareIcon, group: 'Mining' }, ]; -export default function Sidebar({ active, onNav }) { +export default function Sidebar({ active, onNav, open, isMobile, onClose }) { const [aggregatorRunning, setAggregatorRunning] = useState(null); useEffect(() => { @@ -21,14 +21,23 @@ export default function Sidebar({ active, onNav }) { return () => clearInterval(id); }, []); + if (!open) return null; + + const navStyle = isMobile + ? { ...s.nav, position: 'fixed', top: 0, left: 0, height: '100vh', zIndex: 200 } + : s.nav; + return ( -