fix(dashboard): stop iOS Safari zooming the whole site out on phones

Merged
DA
6h ago
+10-5

Requested by Daniel · project thread

Problem

On an iPhone every page that mounts the Stack Builder (home, catalog, component pages, trending, jobs) renders at roughly half scale: text, badges, install command and buttons all look tiny. The viewport meta tag is fine.

Cause

CartSidebar's closed panel is a position: fixed element pushed off-screen with translate-x-full (w-96 max-w-[90vw]). iOS Safari counts it in the page width: 390 + 351 = 741 px on a 390 px iPhone, so it zooms the page out to ~0.53x. That ratio matches the screenshot. Chromium leaves that overflow out of the page width, so desktop devtools never showed it. The blog doesn't mount the drawer and isn't affected.

Changes

  • CartSidebar.tsx: the panel now sits inside a fixed inset-0 overflow-hidden pointer-events-none wrapper, so nothing extends past the viewport. When closed the panel is invisible (out of tab order) and has no shadow (it used to bleed into the right edge).
  • SkillSpectorBadge.tsx (md, component page only): below sm the label wraps instead of being clipped to "Scanned by NVIDIA SkillSpe" at 375 px. From sm up it's unchanged.

Verification

  • Chromium mobile emulation at 375/390/430: no element extends past the viewport on /, /skills, /trending, a component page or /blog/ (before: the drawer reached 741 px).
  • The drawer still opens and closes, with scrollWidth = viewport.
  • Desktop 1440: the component header is pixel-identical before and after.
  • npm test (13 pass) and npm run build pass.
  • Not tested on real Safari/WebKit. The final check is on an iPhone after deploy.

Generated by Claude Code


Summary by cubic

Stops iOS Safari from zooming the whole site out to ~0.5x on iPhones. The closed cart drawer sat off-screen on a fixed element, which iOS counts in the page width (390 + 351 = 741 px on a 390 px phone) and zooms to fit; Chromium ignores that overflow, so it never showed in desktop emulation.

Changes

  • CartSidebar now clips the closed panel inside a fixed inset-0 overflow-hidden pointer-events-none wrapper and hides it (invisible, no shadow) when closed.
  • SkillSpectorBadge (component pages, md size) wraps its label below sm instead of clipping "Scanned by NVIDIA SkillSpector" at 375 px.
  • Affects the dashboard only; no new components, so docs/components.json needs no regeneration, and no new environment variables or secrets are required.