[DTP-Worker] Sprint 2 · Publiciste scaffold (parser faisabilité → JSON + generator + gate)
Livrable Publiciste · Sprint 2 · Semaine 2 (seul module net-neuf · chemin critique · GAP_ANALYSIS §3.13). Cible portage VPS : otoia/capabilities/publiciste.py. - lib/parser.py : data_room/PXX/ (template v1.0) → projet dict conforme au contrat projets_master.schema.json (livré S1). Mapping colonnes par en-tête, parsing montants USD/DOP robuste. Anti-invention #6 : rétrogradation défensive « en_developpement » si prix USD manquant ; absent → null (jamais 0/inventé). - lib/validator.py : validateur JSON-Schema draft-07 (sous-ensemble) ZÉRO dépendance pip (runner Gitea sans pip). Oracle jsonschema en test si présent. - lib/generator.py + template + branding : rendu HTML luxury #4 (dark+doré, Fraunces + Cormorant Garamond) ; sans prix → « Prochainement · Détails à venir ». - publiciste.py : CLI parse/validate/generate/run. - fixtures/ : données SYNTHÉTIQUES de test (jamais publiées) P01 complète + P02 incomplète. - tests/ : 23 tests unittest (stdlib) verts. - CI : job publiciste-tests ajouté au gate (.gitea/workflows/ci.yml · Gitea #2). Vérifs (en-repo, sans VPS) : 23/23 tests verts · gate CI local vert (guard/JSON/ docs) · pipeline CLI produit un master conforme au schéma. Auto-score 4Big 95/100. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>{{TITRE}}</title>
|
||||
<meta name="description" content="{{META_DESCRIPTION}}" />
|
||||
<!-- Généré automatiquement par le Publiciste Agent — NE PAS éditer à la main.
|
||||
Source : faisabilités canoniques data_room/PXX/ (contrainte CLAUDE.md #6). -->
|
||||
<style>
|
||||
:root {
|
||||
--bg: {{COLOR_BG}};
|
||||
--accent: {{COLOR_ACCENT}};
|
||||
--ink: {{COLOR_INK}};
|
||||
--muted: {{COLOR_MUTED}};
|
||||
--font-display: "{{FONT_DISPLAY}}", Georgia, serif;
|
||||
--font-body: "{{FONT_BODY}}", Georgia, serif;
|
||||
}
|
||||
* { box-sizing: border-box; }
|
||||
body {
|
||||
margin: 0; background: var(--bg); color: var(--ink);
|
||||
font-family: var(--font-body); font-size: 18px; line-height: 1.6;
|
||||
}
|
||||
header.hero {
|
||||
padding: 96px 24px 64px; text-align: center;
|
||||
border-bottom: 1px solid rgba(240,180,41,0.25);
|
||||
}
|
||||
header.hero h1 {
|
||||
font-family: var(--font-display); font-weight: 600;
|
||||
font-size: clamp(2.4rem, 6vw, 4rem); margin: 0 0 12px; color: var(--ink);
|
||||
}
|
||||
header.hero .accent { color: var(--accent); }
|
||||
header.hero p.tagline { color: var(--muted); max-width: 640px; margin: 0 auto; }
|
||||
main { max-width: 1120px; margin: 0 auto; padding: 48px 24px 96px; }
|
||||
.grille { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 28px; }
|
||||
article.projet {
|
||||
background: #12121c; border: 1px solid rgba(240,180,41,0.18);
|
||||
border-radius: 14px; overflow: hidden; display: flex; flex-direction: column;
|
||||
}
|
||||
article.projet .media {
|
||||
aspect-ratio: 16/10; background: #0f0f18 center/cover no-repeat;
|
||||
border-bottom: 1px solid rgba(240,180,41,0.12);
|
||||
}
|
||||
article.projet .corps { padding: 22px 24px 26px; flex: 1; display: flex; flex-direction: column; }
|
||||
article.projet h2 {
|
||||
font-family: var(--font-display); font-weight: 600; font-size: 1.6rem;
|
||||
margin: 0 0 4px; color: var(--ink);
|
||||
}
|
||||
.localisation { color: var(--muted); font-size: 0.95rem; margin: 0 0 14px; }
|
||||
.statut {
|
||||
display: inline-block; font-family: var(--font-body); font-size: 0.8rem;
|
||||
letter-spacing: 0.06em; text-transform: uppercase; padding: 4px 12px;
|
||||
border-radius: 999px; margin-bottom: 14px;
|
||||
}
|
||||
.statut.disponible { color: var(--bg); background: var(--accent); }
|
||||
.statut.en_developpement, .statut.bientot, .statut.en_processus {
|
||||
color: var(--accent); border: 1px solid var(--accent);
|
||||
}
|
||||
.positionnement { color: var(--ink); opacity: 0.92; margin: 0 0 18px; }
|
||||
table.prix { width: 100%; border-collapse: collapse; margin: 8px 0 6px; font-size: 0.98rem; }
|
||||
table.prix th, table.prix td { text-align: left; padding: 7px 8px; border-bottom: 1px solid rgba(240,180,41,0.12); }
|
||||
table.prix th { color: var(--accent); font-family: var(--font-display); font-weight: 600; }
|
||||
.prix-depuis { color: var(--accent); font-weight: 600; white-space: nowrap; }
|
||||
.a-venir { color: var(--muted); font-style: italic; margin: 6px 0 10px; }
|
||||
ul.inclus { list-style: none; padding: 0; margin: 14px 0 0; }
|
||||
ul.inclus li { padding: 3px 0 3px 20px; position: relative; color: var(--ink); opacity: 0.88; font-size: 0.96rem; }
|
||||
ul.inclus li::before { content: "◆"; color: var(--accent); position: absolute; left: 0; font-size: 0.7rem; top: 6px; }
|
||||
footer.legal { color: var(--muted); font-size: 0.82rem; text-align: center; padding: 32px 24px 56px; border-top: 1px solid rgba(240,180,41,0.15); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header class="hero">
|
||||
<h1>Helios <span class="accent">RD</span></h1>
|
||||
<p class="tagline">{{TAGLINE}}</p>
|
||||
</header>
|
||||
<main>
|
||||
<div class="grille">
|
||||
{{PROJETS}}
|
||||
</div>
|
||||
</main>
|
||||
<footer class="legal">
|
||||
{{FOOTER}}
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user