diff --git a/new-ui/src/app/App.tsx b/new-ui/src/app/App.tsx
index ec5f23f4..161814e4 100644
--- a/new-ui/src/app/App.tsx
+++ b/new-ui/src/app/App.tsx
@@ -1,11 +1,32 @@
import { QueryClientProvider } from '@tanstack/react-query';
import { RouterProvider } from '@tanstack/react-router';
+import { type as getOsType } from '@tauri-apps/plugin-os';
+import { useEffect } from 'react';
import { MainBackground } from '../shared/components/MainBackground/MainBackground';
import { WindowDecorations } from '../shared/components/WindowDecorations/WindowDecorations';
import { queryClient } from './query';
import { router } from './router';
+const isLinux = getOsType() === 'linux';
+
+// WebKitGTK on Linux doesn't recompute 100dvh on window resize, so on Linux
+// only we track window.innerHeight in JS instead. Windows/macOS keep the
+// native 100dvh default (--app-dvh's fallback value in _shared_tokens.scss) unchanged.
+function applyLinuxViewportHeightFix(): () => void {
+ const update = () => {
+ document.documentElement.style.setProperty('--app-dvh', `${window.innerHeight}px`);
+ };
+ update();
+ window.addEventListener('resize', update);
+ return () => window.removeEventListener('resize', update);
+}
+
function App() {
+ useEffect(() => {
+ if (!isLinux) return;
+ return applyLinuxViewportHeightFix();
+ }, []);
+
return (
diff --git a/new-ui/src/pages/compact/CompactLocationsPage/style.scss b/new-ui/src/pages/compact/CompactLocationsPage/style.scss
index ede1152d..5bc5b1fc 100644
--- a/new-ui/src/pages/compact/CompactLocationsPage/style.scss
+++ b/new-ui/src/pages/compact/CompactLocationsPage/style.scss
@@ -1,7 +1,7 @@
#compact-locations-page {
display: flex;
flex-flow: column;
- height: 100dvh;
+ height: var(--app-dvh);
> .compact-footer {
display: flex;
diff --git a/new-ui/src/pages/full/OverviewPage/style.scss b/new-ui/src/pages/full/OverviewPage/style.scss
index 32d8c8a0..ef3e40bb 100644
--- a/new-ui/src/pages/full/OverviewPage/style.scss
+++ b/new-ui/src/pages/full/OverviewPage/style.scss
@@ -8,7 +8,7 @@
height: 100%;
width: 100%;
overflow: hidden;
- max-height: calc(100dvh - 50px);
+ max-height: calc(var(--app-dvh) - 50px);
}
.overview-content {
diff --git a/new-ui/src/pages/full/SessionTimeoutPage/style.scss b/new-ui/src/pages/full/SessionTimeoutPage/style.scss
index fbf91cb0..6db7d437 100644
--- a/new-ui/src/pages/full/SessionTimeoutPage/style.scss
+++ b/new-ui/src/pages/full/SessionTimeoutPage/style.scss
@@ -1,9 +1,9 @@
#session-timeout {
- min-height: 100dvh;
+ min-height: var(--app-dvh);
min-width: 100%;
> .positioner {
- height: 100dvh;
+ height: var(--app-dvh);
display: flex;
flex-flow: column;
align-items: center;
diff --git a/new-ui/src/shared/components/ModalFoundation/style.scss b/new-ui/src/shared/components/ModalFoundation/style.scss
index 4bdf7e72..9d014555 100644
--- a/new-ui/src/shared/components/ModalFoundation/style.scss
+++ b/new-ui/src/shared/components/ModalFoundation/style.scss
@@ -11,7 +11,7 @@
display: block;
content: ' ';
width: 100%;
- height: calc(100dvh - var(--window-decorations-height));
+ height: calc(var(--app-dvh) - var(--window-decorations-height));
z-index: 4;
}
@@ -21,7 +21,7 @@
left: 0;
top: var(--window-decorations-height);
width: 100%;
- height: calc(100dvh - var(--window-decorations-height));
+ height: calc(var(--app-dvh) - var(--window-decorations-height));
z-index: 4;
display: flex;
flex-flow: column;
diff --git a/new-ui/src/shared/components/WindowDecorations/WindowDecorations.tsx b/new-ui/src/shared/components/WindowDecorations/WindowDecorations.tsx
index 3994c4b2..9d07073d 100644
--- a/new-ui/src/shared/components/WindowDecorations/WindowDecorations.tsx
+++ b/new-ui/src/shared/components/WindowDecorations/WindowDecorations.tsx
@@ -29,7 +29,7 @@ export const WindowDecorations = () => {
const shouldReserveSpace = isFullView && osCheck && (isMac || !isDecorated);
document.documentElement.style.setProperty(
'--window-decorations-height',
- shouldReserveSpace ? `${decorationsHeight}px` : '0',
+ shouldReserveSpace ? `${decorationsHeight}px` : '0px',
);
}, [isDecorated]);
diff --git a/new-ui/src/shared/components/wizard/WizardPage/style.scss b/new-ui/src/shared/components/wizard/WizardPage/style.scss
index 4d909fd7..298f6737 100644
--- a/new-ui/src/shared/components/wizard/WizardPage/style.scss
+++ b/new-ui/src/shared/components/wizard/WizardPage/style.scss
@@ -1,7 +1,7 @@
.wizard-page {
--page-content-limit: 536px;
- height: calc(100dvh - var(--window-decorations-height));
+ height: calc(var(--app-dvh) - var(--window-decorations-height));
overflow-y: auto;
> .page-grid {
diff --git a/new-ui/src/shared/layouts/FullPageLayout/style.scss b/new-ui/src/shared/layouts/FullPageLayout/style.scss
index 59e4fd14..8ddcada7 100644
--- a/new-ui/src/shared/layouts/FullPageLayout/style.scss
+++ b/new-ui/src/shared/layouts/FullPageLayout/style.scss
@@ -2,7 +2,7 @@
display: grid;
grid-template-columns: 52px 1fr;
grid-template-rows: 50px 1fr;
- height: calc(100dvh - var(--window-decorations-height));
+ height: calc(var(--app-dvh) - var(--window-decorations-height));
overflow: hidden;
#window-header {
diff --git a/new-ui/src/shared/scss/_base.scss b/new-ui/src/shared/scss/_base.scss
index 5cef2d1e..deb782f0 100644
--- a/new-ui/src/shared/scss/_base.scss
+++ b/new-ui/src/shared/scss/_base.scss
@@ -25,7 +25,7 @@ body {
#root,
#app {
- min-height: 100dvh;
+ min-height: var(--app-dvh);
overflow: hidden;
}
diff --git a/new-ui/src/shared/scss/_shared_tokens.scss b/new-ui/src/shared/scss/_shared_tokens.scss
index 70e43b41..70f5e366 100644
--- a/new-ui/src/shared/scss/_shared_tokens.scss
+++ b/new-ui/src/shared/scss/_shared_tokens.scss
@@ -25,6 +25,8 @@ $jetbrains:
// set by WindowDecorations component via effect on window metadata
// --window-decorations-height: 33px;
--window-header-height: 50px;
+ // 100dvh on Windows/macOS; overridden in px on Linux by App.tsx, see applyLinuxViewportHeightFix
+ --app-dvh: 100dvh;
// font settings
--font-family-title: #{$geist};