From bfe70b0b0a1e00c690cc771471fb856a33f2218d Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 16 Jun 2026 01:11:32 +0000 Subject: [PATCH 01/15] Fix clipped mobile column pager and add deck switcher to mobile top bar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- src/components/DeckArea/ColumnPageIndicator.tsx | 10 ++++++---- src/components/DeckSwitcher/Dropdown.tsx | 2 +- src/components/TopBar/index.tsx | 6 +++--- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/components/DeckArea/ColumnPageIndicator.tsx b/src/components/DeckArea/ColumnPageIndicator.tsx index 57547ab..e5439c2 100644 --- a/src/components/DeckArea/ColumnPageIndicator.tsx +++ b/src/components/DeckArea/ColumnPageIndicator.tsx @@ -17,9 +17,11 @@ type Props = { * page. The active dot tints to the column's account hue so the indicator * doubles as a "whose perspective am I on?" reference at a glance. * - * Positioned above the BottomBar via the `--bottom-bar-offset` CSS variable - * the Shell sets on its stacked-layout wrapper. `z-30` sits below the bottom - * bar (`z-40`) and below drawers / modals (`z-50+`). + * Positioned above the BottomBar. The bar is a 3rem (h-12) button row plus + * `env(safe-area-inset-bottom)` (the home-indicator inset), so the pager has + * to offset by both — offsetting by a flat 3rem tucks it behind the bar on + * home-indicator iPhones. `z-30` sits below the bottom bar (`z-40`) and below + * drawers / modals (`z-50+`). * * The buttons are wrapped in larger transparent tap-targets so a thumb can * still hit them despite the visual dot being small. @@ -33,7 +35,7 @@ export default function ColumnPageIndicator({ return (
- + {chipState.name} {chipState.showDirtyPip && ( diff --git a/src/components/TopBar/index.tsx b/src/components/TopBar/index.tsx index 6dc646f..15b9f24 100644 --- a/src/components/TopBar/index.tsx +++ b/src/components/TopBar/index.tsx @@ -1,8 +1,8 @@ /** * TopBar — single chrome region for the app shell. * - * Mobile: brand · empty middle · Add column · AccountButton compact - * (BottomBar handles Home + Post; swipe + page-dot covers nav) + * Mobile: brand · DeckSwitcher · spacer · AgentChat · Add column · Account + * (BottomBar handles Home + Post; swipe + page-dot covers column nav) * Desktop: brand · QuickJumps (5 icons) · spacer · Compose · Add column · AccountButton compact * * Surfaces Settings / Wallet / account switch via the AccountButton dropdown, @@ -47,7 +47,7 @@ export default function TopBar() { > - {!isSmallScreen && } + {!isSmallScreen && }
From 07abc2938a7c38f63169e1e950cb6bdbf95ba386 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 16 Jun 2026 01:17:11 +0000 Subject: [PATCH 02/15] Harden iOS Safari viewport handling 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 --- src/index.css | 13 +++++++++++-- src/main.tsx | 15 +++++++++++++-- src/pages/primary/NoteListPage/FeedButton.tsx | 2 +- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/index.css b/src/index.css index 5a420e3..06b69ad 100644 --- a/src/index.css +++ b/src/index.css @@ -325,8 +325,17 @@ } @media (max-width: 768px) { :root { - --deck-col-width: calc(100vw - 1rem); - --deck-placeholder-width: calc(100vw - 1rem); + /* Subtract the horizontal safe-area insets so a column never exceeds the + *visible* viewport. Plain 100vw ignores the notch/Dynamic-Island insets + in landscape on iOS Safari, which pushed columns wider than the screen + and cropped their trailing edge. Insets are 0 in portrait / on desktop, + so this is a no-op there. */ + --deck-col-width: calc( + 100vw - 1rem - env(safe-area-inset-left) - env(safe-area-inset-right) + ); + --deck-placeholder-width: calc( + 100vw - 1rem - env(safe-area-inset-left) - env(safe-area-inset-right) + ); } } diff --git a/src/main.tsx b/src/main.tsx index 6666a9a..2d5a195 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -10,10 +10,21 @@ import { ErrorBoundary } from './components/ErrorBoundary.tsx' import storage from './services/local-storage.service' const setVh = () => { + // iOS Safari's 100vh counts the area behind the dynamic toolbar, so the shell + // is sized against this --vh instead (the classic workaround). We read + // window.innerHeight, NOT visualViewport.height, on purpose: visualViewport + // shrinks when the on-screen keyboard opens, which would collapse the whole + // app shell. innerHeight stays put across keyboard toggles. document.documentElement.style.setProperty('--vh', `${window.innerHeight}px`) } -window.addEventListener('resize', setVh) -window.addEventListener('orientationchange', setVh) +// rAF-defer so the read happens after the browser has settled the new layout +// (innerHeight is briefly stale immediately after orientationchange on iOS). +const scheduleVh = () => requestAnimationFrame(setVh) +window.addEventListener('resize', scheduleVh) +window.addEventListener('orientationchange', scheduleVh) +// visualViewport fires on the Safari toolbar collapse/expand that a plain +// resize event can miss, keeping --vh in step as the chrome animates. +window.visualViewport?.addEventListener('resize', scheduleVh) setVh() const root = createRoot(document.getElementById('root')!) diff --git a/src/pages/primary/NoteListPage/FeedButton.tsx b/src/pages/primary/NoteListPage/FeedButton.tsx index 8c936ca..cb5bb8a 100644 --- a/src/pages/primary/NoteListPage/FeedButton.tsx +++ b/src/pages/primary/NoteListPage/FeedButton.tsx @@ -58,7 +58,7 @@ export default function FeedButton({
e.stopPropagation()} onTouchMove={(e) => e.stopPropagation()} > From 80198b5ffaa4508ef73d278f94ed94a6f602a7c9 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 16 Jun 2026 01:52:01 +0000 Subject: [PATCH 03/15] Fix iOS input-focus zoom and overflowing column-picker tile labels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- src/components/AddColumnModal/PickerGrid.tsx | 2 +- src/index.css | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/components/AddColumnModal/PickerGrid.tsx b/src/components/AddColumnModal/PickerGrid.tsx index ccf5c21..50e86ed 100644 --- a/src/components/AddColumnModal/PickerGrid.tsx +++ b/src/components/AddColumnModal/PickerGrid.tsx @@ -120,7 +120,7 @@ export default function PickerGrid({ onSelect }: Props) { )} > - + {t(desc.label)} {/* Keyboard-shortcut hint in the bottom-end corner. Muted + diff --git a/src/index.css b/src/index.css index 06b69ad..1653596 100644 --- a/src/index.css +++ b/src/index.css @@ -339,6 +339,26 @@ } } +/* + iOS Safari zooms the page in whenever a focused /