fix: fit view — defer layout measurement to rAF, stretch pre to fill tile
Bug 1: applyFitLayout measured parentElement.clientHeight before the
browser reflowed the DOM — returned 0 on first render. Fix: wrap in
requestAnimationFrame so measurement happens after layout pass.
Applies to all three call sites: renderGrid(), applyDisplaySettings(),
and the window resize handler.
Bug 2: .tile-body pre had position:absolute bottom:0 but no top:0.
In fit mode (taller tiles), content sat at the bottom with a gap above.
Fix: .session-grid--fit .tile-body pre { top: 0; overflow-y: auto }
This commit is contained in:
@@ -652,7 +652,7 @@ function renderGrid(sessions) {
|
|||||||
var currentMode = currentDs.viewMode || 'auto';
|
var currentMode = currentDs.viewMode || 'auto';
|
||||||
if (currentMode === 'fit' && grid) {
|
if (currentMode === 'fit' && grid) {
|
||||||
grid.classList.add('session-grid--fit');
|
grid.classList.add('session-grid--fit');
|
||||||
applyFitLayout(grid);
|
requestAnimationFrame(function() { applyFitLayout(grid); });
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1191,7 +1191,7 @@ function applyDisplaySettings(ds) {
|
|||||||
|
|
||||||
} else if (mode === 'fit') {
|
} else if (mode === 'fit') {
|
||||||
grid.classList.add('session-grid--fit');
|
grid.classList.add('session-grid--fit');
|
||||||
applyFitLayout(grid);
|
requestAnimationFrame(function() { applyFitLayout(grid); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1858,7 +1858,7 @@ window.addEventListener('resize', function() {
|
|||||||
var ds = loadDisplaySettings();
|
var ds = loadDisplaySettings();
|
||||||
if ((ds.viewMode || 'auto') === 'fit') {
|
if ((ds.viewMode || 'auto') === 'fit') {
|
||||||
var grid = document.getElementById('session-grid');
|
var grid = document.getElementById('session-grid');
|
||||||
if (grid) applyFitLayout(grid);
|
if (grid) requestAnimationFrame(function() { applyFitLayout(grid); });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1380,6 +1380,12 @@ body {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* In fit mode, stretch pre to fill the full tile body height (not just bottom-anchor) */
|
||||||
|
.session-grid--fit .tile-body pre {
|
||||||
|
top: 0; /* stretch to fill full tile body height in fit mode */
|
||||||
|
overflow-y: auto; /* scroll if content exceeds the tile */
|
||||||
|
}
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
Responsive overlay sidebar at <960px
|
Responsive overlay sidebar at <960px
|
||||||
============================================================ */
|
============================================================ */
|
||||||
|
|||||||
@@ -2204,3 +2204,11 @@ test('bindStaticEventListeners wires view-mode-btn click to cycleViewMode', () =
|
|||||||
'bindStaticEventListeners must wire #view-mode-btn click handler'
|
'bindStaticEventListeners must wire #view-mode-btn click handler'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('applyFitLayout is called via requestAnimationFrame for correct timing', () => {
|
||||||
|
const source = fs.readFileSync(new URL('../app.js', import.meta.url), 'utf8');
|
||||||
|
assert.ok(
|
||||||
|
source.includes('requestAnimationFrame') && source.includes('applyFitLayout'),
|
||||||
|
'applyFitLayout must be deferred via requestAnimationFrame'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|||||||
@@ -1705,3 +1705,26 @@ def test_css_no_compact_tile_height() -> None:
|
|||||||
assert ".session-grid--compact .session-tile" not in css, (
|
assert ".session-grid--compact .session-tile" not in css, (
|
||||||
".session-grid--compact .session-tile must be removed — compact view mode was removed"
|
".session-grid--compact .session-tile must be removed — compact view mode was removed"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# Fit view bug fixes
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
|
||||||
|
def test_fit_view_pre_has_top_zero() -> None:
|
||||||
|
"""In fit mode, .tile-body pre must have top:0 to fill the full tile height.
|
||||||
|
|
||||||
|
Bug: .tile-body pre uses position:absolute with bottom:0 but no top:0.
|
||||||
|
In fit mode where tiles are taller than auto mode, the pre is anchored
|
||||||
|
to the bottom but only takes natural content height, leaving a black gap above.
|
||||||
|
Fix: .session-grid--fit .tile-body pre { top: 0 } stretches it to fill the tile.
|
||||||
|
"""
|
||||||
|
css = read_css()
|
||||||
|
assert ".session-grid--fit .tile-body pre" in css, (
|
||||||
|
"Missing .session-grid--fit .tile-body pre rule — needed to fix pre height in fit mode"
|
||||||
|
)
|
||||||
|
block = _extract_rule_block(css, ".session-grid--fit .tile-body pre {")
|
||||||
|
assert "top: 0" in block or "top:0" in block, (
|
||||||
|
".session-grid--fit .tile-body pre must have top: 0 to fill full tile body height"
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user