fix(mobile): mobile browser interface fixes (#2940)#2946
Conversation
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.
|
Claude finished @Yeraze's task —— View job PR Review: Mobile Browser Interface FixesReview Tasks
✅ Comprehensive and Well-Executed Mobile UI ImprovementsThis 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
✅ CSS Architecture
✅ TypeScript Changes
Performance: Good
Security: Compliant
Testing GapsThe test plan shows incomplete mobile device testing:
Minor Issues FoundIssue 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 Issue 2: Potential FOUC RiskThe dual-property fallback pattern ( Recommendations✅ Approve with Suggestions
Overall AssessmentThis 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 |
* 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>
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: dropmin-width: 600pxon narrow viewports so backup modal fitsmap-analysis.css: time slider switches towidth: min(520px, calc(100vw - 24px))+ safe-area bottom anchorDashboard.css: 36×36 widget header buttons on touch; hide drag handle ≤768pxApp.css: ≥16px on inputs to prevent iOS zoom-on-focus; horizontal-scroll section nav; sticky composer withsafe-area-inset-bottom; 44×44 close-button targetsSecond pass — audit priorities (5 commits):
Modal.css: full-screen sheet on(max-width: 768px), scoped under.modal-overlayso per-modalmax-widthoverrides don't beat it100vh → 100dvhsweep across stylesheets and TSX (dual-property fallback in CSS, direct switch in TS)env(safe-area-inset-*)on AppBanners, SaveBar, NewsPopup, AdvancedNodeFilterPopup, SearchModal mobile branchbody { overflow-x: hidden };.dashboard-gridand.graphs-griduseminmax(min(100%, ...px), 1fr)to collapse instead of overflow on tablet widthsBuild / 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 spaceDashboard.css:798,960— non-interactive labels (.hop-bar-count,.heatmap-cell)SaveBar.css:132— 20px notification badge, not a buttonnodes.css:1320— slider readout, not interactiveNewsPopup.css:260-261— native checkbox; label is the click targetuser-scalable=noleft alone (load-bearing for keyboard); 16px input rule mitigates the zoom side effectTest plan
npm run typecheckcleannpm run buildclean (only pre-existing chunk-size / deprecation warnings)http://spire.yeraze.online:8081/meshmonitor/)🤖 Generated with Claude Code