This commit is contained in:
kim
2026-04-29 23:16:01 +09:00
parent d89d7213f6
commit c348c9cbed
105 changed files with 212 additions and 201 deletions
+195 -12
View File
@@ -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;