Audit complet de mise en forme — Bouton (3e élément du tableau)

Implémente toutes les options manquantes identifiées pour l'élément
Bouton : typographie (gras/italique/transformation/police/taille/
espacement des lettres/couleur), icône SVG optionnelle avec position
(avant/après le texte) et taille réglables — au-delà de l'Étiquette,
qui n'a qu'une icône fixe —, tous les attributs de boîte partagés déjà
créés pour Titre/Paragraphe/Image, et un effet visuel universel au
survol/clic.

Deux ajouts transversaux demandés pendant le test : un réglage "les 4
côtés de la bordure à la fois" dans le module de boîte partagé
(bénéficie automatiquement à tous les éléments qui l'utilisent), et le
glisser-déposer d'un élément du canevas vers une autre page via le
panneau Pages (le mécanisme serveur existait déjà pour la pagination
automatique, seule l'interaction manuelle manquait).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
william
2026-09-26 12:47:46 +02:00
co-authored by Claude Sonnet 5
parent 9ad50c58b8
commit 8f879f6321
8 changed files with 529 additions and 16 deletions
@@ -222,6 +222,51 @@ def _render_list(el: dict[str, Any], _children_by_parent: dict[int | None, list[
return f'<{tag} class="docList" data-element-id="{el["id"]}" data-kind="{el["kind"]}">{items_html}</{tag}>'
_BUTTON_TEXT_TRANSFORMS = ("uppercase", "lowercase", "capitalize")
def _button_text_style(a: dict[str, Any]) -> list[str]:
"""Déclarations de typographie propres au bouton (jamais dans
box_style.py, partagé avec d'autres kinds qui n'ont pas tous une
notion de texte)."""
parts = []
if a.get("bold"):
# 800 (jamais 700, déjà le poids par défaut du CSS de base) :
# "gras" ne fait que RENFORCER le poids existant, jamais
# l'affaiblir — aucun bouton déjà créé ne change d'apparence tant
# que cette case n'est pas cochée explicitement.
parts.append("font-weight:800;")
if a.get("italic"):
parts.append("font-style:italic;")
text_transform = str(a.get("text_transform", "none"))
if text_transform in _BUTTON_TEXT_TRANSFORMS:
parts.append(f"text-transform:{text_transform};")
font_family = str(a.get("font_family", "")).strip()
if font_family:
parts.append(f"font-family:{html_lib.escape(font_family)};")
font_size = str(a.get("font_size", "")).strip()
if font_size:
parts.append(f"font-size:{html_lib.escape(font_size)};")
letter_spacing = str(a.get("letter_spacing", "")).strip()
if letter_spacing:
parts.append(f"letter-spacing:{html_lib.escape(letter_spacing)};")
text_color = str(a.get("text_color", "")).strip()
if text_color:
parts.append(f"color:{html_lib.escape(text_color)};")
return parts
def _button_icon_html(a: dict[str, Any]) -> str:
svg_markup = str(a.get("svg_markup", "")).strip()
if not svg_markup:
return ""
icon_size = str(a.get("icon_size", "")).strip()
size_style = (
f' style="width:{html_lib.escape(icon_size)}; height:{html_lib.escape(icon_size)};"' if icon_size else ""
)
return f'<span class="docButtonIcon"{size_style}>{sanitize_svg_markup(svg_markup)}</span>'
def _render_button(el: dict[str, Any], _children_by_parent: dict[int | None, list[dict[str, Any]]]) -> str:
a = el["attributes"]
label = html_lib.escape(str(a.get("label", "Bouton")))
@@ -236,9 +281,19 @@ def _render_button(el: dict[str, Any], _children_by_parent: dict[int | None, lis
# que le reste des appels AJAX de l'éditeur.
attachment_filename = html_lib.escape(str(a.get("attachment_filename", "")))
attachment_attr = f' data-attachment-filename="{attachment_filename}"' if attachment_filename else ""
style = " ".join(_button_text_style(a) + [render_box_style(a)]).strip()
style_attr = f' style="{style}"' if style else ""
icon_html = _button_icon_html(a)
label_span = f'<span class="docButtonLabel">{label}</span>'
inner = (
f"{label_span}{icon_html}" if str(a.get("icon_position", "before")) == "after" else f"{icon_html}{label_span}"
)
return (
f'<button type="button" class="docButton" data-element-id="{el["id"]}" '
f'data-kind="bouton"{target_attr}{attachment_attr}>{label}</button>'
f'data-kind="bouton"{target_attr}{attachment_attr}{style_attr}>{inner}</button>'
)