feat(dashboard): drag-resizable event/error log dock height (persisted)

Add a drag handle on the top edge of the bottom log dock so its height can be
adjusted freely (80px .. 82vh), persisted in localStorage. Dock max-height
raised to 90vh; syncDockPad keeps the page bottom padding in step so the last
turn never hides behind the dock. Handle is hidden while the dock is collapsed.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
EJClaw
2026-08-26 23:40:56 +09:00
parent 6d8ba3ad3a
commit d164630bb8

View File

@@ -936,7 +936,13 @@ PAGE = r"""<!DOCTYPE html>
main{padding-bottom:46px} main{padding-bottom:46px}
.logdock{position:fixed;left:0;right:0;bottom:0;z-index:15;background:#0a0e13; .logdock{position:fixed;left:0;right:0;bottom:0;z-index:15;background:#0a0e13;
border-top:1px solid var(--line);display:flex;flex-direction:column; border-top:1px solid var(--line);display:flex;flex-direction:column;
max-height:45vh;box-shadow:0 -8px 24px rgba(0,0,0,.35)} max-height:90vh;box-shadow:0 -8px 24px rgba(0,0,0,.35)}
.logresize{height:7px;cursor:ns-resize;background:#0d141c;border-bottom:1px solid var(--line);
flex:0 0 auto;touch-action:none}
.logresize:hover{background:#1d3d54}
.logresize::before{content:"";display:block;width:44px;height:3px;margin:2px auto 0;
border-radius:2px;background:#2a3a49}
.logdock.collapsed .logresize{display:none}
.logbar{display:flex;align-items:center;gap:8px;padding:6px 12px;border-bottom:1px solid var(--line); .logbar{display:flex;align-items:center;gap:8px;padding:6px 12px;border-bottom:1px solid var(--line);
background:#0d141c;flex-wrap:wrap} background:#0d141c;flex-wrap:wrap}
.logtoggle{background:none;border:none;color:var(--fg);font-size:12.5px;cursor:pointer;font-weight:600;padding:4px 6px} .logtoggle{background:none;border:none;color:var(--fg);font-size:12.5px;cursor:pointer;font-weight:600;padding:4px 6px}
@@ -1071,6 +1077,7 @@ PAGE = r"""<!DOCTYPE html>
<div id="empty" class="empty">아직 대화가 없습니다. 사용자가 말하면 여기에 단계별로 나타납니다.</div> <div id="empty" class="empty">아직 대화가 없습니다. 사용자가 말하면 여기에 단계별로 나타납니다.</div>
</main> </main>
<div id="logdock" class="logdock"> <div id="logdock" class="logdock">
<div id="logResize" class="logresize" title="드래그해서 로그 높이 조절"></div>
<div class="logbar"> <div class="logbar">
<button id="logToggle" class="logtoggle">▾ 이벤트 / 오류 로그</button> <button id="logToggle" class="logtoggle">▾ 이벤트 / 오류 로그</button>
<input id="logSearch" class="logsearch" placeholder="로그 검색 (텍스트)"> <input id="logSearch" class="logsearch" placeholder="로그 검색 (텍스트)">
@@ -1509,6 +1516,26 @@ $('logToggle').onclick = ()=>{
syncDockPad(); syncDockPad();
}; };
window.addEventListener('resize', syncDockPad); window.addEventListener('resize', syncDockPad);
// Drag the top edge of the log dock to resize its height (persisted).
(function(){
const dock=$('logdock'), body=$('logbody'), handle=$('logResize');
const KEY='wsai_logH';
const maxH = ()=> Math.round(window.innerHeight*0.82);
function setH(px){ const h=Math.max(80, Math.min(maxH(), Math.round(px)));
body.style.height=h+'px'; localStorage.setItem(KEY, h); syncDockPad(); }
setH(parseInt(localStorage.getItem(KEY)||'180', 10));
let startY=0, startH=0, dragging=false;
handle.addEventListener('pointerdown', (e)=>{
if(dock.classList.contains('collapsed')) return;
dragging=true; startY=e.clientY; startH=body.offsetHeight;
try{ handle.setPointerCapture(e.pointerId); }catch(_){}
e.preventDefault();
});
handle.addEventListener('pointermove', (e)=>{ if(dragging) setH(startH + (startY - e.clientY)); });
const end=(e)=>{ if(!dragging) return; dragging=false; try{ handle.releasePointerCapture(e.pointerId); }catch(_){} };
handle.addEventListener('pointerup', end);
handle.addEventListener('pointercancel', end);
})();
$('logSearch').oninput = renderLogs; $('logSearch').oninput = renderLogs;
$('logLevel').onchange = renderLogs; $('logLevel').onchange = renderLogs;
$('logClear').onclick = async ()=>{ $('logClear').onclick = async ()=>{