Mobile usability pass: native drill-down screens, column overview, edge-to-edge, iOS fixes#16
Merged
Merged
Conversation
The mobile column page indicator positioned itself with the orphaned `--bottom-bar-offset` CSS variable, which the Phase-2 Shell refactor stopped setting. It fell back to a flat 3rem, ignoring `env(safe-area-inset-bottom)`, so on home-indicator iPhones the pill tucked behind the taller bottom bar. Offset by the bar's true height (3rem + safe-area inset) instead. Also surface the DeckSwitcher on mobile by rendering it in the previously empty middle of the top bar, so the active deck name is visible and decks are switchable without desktop — mobile users run several decks too. The deck-name chip tightens to 120px on small screens to keep clear of the action icons. https://claude.ai/code/session_01V6XfpQLFEfySw8FLiPntcb
Three fixes for the "screen cropped weirdly" report on iOS Safari: - Mobile deck column width subtracts env(safe-area-inset-left/right). Plain 100vw ignores the notch/Dynamic-Island insets in landscape, so columns ran wider than the visible viewport and their trailing edge was cropped. Insets are 0 in portrait / on desktop, so this is a no-op there. - FeedButton popover max-height uses 100dvh instead of 100vh so it tracks the toolbar-aware dynamic viewport rather than overflowing behind the chrome. - --vh now also recomputes on visualViewport resize and is rAF-deferred, so it stays accurate through Safari toolbar collapse/expand and isn't stale right after orientationchange. Still reads window.innerHeight (not visualViewport.height) so the on-screen keyboard doesn't collapse the shell. https://claude.ai/code/session_01V6XfpQLFEfySw8FLiPntcb
iOS Safari zooms in on focus of any input with font-size < 16px and never cleanly resets, so inline inputs using text-sm (14px) — the hashtag/search pickers, search column, message compose, bunker-URI and npub-search fields — left the page stuck partially zoomed. Add an unlayered mobile rule flooring all text form controls at 16px so focus never triggers the zoom; gated to the mobile breakpoint so desktop keeps its smaller md: sizes. Also let column-picker tile labels wrap (break-words + hyphens) so a long single word like "Notifications" no longer bleeds past the tile border. https://claude.ai/code/session_01V6XfpQLFEfySw8FLiPntcb
The deck scroller's 8px top padding rendered as a dark band between the top toolbar and the column on mobile — conspicuous in the terminal preset, where the deck surface (3% L) sits darker than the card (5% L) with a bright top stripe. Drop the top padding below the mobile breakpoint so columns sit flush under the toolbar; desktop keeps its floating-card top margin. https://claude.ai/code/session_01V6XfpQLFEfySw8FLiPntcb
A relay that answers its NIP-11 info request with 401 + WWW-Authenticate: Basic (e.g. a defunct/parked host like astral.ninja) made Safari pop its native username/password sheet over the app. NIP-11 is public data, so fetch it with credentials: 'omit' — that also keeps WebKit from engaging the auth challenge, suppressing the prompt for any relay that 401s this way. https://claude.ai/code/session_01V6XfpQLFEfySw8FLiPntcb
Edge-to-edge: on mobile, columns now fill the full viewport (no side padding, no card border/rounding/shadow) so the feed bleeds to the screen edges like a native client — the card frame only ever separated side-by-side columns, which never happens on mobile. Desktop keeps its floating-card frame. Theme-agnostic (breakpoint utilities + CSS vars, not keyed to the theme preset). Page-dots: the indicator tracked the active column via scroll/scrollend events, but scrollend only shipped in Safari 18.2 and iOS momentum scrolling throttles scroll, so the active dot stayed put after a swipe (taps worked — they set the id directly). Replace it with an IntersectionObserver on the deck scroller: the most-visible column (>=50%) becomes active, so the dots update live as you pan. https://claude.ai/code/session_01V6XfpQLFEfySw8FLiPntcb
- Mute column: the last section (Muted words) scrolled under the fixed bottom bar + page-dot pager with no room to clear them. Add mobile bottom padding (6rem + safe-area inset) so it's reachable. Desktop keeps the tight pb-4. - Edge-swipe-back: swiping past the deck's left edge chained into Safari's history back-gesture, navigating off the SPA and flashing a white page. Add overscroll-x-contain to the deck scroller and overscroll-behavior: none on body/html so horizontal overscroll no longer triggers browser navigation. https://claude.ai/code/session_01V6XfpQLFEfySw8FLiPntcb
The bottom cutoff wasn't mute-specific — every column's content shared the same scroll area with no room to clear the fixed bottom bar + page-dot pager, so finite-content columns (settings, profile, mute) had their last rows hidden. Move the bottom padding from MuteListColumnBody onto the shared column-body scroll container (mobile only, 6rem + safe-area inset). Feeds just gain a little scroll-past room (NoteList adds no bottom padding of its own, so no double-pad). https://claude.ai/code/session_01V6XfpQLFEfySw8FLiPntcb
A full-screen grid of every open column in the active deck. Tap a card to jump to that column (routes through focusedColumnRequestAtom so DeckArea sets it active + scrolls it in), tap × to close it, or tap the + card to add one. Cards are static metadata (account-hue stripe + type icon + label via the existing columnLabel/COLUMN_TYPES sources), not live thumbnails — every column owns a subscription, so real snapshots would be costly; a cached first-note preview can come later. Esc closes it. Entry points: a grid button added to the mobile page-dot pill (dot taps still jump, + still adds — distinct targets) and a LayoutGrid button in the desktop top bar. Drag-reorder in the grid is deferred to a follow-up. https://claude.ai/code/session_01V6XfpQLFEfySw8FLiPntcb
- The bottom Home button (which only scrolled to the first column) becomes an Overview button (grid icon) that opens the column overview — the deck's "home base". The brand tap still scrolls to the first column. - The bottom "+" now means New column (opens the picker), not compose — a plus reading as compose was confusing. Compose moves to its own pencil button. - The page-dot pill drops its grid + add-column buttons; it's pure position + tap-to-jump again. Overview / add / compose all live in the bottom bar. - Add-column button in the top bar is now desktop-only (the bottom bar owns it on mobile), so there's a single, unambiguous add entry per surface. https://claude.ai/code/session_01V6XfpQLFEfySw8FLiPntcb
In-feed drill-downs on mobile (note threads, profiles, settings, following lists, ...) now push a full-screen native screen that slides in from the right, with the page's own back-chevron titlebar + hardware/gesture back, instead of spawning a deck column. This fixes the "tapping a note opens a confusing new column" problem while keeping the deck identity intact. Desktop is unchanged — it still spawns transient columns. How it works: - mobileNavStackAtom holds the push stack; MobileNavStack renders each entry as a SECONDARY_ROUTES page (reusing the dispatch + SecondaryPageLayout's back button), lower layers kept mounted (display:none) so scroll/state survive a back-out. - DeckManager.pushSecondaryPage intercepts on mobile: opensAsColumnOnMobile() routes feed-shaped standing surfaces (hashtag/relay/search/notifications/ bookmarks/mutes) to columns as before; everything else becomes a screen. - popstate pops one screen per back press (re-arming a history entry); the bottom bar stays visible above the stack so Overview is a one-tap escape to the deck from any depth. - normalizeToSecondaryRoute maps canonical /p/<id> to the /users/:id page route. v1 scope: no swipe-back gesture yet (back chevron + hardware back + Overview cover it), no slide-out-on-pop, LTR-only slide-in. Hashtag/relay/search stay columns. Drill-downs sign as the active account (no per-screen AccountScope). https://claude.ai/code/session_01V6XfpQLFEfySw8FLiPntcb
Two fixes to the mobile push-stack: - Back no longer animates the previous screen in from the right. Lower layers were display:none; revealing one flipped it none→block, which restarts the CSS slide-in animation. Drop display:none so lower layers stay painted and the previous screen is simply revealed beneath the top one (also makes the push slide-in show the previous screen behind it, like native). - Add an edge swipe-back gesture: a left-edge drag moves the top screen with the finger; releasing past ~1/3 width slides it off and pops. Vertical-dominant drags fall through to page scroll. The back chevron animates the same slide-out via closeTop(). https://claude.ai/code/session_01V6XfpQLFEfySw8FLiPntcb
Swiping a screen back revealed the live deck behind it — the feed you came from, which often shows the very note you opened, so it read as a second/doubled screen behind the one being dismissed. Add an opaque backdrop beneath the screen stack that hides the deck while any screen is open, so a swipe-back reveals a clean surface (or the immediate previous screen when stacked). The deck reappears once the last screen is fully popped. https://claude.ai/code/session_01V6XfpQLFEfySw8FLiPntcb
The relay NIP-11 fix missed the actual on-scroll culprit: the Nip05 component renders on every note, so scrolling verifies each author's NIP-05 by fetching their /.well-known/nostr.json. An author whose NIP-05 domain answers 401 + WWW-Authenticate: Basic (e.g. a parked host like astral.ninja) made Safari pop its native sign-in sheet. NIP-05 is public, so fetch it (and the domain pubkey lookup) with credentials: 'omit' to keep WebKit from engaging the challenge. https://claude.ai/code/session_01V6XfpQLFEfySw8FLiPntcb
Native push/pop drill-down screens, edge-to-edge columns, the column overview, the reorganized bottom bar, the mobile deck switcher, and the iOS layout/auth fixes. Arms the in-app "What's new" dialog. https://claude.ai/code/session_01V6XfpQLFEfySw8FLiPntcb
Deploying jank with
|
| Latest commit: |
6025558
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://bde3edcd.jank-4ii.pages.dev |
| Branch Preview URL: | https://claude-jank-mobile-review-x9.jank-4ii.pages.dev |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A focused pass to make jank's mobile (iOS Safari/PWA) experience genuinely usable while keeping the desktop deck identity untouched. Desktop is unchanged except it gains the new column overview button.
Navigation & layout
+that meant "compose" was confusing).Fixes
100dvhpopover,visualViewport-aware--vh).credentials: 'omit').Also merged the tombstone deck-sync fix from
main(PR #15) into the branch along the way.Test plan
npm run buildgreennpm runtest suite green (889 + new link-routing tests)Ships release notes + version bump to 26.15.0 (arms the in-app "What's new").
https://claude.ai/code/session_01V6XfpQLFEfySw8FLiPntcb
Generated by Claude Code