Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/app/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -972,7 +972,7 @@ window.S = Object.assign({
tbSecView: '👁 View/Set',
tbSecCharts: '📋 Charts',
tbSecExport: '📤 Export/import',
tbSecWeather: 'ℹ️ Information',
tbSecWeather: '🗂 Extra layers',
tbSecSim: '✈ Simulator',
tbSimConnect: 'Connect to simulator',
tbSimDisconnect: 'Disconnect from simulator',
Expand Down
26 changes: 23 additions & 3 deletions docs/app/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,26 @@ body.theme-light .leaflet-image-layer.ims-pwx-layer {
border-radius: 6px;
padding: 4px 6px;
margin-top: 4px;
display: flex;
flex-direction: column;
gap: 3px;
}
/* Uniform layout for every layer card: stacked controls with even spacing,
small sub-control labels, and full-width selects. */
.tb-group-box [id$="-controls"] {
display: flex;
flex-direction: column;
gap: 3px;
}
/* The display:flex above must not defeat the `hidden` attribute (equal
specificity, later rule) — keep hidden boxes/controls hidden. */
.tb-group-box[hidden],
.tb-group-box [id$="-controls"][hidden] { display: none; }
.tb-group-box .navtoggle > span:first-child { font-size: 11px; } /* sub-control row labels */
.tb-group-box select {
width: 100%;
font: inherit;
font-size: 11px;
}
.tb-group {
display: flex;
Expand Down Expand Up @@ -555,7 +575,7 @@ body.theme-light .leaflet-image-layer.ims-pwx-layer {
}

.tb-section[data-sec="export"] .tb-section-body,
.tb-section[data-sec="sim"] .tb-section-body,
.tb-section[data-sec="weather"] .tb-section-body,
.tb-section[data-sec="print"] .tb-section-body {
right: 0;
left: auto;
Expand All @@ -567,7 +587,7 @@ body.theme-light .leaflet-image-layer.ims-pwx-layer {
}

html[dir="rtl"] .tb-section[data-sec="export"] .tb-section-body,
html[dir="rtl"] .tb-section[data-sec="sim"] .tb-section-body,
html[dir="rtl"] .tb-section[data-sec="weather"] .tb-section-body,
html[dir="rtl"] .tb-section[data-sec="print"] .tb-section-body {
right: auto;
left: 0;
Expand Down Expand Up @@ -645,7 +665,7 @@ body.theme-light .leaflet-image-layer.ims-pwx-layer {
#toolbar.multi-open .tb-section[data-sec="display"] .tb-section-body { left: calc(28.57vw + 4px); }
#toolbar.multi-open .tb-section[data-sec="charts"] .tb-section-body { left: calc(42.855vw + 2px); }
#toolbar.multi-open .tb-section[data-sec="export"] .tb-section-body { left: 57.14vw; }
#toolbar.multi-open .tb-section[data-sec="sim"] .tb-section-body { left: calc(71.425vw - 2px); }
#toolbar.multi-open .tb-section[data-sec="weather"] .tb-section-body { left: calc(71.425vw - 2px); }
#toolbar.multi-open .tb-section[data-sec="print"] .tb-section-body { left: calc(85.71vw - 4px); }

#toolbar .tb-section-body button,
Expand Down
2 changes: 1 addition & 1 deletion docs/i18n/he/strings.js
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ window.S = {
tbSecView: '👁 תצוגה/הגדרה',
tbSecCharts: '📋 דפיות',
tbSecExport: '📤 ייצוא/ייבוא',
tbSecWeather: 'ℹ️ מידע',
tbSecWeather: '🗂 שכבות נוספות',
tbSecSim: '✈ סימולטור',
tbSimConnect: 'התחבר לסימולטור',
tbSimDisconnect: 'התנתק מהסימולטור',
Expand Down
112 changes: 61 additions & 51 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@
</script>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet-velocity@1.7.0/dist/leaflet-velocity.min.css">
<link rel="stylesheet" href="app/style.css?v=182">
<link rel="stylesheet" href="app/style.css?v=184">
</head>
<body>
<!-- Crawlable static content. The app renders into a full-screen canvas/map
Expand Down Expand Up @@ -347,66 +347,76 @@ <h2>Israeli airfields and waypoints</h2>
<!-- Weather: SIGMET, wind, and the IMS PWX wind/temperature chart overlay. -->
<div class="tb-section" data-sec="weather">
<div class="tb-section-head" tabindex="0" role="button" data-i18n="tbSecWeather"></div>
<!-- Each map layer is a uniform .tb-group-box: a toggle on top, its
controls (sliders / selects) below, same spacing + widths for all. -->
<div class="tb-section-body">
<label class="navtoggle" data-i18n-title="tbShowSigmetTitle">
<input type="checkbox" id="sigmet-cb"> <span data-i18n="tbShowSigmet"></span>
</label>
<label class="navtoggle" data-i18n-title="tbShowNotamTitle">
<input type="checkbox" id="notam-cb"> <span data-i18n="tbShowNotam"></span>
</label>
<div id="notam-controls" hidden>
<label class="navtoggle" style="margin-top:3px" data-i18n-title="tbNotamTimeTitle">
<span data-i18n="tbNotamTime" style="font-size:11px"></span>
<input type="range" id="notam-time" min="0" max="72" step="1" value="0">
<span class="slider-val" id="notam-time-val" style="flex:0 0 auto"></span>
<div class="tb-group-box">
<label class="navtoggle" data-i18n-title="tbShowSigmetTitle">
<input type="checkbox" id="sigmet-cb"> <span data-i18n="tbShowSigmet"></span>
</label>
<div id="notam-updated" class="notam-updated" dir="ltr"></div>
</div>
<label class="navtoggle" data-i18n-title="tbShowWindTitle">
<input type="checkbox" id="show-wind-cb"> <span data-i18n="tbShowWind"></span>
</label>
<button id="wind-fetch" class="wind-input-row" type="button" style="display:none"
data-i18n="tbFetchWind" data-i18n-title="tbFetchWindTitle"></button>
<div id="wind-fetch-status" class="wind-input-row wind-fetch-status" style="display:none"></div>
<!-- Animated wind-field overlay (live Open-Meteo grid → leaflet-velocity). -->
<label class="navtoggle" data-i18n-title="tbWindFieldTitle">
<input type="checkbox" id="windfield-cb"> <span data-i18n="tbWindField"></span>
</label>
<div id="windfield-controls" hidden>
<label class="navtoggle" style="margin-top:3px">
<span data-i18n="tbWindFieldAlt" style="font-size:11px"></span>
<input type="range" id="windfield-alt" min="1000" max="5000" step="500" value="1500">
<span class="slider-val" id="windfield-alt-val" style="flex:0 0 auto"></span>
<div class="tb-group-box">
<label class="navtoggle" data-i18n-title="tbShowNotamTitle">
<input type="checkbox" id="notam-cb"> <span data-i18n="tbShowNotam"></span>
</label>
<label class="navtoggle" style="margin-top:3px">
<span data-i18n="tbWindFieldTime" style="font-size:11px"></span>
<input type="range" id="windfield-time" min="0" max="24" step="1" value="0">
<span class="slider-val" id="windfield-time-val" style="flex:0 0 auto"></span>
<div id="notam-controls" hidden>
<label class="navtoggle" data-i18n-title="tbNotamTimeTitle">
<span data-i18n="tbNotamTime"></span>
<input type="range" id="notam-time" min="0" max="72" step="1" value="0">
<span class="slider-val" id="notam-time-val"></span>
</label>
<div id="notam-updated" class="notam-updated" dir="ltr"></div>
</div>
</div>
<div class="tb-group-box">
<label class="navtoggle" data-i18n-title="tbShowWindTitle">
<input type="checkbox" id="show-wind-cb"> <span data-i18n="tbShowWind"></span>
</label>
<label class="navtoggle" style="margin-top:3px">
<span data-i18n="tbWindFieldOpacity" style="font-size:11px"></span>
<input type="range" id="windfield-opacity" min="0.2" max="1" step="0.05" value="0.7">
<span class="slider-val" id="windfield-opacity-val" style="flex:0 0 auto"></span>
<button id="windfield-opacity-reset" type="button" data-i18n-title="tbWindFieldOpacityReset" style="flex:0 0 auto;width:26px;padding:2px 0">↻</button>
<button id="wind-fetch" class="wind-input-row" type="button" style="display:none"
data-i18n="tbFetchWind" data-i18n-title="tbFetchWindTitle"></button>
<div id="wind-fetch-status" class="wind-input-row wind-fetch-status" style="display:none"></div>
</div>
<!-- Animated wind-field overlay (live Open-Meteo grid → leaflet-velocity). -->
<div class="tb-group-box">
<label class="navtoggle" data-i18n-title="tbWindFieldTitle">
<input type="checkbox" id="windfield-cb"> <span data-i18n="tbWindField"></span>
</label>
<div id="windfield-controls" hidden>
<label class="navtoggle">
<span data-i18n="tbWindFieldAlt"></span>
<input type="range" id="windfield-alt" min="1000" max="5000" step="500" value="1500">
<span class="slider-val" id="windfield-alt-val"></span>
</label>
<label class="navtoggle">
<span data-i18n="tbWindFieldTime"></span>
<input type="range" id="windfield-time" min="0" max="24" step="1" value="0">
<span class="slider-val" id="windfield-time-val"></span>
</label>
<label class="navtoggle">
<span data-i18n="tbWindFieldOpacity"></span>
<input type="range" id="windfield-opacity" min="0.2" max="1" step="0.05" value="0.7">
<span class="slider-val" id="windfield-opacity-val"></span>
<button id="windfield-opacity-reset" class="slider-reset" type="button" data-i18n-title="tbWindFieldOpacityReset">↻</button>
</label>
</div>
<div id="windfield-status" class="wind-fetch-status" style="display:none"></div>
</div>
<div id="windfield-status" class="wind-fetch-status" style="display:none"></div>
<!-- IMS PWX wind/temperature chart overlay (hidden until the ims-data
manifest loads). -->
<div id="ims-pwx" class="tb-group-box" hidden>
<label class="navtoggle" data-i18n-title="tbImsPwxTitle">
<input type="checkbox" id="ims-pwx-cb"> <span data-i18n="tbImsPwx"></span>
</label>
<div id="ims-pwx-controls" hidden>
<select id="ims-pwx-level" data-i18n-aria="tbImsPwxLevel" style="width:100%;font:inherit;font-size:11px;margin-top:3px"></select>
<select id="ims-pwx-time" data-i18n-aria="tbImsPwxTime" style="width:100%;font:inherit;font-size:11px;margin-top:3px"></select>
<label class="navtoggle" style="margin-top:3px">
<span data-i18n="tbImsPwxOpacity" style="font-size:11px"></span>
<select id="ims-pwx-level" data-i18n-aria="tbImsPwxLevel"></select>
<select id="ims-pwx-time" data-i18n-aria="tbImsPwxTime"></select>
<label class="navtoggle">
<span data-i18n="tbImsPwxOpacity"></span>
<input type="range" id="ims-pwx-opacity" min="0.2" max="1" step="0.05" value="0.6">
<span class="slider-val" id="ims-pwx-opacity-val" style="flex:0 0 auto"></span>
<button id="ims-pwx-opacity-reset" type="button" data-i18n-title="tbImsPwxOpacityReset" style="flex:0 0 auto;width:26px;padding:2px 0">↻</button>
<span class="slider-val" id="ims-pwx-opacity-val"></span>
<button id="ims-pwx-opacity-reset" class="slider-reset" type="button" data-i18n-title="tbImsPwxOpacityReset">↻</button>
</label>
<div id="ims-pwx-run" style="font-size:10px;opacity:0.75;margin-top:3px"></div>
<div id="ims-pwx-run" style="font-size:10px;opacity:0.75"></div>
</div>
</div>
<!-- SIGWX significant-weather map overlay (low-level prog chart panel,
Expand All @@ -417,12 +427,12 @@ <h2>Israeli airfields and waypoints</h2>
<input type="checkbox" id="sigwx-ov-cb"> <span data-i18n="tbSigwxOverlay"></span>
</label>
<div id="sigwx-ov-controls" hidden>
<select id="sigwx-ov-time" data-i18n-aria="tbSigwxTime" style="width:100%;font:inherit;font-size:11px;margin-top:3px"></select>
<label class="navtoggle" style="margin-top:3px">
<span data-i18n="tbImsPwxOpacity" style="font-size:11px"></span>
<select id="sigwx-ov-time" data-i18n-aria="tbSigwxTime"></select>
<label class="navtoggle">
<span data-i18n="tbImsPwxOpacity"></span>
<input type="range" id="sigwx-ov-opacity" min="0.2" max="1" step="0.05" value="0.55">
<span class="slider-val" id="sigwx-ov-opacity-val" style="flex:0 0 auto"></span>
<button id="sigwx-ov-opacity-reset" type="button" data-i18n-title="tbImsPwxOpacityReset" style="flex:0 0 auto;width:26px;padding:2px 0">↻</button>
<span class="slider-val" id="sigwx-ov-opacity-val"></span>
<button id="sigwx-ov-opacity-reset" class="slider-reset" type="button" data-i18n-title="tbImsPwxOpacityReset">↻</button>
</label>
</div>
</div>
Expand Down Expand Up @@ -622,7 +632,7 @@ <h3 data-i18n="tbSecSim">Simulator</h3>
hack for strings.js. Silences CodeQL js/eval-like-call (#12). -->
<script>
(function () {
var v = '?v=182';
var v = '?v=184';
var srcs = [
'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js',
'https://unpkg.com/leaflet-rotate@0.2.8/dist/leaflet-rotate.js',
Expand Down
29 changes: 29 additions & 0 deletions tests/toolbar-narrow-desktop.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,32 @@ test('Information section sliders + values stay inside the menu', async ({ page
Math.round(document.getElementById('notam-time').getBoundingClientRect().width));
expect(after).toBe(before); // stable while value changes
});

test('multi-open dropdowns get distinct columns (Extra layers ≠ Charts overlap)', async ({ page }) => {
// Opening two sections at once (here Extra layers + Charts) must tile them
// into separate columns; a missing offset once let the Extra-layers menu
// land on top of Charts and swallow #notam-list-btn clicks.
await boot(page, 1280);
await page.evaluate(() => {
for (const sec of ['charts', 'weather']) {
const el = document.querySelector('.tb-section[data-sec="' + sec + '"]');
el.classList.add('open');
el.querySelector('.tb-section-head')?.setAttribute('aria-expanded', 'true');
}
const tb = document.getElementById('toolbar');
tb.classList.add('multi-open');
tb.dataset.openCount = '2';
});
const rects = await page.evaluate(() => {
const r = sec => {
const b = document.querySelector('.tb-section[data-sec="' + sec + '"] .tb-section-body')
.getBoundingClientRect();
return { left: b.left, right: b.right };
};
return { charts: r('charts'), weather: r('weather') };
});
// The two bodies must not horizontally overlap.
const overlap = Math.min(rects.charts.right, rects.weather.right) -
Math.max(rects.charts.left, rects.weather.left);
expect(overlap).toBeLessThanOrEqual(0);
});
Loading