Mobile-responsive UI: bottom tab nav, stacked dashboard, page fixes for phones
- Layout: sidebar hidden below md; mobile top header + bottom tab bar (Dashboard/Activities/Health/Routes) with a More slide-up sheet holding Records/Import/Profile/Users, Garmin sync progress and sign-out - Dashboard: single-column widget stack on phones ordered from the saved desktop layout (stat cards pair into 2-col grid); drag-edit stays desktop-only; grid conditionally mounted so WidthProvider never measures a hidden container - New useMediaQuery/useIsMobile hook (matchMedia, md breakpoint) - ActivityDetail: 2-col stats on phones, wrapping map toolbar, Height control hidden on small screens - Activities: compact distance/time/pace line on mobile rows - Records/Users: horizontally scrollable tables; route records hide Pace/Date columns below sm - Profile forms single-column on phones; Routes expanded card stacks; Health flex-wrap fixes; p-4 md:p-6 page padding; h-dvh for mobile browser chrome - vite.config: VITE_PROXY_TARGET override for host-side dev Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
|
||||
export function useMediaQuery(query) {
|
||||
const [matches, setMatches] = useState(() => window.matchMedia(query).matches)
|
||||
useEffect(() => {
|
||||
const mql = window.matchMedia(query)
|
||||
const onChange = e => setMatches(e.matches)
|
||||
mql.addEventListener('change', onChange)
|
||||
setMatches(mql.matches)
|
||||
return () => mql.removeEventListener('change', onChange)
|
||||
}, [query])
|
||||
return matches
|
||||
}
|
||||
|
||||
// Matches Tailwind's md breakpoint — keep CSS (md:) and JS forks in agreement.
|
||||
export const useIsMobile = () => !useMediaQuery('(min-width: 768px)')
|
||||
Reference in New Issue
Block a user