Dev #1

Merged
w-vandal merged 62 commits from dev into main 2026-08-26 04:56:44 +00:00
7 changed files with 122 additions and 35 deletions
Showing only changes of commit a7518355ed - Show all commits
+3 -1
View File
@@ -138,8 +138,10 @@ def _render_jauge(el, meta, slug, children_map=None, ctx=None, parent_flex_direc
# donnée" — sinon la jauge resterait figée sur sa valeur de départ après
# un changement, exactement comme il fallait déjà repérer "repeaterItem"
# pour les Répéteurs (voir 1.1/1.2).
extra_classes = " ".join(v for k, v in attrs.items() if k.startswith("_class_") and v)
bar_class = html_lib.escape((f"progress jaugeBar {extra_classes}").strip())
bar = (
f'<progress class="progress jaugeBar" value="{percent}" max="100" '
f'<progress class="{bar_class}" value="{percent}" max="100" '
f'style="--bulma-progress-value-background-color:{fill_color}; --bulma-progress-bar-background-color:#1c2130; '
f'margin:0; border-radius:6px; transition:background-color .3s ease;">{percent}%</progress>'
)
+6 -1
View File
@@ -21,6 +21,10 @@ def _render_onglets(el, meta, slug, children_map=None, ctx=None, parent_flex_dir
tabs = (children_map or {}).get(el["id"], [])
attrs = _visible_attrs(el, meta, ctx)
# Les variantes Bulma (alignement/style/taille... voir BULMA_TABS_CONTROLS)
# calculées par _visible_attrs atterrissent dans "class" — c'est le
# <div class="tabs"> qui doit les porter, pas ce wrapper de positionnement.
tabs_extra_classes = attrs.pop("class", "")
style = _style_string(el, " display:flex; flex-direction:column;", parent_flex_direction)
group_id = _auto_id(el)
@@ -53,9 +57,10 @@ def _render_onglets(el, meta, slug, children_map=None, ctx=None, parent_flex_dir
f'{tab_html}</div>'
)
tabs_class = html_lib.escape(("tabs " + tabs_extra_classes).strip())
return (
f'<div {_attr_string(attrs, style)}>'
f'<div class="tabs"><ul>{"".join(bar_items)}</ul></div>'
f'<div class="{tabs_class}"><ul>{"".join(bar_items)}</ul></div>'
f'<div class="forgeTabPanels" style="flex:1 1 auto; min-height:0;">{"".join(panels)}</div>'
f"</div>"
)
+7 -1
View File
@@ -15,6 +15,11 @@ def _render_select(el, meta, slug=None, children_map=None, ctx=None, parent_flex
# l'élément (comme tous les autres widgets), le <select> reste à
# l'intérieur avec ses propres attributs de formulaire (name, required).
outer_attrs = _visible_attrs(el, meta, ctx)
# Les variantes Bulma (couleur/taille/arrondi... voir BULMA_FIELD_CONTROLS)
# calculées par _visible_attrs atterrissent normalement dans "class" —
# ici c'est le <div class="select"> qui doit les porter, pas le <select>
# ni le wrapper de positionnement, donc on les redirige à la main.
bulma_classes = outer_attrs.get("class", "")
select_attrs = {k: v for k, v in outer_attrs.items() if k not in ("id", "class", "data-element-id", "data-anim-target")}
wrapper_attrs = {k: v for k, v in outer_attrs.items() if k in ("id", "data-element-id", "data-anim-target")}
style = _style_string(el, " display:flex;", parent_flex_direction)
@@ -22,4 +27,5 @@ def _render_select(el, meta, slug=None, children_map=None, ctx=None, parent_flex
options = [o.strip() for o in content.split("\n") if o.strip()]
opts_html = "".join(f'<option value="{html_lib.escape(o)}">{html_lib.escape(o)}</option>' for o in options)
select_html = f'<select {_attr_string(select_attrs, "")}>{opts_html}</select>'
return f'<div {_attr_string(wrapper_attrs, style)}><div class="select is-fullwidth">{select_html}</div></div>'
select_wrap_class = html_lib.escape(("select is-fullwidth " + bulma_classes).strip())
return f'<div {_attr_string(wrapper_attrs, style)}><div class="{select_wrap_class}">{select_html}</div></div>'
+14
View File
@@ -0,0 +1,14 @@
# Listes de modificateurs Bulma (https://bulma.io) réutilisées par plusieurs
# widgets pour construire leurs réglages "class:xxx" (voir
# control_groups/bulma_controls.py et save_element_controls.py) — un seul
# endroit à mettre à jour si Bulma change de version/palette.
BULMA_COLOR_OPTIONS = [
("", "Aucune (couleur par défaut)"),
("is-primary", "Primaire"), ("is-link", "Lien"), ("is-info", "Info"),
("is-success", "Succès"), ("is-warning", "Attention"), ("is-danger", "Danger"),
("is-white", "Blanc"), ("is-light", "Clair"), ("is-dark", "Sombre"), ("is-black", "Noir"), ("is-text", "Texte"),
]
BULMA_SIZE_OPTIONS = [
("", "Normale"), ("is-small", "Petite"), ("is-medium", "Moyenne"), ("is-large", "Grande"),
]
@@ -1,25 +1,65 @@
from ..controls.c_select import c_select
from ..controls.c_checkbox import c_checkbox
from ..bulma_variants import BULMA_COLOR_OPTIONS, BULMA_SIZE_OPTIONS
_GROUP = "Style Bulma"
# Chaque widget "natif Bulma" (voir fixed_attrs dans registry.py) expose ici
# TOUTES les variantes que Bulma propose pour son composant — chacune ajoute
# un jeton de classe indépendant (target "class:xxx", voir
# save_element_controls.py et _visible_attrs.py) à la classe de base déjà
# posée par fixed_attrs. Laissé à "" (par défaut) = aucun modificateur, look
# Bulma nu. Les réglages de couleur/taille "libres" du widget (curseurs,
# sélecteurs de couleur) restent utilisables par-dessus : un style en ligne
# gagne toujours contre une classe CSS, donc personnaliser une couleur ou une
# taille "à la main" continue de fonctionner exactement comme avant.
# 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"),
c_select("bulma_couleur", "Couleur", "class:couleur", BULMA_COLOR_OPTIONS, default="", group=_GROUP),
c_checkbox("bulma_nuance_claire", "Nuance claire (combinable avec une couleur)", "class:nuance", "is-light", "", group=_GROUP),
c_select("bulma_taille", "Taille", "class:taille", BULMA_SIZE_OPTIONS, default="", group=_GROUP),
c_checkbox("bulma_arrondi", "Coins bien arrondis", "class:arrondi", "is-rounded", "", group=_GROUP),
c_checkbox("bulma_contour", "Contour seulement (fond transparent)", "class:contour", "is-outlined", "", group=_GROUP),
c_checkbox("bulma_inverse", "Couleurs inversées", "class:inverse", "is-inverted", "", group=_GROUP),
c_checkbox("bulma_statique", "Statique (non cliquable visuellement)", "class:statique", "is-static", "", group=_GROUP),
c_checkbox("bulma_chargement", "Indicateur de chargement", "class:chargement", "is-loading", "", group=_GROUP),
c_checkbox("bulma_pleine_largeur", "Pleine largeur", "class:largeur", "is-fullwidth", "", group=_GROUP),
]
BULMA_TITLE_CONTROLS = [
c_select("bulma_taille", "Taille Bulma (indépendante du niveau de titre)", "class:taille",
[("", "Automatique"), ("is-1", "1 — la plus grande"), ("is-2", "2"), ("is-3", "3"),
("is-4", "4"), ("is-5", "5"), ("is-6", "6 — la plus petite")], default="", group=_GROUP),
c_checkbox("bulma_espace", "Garder l'espacement même sans sous-titre", "class:espace", "is-spaced", "", group=_GROUP),
]
BULMA_PROGRESS_CONTROLS = [
c_select("bulma_taille", "Taille de la barre", "class:taille", BULMA_SIZE_OPTIONS, default="", group=_GROUP),
]
BULMA_TABLE_CONTROLS = [
c_checkbox("bulma_bordure", "Bordures", "class:bordure", "is-bordered", "", default=True, group=_GROUP),
c_checkbox("bulma_pleine_largeur", "Pleine largeur", "class:largeur", "is-fullwidth", "", default=True, group=_GROUP),
c_checkbox("bulma_zebre", "Lignes zébrées", "class:zebre", "is-striped", "", group=_GROUP),
c_checkbox("bulma_survol", "Ligne surlignée au survol", "class:survol", "is-hoverable", "", group=_GROUP),
c_checkbox("bulma_compact", "Compact (cellules resserrées)", "class:compact", "is-narrow", "", group=_GROUP),
]
BULMA_TABS_CONTROLS = [
c_select("bulma_alignement", "Alignement", "class:alignement",
[("", "Gauche (par défaut)"), ("is-centered", "Centré"), ("is-right", "Droite")], default="", group=_GROUP),
c_select("bulma_style", "Style", "class:style",
[("", "Simple (soulignement)"), ("is-boxed", "Encadré"), ("is-toggle", "Boutons accolés"),
("is-toggle is-toggle-rounded", "Boutons accolés, arrondis")], default="", group=_GROUP),
c_select("bulma_taille", "Taille", "class:taille", BULMA_SIZE_OPTIONS, default="", group=_GROUP),
c_checkbox("bulma_pleine_largeur", "Pleine largeur (onglets étirés)", "class:largeur", "is-fullwidth", "", group=_GROUP),
]
# Champs de formulaire (input/textarea/select) : mêmes variantes que Bulma
# propose pour .input/.textarea/.select.
BULMA_FIELD_CONTROLS = [
c_select("bulma_couleur", "Couleur", "class:couleur", BULMA_COLOR_OPTIONS, default="", group=_GROUP),
c_select("bulma_taille", "Taille", "class:taille", BULMA_SIZE_OPTIONS, default="", group=_GROUP),
c_checkbox("bulma_arrondi", "Coins bien arrondis", "class:arrondi", "is-rounded", "", group=_GROUP),
c_checkbox("bulma_statique", "Statique (lecture seule visuelle)", "class:statique", "is-static", "", group=_GROUP),
]
+18 -1
View File
@@ -49,7 +49,24 @@ def default_style_and_attributes(widget_key):
attributes, style = {}, {}
for control in meta.get("controls", []):
ctype = control["type"]
if ctype in ("checkbox", "toggle_token", "preset", "scale", "color"):
if ctype == "checkbox":
# Une case cochée PAR DÉFAUT (ex: "Première ligne = en-tête" du
# Tableau, ou un modificateur Bulma comme "is-bordered" activé
# d'origine) doit vraiment être active dès la création — sinon le
# panneau de propriétés affiche une case cochée qui ne correspond
# à rien de réellement posé sur l'élément. Une case décochée par
# défaut, elle, reste volontairement absente (comportement
# existant, inchangé) : rien à figer.
if control.get("default") is True and control.get("target"):
kind, name = control["target"].split(":", 1)
if kind == "class":
attributes["_class_" + name] = control["true_value"]
elif kind == "attr":
attributes[name] = control["true_value"]
else:
style[name] = control["true_value"]
continue
if ctype in ("toggle_token", "preset", "scale", "color"):
continue
if ctype == "size":
# 0 est TOUJOURS la valeur sentinelle "automatique" pour ce
+14 -11
View File
@@ -9,7 +9,10 @@ from .controls.c_align import c_align
from .controls.c_select import c_select
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.bulma_controls import BULMA_BUTTON_CONTROLS
from .control_groups.bulma_controls import (
BULMA_BUTTON_CONTROLS, BULMA_TITLE_CONTROLS, BULMA_PROGRESS_CONTROLS,
BULMA_TABLE_CONTROLS, BULMA_TABS_CONTROLS, BULMA_FIELD_CONTROLS,
)
from .font_options import FONT_OPTIONS
from ..flow.constants import CONDITION_OPERATORS
@@ -40,7 +43,7 @@ WIDGETS = {
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",
[("1", "Très grand — titre principal"), ("2", "Grand"), ("3", "Moyen")], default="2", group="Contenu"),
] + DATA_BINDING_CONTROLS + [
] + DATA_BINDING_CONTROLS + BULMA_TITLE_CONTROLS + [
c_slider("font-size", "Taille du texte", "style:font-size", min=14, max=80, default=32, group="Texte"),
c_color("color", "Couleur du texte", "style:color", "#e8eaf0", group="Texte"),
c_align("text-align", "Alignement", "style:text-align", default="left", group="Texte"),
@@ -105,7 +108,7 @@ WIDGETS = {
c_text("placeholder", "Texte indicatif", "attr:placeholder", placeholder="ex. Votre réponse", group="Contenu"),
c_text("name", "Nom du champ", "attr:name", placeholder="ex. reponse1", group="Contenu"),
c_checkbox("required", "Obligatoire", "attr:required", "required", "", group="Contenu"),
],
] + BULMA_FIELD_CONTROLS,
},
"champ_email": {
"label": "Champ — email", "icon": "📧", "tag": "input", "has_content": False, "self_closing": True,
@@ -114,7 +117,7 @@ WIDGETS = {
c_text("placeholder", "Texte indicatif", "attr:placeholder", placeholder="ex. votre@email.com", default="votre@email.com", group="Contenu"),
c_text("name", "Nom du champ", "attr:name", placeholder="ex. email", group="Contenu"),
c_checkbox("required", "Obligatoire", "attr:required", "required", "", group="Contenu"),
],
] + BULMA_FIELD_CONTROLS,
},
"champ_mot_de_passe": {
"label": "Champ — mot de passe", "icon": "🔒", "tag": "input", "has_content": False, "self_closing": True,
@@ -123,7 +126,7 @@ WIDGETS = {
c_text("placeholder", "Texte indicatif", "attr:placeholder", placeholder="ex. Mot de passe", group="Contenu"),
c_text("name", "Nom du champ", "attr:name", placeholder="ex. mot_de_passe", group="Contenu"),
c_checkbox("required", "Obligatoire", "attr:required", "required", "", group="Contenu"),
],
] + BULMA_FIELD_CONTROLS,
},
"case_a_cocher": {
"label": "Case à cocher", "icon": "☑️", "tag": "input", "has_content": True, "special_render": "checkbox_label",
@@ -154,7 +157,7 @@ WIDGETS = {
c_text("placeholder", "Texte indicatif", "attr:placeholder", placeholder="ex. Votre message", group="Contenu"),
c_text("name", "Nom du champ", "attr:name", placeholder="ex. message", group="Contenu"),
c_checkbox("required", "Obligatoire", "attr:required", "required", "", group="Contenu"),
],
] + BULMA_FIELD_CONTROLS,
},
"liste_deroulante": {
"label": "Liste déroulante", "icon": "🔽", "tag": "select", "has_content": True, "special_render": "select_options",
@@ -163,7 +166,7 @@ WIDGETS = {
c_textarea("content", "Options — une par ligne", "content", default="Option 1\nOption 2\nOption 3", group="Contenu"),
c_text("name", "Nom du champ", "attr:name", placeholder="ex. choix", group="Contenu"),
c_checkbox("required", "Obligatoire", "attr:required", "required", "", group="Contenu"),
],
] + BULMA_FIELD_CONTROLS,
},
"groupe_champs": {
"label": "Groupe de champs", "icon": "🗃️", "tag": "fieldset", "has_content": True, "special_render": "fieldset_legend",
@@ -195,13 +198,13 @@ WIDGETS = {
"tableau": {
"label": "Tableau", "icon": "🗂️", "tag": "table", "has_content": True, "special_render": "table",
"w": 55, "h": 25, "default_content": "Colonne 1;Colonne 2\nValeur A;Valeur B",
"fixed_attrs": {"class": "table is-bordered is-fullwidth"},
"fixed_attrs": {"class": "table"},
"controls": [
c_textarea("content", "Contenu — une ligne par rangée, colonnes séparées par ;", "content",
default="Colonne 1;Colonne 2\nValeur A;Valeur B", group="Contenu"),
c_checkbox("header_row", "Première ligne = en-tête", "attr:_header_row", "1", "", default=True, group="Contenu"),
c_color("color", "Couleur du texte", "style:color", "#e8eaf0", group="Texte"),
],
] + BULMA_TABLE_CONTROLS,
},
"conteneur": {
"label": "Conteneur / décor", "icon": "⬛", "tag": "div", "has_content": True,
@@ -283,7 +286,7 @@ WIDGETS = {
c_slider("nom_taille", "Taille du texte du nom", "attr:_nom_taille", unit="", min=8, max=32, default=12, group="Apparence"),
c_checkbox("nom_gras", "Nom en gras", "attr:_nom_gras", "1", "", default=False, group="Apparence"),
c_checkbox("nom_italique", "Nom en italique", "attr:_nom_italique", "1", "", default=False, group="Apparence"),
],
] + BULMA_PROGRESS_CONTROLS,
},
"superposition": {
# 3.4 (Confort) — overlay/modale réutilisable : couvre TOUJOURS tout
@@ -310,6 +313,6 @@ WIDGETS = {
# qui réutilise les routes existantes (element_rename, element_delete).
"label": "Onglets", "icon": "🗂️", "tag": "div", "has_content": False, "special_render": "onglets",
"w": 60, "h": 40, "default_content": "",
"controls": [],
"controls": BULMA_TABS_CONTROLS,
},
}