refactor: remove dimmer overlay, add cyan border to preview popover
ANSI colors make the overlay content readable without dimming. Removed preview-dimmer, liftHoveredTile(), tile--previewing/item--previewing — all dead code now. Added var(--accent) 2px border to .preview-popover for visual separation.
This commit is contained in:
+1
-37
@@ -127,7 +127,7 @@ let _notificationPermission = 'default';
|
|||||||
let _pollFailCount = 0;
|
let _pollFailCount = 0;
|
||||||
let _previewPopover = null;
|
let _previewPopover = null;
|
||||||
let _previewTimer = null;
|
let _previewTimer = null;
|
||||||
var _previewDimmer = null;
|
|
||||||
var _previewSessionName = null; // track by NAME, not DOM element
|
var _previewSessionName = null; // track by NAME, not DOM element
|
||||||
|
|
||||||
// ─── DOM helpers ──────────────────────────────────────────────────────────────
|
// ─── DOM helpers ──────────────────────────────────────────────────────────────
|
||||||
@@ -465,8 +465,6 @@ function renderSidebar(sessions, currentSession) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Re-apply z-index lift after innerHTML rebuild (preview survives re-renders)
|
|
||||||
if (_previewSessionName) liftHoveredTile();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const SIDEBAR_KEY = 'muxplex.sidebarOpen';
|
const SIDEBAR_KEY = 'muxplex.sidebarOpen';
|
||||||
@@ -606,8 +604,6 @@ function renderGrid(sessions) {
|
|||||||
updatePillBell();
|
updatePillBell();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Re-apply z-index lift after innerHTML rebuild (preview survives re-renders)
|
|
||||||
if (_previewSessionName) liftHoveredTile();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -638,12 +634,6 @@ function showPreview(name) {
|
|||||||
hidePreviewDOM();
|
hidePreviewDOM();
|
||||||
_previewSessionName = name;
|
_previewSessionName = name;
|
||||||
|
|
||||||
// Dimmer
|
|
||||||
var dimmer = document.createElement('div');
|
|
||||||
dimmer.className = 'preview-dimmer';
|
|
||||||
document.body.appendChild(dimmer);
|
|
||||||
_previewDimmer = dimmer;
|
|
||||||
|
|
||||||
// Full-window overlay
|
// Full-window overlay
|
||||||
var popover = document.createElement('div');
|
var popover = document.createElement('div');
|
||||||
popover.className = 'preview-popover';
|
popover.className = 'preview-popover';
|
||||||
@@ -653,9 +643,6 @@ function showPreview(name) {
|
|||||||
document.body.appendChild(popover);
|
document.body.appendChild(popover);
|
||||||
_previewPopover = popover;
|
_previewPopover = popover;
|
||||||
|
|
||||||
// Lift the original tile above dimmer
|
|
||||||
liftHoveredTile();
|
|
||||||
|
|
||||||
// Auto-scroll to bottom (prompt area)
|
// Auto-scroll to bottom (prompt area)
|
||||||
popover.scrollTop = popover.scrollHeight;
|
popover.scrollTop = popover.scrollHeight;
|
||||||
|
|
||||||
@@ -663,22 +650,6 @@ function showPreview(name) {
|
|||||||
document.addEventListener('click', _previewClickHandler, true);
|
document.addEventListener('click', _previewClickHandler, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function liftHoveredTile() {
|
|
||||||
// Remove any existing lift class from all tiles/items
|
|
||||||
document.querySelectorAll('.tile--previewing, .item--previewing').forEach(function (el) {
|
|
||||||
el.classList.remove('tile--previewing', 'item--previewing');
|
|
||||||
});
|
|
||||||
if (!_previewSessionName) return;
|
|
||||||
var el = document.querySelector(
|
|
||||||
'.session-tile[data-session="' + _previewSessionName + '"]'
|
|
||||||
);
|
|
||||||
if (el) el.classList.add('tile--previewing');
|
|
||||||
var item = document.querySelector(
|
|
||||||
'.sidebar-item[data-session="' + _previewSessionName + '"]'
|
|
||||||
);
|
|
||||||
if (item) item.classList.add('item--previewing');
|
|
||||||
}
|
|
||||||
|
|
||||||
// hidePreviewDOM: removes the visual elements only (no render trigger)
|
// hidePreviewDOM: removes the visual elements only (no render trigger)
|
||||||
function hidePreviewDOM() {
|
function hidePreviewDOM() {
|
||||||
document.removeEventListener('click', _previewClickHandler, true);
|
document.removeEventListener('click', _previewClickHandler, true);
|
||||||
@@ -686,13 +657,6 @@ function hidePreviewDOM() {
|
|||||||
_previewPopover.remove();
|
_previewPopover.remove();
|
||||||
_previewPopover = null;
|
_previewPopover = null;
|
||||||
}
|
}
|
||||||
if (_previewDimmer) {
|
|
||||||
_previewDimmer.remove();
|
|
||||||
_previewDimmer = null;
|
|
||||||
}
|
|
||||||
document.querySelectorAll('.tile--previewing, .item--previewing').forEach(function (el) {
|
|
||||||
el.classList.remove('tile--previewing', 'item--previewing');
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// hidePreview: full cleanup including timer and session name
|
// hidePreview: full cleanup including timer and session name
|
||||||
|
|||||||
@@ -967,7 +967,7 @@ body {
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 500;
|
z-index: 500;
|
||||||
background: var(--bg-secondary);
|
background: var(--bg-secondary);
|
||||||
border: 1px solid var(--border);
|
border: 2px solid var(--accent);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 16px 20px;
|
padding: 16px 20px;
|
||||||
/* Cover most of the viewport — centered with margin */
|
/* Cover most of the viewport — centered with margin */
|
||||||
@@ -991,19 +991,7 @@ body {
|
|||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.preview-dimmer {
|
|
||||||
position: fixed;
|
|
||||||
inset: 0;
|
|
||||||
z-index: 499; /* behind popover (500), above everything else */
|
|
||||||
background: rgba(0, 0, 0, 0.55);
|
|
||||||
pointer-events: none; /* clicks pass through — don't block mouseleave */
|
|
||||||
}
|
|
||||||
|
|
||||||
.session-tile.tile--previewing,
|
|
||||||
.sidebar-item.item--previewing {
|
|
||||||
position: relative;
|
|
||||||
z-index: 500; /* same as popover — above dimmer */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
Responsive overlay sidebar at <960px
|
Responsive overlay sidebar at <960px
|
||||||
|
|||||||
@@ -2075,13 +2075,12 @@ test('hover preview popover works for both grid tiles and sidebar items', () =>
|
|||||||
'must handle sidebar items too');
|
'must handle sidebar items too');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('hover preview popover has dim overlay and highlights hovered element', () => {
|
test('hover preview popover uses cyan border and no dimmer', () => {
|
||||||
const source = fs.readFileSync(
|
const source = fs.readFileSync(
|
||||||
new URL('../app.js', import.meta.url), 'utf8'
|
new URL('../app.js', import.meta.url), 'utf8'
|
||||||
);
|
);
|
||||||
assert.ok(source.includes('preview-dimmer'), 'must create dimmer overlay');
|
assert.ok(source.includes('preview-popover'), 'must create popover');
|
||||||
assert.ok(source.includes('tile--previewing'), 'must lift grid tile above dimmer');
|
assert.ok(!source.includes('preview-dimmer'), 'must NOT use dimmer overlay (removed)');
|
||||||
assert.ok(source.includes('item--previewing'), 'must lift sidebar item above dimmer');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('hover preview delay is 1500ms (not 350ms)', () => {
|
test('hover preview delay is 1500ms (not 350ms)', () => {
|
||||||
@@ -2092,31 +2091,16 @@ test('hover preview delay is 1500ms (not 350ms)', () => {
|
|||||||
assert.ok(!source.includes(', 350)'), 'old 350ms delay must be removed');
|
assert.ok(!source.includes(', 350)'), 'old 350ms delay must be removed');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('hover preview uses full-window overlay with text wrapping', () => {
|
test('hover preview uses full-window overlay with click-to-navigate', () => {
|
||||||
const source = fs.readFileSync(
|
const source = fs.readFileSync(
|
||||||
new URL('../app.js', import.meta.url), 'utf8'
|
new URL('../app.js', import.meta.url), 'utf8'
|
||||||
);
|
);
|
||||||
assert.ok(source.includes('_previewSessionName'), 'must track by session name');
|
assert.ok(source.includes('_previewSessionName'), 'must track by session name');
|
||||||
assert.ok(source.includes('liftHoveredTile'), 'must re-lift tile after renders');
|
|
||||||
assert.ok(source.includes('scrollHeight'), 'must auto-scroll to bottom');
|
assert.ok(source.includes('scrollHeight'), 'must auto-scroll to bottom');
|
||||||
assert.ok(source.includes('preview-dimmer'), 'must have dim overlay');
|
|
||||||
assert.ok(source.includes('ontouchstart'), 'must be desktop-only');
|
assert.ok(source.includes('ontouchstart'), 'must be desktop-only');
|
||||||
assert.ok(source.includes('_previewClickHandler'), 'must have click-to-navigate handler');
|
assert.ok(source.includes('_previewClickHandler'), 'must have click-to-navigate handler');
|
||||||
// Must NOT have repositionPreview (old side-positioned approach)
|
|
||||||
assert.ok(!source.includes('repositionPreview'), 'must NOT have repositionPreview (old approach)');
|
assert.ok(!source.includes('repositionPreview'), 'must NOT have repositionPreview (old approach)');
|
||||||
});
|
assert.ok(!source.includes('preview-dimmer'), 'must NOT have dimmer (removed — ANSI colors are readable without it)');
|
||||||
|
|
||||||
test('renderGrid and renderSidebar re-lift hovered tile after innerHTML rebuild', () => {
|
|
||||||
const source = fs.readFileSync(
|
|
||||||
new URL('../app.js', import.meta.url), 'utf8'
|
|
||||||
);
|
|
||||||
// renderGrid should call liftHoveredTile after innerHTML
|
|
||||||
const gridFn = source.substring(source.indexOf('function renderGrid'), source.indexOf('function renderGrid') + 1500);
|
|
||||||
assert.ok(gridFn.includes('liftHoveredTile'), 'renderGrid must re-lift tile after render');
|
|
||||||
|
|
||||||
// renderGrid should NOT have the old _previewPopover guard
|
|
||||||
assert.ok(!gridFn.includes('if (_previewPopover) return'),
|
|
||||||
'renderGrid must NOT skip renders while preview active (old approach caused bugs)');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('ansiToHtml converts SGR codes to styled spans', () => {
|
test('ansiToHtml converts SGR codes to styled spans', () => {
|
||||||
|
|||||||
@@ -633,7 +633,10 @@ def test_preview_popover_css_exists():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_preview_dimmer_css_exists():
|
def test_preview_popover_has_accent_border():
|
||||||
"""Dim overlay behind popover must have CSS rules."""
|
"""Preview popover must use brand cyan border."""
|
||||||
css = read_css()
|
css = read_css()
|
||||||
assert ".preview-dimmer" in css
|
start = css.index(".preview-popover {")
|
||||||
|
end = css.index("}", start)
|
||||||
|
block = css[start:end]
|
||||||
|
assert "var(--accent)" in block, ".preview-popover must use var(--accent) border"
|
||||||
|
|||||||
Reference in New Issue
Block a user