Skip to content

fix(mobile): mobile browser interface fixes (#2940)#2946

Merged
Yeraze merged 10 commits intomainfrom
feat/issue-2940-mobile-browser
May 9, 2026
Merged

fix(mobile): mobile browser interface fixes (#2940)#2946
Yeraze merged 10 commits intomainfrom
feat/issue-2940-mobile-browser

Conversation

@Yeraze
Copy link
Copy Markdown
Owner

@Yeraze Yeraze commented May 9, 2026

Summary

Fixes #2940 — comprehensive mobile browser pass across the MeshMonitor UI.

First pass — foundational fixes (5 commits):

  • messages.css: keep reply/emoji/delete actions visible on touch (@media (hover: none))
  • BackupManagement.css: drop min-width: 600px on narrow viewports so backup modal fits
  • map-analysis.css: time slider switches to width: min(520px, calc(100vw - 24px)) + safe-area bottom anchor
  • Dashboard.css: 36×36 widget header buttons on touch; hide drag handle ≤768px
  • App.css: ≥16px on inputs to prevent iOS zoom-on-focus; horizontal-scroll section nav; sticky composer with safe-area-inset-bottom; 44×44 close-button targets

Second pass — audit priorities (5 commits):

  • P1 Modal.css: full-screen sheet on (max-width: 768px), scoped under .modal-overlay so per-modal max-width overrides don't beat it
  • P2 100vh → 100dvh sweep across stylesheets and TSX (dual-property fallback in CSS, direct switch in TS)
  • P3 env(safe-area-inset-*) on AppBanners, SaveBar, NewsPopup, AdvancedNodeFilterPopup, SearchModal mobile branch
  • P4 44×44 tap targets on coarse pointers (App.css, SecurityTab, EmojiPickerModal, nodes sort-direction)
  • P5 body { overflow-x: hidden }; .dashboard-grid and .graphs-grid use minmax(min(100%, ...px), 1fr) to collapse instead of overflow on tablet widths

Build / lint: typecheck clean, build clean. Lint shows pre-existing baseline only — no new diagnostics from this branch.

Deliberate skips with rationale:

  • Sidebar.css:401,476 — landscape-density choice (28/32px); 44px would eat too much vertical space
  • Dashboard.css:798,960 — non-interactive labels (.hop-bar-count, .heatmap-cell)
  • SaveBar.css:132 — 20px notification badge, not a button
  • nodes.css:1320 — slider readout, not interactive
  • NewsPopup.css:260-261 — native checkbox; label is the click target
  • Viewport meta user-scalable=no left alone (load-bearing for keyboard); 16px input rule mitigates the zoom side effect

Test plan

  • npm run typecheck clean
  • npm run build clean (only pre-existing chunk-size / deprecation warnings)
  • Container deployed and verified loading on a real mobile browser (http://spire.yeraze.online:8081/meshmonitor/)
  • Smoke test on iOS Safari (PWA + browser tab)
  • Smoke test on Android Chrome
  • Verify modals render full-screen on phones, retain bordered card on desktop
  • Verify safe-area padding on notched devices

🤖 Generated with Claude Code

Yeraze added 10 commits May 9, 2026 17:30
Reply/emoji/delete buttons inside .message-actions are gated on :hover,
so on phones and tablets they are simply unreachable. A @media (hover:
none) override pins them visible and reflows them inline below the
bubble (mirrored for "mine" vs "theirs").
.backup-modal-content kept min-width: 600px and margin-left: var
(--sidebar-width) inside the @media (max-width: 768px) block, which
prevented the modal from fitting inside iPhone-class viewports.
Reset the floor and the sidebar offset on mobile.
The fixed 520px min-width pushed the slider off-screen on phones.
Switch to width: min(520px, calc(100vw - 24px)) so it shrinks to the
viewport, and lift the bottom anchor above the home-indicator inset
on small screens.
Widget header controls (remove, solar toggle, distance settings,
node remove) were 24x24 — too small for a finger. @media (hover:
none) bumps them to 36x36 (or comfortable padding for the inline
remove). Also hide the drag handle on phones since drag gestures
are awkward and steal title width.
A new block at the end of App.css addresses gaps that don't fit any
single component sheet:

- Force >=16px font-size on text inputs/textarea/select inside the
  768px breakpoint so iOS Safari doesn't auto-zoom on focus if the
  user-scalable=no meta is ever loosened.
- Compact the settings header card (logo/name/version) so the 4rem
  logo + 2rem padding don't dominate the viewport on phones.
- Make .section-nav scroll horizontally on mobile instead of wrapping
  into a 4-row pile of pills, with WCAG-friendly 40px tap height.
- Bump .button min-height to 44px on mobile.
- Keep .send-message-form / .send-direct-message-form pinned above
  the iPhone home-indicator safe-area inset.
- Outside any width breakpoint, enforce 44x44 hit area on .modal-close
  and .close-button for any coarse-pointer device (covers iPad in
  landscape, which is wider than 768px).
The shared `.modal-content` base in `src/components/common/Modal.css` had
no mobile branch, so the ~13 modals that cascade through it
(RebootModal, TelemetryRequestModal, WaypointEditorModal, RelayNodeModal,
ChangePasswordModal, LoginModal, TracerouteHistoryModal,
RouteSegmentTraceroutesModal, ScriptTestModal, NodeInfoModal,
PurgeDataModal, PositionOverrideModal, SystemStatusModal) were stuck at
`max-width: 500px; max-height: 80vh` on phones, leaving awkward gutters.

Add a `@media (max-width: 768px)` branch that turns the modal into a
full-height sheet using `100dvh`, drops the border radius, and pads the
body with `env(safe-area-inset-bottom)` for the home-indicator area.
Add a coarse-pointer rule to grow `.modal-close` to a 44x44 hit target.

The mobile rules are scoped under `.modal-overlay` so their specificity
(0,2,0) outranks per-modal width overrides like `.relay-node-modal`
(0,1,0); otherwise the modal-specific rules would still cap width on
mobile.
Mobile browsers shrink the visual viewport when their URL bar appears,
so `100vh` overflows the visible area and clips the bottom of the page.
`100dvh` tracks the dynamic viewport, so the chrome and the page agree.

Use the dual-property fallback in stylesheets (keep `100vh` for browsers
that ignore `dvh`, then `100dvh` overrides it) following the existing
pattern in `Sidebar.css:6-7`. For inline TSX styles, switch directly to
`100dvh` since duplicate keys aren't valid in object literals.

Touched:
- src/styles/{unified,map-analysis,dashboard,analysis-reports,users}.css
- src/components/{LoginPage,SearchModal/SearchModal}.css
- src/{main,App}.tsx, src/pages/PacketMonitorPage.tsx
- src/components/configuration/GpioPinSummary.tsx (both occurrences)
Fixed-position elements were drawing under iOS notches and home
indicators. Add `env(safe-area-inset-*)` padding so their content stays
inside the safe area.

- AppBanners: warning/update banners get inset-top padding so the text
  isn't clipped by the status-bar / notch.
- SaveBar: inset-bottom on the bottom-anchored bar so action buttons
  clear the home indicator.
- NewsPopup, AdvancedNodeFilterPopup: inset-top + inset-bottom on the
  centered overlays so the modal body keeps a margin from the notch and
  home indicator on full-screen viewports.
- SearchModal mobile branch: same insets on the full-screen sheet.
Several action buttons fall under the 44x44 iOS/Android minimum hit
target. Bump the genuinely interactive ones; mobile-cramped layout
elements (sidebar nav in landscape, badges, slider readouts, label
cells) are intentionally compact and stay as-is.

- App.css: `.send-btn` 40px -> 44x44 inside the existing
  `@media (max-width: 768px)` block.
- SecurityTab.css: `.send-notification-btn` gets a
  `(hover: none) and (pointer: coarse)` bump to 44x44 so the desktop
  shape isn't disturbed.
- EmojiPickerModal.css: `.emoji-picker-close` gets the same
  coarse-pointer 44x44 bump.
- nodes.css: `.sort-direction-btn` 36px and 32px (in two narrower
  media queries) -> 44x44.
- App.css: add `overflow-x: hidden` to `body` so a stray
  full-width child can't introduce a sideways scrollbar on phones.
- Dashboard.css and TelemetryGraphs.css: the `auto-fit` grids used
  `minmax(400-450px, 1fr)`, which forces a single track to expand past
  the viewport on 769-1024px tablet widths. Switch to
  `minmax(min(100%, ...px), 1fr)` so the column shrinks to the
  container when there's no room, instead of overflowing.

users.css `.users-container` was flagged for the 350px sidebar at
1024-1200, but the file already collapses to a single column at the
1200px breakpoint, so no change needed.
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 9, 2026

Claude finished @Yeraze's task —— View job


PR Review: Mobile Browser Interface Fixes

Review Tasks

  • Analyze scope and understand changes
  • Review core CSS mobile improvements (App.css, Modal.css)
  • Check viewport and safe-area handling
  • Review touch target improvements
  • Analyze TypeScript changes
  • Check for potential bugs or issues
  • Evaluate performance implications
  • Assess security considerations
  • Provide final recommendations

Comprehensive and Well-Executed Mobile UI Improvements

This PR implements thoughtful mobile browser optimizations with excellent attention to detail. The changes follow modern mobile web development best practices.

Code Quality: Excellent

✅ Strong Points

  1. Proper touch detection: Uses correct media queries @media (hover: none) and @media (pointer: coarse) to detect touch devices
  2. iOS-safe viewport units: Systematic migration from 100vh100dvh to handle dynamic viewport changes on mobile browsers
  3. Apple HIG compliance: 44×44px minimum touch targets follow Apple's Human Interface Guidelines
  4. Safe area handling: Comprehensive env(safe-area-inset-*) usage for notched devices
  5. Overflow prevention: Smart overflow-x: hidden and CSS Grid minmax(min(100%, Npx), 1fr) prevent tablet layout breaks

✅ CSS Architecture

  • Clean separation of concerns with scoped selectors (.modal-overlay .modal-content)
  • Fallback support: 100vh; 100dvh and env(safe-area-inset-bottom, 0) patterns
  • Responsive breakpoint consistency at 768px

✅ TypeScript Changes

  • Limited, focused changes in GpioPinSummary.tsx and PacketMonitorPage.tsx
  • Consistent inline style patterns: maxHeight: 'calc(100dvh - 2rem)'

Performance: Good

  • No performance concerns identified
  • CSS-only improvements with minimal JavaScript changes
  • Grid layout optimizations will improve tablet rendering efficiency

Security: Compliant

  • Accessibility consideration: Author correctly kept user-scalable=no but mitigates with 16px input font-sizes to prevent iOS zoom
  • No security vulnerabilities introduced

Testing Gaps

The test plan shows incomplete mobile device testing:

  • Smoke test on iOS Safari (PWA + browser tab) — Missing
  • Smoke test on Android Chrome — Missing
  • Verify safe-area padding on notched devices — Missing

Minor Issues Found

Issue 1: Backup Modal min-width Override (BackupManagement.css:31-32)

.modal-content.backup-modal {
  min-width: 600px; /* Still present */
}

@media (max-width: 768px) {
  .modal-content.backup-modal {
    min-width: 0; /* Override only in mobile */
  }
}

Impact: Desktop users might see layout shifts. Consider removing the desktop min-width entirely or using min-width: min(600px, 100vw).

Issue 2: Potential FOUC Risk

The dual-property fallback pattern (100vh100dvh) could cause brief layout shifts on older browsers that don't support dvh. Consider feature detection if this becomes problematic.

Recommendations

✅ Approve with Suggestions

  1. Complete mobile testing on actual devices before merging
  2. Consider consolidating the backup modal width logic for cleaner CSS
  3. Document the mobile testing results for future reference

Overall Assessment

This is a high-quality mobile improvement that demonstrates excellent understanding of mobile web challenges. The systematic approach across 24 files shows thorough planning and execution. The author's deliberate skips with rationale (sidebar density, non-interactive elements) show thoughtful decision-making.

Recommendation: Approve after mobile device testing completion


@Yeraze Yeraze merged commit 94f7049 into main May 9, 2026
19 checks passed
@Yeraze Yeraze deleted the feat/issue-2940-mobile-browser branch May 9, 2026 22:58
Yeraze added a commit that referenced this pull request May 10, 2026
* chore(release): bump version to 4.3.0

Headline feature: Waypoints — per-source storage, map rendering,
and in-place authoring UI for Meshtastic WAYPOINT_APP pins.

Includes since 4.2.3:
- #2936/#2938 feat(waypoints): basic waypoint support
- #2942 feat(waypoints): authoring UI for create/edit/delete
- #2937 fix(auth): bootstrap first OIDC user as admin
- #2935 fix(traceroute): stop cascading IP-style across radio segments
- #2945 feat: Tile Selection / Legend visibility toggles in Map Features
- #2944 fix: correct channel encryption label for unencrypted/shorthand PSKs
- #2946 fix(mobile): mobile browser interface fixes
- #2948 fix: map tileset selection not applying on dashboard
- docs: new Waypoints feature page; 4.3 Highlights nav entry

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs: list Waypoints under regular Features instead of 4.3 Highlights

Per Randall: Waypoints should be documented like any other feature, not
called out in the nav as a "🆕 4.3 Highlights" section.

- Drop the "🆕 4.3 Highlights" entry from the top nav and the /features/
  sidebar; restore "🆕" on 4.2 Highlights as the most-recent callout
- Add Waypoints to the regular Features sidebar list (next to Embed Maps)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs: drop version-Highlights nav sections, fold entries into Features

Removes the "🆕 4.2 / 4.1 / 4.0 Highlights" callouts from both the top
nav and the /features/ sidebar. Their pages — Analysis & Reports, Map
Analysis, Multi-Source, Per-Source Permissions, Global Settings, Store
& Forward, Geofence Triggers — now live in the regular Features list,
slotted near topically-related entries (Multi-Source / permissions
near Settings; Geofence Triggers next to Automation; Map Analysis next
to Embed Maps; Analysis & Reports next to Analytics; etc.).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Mobile browser interface

1 participant