mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 02:14:01 +00:00
fix(ui): stop panel glows from adding scrollbars to the narrow-screen rails (#699)
At 720px and below both panel stacks scroll vertically, so each panel's absolutely positioned glow (negative inset) became scrollable overflow on both axes and drew a horizontal scrollbar band plus a spurious vertical scrollbar whenever CCTV, Context, Data Layers or Scenes was expanded. Pin the glow to its panel box in the narrow-screen block and add a stylesheet test that checks every 720px media block.
This commit is contained in:
1 parent
0dbde1e36c
commit
f01b6a5d84
4 files changed
+117
No files matched your search
@@ -1,5 +1,16 @@
|
||||
# Changelog
|
||||
|
||||
- Remove the spurious scrollbars that appeared on both panel stacks at narrow
|
||||
widths (720px and below) as soon as a panel was expanded. The stacks scroll
|
||||
vertically there, and each panel's decorative glow, absolutely positioned
|
||||
with a negative inset, became 18–20px of scrollable overflow on both axes: a
|
||||
horizontal scrollbar band under the expanded CCTV, Context, Data Layers or
|
||||
Scenes panel plus a vertical scrollbar that scrolled nothing but glow. The
|
||||
narrow-screen rules now pin the glow to its panel box; the stacks still
|
||||
scroll for genuinely tall content such as an expanded DISPLAY panel, and the
|
||||
Context radio popover is not clipped. `src/ui/panelRails.test.mjs` pins the
|
||||
rule against every 720px media block.
|
||||
|
||||
- Enable responsive trackpad pinch zoom on the globe. Browser pixel-mode
|
||||
`Ctrl+wheel` pinch gestures now reach Cesium with bounded amplification,
|
||||
while ordinary wheel, line-mode and touch-pinch inputs retain their existing
|
||||
|
||||
@@ -3599,6 +3599,7 @@ are omitted rather than framing the wrong part of the globe.
|
||||
- The desktop right rail (`#right-context-rail`) owns `DISPLAY`, `CCTV`, its active parameter controls, and `GLOBAL CONTEXT` as one fixed responsive stack in that order. Its compact buttons use the same 176 px width as the left accordion and one consistent 50 px height, share the left stack's 52 px edge inset and measured top baseline across HUD variants, then constrain themselves against visible HUD/chrome rectangles and the remaining vertical corridor. `DISPLAY` is no longer draggable and legacy saved coordinates are ignored.
|
||||
- The right rail is labeled **DISPLAY** (formerly "MOVE") and groups, in order, HUD, DETECT, Bloom, Sharpen, 3D, Clean-UI (HUD + DETECT promoted to the top). Its expanded controls retain the same compact 176 px width as the right-side tabs instead of growing to the wider Context detail-card width. It starts expanded on first run and respects the user's later `v6` collapse choice. Collapses/expands with directional chevrons (`◀` collapsed, `▶` expanded).
|
||||
- Display and Context use matching 330 px expanded widths and matching compact tab dimensions. The parameter panel is part of Display's expanded content. DISPLAY may remain open beside one contextual panel; CCTV and Context are mutually exclusive. In Tactical HUD, expanding CCTV or Context hides the other contextual launcher while DISPLAY remains independently available. The most recently opened right-rail panel owns the constrained lane even when it appears later in DOM order; passive restoration and automatic disclosure do not replace that explicit owner. Minimal and other HUD layouts retain the collapsed launchers; when their active panel exceeds the measured corridor, the rail reserves sibling heights and gaps and scrolls the active panel internally.
|
||||
- At 720px and below both panel stacks (`#left-panel-stack`, `#right-context-rail`) go edge-to-edge and scroll vertically. Every hosted panel's decorative `.panel-glow` is pinned to its panel box there (`inset: 0` in `src/ui/styles/responsive.css`): on desktop the glow overhangs the panel by 18–20 px as harmless paint, but inside a scroll container that overhang is scrollable overflow on both axes and drew a horizontal scrollbar band plus a vertical scrollbar that scrolled nothing but glow whenever CCTV, Context, Data Layers or Scenes was expanded. The glow's blur is ink overflow and never scrolls, so the look is unchanged. Do not fix this by clipping the stacks: `overflow-x: clip` would also clip the Context radio popover and would not remove the vertical scrollbar. Pinned by `src/ui/panelRails.test.mjs` against every `(max-width: 720px)` block in the flattened stylesheet.
|
||||
- `STYLE PRESETS` and `LOCATIONS` start collapsed, expand on intentional hover/click, and auto-collapse after hover leave delay.
|
||||
- Collapsed mini-status indicators show active style and active location/landmark.
|
||||
- Detection mode is user-controlled and should persist when switching styles. Since 2026-08-22 it also STARTS on — Dense @ 75% for every style on a first run, Normal included — as a `GLOBAL_POST_DEFAULTS` baseline that does NOT set `_detectionUserOverridden`. Exception (unchanged): selecting a military style (CRT/NVG/FLIR) auto-enables the same Dense preset, but only until the user manually changes detection this session (`_detectionUserOverridden` gate), after which style switches never touch it.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { readStylesheet } from '../testSupport/readStylesheet.mjs';
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import {
|
||||
@@ -269,3 +270,93 @@ test('natural height includes visible content, margins and wrapper chrome, exclu
|
||||
100,
|
||||
);
|
||||
});
|
||||
|
||||
// ── Narrow-screen rail overflow pin ──────────────────────────────────────────
|
||||
// At ≤720px both panel stacks become scroll containers (overflow-y: auto),
|
||||
// which also makes their overflow-x compute to auto. Each panel's decorative
|
||||
// .panel-glow is absolutely positioned with a negative inset, so inside a
|
||||
// scroll container that overhang is no longer harmless paint: it becomes
|
||||
// 18–20px of scrollable overflow on both axes, drawing a horizontal scrollbar
|
||||
// band under the expanded CCTV/Context/Data panel plus a vertical scrollbar
|
||||
// that scrolls nothing but glow. The narrow block therefore pins every hosted
|
||||
// glow to its panel box.
|
||||
|
||||
/** Strip comments and return the bodies of every ≤720px media block. */
|
||||
function narrowScreenBlocks(css) {
|
||||
const source = css.replace(/\/\*[\s\S]*?\*\//g, '');
|
||||
const blocks = [];
|
||||
let from = 0;
|
||||
for (;;) {
|
||||
const start = source.indexOf('@media (max-width: 720px) {', from);
|
||||
if (start === -1) break;
|
||||
const open = source.indexOf('{', start);
|
||||
let depth = 0;
|
||||
let close = -1;
|
||||
for (let index = open; index < source.length; index += 1) {
|
||||
if (source[index] === '{') depth += 1;
|
||||
if (source[index] === '}' && (depth -= 1) === 0) {
|
||||
close = index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert.notEqual(close, -1, 'unterminated narrow-screen media block');
|
||||
blocks.push(source.slice(open + 1, close));
|
||||
from = close + 1;
|
||||
}
|
||||
assert.ok(blocks.length, 'narrow-screen media block is missing');
|
||||
return blocks;
|
||||
}
|
||||
|
||||
/** Split a flat (non-nested) rule list into [selectors, declarations] pairs. */
|
||||
function flatRules(block) {
|
||||
assert.doesNotMatch(block, /@media/, 'nested media queries are not modelled');
|
||||
return [...block.matchAll(/([^{}]+)\{([^{}]*)\}/g)].map(
|
||||
([, selectors, declarations]) => [
|
||||
selectors.split(',').map((part) => part.trim().replace(/\s+/g, ' ')),
|
||||
declarations,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
test('narrow-screen rails pin every hosted panel glow inside its panel box', () => {
|
||||
const css = readStylesheet(new URL('../../style.css', import.meta.url));
|
||||
for (const panel of [
|
||||
'data-panel',
|
||||
'scene-panel',
|
||||
'cctv-panel',
|
||||
'global-context-panel',
|
||||
]) {
|
||||
assert.match(
|
||||
css,
|
||||
new RegExp(`#${panel} \\.panel-glow \\{[^}]*\\binset: -\\d+px;`),
|
||||
`${panel} glow no longer overhangs its panel; revisit this pin`,
|
||||
);
|
||||
}
|
||||
const narrow = narrowScreenBlocks(css).flatMap(flatRules);
|
||||
const scrollingRails = [
|
||||
...new Set(
|
||||
narrow
|
||||
.filter(([, declarations]) =>
|
||||
/\boverflow(?:-y)?:\s*(?:auto|scroll)\b/.test(declarations),
|
||||
)
|
||||
.flatMap(([selectors]) => selectors)
|
||||
.filter((selector) =>
|
||||
/^#(?:left-panel-stack|right-context-rail)$/.test(selector),
|
||||
),
|
||||
),
|
||||
].sort();
|
||||
assert.deepEqual(scrollingRails, [
|
||||
'#left-panel-stack',
|
||||
'#right-context-rail',
|
||||
]);
|
||||
for (const rail of scrollingRails) {
|
||||
assert.ok(
|
||||
narrow.some(
|
||||
([selectors, declarations]) =>
|
||||
selectors.includes(`${rail} .panel-glow`) &&
|
||||
/(?:^|;)\s*inset:\s*0\s*;/.test(declarations),
|
||||
),
|
||||
`${rail} scrolls at ≤720px but does not pin its panel glows (inset: 0)`,
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -197,6 +197,20 @@
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* Both stacks are scroll containers at this width (overflow-y above), which
|
||||
also makes their overflow-x compute to auto. Each panel's decorative
|
||||
.panel-glow is absolutely positioned with a negative inset (-18px/-20px),
|
||||
so inside a scroll container it stops being harmless paint and becomes
|
||||
18–20px of scrollable overflow on BOTH axes: a horizontal scrollbar band
|
||||
under the expanded panel plus a vertical scrollbar that scrolls nothing
|
||||
but glow. Pin the glow to the panel box here — its blur is ink overflow,
|
||||
which never scrolls — instead of clipping the rail, which would also clip
|
||||
legitimate content such as the Context radio popover. */
|
||||
#left-panel-stack .panel-glow,
|
||||
#right-context-rail .panel-glow {
|
||||
inset: 0;
|
||||
}
|
||||
|
||||
#right-context-rail > #pp-toggles {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user