Files
familysync/.planning/phases/17-ui-optimization-polish/17-03-SUMMARY.md
T
Lucas Berger 28e9ca9840 docs(17-03): complete phone layout overlap fix plan — SUMMARY.md
FAB lifted above BottomTabBar, phone content padding added, D-01
regression guard committed to layout.spec.ts; 3-profile e2e sweep green.
2026-06-18 12:54:30 -04:00

6.5 KiB
Raw Blame History

phase, plan, subsystem, tags, dependency_graph, tech_stack, key_files, decisions, metrics, status
phase plan subsystem tags dependency_graph tech_stack key_files decisions metrics status
17 03 pwa/layout
layout-fix
fab-overlap
bottom-tab-bar
phone-only
regression-guard
css-tokens
d-01
d-02
requires provides affects
apps/pwa/src/styles/tokens.css — --bottom-chrome-h token (provided by plan 17-01)
FAB overlap fix
CalendarShell.tsx FAB bottom = calc(var(--bottom-chrome-h) + var(--space-6))
Phone content padding
App.tsx contentStyle paddingBottom = var(--bottom-chrome-h) (phone-only)
Regression guard
apps/pwa/e2e/layout.spec.ts — D-01 overlap assertion (iphone + pixel)
apps/pwa/src/components/CalendarShell.tsx (FAB bottom offset)
apps/pwa/src/App.tsx (contentStyle paddingBottom)
apps/pwa/e2e/layout.spec.ts (new overlap assertion)
added patterns
CSS calc() combining --bottom-chrome-h token with --space-6 for FAB clearance above BottomTabBar
Spread pattern ...(phone ? { paddingBottom: var(--bottom-chrome-h) } : {}) for phone-only contentStyle
Playwright boundingBox() geometry assertion: fabBox.y + fabBox.height <= navBox.y
created modified
apps/pwa/src/components/CalendarShell.tsx
apps/pwa/src/App.tsx
apps/pwa/e2e/layout.spec.ts
FAB bottom uses calc(var(--bottom-chrome-h) + var(--space-6)) — positions FAB 24px above bar top edge regardless of safe-area-inset value
contentStyle paddingBottom is phone-only via spread pattern — desktop has no BottomTabBar and must not gain extra bottom padding (RESEARCH Pitfall 2)
Overlap assertion skips desktop profile — the desktop New Event button is a toolbar button, not the FAB; geometry check is semantically wrong for sidebar layout
Full e2e suite run on all three profiles confirmed zero regressions from layout changes
duration completed_date tasks_completed tasks_total files_changed
~18 minutes 2026-06-18 3 3 3
complete

Phase 17 Plan 03: Phone Layout Overlap Fix — Summary

Fixed the long-standing phone (≤767px) fixed-chrome overlap where the position: fixed BottomTabBar was covering the New Event FAB and occluding the bottom color-legend chips, using the --bottom-chrome-h token from plan 17-01. Added a permanent D-01 overlap regression assertion to layout.spec.ts. Full 3-profile Playwright suite is green.

What Was Built

One-liner: FAB lifted above BottomTabBar via calc(var(--bottom-chrome-h) + var(--space-6)), phone content reserves --bottom-chrome-h padding, permanent overlap regression guard added to CI.

Task 1: FAB lift + phone content padding (CalendarShell.tsx, App.tsx)

CalendarShell.tsx (phone-only FAB, lines 463491):

  • Changed bottom: 'var(--space-6)'bottom: 'calc(var(--bottom-chrome-h) + var(--space-6))'
  • FAB now sits 24px (var(--space-6)) above the BottomTabBar top edge regardless of safe-area-inset
  • All other FAB style properties unchanged (right, width, height, zIndex, etc.)

App.tsx (contentStyle, lines 155164):

  • Added phone-only spread: ...(phone ? { paddingBottom: 'var(--bottom-chrome-h)' } : {})
  • Phone content area now reserves space equal to the BottomTabBar height
  • Desktop branch has no paddingBottom — geometry unchanged
  • Build: pnpm --filter @familysync/pwa build exits 0

Task 2: FAB↔BottomTabBar overlap regression assertion (layout.spec.ts)

Added new test.describe block "D-01 regression guard — FAB does not overlap BottomTabBar":

  • Test name: "New Event FAB does not overlap BottomTabBar (A — phone only)"
  • Skips on desktop (testInfo.project.name === 'desktop')
  • Locates FAB via page.getByRole('button', { name: 'New Event' }) and bar via page.getByRole('navigation', { name: 'Main navigation' })
  • Asserts fabBox.y + fabBox.height <= navBox.y (FAB bottom ≤ BottomTabBar top)
  • Passes GREEN on iphone (390×844 WebKit) and pixel (412×915 Chromium)

Task 3: Small-viewport sweep across all three profiles

  • pnpm --filter @familysync/pwa test:e2e (all 3 profiles): 115 passed, 23 skipped, 0 failed
    • iphone profile: all layout.spec.ts assertions pass including new D-01 guard
    • pixel profile: all layout.spec.ts assertions pass including new D-01 guard
    • desktop profile: all layout.spec.ts assertions pass; D-01 guard correctly skipped
  • No violations flagged by Rules 14 assertions
  • Admin tab tap target still meets ≥44px after layout changes
  • Color-legend chips confirmed fully visible via playwright-cli screenshot at 390×844

Visual Confirmation (playwright-cli @390×844)

Screenshot taken via playwright-cli (Chromium, viewport 390×844, reloaded to pick up phone layout):

  • New Event FAB (+): clearly positioned above the BottomTabBar with visible gap
  • Color-legend chips ("Dev User" blue, "Family" pink): fully visible between calendar content and BottomTabBar — not clipped or occluded
  • BottomTabBar (Calendar, Lists, Admin): fully visible at the bottom edge

Verification Results

Check Result
grep 'calc(var(--bottom-chrome-h) + var(--space-6))' in CalendarShell.tsx PASS
grep "paddingBottom: 'var(--bottom-chrome-h)'" in App.tsx PASS
grep 'New Event FAB does not overlap BottomTabBar' in layout.spec.ts PASS
pnpm --filter @familysync/pwa build PASS
Playwright iphone + pixel layout.spec.ts (overlap assertion) PASS — 32 passed, 2 skipped
Full 3-profile pnpm --filter @familysync/pwa test:e2e PASS — 115 passed, 23 skipped, 0 failed
playwright-cli visual confirmation @390×844 PASS — FAB above bar, legend chips visible
Desktop geometry unchanged PASS — no desktop layout changes

Deviations from Plan

None. Plan executed exactly as written. The three-task sequence (CSS fix, regression guard, sweep) was completed without any deviations. The FAB bottom value, phone contentStyle spread pattern, and overlap assertion all match the plan specification exactly.

Known Stubs

None. All changes are wired and fully functional.

Threat Flags

None. CSS-only layout offsets plus a Playwright geometry test — no new network endpoints, auth paths, or data flows introduced.

Self-Check: PASSED

Item Result
CalendarShell.tsx exists FOUND
App.tsx exists FOUND
layout.spec.ts exists FOUND
SUMMARY.md exists FOUND
Commit 5e1c714 (Task 1) FOUND
Commit 85a803f (Task 2) FOUND
CalendarShell FAB bottom grep PASS
App.tsx paddingBottom grep PASS
layout.spec.ts overlap assertion grep PASS