Compare commits

..
Author SHA1 Message Date
Richard Zink b3a298fb7c Release v202611-00016 2026-11-10 13:49:53 +01:00
Richard ZinkandClaude Opus 5.5 61219dbca2 Phone: keyboard no longer leaves the page shifted
Mobile browsers scroll the whole page up to show the focused input and do not
always scroll it back when the keyboard closes; the app never scrolls the page
itself, so the top bar (menu) stayed out of reach.

- Viewport interactive-widget=resizes-content: on Android the keyboard shrinks
  the page instead of shifting it.
- Elsewhere (iOS Safari) the page offset is undone when the visual viewport
  grows again or the input loses focus.
- The chat keeps following the latest message when its pane shrinks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 13:49:53 +01:00
5 changed files with 61 additions and 2 deletions

No files matched your search

+9
View File
@@ -3,6 +3,15 @@
All notable changes to CodeCraft. Versions follow [Semantic Versioning](https://semver.org/);
until 1.0, minor versions may contain breaking changes.
## [v202611-00016] – 2026-11-10
### Fixed
- **Phone: page stayed shifted after the keyboard closed** – the top bar (menu) was out of
reach. On Android the keyboard now shrinks the page instead of shifting it
(`interactive-widget=resizes-content`; the chat stays at its latest message); browsers that
still shift the page (iOS Safari) get it scrolled back once the keyboard closes.
## [v202611-00015] – 2026-11-10
### Fixed
+1 -1
View File
@@ -11,7 +11,7 @@
</p>
<p align="center">
<img alt="Version v202611-00015" src="https://img.shields.io/badge/version-v202611--00015-d69e2e?style=flat-square">
<img alt="Version v202611-00016" src="https://img.shields.io/badge/version-v202611--00016-d69e2e?style=flat-square">
<img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-689d6a?style=flat-square">
<img alt="Rust backend" src="https://img.shields.io/badge/backend-Rust-b7410e?style=flat-square&logo=rust">
<img alt="React PWA" src="https://img.shields.io/badge/frontend-React%20PWA-2d81ff?style=flat-square&logo=react">
+3 -1
View File
@@ -2,7 +2,9 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<!-- interactive-widget: the on-screen keyboard shrinks the page (Android) instead of
shifting it up – the top bar stays in place. -->
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover, interactive-widget=resizes-content" />
<meta name="theme-color" content="#282828" />
<link rel="icon" href="/icon.svg" type="image/svg+xml" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
+11
View File
@@ -202,6 +202,17 @@ export function ChatView({ sessionId, onMenu, onClosePane }: { sessionId: string
const el = scrollRef.current;
if (el && stick.current) el.scrollTop = el.scrollHeight;
});
// … also when the pane gets smaller (on-screen keyboard opens) without a render.
const hasSession = !!session;
useEffect(() => {
const el = scrollRef.current;
if (!el || typeof ResizeObserver === "undefined") return;
const ro = new ResizeObserver(() => {
if (stick.current) el.scrollTop = el.scrollHeight;
});
ro.observe(el);
return () => ro.disconnect();
}, [hasSession, sessionId]);
if (loadError) return <div className="empty">{loadError}</div>;
if (!session) return <div className="empty">{t("common.loading")}</div>;
+37
View File
@@ -10,6 +10,43 @@ import { captureShare } from "./share";
applyTheme();
captureShare();
registerSW({ immediate: true });
undoKeyboardShift();
/**
* Browsers that do not resize the page for the on-screen keyboard (iOS Safari, older
* Android) scroll the whole page up to show the input – and do not always scroll it back
* when the keyboard closes, leaving the top bar (menu) out of reach. The app never
* scrolls the page itself (only its panes), so any page offset is undone once the
* visible area grows again.
*/
function undoKeyboardShift() {
const vv = window.visualViewport;
if (!vv) return;
let last = vv.height;
const reset = () => {
const el = document.scrollingElement ?? document.documentElement;
if (window.scrollY !== 0 || el.scrollTop !== 0 || document.body.scrollTop !== 0) {
window.scrollTo(0, 0);
el.scrollTop = 0;
document.body.scrollTop = 0;
}
};
vv.addEventListener("resize", () => {
// Grown back (keyboard closed or closing): after the browser's own adjustment.
if (vv.height > last + 1) {
requestAnimationFrame(reset);
setTimeout(reset, 350);
}
last = vv.height;
});
// Keyboard closed by leaving the input (no resize on some browsers).
document.addEventListener("focusout", () =>
setTimeout(() => {
const a = document.activeElement;
if (!a || !(a instanceof HTMLInputElement || a instanceof HTMLTextAreaElement || (a as HTMLElement).isContentEditable)) reset();
}, 300),
);
}
createRoot(document.getElementById("root")!).render(
<StrictMode>