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 (
-