From dc58d985e7d4f107a4d4079c61ddd8c4921f61a6 Mon Sep 17 00:00:00 2001 From: Huang Xin Date: Fri, 8 May 2026 20:31:37 +0800 Subject: [PATCH] fix(layout): center fixed modals above the on-screen keyboard on Android (#4091) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds `interactive-widget=resizes-content` to the viewport meta. iOS Safari already shrinks the layout viewport when the keyboard opens, so existing `fixed inset-0` flex-centered modals (PassphrasePrompt, GroupingModal, etc.) auto-center in the visible space. Android Chrome defaults to `resizes-visual` — only the visual viewport shrinks, layout stays full-height — leaving those modals rendered under the keyboard. Switching to `resizes-content` makes Android match iOS without any per-modal JS. Updates both the App Router viewport export (src/app/layout.tsx) and the Pages Router fallback meta (src/pages/_app.tsx). Co-authored-by: Claude Opus 4.7 (1M context) --- apps/readest-app/src/app/layout.tsx | 9 +++++++++ apps/readest-app/src/pages/_app.tsx | 9 ++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/apps/readest-app/src/app/layout.tsx b/apps/readest-app/src/app/layout.tsx index f14ccf6d..f83fdbc8 100644 --- a/apps/readest-app/src/app/layout.tsx +++ b/apps/readest-app/src/app/layout.tsx @@ -67,6 +67,15 @@ export const viewport: Viewport = { maximumScale: 1, userScalable: false, viewportFit: 'cover', + // Make Android Chrome's layout viewport shrink when the on-screen + // keyboard opens (matches iOS behavior). Without this, Android's + // default `interactive-widget=resizes-visual` keeps the layout + // viewport at full screen height while only the visual viewport + // shrinks — causing fixed `inset-0`-centered modals (passphrase + // prompt, group picker, etc.) to render under the keyboard. With + // `resizes-content`, `100vh` / flex centering naturally targets + // the available space above the keyboard. + interactiveWidget: 'resizes-content', }; export default function RootLayout({ children }: { children: React.ReactNode }) { diff --git a/apps/readest-app/src/pages/_app.tsx b/apps/readest-app/src/pages/_app.tsx index 50205794..8c707fc5 100644 --- a/apps/readest-app/src/pages/_app.tsx +++ b/apps/readest-app/src/pages/_app.tsx @@ -9,9 +9,16 @@ function MyApp({ Component, pageProps }: AppProps) { return ( <> + {/* + * `interactive-widget=resizes-content` makes Android Chrome + * shrink the layout viewport when the on-screen keyboard + * opens (matches iOS default behavior). Without it, the + * layout viewport stays full-height and `fixed inset-0`- + * centered modals render under the keyboard. + */}