Mobile-responsive UI: bottom tab nav, stacked dashboard, page fixes for phones
Build and push images / validate (push) Successful in 3s
Build and push images / build-backend (push) Successful in 6s
Build and push images / build-worker (push) Successful in 5s
Build and push images / build-frontend (push) Successful in 10s

- 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:
2026-06-12 20:52:10 +01:00
co-authored by Claude Fable 5
parent 7673452bdb
commit e7123ee5db
13 changed files with 245 additions and 68 deletions
+3 -3
View File
@@ -488,7 +488,7 @@ function DailySnapshot({ day, snapshotWeight, avg30, intradayHr, bodyBattery, bb
</span>
)}
</div>
<div className="flex items-end gap-3">
<div className="flex flex-wrap items-end gap-3">
<span className="text-4xl font-bold text-white tracking-tight">
{formatSleep(day.sleep_duration_s)}
</span>
@@ -995,7 +995,7 @@ export default function HealthPage() {
const selDateForCharts = selectedDay?.date
return (
<div className="p-6 space-y-8">
<div className="p-4 md:p-6 space-y-6 md:space-y-8">
<h1 className="text-2xl font-bold text-white">Health</h1>
<DailySnapshot
@@ -1024,7 +1024,7 @@ export default function HealthPage() {
<h2 className="text-base font-semibold text-gray-300">Trends</h2>
<p className="text-xs text-gray-600">Click any point to load that day above</p>
</div>
<div className="flex gap-1.5">
<div className="flex flex-wrap gap-1.5">
{RANGES.map(({ label, days }, i) => {
const disabled = i > maxEnabledRangeIdx
return (