Files
sliding-automation/build_gallery.py
T

155 lines
7.7 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
build_gallery.py — Génère la galerie HTML du design system v2
depuis layouts_v2.yaml. Relancer après tout ajout de layout.
Usage : python3 build_gallery.py → produit index.html
"""
import yaml
from pathlib import Path
from datetime import datetime
LAYOUTS = yaml.safe_load(open("layouts_v2.yaml", encoding="utf-8"))["layouts"]
THEME = yaml.safe_load(open("theme_v2.yaml", encoding="utf-8"))
C = THEME["colors"]
NAVY = C["primary"]["navy"]
NAVY2 = C["primary"]["navy_light"]
CORAL = C["accent"]["coral"]
GLACIER = C["secondary"]["glacier"]
SLATE = C["secondary"]["slate"]
CARD = C["backgrounds"]["card"]
# Familles regroupées dans l'ordre d'apparition
families = {}
for name, cfg in LAYOUTS.items():
fam = cfg.get("famille", "Autres")
families.setdefault(fam, []).append((name, cfg))
n_layouts = len(LAYOUTS)
n_families = len(families)
def card(name, cfg):
lid = cfg.get("id", "")
mode = cfg.get("mode", "light")
hint = " ".join(cfg.get("agent_hint", "").split())
champs = ", ".join(cfg.get("champs", []))
requis = ", ".join(cfg.get("champs_requis", []))
mode_badge = {
"light": ("Clair", "#f4f1ec", NAVY),
"dark": ("Sombre", NAVY, "#ffffff"),
"panel": ("Panel", GLACIER, NAVY),
}.get(mode, ("Clair", "#f4f1ec", NAVY))
return f"""
<div class="lc">
<div class="lc-head">
<span class="lcode">{lid}</span>
<span class="lmode" style="background:{mode_badge[1]};color:{mode_badge[2]}">{mode_badge[0]}</span>
</div>
<h3>{name}</h3>
<p class="hint">{hint}</p>
<div class="fields">
<div class="frow"><span class="flab">Champs</span><code>{champs}</code></div>
<div class="frow"><span class="flab">Requis</span><code class="req">{requis}</code></div>
</div>
</div>"""
sections = ""
for fam, items in families.items():
cards = "\n".join(card(n, c) for n, c in items)
sections += f"""
<section class="family">
<div class="fh">
<div>
<div class="se">{len(items)} layout{'s' if len(items)>1 else ''}</div>
<h2 class="st">{fam}</h2>
</div>
</div>
<div class="lg">{cards}</div>
</section>"""
palette = "".join(
f'<div class="cc"><div class="cs" style="background:{hexv}"></div>'
f'<div class="cm"><div class="cn">{label}</div>'
f'<div class="chx">{hexv}</div></div></div>'
for label, hexv in [
("Navy", NAVY), ("Navy light", NAVY2), ("Coral", CORAL),
("Glacier", GLACIER), ("Slate", SLATE), ("Card", CARD)])
html = f"""<!DOCTYPE html>
<html lang="fr">
<head>
<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="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>
:root{{--navy:{NAVY};--navy2:{NAVY2};--coral:{CORAL};--glacier:{GLACIER};--slate:{SLATE};--card:{CARD};--bg:#faf8f4;--bo:#e8e2d6;--t1:#1a1a1a;--t2:#6b6b6b;--t3:#9a9a9a}}
*{{margin:0;padding:0;box-sizing:border-box}}
body{{font-family:Inter,sans-serif;background:var(--bg);color:var(--t1);font-weight:300;-webkit-font-smoothing:antialiased}}
header{{background:var(--navy);color:#fff;padding:80px 60px 60px;position:relative;overflow:hidden}}
header::after{{content:"";position:absolute;right:-80px;top:-80px;width:340px;height:340px;border-radius:50%;background:var(--navy2);opacity:.5}}
header::before{{content:"";position:absolute;right:120px;bottom:-60px;width:160px;height:160px;border-radius:50%;background:var(--coral);opacity:.85}}
.eyebrow{{font-size:11px;letter-spacing:.3em;text-transform:uppercase;color:var(--glacier);margin-bottom:24px;font-weight:500;position:relative;z-index:2}}
h1{{font-family:Cambria,serif;font-size:60px;font-weight:700;line-height:1.05;letter-spacing:-.02em;margin-bottom:24px;position:relative;z-index:2}}
.lead{{font-size:17px;line-height:1.6;color:rgba(255,255,255,.75);max-width:680px;position:relative;z-index:2}}
.hmeta{{display:flex;gap:60px;margin-top:50px;padding-top:30px;border-top:1px solid rgba(255,255,255,.15);position:relative;z-index:2}}
.mi{{display:flex;flex-direction:column;gap:4px}}
.ml{{font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:var(--glacier)}}
.mv{{font-family:Cambria,serif;font-size:28px;font-weight:700}}
.charte{{padding:70px 60px;background:#fff;border-bottom:1px solid var(--bo)}}
.se{{font-size:11px;letter-spacing:.3em;text-transform:uppercase;color:var(--coral);font-weight:600;margin-bottom:14px}}
.st{{font-family:Cambria,serif;font-size:40px;font-weight:700;line-height:1.1;color:var(--navy);margin-bottom:30px}}
.cr{{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:12px;max-width:900px}}
.cc{{border-radius:8px;overflow:hidden;border:1px solid var(--bo)}}
.cs{{height:60px}}
.cm{{padding:8px 12px;background:#fff}}
.cn{{font-size:12px;font-weight:500}}
.chx{{font-size:10px;color:var(--t3);font-family:monospace;margin-top:2px}}
.family{{padding:60px}}
.family:nth-child(even){{background:#fff}}
.fh{{margin-bottom:36px}}
.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)}}
.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}}
.lc h3{{font-family:Cambria,serif;font-size:23px;font-weight:700;color:var(--navy);margin-bottom:10px}}
.hint{{font-size:13.5px;line-height:1.55;color:var(--t2);margin-bottom:18px;flex:1}}
.fields{{border-top:1px solid var(--bo);padding-top:14px;display:flex;flex-direction:column;gap:8px}}
.frow{{display:flex;gap:10px;align-items:baseline}}
.flab{{font-size:9px;letter-spacing:.15em;text-transform:uppercase;color:var(--t3);min-width:48px;font-weight:600}}
.frow code{{font-size:11.5px;font-family:monospace;color:var(--slate);line-height:1.4}}
.frow code.req{{color:var(--coral)}}
footer{{padding:50px 60px;background:var(--navy);color:rgba(255,255,255,.6);font-size:13px;text-align:center}}
@media(max-width:640px){{header,.charte,.family{{padding:40px 24px}}h1{{font-size:40px}}.lg{{grid-template-columns:1fr}}}}
</style>
</head>
<body>
<header>
<div class="eyebrow">Pernod Ricard · Data Governance</div>
<h1>Sliding Design System v2</h1>
<p class="lead">Catalogue des layouts disponibles dans le pipeline de génération automatique de présentations. Design system « PR Editorial » : navy dominant, accent corail, grille fixe et centrage vertical systématique.</p>
<div class="hmeta">
<div class="mi"><span class="ml">Layouts</span><span class="mv">{n_layouts}</span></div>
<div class="mi"><span class="ml">Familles</span><span class="mv">{n_families}</span></div>
<div class="mi"><span class="ml">Version</span><span class="mv">2.0</span></div>
</div>
</header>
<section class="charte">
<div class="se">Palette</div>
<h2 class="st">Charte chromatique</h2>
<div class="cr">{palette}</div>
</section>
{sections}
<footer>
Généré automatiquement depuis layouts_v2.yaml · {datetime.now().strftime('%d/%m/%Y')} · {n_layouts} layouts
</footer>
</body>
</html>"""
Path("index.html").write_text(html, encoding="utf-8")
print(f"index.html généré — {n_layouts} layouts, {n_families} familles")