2026-07-09 22:03:15 +02:00
#!/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
2026-07-16 19:31:14 +02:00
import wireframes
2026-07-09 22:03:15 +02:00
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 " , [ ] ) )
2026-07-16 19:31:14 +02:00
thumb = wireframes . svg_for ( name , mode )
2026-07-09 22:03:15 +02:00
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>
2026-07-16 19:31:14 +02:00
<div class= " wf-thumb " > { thumb } </div>
2026-07-09 22:03:15 +02:00
<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>
2026-07-16 19:31:14 +02:00
<link rel= " icon " type= " image/svg+xml " href= " /static/favicon.svg " >
2026-07-09 22:03:15 +02:00
<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) }}
2026-07-16 19:31:14 +02:00
.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 }}
2026-07-09 22:03:15 +02:00
.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 " )