Audit complet de mise en forme — Titre/Paragraphe (1er élément du tableau)
Nouveau module partagé document_engine/rendering/box_style.py (padding/margin/background_color/border_radius/border par côté/height/ min-height/max-height/min-width/box-shadow/opacity/align_self) — réutilisable tel quel par tous les kinds suivants du tableau d'audit. Titre/Paragraphe gagnent : barré, police de caractère, taille de police, hauteur de ligne, espacement des lettres, majuscules/ minuscules/capitales, ombre du texte, et tous les attributs de boîte partagés ci-dessus. Interface entièrement à base de curseurs/cases à cocher/listes déroulantes/sélecteurs de couleur natifs — plus aucun champ de texte libre pour une valeur CSS (retour utilisateur). Deux bugs transversaux corrigés au passage (concernent tout l'éditeur) : - Le panneau Propriétés n'était jamais reconstruit après un clic sur un bouton (gras/alignement/segments...) — il fallait recharger la page pour voir l'état réel. Corrigé dans forgeDocUpdateAttributes, point d'entrée unique de toute mise à jour d'attribut. - Les cases à cocher et curseurs héritaient à tort le style d'un champ de texte (padding/bordure/fond/largeur 100%) via la règle générique .docField input. Ajoute docs/plan/AUDIT_MISE_EN_FORME.md : suivi de l'audit élément par élément (Titre/Paragraphe traité, Image ensuite). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
e03bea39c5
commit
6c7675fad0
@@ -3,6 +3,7 @@ import json
|
||||
import random
|
||||
from typing import Any
|
||||
|
||||
from .box_style import render_box_style
|
||||
from .sanitize_svg_markup import sanitize_svg_markup
|
||||
|
||||
|
||||
@@ -51,16 +52,48 @@ def _render_text(el: dict[str, Any], _children_by_parent: dict[int | None, list[
|
||||
a = el["attributes"]
|
||||
content = html_lib.escape(str(a.get("content", "")))
|
||||
style_name = a.get("style", "paragraphe")
|
||||
font_size, base_weight, line_height = _STYLE_PRESETS.get(style_name, _STYLE_PRESETS["paragraphe"])
|
||||
preset_font_size, base_weight, preset_line_height = _STYLE_PRESETS.get(style_name, _STYLE_PRESETS["paragraphe"])
|
||||
weight = 800 if a.get("bold") else base_weight
|
||||
font_style = "italic" if a.get("italic") else "normal"
|
||||
text_decoration = "underline" if a.get("underline") else "none"
|
||||
|
||||
# underline/strikethrough se combinent (text-decoration-line accepte
|
||||
# plusieurs valeurs) — retour utilisateur du 26/09/2026 : "barré"
|
||||
# manquait à côté du souligné déjà existant.
|
||||
decoration_parts = []
|
||||
if a.get("underline"):
|
||||
decoration_parts.append("underline")
|
||||
if a.get("strikethrough"):
|
||||
decoration_parts.append("line-through")
|
||||
text_decoration = " ".join(decoration_parts) if decoration_parts else "none"
|
||||
|
||||
align = html_lib.escape(str(a.get("align", "left")))
|
||||
color = html_lib.escape(str(a.get("color", "var(--forge-text)")))
|
||||
|
||||
# font_size/line_height : vides par défaut = valeurs du préréglage
|
||||
# `style` (titre1/titre2/paragraphe/légende) inchangées ; une valeur
|
||||
# explicite les remplace SANS changer `weight` (qui reste piloté par
|
||||
# le préréglage + `bold`).
|
||||
font_size = html_lib.escape(str(a.get("font_size", "")).strip()) or preset_font_size
|
||||
line_height = html_lib.escape(str(a.get("line_height", "")).strip()) or str(preset_line_height)
|
||||
|
||||
style = (
|
||||
f"font-size:{font_size}; font-weight:{weight}; line-height:{line_height}; "
|
||||
f"font-style:{font_style}; text-decoration:{text_decoration}; text-align:{align}; color:{color};"
|
||||
)
|
||||
|
||||
text_transform = str(a.get("text_transform", "none"))
|
||||
if text_transform and text_transform != "none":
|
||||
style += f" text-transform:{html_lib.escape(text_transform)};"
|
||||
font_family = str(a.get("font_family", "")).strip()
|
||||
if font_family:
|
||||
style += f" font-family:{html_lib.escape(font_family)};"
|
||||
letter_spacing = str(a.get("letter_spacing", "")).strip()
|
||||
if letter_spacing:
|
||||
style += f" letter-spacing:{html_lib.escape(letter_spacing)};"
|
||||
text_shadow = str(a.get("text_shadow", "")).strip()
|
||||
if text_shadow:
|
||||
style += f" text-shadow:{html_lib.escape(text_shadow)};"
|
||||
|
||||
# max_width optionnel (ex. "60ch", "480px") — vide par défaut (pleine
|
||||
# largeur de .docPageContent, comportement inchangé). Retour
|
||||
# utilisateur du 24/09/2026 : un paragraphe doit pouvoir rester plus
|
||||
@@ -69,6 +102,11 @@ def _render_text(el: dict[str, Any], _children_by_parent: dict[int | None, list[
|
||||
max_width = str(a.get("max_width", "")).strip()
|
||||
if max_width:
|
||||
style += f" max-width:{html_lib.escape(max_width)};"
|
||||
|
||||
box_style = render_box_style(a)
|
||||
if box_style:
|
||||
style += f" {box_style}"
|
||||
|
||||
return f'<div class="docText" data-element-id="{el["id"]}" data-kind="{el["kind"]}" style="{style}">{content}</div>'
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user