Add mobile-responsive design with full feature parity: - Bottom sheet (vaul) with 3 snap points for map+list coexistence - Swipeable property cards with horizontal scroll-snap - Hamburger menu with health, tasks, user info - Full-screen map with repositioned legend (top-left on mobile) - Filter FAB opening Sheet drawer - TaskProgressDrawer from bottom on mobile - All changes gated behind useIsMobile() hook (768px breakpoint) - Desktop layout completely untouched New components: MobileBottomSheet, SwipeableCardRow, PropertyCardCompact, MobileMenu Also fixes: idempotent longitude migration, React hooks order
123 lines
4.4 KiB
Markdown
123 lines
4.4 KiB
Markdown
# Mobile Responsive Design
|
|
|
|
## Goal
|
|
|
|
Make the realestate-crawler frontend fully responsive with complete feature parity on mobile devices. All desktop functionality must be preserved, adapted to mobile-friendly interaction patterns.
|
|
|
|
## Current State
|
|
|
|
The frontend (React 19, TypeScript, Vite, Tailwind CSS, Radix UI, Mapbox GL) has partial mobile support:
|
|
- `useIsMobile()` hook with 768px breakpoint
|
|
- Filter panel converts to FAB + Sheet on mobile
|
|
- Scattered `md:hidden` / `hidden md:block` patterns
|
|
|
|
Missing: bottom sheet for map+list coexistence, swipeable property cards, compact header, touch-optimized interactions, mobile task progress.
|
|
|
|
## Design Decisions
|
|
|
|
| Decision | Choice | Rationale |
|
|
|----------|--------|-----------|
|
|
| Map + list coexistence | Bottom sheet over full-screen map | Natural pattern for geo apps (Google Maps, Zillow) |
|
|
| Property browsing | Horizontal swipeable cards | Quick scanning with map context preserved |
|
|
| Heavy features (filters, POI, tasks) | Sheet drawers | Already partly implemented; consistent UX |
|
|
| Bottom sheet library | `vaul` | Lightweight (~4KB), snap points, gesture handling, Radix-compatible |
|
|
| Card swiping | CSS scroll-snap | Native, no extra dependency, smooth performance |
|
|
| Desktop impact | None | All changes gated behind `useIsMobile()` |
|
|
|
|
## Layout Architecture
|
|
|
|
### Mobile (< 768px)
|
|
|
|
```
|
|
+----------------------------+
|
|
| HEADER (compact, h-12) |
|
|
| Logo | hamburger |
|
|
+----------------------------+
|
|
| |
|
|
| |
|
|
| FULL-SCREEN MAP |
|
|
| |
|
|
| |
|
|
| |
|
|
+----------------------------+ <- draggable handle
|
|
| Bottom Sheet |
|
|
| Stats bar (compact) |
|
|
| +----+ +----+ +----+ | <- swipeable cards
|
|
| |Card|>|Card|>|Card| |
|
|
| +----+ +----+ +----+ |
|
|
| |
|
|
| (drag up to expand to |
|
|
| full list view) |
|
|
+----------------------------+
|
|
|
|
FAB buttons (bottom-right, above sheet):
|
|
Filter icon - opens filter Sheet
|
|
POI icon - opens POI manager Sheet
|
|
```
|
|
|
|
### Bottom Sheet Snap Points
|
|
|
|
- `80px` - collapsed: drag handle + listing count
|
|
- `35%` - peek (default): stats + swipeable property cards
|
|
- `85%` - expanded: full scrollable list with sort controls
|
|
|
|
### Desktop (>= 768px)
|
|
|
|
No changes. Existing layout preserved exactly.
|
|
|
|
## Component Changes
|
|
|
|
### New Components
|
|
|
|
| Component | Purpose |
|
|
|-----------|---------|
|
|
| `MobileBottomSheet` | vaul-based drawer with 3 snap points, contains stats + cards + list |
|
|
| `SwipeableCardRow` | Horizontal scroll-snap container of compact property cards, syncs with map |
|
|
| `PropertyCardCompact` | ~280px wide card for swipe browsing (thumbnail, price, beds, sqm) |
|
|
| `MobileMenu` | Hamburger menu Sheet with health, tasks, user info |
|
|
|
|
### Modified Components
|
|
|
|
| Component | Changes |
|
|
|-----------|---------|
|
|
| `App.tsx` | Conditional layout: mobile renders full-screen map + MobileBottomSheet + FABs |
|
|
| `Header.tsx` | Hamburger menu on mobile, hide inline items |
|
|
| `StatsBar.tsx` | Render inside bottom sheet header on mobile |
|
|
| `Map.tsx` | Full-screen on mobile, legend to top-left, bidirectional sync with cards |
|
|
| `ListView.tsx` | Render inside expanded bottom sheet on mobile |
|
|
| `TaskProgressDrawer.tsx` | Bottom Sheet on mobile instead of right-side drawer |
|
|
| `FilterPanel.tsx` | Touch-friendly sizing, no structural changes |
|
|
| `POIManager.tsx` | Touch-friendly sizing when in Sheet |
|
|
|
|
### Unchanged
|
|
|
|
- Backend, API, services, auth
|
|
- Core logic, data flow, state management
|
|
- Desktop layout
|
|
|
|
## Map-Card Synchronization
|
|
|
|
- Swipe to a card -> map pans/highlights that listing's marker
|
|
- Tap a map marker -> cards scroll to that listing
|
|
- Maintains spatial context during browsing
|
|
|
|
## Navigation & Touch
|
|
|
|
- Header: logo + hamburger on mobile. Hamburger opens Sheet with health, tasks, user info
|
|
- Two FABs stacked bottom-right (filter, POI). Auto-hide when sheet is fully expanded
|
|
- All tap targets minimum 44x44px
|
|
- No hover-dependent interactions on mobile (tooltips become tap-to-show)
|
|
- Map popup close buttons enlarged
|
|
- Gesture isolation: horizontal card swipe, vertical sheet drag, and map pan don't conflict
|
|
|
|
## New Dependencies
|
|
|
|
- `vaul` (~4KB gzipped) - bottom sheet drawer with snap points and gestures
|
|
|
|
## Scope Boundaries
|
|
|
|
- No new backend work
|
|
- No new API endpoints
|
|
- No changes to authentication flow
|
|
- No changes to data models
|
|
- Purely frontend layout and interaction changes
|