Fix log panel overlap and hover-peek dismissal

The empty Changes state (flex:1 with no min-height:0) overflowed .main and
drew over the log panel; add min-height:0/overflow clipping to .empty, .left
and .main so the panel gets its own space. Make the status-bar log-peek use
hover-intent (220ms delay + keep-open while hovering the popover) and sit
flush above the bar so it can be moused into and scrolled.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Bonchellon
2026-07-07 14:34:23 +03:00
parent 80f2acf40d
commit a67c171315
2 changed files with 20 additions and 11 deletions

View File

@ -226,6 +226,9 @@ function Workbench({ info, session, light, toggleTheme, lang, setLang, zoom, set
const [logOpen, setLogOpen] = useState(false);
const [peek, setPeek] = useState(false); // hover-over-loader log preview
const logId = useRef(0);
const peekTimer = useRef<number | null>(null);
function showPeek() { if (peekTimer.current) { clearTimeout(peekTimer.current); peekTimer.current = null; } setPeek(true); }
function hidePeek() { if (peekTimer.current) clearTimeout(peekTimer.current); peekTimer.current = window.setTimeout(() => setPeek(false), 220); }
// resizable panels (persisted): left panel width + Get-Latest zone width
const [leftW, setLeftW] = useState<number>(() => { const v = Number(localStorage.getItem("exd-left-w")); return v >= 280 ? v : 380; });
const [syncW, setSyncW] = useState<number>(() => { const v = Number(localStorage.getItem("exd-sync-w")); return v >= 150 ? v : 220; });
@ -634,13 +637,16 @@ function Workbench({ info, session, light, toggleTheme, lang, setLang, zoom, set
{logOpen && <LogPanel logs={logs} onClose={() => setLogOpen(false)} onClear={() => setLogs([])} />}
<div className="statusbar" onMouseEnter={() => setPeek(true)} onMouseLeave={() => setPeek(false)}>
<span className={"stdot" + ((busy || scanning || !!pushing) ? " busy" : "")}>{(busy || scanning || !!pushing) ? <span className="ldr sm" /> : I.check}</span>
<span className="stlast">{logs.length ? `${logs[logs.length - 1].cmd} ${logCount(logs[logs.length - 1])}` : "p4 — ready"}</span>
<div className="statusbar">
<span className="stfront" onMouseEnter={showPeek} onMouseLeave={hidePeek}>
<span className={"stdot" + ((busy || scanning || !!pushing) ? " busy" : "")}>{(busy || scanning || !!pushing) ? <span className="ldr sm" /> : I.check}</span>
<span className="stlast">{logs.length ? `${logs[logs.length - 1].cmd} ${logCount(logs[logs.length - 1])}` : "p4 — ready"}</span>
</span>
<button className="stlog" onClick={() => setLogOpen((o) => !o)} title="Ctrl+L">{I.log}<span>Log</span></button>
{peek && logs.length > 0 && (
<div className="logpeek">
{logs.slice(-14).map((l) => <LogRow key={l.id} l={l} />)}
<div className="logpeek" onMouseEnter={showPeek} onMouseLeave={hidePeek}>
<div className="logpeek-h">{t("Log")} · {logs.length}</div>
{logs.slice(-40).map((l) => <LogRow key={l.id} l={l} />)}
</div>
)}
</div>