You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
PR #1078 (/scan paste button placement) and PR #1032 (home-screen buttons) both reach for the same pattern to handle different padding on PWA vs non-PWA mobile:
This is a workaround. Per Josip on #1078: "approved but something smells here. I am fairly confident that this can be done better. lets just add some ticket so we don't forget this hack. problem with hacks like this is that most of the time it has other issues on different devices/sizes or bites you when you try to do something else in the future." gudnuf agrees the current shape is fragile.
Why it's a hack
useIsPwa() is a runtime media query (display-mode: standalone). That's a behavioral signal ("is this an installed PWA?"), not a layout signal. We're using it as a proxy for "how much vertical space does the browser/system chrome already leave us at the bottom?" — which is what we actually care about.
The pixel offset (pb-20 = 80px) is a guess based on visible iPhone X+ models. It doesn't track:
Other notched form factors that ship a different safe-area inset
Android PWAs (no home indicator → 80px is too much)
iPad PWA installed, landscape orientation
Future devices
It also doesn't help non-PWA mobile browsers where individual browser chromes (Safari URL bar, Chrome bottom toolbar, Brave bottom toolbar) carve up the visible viewport differently. PR fix(scan): float paste button over fullscreen scanner #1078 ended up swapping h-screen → h-dvh on the scanner for the same reason — and we should be consistent about which viewport units we trust everywhere.
Proper fix(es) to consider
env(safe-area-inset-bottom) for the bottom padding. Resolves to the real OS-reported safe-area inset; 0 in mobile browsers (already handled by the browser's own chrome), the actual home-indicator height on iOS PWA, the real navigation-bar height on Android PWA. We tried this on a fixed-positioned button mid-PR; the right shape is probably padding-bottom: max(theme(spacing.2), env(safe-area-inset-bottom))on the in-flow container, not on a fixed element.
100dvh / 100svh / 100lvh consistently. The dvh switch on QRScanner should likely propagate to Page so the whole layout reasons in the dynamic viewport instead of mixing h-dvh (Page) with h-screen (scanner).
Drop the PWA/non-PWA branch entirely — the visible difference should fall out of (1) + (2) automatically, with no useIsPwa reads on layout code.
Context
PR #1078 (
/scanpaste button placement) and PR #1032 (home-screen buttons) both reach for the same pattern to handle different padding on PWA vs non-PWA mobile:This is a workaround. Per Josip on #1078: "approved but something smells here. I am fairly confident that this can be done better. lets just add some ticket so we don't forget this hack. problem with hacks like this is that most of the time it has other issues on different devices/sizes or bites you when you try to do something else in the future." gudnuf agrees the current shape is fragile.
Why it's a hack
useIsPwa()is a runtime media query (display-mode: standalone). That's a behavioral signal ("is this an installed PWA?"), not a layout signal. We're using it as a proxy for "how much vertical space does the browser/system chrome already leave us at the bottom?" — which is what we actually care about.pb-20= 80px) is a guess based on visible iPhone X+ models. It doesn't track:h-screen→h-dvhon the scanner for the same reason — and we should be consistent about which viewport units we trust everywhere.Proper fix(es) to consider
env(safe-area-inset-bottom)for the bottom padding. Resolves to the real OS-reported safe-area inset; 0 in mobile browsers (already handled by the browser's own chrome), the actual home-indicator height on iOS PWA, the real navigation-bar height on Android PWA. We tried this on afixed-positioned button mid-PR; the right shape is probablypadding-bottom: max(theme(spacing.2), env(safe-area-inset-bottom))on the in-flow container, not on a fixed element.100dvh/100svh/100lvhconsistently. Thedvhswitch onQRScannershould likely propagate toPageso the whole layout reasons in the dynamic viewport instead of mixingh-dvh(Page) withh-screen(scanner).useIsPwareads on layout code.Files touching this pattern today:
app/routes/_protected._index.tsx(home buttons + balance) — PR fix(home): protect balance spacing on short mobile screens #1032 / commit44f7388app/routes/_protected.scan.tsx(paste button) — PR fix(scan): float paste button over fullscreen scanner #1078app/hooks/use-is-pwa.tsAcceptance criteria
sm:)isPwa &&conditionals in the layout code afterward (or, ifuseIsPwais kept for something else, none on layout/positioning).Out of scope
Page/PageContent/PageFooterbeyond what's needed to make these two screens correct.QRScanneritself.