diff --git a/frontend/src/components/ui/Layout.jsx b/frontend/src/components/ui/Layout.jsx index 8ce11da..0b03099 100644 --- a/frontend/src/components/ui/Layout.jsx +++ b/frontend/src/components/ui/Layout.jsx @@ -1,13 +1,13 @@ import { useEffect, useState } from 'react' -import { Outlet, NavLink, useNavigate } from 'react-router-dom' +import { Outlet, NavLink, useNavigate, useLocation } from 'react-router-dom' import { useAuthStore } from '../../hooks/useAuth' import { useSyncStore, syncProgressPct } from '../../hooks/useSync' const nav = [ - { to: '/', label: 'Dashboard', icon: 'πŸ“Š', exact: true }, - { to: '/activities', label: 'Activities', icon: 'πŸƒ' }, - { to: '/health', label: 'Health', icon: '❀️' }, - { to: '/routes', label: 'Routes', icon: 'πŸ—ΊοΈ' }, + { to: '/', label: 'Dashboard', icon: 'πŸ“Š', exact: true, mobilePrimary: true }, + { to: '/activities', label: 'Activities', icon: 'πŸƒ', mobilePrimary: true }, + { to: '/health', label: 'Health', icon: '❀️', mobilePrimary: true }, + { to: '/routes', label: 'Routes', icon: 'πŸ—ΊοΈ', mobilePrimary: true }, { to: '/records', label: 'Records', icon: 'πŸ†' }, { to: '/upload', label: 'Import', icon: '⬆️' }, { to: '/profile', label: 'Profile', icon: 'βš™οΈ' }, @@ -17,14 +17,19 @@ const nav = [ export default function Layout() { const { user, logout } = useAuthStore() const navigate = useNavigate() + const location = useLocation() const { inProgress, status, startPolling, stopPolling } = useSyncStore() const [collapsed, setCollapsed] = useState(() => localStorage.getItem('navCollapsed') === '1') + const [moreOpen, setMoreOpen] = useState(false) useEffect(() => { startPolling() return () => stopPolling() }, []) + // Close the mobile "More" sheet on navigation + useEffect(() => { setMoreOpen(false) }, [location.pathname]) + const toggleCollapsed = () => { setCollapsed(c => { const next = !c @@ -39,10 +44,28 @@ export default function Layout() { } const role = user?.is_admin ? 'Administrator' : 'Member' + const visibleNav = nav.filter(({ adminOnly }) => !adminOnly || user?.is_admin) + const primaryNav = visibleNav.filter(i => i.mobilePrimary) + const moreNav = visibleNav.filter(i => !i.mobilePrimary) + const moreActive = moreNav.some(i => location.pathname.startsWith(i.to)) + + const syncProgress = ( +
+
+ + Garmin sync +
+
+
+
+

{status || 'Starting sync…'}

+
+ ) return ( -
-