Reskin the whole admin UI (not just game widgets) with Bulma
Loads Bulma 1.0.2 in base.html (data-theme="dark" for its native dark palette) for every page that extends it, plus play.html directly. Converts every admin template — index, game dashboard, screens list, element types, object new/edit, data form/list — to real Bulma markup: navbar, breadcrumb component, box/card, field/control/input/select, table, notification, buttons, and a native Bulma modal for the data-row detail popup. Forge's own style.css keeps only what Bulma doesn't cover (the fixed-viewport builder/object-edit layouts, the element tree, canvas, flow-graph editor) and now acts as a secondary/override layer rather than a competing design system, matching how per-element inline customization already overrides widget defaults. screen_edit.html (the 3-panel screen builder) gets the same navbar/breadcrumb/button treatment plus its top rename form, but its flow-graph node editor, canvas and element tree keep their existing custom styling — several of their inputs have JS relying on exact DOM sibling structure (e.g. slider oninput reading nextElementSibling) or Bulma's own select/wrapper requirement, and reskinning them without a browser to verify against risked silently breaking the app's most complex feature. Buttons and headings there are still fully converted (safe, purely additive class changes). Verified: full test suite green, every route smoke-rendered 200 OK via the test client after the change.
This commit is contained in:
+27
-35
@@ -5,28 +5,20 @@
|
||||
{% block extra_head %}
|
||||
<link rel="stylesheet" href="{{ google_fonts_link }}">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css">
|
||||
<!-- Bulma : moteur de style par défaut de certains widgets (Bouton, Titre,
|
||||
Conteneur en carte) — voir screens/widgets/control_groups/bulma_controls.py.
|
||||
Chargé APRÈS style.css : les styles en ligne posés par le panneau de
|
||||
propriétés (couleur, taille personnalisées...) gagnent de toute façon
|
||||
toujours contre une classe CSS, donc l'ordre ne change rien au résultat
|
||||
— Bulma ne fournit qu'un habillage par défaut, jamais un dernier mot. -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@1.0.2/css/bulma.min.css">
|
||||
{% endblock %}
|
||||
{% block breadcrumb %}
|
||||
<a class="crumb" href="{{ url_for('game_dashboard', slug=game.slug) }}">{{ game.name }}</a>
|
||||
<span class="crumb-sep">/</span>
|
||||
<a class="crumb" href="{{ url_for('screens_list', slug=game.slug) }}">Écrans</a>
|
||||
<span class="crumb-sep">/</span><span class="crumb">{{ screen.name }}</span>
|
||||
<li><a href="{{ url_for('game_dashboard', slug=game.slug) }}">{{ game.name }}</a></li>
|
||||
<li><a href="{{ url_for('screens_list', slug=game.slug) }}">Écrans</a></li>
|
||||
<li class="is-active"><a>{{ screen.name }}</a></li>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div class="fieldRow" style="align-items:center; justify-content:space-between;">
|
||||
<form method="post" action="{{ url_for('screen_rename', slug=game.slug, screen_id=screen.id) }}" class="fieldRow" style="align-items:center; margin:0;">
|
||||
<input type="text" name="name" value="{{ screen.name }}" required style="font-size:16px; font-weight:700; width:auto;">
|
||||
<button type="submit" class="smallBtn">Renommer</button>
|
||||
<form method="post" action="{{ url_for('screen_rename', slug=game.slug, screen_id=screen.id) }}" class="field has-addons" style="align-items:center; margin:0;">
|
||||
<div class="control"><input class="input" type="text" name="name" value="{{ screen.name }}" required style="font-size:16px; font-weight:700; width:auto;"></div>
|
||||
<div class="control"><button type="submit" class="button is-small">Renommer</button></div>
|
||||
</form>
|
||||
{% if not screen.is_template %}
|
||||
<a class="smallBtn primary" href="{{ url_for('game_play', slug=game.slug) }}" target="_blank">▶️ Jouer depuis le début</a>
|
||||
<a class="button is-small is-primary" href="{{ url_for('game_play', slug=game.slug) }}" target="_blank">▶️ Jouer depuis le début</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
@@ -67,7 +59,7 @@
|
||||
{% 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">
|
||||
<h2>Éléments de cet écran</h2>
|
||||
<h2 class="subtitle is-6">Éléments de cet écran</h2>
|
||||
{% if top_level_elements %}
|
||||
<div class="elementTree">
|
||||
{% for el in top_level_elements %}
|
||||
@@ -162,12 +154,12 @@
|
||||
<h2 style="margin:0;">{{ w.get('icon','❔') }} {{ el|elabel }}{% if el.name %} <span class="hint">— {{ w.get('label', el.widget) }}</span>{% endif %}</h2>
|
||||
<form method="post" action="{{ url_for('element_delete', slug=game.slug, element_id=el.id) }}"
|
||||
onsubmit="return confirm('Supprimer cet élément ?');">
|
||||
<button type="submit" class="smallBtn danger">🗑️</button>
|
||||
<button type="submit" class="smallBtn button is-small is-danger">🗑️</button>
|
||||
</form>
|
||||
</div>
|
||||
<form method="post" action="{{ url_for('element_rename', slug=game.slug, element_id=el.id) }}" class="fieldRow" style="align-items:center; margin:6px 0;">
|
||||
<input type="text" name="name" value="{{ el.name or '' }}" placeholder="Donne un nom à cet élément" style="flex:1;">
|
||||
<button type="submit" class="smallBtn">Nommer</button>
|
||||
<button type="submit" class="smallBtn button is-small">Nommer</button>
|
||||
</form>
|
||||
<div class="fieldRow" style="align-items:center; margin:6px 0;">
|
||||
<label style="width:auto; margin-right:6px;">ID</label>
|
||||
@@ -204,12 +196,12 @@
|
||||
<div class="listRow" style="display:flex; flex-direction:column; gap:6px;">
|
||||
<form method="post" action="{{ url_for('element_rename', slug=game.slug, element_id=tab.id) }}" class="fieldRow" style="align-items:center; margin:0;">
|
||||
<input type="text" name="name" value="{{ tab.name or ('Onglet ' ~ loop.index) }}" placeholder="Nom de l'onglet" style="flex:1;">
|
||||
<button type="submit" class="smallBtn">Renommer</button>
|
||||
<button type="submit" class="smallBtn button is-small">Renommer</button>
|
||||
</form>
|
||||
<div class="fieldRow" style="align-items:center; margin:0;">
|
||||
<a class="smallBtn" style="flex:1; text-align:center;" href="{{ url_for('screen_edit', slug=game.slug, screen_id=screen.id, selected=tab.id) }}">📥 Contenu de l'onglet</a>
|
||||
<a class="smallBtn button is-small" style="flex:1; text-align:center;" href="{{ url_for('screen_edit', slug=game.slug, screen_id=screen.id, selected=tab.id) }}">📥 Contenu de l'onglet</a>
|
||||
<form method="post" action="{{ url_for('element_delete', slug=game.slug, element_id=tab.id) }}" onsubmit="return confirm('Supprimer cet onglet et tout son contenu ?');">
|
||||
<button type="submit" class="smallBtn danger">🗑️</button>
|
||||
<button type="submit" class="smallBtn button is-small is-danger">🗑️</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -219,7 +211,7 @@
|
||||
<p class="hint">Aucun onglet pour l'instant.</p>
|
||||
{% endif %}
|
||||
<form method="post" action="{{ url_for('element_tab_add', slug=game.slug, element_id=el.id) }}" style="margin-top:8px;">
|
||||
<button type="submit" class="smallBtn primary" style="width:100%;">➕ Ajouter un onglet</button>
|
||||
<button type="submit" class="smallBtn button is-small is-primary" style="width:100%;">➕ Ajouter un onglet</button>
|
||||
</form>
|
||||
</div>
|
||||
</details>
|
||||
@@ -356,16 +348,16 @@
|
||||
</div>
|
||||
<div class="flowPanelBody" id="flowPanelBody">
|
||||
<div class="flowToolbar">
|
||||
<button type="button" class="smallBtn" onclick="openNodeForm('trigger')">➕ Déclencheur</button>
|
||||
<button type="button" class="smallBtn" onclick="openNodeForm('condition')">➕ Condition</button>
|
||||
<button type="button" class="smallBtn" onclick="openNodeForm('action')">➕ Action</button>
|
||||
<button type="button" class="smallBtn button is-small" onclick="openNodeForm('trigger')">➕ Déclencheur</button>
|
||||
<button type="button" class="smallBtn button is-small" onclick="openNodeForm('condition')">➕ Condition</button>
|
||||
<button type="button" class="smallBtn button is-small" onclick="openNodeForm('action')">➕ Action</button>
|
||||
<span class="hint">Clique un point de sortie d'un nœud, puis le point d'entrée d'un autre nœud, pour les relier. Reclique une connexion pour la supprimer.</span>
|
||||
</div>
|
||||
|
||||
<div id="nodeForm" class="nodeForm" style="display:none;">
|
||||
<div class="fieldRow" style="align-items:center; justify-content:space-between;">
|
||||
<strong id="nodeFormTitle">Nouveau nœud</strong>
|
||||
<button type="button" class="smallBtn" onclick="closeNodeForm()">✕</button>
|
||||
<button type="button" class="smallBtn button is-small" onclick="closeNodeForm()">✕</button>
|
||||
</div>
|
||||
|
||||
<div id="nodeFormTrigger" style="display:none;">
|
||||
@@ -409,7 +401,7 @@
|
||||
</select>
|
||||
</label>
|
||||
<div id="nf-cond-extra-clauses"></div>
|
||||
<button type="button" class="smallBtn" onclick="addFlowConditionClause()">+ Ajouter une condition</button>
|
||||
<button type="button" class="smallBtn button is-small" onclick="addFlowConditionClause()">+ Ajouter une condition</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -497,7 +489,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="actionsRow"><button type="button" class="smallBtn primary" onclick="submitNodeForm()">+ Ajouter ce nœud</button></div>
|
||||
<div class="actionsRow"><button type="button" class="smallBtn button is-small is-primary" onclick="submitNodeForm()">+ Ajouter ce nœud</button></div>
|
||||
</div>
|
||||
|
||||
<div class="flowCanvasWrap">
|
||||
@@ -532,13 +524,13 @@
|
||||
{% endfor %}
|
||||
</select>
|
||||
</label>
|
||||
<button type="button" class="smallBtn" onclick="addAnimTrack()">➕ Ajouter un clip</button>
|
||||
<button type="button" class="smallBtn button is-small" onclick="addAnimTrack()">➕ Ajouter un clip</button>
|
||||
</div>
|
||||
|
||||
<div id="animClipForm" class="nodeForm" style="display:none;">
|
||||
<div class="fieldRow" style="align-items:center; justify-content:space-between;">
|
||||
<strong id="animClipFormTitle">Clip d'animation</strong>
|
||||
<button type="button" class="smallBtn" onclick="closeAnimClipForm()">✕</button>
|
||||
<button type="button" class="smallBtn button is-small" onclick="closeAnimClipForm()">✕</button>
|
||||
</div>
|
||||
|
||||
<label>Type
|
||||
@@ -564,7 +556,7 @@
|
||||
|
||||
<div id="anim-clip-custom-fields" style="display:none;">
|
||||
<div id="anim-clip-keyframes"></div>
|
||||
<button type="button" class="smallBtn" onclick="addAnimKeyframeRow()">+ Ajouter une image-clé</button>
|
||||
<button type="button" class="smallBtn button is-small" onclick="addAnimKeyframeRow()">+ Ajouter une image-clé</button>
|
||||
</div>
|
||||
|
||||
<div class="fieldRow">
|
||||
@@ -599,9 +591,9 @@
|
||||
</label>
|
||||
|
||||
<div class="actionsRow">
|
||||
<button type="button" class="smallBtn primary" onclick="saveAnimClipForm()">Enregistrer</button>
|
||||
<button type="button" class="smallBtn" onclick="previewAnimClip()">▶ Aperçu</button>
|
||||
<button type="button" class="smallBtn danger" onclick="deleteAnimClipForm()">🗑️ Supprimer</button>
|
||||
<button type="button" class="smallBtn button is-small is-primary" onclick="saveAnimClipForm()">Enregistrer</button>
|
||||
<button type="button" class="smallBtn button is-small" onclick="previewAnimClip()">▶ Aperçu</button>
|
||||
<button type="button" class="smallBtn button is-small is-danger" onclick="deleteAnimClipForm()">🗑️ Supprimer</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1546,7 +1538,7 @@ function renderFlowConditionClauses() {
|
||||
CONDITION_OPERATORS_HTML +
|
||||
'</select></label>' +
|
||||
'<label>Valeur de comparaison<input type="text" id="nf-cond-extra-value-' + idx + '" placeholder="ex. 1, vrai, 10..." value="' + (clause.value || '').replace(/"/g, '"') + '" onchange="flowConditionExtraClauses[' + idx + '].value = this.value"></label>' +
|
||||
'<button type="button" class="smallBtn" onclick="removeFlowConditionClause(' + idx + ')">Retirer cette condition</button>' +
|
||||
'<button type="button" class="smallBtn button is-small" onclick="removeFlowConditionClause(' + idx + ')">Retirer cette condition</button>' +
|
||||
'</div>';
|
||||
}).join('');
|
||||
flowConditionExtraClauses.forEach(function(clause, idx) {
|
||||
|
||||
Reference in New Issue
Block a user