mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 10:24:02 +00:00
fix(ui): keep panel scroll position through rail layout passes (#731)
The right-rail layout pass lifts the Context, CCTV, Weather and Recent Imagery panel scrollers to measure their natural heights, which clamps their scroll offset to zero, but it only restored scrollers tagged data-rail-scroller. A layer that refreshes its Layers-panel row every second snapped the Context panel back to the top while scrolling. Tag every lifted scroller and pin the pairing with a test that reads the measuring CSS. Co-authored-by: Bilawal Sidhu <[email protected]>
This commit is contained in:
1 parent
005254fcd1
commit
143cffd7ca
4 files changed
+36
-5
No files matched your search
@@ -808,5 +808,6 @@
|
|||||||
"src/ui/imageryBoxTool.test.mjs",
|
"src/ui/imageryBoxTool.test.mjs",
|
||||||
"src/ui/recentImagery.test.mjs",
|
"src/ui/recentImagery.test.mjs",
|
||||||
"src/layers/recentImagery/testDoubles.mjs",
|
"src/layers/recentImagery/testDoubles.mjs",
|
||||||
"scripts/qa-recent-imagery.mjs"
|
"scripts/qa-recent-imagery.mjs",
|
||||||
|
"src/ui/railScrollers.test.mjs"
|
||||||
]
|
]
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import { readFileSync } from 'node:fs';
|
||||||
|
import test from 'node:test';
|
||||||
|
|
||||||
|
const read = (path) => readFileSync(new URL(path, import.meta.url), 'utf8');
|
||||||
|
|
||||||
|
// The rail's measuring pass lifts these panel scrollers to their natural
|
||||||
|
// height, which clamps their scroll offset to zero. Only scrollers tagged
|
||||||
|
// `data-rail-scroller` get their offset restored afterwards, so every lifted
|
||||||
|
// scroller must carry the tag or a layout pass snaps it back to the top.
|
||||||
|
test('every scroller the rail measuring pass lifts restores its scroll offset', () => {
|
||||||
|
const css = read('./styles/layers.css');
|
||||||
|
const templates = [
|
||||||
|
read('./templates/context.html'),
|
||||||
|
read('./templates/layer-panels.html'),
|
||||||
|
].join('\n');
|
||||||
|
const lifted = [
|
||||||
|
...css.matchAll(
|
||||||
|
/#right-context-rail\[data-rail-measuring\]\s*>\s*\[data-panel-id\]:not\(\.collapsed\)\s*>\s*\.([a-z-]+)/g,
|
||||||
|
),
|
||||||
|
].map((match) => match[1]);
|
||||||
|
assert.ok(lifted.length > 0, 'measuring CSS lists lifted scrollers');
|
||||||
|
for (const className of lifted) {
|
||||||
|
const tag = templates.match(
|
||||||
|
new RegExp(`<div class="${className}"[^>]*>`),
|
||||||
|
)?.[0];
|
||||||
|
if (!tag) continue;
|
||||||
|
assert.match(tag, /data-rail-scroller/, `${className} restores its scroll`);
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
<aside id="right-context-rail">
|
<aside id="right-context-rail">
|
||||||
<div id="weather-panel" class="panel-collapsible" data-panel-id="weather-panel" hidden>
|
<div id="weather-panel" class="panel-collapsible" data-panel-id="weather-panel" hidden>
|
||||||
<div class="panel-glow"></div>
|
<div class="panel-glow"></div>
|
||||||
<div class="weather-panel-inner">
|
<div class="weather-panel-inner" data-rail-scroller>
|
||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<span class="panel-title">WEATHER</span>
|
<span class="panel-title">WEATHER</span>
|
||||||
<span id="weather-panel-count" aria-label="Active weather products">0</span>
|
<span id="weather-panel-count" aria-label="Active weather products">0</span>
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id="recent-imagery-panel" class="panel-collapsible" data-panel-id="recent-imagery-panel" hidden>
|
<div id="recent-imagery-panel" class="panel-collapsible" data-panel-id="recent-imagery-panel" hidden>
|
||||||
<div class="panel-glow"></div>
|
<div class="panel-glow"></div>
|
||||||
<div class="recent-imagery-panel-inner">
|
<div class="recent-imagery-panel-inner" data-rail-scroller>
|
||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<span class="panel-title">RECENT IMAGERY</span>
|
<span class="panel-title">RECENT IMAGERY</span>
|
||||||
<span id="recent-imagery-panel-count" aria-label="Imagery days in the box"></span>
|
<span id="recent-imagery-panel-count" aria-label="Imagery days in the box"></span>
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id="global-context-panel" class="panel-collapsible collapsed" data-panel-id="global-context-panel">
|
<div id="global-context-panel" class="panel-collapsible collapsed" data-panel-id="global-context-panel">
|
||||||
<div class="panel-glow"></div>
|
<div class="panel-glow"></div>
|
||||||
<div class="global-context-panel-inner">
|
<div class="global-context-panel-inner" data-rail-scroller>
|
||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<span class="panel-title">CONTEXT</span>
|
<span class="panel-title">CONTEXT</span>
|
||||||
<span class="panel-divider"></span>
|
<span class="panel-divider"></span>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<!-- CCTV Coverage Panel -->
|
<!-- CCTV Coverage Panel -->
|
||||||
<div id="cctv-panel" class="panel-collapsible collapsed" data-panel-id="cctv-panel">
|
<div id="cctv-panel" class="panel-collapsible collapsed" data-panel-id="cctv-panel">
|
||||||
<div class="panel-glow"></div>
|
<div class="panel-glow"></div>
|
||||||
<div class="cctv-panel-inner">
|
<div class="cctv-panel-inner" data-rail-scroller>
|
||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<span class="panel-title">CCTV</span>
|
<span class="panel-title">CCTV</span>
|
||||||
<span class="panel-divider"></span>
|
<span class="panel-divider"></span>
|
||||||
|
|||||||
Reference in new issue
Block a user