Add burger menu to mobile top-bar — sidebar slides in with backdrop overlay

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
jtricerolph 2026-07-21 08:36:54 +00:00
parent 552c11864d
commit 7cf6f14aeb
2 changed files with 37 additions and 4 deletions

View file

@ -386,13 +386,38 @@ html, body, #root {
/* ── Mobile ─────────────────────────────────────────────────────── */ /* ── Mobile ─────────────────────────────────────────────────────── */
@media (max-width: 700px) { @media (max-width: 700px) {
.sidebar { display: none; } .app-shell { flex-direction: column; }
.page-content { flex-direction: column; } .sidebar {
position: fixed;
top: 0; left: 0; bottom: 0;
z-index: 200;
transform: translateX(calc(-1 * var(--sidebar-w)));
transition: transform 0.25s ease;
}
.app-shell.menu-open .sidebar { transform: translateX(0); }
.top-bar { display: flex; } .top-bar { display: flex; }
.report-view { padding: 16px; } .report-view { padding: 16px; }
.report-controls { gap: 8px; } .report-controls { gap: 8px; }
} }
.menu-backdrop {
position: fixed;
inset: 0;
background: rgba(0,0,0,0.5);
z-index: 199;
}
.top-bar-burger {
background: none;
border: none;
color: #fff;
cursor: pointer;
display: flex;
align-items: center;
padding: 4px;
flex-shrink: 0;
}
/* Sidebar scrollbar */ /* Sidebar scrollbar */
.nav-scroll::-webkit-scrollbar, .nav-scroll::-webkit-scrollbar,
.sidebar::-webkit-scrollbar, .sidebar::-webkit-scrollbar,

View file

@ -2,7 +2,7 @@ import { useEffect, useState, useCallback } from 'react'
import { import {
BarChart2, Building2, UtensilsCrossed, ShoppingCart, Database, BarChart2, Building2, UtensilsCrossed, ShoppingCart, Database,
ChevronRight, ChevronDown, Play, Download, Loader2, AlertCircle, ChevronRight, ChevronDown, Play, Download, Loader2, AlertCircle,
FileBarChart, TrendingUp, Settings, FileBarChart, TrendingUp, Settings, Menu,
} from 'lucide-react' } from 'lucide-react'
import { useAuth } from '../components/AuthGate' import { useAuth } from '../components/AuthGate'
import { fetchReports, runReport } from '../api' import { fetchReports, runReport } from '../api'
@ -276,6 +276,7 @@ export default function ReportsPage() {
const [reports, setReports] = useState<ReportMeta[]>([]) const [reports, setReports] = useState<ReportMeta[]>([])
const [selected, setSelected] = useState<ReportMeta | null>(null) const [selected, setSelected] = useState<ReportMeta | null>(null)
const [showSettings, setShowSettings] = useState(false) const [showSettings, setShowSettings] = useState(false)
const [menuOpen, setMenuOpen] = useState(false)
const [dateFrom, setDateFrom] = useState(daysAgo(7)) const [dateFrom, setDateFrom] = useState(daysAgo(7))
const [dateTo, setDateTo] = useState(today()) const [dateTo, setDateTo] = useState(today())
const [result, setResult] = useState<ReportResult | null>(null) const [result, setResult] = useState<ReportResult | null>(null)
@ -291,6 +292,7 @@ export default function ReportsPage() {
const handleSelect = useCallback((r: ReportMeta) => { const handleSelect = useCallback((r: ReportMeta) => {
setSelected(r) setSelected(r)
setShowSettings(false) setShowSettings(false)
setMenuOpen(false)
setResult(null) setResult(null)
setError(null) setError(null)
}, []) }, [])
@ -298,6 +300,7 @@ export default function ReportsPage() {
const handleSettings = useCallback(() => { const handleSettings = useCallback(() => {
setShowSettings(true) setShowSettings(true)
setSelected(null) setSelected(null)
setMenuOpen(false)
}, []) }, [])
const handleRun = async () => { const handleRun = async () => {
@ -316,11 +319,16 @@ export default function ReportsPage() {
} }
return ( return (
<div className="app-shell"> <div className={`app-shell${menuOpen ? ' menu-open' : ''}`}>
<Sidebar tree={tree} selectedId={showSettings ? '__settings__' : (selected?.id ?? null)} onSelect={handleSelect} onSettings={handleSettings} /> <Sidebar tree={tree} selectedId={showSettings ? '__settings__' : (selected?.id ?? null)} onSelect={handleSelect} onSettings={handleSettings} />
{menuOpen && <div className="menu-backdrop" onClick={() => setMenuOpen(false)} />}
{/* Mobile top bar */} {/* Mobile top bar */}
<div className="top-bar"> <div className="top-bar">
<button className="top-bar-burger" onClick={() => setMenuOpen(o => !o)}>
<Menu size={20} strokeWidth={1.75} />
</button>
<BarChart2 size={18} strokeWidth={1.75} color="var(--gold)" /> <BarChart2 size={18} strokeWidth={1.75} color="var(--gold)" />
<span className="top-bar-title">Reports</span> <span className="top-bar-title">Reports</span>
</div> </div>