Dev #1
+32
-2
@@ -151,9 +151,33 @@ body.builderBody > main.content{ flex:1 1 auto; min-height:0; overflow:hidden; d
|
||||
disponible), avec leur propre défilement interne si leur contenu dépasse. */
|
||||
.builder3{ display:flex; gap:20px; align-items:stretch; margin-top:14px; flex:1 1 auto; min-height:0; }
|
||||
.builderPanel{ flex:0 0 260px; min-width:0; height:100%; overflow-y:auto; }
|
||||
.builderPanelRight{ flex:0 0 320px; min-width:0; height:100%; overflow-y:auto; }
|
||||
.builderCanvasArea{ flex:1 1 auto; min-width:0; height:100%; overflow-y:auto; display:flex; flex-direction:column; }
|
||||
|
||||
/* ---------- Panneau de propriétés flottant ---------- */
|
||||
/* Sorti du flux flex de .builder3 (position:fixed) : .builderCanvasArea
|
||||
(flex:1 1 auto) récupère automatiquement l'espace libéré, sans réglage
|
||||
supplémentaire — un panneau flottant repositionné par l'utilisateur
|
||||
n'agrandit/ne rétrécit donc jamais le canevas de travers. Position et
|
||||
état ouvert/fermé mémorisés par écran (voir restorePropsPanelState dans
|
||||
screen_edit.html) pour survivre à un changement de sélection ou un
|
||||
rechargement. */
|
||||
.builderPanelRight{
|
||||
position:fixed; top:90px; right:24px; width:340px; max-height:calc(100vh - 120px);
|
||||
min-width:0; display:flex; flex-direction:column; z-index:60;
|
||||
background:var(--panel); border:1px solid var(--border); border-radius:10px;
|
||||
box-shadow:0 12px 40px rgba(0,0,0,.55);
|
||||
}
|
||||
.builderPanelRight.hidden{ display:none; }
|
||||
.propsPanelHeader{
|
||||
display:flex; align-items:center; justify-content:space-between; gap:8px;
|
||||
padding:8px 10px; border-bottom:1px solid var(--border); background:var(--panel2);
|
||||
border-radius:10px 10px 0 0; cursor:move; flex:0 0 auto; user-select:none;
|
||||
}
|
||||
.propsPanelHeader .propsPanelTitle{ font-size:11px; color:var(--text-dim); text-transform:uppercase; letter-spacing:.05em; }
|
||||
.propsPanelBody{ padding:12px; overflow-y:auto; min-height:0; flex:1 1 auto; }
|
||||
#propsPanelReopenBtn{ position:fixed; top:90px; right:24px; z-index:60; display:none; }
|
||||
#propsPanelReopenBtn.visible{ display:inline-flex; }
|
||||
|
||||
.widgetGrid{ display:grid; grid-template-columns:1fr 1fr; gap:8px; }
|
||||
.widgetBtnForm{ margin:0; }
|
||||
.widgetBtn{
|
||||
@@ -306,7 +330,13 @@ code{ background:var(--panel2); border:1px solid var(--border); border-radius:4p
|
||||
body.builderBody{ height:auto; overflow:visible; }
|
||||
body.builderBody > main.content{ overflow:visible; }
|
||||
.builder3{ flex-direction:column; flex:none; }
|
||||
.builderPanel, .builderPanelRight, .builderCanvasArea{ flex:none; width:100%; height:auto; max-height:none; overflow:visible; }
|
||||
.builderPanel, .builderCanvasArea{ flex:none; width:100%; height:auto; max-height:none; overflow:visible; }
|
||||
/* Trop peu de largeur pour qu'un panneau flottant ait un sens (il
|
||||
couvrirait tout l'écran) : il rejoint la pile normale comme les deux
|
||||
autres colonnes, redimensionnement/déplacement désactivés (voir le
|
||||
garde useFloatingPanel() dans screen_edit.html). */
|
||||
.builderPanelRight{ position:static; flex:none; width:100%; height:auto; max-height:none; box-shadow:none; top:auto; right:auto; }
|
||||
#propsPanelReopenBtn{ display:none !important; }
|
||||
}
|
||||
|
||||
/* ---------- Logique de la scène : éditeur de flow à nœuds ---------- */
|
||||
|
||||
@@ -142,8 +142,16 @@
|
||||
<p class="hint" style="text-align:center;">Glisse pour déplacer, tire le coin pour redimensionner, clique pour sélectionner.</p>
|
||||
</div>
|
||||
|
||||
<!-- Panneau droit : propriétés de l'élément sélectionné -->
|
||||
<div class="builderPanel builderPanelRight">
|
||||
<!-- 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>
|
||||
<button type="button" class="button is-small" onclick="closePropsPanel()" title="Fermer">✕</button>
|
||||
</div>
|
||||
<div class="propsPanelBody">
|
||||
{% 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 %}
|
||||
@@ -370,6 +378,7 @@
|
||||
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -729,6 +738,89 @@ function restoreTreeCollapsedState() {
|
||||
});
|
||||
}
|
||||
|
||||
// ---------- Panneau de propriétés : flottant, déplaçable, fermable ----------
|
||||
//
|
||||
// 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
|
||||
// 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;
|
||||
}
|
||||
|
||||
function savePropsPanelState(state) {
|
||||
try {
|
||||
var current = JSON.parse(localStorage.getItem(propsPanelStateKey()) || '{}');
|
||||
localStorage.setItem(propsPanelStateKey(), JSON.stringify(Object.assign(current, state)));
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
function loadPropsPanelState() {
|
||||
try { return JSON.parse(localStorage.getItem(propsPanelStateKey()) || '{}'); } catch (e) { return {}; }
|
||||
}
|
||||
|
||||
function restorePropsPanelState() {
|
||||
var panel = document.getElementById('propsPanelFloat');
|
||||
var reopenBtn = document.getElementById('propsPanelReopenBtn');
|
||||
if (!panel) return;
|
||||
var state = loadPropsPanelState();
|
||||
if (state.left != null && state.top != null) {
|
||||
panel.style.left = state.left + 'px';
|
||||
panel.style.top = state.top + 'px';
|
||||
panel.style.right = 'auto';
|
||||
}
|
||||
var open = state.open !== false; // ouvert par défaut tant que rien n'a été fermé
|
||||
panel.classList.toggle('hidden', !open);
|
||||
if (reopenBtn) reopenBtn.classList.toggle('visible', !open);
|
||||
}
|
||||
|
||||
function closePropsPanel() {
|
||||
var panel = document.getElementById('propsPanelFloat');
|
||||
var reopenBtn = document.getElementById('propsPanelReopenBtn');
|
||||
if (panel) panel.classList.add('hidden');
|
||||
if (reopenBtn) reopenBtn.classList.add('visible');
|
||||
savePropsPanelState({ open: false });
|
||||
}
|
||||
|
||||
function openPropsPanel() {
|
||||
var panel = document.getElementById('propsPanelFloat');
|
||||
var reopenBtn = document.getElementById('propsPanelReopenBtn');
|
||||
if (panel) panel.classList.remove('hidden');
|
||||
if (reopenBtn) reopenBtn.classList.remove('visible');
|
||||
savePropsPanelState({ open: true });
|
||||
}
|
||||
|
||||
if (!window.__forgePropsPanelDragBound) {
|
||||
window.__forgePropsPanelDragBound = true;
|
||||
document.addEventListener('mousedown', function (e) {
|
||||
if (!e.target.closest('#propsPanelDragHandle') || e.target.closest('button')) return;
|
||||
var panel = document.getElementById('propsPanelFloat');
|
||||
if (!panel) return;
|
||||
var rect = panel.getBoundingClientRect();
|
||||
var startX = e.clientX, startY = e.clientY;
|
||||
var startLeft = rect.left, startTop = rect.top;
|
||||
panel.style.right = 'auto';
|
||||
function onMove(ev) {
|
||||
var maxLeft = window.innerWidth - panel.offsetWidth - 4;
|
||||
var maxTop = window.innerHeight - 40;
|
||||
var left = Math.max(4, Math.min(maxLeft, startLeft + (ev.clientX - startX)));
|
||||
var top = Math.max(4, Math.min(maxTop, startTop + (ev.clientY - startY)));
|
||||
panel.style.left = left + 'px';
|
||||
panel.style.top = top + 'px';
|
||||
}
|
||||
function onUp() {
|
||||
document.removeEventListener('mousemove', onMove);
|
||||
document.removeEventListener('mouseup', onUp);
|
||||
savePropsPanelState({ left: parseFloat(panel.style.left), top: parseFloat(panel.style.top) });
|
||||
}
|
||||
document.addEventListener('mousemove', onMove);
|
||||
document.addEventListener('mouseup', onUp);
|
||||
});
|
||||
}
|
||||
|
||||
// ---------- Surbrillance sur le canevas de l'élément sélectionné ----------
|
||||
//
|
||||
// Un élément posé DIRECTEMENT sur l'écran a déjà son cadre de sélection via
|
||||
@@ -1132,6 +1224,7 @@ function initBuilderPanel() {
|
||||
bindJaugeDefinitionSelect();
|
||||
restoreTreeCollapsedState();
|
||||
applySelectionHighlight(CURRENT_SELECTED_ID);
|
||||
restorePropsPanelState();
|
||||
}
|
||||
|
||||
// Jauge : quand on change l'objet de données à suivre SANS quitter le
|
||||
|
||||
Reference in New Issue
Block a user