Fieldstack
Dashboard Responsive Cleanup
Full responsive audit and implementation pass on the Fieldstack SaaS dashboard — a B2B field operations platform. Primary complaints: broken mobile layout, overflowing data tables, and inconsistent component spacing across breakpoints.
- Mobile navigation collapsed and non-functional below 768px
- Data tables overflowing viewport on all mobile breakpoints
- Sidebar overlapping content on tablet (1024px)
- Dashboard stat cards breaking to 1 column on laptop
- Button touch targets below 44px on mobile
- Typography scaling inconsistent across breakpoints
- Missing OpenGraph and Twitter card metadata on all routes
- robots.txt absent, sitemap.xml not linked in HTML
- Reusable
ResponsiveTablecomponent replacing 4 duplicated instances - Reusable
MobileDrawernavigation component - Shared spacing token system via CSS custom properties
- SEO metadata service wired into all existing routes
- Performance: removed 3 unused heavy imports (~42 kB gzip)
Human-readable summary of meaningful changes. Full git history available in the PR.
Navigation Inline mobile nav (340 lines in AppShell.tsx) extracted into a reusable MobileDrawer with focus-trap, scroll-lock, and reduced-motion support. Now used in 3 layouts.
Sidebar had z-index: 999 without a stacking context — causing overlay on main content at 768–1024px. Introduced a stacking context on the layout root and reduced sidebar z-index to 50.
Four copies of table markup replaced with a single parameterised ResponsiveTable. On mobile (<640px) it collapses to a card-per-row layout via a data-label attribute pattern.
Tables had no min-width constraint and overflow: hidden on the parent — content was being clipped silently. Added overflow-x: auto scroll wrapper and min-width: 600px on table internals.
Introduced --space-* CSS custom properties (4px base, 8-step scale) replacing 47 instances of hardcoded pixel values across 12 component files.
Grid was repeat(auto-fill, minmax(200px, 1fr)) — collapsing to 1 column at 900px due to padding. Changed to explicit repeat(2, 1fr) at tablet and repeat(4, 1fr) at desktop.
Created a useSeoMeta hook wired into the router layout. All 9 routes now have unique <title>, description, og:title, og:image, and twitter:card tags. sitemap.xml and robots.txt added to /public.
/components structure works at current scale but will need feature-based grouping as the product grows — see Future Recommendations. Key visual changes at 375px (iPhone) and 768px (iPad).
Honest observations about what's worth addressing next. Not a sales pitch.
Modal dialogs (New Job, Edit Contact) have no focus trap — keyboard users can tab behind the overlay. WCAG 2.1 AA failure and a legal risk in EU markets. The MobileDrawer delivered in this engagement includes a reference focus-trap implementation.
Currently 68 components in a single flat /components folder. Recommend migrating to feature-based grouping: /features/jobs, /features/contacts, /shared/ui. Low urgency now, high cost later.
Avatar images in the Contacts table are served as PNG without responsive sizes or lazy loading. A simple loading="lazy" attribute and WebP conversion via Vite plugin would solve it in a few hours.
<input type="date"> fallback or a mobile-first picker is the recommended fix. ResponsiveTable component renders all rows. If the Reports dataset grows beyond ~1000 rows, virtual scrolling (e.g. TanStack Virtual) will be needed to maintain performance.