fix(zoom): keep the window filled when zoomed out
CSS `zoom` doesn't rescale viewport units, so the 100vh app root left an empty strip below the UI when zoomed under 100%. Counter-size the app root to (100/z)vw × (100/z)vh so that, after the zoom scales it back down, it exactly fills the window again. Zoom still applies to the whole document so portalled menus/modals scale with it.
This commit is contained in:
+20
-4
@@ -845,13 +845,29 @@ export default function App() {
|
|||||||
useEffect(() => { wkEsmRef.current = wkEsm; }, [wkEsm]);
|
useEffect(() => { wkEsmRef.current = wkEsm; }, [wkEsm]);
|
||||||
|
|
||||||
// Persistent Ctrl+wheel zoom. The native WebView2 Ctrl+wheel zoom isn't saved,
|
// Persistent Ctrl+wheel zoom. The native WebView2 Ctrl+wheel zoom isn't saved,
|
||||||
// so we run our own: CSS `zoom` on the root element, factor stored in
|
// so we run our own: CSS `zoom` on the app root, factor stored in localStorage
|
||||||
// localStorage and restored at startup. Ctrl+0 resets to 100%.
|
// and restored at startup. Ctrl+0 resets to 100%.
|
||||||
|
//
|
||||||
|
// `zoom` scales the element uniformly (grid included) but does NOT rescale
|
||||||
|
// viewport units, so a 100vh/100vw root would leave an empty strip when zoomed
|
||||||
|
// out. We counter that by sizing the root to (100/z)vw × (100/z)vh so that,
|
||||||
|
// after the zoom multiplies it back down, it exactly fills the window.
|
||||||
|
const appRootRef = useRef<HTMLDivElement>(null);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const KEY = 'opslog.uiZoom';
|
const KEY = 'opslog.uiZoom';
|
||||||
let z = parseFloat(localStorage.getItem(KEY) || '1');
|
let z = parseFloat(localStorage.getItem(KEY) || '1');
|
||||||
if (!Number.isFinite(z) || z <= 0) z = 1;
|
if (!Number.isFinite(z) || z <= 0) z = 1;
|
||||||
const apply = () => { (document.documentElement.style as any).zoom = String(z); };
|
const apply = () => {
|
||||||
|
// Zoom the whole document (so portalled menus/modals/tooltips scale too)…
|
||||||
|
(document.documentElement.style as any).zoom = String(z);
|
||||||
|
// …and counter-size the app root: `zoom` doesn't rescale vh/vw, so a 100vh
|
||||||
|
// root leaves an empty strip when zoomed out. (100/z)vh zoomed by z = 100vh.
|
||||||
|
const el = appRootRef.current;
|
||||||
|
if (el) {
|
||||||
|
el.style.width = `${100 / z}vw`;
|
||||||
|
el.style.height = `${100 / z}vh`;
|
||||||
|
}
|
||||||
|
};
|
||||||
apply();
|
apply();
|
||||||
const onWheel = (e: WheelEvent) => {
|
const onWheel = (e: WheelEvent) => {
|
||||||
if (!e.ctrlKey && !e.metaKey) return; // plain wheel is left alone (scroll / freq nudge)
|
if (!e.ctrlKey && !e.metaKey) return; // plain wheel is left alone (scroll / freq nudge)
|
||||||
@@ -4034,7 +4050,7 @@ export default function App() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col h-screen overflow-hidden bg-background">
|
<div ref={appRootRef} className="flex flex-col h-screen overflow-hidden bg-background">
|
||||||
<ShutdownProgress />
|
<ShutdownProgress />
|
||||||
{/* ===== TOPBAR ===== */}
|
{/* ===== TOPBAR ===== */}
|
||||||
{compact ? (
|
{compact ? (
|
||||||
|
|||||||
Reference in New Issue
Block a user