Make Bulma the default style engine for Bouton/Titre/Conteneur, layered under existing inline customization
Adds a new "class:" control-target kind (save_element_controls.py, _visible_attrs.py) alongside the existing content/attr/style ones, so a widget can carry CSS classes built from independent named slots (color, size, shape...) without them overwriting each other. Bouton and Titre get their Bulma base class (button/title) via fixed_attrs; Conteneur gets an opt-in "Carte (Bulma)" preset instead of a forced default, since it's also used as an invisible layout wrapper. Bouton's font-size/border-radius sliders no longer freeze their default value into inline style at creation (new c_slider no_freeze flag), so Bulma's own button styling shows through until a user actually customizes it — inline style still wins over any class the moment it's set, exactly like today. Loads bulma.min.css via CDN in screen_edit.html and play.html, same pattern as animate.css.
This commit is contained in:
@@ -97,7 +97,15 @@ def save_element_controls(slug, element_id, form):
|
|||||||
content = raw_value
|
content = raw_value
|
||||||
else:
|
else:
|
||||||
kind, name = target.split(":", 1)
|
kind, name = target.split(":", 1)
|
||||||
store = attributes if kind == "attr" else style
|
if kind == "class":
|
||||||
|
# "class:xxx" : un jeton de classe CSS externe (ex. un
|
||||||
|
# modificateur Bulma) parmi d'autres, chacun mémorisé sous sa
|
||||||
|
# propre clé "_class_xxx" pour ne pas s'écraser entre eux —
|
||||||
|
# voir _visible_attrs.py qui les rassemble avec la classe de
|
||||||
|
# base du widget (fixed_attrs) au moment du rendu.
|
||||||
|
store, name = attributes, "_class_" + name
|
||||||
|
else:
|
||||||
|
store = attributes if kind == "attr" else style
|
||||||
if raw_value in (None, ""):
|
if raw_value in (None, ""):
|
||||||
store.pop(name, None)
|
store.pop(name, None)
|
||||||
elif ctype != "checkbox" and name not in store and _is_default_value(control, raw_value):
|
elif ctype != "checkbox" and name not in store and _is_default_value(control, raw_value):
|
||||||
|
|||||||
@@ -3,11 +3,23 @@ from .auto_id import _auto_id
|
|||||||
|
|
||||||
|
|
||||||
def _visible_attrs(el, meta, ctx=None):
|
def _visible_attrs(el, meta, ctx=None):
|
||||||
|
raw_attrs = el.get("attributes") or {}
|
||||||
attrs = {
|
attrs = {
|
||||||
k: (_apply_ctx(v, ctx) if isinstance(v, str) else v)
|
k: (_apply_ctx(v, ctx) if isinstance(v, str) else v)
|
||||||
for k, v in (el.get("attributes") or {}).items() if not k.startswith("_")
|
for k, v in raw_attrs.items() if not k.startswith("_")
|
||||||
}
|
}
|
||||||
attrs.update(meta.get("fixed_attrs", {}))
|
attrs.update(meta.get("fixed_attrs", {}))
|
||||||
|
# Classes externes (ex. Bulma) réglées via un contrôle "class:xxx" — voir
|
||||||
|
# save_element_controls.py — chacune mémorisée sous "_class_xxx" pour ne
|
||||||
|
# pas s'écraser entre elles ; assemblées ici avec la classe de base du
|
||||||
|
# widget (posée via fixed_attrs, ex. "button"/"box"/"title") pour former
|
||||||
|
# l'attribut class final. Une classe personnalisée éventuellement tapée
|
||||||
|
# à la main (peu probable ici, mais possible via fixed_attrs) est gardée
|
||||||
|
# en tête.
|
||||||
|
extra_classes = [v for k, v in raw_attrs.items() if k.startswith("_class_") and v]
|
||||||
|
if extra_classes:
|
||||||
|
base_class = attrs.get("class", "")
|
||||||
|
attrs["class"] = " ".join(([base_class] if base_class else []) + extra_classes)
|
||||||
attrs.setdefault("id", _auto_id(el))
|
attrs.setdefault("id", _auto_id(el))
|
||||||
attrs["data-element-id"] = el["id"]
|
attrs["data-element-id"] = el["id"]
|
||||||
if el.get("parent_id"):
|
if el.get("parent_id"):
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
from ..controls.c_select import c_select
|
||||||
|
from ..controls.c_checkbox import c_checkbox
|
||||||
|
|
||||||
|
# Réglages Bulma (https://bulma.io) posés en plus des réglages de style
|
||||||
|
# "libres" déjà existants (couleur, taille de police...) — chacun ajoute un
|
||||||
|
# jeton de classe CSS (target "class:xxx", voir save_element_controls.py et
|
||||||
|
# _visible_attrs.py) à la classe de base du widget (posée via fixed_attrs,
|
||||||
|
# ex. "button"). Laissé à "" (par défaut) = look Bulma nu, sans modificateur.
|
||||||
|
# Les réglages de couleur/taille "libres" du widget restent utilisables par-
|
||||||
|
# dessus : un style en ligne gagne toujours contre une classe CSS, donc
|
||||||
|
# personnaliser une couleur ou une taille continue de fonctionner exactement
|
||||||
|
# comme avant, Bulma ne servant alors que de base par défaut.
|
||||||
|
BULMA_BUTTON_CONTROLS = [
|
||||||
|
c_select("bulma_couleur", "Style Bulma — couleur", "class:couleur", [
|
||||||
|
("", "Aucun (couleurs ci-dessous)"),
|
||||||
|
("is-primary", "Primaire"), ("is-link", "Lien"), ("is-info", "Info"),
|
||||||
|
("is-success", "Succès"), ("is-warning", "Attention"), ("is-danger", "Danger"),
|
||||||
|
("is-light", "Clair"), ("is-dark", "Sombre"),
|
||||||
|
], default="", group="Style Bulma"),
|
||||||
|
c_select("bulma_taille", "Style Bulma — taille", "class:taille", [
|
||||||
|
("", "Normale"), ("is-small", "Petite"), ("is-medium", "Moyenne"), ("is-large", "Grande"),
|
||||||
|
], default="", group="Style Bulma"),
|
||||||
|
c_checkbox("bulma_arrondi", "Coins bien arrondis (Bulma)", "class:arrondi", "is-rounded", "", group="Style Bulma"),
|
||||||
|
c_checkbox("bulma_contour", "Contour seulement (Bulma)", "class:contour", "is-outlined", "", group="Style Bulma"),
|
||||||
|
]
|
||||||
@@ -1,2 +1,11 @@
|
|||||||
def c_slider(key, label, target, unit="px", min=0, max=100, step=1, default=16, group=None):
|
def c_slider(key, label, target, unit="px", min=0, max=100, step=1, default=16, group=None, no_freeze=False):
|
||||||
return {"key": key, "label": label, "type": "slider", "target": target, "unit": unit, "min": min, "max": max, "step": step, "default": default, "group": group}
|
return {
|
||||||
|
"key": key, "label": label, "type": "slider", "target": target, "unit": unit,
|
||||||
|
"min": min, "max": max, "step": step, "default": default, "group": group,
|
||||||
|
# no_freeze : n'écrit PAS ce réglage en style au moment de la création
|
||||||
|
# de l'élément malgré sa valeur par défaut non-vide (voir
|
||||||
|
# default_style_and_attributes) — utilisé quand un widget porte déjà
|
||||||
|
# une classe CSS externe (ex. Bulma) qui doit rester visible tant que
|
||||||
|
# ce réglage n'a pas été explicitement personnalisé.
|
||||||
|
"no_freeze": no_freeze,
|
||||||
|
}
|
||||||
|
|||||||
@@ -50,8 +50,8 @@ def default_style_and_attributes(widget_key):
|
|||||||
if default in (None, ""):
|
if default in (None, ""):
|
||||||
continue
|
continue
|
||||||
if ctype == "slider":
|
if ctype == "slider":
|
||||||
if control["key"] in _PER_SIDE_KEYS:
|
if control["key"] in _PER_SIDE_KEYS or control.get("no_freeze"):
|
||||||
continue # réglage par côté : jamais figé (voir commentaire plus haut)
|
continue # réglage par côté, ou explicitement non figé (voir c_slider) : jamais figé
|
||||||
unit = control.get("unit", "")
|
unit = control.get("unit", "")
|
||||||
default = f"{default}{unit}"
|
default = f"{default}{unit}"
|
||||||
kind, name = target.split(":", 1)
|
kind, name = target.split(":", 1)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ from .controls.c_align import c_align
|
|||||||
from .controls.c_select import c_select
|
from .controls.c_select import c_select
|
||||||
from .control_groups.text_style_controls_extra import TEXT_STYLE_CONTROLS_EXTRA
|
from .control_groups.text_style_controls_extra import TEXT_STYLE_CONTROLS_EXTRA
|
||||||
from .control_groups.data_binding_controls import DATA_BINDING_CONTROLS
|
from .control_groups.data_binding_controls import DATA_BINDING_CONTROLS
|
||||||
|
from .control_groups.bulma_controls import BULMA_BUTTON_CONTROLS
|
||||||
from .font_options import FONT_OPTIONS
|
from .font_options import FONT_OPTIONS
|
||||||
from ..flow.constants import CONDITION_OPERATORS
|
from ..flow.constants import CONDITION_OPERATORS
|
||||||
|
|
||||||
@@ -31,6 +32,10 @@ WIDGETS = {
|
|||||||
"titre": {
|
"titre": {
|
||||||
"label": "Titre", "icon": "🔠", "tag": None, "has_content": True,
|
"label": "Titre", "icon": "🔠", "tag": None, "has_content": True,
|
||||||
"w": 55, "h": 10, "default_content": "Titre",
|
"w": 55, "h": 10, "default_content": "Titre",
|
||||||
|
# class:"title" — poids de police et espacement Bulma par défaut ; la
|
||||||
|
# taille reste pilotée par le réglage "Taille du texte" ci-dessous
|
||||||
|
# comme avant (non affecté), Bulma ne fournissant ici que l'habillage.
|
||||||
|
"fixed_attrs": {"class": "title"},
|
||||||
"controls": [
|
"controls": [
|
||||||
c_textarea("content", "Texte — {{champ}} affiche la valeur de ce champ sur la ligne trouvée ci-dessous", "content", default="Titre", group="Contenu"),
|
c_textarea("content", "Texte — {{champ}} affiche la valeur de ce champ sur la ligne trouvée ci-dessous", "content", default="Titre", group="Contenu"),
|
||||||
c_select("niveau", "Importance du titre", "attr:_niveau",
|
c_select("niveau", "Importance du titre", "attr:_niveau",
|
||||||
@@ -46,14 +51,19 @@ WIDGETS = {
|
|||||||
"bouton": {
|
"bouton": {
|
||||||
"label": "Bouton", "icon": "🔘", "tag": "button", "has_content": True,
|
"label": "Bouton", "icon": "🔘", "tag": "button", "has_content": True,
|
||||||
"w": 30, "h": 8, "default_content": "Valider",
|
"w": 30, "h": 8, "default_content": "Valider",
|
||||||
|
# class:"button" — donne au Bouton l'apparence Bulma par défaut
|
||||||
|
# (padding, poids de police, transitions...) tant qu'aucune couleur/
|
||||||
|
# taille "libre" n'est personnalisée ci-dessous — voir
|
||||||
|
# BULMA_BUTTON_CONTROLS et _visible_attrs.py.
|
||||||
|
"fixed_attrs": {"class": "button"},
|
||||||
"controls": [
|
"controls": [
|
||||||
c_text("content", "Texte du bouton", "content", default="Valider", group="Contenu"),
|
c_text("content", "Texte du bouton", "content", default="Valider", group="Contenu"),
|
||||||
c_color("color", "Couleur du texte", "style:color", "#ffffff", group="Texte"),
|
c_color("color", "Couleur du texte", "style:color", "#ffffff", group="Texte"),
|
||||||
c_color("background", "Couleur de fond", "style:background-color", "#5b8cff", group="Texte"),
|
c_color("background", "Couleur de fond", "style:background-color", "#5b8cff", group="Texte"),
|
||||||
c_slider("font-size", "Taille du texte", "style:font-size", min=10, max=40, default=15, group="Texte"),
|
c_slider("font-size", "Taille du texte", "style:font-size", min=10, max=40, default=15, group="Texte", no_freeze=True),
|
||||||
c_slider("border-radius", "Arrondi des coins", "style:border-radius", min=0, max=40, default=8, group="Texte"),
|
c_slider("border-radius", "Arrondi des coins", "style:border-radius", min=0, max=40, default=8, group="Texte", no_freeze=True),
|
||||||
c_checkbox("submit", "Valide un formulaire", "attr:type", "submit", "button", group="Contenu"),
|
c_checkbox("submit", "Valide un formulaire", "attr:type", "submit", "button", group="Contenu"),
|
||||||
] + TEXT_STYLE_CONTROLS_EXTRA,
|
] + BULMA_BUTTON_CONTROLS + TEXT_STYLE_CONTROLS_EXTRA,
|
||||||
},
|
},
|
||||||
"lien": {
|
"lien": {
|
||||||
"label": "Lien", "icon": "🔗", "tag": "a", "has_content": True,
|
"label": "Lien", "icon": "🔗", "tag": "a", "has_content": True,
|
||||||
@@ -197,6 +207,13 @@ WIDGETS = {
|
|||||||
"w": 50, "h": 30, "default_content": "",
|
"w": 50, "h": 30, "default_content": "",
|
||||||
"controls": [
|
"controls": [
|
||||||
c_text("content", "Texte", "content", group="Contenu"),
|
c_text("content", "Texte", "content", group="Contenu"),
|
||||||
|
# "Carte (Bulma)" reste optionnel (pas une classe posée par
|
||||||
|
# défaut) : ce widget sert aussi bien de simple habillage
|
||||||
|
# invisible (empilement, fond de décor plein écran...) que de
|
||||||
|
# vraie carte — lui imposer le fond blanc/l'ombre de Bulma par
|
||||||
|
# défaut casserait ces usages existants. Voir _visible_attrs.py.
|
||||||
|
c_select("bulma_carte", "Style Bulma", "class:carte",
|
||||||
|
[("", "Aucun"), ("box", "Carte (fond clair, ombre, coins arrondis)")], default="", group="Style Bulma"),
|
||||||
c_color("background", "Couleur de fond", "style:background-color", "#1f2430", group="Texte"),
|
c_color("background", "Couleur de fond", "style:background-color", "#1f2430", group="Texte"),
|
||||||
c_slider("border-radius", "Arrondi des coins", "style:border-radius", min=0, max=60, default=10, group="Texte"),
|
c_slider("border-radius", "Arrondi des coins", "style:border-radius", min=0, max=60, default=10, group="Texte"),
|
||||||
c_slider("opacity", "Opacité", "style:opacity", unit="", min=0, max=1, step=0.05, default=1, group="Texte"),
|
c_slider("opacity", "Opacité", "style:opacity", unit="", min=0, max=1, step=0.05, default=1, group="Texte"),
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
||||||
<link rel="stylesheet" href="{{ google_fonts_link }}">
|
<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">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css">
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@1.0.2/css/bulma.min.css">
|
||||||
<style>
|
<style>
|
||||||
body{ margin:0; background:#000; }
|
body{ margin:0; background:#000; }
|
||||||
/* ---------- Zone de jeu à proportion fixe (voir #playFrame) ----------
|
/* ---------- Zone de jeu à proportion fixe (voir #playFrame) ----------
|
||||||
|
|||||||
@@ -5,6 +5,13 @@
|
|||||||
{% block extra_head %}
|
{% block extra_head %}
|
||||||
<link rel="stylesheet" href="{{ google_fonts_link }}">
|
<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">
|
<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 %}
|
{% endblock %}
|
||||||
{% block breadcrumb %}
|
{% block breadcrumb %}
|
||||||
<a class="crumb" href="{{ url_for('game_dashboard', slug=game.slug) }}">{{ game.name }}</a>
|
<a class="crumb" href="{{ url_for('game_dashboard', slug=game.slug) }}">{{ game.name }}</a>
|
||||||
|
|||||||
Reference in New Issue
Block a user