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:
co-authored by
Claude Sonnet 5
parent
9ad50c58b8
commit
8f879f6321
@@ -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>'
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -67,14 +67,31 @@ regroupement à chaque appel.
|
||||
forgeDocOpenImageLightbox), même principe que les mini-jeux et la
|
||||
pièce jointe d'un bouton. `caption` (non vide) enveloppe le tout dans
|
||||
un `<figure><figcaption>` échappée.
|
||||
- **Bouton** : `<button>` avec son `label`, un `data-target` optionnel
|
||||
- **Bouton** : `<button>` avec son `label` (enveloppé dans
|
||||
`<span class="docButtonLabel">`), un `data-target` optionnel
|
||||
(navigation) et un `data-attachment-filename` optionnel — marqueur
|
||||
mécanique posé quand un fichier a été joint (voir
|
||||
`routes/document/document_element_upload_attachment.py`), jamais
|
||||
l'URL de téléchargement elle-même (ce renderer ne connaît pas le slug
|
||||
du support ; `static/document/js/document-editor.js` l'assemble à
|
||||
partir de `data-element-id` + `FORGE_DOCUMENT.slug`, même principe que
|
||||
le reste des appels AJAX de l'éditeur).
|
||||
le reste des appels AJAX de l'éditeur). Style inline (audit du
|
||||
26/09/2026, réglages manquants — colonne "Bouton") : `bold` pousse
|
||||
`font-weight` à `800` (jamais en dessous du `700` déjà posé par le CSS
|
||||
de base — "gras" ne fait que renforcer, jamais affaiblir, aucune
|
||||
régression visuelle sur les boutons déjà créés), `italic`/
|
||||
`text_transform` (`"uppercase"`/`"lowercase"`/`"capitalize"`, jamais
|
||||
`"none"`)/`font_family`/`font_size`/`letter_spacing`/`text_color`
|
||||
(vides par défaut) + les attributs de boîte partagés
|
||||
(`render_box_style`, voir `box_style.py`). `svg_markup` (optionnel,
|
||||
nettoyé par `sanitize_svg_markup`) ajoute un `<span
|
||||
class="docButtonIcon">` avant OU après `.docButtonLabel` selon
|
||||
`icon_position` (`"before"` par défaut), dimensionné par `icon_size`
|
||||
(vide = `1em`, suit la taille du texte). États interactifs
|
||||
survol/actif : effet CSS universel (`filter`/`transform`, voir
|
||||
`static/document/document-editor.css`), jamais configurable par
|
||||
attribut — pas de notion d'état "désactivé" pour un bouton de contenu
|
||||
(ce n'est pas un vrai contrôle de formulaire).
|
||||
- **Étiquette** (`badge`) : `<div>` portant `attributes["content"]`
|
||||
échappé, précédé d'un `<span class="docBadgeIcon">` optionnel si
|
||||
`svg_markup` est non vide (nettoyé par `sanitize_svg_markup`, même
|
||||
|
||||
Reference in New Issue
Block a user