Ajoute icône/largeur/arrondi/gras/majuscules à l'étiquette (badge)
Nouveaux attributs par élément (svg_markup/width/border_radius/bold/ uppercase, tous vides ou False par défaut = comportement historique inchangé), réglables depuis le panneau Propriétés — même esprit que bold/align/color déjà présents sur titre/paragraphe. Fixer une largeur implique toujours de sortir de l'étirement pleine largeur par défaut (align-self:flex-start posé automatiquement avec elle). Le kicker "Module obligatoire" du thème Sécurité Incendie s'en sert maintenant (icône flamme, largeur au contenu, arrondi complet, gras, majuscules) pour être conforme à la maquette d'origine — la puce décorative CSS générique qui la remplaçait disparaît du thème. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
1296edc2f8
commit
e03bea39c5
@@ -81,7 +81,20 @@ def element_default_attributes(kind: str) -> dict[str, Any]:
|
||||
# attribut "ordered" redondant à tenir synchronisé avec le kind.
|
||||
return {"items": ["Premier élément", "Deuxième élément"]}
|
||||
if kind == "badge":
|
||||
return {"content": "Étiquette"}
|
||||
# Même esprit que titre/paragraphe (bold/align/color... déjà des
|
||||
# attributs par élément, pas des choix figés par le moteur) :
|
||||
# svg_markup/width/border_radius/bold/uppercase vides ou False par
|
||||
# défaut = comportement historique inchangé (pleine largeur, sans
|
||||
# icône, casse normale) ; un thème ou le créateur les règle au cas
|
||||
# par cas (retour utilisateur du 24/09/2026).
|
||||
return {
|
||||
"content": "Étiquette",
|
||||
"svg_markup": "",
|
||||
"width": "",
|
||||
"border_radius": "",
|
||||
"bold": False,
|
||||
"uppercase": False,
|
||||
}
|
||||
if kind == "carte":
|
||||
# Contenu pur (lettre/repère court + titre + description) — sans
|
||||
# aucun choix de couleur/forme, laissé au futur système de
|
||||
|
||||
@@ -11,12 +11,18 @@ top-niveau ou enfants d'une rangée. `"liste_puces"`/`"liste_numerotee"`
|
||||
partagent la même structure d'attributs (`items`) ; c'est le `kind`
|
||||
lui-même qui décide `<ul>` ou `<ol>` au rendu (voir
|
||||
`document_engine/rendering/render_document_element.py::_render_list`),
|
||||
jamais un attribut `ordered` redondant. `"badge"` et `"carte"` sont du
|
||||
contenu PUR, sans aucun attribut de style/couleur/forme (décision du
|
||||
24/09/2026 : le moteur ne porte que contenu et mécanisme, tout habillage
|
||||
visuel revient à un futur système de templates) — voir aussi le mode SVG
|
||||
inline de `"image"` (`svg_markup`) et la pièce jointe téléchargeable de
|
||||
`"bouton"` (`attachment_filename`), ci-dessous.
|
||||
jamais un attribut `ordered` redondant. `"carte"` reste du contenu PUR,
|
||||
sans aucun attribut de style/couleur/forme (décision du 24/09/2026 : le
|
||||
moteur ne porte que contenu et mécanisme, tout habillage visuel revient
|
||||
à un futur système de templates). `"badge"` a depuis gagné des
|
||||
attributs de mise en forme PAR ÉLÉMENT (`svg_markup`/`width`/
|
||||
`border_radius`/`bold`/`uppercase`, retour utilisateur du 24/09/2026)
|
||||
— même esprit que `bold`/`align`/`color` déjà présents sur
|
||||
`"titre"`/`"paragraphe"` : des réglages posés par le créateur ou un
|
||||
thème au cas par cas, jamais une valeur figée dans le moteur. Voir
|
||||
aussi le mode SVG inline de `"image"` (`svg_markup`) et la pièce
|
||||
jointe téléchargeable de `"bouton"` (`attachment_filename`),
|
||||
ci-dessous.
|
||||
|
||||
## `MINIGAME_KINDS: tuple[str, ...]`
|
||||
`("quiz", "association", "memory", "mots", "scenario", "zones")` —
|
||||
@@ -47,8 +53,11 @@ Attributs posés à la création d'un élément de ce type (voir
|
||||
rendu, voir rendering.md), bouton (`label/target/
|
||||
attachment_stored_name/attachment_filename` — la pièce jointe est
|
||||
indépendante de `target`, réservé à la navigation), liste à
|
||||
puces/numérotée (`items`, une liste de chaînes), badge (`content`),
|
||||
carte (`label/title/description`, contenu pur sans couleur/forme),
|
||||
puces/numérotée (`items`, une liste de chaînes), badge
|
||||
(`content/svg_markup/width/border_radius/bold/uppercase` — tous vides
|
||||
ou `False` par défaut = comportement historique inchangé, voir
|
||||
rendering.md), carte (`label/title/description`, contenu pur sans
|
||||
couleur/forme),
|
||||
rangée (`gap/align/justify`), quiz (`DEFAULT_QUIZ_CONFIG`, voir
|
||||
`quiz_config.py`), association (`DEFAULT_ASSOCIATION_CONFIG`, voir
|
||||
`association_config.py`), memory (`DEFAULT_MEMORY_CONFIG`, voir
|
||||
|
||||
@@ -3,6 +3,8 @@ import json
|
||||
import random
|
||||
from typing import Any
|
||||
|
||||
from .sanitize_svg_markup import sanitize_svg_markup
|
||||
|
||||
|
||||
def render_document(elements: list[dict[str, Any]]) -> str:
|
||||
"""Assemble le document ENTIER à partir de la liste à plat renvoyée
|
||||
@@ -79,8 +81,6 @@ def _render_image(el: dict[str, Any], _children_by_parent: dict[int | None, list
|
||||
# element_kind_labels.element_default_attributes). Nettoyé à
|
||||
# CHAQUE rendu (jamais seulement à l'écriture) par sanitize_svg_markup,
|
||||
# même défense en profondeur que html.escape sur les autres kinds.
|
||||
from .sanitize_svg_markup import sanitize_svg_markup
|
||||
|
||||
sanitized = sanitize_svg_markup(svg_markup)
|
||||
return f'<div class="docImage" data-element-id="{el["id"]}" data-kind="image">{sanitized}</div>'
|
||||
src = html_lib.escape(str(a.get("src", "")))
|
||||
@@ -128,8 +128,31 @@ def _render_button(el: dict[str, Any], _children_by_parent: dict[int | None, lis
|
||||
|
||||
|
||||
def _render_badge(el: dict[str, Any], _children_by_parent: dict[int | None, list[dict[str, Any]]]) -> str:
|
||||
content = html_lib.escape(str(el["attributes"].get("content", "")))
|
||||
return f'<div class="docBadge" data-element-id="{el["id"]}" data-kind="badge">{content}</div>'
|
||||
a = el["attributes"]
|
||||
content = html_lib.escape(str(a.get("content", "")))
|
||||
svg_markup = str(a.get("svg_markup", "")).strip()
|
||||
icon_html = f'<span class="docBadgeIcon">{sanitize_svg_markup(svg_markup)}</span>' if svg_markup else ""
|
||||
|
||||
style_parts = []
|
||||
width = str(a.get("width", "")).strip()
|
||||
if width:
|
||||
# Fixer une largeur implique de ne plus s'étirer sur toute la
|
||||
# largeur de .docPageContent (comportement par défaut d'un enfant
|
||||
# flex en colonne, voir static/document/document-editor.css) —
|
||||
# les deux vont toujours ensemble, jamais l'un sans l'autre.
|
||||
style_parts.append(f"align-self:flex-start; width:{html_lib.escape(width)};")
|
||||
border_radius = str(a.get("border_radius", "")).strip()
|
||||
if border_radius:
|
||||
style_parts.append(f"border-radius:{html_lib.escape(border_radius)};")
|
||||
if a.get("bold"):
|
||||
style_parts.append("font-weight:800;")
|
||||
if a.get("uppercase"):
|
||||
style_parts.append("text-transform:uppercase;")
|
||||
style_attr = f' style="{" ".join(style_parts)}"' if style_parts else ""
|
||||
|
||||
return (
|
||||
f'<div class="docBadge" data-element-id="{el["id"]}" data-kind="badge"{style_attr}>{icon_html}{content}</div>'
|
||||
)
|
||||
|
||||
|
||||
def _render_carte(el: dict[str, Any], _children_by_parent: dict[int | None, list[dict[str, Any]]]) -> str:
|
||||
|
||||
@@ -50,7 +50,18 @@ regroupement à chaque appel.
|
||||
partir de `data-element-id` + `FORGE_DOCUMENT.slug`, même principe que
|
||||
le reste des appels AJAX de l'éditeur).
|
||||
- **Étiquette** (`badge`) : `<div>` portant `attributes["content"]`
|
||||
échappé — contenu pur, aucun attribut de style.
|
||||
échappé, précédé d'un `<span class="docBadgeIcon">` optionnel si
|
||||
`svg_markup` est non vide (nettoyé par `sanitize_svg_markup`, même
|
||||
mécanisme que le mode SVG de `"image"`). `width` (non vide) ajoute
|
||||
`align-self:flex-start; width:{valeur};` en style inline — fixer une
|
||||
largeur implique TOUJOURS de sortir de l'étirement pleine largeur par
|
||||
défaut d'un enfant flex en colonne (voir static/document/
|
||||
document-editor.css, `.docPageContent`), jamais l'un sans l'autre.
|
||||
`border_radius` (non vide) ajoute `border-radius:{valeur};`. `bold`/
|
||||
`uppercase` ajoutent respectivement `font-weight:800;`/
|
||||
`text-transform:uppercase;` quand `True`. Tous ces attributs sont vides
|
||||
ou `False` par défaut (comportement historique inchangé, aucun style
|
||||
inline ajouté).
|
||||
- **Carte** (`carte`) : `<div>` composé de trois blocs enfants
|
||||
(`label`/`title`/`description`, tous échappés) — contenu pur, aucune
|
||||
couleur/forme choisie ici (voir `element_kind_labels.md`).
|
||||
|
||||
@@ -14,7 +14,21 @@ SECURITE_INCENDIE_SEED_PAGES: list[dict[str, Any]] = [
|
||||
{
|
||||
"vertical_align": "center",
|
||||
"blocks": [
|
||||
{"kind": "badge", "attributes": {"content": "Module obligatoire"}},
|
||||
{
|
||||
"kind": "badge",
|
||||
"attributes": {
|
||||
"content": "Module obligatoire",
|
||||
"svg_markup": (
|
||||
'<svg viewBox="0 0 24 24" fill="currentColor">'
|
||||
'<path d="M12 2C9 6 6 9 6 13a6 6 0 0 0 12 0c0-2-1-3.5-2-5 '
|
||||
'.3 2-.7 3-1.5 2.3C15.5 9 15 6 12 2z"/></svg>'
|
||||
),
|
||||
"width": "fit-content",
|
||||
"border_radius": "999px",
|
||||
"bold": True,
|
||||
"uppercase": True,
|
||||
},
|
||||
},
|
||||
{"kind": "titre", "attributes": {"content": "Formation Sécurité Incendie", "style": "titre1"}},
|
||||
{
|
||||
"kind": "paragraphe",
|
||||
|
||||
Reference in New Issue
Block a user