Make the left element-tree panel floating/draggable/closable too, same as the right one
Generalized the floating-panel mechanism from the properties panel (props/propsPanelFloat/propsPanelReopenBtn) into reusable functions keyed by a short id, and applied it to the left "Éléments de cet écran" panel (key "left", panelLeftFloat, panelLeftReopenBtn). Both panels can now be closed independently, letting the canvas take the screen's full width for the most faithful possible preview against the actual /play rendering. Shared CSS (.floatPanel/.floatPanelHeader/.floatPanelBody/.floatPanelReopenBtn with --left/--right position variants) replaces the props-panel-only rules from the previous commit.
Fixed the two querySelector('.builderPanel .elementTree') call sites (used to patch the tree preview into the DOM after an unrelated canvas-only refresh) that would have silently stopped finding the tree once its wrapper's class changed.
This commit is contained in:
+65
-44
@@ -57,8 +57,16 @@
|
||||
|
||||
<div class="builder3" id="builder3">
|
||||
{% set el = elements|selectattr("id", "equalto", selected_id)|first if selected_id else none %}
|
||||
<!-- Panneau gauche : ajouter un élément (icônes, sans jargon technique) -->
|
||||
<div class="builderPanel">
|
||||
<!-- Panneau gauche : ajouter un élément (icônes, sans jargon technique) —
|
||||
flottant, déplaçable, fermable, même mécanisme que le panneau droit
|
||||
(voir floatPanel*() plus bas). -->
|
||||
<button type="button" id="panelLeftReopenBtn" class="button is-small floatPanelReopenBtn" onclick="openLeftPanel()" title="Rouvrir le panneau des éléments">🧩 Éléments</button>
|
||||
<div class="floatPanel floatPanel--left" id="panelLeftFloat">
|
||||
<div class="floatPanelHeader" data-drag-panel="panelLeftFloat" data-drag-key="left">
|
||||
<span class="floatPanelTitle">⋮⋮ Éléments de cet écran</span>
|
||||
<button type="button" class="button is-small" onclick="closeLeftPanel()" title="Fermer">✕</button>
|
||||
</div>
|
||||
<div class="floatPanelBody">
|
||||
<h2 class="subtitle is-6">Éléments de cet écran</h2>
|
||||
{% if top_level_elements %}
|
||||
<div class="elementTree">
|
||||
@@ -112,6 +120,7 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Menu contextuel (clic droit sur un élément de l'arborescence) -->
|
||||
@@ -144,14 +153,14 @@
|
||||
|
||||
<!-- Panneau droit : propriétés de l'élément sélectionné — flottant,
|
||||
déplaçable à la souris par son en-tête, fermable pour agrandir le
|
||||
canevas (voir bindPropsPanelFloating() plus bas). -->
|
||||
<button type="button" id="propsPanelReopenBtn" class="button is-small" onclick="openPropsPanel()" title="Rouvrir le panneau de propriétés">⚙️ Propriétés</button>
|
||||
<div class="builderPanel builderPanelRight" id="propsPanelFloat">
|
||||
<div class="propsPanelHeader" id="propsPanelDragHandle">
|
||||
<span class="propsPanelTitle">⋮⋮ Propriétés</span>
|
||||
canevas (voir floatPanel*() plus bas). -->
|
||||
<button type="button" id="propsPanelReopenBtn" class="button is-small floatPanelReopenBtn" onclick="openPropsPanel()" title="Rouvrir le panneau de propriétés">⚙️ Propriétés</button>
|
||||
<div class="floatPanel floatPanel--right" id="propsPanelFloat">
|
||||
<div class="floatPanelHeader" data-drag-panel="propsPanelFloat" data-drag-key="props">
|
||||
<span class="floatPanelTitle">⋮⋮ Propriétés</span>
|
||||
<button type="button" class="button is-small" onclick="closePropsPanel()" title="Fermer">✕</button>
|
||||
</div>
|
||||
<div class="propsPanelBody">
|
||||
<div class="floatPanelBody">
|
||||
{% if not selected_id %}
|
||||
<div class="hint" style="padding:20px 0;">Sélectionne un élément (sur l'écran ou dans la liste) pour voir et modifier ses propriétés ici.</div>
|
||||
{% else %}
|
||||
@@ -738,35 +747,38 @@ function restoreTreeCollapsedState() {
|
||||
});
|
||||
}
|
||||
|
||||
// ---------- Panneau de propriétés : flottant, déplaçable, fermable ----------
|
||||
// ---------- Panneaux gauche/droite : flottants, déplaçables, fermables ----------
|
||||
//
|
||||
// Sorti du flux (position:fixed en CSS) pour ne jamais rétrécir le canevas
|
||||
// selon où on le pose — le fermer libère toute cette largeur pour une
|
||||
// Sortis du flux (position:fixed en CSS) pour ne jamais rétrécir le canevas
|
||||
// selon où on les pose — les fermer libère cette largeur pour une
|
||||
// prévisualisation plus fidèle à ce que "Jouer" affiche réellement (voir
|
||||
// bug remonté : un panneau trop large réduisait le canevas au point de
|
||||
// casser la mise en page des onglets). Position et état ouvert/fermé
|
||||
// mémorisés par écran pour survivre à un changement de sélection (qui
|
||||
// remplace tout #builder3, voir refreshBuilderPanel) ou un rechargement.
|
||||
function propsPanelStateKey() {
|
||||
return 'forgePropsPanel:' + GAME_SLUG + ':' + SCREEN_ID;
|
||||
// bug remonté : des panneaux trop larges réduisaient le canevas au point de
|
||||
// casser la mise en page des onglets). Un seul jeu de fonctions génériques
|
||||
// (key = identifiant court mémorisé dans localStorage, distinct par
|
||||
// panneau) plutôt qu'une copie par panneau. Position et état ouvert/fermé
|
||||
// survivent à un changement de sélection (qui remplace tout #builder3, voir
|
||||
// refreshBuilderPanel) ou un rechargement — voir les appels à
|
||||
// restoreFloatPanelState() dans initBuilderPanel().
|
||||
function floatPanelStateKey(key) {
|
||||
return 'forgeFloatPanel:' + GAME_SLUG + ':' + SCREEN_ID + ':' + key;
|
||||
}
|
||||
|
||||
function savePropsPanelState(state) {
|
||||
function saveFloatPanelState(key, state) {
|
||||
try {
|
||||
var current = JSON.parse(localStorage.getItem(propsPanelStateKey()) || '{}');
|
||||
localStorage.setItem(propsPanelStateKey(), JSON.stringify(Object.assign(current, state)));
|
||||
var current = JSON.parse(localStorage.getItem(floatPanelStateKey(key)) || '{}');
|
||||
localStorage.setItem(floatPanelStateKey(key), JSON.stringify(Object.assign(current, state)));
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
function loadPropsPanelState() {
|
||||
try { return JSON.parse(localStorage.getItem(propsPanelStateKey()) || '{}'); } catch (e) { return {}; }
|
||||
function loadFloatPanelState(key) {
|
||||
try { return JSON.parse(localStorage.getItem(floatPanelStateKey(key)) || '{}'); } catch (e) { return {}; }
|
||||
}
|
||||
|
||||
function restorePropsPanelState() {
|
||||
var panel = document.getElementById('propsPanelFloat');
|
||||
var reopenBtn = document.getElementById('propsPanelReopenBtn');
|
||||
function restoreFloatPanelState(key, panelId, reopenBtnId) {
|
||||
var panel = document.getElementById(panelId);
|
||||
var reopenBtn = document.getElementById(reopenBtnId);
|
||||
if (!panel) return;
|
||||
var state = loadPropsPanelState();
|
||||
var state = loadFloatPanelState(key);
|
||||
if (state.left != null && state.top != null) {
|
||||
panel.style.left = state.left + 'px';
|
||||
panel.style.top = state.top + 'px';
|
||||
@@ -777,27 +789,35 @@ function restorePropsPanelState() {
|
||||
if (reopenBtn) reopenBtn.classList.toggle('visible', !open);
|
||||
}
|
||||
|
||||
function closePropsPanel() {
|
||||
var panel = document.getElementById('propsPanelFloat');
|
||||
var reopenBtn = document.getElementById('propsPanelReopenBtn');
|
||||
function closeFloatPanel(key, panelId, reopenBtnId) {
|
||||
var panel = document.getElementById(panelId);
|
||||
var reopenBtn = document.getElementById(reopenBtnId);
|
||||
if (panel) panel.classList.add('hidden');
|
||||
if (reopenBtn) reopenBtn.classList.add('visible');
|
||||
savePropsPanelState({ open: false });
|
||||
saveFloatPanelState(key, { open: false });
|
||||
}
|
||||
|
||||
function openPropsPanel() {
|
||||
var panel = document.getElementById('propsPanelFloat');
|
||||
var reopenBtn = document.getElementById('propsPanelReopenBtn');
|
||||
function openFloatPanel(key, panelId, reopenBtnId) {
|
||||
var panel = document.getElementById(panelId);
|
||||
var reopenBtn = document.getElementById(reopenBtnId);
|
||||
if (panel) panel.classList.remove('hidden');
|
||||
if (reopenBtn) reopenBtn.classList.remove('visible');
|
||||
savePropsPanelState({ open: true });
|
||||
saveFloatPanelState(key, { open: true });
|
||||
}
|
||||
|
||||
if (!window.__forgePropsPanelDragBound) {
|
||||
window.__forgePropsPanelDragBound = true;
|
||||
// Raccourcis utilisés directement par les attributs onclick du gabarit.
|
||||
function closePropsPanel() { closeFloatPanel('props', 'propsPanelFloat', 'propsPanelReopenBtn'); }
|
||||
function openPropsPanel() { openFloatPanel('props', 'propsPanelFloat', 'propsPanelReopenBtn'); }
|
||||
function closeLeftPanel() { closeFloatPanel('left', 'panelLeftFloat', 'panelLeftReopenBtn'); }
|
||||
function openLeftPanel() { openFloatPanel('left', 'panelLeftFloat', 'panelLeftReopenBtn'); }
|
||||
|
||||
if (!window.__forgeFloatPanelDragBound) {
|
||||
window.__forgeFloatPanelDragBound = true;
|
||||
document.addEventListener('mousedown', function (e) {
|
||||
if (!e.target.closest('#propsPanelDragHandle') || e.target.closest('button')) return;
|
||||
var panel = document.getElementById('propsPanelFloat');
|
||||
var handle = e.target.closest('.floatPanelHeader');
|
||||
if (!handle || e.target.closest('button')) return;
|
||||
var panel = document.getElementById(handle.dataset.dragPanel);
|
||||
var key = handle.dataset.dragKey;
|
||||
if (!panel) return;
|
||||
var rect = panel.getBoundingClientRect();
|
||||
var startX = e.clientX, startY = e.clientY;
|
||||
@@ -814,7 +834,7 @@ if (!window.__forgePropsPanelDragBound) {
|
||||
function onUp() {
|
||||
document.removeEventListener('mousemove', onMove);
|
||||
document.removeEventListener('mouseup', onUp);
|
||||
savePropsPanelState({ left: parseFloat(panel.style.left), top: parseFloat(panel.style.top) });
|
||||
saveFloatPanelState(key, { left: parseFloat(panel.style.left), top: parseFloat(panel.style.top) });
|
||||
}
|
||||
document.addEventListener('mousemove', onMove);
|
||||
document.addEventListener('mouseup', onUp);
|
||||
@@ -960,8 +980,8 @@ function refreshAfterReorder() {
|
||||
curCanvas.innerHTML = newCanvas.innerHTML;
|
||||
applySelectionHighlight(CURRENT_SELECTED_ID);
|
||||
}
|
||||
var newTree = doc.querySelector('.builderPanel .elementTree');
|
||||
var curTree = document.querySelector('.builderPanel .elementTree');
|
||||
var newTree = doc.querySelector('#panelLeftFloat .elementTree');
|
||||
var curTree = document.querySelector('#panelLeftFloat .elementTree');
|
||||
if (newTree && curTree) { curTree.innerHTML = newTree.innerHTML; }
|
||||
restoreTreeCollapsedState();
|
||||
});
|
||||
@@ -1016,8 +1036,8 @@ function refreshCanvasOnly() {
|
||||
// Aperçu du contenu dans l'arborescence de gauche (ex: texte tronqué) —
|
||||
// sans toucher au panneau de droite, pour ne jamais faire perdre le
|
||||
// focus/curseur pendant qu'on modifie un réglage.
|
||||
var newTree = doc.querySelector('.builderPanel .elementTree');
|
||||
var curTree = document.querySelector('.builderPanel .elementTree');
|
||||
var newTree = doc.querySelector('#panelLeftFloat .elementTree');
|
||||
var curTree = document.querySelector('#panelLeftFloat .elementTree');
|
||||
if (newTree && curTree) { curTree.innerHTML = newTree.innerHTML; restoreTreeCollapsedState(); }
|
||||
});
|
||||
}
|
||||
@@ -1224,7 +1244,8 @@ function initBuilderPanel() {
|
||||
bindJaugeDefinitionSelect();
|
||||
restoreTreeCollapsedState();
|
||||
applySelectionHighlight(CURRENT_SELECTED_ID);
|
||||
restorePropsPanelState();
|
||||
restoreFloatPanelState('props', 'propsPanelFloat', 'propsPanelReopenBtn');
|
||||
restoreFloatPanelState('left', 'panelLeftFloat', 'panelLeftReopenBtn');
|
||||
}
|
||||
|
||||
// Jauge : quand on change l'objet de données à suivre SANS quitter le
|
||||
|
||||
Reference in New Issue
Block a user