feat: vignettes wireframe SVG des 31 layouts dans la galerie + favicon
This commit is contained in:
@@ -6,6 +6,7 @@ depuis layouts_v2.yaml. Relancer après tout ajout de layout.
|
||||
Usage : python3 build_gallery.py → produit index.html
|
||||
"""
|
||||
import yaml
|
||||
import wireframes
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
|
||||
@@ -35,6 +36,7 @@ def card(name, cfg):
|
||||
hint = " ".join(cfg.get("agent_hint", "").split())
|
||||
champs = ", ".join(cfg.get("champs", []))
|
||||
requis = ", ".join(cfg.get("champs_requis", []))
|
||||
thumb = wireframes.svg_for(name, mode)
|
||||
mode_badge = {
|
||||
"light": ("Clair", "#f4f1ec", NAVY),
|
||||
"dark": ("Sombre", NAVY, "#ffffff"),
|
||||
@@ -46,6 +48,7 @@ def card(name, cfg):
|
||||
<span class="lcode">{lid}</span>
|
||||
<span class="lmode" style="background:{mode_badge[1]};color:{mode_badge[2]}">{mode_badge[0]}</span>
|
||||
</div>
|
||||
<div class="wf-thumb">{thumb}</div>
|
||||
<h3>{name}</h3>
|
||||
<p class="hint">{hint}</p>
|
||||
<div class="fields">
|
||||
@@ -82,6 +85,7 @@ html = f"""<!DOCTYPE html>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<title>Sliding Design System v2 — Pernod Ricard</title>
|
||||
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Cambria&family=Inter:wght@300;400;500;600&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
@@ -113,6 +117,8 @@ h1{{font-family:Cambria,serif;font-size:60px;font-weight:700;line-height:1.05;le
|
||||
.lg{{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:24px}}
|
||||
.lc{{background:#fff;border:1px solid var(--bo);border-radius:10px;padding:24px;transition:all .25s;display:flex;flex-direction:column;box-shadow:0 1px 3px rgba(6,16,51,.04)}}
|
||||
.lc:hover{{transform:translateY(-3px);box-shadow:0 12px 36px rgba(6,16,51,.10);border-color:var(--coral)}}
|
||||
.wf-thumb{{margin:0 0 14px;border:1px solid #ECE9E2;border-radius:8px;overflow:hidden;background:#fff}}
|
||||
.wf-thumb svg{{display:block;width:100%;height:auto}}
|
||||
.lc-head{{display:flex;justify-content:space-between;align-items:center;margin-bottom:14px}}
|
||||
.lcode{{background:var(--navy);color:#fff;font-size:10px;font-weight:600;padding:3px 9px;border-radius:4px;letter-spacing:.1em;font-family:monospace}}
|
||||
.lmode{{font-size:10px;font-weight:600;padding:3px 10px;border-radius:20px;letter-spacing:.05em}}
|
||||
|
||||
+35
-1
@@ -4,6 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<title>Sliding Design System v2 — Pernod Ricard</title>
|
||||
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Cambria&family=Inter:wght@300;400;500;600&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
@@ -35,6 +36,8 @@ h1{font-family:Cambria,serif;font-size:60px;font-weight:700;line-height:1.05;let
|
||||
.lg{display:grid;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));gap:24px}
|
||||
.lc{background:#fff;border:1px solid var(--bo);border-radius:10px;padding:24px;transition:all .25s;display:flex;flex-direction:column;box-shadow:0 1px 3px rgba(6,16,51,.04)}
|
||||
.lc:hover{transform:translateY(-3px);box-shadow:0 12px 36px rgba(6,16,51,.10);border-color:var(--coral)}
|
||||
.wf-thumb{margin:0 0 14px;border:1px solid #ECE9E2;border-radius:8px;overflow:hidden;background:#fff}
|
||||
.wf-thumb svg{display:block;width:100%;height:auto}
|
||||
.lc-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:14px}
|
||||
.lcode{background:var(--navy);color:#fff;font-size:10px;font-weight:600;padding:3px 9px;border-radius:4px;letter-spacing:.1em;font-family:monospace}
|
||||
.lmode{font-size:10px;font-weight:600;padding:3px 10px;border-radius:20px;letter-spacing:.05em}
|
||||
@@ -79,6 +82,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
|
||||
<span class="lcode">L01</span>
|
||||
<span class="lmode" style="background:#061033;color:#ffffff">Sombre</span>
|
||||
</div>
|
||||
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#061033" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><circle cx="300" cy="20" r="46" fill="#10204D" opacity="1.0"/><circle cx="288" cy="150" r="30" fill="#F4795B" opacity="0.9"/><circle cx="250" cy="150" r="14" fill="#8FA9D0" opacity="1.0"/><rect x="20" y="74" width="40" height="4" rx="1" fill="#F4795B" opacity="1.0"/><rect x="20" y="88" width="150" height="16" rx="2" fill="#FFFFFF" opacity="1.0"/><rect x="20" y="120" width="96" height="8" rx="2" fill="#8FA9D0" opacity="1.0"/></svg></div>
|
||||
<h3>cover_split</h3>
|
||||
<p class="hint">Slide de couverture. titre = titre de la présentation, sous_titre = tagline en une phrase.</p>
|
||||
<div class="fields">
|
||||
@@ -100,6 +104,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
|
||||
<span class="lcode">L05</span>
|
||||
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||
</div>
|
||||
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="160" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="20" y="54" width="96" height="108" rx="6" fill="#F4F1EC" opacity="1.0"/><circle cx="36" cy="74" r="9" fill="#061033" opacity="1.0"/><rect x="32" y="96" width="72" height="7" rx="3" fill="#46505A" opacity="1.0"/><rect x="32" y="112" width="72" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="32" y="124" width="72" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="32" y="136" width="72" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="112" y="54" width="96" height="108" rx="6" fill="#F4F1EC" opacity="1.0"/><circle cx="128" cy="74" r="9" fill="#061033" opacity="1.0"/><rect x="124" y="96" width="72" height="7" rx="3" fill="#46505A" opacity="1.0"/><rect x="124" y="112" width="72" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="124" y="124" width="72" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="124" y="136" width="72" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="204" y="54" width="96" height="108" rx="6" fill="#F4F1EC" opacity="1.0"/><circle cx="220" cy="74" r="9" fill="#061033" opacity="1.0"/><rect x="216" y="96" width="72" height="7" rx="3" fill="#46505A" opacity="1.0"/><rect x="216" y="112" width="72" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="216" y="124" width="72" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="216" y="136" width="72" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="20" y="54" width="96" height="4" rx="2" fill="#F4795B" opacity="1.0"/></svg></div>
|
||||
<h3>executive_summary</h3>
|
||||
<p class="hint">Synthèse SCR. Titre = So What. 3 cartes pleine largeur : situation, complication, resolution (1-2 phrases chacune).</p>
|
||||
<div class="fields">
|
||||
@@ -121,6 +126,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
|
||||
<span class="lcode">L03</span>
|
||||
<span class="lmode" style="background:#061033;color:#ffffff">Sombre</span>
|
||||
</div>
|
||||
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#061033" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><circle cx="300" cy="150" r="40" fill="#10204D" opacity="1.0"/><rect x="20" y="78" width="20" height="20" rx="2" fill="#F4795B" opacity="1.0"/><rect x="20" y="104" width="130" height="14" rx="2" fill="#FFFFFF" opacity="1.0"/></svg></div>
|
||||
<h3>section_divider</h3>
|
||||
<p class="hint">Transition de section. titre = nom de la section. Le numéro est incrémenté automatiquement par le moteur.</p>
|
||||
<div class="fields">
|
||||
@@ -134,6 +140,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
|
||||
<span class="lcode">L40</span>
|
||||
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||
</div>
|
||||
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="140" height="12" rx="2" fill="#061033" opacity="1.0"/><circle cx="32" cy="52" r="10" fill="#061033" opacity="1.0"/><rect x="50" y="47" width="180" height="9" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="230" y="47" width="60" height="9" rx="3" fill="#C9CDD3" opacity="0.6"/><circle cx="32" cy="84" r="10" fill="#F4795B" opacity="1.0"/><rect x="50" y="79" width="180" height="9" rx="3" fill="#061033" opacity="1.0"/><rect x="230" y="79" width="60" height="9" rx="3" fill="#C9CDD3" opacity="0.6"/><circle cx="32" cy="116" r="10" fill="#061033" opacity="1.0"/><rect x="50" y="111" width="180" height="9" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="230" y="111" width="60" height="9" rx="3" fill="#C9CDD3" opacity="0.6"/><circle cx="32" cy="148" r="10" fill="#061033" opacity="1.0"/><rect x="50" y="143" width="180" height="9" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="230" y="143" width="60" height="9" rx="3" fill="#C9CDD3" opacity="0.6"/></svg></div>
|
||||
<h3>agenda</h3>
|
||||
<p class="hint">Sommaire du deck : à placer en slide 2 pour toute présentation de plus de 15 minutes. sections = liste de {label, numero?, duree?, actif?}, 2 à 8 entrées. actif: true met la section en corail (utile pour les rappels d'agenda en cours de deck). duree (ex "10 min") s'affiche à droite en discret.</p>
|
||||
<div class="fields">
|
||||
@@ -155,6 +162,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
|
||||
<span class="lcode">L10</span>
|
||||
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||
</div>
|
||||
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="120" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="90" y="66" width="140" height="40" rx="4" fill="#F4795B" opacity="1.0"/><rect x="110" y="116" width="100" height="8" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="134" y="132" width="52" height="5" rx="2" fill="#C9CDD3" opacity="0.6"/></svg></div>
|
||||
<h3>big_stat</h3>
|
||||
<p class="hint">Un chiffre héro plein écran. valeur = le chiffre (ex "78%"), description = ce qu'il signifie, source = référence.</p>
|
||||
<div class="fields">
|
||||
@@ -168,6 +176,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
|
||||
<span class="lcode">L09</span>
|
||||
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||
</div>
|
||||
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="120" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="20" y="56" width="96" height="100" rx="6" fill="#F4F1EC" opacity="1.0"/><rect x="32" y="74" width="50" height="22" rx="3" fill="#F4795B" opacity="1.0"/><rect x="32" y="104" width="70" height="6" rx="3" fill="#46505A" opacity="1.0"/><rect x="32" y="118" width="56" height="6" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="112" y="56" width="96" height="100" rx="6" fill="#F4F1EC" opacity="1.0"/><rect x="124" y="74" width="50" height="22" rx="3" fill="#061033" opacity="1.0"/><rect x="124" y="104" width="70" height="6" rx="3" fill="#46505A" opacity="1.0"/><rect x="124" y="118" width="56" height="6" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="204" y="56" width="96" height="100" rx="6" fill="#F4F1EC" opacity="1.0"/><rect x="216" y="74" width="50" height="22" rx="3" fill="#061033" opacity="1.0"/><rect x="216" y="104" width="70" height="6" rx="3" fill="#46505A" opacity="1.0"/><rect x="216" y="118" width="56" height="6" rx="3" fill="#C9CDD3" opacity="1.0"/></svg></div>
|
||||
<h3>kpi_grid</h3>
|
||||
<p class="hint">2 à 6 cartes KPI. items = [{label, valeur, description}]. valeur en grand corail, label en en-tête, description en source.</p>
|
||||
<div class="fields">
|
||||
@@ -181,6 +190,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
|
||||
<span class="lcode">L42</span>
|
||||
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||
</div>
|
||||
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="120" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="40" y="110" width="32" height="40" rx="2" fill="#061033" opacity="1.0"/><rect x="92" y="80" width="32" height="70" rx="2" fill="#061033" opacity="1.0"/><rect x="144" y="95" width="32" height="55" rx="2" fill="#061033" opacity="1.0"/><rect x="196" y="60" width="32" height="90" rx="2" fill="#061033" opacity="1.0"/><rect x="248" y="88" width="32" height="62" rx="2" fill="#061033" opacity="1.0"/><rect x="30" y="150" width="270" height="2" rx="0" fill="#46505A" opacity="1.0"/></svg></div>
|
||||
<h3>bar_chart</h3>
|
||||
<p class="hint">Comparaison de valeurs par catégories — graphique NATIF éditable. Max 8 catégories × 3 séries. series = liste de {label, values} ; values = nombres SANS guillemets, alignés sur categories. horizontal: true pour des barres (libellés longs). unite (ex M€) et source optionnels. Couleurs imposées : navy, coral, glacier.</p>
|
||||
<div class="fields">
|
||||
@@ -194,6 +204,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
|
||||
<span class="lcode">L43</span>
|
||||
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||
</div>
|
||||
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="120" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="30" y="150" width="270" height="2" rx="0" fill="#46505A" opacity="1.0"/><polyline points="40,130 100,96 160,110 220,70 288,84" fill="none" stroke="#061033" stroke-width="2.5"/><circle cx="288" cy="84" r="5" fill="#F4795B" opacity="1.0"/></svg></div>
|
||||
<h3>line_chart</h3>
|
||||
<p class="hint">Évolution temporelle — graphique NATIF éditable. Max 12 points × 3 séries. points_x = libellés d'axe (mois, années...) ; series = {label, values}, nombres sans guillemets. Le dernier point de la première série est automatiquement mis en valeur (corail).</p>
|
||||
<div class="fields">
|
||||
@@ -207,6 +218,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
|
||||
<span class="lcode">L44</span>
|
||||
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||
</div>
|
||||
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="110" height="12" rx="2" fill="#061033" opacity="1.0"/><circle cx="100" cy="106" r="40" fill="none" stroke="#061033" stroke-width="18"/><path d="M100 66 A40 40 0 0 1 138 118" fill="none" stroke="#F4795B" stroke-width="18"/><circle cx="210" cy="84" r="6" fill="#061033" opacity="1.0"/><rect x="224" y="80" width="76" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><circle cx="210" cy="108" r="6" fill="#F4795B" opacity="1.0"/><rect x="224" y="104" width="76" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><circle cx="210" cy="132" r="6" fill="#8FA9D0" opacity="1.0"/><rect x="224" y="128" width="76" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/></svg></div>
|
||||
<h3>donut_split</h3>
|
||||
<p class="hint">Répartition d'un tout : anneau à gauche + légende détaillée à droite. 2 à 6 segments = {label, valeur} (nombres sans guillemets). valeur_centrale (optionnelle) s'affiche au centre de l'anneau (ex : total « 120 M€ »). Couleurs = cycle PR imposé.</p>
|
||||
<div class="fields">
|
||||
@@ -220,6 +232,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
|
||||
<span class="lcode">L45</span>
|
||||
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||
</div>
|
||||
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="140" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="30" y="150" width="270" height="2" rx="0" fill="#46505A" opacity="1.0"/><rect x="40" y="80" width="34" height="70" rx="2" fill="#061033" opacity="1.0"/><rect x="94" y="80" width="34" height="34" rx="2" fill="#F4795B" opacity="1.0"/><rect x="148" y="60" width="34" height="40" rx="2" fill="#F4795B" opacity="1.0"/><rect x="202" y="44" width="34" height="30" rx="2" fill="#F4795B" opacity="1.0"/><rect x="256" y="60" width="34" height="90" rx="2" fill="#061033" opacity="1.0"/></svg></div>
|
||||
<h3>waterfall</h3>
|
||||
<p class="hint">Pont de valeur (waterfall) : expliquer un écart entre deux montants par des variations successives. depart et arrivee = {label, valeur} ; marches = liste de {label, delta} SIGNÉ (positif ou négatif, max 8). Le moteur calcule les cumuls — ne jamais fournir de cumul. Idéal pour : évolution de budget, pont d'effectifs, décomposition d'un résultat.</p>
|
||||
<div class="fields">
|
||||
@@ -241,6 +254,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
|
||||
<span class="lcode">L07</span>
|
||||
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||
</div>
|
||||
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="170" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="20" y="44" width="132" height="120" rx="6" fill="#F4F1EC" opacity="1.0"/><rect x="20" y="44" width="132" height="26" rx="6" fill="#061033" opacity="1.0"/><rect x="20" y="58" width="132" height="12" rx="0" fill="#061033" opacity="1.0"/><rect x="32" y="52" width="70" height="10" rx="3" fill="#FFFFFF" opacity="1.0"/><rect x="32" y="84" width="100" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="32" y="99" width="100" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="32" y="114" width="100" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="32" y="129" width="100" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="168" y="44" width="132" height="120" rx="6" fill="#F4F1EC" opacity="1.0"/><rect x="168" y="44" width="132" height="26" rx="6" fill="#F4795B" opacity="1.0"/><rect x="168" y="58" width="132" height="12" rx="0" fill="#F4795B" opacity="1.0"/><rect x="180" y="52" width="70" height="10" rx="3" fill="#FFFFFF" opacity="1.0"/><rect x="180" y="84" width="100" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="180" y="99" width="100" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="180" y="114" width="100" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="180" y="129" width="100" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/></svg></div>
|
||||
<h3>two_cols_text</h3>
|
||||
<p class="hint">Deux colonnes en cartes avec en-tête coloré. left/right = {titre, bullets[]}. Gauche = navy, droite = corail.</p>
|
||||
<div class="fields">
|
||||
@@ -254,6 +268,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
|
||||
<span class="lcode">L34</span>
|
||||
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||
</div>
|
||||
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="150" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="20" y="48" width="280" height="20" rx="4" fill="#061033" opacity="1.0"/><rect x="24" y="52" width="84" height="12" rx="2" fill="#FFFFFF" opacity="0.5"/><rect x="116" y="52" width="84" height="12" rx="2" fill="#FFFFFF" opacity="0.5"/><rect x="208" y="52" width="84" height="12" rx="2" fill="#FFFFFF" opacity="0.5"/><rect x="20" y="72" width="280" height="18" rx="2" fill="#FFFFFF" opacity="1.0" stroke="#E3E0D9" stroke-width="1"/><rect x="30" y="77" width="64" height="7" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="122" y="77" width="64" height="7" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="214" y="77" width="64" height="7" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="20" y="94" width="280" height="18" rx="2" fill="#F4F1EC" opacity="1.0" stroke="#E3E0D9" stroke-width="1"/><rect x="30" y="99" width="64" height="7" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="122" y="99" width="64" height="7" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="214" y="99" width="64" height="7" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="20" y="116" width="280" height="18" rx="2" fill="#FFFFFF" opacity="1.0" stroke="#E3E0D9" stroke-width="1"/><rect x="30" y="121" width="64" height="7" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="122" y="121" width="64" height="7" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="214" y="121" width="64" height="7" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="20" y="138" width="280" height="18" rx="2" fill="#F4F1EC" opacity="1.0" stroke="#E3E0D9" stroke-width="1"/><rect x="30" y="143" width="64" height="7" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="122" y="143" width="64" height="7" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="214" y="143" width="64" height="7" rx="2" fill="#C9CDD3" opacity="1.0"/></svg></div>
|
||||
<h3>comparison_table</h3>
|
||||
<p class="hint">Tableau structuré multi-critères. headers = liste de colonnes (1ère = critères). rows = [{label, values: []}] ou listes plates. Max 5 colonnes, 8 lignes.</p>
|
||||
<div class="fields">
|
||||
@@ -267,6 +282,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
|
||||
<span class="lcode">L46</span>
|
||||
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||
</div>
|
||||
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="120" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="60" y="54" width="42" height="22" rx="2" fill="#D6DCEA" opacity="1.0"/><rect x="106" y="54" width="42" height="22" rx="2" fill="#9FB0D0" opacity="1.0"/><rect x="152" y="54" width="42" height="22" rx="2" fill="#8FA9D0" opacity="1.0"/><rect x="198" y="54" width="42" height="22" rx="2" fill="#10204D" opacity="1.0"/><rect x="244" y="54" width="42" height="22" rx="2" fill="#061033" opacity="1.0"/><rect x="20" y="58" width="32" height="12" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="60" y="80" width="42" height="22" rx="2" fill="#9FB0D0" opacity="1.0"/><rect x="106" y="80" width="42" height="22" rx="2" fill="#8FA9D0" opacity="1.0"/><rect x="152" y="80" width="42" height="22" rx="2" fill="#10204D" opacity="1.0"/><rect x="198" y="80" width="42" height="22" rx="2" fill="#061033" opacity="1.0"/><rect x="244" y="80" width="42" height="22" rx="2" fill="#D6DCEA" opacity="1.0"/><rect x="20" y="84" width="32" height="12" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="60" y="106" width="42" height="22" rx="2" fill="#8FA9D0" opacity="1.0"/><rect x="106" y="106" width="42" height="22" rx="2" fill="#10204D" opacity="1.0"/><rect x="152" y="106" width="42" height="22" rx="2" fill="#061033" opacity="1.0"/><rect x="198" y="106" width="42" height="22" rx="2" fill="#D6DCEA" opacity="1.0"/><rect x="244" y="106" width="42" height="22" rx="2" fill="#9FB0D0" opacity="1.0"/><rect x="20" y="110" width="32" height="12" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="60" y="132" width="42" height="22" rx="2" fill="#10204D" opacity="1.0"/><rect x="106" y="132" width="42" height="22" rx="2" fill="#061033" opacity="1.0"/><rect x="152" y="132" width="42" height="22" rx="2" fill="#D6DCEA" opacity="1.0"/><rect x="198" y="132" width="42" height="22" rx="2" fill="#9FB0D0" opacity="1.0"/><rect x="244" y="132" width="42" height="22" rx="2" fill="#8FA9D0" opacity="1.0"/><rect x="20" y="136" width="32" height="12" rx="2" fill="#C9CDD3" opacity="1.0"/></svg></div>
|
||||
<h3>heatmap_table</h3>
|
||||
<p class="hint">Tableau à intensité : évaluer plusieurs items sur plusieurs critères. headers = colonnes (max 6) ; rows = {label, scores} avec score ENTIER de 0 (faible) à 4 (fort), max 8 lignes. Le moteur traduit chaque score en teinte de navy — aucune autre donnée. Idéal pour : maturité, couverture fonctionnelle, cartographie de risques.</p>
|
||||
<div class="fields">
|
||||
@@ -288,6 +304,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
|
||||
<span class="lcode">L08</span>
|
||||
<span class="lmode" style="background:#061033;color:#ffffff">Sombre</span>
|
||||
</div>
|
||||
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#061033" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="40" y="70" width="240" height="14" rx="2" fill="#FFFFFF" opacity="1.0"/><rect x="70" y="92" width="180" height="14" rx="2" fill="#8FA9D0" opacity="1.0"/><rect x="130" y="120" width="60" height="6" rx="2" fill="#F4795B" opacity="1.0"/></svg></div>
|
||||
<h3>key_message</h3>
|
||||
<p class="hint">Message clé en citation plein écran. message = la phrase forte, detail = sous-texte optionnel.</p>
|
||||
<div class="fields">
|
||||
@@ -309,6 +326,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
|
||||
<span class="lcode">L17</span>
|
||||
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||
</div>
|
||||
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="130" height="12" rx="2" fill="#061033" opacity="1.0"/><circle cx="144" cy="108" r="22" fill="#061033" opacity="1.0"/><circle cx="93" cy="137" r="22" fill="#46505A" opacity="1.0"/><circle cx="93" cy="79" r="22" fill="#8FA9D0" opacity="1.0"/><circle cx="110" cy="108" r="14" fill="#F4795B" opacity="1.0"/><circle cx="210" cy="70" r="6" fill="#061033" opacity="1.0"/><rect x="224" y="66" width="76" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><circle cx="210" cy="100" r="6" fill="#46505A" opacity="1.0"/><rect x="224" y="96" width="76" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><circle cx="210" cy="130" r="6" fill="#8FA9D0" opacity="1.0"/><rect x="224" y="126" width="76" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/></svg></div>
|
||||
<h3>circular_diagram</h3>
|
||||
<p class="hint">3 à 6 valeurs en cercles + légende à droite. segments = [{label, description, couleur?}].</p>
|
||||
<div class="fields">
|
||||
@@ -322,6 +340,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
|
||||
<span class="lcode">L41</span>
|
||||
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||
</div>
|
||||
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="110" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="115" y="132" width="90" height="20" rx="2" fill="#F4795B" opacity="1.0"/><rect x="85" y="108" width="150" height="20" rx="2" fill="#8FA9D0" opacity="1.0"/><rect x="55" y="84" width="210" height="20" rx="2" fill="#46505A" opacity="1.0"/><rect x="25" y="60" width="270" height="20" rx="2" fill="#061033" opacity="1.0"/></svg></div>
|
||||
<h3>pyramid</h3>
|
||||
<p class="hint">Argumentation pyramidale : la conclusion au sommet, les fondations à la base. niveaux = liste de {label, description?}, EXACTEMENT 3 ou 4 niveaux, du sommet vers la base. Largeurs d'étages fixes gérées par le moteur. Idéal pour : message clé et ses appuis, hiérarchie stratégie/tactiques/moyens.</p>
|
||||
<div class="fields">
|
||||
@@ -343,6 +362,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
|
||||
<span class="lcode">L06</span>
|
||||
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||
</div>
|
||||
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="150" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="20" y="66" width="8" height="8" rx="1" fill="#F4795B" opacity="1.0"/><rect x="38" y="66" width="250" height="8" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="20" y="94" width="8" height="8" rx="1" fill="#F4795B" opacity="1.0"/><rect x="38" y="94" width="250" height="8" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="20" y="122" width="8" height="8" rx="1" fill="#F4795B" opacity="1.0"/><rect x="38" y="122" width="250" height="8" rx="3" fill="#C9CDD3" opacity="1.0"/></svg></div>
|
||||
<h3>default_bullets</h3>
|
||||
<p class="hint">Liste de points clés. Si texte au format "Mot : explication", le moteur met le mot en gras navy. Max 5 bullets. bullets = [{niveau, texte}].</p>
|
||||
<div class="fields">
|
||||
@@ -364,6 +384,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
|
||||
<span class="lcode">L19</span>
|
||||
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||
</div>
|
||||
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="150" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="20" y="52" width="280" height="28" rx="6" fill="#F4F1EC" opacity="1.0"/><circle cx="38" cy="66" r="11" fill="#061033" opacity="1.0"/><rect x="60" y="62" width="200" height="8" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="20" y="86" width="280" height="28" rx="6" fill="#F4F1EC" opacity="1.0"/><circle cx="38" cy="100" r="11" fill="#061033" opacity="1.0"/><rect x="60" y="96" width="200" height="8" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="20" y="120" width="280" height="28" rx="6" fill="#F4F1EC" opacity="1.0"/><circle cx="38" cy="134" r="11" fill="#061033" opacity="1.0"/><rect x="60" y="130" width="200" height="8" rx="3" fill="#C9CDD3" opacity="1.0"/></svg></div>
|
||||
<h3>numbered_steps</h3>
|
||||
<p class="hint">Étapes en cartes pleine largeur avec badge rond numéroté. steps = [{numero, titre, description}].</p>
|
||||
<div class="fields">
|
||||
@@ -377,6 +398,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
|
||||
<span class="lcode">L36</span>
|
||||
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||
</div>
|
||||
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="140" height="12" rx="2" fill="#061033" opacity="1.0"/><polygon points="20,80 90,80 106,104 90,128 20,128 36,104" fill="#061033"/><polygon points="120,80 190,80 206,104 190,128 120,128 136,104" fill="#F4795B"/><polygon points="220,80 290,80 306,104 290,128 220,128 236,104" fill="#061033"/></svg></div>
|
||||
<h3>process_arrow</h3>
|
||||
<p class="hint">Flux horizontal de 3 à 6 étapes. steps = [{titre, description}]. Badges numérotés corail, couleurs cycle alternées. Max 6 étapes.</p>
|
||||
<div class="fields">
|
||||
@@ -390,6 +412,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
|
||||
<span class="lcode">L47</span>
|
||||
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||
</div>
|
||||
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="110" height="12" rx="2" fill="#061033" opacity="1.0"/><polygon points="40.0,58 280.0,58 266.0,80 54.0,80" fill="#061033"/><polygon points="70.0,84 250.0,84 236.0,106 84.0,106" fill="#10204D"/><polygon points="100.0,110 220.0,110 206.0,132 114.0,132" fill="#8FA9D0"/><polygon points="125.0,136 195.0,136 181.0,158 139.0,158" fill="#F4795B"/></svg></div>
|
||||
<h3>funnel</h3>
|
||||
<p class="hint">Entonnoir de conversion : volumes décroissants d'étape en étape. etapes = {label, valeur, description?} du haut vers le bas, 3 à 5 étages. Largeurs proportionnelles aux valeurs (plancher de lisibilité), dernier étage corail. Idéal pour : pipeline commercial, adoption, qualification progressive.</p>
|
||||
<div class="fields">
|
||||
@@ -411,6 +434,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
|
||||
<span class="lcode">L23</span>
|
||||
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||
</div>
|
||||
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="150" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="20" y="74" width="96" height="44" rx="6" fill="#061033" opacity="1.0"/><rect x="116" y="94" width="16" height="4" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="40" y="126" width="56" height="6" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="112" y="74" width="96" height="44" rx="6" fill="#46505A" opacity="1.0"/><rect x="208" y="94" width="16" height="4" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="132" y="126" width="56" height="6" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="204" y="74" width="96" height="44" rx="6" fill="#8FA9D0" opacity="1.0"/><rect x="224" y="126" width="56" height="6" rx="3" fill="#C9CDD3" opacity="1.0"/></svg></div>
|
||||
<h3>phases_timeline</h3>
|
||||
<p class="hint">Phases reliées par une ligne pointillée. phases = [{label, periode}]. Couleurs du cycle theme.</p>
|
||||
<div class="fields">
|
||||
@@ -424,6 +448,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
|
||||
<span class="lcode">L32</span>
|
||||
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||
</div>
|
||||
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="140" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="20" y="56" width="60" height="10" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="130" y="56" width="120" height="12" rx="3" fill="#061033" opacity="1.0"/><rect x="20" y="82" width="60" height="10" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="180" y="82" width="90" height="12" rx="3" fill="#46505A" opacity="1.0"/><rect x="20" y="108" width="60" height="10" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="240" y="108" width="100" height="12" rx="3" fill="#061033" opacity="1.0"/><rect x="20" y="134" width="60" height="10" rx="2" fill="#C9CDD3" opacity="1.0"/><rect x="160" y="134" width="130" height="12" rx="3" fill="#8FA9D0" opacity="1.0"/></svg></div>
|
||||
<h3>gantt_timeline</h3>
|
||||
<p class="hint">Gantt par workstreams. periods = liste de labels (ex ["Juin","Juil"]). workstreams = [{label, tasks: [{label, start, end}]}]. start/end = index dans periods (0-based). Max 3 workstreams, 4 tâches chacun.</p>
|
||||
<div class="fields">
|
||||
@@ -445,6 +470,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
|
||||
<span class="lcode">L28</span>
|
||||
<span class="lmode" style="background:#8FA9D0;color:#061033">Panel</span>
|
||||
</div>
|
||||
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="150" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="20" y="48" width="190" height="116" rx="6" fill="#F4F1EC" opacity="1.0"/><rect x="20" y="48" width="190" height="6" rx="3" fill="#F4795B" opacity="1.0"/><circle cx="40" cy="72" r="10" fill="#061033" opacity="1.0"/><rect x="60" y="66" width="130" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="60" y="82" width="130" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="60" y="98" width="130" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="60" y="114" width="130" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="228" y="48" width="72" height="116" rx="6" fill="#061033" opacity="1.0"/><rect x="240" y="70" width="48" height="8" rx="3" fill="#8FA9D0" opacity="1.0"/><rect x="240" y="92" width="48" height="7" rx="3" fill="#33436A" opacity="1.0"/><rect x="240" y="105" width="48" height="7" rx="3" fill="#33436A" opacity="1.0"/><rect x="240" y="118" width="48" height="7" rx="3" fill="#33436A" opacity="1.0"/></svg></div>
|
||||
<h3>recommendation_card</h3>
|
||||
<p class="hint">Carte de recommandation. Sidebar = numero + titre + cta. Corps = headline + bullets.</p>
|
||||
<div class="fields">
|
||||
@@ -466,6 +492,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
|
||||
<span class="lcode">L30</span>
|
||||
<span class="lmode" style="background:#061033;color:#ffffff">Sombre</span>
|
||||
</div>
|
||||
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#061033" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><circle cx="300" cy="24" r="40" fill="#F4795B" opacity="0.9"/><circle cx="30" cy="150" r="46" fill="#10204D" opacity="1.0"/><rect x="96" y="74" width="128" height="14" rx="2" fill="#FFFFFF" opacity="1.0"/><rect x="120" y="100" width="80" height="8" rx="2" fill="#8FA9D0" opacity="1.0"/></svg></div>
|
||||
<h3>end_slide</h3>
|
||||
<p class="hint">Slide de fin. message = phrase de conclusion.</p>
|
||||
<div class="fields">
|
||||
@@ -487,6 +514,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
|
||||
<span class="lcode">L31</span>
|
||||
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||
</div>
|
||||
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="150" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="20" y="50" width="120" height="100" rx="6" fill="#F4F1EC" opacity="1.0"/><rect x="20" y="50" width="120" height="6" rx="3" fill="#061033" opacity="1.0"/><rect x="32" y="70" width="90" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="32" y="86" width="90" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="32" y="102" width="90" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="32" y="118" width="90" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="176" y="50" width="120" height="100" rx="6" fill="#F4F1EC" opacity="1.0"/><rect x="176" y="50" width="120" height="6" rx="3" fill="#46505A" opacity="1.0"/><rect x="188" y="70" width="90" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="188" y="86" width="90" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="188" y="102" width="90" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="188" y="118" width="90" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><circle cx="160" cy="100" r="10" fill="#F4795B" opacity="1.0"/></svg></div>
|
||||
<h3>from_to_pairs</h3>
|
||||
<p class="hint">Transformation avant/après en paires alignées. pairs = [{from, to}]. label_from/label_to = en-têtes colonnes. Max 5 paires. Idéal pour tangibiliser un changement.</p>
|
||||
<div class="fields">
|
||||
@@ -508,6 +536,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
|
||||
<span class="lcode">L33</span>
|
||||
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||
</div>
|
||||
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="130" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="20" y="100" width="280" height="3" rx="0" fill="#061033" opacity="1.0"/><circle cx="40" cy="101" r="7" fill="#061033" opacity="1.0"/><rect x="20" y="116" width="40" height="6" rx="2" fill="#C9CDD3" opacity="1.0"/><circle cx="120" cy="101" r="7" fill="#F4795B" opacity="1.0"/><rect x="100" y="116" width="40" height="6" rx="2" fill="#C9CDD3" opacity="1.0"/><circle cx="200" cy="101" r="7" fill="#061033" opacity="1.0"/><rect x="180" y="116" width="40" height="6" rx="2" fill="#C9CDD3" opacity="1.0"/><circle cx="280" cy="101" r="7" fill="#061033" opacity="1.0"/><rect x="260" y="116" width="40" height="6" rx="2" fill="#C9CDD3" opacity="1.0"/></svg></div>
|
||||
<h3>yearly_timeline</h3>
|
||||
<p class="hint">Frise chronologique horizontale. milestones = [{annee, label, actif?}]. actif = true pour le jalon courant (corail). Labels alternent haut/bas. Max 6 jalons.</p>
|
||||
<div class="fields">
|
||||
@@ -529,6 +558,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
|
||||
<span class="lcode">L35</span>
|
||||
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||
</div>
|
||||
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="120" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="20" y="48" width="280" height="18" rx="4" fill="#061033" opacity="1.0"/><rect x="20" y="70" width="80" height="16" rx="2" fill="#F4F1EC" opacity="1.0"/><circle cx="130" cy="78" r="7" fill="#061033" opacity="0.85"/><circle cx="174" cy="78" r="7" fill="#F4795B" opacity="0.85"/><circle cx="218" cy="78" r="7" fill="#46505A" opacity="0.85"/><circle cx="262" cy="78" r="7" fill="#8FA9D0" opacity="0.85"/><rect x="20" y="92" width="80" height="16" rx="2" fill="#F4F1EC" opacity="1.0"/><circle cx="130" cy="100" r="7" fill="#061033" opacity="0.85"/><circle cx="174" cy="100" r="7" fill="#F4795B" opacity="0.85"/><circle cx="218" cy="100" r="7" fill="#46505A" opacity="0.85"/><circle cx="262" cy="100" r="7" fill="#8FA9D0" opacity="0.85"/><rect x="20" y="114" width="80" height="16" rx="2" fill="#F4F1EC" opacity="1.0"/><circle cx="130" cy="122" r="7" fill="#061033" opacity="0.85"/><circle cx="174" cy="122" r="7" fill="#F4795B" opacity="0.85"/><circle cx="218" cy="122" r="7" fill="#46505A" opacity="0.85"/><circle cx="262" cy="122" r="7" fill="#8FA9D0" opacity="0.85"/><rect x="20" y="136" width="80" height="16" rx="2" fill="#F4F1EC" opacity="1.0"/><circle cx="130" cy="144" r="7" fill="#061033" opacity="0.85"/><circle cx="174" cy="144" r="7" fill="#F4795B" opacity="0.85"/><circle cx="218" cy="144" r="7" fill="#46505A" opacity="0.85"/><circle cx="262" cy="144" r="7" fill="#8FA9D0" opacity="0.85"/></svg></div>
|
||||
<h3>raci_table</h3>
|
||||
<p class="hint">Matrice RACI. roles = liste de rôles. tasks = [{label, raci: [R/A/C/I]}]. R=Responsable(corail), A=Autorité(navy), C=Consulté(slate), I=Informé(muted). Max 4 rôles, 8 tâches.</p>
|
||||
<div class="fields">
|
||||
@@ -550,6 +580,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
|
||||
<span class="lcode">L37</span>
|
||||
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||
</div>
|
||||
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="120" height="12" rx="2" fill="#061033" opacity="1.0"/><rect x="130" y="52" width="60" height="26" rx="4" fill="#061033" opacity="1.0"/><rect x="60" y="120" width="56" height="26" rx="4" fill="#F4F1EC" opacity="1.0" stroke="#E3E0D9" stroke-width="1"/><line x1="160" y1="78" x2="88" y2="120" stroke="#061033" stroke-width="1.5"/><rect x="140" y="120" width="56" height="26" rx="4" fill="#F4F1EC" opacity="1.0" stroke="#E3E0D9" stroke-width="1"/><line x1="160" y1="78" x2="168" y2="120" stroke="#061033" stroke-width="1.5"/><rect x="220" y="120" width="56" height="26" rx="4" fill="#F4F1EC" opacity="1.0" stroke="#E3E0D9" stroke-width="1"/><line x1="160" y1="78" x2="248" y2="120" stroke="#061033" stroke-width="1.5"/></svg></div>
|
||||
<h3>org_chart</h3>
|
||||
<p class="hint">Organigramme hiérarchique max 3 niveaux. root = {label, children: [{label, children?: [{label}]}]}. Max 4 enfants directs, 3 petits-enfants par enfant.</p>
|
||||
<div class="fields">
|
||||
@@ -571,6 +602,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
|
||||
<span class="lcode">L38</span>
|
||||
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||
</div>
|
||||
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="16" width="120" height="12" rx="2" fill="#061033" opacity="1.0"/><line x1="160" y1="46" x2="160" y2="170" stroke="#46505A" stroke-width="1.5"/><line x1="24" y1="108" x2="296" y2="108" stroke="#46505A" stroke-width="1.5"/><circle cx="92" cy="78" r="16" fill="#061033" opacity="0.9"/><circle cx="228" cy="78" r="16" fill="#F4795B" opacity="0.9"/><circle cx="92" cy="140" r="16" fill="#46505A" opacity="0.9"/><circle cx="228" cy="140" r="16" fill="#8FA9D0" opacity="0.9"/></svg></div>
|
||||
<h3>matrix_2x2</h3>
|
||||
<p class="hint">Matrice effort/impact. axis_x/axis_y = {label, low, high}. quadrants = {top_left, top_right, bottom_left, bottom_right}. items = [{label, x, y}] avec x/y de 0 à 100. Max 8 items.</p>
|
||||
<div class="fields">
|
||||
@@ -592,6 +624,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
|
||||
<span class="lcode">L50</span>
|
||||
<span class="lmode" style="background:#f4f1ec;color:#061033">Clair</span>
|
||||
</div>
|
||||
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="20" y="44" width="130" height="120" rx="4" fill="#8FA9D0" opacity="0.5"/><line x1="20" y1="164" x2="150" y2="44" stroke="#8FA9D0" stroke-width="1.5"/><line x1="20" y1="44" x2="150" y2="164" stroke="#8FA9D0" stroke-width="1.5"/><rect x="168" y="44" width="130" height="14" rx="2" fill="#061033" opacity="1.0"/><circle cx="176" cy="78" r="3" fill="#F4795B" opacity="1.0"/><rect x="184" y="74" width="108" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="184" y="91" width="108" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="184" y="108" width="108" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/><rect x="184" y="125" width="108" height="7" rx="3" fill="#C9CDD3" opacity="1.0"/></svg></div>
|
||||
<h3>image_split</h3>
|
||||
<p class="hint">Image d'appui sur 40 % de la slide (side: left par défaut, right possible) + titre et points clés (max 4 bullets). À utiliser quand une image du dossier assets/ du projet illustre le propos ; image = nom de fichier exact tel que listé par /lire. legende (optionnelle) s'affiche sur un bandeau navy sous l'image.</p>
|
||||
<div class="fields">
|
||||
@@ -605,6 +638,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
|
||||
<span class="lcode">L51</span>
|
||||
<span class="lmode" style="background:#061033;color:#ffffff">Sombre</span>
|
||||
</div>
|
||||
<div class="wf-thumb"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 180" class="wf"><rect x="0" y="0" width="320" height="180" rx="8" fill="#FFFFFF" opacity="1.0"/><rect x="0.5" y="0.5" width="319" height="179" rx="8" fill="none" stroke="#E3E0D9"/><rect x="0" y="0" width="320" height="180" rx="4" fill="#8FA9D0" opacity="0.5"/><line x1="0" y1="180" x2="320" y2="0" stroke="#8FA9D0" stroke-width="1.5"/><line x1="0" y1="0" x2="320" y2="180" stroke="#8FA9D0" stroke-width="1.5"/><rect x="0" y="120" width="320" height="60" rx="0" fill="#061033" opacity="0.82"/><rect x="20" y="134" width="150" height="12" rx="2" fill="#FFFFFF" opacity="1.0"/><rect x="20" y="152" width="90" height="7" rx="2" fill="#8FA9D0" opacity="1.0"/></svg></div>
|
||||
<h3>image_full</h3>
|
||||
<p class="hint">Ouverture de chapitre visuelle : image plein cadre + voile navy + titre display blanc. Alternative à section_divider quand un asset du projet s'y prête. image = nom de fichier exact de assets/.</p>
|
||||
<div class="fields">
|
||||
@@ -614,7 +648,7 @@ footer{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-
|
||||
</div></div>
|
||||
</section>
|
||||
<footer>
|
||||
Généré automatiquement depuis layouts_v2.yaml · 13/07/2026 · 31 layouts
|
||||
Généré automatiquement depuis layouts_v2.yaml · 16/07/2026 · 31 layouts
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
+498
@@ -0,0 +1,498 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
wireframes.py — Vignettes SVG des layouts (Sliding Design System)
|
||||
=================================================================
|
||||
Schémas grosse maille, aux couleurs de la charte, FIDÈLES à la
|
||||
structure de chaque _render_* du moteur (cartes, bandeaux navy/coral,
|
||||
cercles, colonnes, barres, badges…). Pur Python/SVG : aucune
|
||||
dépendance, aucun LibreOffice, régénérable en une fraction de seconde.
|
||||
|
||||
API : svg_for(layout_name, mode) -> str (SVG inline, viewBox 320x180).
|
||||
Un layout inconnu retombe sur un gabarit générique titre + lignes.
|
||||
|
||||
Consommé par build_gallery.py (vignette dans chaque fiche).
|
||||
"""
|
||||
|
||||
# ── Charte ───────────────────────────────────────────────────────────────────
|
||||
NAVY = "#061033"
|
||||
NAVY2 = "#10204D"
|
||||
CORAL = "#F4795B"
|
||||
GLACIER = "#8FA9D0"
|
||||
SLATE = "#46505A"
|
||||
CARD = "#F4F1EC"
|
||||
BODY = "#2B3440"
|
||||
MUTED = "#C9CDD3"
|
||||
WHITE = "#FFFFFF"
|
||||
|
||||
W, H = 320, 180
|
||||
MX = 20 # marge horizontale de la zone utile
|
||||
|
||||
# ── Primitives ───────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
def _r(x, y, w, h, fill, rad=0, op=1.0, stroke=None):
|
||||
s = f' stroke="{stroke}" stroke-width="1"' if stroke else ""
|
||||
return (f'<rect x="{x:.0f}" y="{y:.0f}" width="{w:.0f}" '
|
||||
f'height="{h:.0f}" rx="{rad}" fill="{fill}" '
|
||||
f'opacity="{op}"{s}/>')
|
||||
|
||||
|
||||
def _c(cx, cy, rad, fill, op=1.0):
|
||||
return (f'<circle cx="{cx:.0f}" cy="{cy:.0f}" r="{rad:.0f}" '
|
||||
f'fill="{fill}" opacity="{op}"/>')
|
||||
|
||||
|
||||
def _title_bar(y=16, w=150, c=NAVY):
|
||||
return _r(MX, y, w, 12, c, rad=2)
|
||||
|
||||
|
||||
def _lines(x, y, w, n, gap=13, c=MUTED, first=None, fw=None):
|
||||
out = []
|
||||
for i in range(n):
|
||||
cc = first if (first and i == 0) else c
|
||||
ww = (fw or w) if (fw and i == 0) else w
|
||||
out.append(_r(x, y + i * gap, ww, 7, cc, rad=3))
|
||||
return "".join(out)
|
||||
|
||||
|
||||
def _img_zone(x, y, w, h, mode="light"):
|
||||
"""Zone image : aplat glacier clair + diagonale (convention wireframe)."""
|
||||
fill = GLACIER
|
||||
return (_r(x, y, w, h, fill, rad=4, op=0.5)
|
||||
+ f'<line x1="{x:.0f}" y1="{y+h:.0f}" x2="{x+w:.0f}" '
|
||||
f'y2="{y:.0f}" stroke="{GLACIER}" stroke-width="1.5"/>'
|
||||
+ f'<line x1="{x:.0f}" y1="{y:.0f}" x2="{x+w:.0f}" '
|
||||
f'y2="{y+h:.0f}" stroke="{GLACIER}" stroke-width="1.5"/>')
|
||||
|
||||
|
||||
def _frame(mode, body):
|
||||
bg = NAVY if mode == "dark" else ("#EEF1F6" if mode == "panel"
|
||||
else WHITE)
|
||||
return (f'<svg xmlns="http://www.w3.org/2000/svg" '
|
||||
f'viewBox="0 0 {W} {H}" class="wf">'
|
||||
f'{_r(0, 0, W, H, bg, rad=8)}'
|
||||
f'<rect x="0.5" y="0.5" width="{W-1}" height="{H-1}" rx="8" '
|
||||
f'fill="none" stroke="#E3E0D9"/>{body}</svg>')
|
||||
|
||||
|
||||
def _title_light(mode):
|
||||
return WHITE if mode == "dark" else NAVY
|
||||
|
||||
|
||||
# ── Archétypes (fidèles aux _render_*) ───────────────────────────────────────
|
||||
|
||||
def _wf_cover(mode):
|
||||
# cover_split : fond navy, cercles décoratifs coin, filet coral, titre
|
||||
b = [_c(300, 20, 46, NAVY2), _c(288, 150, 30, CORAL, 0.9),
|
||||
_c(250, 150, 14, GLACIER),
|
||||
_r(MX, 74, 40, 4, CORAL, rad=1),
|
||||
_r(MX, 88, 150, 16, WHITE, rad=2),
|
||||
_r(MX, 120, 96, 8, GLACIER, rad=2)]
|
||||
return _frame("dark", "".join(b))
|
||||
|
||||
|
||||
def _wf_section(mode):
|
||||
# section_divider : navy, gros numéro fantôme, titre
|
||||
b = [_c(300, 150, 40, NAVY2),
|
||||
_r(MX, 78, 20, 20, CORAL, rad=2),
|
||||
_r(MX, 104, 130, 14, WHITE, rad=2)]
|
||||
return _frame("dark", "".join(b))
|
||||
|
||||
|
||||
def _wf_end(mode):
|
||||
b = [_c(300, 24, 40, CORAL, 0.9), _c(30, 150, 46, NAVY2),
|
||||
_r(96, 74, 128, 14, WHITE, rad=2),
|
||||
_r(120, 100, 80, 8, GLACIER, rad=2)]
|
||||
return _frame("dark", "".join(b))
|
||||
|
||||
|
||||
def _wf_big_stat(mode):
|
||||
tl = _title_light(mode)
|
||||
# titre en haut ; chiffre coral CENTRÉ (H et V) ; desc + source
|
||||
# centrées dessous — cf _render_big_stat (align CENTER, _cy).
|
||||
b = [_title_bar(w=120, c=tl),
|
||||
_r(90, 66, 140, 40, CORAL, rad=4), # chiffre héros, centré
|
||||
_r(110, 116, 100, 8, MUTED, rad=3), # description centrée
|
||||
_r(134, 132, 52, 5, MUTED, rad=2, op=0.6)] # source centrée
|
||||
return _frame(mode, "".join(b))
|
||||
|
||||
|
||||
def _wf_key_message(mode):
|
||||
# key_message : fond navy, grande phrase centrée
|
||||
b = [_r(40, 70, 240, 14, WHITE, rad=2),
|
||||
_r(70, 92, 180, 14, GLACIER, rad=2),
|
||||
_r(130, 120, 60, 6, CORAL, rad=2)]
|
||||
return _frame("dark", "".join(b))
|
||||
|
||||
|
||||
def _wf_bullets(mode):
|
||||
tl = _title_light(mode)
|
||||
# titre en haut ; puces CARRÉES coral + texte, bloc centré vertical.
|
||||
# Pas de barre latérale (cf _render_default_bullets).
|
||||
b = [_title_bar(c=tl)]
|
||||
for y in (66, 94, 122):
|
||||
b.append(_r(MX, y, 8, 8, CORAL, rad=1)) # square_mark coral
|
||||
b.append(_r(MX + 18, y, 250, 8, MUTED, rad=3))
|
||||
return _frame(mode, "".join(b))
|
||||
|
||||
|
||||
def _wf_two_cols(mode):
|
||||
b = [_title_bar(w=170)]
|
||||
cw, xs, acc = 132, (MX, 168), (NAVY, CORAL)
|
||||
for i in range(2):
|
||||
x = xs[i]
|
||||
b.append(_r(x, 44, cw, 120, CARD, rad=6))
|
||||
b.append(_r(x, 44, cw, 26, acc[i], rad=6))
|
||||
b.append(_r(x, 58, cw, 12, acc[i]))
|
||||
b.append(_r(x + 12, 52, 70, 10, WHITE, rad=3))
|
||||
b.append(_lines(x + 12, 84, 100, 4, gap=15))
|
||||
return _frame("light", "".join(b))
|
||||
|
||||
|
||||
def _wf_from_to(mode):
|
||||
b = [_title_bar(w=150)]
|
||||
for i, (x, c) in enumerate(((MX, NAVY), (176, SLATE))):
|
||||
b.append(_r(x, 50, 120, 100, CARD, rad=6))
|
||||
b.append(_r(x, 50, 120, 6, c, rad=3))
|
||||
b.append(_lines(x + 12, 70, 90, 4, gap=16))
|
||||
b.append(_c(160, 100, 10, CORAL)) # flèche/pivot central
|
||||
return _frame("light", "".join(b))
|
||||
|
||||
|
||||
def _wf_exec_summary(mode):
|
||||
b = [_title_bar(w=160)]
|
||||
for i, x in enumerate((MX, 112, 204)):
|
||||
b.append(_r(x, 54, 96, 108, CARD, rad=6))
|
||||
b.append(_c(x + 16, 74, 9, NAVY))
|
||||
b.append(_r(x + 12, 96, 72, 7, SLATE, rad=3))
|
||||
b.append(_lines(x + 12, 112, 72, 3, gap=12))
|
||||
b.append(_r(MX, 54, 96, 4, CORAL, rad=2)) # 1re carte accentuée
|
||||
return _frame("light", "".join(b))
|
||||
|
||||
|
||||
def _wf_kpi_grid(mode):
|
||||
b = [_title_bar(w=120)]
|
||||
xs = (MX, 112, 204)
|
||||
for i, x in enumerate(xs):
|
||||
b.append(_r(x, 56, 96, 100, CARD, rad=6))
|
||||
b.append(_r(x + 12, 74, 50, 22, CORAL if i == 0 else NAVY,
|
||||
rad=3))
|
||||
b.append(_r(x + 12, 104, 70, 6, SLATE, rad=3))
|
||||
b.append(_r(x + 12, 118, 56, 6, MUTED, rad=3))
|
||||
return _frame("light", "".join(b))
|
||||
|
||||
|
||||
def _wf_numbered_steps(mode):
|
||||
b = [_title_bar(w=150)]
|
||||
for i, y in enumerate((52, 86, 120)):
|
||||
b.append(_r(MX, y, 280, 28, CARD, rad=6))
|
||||
b.append(_c(MX + 18, y + 14, 11, NAVY))
|
||||
b.append(_r(MX + 40, y + 10, 200, 8, MUTED, rad=3))
|
||||
return _frame("light", "".join(b))
|
||||
|
||||
|
||||
def _wf_agenda(mode):
|
||||
b = [_title_bar(w=140)]
|
||||
for i, y in enumerate((52, 84, 116, 148)):
|
||||
active = (i == 1)
|
||||
b.append(_c(MX + 12, y, 10, CORAL if active else NAVY))
|
||||
b.append(_r(MX + 30, y - 5, 180, 9,
|
||||
NAVY if active else MUTED, rad=3))
|
||||
b.append(_r(230, y - 5, 60, 9, MUTED, rad=3, op=0.6))
|
||||
return _frame("light", "".join(b))
|
||||
|
||||
|
||||
def _wf_circular(mode):
|
||||
tl = _title_light(mode)
|
||||
b = [_title_bar(w=130, c=tl)]
|
||||
cx, cy = 110, 108
|
||||
for ang, c in ((0, NAVY), (120, SLATE), (240, GLACIER)):
|
||||
import math
|
||||
x = cx + 34 * math.cos(math.radians(ang))
|
||||
y = cy + 34 * math.sin(math.radians(ang))
|
||||
b.append(_c(x, y, 22, c))
|
||||
b.append(_c(cx, cy, 14, CORAL))
|
||||
# légende
|
||||
for i, y in enumerate((70, 100, 130)):
|
||||
b.append(_c(210, y, 6, (NAVY, SLATE, GLACIER)[i]))
|
||||
b.append(_r(224, y - 4, 76, 7, MUTED, rad=3))
|
||||
return _frame(mode, "".join(b))
|
||||
|
||||
|
||||
def _wf_recommendation(mode):
|
||||
b = [_title_bar(w=150),
|
||||
_r(MX, 48, 190, 116, CARD, rad=6),
|
||||
_r(MX, 48, 190, 6, CORAL, rad=3),
|
||||
_c(MX + 20, 72, 10, NAVY),
|
||||
_lines(MX + 40, 66, 130, 4, gap=16),
|
||||
_r(228, 48, 72, 116, NAVY, rad=6), # panneau latéral navy
|
||||
_r(240, 70, 48, 8, GLACIER, rad=3),
|
||||
_lines(240, 92, 48, 3, gap=13, c="#33436A")]
|
||||
return _frame("light", "".join(b))
|
||||
|
||||
|
||||
def _wf_phases_timeline(mode):
|
||||
b = [_title_bar(w=150)]
|
||||
for i, x in enumerate((MX, 112, 204)):
|
||||
c = (NAVY, SLATE, GLACIER)[i]
|
||||
b.append(_r(x, 74, 96, 44, c, rad=6))
|
||||
if i < 2:
|
||||
b.append(_r(x + 96, 94, 16, 4, MUTED, rad=2))
|
||||
b.append(_r(x + 20, 126, 56, 6, MUTED, rad=3))
|
||||
return _frame("light", "".join(b))
|
||||
|
||||
|
||||
def _wf_gantt(mode):
|
||||
b = [_title_bar(w=140)]
|
||||
rows = ((40, 120, NAVY), (90, 90, SLATE), (150, 100, NAVY),
|
||||
(70, 130, GLACIER))
|
||||
for i, (x, w, c) in enumerate(rows):
|
||||
y = 56 + i * 26
|
||||
b.append(_r(MX, y, 60, 10, MUTED, rad=2)) # label
|
||||
b.append(_r(90 + x, y, w, 12, c, rad=3)) # barre
|
||||
return _frame("light", "".join(b))
|
||||
|
||||
|
||||
def _wf_yearly(mode):
|
||||
b = [_title_bar(w=130),
|
||||
_r(MX, 100, 280, 3, NAVY)] # ligne de temps
|
||||
for i, x in enumerate((40, 120, 200, 280)):
|
||||
b.append(_c(x, 101, 7, CORAL if i == 1 else NAVY))
|
||||
b.append(_r(x - 20, 116, 40, 6, MUTED, rad=2))
|
||||
return _frame("light", "".join(b))
|
||||
|
||||
|
||||
def _wf_comparison(mode):
|
||||
b = [_title_bar(w=150), _r(MX, 48, 280, 20, NAVY, rad=4)] # entête
|
||||
for j in range(3):
|
||||
b.append(_r(MX + 4 + j * 92, 52, 84, 12, WHITE, rad=2,
|
||||
op=0.5))
|
||||
for i in range(4):
|
||||
y = 72 + i * 22
|
||||
b.append(_r(MX, y, 280, 18, CARD if i % 2 else WHITE, rad=2,
|
||||
stroke="#E3E0D9"))
|
||||
for j in range(3):
|
||||
b.append(_r(MX + 10 + j * 92, y + 5, 64, 7, MUTED, rad=2))
|
||||
return _frame("light", "".join(b))
|
||||
|
||||
|
||||
def _wf_raci(mode):
|
||||
b = [_title_bar(w=120), _r(MX, 48, 280, 18, NAVY, rad=4)]
|
||||
letters = (NAVY, CORAL, SLATE, GLACIER)
|
||||
for i in range(4):
|
||||
y = 70 + i * 22
|
||||
b.append(_r(MX, y, 80, 16, CARD, rad=2))
|
||||
for j in range(4):
|
||||
b.append(_c(130 + j * 44, y + 8, 7, letters[j], 0.85))
|
||||
return _frame("light", "".join(b))
|
||||
|
||||
|
||||
def _wf_process_arrow(mode):
|
||||
b = [_title_bar(w=140)]
|
||||
for i, x in enumerate((MX, 120, 220)):
|
||||
c = CORAL if i == 1 else NAVY
|
||||
b.append(f'<polygon points="{x},80 {x+70},80 {x+86},104 '
|
||||
f'{x+70},128 {x},128 {x+16},104" fill="{c}"/>')
|
||||
return _frame("light", "".join(b))
|
||||
|
||||
|
||||
def _wf_org_chart(mode):
|
||||
b = [_title_bar(w=120),
|
||||
_r(130, 52, 60, 26, NAVY, rad=4)]
|
||||
for x in (60, 140, 220):
|
||||
b.append(_r(x, 120, 56, 26, CARD, rad=4, stroke="#E3E0D9"))
|
||||
b.append(f'<line x1="160" y1="78" x2="{x+28}" y2="120" '
|
||||
f'stroke="{NAVY}" stroke-width="1.5"/>')
|
||||
return _frame("light", "".join(b))
|
||||
|
||||
|
||||
def _wf_matrix(mode):
|
||||
tl = _title_light(mode)
|
||||
b = [_title_bar(w=120, c=tl),
|
||||
f'<line x1="160" y1="46" x2="160" y2="170" stroke="{SLATE}" '
|
||||
f'stroke-width="1.5"/>',
|
||||
f'<line x1="24" y1="108" x2="296" y2="108" stroke="{SLATE}" '
|
||||
f'stroke-width="1.5"/>']
|
||||
quad = ((92, 78, NAVY), (228, 78, CORAL),
|
||||
(92, 140, SLATE), (228, 140, GLACIER))
|
||||
for cx, cy, c in quad:
|
||||
b.append(_c(cx, cy, 16, c, 0.9))
|
||||
return _frame(mode, "".join(b))
|
||||
|
||||
|
||||
def _wf_image_split(mode):
|
||||
b = [_img_zone(MX, 44, 130, 120),
|
||||
_r(168, 44, 130, 14, NAVY, rad=2),
|
||||
_c(176, 78, 3, CORAL),
|
||||
_lines(184, 74, 108, 4, gap=17)]
|
||||
return _frame("light", "".join(b))
|
||||
|
||||
|
||||
def _wf_image_full(mode):
|
||||
b = [_img_zone(0, 0, W, H),
|
||||
_r(0, 120, W, 60, NAVY, rad=0, op=0.82),
|
||||
_r(MX, 134, 150, 12, WHITE, rad=2),
|
||||
_r(MX, 152, 90, 7, GLACIER, rad=2)]
|
||||
return _frame("light", "".join(b))
|
||||
|
||||
|
||||
def _wf_bar_chart(mode):
|
||||
b = [_title_bar(w=120)]
|
||||
vals = (40, 70, 55, 90, 62)
|
||||
for i, v in enumerate(vals):
|
||||
x = 40 + i * 52
|
||||
b.append(_r(x, 150 - v, 32, v, NAVY, rad=2))
|
||||
b.append(_r(30, 150, 270, 2, SLATE))
|
||||
return _frame("light", "".join(b))
|
||||
|
||||
|
||||
def _wf_line_chart(mode):
|
||||
b = [_title_bar(w=120), _r(30, 150, 270, 2, SLATE)]
|
||||
pts = [(40, 130), (100, 96), (160, 110), (220, 70), (288, 84)]
|
||||
path = " ".join(f"{x},{y}" for x, y in pts)
|
||||
b.append(f'<polyline points="{path}" fill="none" stroke="{NAVY}" '
|
||||
f'stroke-width="2.5"/>')
|
||||
b.append(_c(288, 84, 5, CORAL))
|
||||
return _frame("light", "".join(b))
|
||||
|
||||
|
||||
def _wf_donut(mode):
|
||||
tl = _title_light(mode)
|
||||
b = [_title_bar(w=110, c=tl)]
|
||||
b.append(f'<circle cx="100" cy="106" r="40" fill="none" '
|
||||
f'stroke="{NAVY}" stroke-width="18"/>')
|
||||
b.append(f'<path d="M100 66 A40 40 0 0 1 138 118" fill="none" '
|
||||
f'stroke="{CORAL}" stroke-width="18"/>')
|
||||
for i, y in enumerate((84, 108, 132)):
|
||||
b.append(_c(210, y, 6, (NAVY, CORAL, GLACIER)[i]))
|
||||
b.append(_r(224, y - 4, 76, 7, MUTED, rad=3))
|
||||
return _frame(mode, "".join(b))
|
||||
|
||||
|
||||
def _wf_waterfall(mode):
|
||||
b = [_title_bar(w=140), _r(30, 150, 270, 2, SLATE)]
|
||||
# colonnes cumulées : base navy, deltas coral, total navy
|
||||
cols = ((40, 150 - 70, 70, NAVY), (94, 80, 34, CORAL),
|
||||
(148, 60, 40, CORAL), (202, 44, 30, CORAL),
|
||||
(256, 150 - 90, 90, NAVY))
|
||||
for x, y, h, c in cols:
|
||||
b.append(_r(x, y, 34, h, c, rad=2))
|
||||
return _frame("light", "".join(b))
|
||||
|
||||
|
||||
def _wf_heatmap(mode):
|
||||
b = [_title_bar(w=120)]
|
||||
import random
|
||||
random.seed(3)
|
||||
shades = ["#D6DCEA", "#9FB0D0", GLACIER, NAVY2, NAVY]
|
||||
for r in range(4):
|
||||
for cix in range(5):
|
||||
b.append(_r(60 + cix * 46, 54 + r * 26, 42, 22,
|
||||
shades[(r + cix) % 5], rad=2))
|
||||
b.append(_r(MX, 58 + r * 26, 32, 12, MUTED, rad=2))
|
||||
return _frame("light", "".join(b))
|
||||
|
||||
|
||||
def _wf_funnel(mode):
|
||||
b = [_title_bar(w=110)]
|
||||
widths = (240, 180, 120, 70)
|
||||
cols = (NAVY, NAVY2, GLACIER, CORAL)
|
||||
for i, w in enumerate(widths):
|
||||
x = (W - w) / 2
|
||||
b.append(f'<polygon points="{x},{58+i*26} {x+w},{58+i*26} '
|
||||
f'{x+w-14},{80+i*26} {x+14},{80+i*26}" '
|
||||
f'fill="{cols[i]}"/>')
|
||||
return _frame("light", "".join(b))
|
||||
|
||||
|
||||
def _wf_pyramid(mode):
|
||||
b = [_title_bar(w=110)]
|
||||
widths = (90, 150, 210, 270)
|
||||
cols = (CORAL, GLACIER, SLATE, NAVY)
|
||||
for i, w in enumerate(widths):
|
||||
x = (W - w) / 2
|
||||
b.append(_r(x, 132 - i * 24, w, 20, cols[i], rad=2))
|
||||
return _frame("light", "".join(b))
|
||||
|
||||
|
||||
def _wf_generic(mode):
|
||||
tl = _title_light(mode)
|
||||
return _frame(mode, _title_bar(c=tl) + _lines(MX, 50, 240, 5,
|
||||
gap=18))
|
||||
|
||||
|
||||
# ── Mapping layout → archétype ───────────────────────────────────────────────
|
||||
|
||||
_MAP = {
|
||||
"cover_split": _wf_cover,
|
||||
"section_divider": _wf_section,
|
||||
"end_slide": _wf_end,
|
||||
"big_stat": _wf_big_stat,
|
||||
"key_message": _wf_key_message,
|
||||
"default_bullets": _wf_bullets,
|
||||
"two_cols_text": _wf_two_cols,
|
||||
"from_to_pairs": _wf_from_to,
|
||||
"executive_summary": _wf_exec_summary,
|
||||
"kpi_grid": _wf_kpi_grid,
|
||||
"numbered_steps": _wf_numbered_steps,
|
||||
"agenda": _wf_agenda,
|
||||
"circular_diagram": _wf_circular,
|
||||
"recommendation_card": _wf_recommendation,
|
||||
"phases_timeline": _wf_phases_timeline,
|
||||
"gantt_timeline": _wf_gantt,
|
||||
"yearly_timeline": _wf_yearly,
|
||||
"comparison_table": _wf_comparison,
|
||||
"raci_table": _wf_raci,
|
||||
"process_arrow": _wf_process_arrow,
|
||||
"org_chart": _wf_org_chart,
|
||||
"matrix_2x2": _wf_matrix,
|
||||
"image_split": _wf_image_split,
|
||||
"image_full": _wf_image_full,
|
||||
"bar_chart": _wf_bar_chart,
|
||||
"line_chart": _wf_line_chart,
|
||||
"donut_split": _wf_donut,
|
||||
"waterfall": _wf_waterfall,
|
||||
"heatmap_table": _wf_heatmap,
|
||||
"funnel": _wf_funnel,
|
||||
"pyramid": _wf_pyramid,
|
||||
# freeform : pas de structure fixe → gabarit générique
|
||||
"freeform": _wf_generic,
|
||||
}
|
||||
|
||||
|
||||
def svg_for(layout_name, mode="light"):
|
||||
fn = _MAP.get(layout_name, _wf_generic)
|
||||
try:
|
||||
return fn(mode)
|
||||
except Exception:
|
||||
return _wf_generic(mode)
|
||||
|
||||
|
||||
def known():
|
||||
return set(_MAP)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Auto-test : rend tous les archétypes dans un HTML de contrôle
|
||||
import yaml
|
||||
import os
|
||||
try:
|
||||
L = yaml.safe_load(open("layouts_v2.yaml",
|
||||
encoding="utf-8"))["layouts"]
|
||||
names = list(L)
|
||||
except Exception:
|
||||
names = list(_MAP)
|
||||
cells = "".join(
|
||||
f'<figure style="margin:8px;display:inline-block;width:240px">'
|
||||
f'{svg_for(n)}<figcaption style="font:12px sans-serif;'
|
||||
f'text-align:center">{n}</figcaption></figure>'
|
||||
for n in names)
|
||||
open("_wireframes_preview.html", "w").write(
|
||||
f"<!doctype html><meta charset=utf-8><body "
|
||||
f"style='background:#FAF9F7'>{cells}</body>")
|
||||
missing = [n for n in names if n not in _MAP]
|
||||
print("layouts:", len(names), "| mappés:",
|
||||
len([n for n in names if n in _MAP]),
|
||||
"| génériques:", missing or "aucun")
|
||||
print("Contrôle visuel : _wireframes_preview.html")
|
||||
Reference in New Issue
Block a user