Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b3a298fb7c | ||
|
|
61219dbca2 |
No files matched your search
@@ -3,6 +3,15 @@
|
|||||||
All notable changes to CodeCraft. Versions follow [Semantic Versioning](https://semver.org/);
|
All notable changes to CodeCraft. Versions follow [Semantic Versioning](https://semver.org/);
|
||||||
until 1.0, minor versions may contain breaking changes.
|
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
|
## [v202611-00015] – 2026-11-10
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<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="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="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">
|
<img alt="React PWA" src="https://img.shields.io/badge/frontend-React%20PWA-2d81ff?style=flat-square&logo=react">
|
||||||
|
|||||||
+3
-1
@@ -2,7 +2,9 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<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" />
|
<meta name="theme-color" content="#282828" />
|
||||||
<link rel="icon" href="/icon.svg" type="image/svg+xml" />
|
<link rel="icon" href="/icon.svg" type="image/svg+xml" />
|
||||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
||||||
|
|||||||
@@ -202,6 +202,17 @@ export function ChatView({ sessionId, onMenu, onClosePane }: { sessionId: string
|
|||||||
const el = scrollRef.current;
|
const el = scrollRef.current;
|
||||||
if (el && stick.current) el.scrollTop = el.scrollHeight;
|
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 (loadError) return <div className="empty">{loadError}</div>;
|
||||||
if (!session) return <div className="empty">{t("common.loading")}</div>;
|
if (!session) return <div className="empty">{t("common.loading")}</div>;
|
||||||
|
|||||||
@@ -10,6 +10,43 @@ import { captureShare } from "./share";
|
|||||||
applyTheme();
|
applyTheme();
|
||||||
captureShare();
|
captureShare();
|
||||||
registerSW({ immediate: true });
|
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(
|
createRoot(document.getElementById("root")!).render(
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
|
|||||||
Reference in new issue
Block a user