Rétablir l'onglet Génération mémorisé et ignorer le repli du panneau sur téléphone

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Antoine Jacquin
2026-09-27 18:06:16 +02:00
parent b24ebcd83a
commit a9196d0c97
2 changed files with 25 additions and 5 deletions

View File

@ -1403,3 +1403,17 @@ def test_ui_single_tabbed_panel():
assert "@media (max-width: 720px)" in _MAP_CSS and "#panel" in _MAP_CSS
for state in ('data-sheet="closed"', 'data-sheet="half"', 'data-sheet="full"'):
assert state.split('"')[1] in _MAP_CSS, state
def test_ui_panel_restores_tab_and_ignores_collapse_on_phone():
from lidar_pipeline.mapui import _MAP_JS
render = _MAP_JS.split("function panelRender(")[1].split("\nfunction ")[0]
# Onglet choisi gardé à part : Génération rétablie une fois /api/status connu
assert "PANEL.want = PANEL.tab;" in _MAP_JS
assert "PANEL.tab = tabs.includes(PANEL.want) ? PANEL.want : 'view';" in render
assert "tab: PANEL.want" in _MAP_JS.split("function panelSave(")[1].split("\n")[0]
assert "PANEL.want = PANEL.tab = tab;" in _MAP_JS.split("function openTab(")[1].split("\nfunction ")[0]
# Repli en bande d'icônes : ordinateur seulement
assert "PANEL.collapsed && !isPhone()" in render
assert "toggle('collapsed', PANEL.collapsed)" not in render
assert "toggle('panel-collapsed', PANEL.collapsed)" not in render

View File

@ -1112,6 +1112,10 @@ document.addEventListener('panel:tab', (e) => {
// --- panneau à onglets --------------------------------------------------------
const PANEL_LS = 'lidar-panel';
const PANEL = Object.assign({ tab: 'view', collapsed: false, sheet: 'half' }, lsGet(PANEL_LS, {}));
// want = onglet choisi (mémorisé) ; tab = onglet affiché. Génération encore
// inconnue au démarrage (api/status) : Affichage en attendant, puis l'onglet
// choisi revient dès qu'il est proposé.
PANEL.want = PANEL.tab;
const phoneQuery = window.matchMedia('(max-width: 720px)');
const isPhone = () => phoneQuery.matches;
@ -1127,20 +1131,22 @@ function panelVisibleTab() {
return PANEL.tab;
}
function panelSave() { lsSet(PANEL_LS, { tab: PANEL.tab, collapsed: PANEL.collapsed, sheet: PANEL.sheet }); }
function panelSave() { lsSet(PANEL_LS, { tab: PANEL.want, collapsed: PANEL.collapsed, sheet: PANEL.sheet }); }
function panelRender() {
const tabs = panelTabs();
if (!tabs.includes(PANEL.tab)) PANEL.tab = 'view';
PANEL.tab = tabs.includes(PANEL.want) ? PANEL.want : 'view';
el('panelTabs').querySelectorAll('button[data-tab]').forEach(b => {
b.hidden = !tabs.includes(b.dataset.tab);
b.setAttribute('aria-selected', String(b.dataset.tab === PANEL.tab));
});
for (const t of ['view', 'print', 'gen', 'share']) el('tab-' + t).hidden = t !== PANEL.tab;
const panel = el('panel');
panel.classList.toggle('collapsed', PANEL.collapsed);
// Repli en bande d'icônes : ordinateur seulement (le téléphone a son volet).
const collapsed = PANEL.collapsed && !isPhone();
panel.classList.toggle('collapsed', collapsed);
panel.dataset.sheet = PANEL.sheet;
document.body.classList.toggle('panel-collapsed', PANEL.collapsed);
document.body.classList.toggle('panel-collapsed', collapsed);
// Hauteur couverte par le volet, que l'échelle, l'attribution et les messages
// dégagent ; volet plein : la carte est cachée, rien à dégager (sinon ils
// remonteraient en haut de l'écran, sur les outils).
@ -1159,7 +1165,7 @@ function openTab(tab) {
PANEL.sheet = 'half';
}
const resized = isPhone() && PANEL.sheet !== before;
PANEL.tab = tab;
PANEL.want = PANEL.tab = tab;
PANEL.collapsed = false;
panelSave(); panelRender();
if (resized) setTimeout(panelRender, 220); // hauteur finale après la transition CSS