mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-06 23:49:41 +02:00
fix: toolbar pushed off-screen on iPad Safari with tabs
On iPad Safari with the tab bar visible, `100vh` extends behind the browser chrome, pushing the fixed-position toolbar out of view. - Add `viewport-fit=cover` to viewport meta tag - Use `100dvh` with `100vh` fallback for body/.app height - Set `--app-height` CSS variable from `visualViewport.height` via JS - Offset fixed toolbar on iOS Safari using the layout/visual viewport delta
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
<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.0, maximum-scale=1.0, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
|
||||||
<meta name="description" content="Claude Code session manager with web interface">
|
<meta name="description" content="Claude Code session manager with web interface">
|
||||||
<meta name="theme-color" content="#0a0a0a">
|
<meta name="theme-color" content="#0a0a0a">
|
||||||
<meta name="google" content="notranslate">
|
<meta name="google" content="notranslate">
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
<script>if(window.innerWidth<768||(('ontouchstart' in window||navigator.maxTouchPoints>0)&&window.innerWidth<1024))document.documentElement.classList.add('mobile-init');</script>
|
<script>if(window.innerWidth<768||(('ontouchstart' in window||navigator.maxTouchPoints>0)&&window.innerWidth<1024))document.documentElement.classList.add('mobile-init');</script>
|
||||||
<!-- Inline critical CSS for instant skeleton paint (before styles.css loads) -->
|
<!-- Inline critical CSS for instant skeleton paint (before styles.css loads) -->
|
||||||
<style>
|
<style>
|
||||||
.loading-skeleton{display:flex;flex-direction:column;height:100vh;background:#0a0a0a}
|
.loading-skeleton{display:flex;flex-direction:column;height:100vh;height:100dvh;background:#0a0a0a}
|
||||||
.skeleton-header{height:40px;background:#111;border-bottom:1px solid #1a1a2e;display:flex;align-items:center;padding:0 12px}
|
.skeleton-header{height:40px;background:#111;border-bottom:1px solid #1a1a2e;display:flex;align-items:center;padding:0 12px}
|
||||||
.skeleton-brand{color:#60a5fa;font-size:14px;font-weight:600;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;opacity:.7}
|
.skeleton-brand{color:#60a5fa;font-size:14px;font-weight:600;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;opacity:.7}
|
||||||
.skeleton-tabs{display:flex;gap:4px;margin-left:16px}
|
.skeleton-tabs{display:flex;gap:4px;margin-left:16px}
|
||||||
|
|||||||
@@ -98,14 +98,33 @@ const MobileDetection = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/** Set --app-height CSS variable from visual viewport.
|
||||||
|
* On iPad Safari with tabs, 100vh extends behind the tab bar.
|
||||||
|
* visualViewport.height reflects the actual visible area. */
|
||||||
|
updateAppHeight() {
|
||||||
|
const vh = window.visualViewport?.height || window.innerHeight;
|
||||||
|
document.documentElement.style.setProperty('--app-height', `${vh}px`);
|
||||||
|
},
|
||||||
|
|
||||||
/** Initialize mobile detection and set up resize listener */
|
/** Initialize mobile detection and set up resize listener */
|
||||||
init() {
|
init() {
|
||||||
this.updateBodyClass();
|
this.updateBodyClass();
|
||||||
|
this.updateAppHeight();
|
||||||
|
|
||||||
|
// Update --app-height on viewport resize (orientation, tab bar toggle)
|
||||||
|
if (window.visualViewport) {
|
||||||
|
this._appHeightHandler = () => this.updateAppHeight();
|
||||||
|
window.visualViewport.addEventListener('resize', this._appHeightHandler);
|
||||||
|
}
|
||||||
|
|
||||||
// Debounced resize handler
|
// Debounced resize handler
|
||||||
let resizeTimeout;
|
let resizeTimeout;
|
||||||
this._resizeHandler = () => {
|
this._resizeHandler = () => {
|
||||||
clearTimeout(resizeTimeout);
|
clearTimeout(resizeTimeout);
|
||||||
resizeTimeout = setTimeout(() => this.updateBodyClass(), 100);
|
resizeTimeout = setTimeout(() => {
|
||||||
|
this.updateBodyClass();
|
||||||
|
this.updateAppHeight();
|
||||||
|
}, 100);
|
||||||
};
|
};
|
||||||
window.addEventListener('resize', this._resizeHandler);
|
window.addEventListener('resize', this._resizeHandler);
|
||||||
|
|
||||||
|
|||||||
@@ -1903,6 +1903,14 @@ html.mobile-init .file-browser-panel {
|
|||||||
overscroll-behavior: none;
|
overscroll-behavior: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* iPad Safari with tabs: position: fixed uses the layout viewport which extends
|
||||||
|
behind the browser chrome (tab bar). Calculate the offset between the layout
|
||||||
|
viewport (innerHeight) and the visual viewport (--app-height) to push the
|
||||||
|
toolbar into the visible area. --app-height is set by MobileDetection.updateAppHeight(). */
|
||||||
|
.ios-device.safari-browser .toolbar {
|
||||||
|
bottom: calc(var(--safe-area-bottom) + (100vh - var(--app-height, 100vh)));
|
||||||
|
}
|
||||||
|
|
||||||
.ios-device.safari-browser .terminal-container {
|
.ios-device.safari-browser .terminal-container {
|
||||||
/* Keep momentum scrolling but prevent page bounce */
|
/* Keep momentum scrolling but prevent page bounce */
|
||||||
-webkit-overflow-scrolling: touch;
|
-webkit-overflow-scrolling: touch;
|
||||||
|
|||||||
@@ -116,6 +116,8 @@ body {
|
|||||||
background: var(--bg-dark);
|
background: var(--bg-dark);
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
height: 100dvh;
|
||||||
|
height: var(--app-height, 100dvh);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,6 +126,8 @@ body {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
height: 100dvh;
|
||||||
|
height: var(--app-height, 100dvh);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compact Header */
|
/* Compact Header */
|
||||||
@@ -4447,6 +4451,7 @@ kbd {
|
|||||||
right: 0;
|
right: 0;
|
||||||
width: 340px;
|
width: 340px;
|
||||||
height: calc(100vh - var(--header-height));
|
height: calc(100vh - var(--header-height));
|
||||||
|
height: calc(100dvh - var(--header-height));
|
||||||
background: var(--bg-card);
|
background: var(--bg-card);
|
||||||
border-left: 1px solid var(--border);
|
border-left: 1px solid var(--border);
|
||||||
z-index: 10001;
|
z-index: 10001;
|
||||||
@@ -5815,6 +5820,7 @@ kbd {
|
|||||||
left: 0;
|
left: 0;
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
height: 100dvh;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
z-index: 999; /* Below windows (1000+), above panels (91) */
|
z-index: 999; /* Below windows (1000+), above panels (91) */
|
||||||
}
|
}
|
||||||
@@ -6042,6 +6048,7 @@ kbd {
|
|||||||
right: 20px;
|
right: 20px;
|
||||||
width: 280px;
|
width: 280px;
|
||||||
height: calc(100vh - var(--header-height) - var(--toolbar-height) - 40px);
|
height: calc(100vh - var(--header-height) - var(--toolbar-height) - 40px);
|
||||||
|
height: calc(100dvh - var(--header-height) - var(--toolbar-height) - 40px);
|
||||||
max-height: 600px;
|
max-height: 600px;
|
||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
min-height: 300px;
|
min-height: 300px;
|
||||||
|
|||||||
Reference in New Issue
Block a user