mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-04 14:39:42 +02:00
chore: bump version to 0.1443
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
+167
-35
@@ -78,6 +78,106 @@ const BUILTIN_RESPAWN_PRESETS = [
|
||||
},
|
||||
];
|
||||
|
||||
// ============================================================================
|
||||
// Mobile Detection
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* MobileDetection - Detects device type and touch capability.
|
||||
* Updates body classes for CSS targeting.
|
||||
*/
|
||||
const MobileDetection = {
|
||||
/** Check if device supports touch input */
|
||||
isTouchDevice() {
|
||||
return 'ontouchstart' in window ||
|
||||
navigator.maxTouchPoints > 0 ||
|
||||
(window.matchMedia && window.matchMedia('(pointer: coarse)').matches);
|
||||
},
|
||||
|
||||
/** Check if device is iOS (iPhone, iPad, iPod) */
|
||||
isIOS() {
|
||||
return /iPad|iPhone|iPod/.test(navigator.userAgent) ||
|
||||
(navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
|
||||
},
|
||||
|
||||
/** Check if browser is Safari */
|
||||
isSafari() {
|
||||
return /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
||||
},
|
||||
|
||||
/** Check if screen is small (phone-sized, <430px) */
|
||||
isSmallScreen() {
|
||||
return window.innerWidth < 430;
|
||||
},
|
||||
|
||||
/** Check if screen is medium (tablet-sized, 430-768px) */
|
||||
isMediumScreen() {
|
||||
return window.innerWidth >= 430 && window.innerWidth < 768;
|
||||
},
|
||||
|
||||
/** Get device type based on screen width */
|
||||
getDeviceType() {
|
||||
const width = window.innerWidth;
|
||||
if (width < 430) return 'mobile';
|
||||
if (width < 768) return 'tablet';
|
||||
return 'desktop';
|
||||
},
|
||||
|
||||
/** Update body classes based on device detection */
|
||||
updateBodyClass() {
|
||||
const body = document.body;
|
||||
const deviceType = this.getDeviceType();
|
||||
const isTouch = this.isTouchDevice();
|
||||
|
||||
// Remove existing device classes
|
||||
body.classList.remove('device-mobile', 'device-tablet', 'device-desktop', 'touch-device', 'ios-device', 'safari-browser');
|
||||
|
||||
// Add current device class
|
||||
body.classList.add(`device-${deviceType}`);
|
||||
|
||||
// Add touch device class if applicable
|
||||
if (isTouch) {
|
||||
body.classList.add('touch-device');
|
||||
}
|
||||
|
||||
// Add iOS-specific class for safe area handling
|
||||
if (this.isIOS()) {
|
||||
body.classList.add('ios-device');
|
||||
}
|
||||
|
||||
// Add Safari class for browser-specific fixes
|
||||
if (this.isSafari()) {
|
||||
body.classList.add('safari-browser');
|
||||
}
|
||||
},
|
||||
|
||||
/** Initialize mobile detection and set up resize listener */
|
||||
init() {
|
||||
this.updateBodyClass();
|
||||
// Debounced resize handler
|
||||
let resizeTimeout;
|
||||
window.addEventListener('resize', () => {
|
||||
clearTimeout(resizeTimeout);
|
||||
resizeTimeout = setTimeout(() => this.updateBodyClass(), 100);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get unified coordinates from mouse or touch event.
|
||||
* @param {MouseEvent|TouchEvent} e - The event
|
||||
* @returns {{ clientX: number, clientY: number }} Coordinates
|
||||
*/
|
||||
function getEventCoords(e) {
|
||||
if (e.touches && e.touches.length > 0) {
|
||||
return { clientX: e.touches[0].clientX, clientY: e.touches[0].clientY };
|
||||
}
|
||||
if (e.changedTouches && e.changedTouches.length > 0) {
|
||||
return { clientX: e.changedTouches[0].clientX, clientY: e.changedTouches[0].clientY };
|
||||
}
|
||||
return { clientX: e.clientX, clientY: e.clientY };
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Accessibility: Focus Trap for Modals
|
||||
// ============================================================================
|
||||
@@ -773,6 +873,8 @@ class ClaudemanApp {
|
||||
}
|
||||
|
||||
init() {
|
||||
// Initialize mobile detection first (adds device classes to body)
|
||||
MobileDetection.init();
|
||||
this.initTerminal();
|
||||
this.loadFontSize();
|
||||
this.applyHeaderVisibilitySettings();
|
||||
@@ -4950,7 +5052,7 @@ class ClaudemanApp {
|
||||
let dragUpdateScheduled = false;
|
||||
let agentStartPositions = new Map(); // Track agent window start positions during drag
|
||||
|
||||
const mousedownHandler = (e) => {
|
||||
const startHandler = (e) => {
|
||||
// Don't drag if clicking buttons
|
||||
if (e.target.tagName === 'BUTTON' || e.target.closest('button')) return;
|
||||
|
||||
@@ -4962,8 +5064,9 @@ class ClaudemanApp {
|
||||
this.wizardPosition = { left: rect.left, top: rect.top };
|
||||
}
|
||||
|
||||
startX = e.clientX;
|
||||
startY = e.clientY;
|
||||
const coords = getEventCoords(e);
|
||||
startX = coords.clientX;
|
||||
startY = coords.clientY;
|
||||
startLeft = this.wizardPosition.left;
|
||||
startTop = this.wizardPosition.top;
|
||||
|
||||
@@ -4989,8 +5092,9 @@ class ClaudemanApp {
|
||||
const moveHandler = (e) => {
|
||||
if (!isDragging) return;
|
||||
|
||||
const dx = e.clientX - startX;
|
||||
const dy = e.clientY - startY;
|
||||
const coords = getEventCoords(e);
|
||||
const dx = coords.clientX - startX;
|
||||
const dy = coords.clientY - startY;
|
||||
|
||||
// Constrain to viewport
|
||||
const winWidth = wizardContent.offsetWidth || 480;
|
||||
@@ -5025,13 +5129,18 @@ class ClaudemanApp {
|
||||
}
|
||||
};
|
||||
|
||||
header.addEventListener('mousedown', mousedownHandler);
|
||||
// Mouse events
|
||||
header.addEventListener('mousedown', startHandler);
|
||||
document.addEventListener('mousemove', moveHandler);
|
||||
document.addEventListener('mouseup', upHandler);
|
||||
// Touch events
|
||||
header.addEventListener('touchstart', startHandler, { passive: false });
|
||||
document.addEventListener('touchmove', moveHandler, { passive: false });
|
||||
document.addEventListener('touchend', upHandler);
|
||||
|
||||
this.wizardDragListeners = {
|
||||
header,
|
||||
mousedown: mousedownHandler,
|
||||
start: startHandler,
|
||||
move: moveHandler,
|
||||
up: upHandler,
|
||||
};
|
||||
@@ -5039,10 +5148,15 @@ class ClaudemanApp {
|
||||
|
||||
cleanupWizardDragging() {
|
||||
if (this.wizardDragListeners) {
|
||||
const { header, mousedown, move, up } = this.wizardDragListeners;
|
||||
header?.removeEventListener('mousedown', mousedown);
|
||||
const { header, start, move, up } = this.wizardDragListeners;
|
||||
// Mouse events
|
||||
header?.removeEventListener('mousedown', start);
|
||||
document.removeEventListener('mousemove', move);
|
||||
document.removeEventListener('mouseup', up);
|
||||
// Touch events
|
||||
header?.removeEventListener('touchstart', start);
|
||||
document.removeEventListener('touchmove', move);
|
||||
document.removeEventListener('touchend', up);
|
||||
this.wizardDragListeners = null;
|
||||
}
|
||||
}
|
||||
@@ -8908,28 +9022,32 @@ class ClaudemanApp {
|
||||
let isDragging = false;
|
||||
let startX, startY, startLeft, startTop;
|
||||
|
||||
const onMouseDown = (e) => {
|
||||
const onStart = (e) => {
|
||||
// Only drag from header, not from buttons
|
||||
if (e.target.closest('button')) return;
|
||||
if (!panel.classList.contains('detached')) return;
|
||||
|
||||
isDragging = true;
|
||||
startX = e.clientX;
|
||||
startY = e.clientY;
|
||||
const coords = getEventCoords(e);
|
||||
startX = coords.clientX;
|
||||
startY = coords.clientY;
|
||||
const rect = panel.getBoundingClientRect();
|
||||
startLeft = rect.left;
|
||||
startTop = rect.top;
|
||||
|
||||
document.addEventListener('mousemove', onMouseMove);
|
||||
document.addEventListener('mouseup', onMouseUp);
|
||||
document.addEventListener('mousemove', onMove);
|
||||
document.addEventListener('mouseup', onEnd);
|
||||
document.addEventListener('touchmove', onMove, { passive: false });
|
||||
document.addEventListener('touchend', onEnd);
|
||||
e.preventDefault();
|
||||
};
|
||||
|
||||
const onMouseMove = (e) => {
|
||||
const onMove = (e) => {
|
||||
if (!isDragging) return;
|
||||
|
||||
const dx = e.clientX - startX;
|
||||
const dy = e.clientY - startY;
|
||||
const coords = getEventCoords(e);
|
||||
const dx = coords.clientX - startX;
|
||||
const dy = coords.clientY - startY;
|
||||
|
||||
let newLeft = startLeft + dx;
|
||||
let newTop = startTop + dy;
|
||||
@@ -8943,16 +9061,21 @@ class ClaudemanApp {
|
||||
panel.style.top = newTop + 'px';
|
||||
};
|
||||
|
||||
const onMouseUp = () => {
|
||||
const onEnd = () => {
|
||||
isDragging = false;
|
||||
document.removeEventListener('mousemove', onMouseMove);
|
||||
document.removeEventListener('mouseup', onMouseUp);
|
||||
document.removeEventListener('mousemove', onMove);
|
||||
document.removeEventListener('mouseup', onEnd);
|
||||
document.removeEventListener('touchmove', onMove);
|
||||
document.removeEventListener('touchend', onEnd);
|
||||
};
|
||||
|
||||
// Remove existing listeners before adding new ones
|
||||
header.removeEventListener('mousedown', header._dragHandler);
|
||||
header._dragHandler = onMouseDown;
|
||||
header.addEventListener('mousedown', onMouseDown);
|
||||
header.removeEventListener('touchstart', header._touchDragHandler);
|
||||
header._dragHandler = onStart;
|
||||
header._touchDragHandler = onStart;
|
||||
header.addEventListener('mousedown', onStart);
|
||||
header.addEventListener('touchstart', onStart, { passive: false });
|
||||
}
|
||||
|
||||
// ========== Subagents Panel Detach & Drag ==========
|
||||
@@ -8994,28 +9117,32 @@ class ClaudemanApp {
|
||||
let isDragging = false;
|
||||
let startX, startY, startLeft, startTop;
|
||||
|
||||
const onMouseDown = (e) => {
|
||||
const onStart = (e) => {
|
||||
// Only drag from header, not from buttons
|
||||
if (e.target.closest('button')) return;
|
||||
if (!panel.classList.contains('detached')) return;
|
||||
|
||||
isDragging = true;
|
||||
startX = e.clientX;
|
||||
startY = e.clientY;
|
||||
const coords = getEventCoords(e);
|
||||
startX = coords.clientX;
|
||||
startY = coords.clientY;
|
||||
const rect = panel.getBoundingClientRect();
|
||||
startLeft = rect.left;
|
||||
startTop = rect.top;
|
||||
|
||||
document.addEventListener('mousemove', onMouseMove);
|
||||
document.addEventListener('mouseup', onMouseUp);
|
||||
document.addEventListener('mousemove', onMove);
|
||||
document.addEventListener('mouseup', onEnd);
|
||||
document.addEventListener('touchmove', onMove, { passive: false });
|
||||
document.addEventListener('touchend', onEnd);
|
||||
e.preventDefault();
|
||||
};
|
||||
|
||||
const onMouseMove = (e) => {
|
||||
const onMove = (e) => {
|
||||
if (!isDragging) return;
|
||||
|
||||
const dx = e.clientX - startX;
|
||||
const dy = e.clientY - startY;
|
||||
const coords = getEventCoords(e);
|
||||
const dx = coords.clientX - startX;
|
||||
const dy = coords.clientY - startY;
|
||||
|
||||
let newLeft = startLeft + dx;
|
||||
let newTop = startTop + dy;
|
||||
@@ -9029,16 +9156,21 @@ class ClaudemanApp {
|
||||
panel.style.top = newTop + 'px';
|
||||
};
|
||||
|
||||
const onMouseUp = () => {
|
||||
const onEnd = () => {
|
||||
isDragging = false;
|
||||
document.removeEventListener('mousemove', onMouseMove);
|
||||
document.removeEventListener('mouseup', onMouseUp);
|
||||
document.removeEventListener('mousemove', onMove);
|
||||
document.removeEventListener('mouseup', onEnd);
|
||||
document.removeEventListener('touchmove', onMove);
|
||||
document.removeEventListener('touchend', onEnd);
|
||||
};
|
||||
|
||||
// Remove existing listeners before adding new ones
|
||||
header.removeEventListener('mousedown', header._dragHandler);
|
||||
header._dragHandler = onMouseDown;
|
||||
header.addEventListener('mousedown', onMouseDown);
|
||||
header.removeEventListener('touchstart', header._touchDragHandler);
|
||||
header._dragHandler = onStart;
|
||||
header._touchDragHandler = onStart;
|
||||
header.addEventListener('mousedown', onStart);
|
||||
header.addEventListener('touchstart', onStart, { passive: false });
|
||||
}
|
||||
|
||||
renderTaskPanel() {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="description" content="Claude Code session manager with web interface">
|
||||
<meta name="theme-color" content="#0a0a0a">
|
||||
<title>Claudeman</title>
|
||||
|
||||
@@ -26,6 +26,15 @@
|
||||
--session-blue: #3b82f6;
|
||||
--session-purple: #a855f7;
|
||||
--session-pink: #ec4899;
|
||||
|
||||
/* Safe area insets for notched devices (iPhone X+, Dynamic Island) */
|
||||
--safe-area-top: env(safe-area-inset-top, 0px);
|
||||
--safe-area-bottom: env(safe-area-inset-bottom, 0px);
|
||||
--safe-area-left: env(safe-area-inset-left, 0px);
|
||||
--safe-area-right: env(safe-area-inset-right, 0px);
|
||||
|
||||
/* Touch target minimum (iOS Human Interface Guidelines) */
|
||||
--touch-target-min: 44px;
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
@@ -7776,3 +7785,343 @@ kbd {
|
||||
.advanced-options-content {
|
||||
padding-left: 0.5rem;
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
Mobile & Touch Device Optimizations
|
||||
============================================================================ */
|
||||
|
||||
/* Touch-friendly sizing for touch devices */
|
||||
.touch-device .btn-toolbar {
|
||||
min-height: var(--touch-target-min);
|
||||
min-width: var(--touch-target-min);
|
||||
}
|
||||
|
||||
.touch-device .btn-icon-header,
|
||||
.touch-device .btn-icon-sm,
|
||||
.touch-device .btn-icon-only {
|
||||
min-height: var(--touch-target-min);
|
||||
min-width: var(--touch-target-min);
|
||||
}
|
||||
|
||||
.touch-device .session-tab {
|
||||
min-height: var(--touch-target-min);
|
||||
padding: 0.5rem 0.75rem;
|
||||
}
|
||||
|
||||
/* Always show close/gear buttons on touch devices (no hover) */
|
||||
.touch-device .session-tab .tab-close,
|
||||
.touch-device .session-tab .tab-gear {
|
||||
opacity: 1;
|
||||
width: auto;
|
||||
padding: 0.2rem 0.4rem;
|
||||
}
|
||||
|
||||
.touch-device .tab-count-btn {
|
||||
min-height: var(--touch-target-min);
|
||||
min-width: var(--touch-target-min);
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
Tablet Breakpoint (430px - 768px)
|
||||
============================================================================ */
|
||||
@media (max-width: 768px) and (min-width: 430px) {
|
||||
/* Safe area padding for iOS devices */
|
||||
.ios-device .app {
|
||||
padding-left: var(--safe-area-left);
|
||||
padding-right: var(--safe-area-right);
|
||||
}
|
||||
|
||||
/* Increase header height for better touch targets */
|
||||
.header {
|
||||
min-height: 48px;
|
||||
padding: 0.5rem 0.75rem;
|
||||
}
|
||||
|
||||
/* Stack panels vertically */
|
||||
.monitor-panel,
|
||||
.subagents-panel {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
border-radius: 8px 8px 0 0;
|
||||
}
|
||||
|
||||
/* Larger toolbar buttons */
|
||||
.btn-toolbar {
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
/* Session tabs horizontal scroll */
|
||||
.session-tabs {
|
||||
flex-wrap: nowrap;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.session-tabs::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
Phone Breakpoint (<430px)
|
||||
============================================================================ */
|
||||
@media (max-width: 430px) {
|
||||
/* Safe area padding for iOS devices */
|
||||
.ios-device .app {
|
||||
padding-top: var(--safe-area-top);
|
||||
padding-left: var(--safe-area-left);
|
||||
padding-right: var(--safe-area-right);
|
||||
}
|
||||
|
||||
/* Hide header brand on phones */
|
||||
.header-brand {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Hide font controls on phones */
|
||||
.header-font-controls {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Hide system stats on phones */
|
||||
.header-system-stats {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Compact header */
|
||||
.header {
|
||||
min-height: 48px;
|
||||
padding: 0.4rem;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.header-right {
|
||||
padding-left: 0.5rem;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
/* Full-width session tabs with horizontal scroll */
|
||||
.session-tabs {
|
||||
flex: 1;
|
||||
flex-wrap: nowrap;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
scrollbar-width: none;
|
||||
max-height: 56px;
|
||||
}
|
||||
|
||||
.session-tabs::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.session-tab {
|
||||
flex-shrink: 0;
|
||||
min-height: var(--touch-target-min);
|
||||
padding: 0.5rem 0.75rem;
|
||||
}
|
||||
|
||||
/* Simplified toolbar */
|
||||
.toolbar {
|
||||
height: auto;
|
||||
min-height: var(--toolbar-height);
|
||||
padding: 0.5rem;
|
||||
padding-bottom: calc(0.5rem + var(--safe-area-bottom));
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
/* Hide secondary toolbar groups */
|
||||
.toolbar-center {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.toolbar-left .toolbar-group:not(:first-child) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Full-width primary toolbar group */
|
||||
.toolbar-left {
|
||||
flex: 1;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.toolbar-left .toolbar-group:first-child {
|
||||
flex: 1;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
/* Larger toolbar buttons for touch */
|
||||
.btn-toolbar {
|
||||
min-height: var(--touch-target-min);
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.btn-toolbar.btn-claude {
|
||||
flex: 1;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* Full-width panels */
|
||||
.monitor-panel,
|
||||
.subagents-panel {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
border-radius: 8px 8px 0 0;
|
||||
}
|
||||
|
||||
/* Full-screen modals on phones */
|
||||
.modal-content {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
border-radius: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Modal safe area padding */
|
||||
.ios-device .modal-content {
|
||||
padding-top: var(--safe-area-top);
|
||||
padding-bottom: var(--safe-area-bottom);
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding: 1rem;
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.modal-footer,
|
||||
.form-actions {
|
||||
padding: 1rem;
|
||||
padding-bottom: calc(1rem + var(--safe-area-bottom));
|
||||
}
|
||||
|
||||
/* Terminal container safe area */
|
||||
.ios-device .terminal-container {
|
||||
padding-bottom: var(--safe-area-bottom);
|
||||
}
|
||||
|
||||
/* Welcome overlay adjustments */
|
||||
.welcome-content {
|
||||
padding: 1.5rem 1rem;
|
||||
}
|
||||
|
||||
.welcome-title {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.welcome-actions {
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.welcome-btn {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
min-height: var(--touch-target-min);
|
||||
}
|
||||
|
||||
/* Ralph wizard responsive */
|
||||
.modal-wizard {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.wizard-progress {
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.wizard-step-label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Tab count group responsive */
|
||||
.tab-count-group {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.tab-count-btn {
|
||||
min-width: var(--touch-target-min);
|
||||
min-height: var(--touch-target-min);
|
||||
}
|
||||
|
||||
/* Case select responsive */
|
||||
.case-select-group {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.toolbar-select {
|
||||
font-size: 0.8rem;
|
||||
padding: 0.5rem 1.5rem 0.5rem 0.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
Virtual Keyboard Handling
|
||||
============================================================================ */
|
||||
.keyboard-visible .toolbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.keyboard-visible .monitor-panel,
|
||||
.keyboard-visible .subagents-panel {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Ensure terminal fills space when keyboard is visible */
|
||||
.keyboard-visible .main {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
iOS Safari Specific Fixes
|
||||
============================================================================ */
|
||||
.ios-device.safari-browser {
|
||||
/* Prevent pull-to-refresh */
|
||||
overscroll-behavior: none;
|
||||
}
|
||||
|
||||
.ios-device.safari-browser .terminal-container {
|
||||
/* Prevent rubber-banding in terminal */
|
||||
-webkit-overflow-scrolling: auto;
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
Hover State Fallbacks for Touch
|
||||
============================================================================ */
|
||||
@media (hover: none) and (pointer: coarse) {
|
||||
/* Remove hover-dependent UI patterns */
|
||||
.session-tab .tab-close,
|
||||
.session-tab .tab-gear {
|
||||
opacity: 1;
|
||||
width: auto;
|
||||
padding: 0.2rem 0.4rem;
|
||||
}
|
||||
|
||||
/* Simplify button hover states */
|
||||
.btn-toolbar:hover {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.btn-icon-header:hover {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
/* Show dropdown on tap instead of hover */
|
||||
.subagent-dropdown-trigger:active + .subagent-dropdown-menu,
|
||||
.subagent-dropdown-trigger:focus + .subagent-dropdown-menu {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user