Skip to content

Commit 8b8907c

Browse files
authored
Merge pull request #34 from arnlaugsson/fix/ipad-safari-toolbar-viewport
fix: toolbar off-screen on iPad Safari with tabs
2 parents 507423b + 2e4e646 commit 8b8907c

File tree

4 files changed

+37
-3
lines changed

4 files changed

+37
-3
lines changed

src/web/public/index.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<html lang="en">
33
<head>
44
<meta charset="UTF-8">
5-
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
66
<meta name="description" content="Claude Code session manager with web interface">
77
<meta name="theme-color" content="#0a0a0a">
88
<meta name="google" content="notranslate">
@@ -25,7 +25,7 @@
2525
<script>if(window.innerWidth<768||(('ontouchstart' in window||navigator.maxTouchPoints>0)&&window.innerWidth<1024))document.documentElement.classList.add('mobile-init');</script>
2626
<!-- Inline critical CSS for instant skeleton paint (before styles.css loads) -->
2727
<style>
28-
.loading-skeleton{display:flex;flex-direction:column;height:100vh;background:#0a0a0a}
28+
.loading-skeleton{display:flex;flex-direction:column;height:100vh;height:100dvh;background:#0a0a0a}
2929
.skeleton-header{height:40px;background:#111;border-bottom:1px solid #1a1a2e;display:flex;align-items:center;padding:0 12px}
3030
.skeleton-brand{color:#60a5fa;font-size:14px;font-weight:600;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;opacity:.7}
3131
.skeleton-tabs{display:flex;gap:4px;margin-left:16px}

src/web/public/mobile-handlers.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,14 +98,33 @@ const MobileDetection = {
9898
}
9999
},
100100

101+
/** Set --app-height CSS variable from visual viewport.
102+
* On iPad Safari with tabs, 100vh extends behind the tab bar.
103+
* visualViewport.height reflects the actual visible area. */
104+
updateAppHeight() {
105+
const vh = window.visualViewport?.height || window.innerHeight;
106+
document.documentElement.style.setProperty('--app-height', `${vh}px`);
107+
},
108+
101109
/** Initialize mobile detection and set up resize listener */
102110
init() {
103111
this.updateBodyClass();
112+
this.updateAppHeight();
113+
114+
// Update --app-height on viewport resize (orientation, tab bar toggle)
115+
if (window.visualViewport) {
116+
this._appHeightHandler = () => this.updateAppHeight();
117+
window.visualViewport.addEventListener('resize', this._appHeightHandler);
118+
}
119+
104120
// Debounced resize handler
105121
let resizeTimeout;
106122
this._resizeHandler = () => {
107123
clearTimeout(resizeTimeout);
108-
resizeTimeout = setTimeout(() => this.updateBodyClass(), 100);
124+
resizeTimeout = setTimeout(() => {
125+
this.updateBodyClass();
126+
this.updateAppHeight();
127+
}, 100);
109128
};
110129
window.addEventListener('resize', this._resizeHandler);
111130

src/web/public/mobile.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1903,6 +1903,14 @@ html.mobile-init .file-browser-panel {
19031903
overscroll-behavior: none;
19041904
}
19051905

1906+
/* iPad Safari with tabs: position: fixed uses the layout viewport which extends
1907+
behind the browser chrome (tab bar). Calculate the offset between the layout
1908+
viewport (innerHeight) and the visual viewport (--app-height) to push the
1909+
toolbar into the visible area. --app-height is set by MobileDetection.updateAppHeight(). */
1910+
.ios-device.safari-browser .toolbar {
1911+
bottom: calc(var(--safe-area-bottom) + (100vh - var(--app-height, 100vh)));
1912+
}
1913+
19061914
.ios-device.safari-browser .terminal-container {
19071915
/* Keep momentum scrolling but prevent page bounce */
19081916
-webkit-overflow-scrolling: touch;

src/web/public/styles.css

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ body {
116116
background: var(--bg-dark);
117117
color: var(--text);
118118
height: 100vh;
119+
height: 100dvh;
120+
height: var(--app-height, 100dvh);
119121
overflow: hidden;
120122
}
121123

@@ -124,6 +126,8 @@ body {
124126
display: flex;
125127
flex-direction: column;
126128
height: 100vh;
129+
height: 100dvh;
130+
height: var(--app-height, 100dvh);
127131
}
128132

129133
/* Compact Header */
@@ -4447,6 +4451,7 @@ kbd {
44474451
right: 0;
44484452
width: 340px;
44494453
height: calc(100vh - var(--header-height));
4454+
height: calc(100dvh - var(--header-height));
44504455
background: var(--bg-card);
44514456
border-left: 1px solid var(--border);
44524457
z-index: 10001;
@@ -5815,6 +5820,7 @@ kbd {
58155820
left: 0;
58165821
width: 100vw;
58175822
height: 100vh;
5823+
height: 100dvh;
58185824
pointer-events: none;
58195825
z-index: 999; /* Below windows (1000+), above panels (91) */
58205826
}
@@ -6042,6 +6048,7 @@ kbd {
60426048
right: 20px;
60436049
width: 280px;
60446050
height: calc(100vh - var(--header-height) - var(--toolbar-height) - 40px);
6051+
height: calc(100dvh - var(--header-height) - var(--toolbar-height) - 40px);
60456052
max-height: 600px;
60466053
min-width: 200px;
60476054
min-height: 300px;

0 commit comments

Comments
 (0)