v2.1
This commit is contained in:
+195
-12
@@ -59,8 +59,8 @@
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
min-height: 100vh;
|
||||
height: 100vh;
|
||||
min-height: 100dvh;
|
||||
height: 100dvh;
|
||||
font-family: 'Manrope', sans-serif;
|
||||
color: var(--text);
|
||||
background:
|
||||
@@ -1756,22 +1756,87 @@
|
||||
|
||||
@media (max-width: 900px) {
|
||||
body {
|
||||
padding: 8px;
|
||||
gap: 8px;
|
||||
grid-template-rows: 58px 1fr 280px;
|
||||
padding: 0;
|
||||
gap: 0;
|
||||
grid-template-rows: 52px 1fr 56px;
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-areas:
|
||||
"header"
|
||||
"main"
|
||||
"right";
|
||||
"content"
|
||||
"mobile-nav";
|
||||
}
|
||||
header { border-radius: 14px; }
|
||||
header {
|
||||
border-radius: 0;
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
border-top: none;
|
||||
}
|
||||
aside { display: none; }
|
||||
.status-bar { display: none; }
|
||||
#chat-messages,
|
||||
#main-content { padding: 14px; }
|
||||
.chat-input-area,
|
||||
.mission-bar { padding: 10px; }
|
||||
|
||||
/* Both panels share the content cell; JS toggles which is visible */
|
||||
main { grid-area: content; border-radius: 0; }
|
||||
.right-panel { grid-area: content; display: none; border-radius: 0; }
|
||||
body.mob-ctx main { display: none; }
|
||||
body.mob-ctx .right-panel { display: flex; }
|
||||
|
||||
/* Sidebar drawer — slides in from left over content */
|
||||
body.mob-menu aside {
|
||||
display: flex;
|
||||
position: fixed;
|
||||
top: 52px; left: 0; bottom: 56px;
|
||||
width: min(300px, 85vw);
|
||||
z-index: 500;
|
||||
box-shadow: 4px 0 24px rgba(0,0,0,0.18);
|
||||
overflow-y: auto;
|
||||
border-right: 1px solid var(--line);
|
||||
}
|
||||
|
||||
/* Hide desktop resize handle on mobile */
|
||||
#right-panel-resize-handle { display: none !important; }
|
||||
|
||||
/* Prevent iOS auto-zoom on input focus (requires ≥16px) */
|
||||
#chat-input, input[type="text"], input[type="password"],
|
||||
input[type="email"], input[type="number"], textarea {
|
||||
font-size: 16px !important;
|
||||
}
|
||||
|
||||
#chat-messages, #main-content { padding: 12px; }
|
||||
.chat-input-area, .mission-bar { padding: 8px 10px; }
|
||||
|
||||
/* Show mobile bottom nav */
|
||||
#mobile-nav { display: flex !important; }
|
||||
}
|
||||
/* --- Mobile Bottom Nav ---------------------------- */
|
||||
#mobile-nav {
|
||||
display: none;
|
||||
grid-area: mobile-nav;
|
||||
align-items: stretch;
|
||||
background: var(--panel);
|
||||
border-top: 1px solid var(--line);
|
||||
}
|
||||
.mob-tab {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 3px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--muted);
|
||||
font-family: 'Manrope', sans-serif;
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.04em;
|
||||
cursor: pointer;
|
||||
padding: 6px 4px;
|
||||
border-top: 2px solid transparent;
|
||||
transition: color 0.15s, border-color 0.15s;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
.mob-tab.active { color: var(--brand); border-top-color: var(--brand); }
|
||||
.mob-tab svg { width: 20px; height: 20px; stroke-width: 2; }
|
||||
/* --- Heartbeat Page ------------------------------- */
|
||||
#heartbeat-view {
|
||||
display: none;
|
||||
@@ -2399,6 +2464,8 @@
|
||||
|
||||
<!-- RIGHT PANEL -->
|
||||
<div class="right-panel" id="right-panel" style="position:relative">
|
||||
<!-- Resize handle on left edge -->
|
||||
<div id="right-panel-resize-handle" style="position:absolute;left:0;top:0;bottom:0;width:5px;cursor:col-resize;z-index:200;background:transparent;transition:background 0.15s ease" title="Drag to resize"></div>
|
||||
<!-- Right panel topbar with canvas toggle -->
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;padding:6px 12px;border-bottom:1px solid var(--line);flex-shrink:0;background:var(--panel);min-height:38px">
|
||||
<span style="font-size:10px;font-weight:800;color:var(--muted);text-transform:uppercase;letter-spacing:0.06em">Context</span>
|
||||
@@ -2574,6 +2641,25 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MOBILE BOTTOM NAV -->
|
||||
<nav id="mobile-nav">
|
||||
<button id="mob-tab-chat" class="mob-tab active" onclick="mobTab('chat')">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
|
||||
Chat
|
||||
</button>
|
||||
<button id="mob-tab-ctx" class="mob-tab" onclick="mobTab('ctx')">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M9 21V9"/></svg>
|
||||
Context
|
||||
</button>
|
||||
<button id="mob-tab-menu" class="mob-tab" onclick="mobTab('menu')">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>
|
||||
Menu
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
<!-- Mobile backdrop (closes sidebar drawer) -->
|
||||
<div id="mob-backdrop" onclick="mobCloseMenu()" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,0.38);z-index:499;-webkit-tap-highlight-color:transparent"></div>
|
||||
|
||||
<!-- ERROR RESPONSE MODAL -->
|
||||
<div id="error-response-panel">
|
||||
<div class="error-response-header">
|
||||
@@ -9590,6 +9676,103 @@ async function submitErrorResponse() {
|
||||
}
|
||||
})();
|
||||
|
||||
// ── Mobile tab navigation ───────────────────────────────────────────────────
|
||||
function mobTab(tab) {
|
||||
const body = document.body;
|
||||
|
||||
if (tab === 'menu') {
|
||||
const isOpen = body.classList.contains('mob-menu');
|
||||
if (isOpen) {
|
||||
mobCloseMenu();
|
||||
} else {
|
||||
body.classList.add('mob-menu');
|
||||
document.getElementById('mob-backdrop').style.display = 'block';
|
||||
}
|
||||
// Keep chat/ctx tab highlight unchanged; toggle menu highlight
|
||||
document.getElementById('mob-tab-menu').classList.toggle('active', !isOpen);
|
||||
return;
|
||||
}
|
||||
|
||||
mobCloseMenu();
|
||||
['chat', 'ctx', 'menu'].forEach(t =>
|
||||
document.getElementById('mob-tab-' + t)?.classList.toggle('active', t === tab)
|
||||
);
|
||||
|
||||
if (tab === 'ctx') {
|
||||
body.classList.add('mob-ctx');
|
||||
} else {
|
||||
body.classList.remove('mob-ctx');
|
||||
}
|
||||
}
|
||||
|
||||
function mobCloseMenu() {
|
||||
document.body.classList.remove('mob-menu');
|
||||
document.getElementById('mob-backdrop').style.display = 'none';
|
||||
document.getElementById('mob-tab-menu')?.classList.remove('active');
|
||||
}
|
||||
|
||||
// ── Right-panel resize ──────────────────────────────────────────────────────
|
||||
(function initRightPanelResize() {
|
||||
const MIN_W = 280;
|
||||
const MAX_W_RATIO = 0.65;
|
||||
const STORE_KEY = 'rightPanelWidth';
|
||||
|
||||
function applyWidth(px) {
|
||||
document.body.style.gridTemplateColumns = `280px 1fr ${px}px`;
|
||||
}
|
||||
|
||||
function clamp(px) {
|
||||
return Math.max(MIN_W, Math.min(Math.floor(window.innerWidth * MAX_W_RATIO), px));
|
||||
}
|
||||
|
||||
// Restore saved width
|
||||
const saved = parseInt(localStorage.getItem(STORE_KEY), 10);
|
||||
if (saved && saved >= MIN_W) applyWidth(clamp(saved));
|
||||
|
||||
function setup() {
|
||||
const handle = document.getElementById('right-panel-resize-handle');
|
||||
const panel = document.getElementById('right-panel');
|
||||
if (!handle || !panel) return;
|
||||
|
||||
handle.addEventListener('mouseenter', () => { handle.style.background = 'var(--brand, #1668e3)'; handle.style.opacity = '0.35'; });
|
||||
handle.addEventListener('mouseleave', () => { handle.style.background = 'transparent'; handle.style.opacity = '1'; });
|
||||
|
||||
handle.addEventListener('mousedown', (e) => {
|
||||
e.preventDefault();
|
||||
const startX = e.clientX;
|
||||
const startW = panel.getBoundingClientRect().width;
|
||||
|
||||
// Prevent iframes from swallowing events during drag
|
||||
document.querySelectorAll('iframe').forEach(f => f.style.pointerEvents = 'none');
|
||||
document.body.style.userSelect = 'none';
|
||||
handle.style.background = 'var(--brand, #1668e3)';
|
||||
handle.style.opacity = '0.6';
|
||||
|
||||
function onMove(ev) {
|
||||
const newW = clamp(startW + (startX - ev.clientX));
|
||||
applyWidth(newW);
|
||||
}
|
||||
|
||||
function onUp() {
|
||||
document.removeEventListener('mousemove', onMove);
|
||||
document.removeEventListener('mouseup', onUp);
|
||||
document.querySelectorAll('iframe').forEach(f => f.style.pointerEvents = '');
|
||||
document.body.style.userSelect = '';
|
||||
handle.style.background = 'transparent';
|
||||
handle.style.opacity = '1';
|
||||
const finalW = panel.getBoundingClientRect().width;
|
||||
localStorage.setItem(STORE_KEY, Math.round(finalW));
|
||||
}
|
||||
|
||||
document.addEventListener('mousemove', onMove);
|
||||
document.addEventListener('mouseup', onUp);
|
||||
});
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', setup);
|
||||
else setup();
|
||||
})();
|
||||
|
||||
function handleErrorResponseWsEvent(e) {
|
||||
const msg = e.detail || e;
|
||||
if (!msg || msg.type !== 'task_error_requires_response') return;
|
||||
|
||||
Reference in New Issue
Block a user