# Story: Actualité Twig Templates and SCSS

## 1. Contexte (Context)

This story implements the public-facing rendering of the Actualité (news article) page template: the Twig templates for the page shell, the two content-block partials (text-only and text+image, the latter handling both left/right desktop variants and an independent mobile stacking order per Decision #6), the related-posts footer, and the accompanying BEM-structured SCSS. This is purely presentational work built on top of already-defined data shapes — it does not introduce new backend logic.

This story depends on the Actualité DTO/Model story (field names, especially `mobileImagePosition`, must be finalized before markup and editor wiring are built on top of them — renaming JSON keys after the fact is costly), the Tag entity story (for tag-pill rendering in the hero and related-posts cards), and the previous/next enricher story (for the shape of `previousPost`/`nextPost` data consumed by the related-posts footer).

## 2. Le besoin (User Story)

```
En tant que visiteur du site
Je souhaite consulter un article Actualité avec son titre, ses tags, son image principale, ses blocs de contenu (texte ou texte+image) et une section "autres news à découvrir"
Afin de lire l'article dans une mise en page fidèle à la maquette Figma, sur desktop comme sur mobile
```

## 3. Liens utiles (Useful Links)

- **Figma**: https://www.figma.com/design/ldjPgBvJ6j2I9RVTa17H33/Galta_2026?node-id=146-1824 (node `146:1824`, "Detail-News_Galta")
  - Bloc texte seul : node `146:2056`
  - Bloc texte+image (variante gauche) : node `146:2151`
- **Spec source**: `spec-driven-development/2026-07-07-actualite-news-page-template.md`, "Design summary" section and task groups "Frontend — Twig templates" and "Frontend — SCSS"
- **Decisions to respect**: Decision #5 (no "Découvrir en detail" CTA markup — leave a code comment noting it as a future enhancement); Decision #6 (`mobileImagePosition` drives mobile stacking order independently of desktop `imagePosition`)
- **Existing precedent to mirror**:
  - `templates/pages/list.html.twig` (`data-section`/`data-field` convention, editable image attribute convention — check `home.html.twig`/`project_detail` for exact `data-editor-type="image"` attribute naming before finalizing)
  - `scss-best-practices` skill (BEM methodology)
  - Existing string-default convention for editable titles with fallback (check `_nav.html.twig`/`_header.scss` per the current branch's burger-menu work, for the same "default text when field is empty" pattern needed for "Autres news à découvrir")
- **Blocking dependencies**: Story "Actualité DTO/Model + CreationService + TemplateMatcher registration" (`stories/actualite-dto-model-creation-service.md`); Story "Tag entity + admin CRUD" (`stories/actualite-tag-entity-admin-crud.md`); Story "PageRepository::findPublishedByTemplate() + previous/next enricher logic" (`stories/actualite-previous-next-enricher.md`)

## 4. Critères d'acceptation (Acceptance Criteria)

### Scénario 1: Rendu de l'en-tête de la page Actualité
```gherkin
Scénario: Le titre, les tags et l'image principale s'affichent conformément à Figma
  Étant donné une page Actualité publiée avec un titre, 2 tags et une image principale
  Quand la page est rendue via `templates/pages/actualite.html.twig`
  Alors le titre `<h1>` centré porte `data-editable`/`data-field="title"`
  Et les 2 tags sont affichés sous forme de pilules (une par tag), sans être éditables en tant que texte inline
  Et l'image principale est affichée sous un séparateur, avec l'attribut d'édition d'image cohérent avec les autres templates (ex. `data-editable data-field="mainImage" data-editor-type="image"`)
```

### Scénario 2: Rendu avec 0, 1 ou plusieurs tags
```gherkin
Scénario: Le rendu des tags s'adapte au nombre de tags assignés
  Étant donné un article avec 0 tag
  Quand la page est rendue
  Alors aucune pilule de tag n'est affichée, sans erreur ni espace vide disgracieux
  Étant donné un article avec 5 tags
  Quand la page est rendue
  Alors les 5 pilules s'affichent avec un retour à la ligne (wrap) plutôt qu'un débordement horizontal
```

### Scénario 3: Rendu du bloc texte seul
```gherkin
Scénario: Le bloc texte seul reproduit fidèlement le design Figma
  Étant donné un bloc de type "text" avec title/subtitle/content renseignés
  Quand `_actualite-block-text.html.twig` est rendu
  Alors il correspond pixel pour pixel au node Figma `146:2056` (titre Bochan Serif 36px, sous-titre Lato Bold 18px, corps Lato 16px multi-paragraphe)
  Et le conteneur porte `data-section="{{ block.id }}" data-section-type="text"`
  Et chaque champ (title/subtitle/content) porte son propre `data-editable`/`data-field`
```

### Scénario 4: Rendu du bloc texte+image (gauche et droite) avec position mobile indépendante
```gherkin
Scénario: Un seul partial gère les deux variantes desktop et la position mobile indépendante
  Étant donné un bloc de type "text-image-left" avec `mobileImagePosition = "after"`
  Quand `_actualite-block-text-image.html.twig` est rendu avec `imagePosition: 'left'` et `mobileImagePosition: 'after'`
  Alors la disposition desktop place l'image à gauche (classe `actualite-block--image-left`)
  Et l'ordre d'affichage mobile place l'image après le texte, indépendamment de la variante desktop
  Et un bloc "text-image-right" avec `mobileImagePosition = "before"` produit le miroir correct côté desktop tout en respectant sa propre position mobile
  Et aucune balise de CTA ("Découvrir en detail") n'est présente dans le rendu (Décision #5), avec un commentaire de code notant l'évolution future possible
```

### Scénario 5: Dispatch des blocs dans l'ordre stocké
```gherkin
Scénario: Les blocs sont rendus dans l'ordre exact du tableau content.blocks
  Étant donné un article avec 4 blocs mélangeant les 3 types dans un ordre arbitraire
  Quand la page est rendue
  Alors les 4 blocs apparaissent dans le DOM exactement dans l'ordre de `content.blocks`
  Et chaque bloc respecte son propre `mobileImagePosition` indépendamment des autres
  Et une page avec 0 bloc ne produit aucune erreur de rendu
```

### Scénario 6: Section "related posts" (Autres news à découvrir)
```gherkin
Scénario: La section related-posts affiche 0, 1 ou 2 cartes selon la disponibilité
  Étant donné un article ayant à la fois un `previousPost` et un `nextPost`
  Quand `_actualite-related-posts.html.twig` est rendu
  Alors 2 cartes s'affichent, chacune avec image, pilule(s) de tag, date, titre (Lato Bold 24px), et séparateur bas
  Étant donné un article n'ayant qu'un seul voisin (premier ou dernier article publié)
  Quand la section est rendue
  Alors une seule carte s'affiche
  Étant donné un article sans aucun voisin (seul article publié)
  Quand la section est rendue
  Alors aucune carte ne s'affiche, mais le titre de section reste visible

Scénario: Le titre de la section a une valeur par défaut éditable
  Étant donné qu'aucune valeur n'a été saisie pour le titre de la section related-posts
  Quand la page est rendue (mode édition ou non)
  Alors le titre affiché est "Autres news à découvrir" par défaut (pattern de fallback déjà en place ailleurs dans le codebase)
  Et le titre reste éditable via `data-editable`/`data-field` en mode édition
```

### Scénario 7: SCSS BEM et responsive
```gherkin
Scénario: Les styles suivent la méthodologie BEM et gèrent le responsive par bloc
  Étant donné les fichiers `assets/styles/pages/_actualite.scss`, `assets/styles/components/_actualite-block.scss` et `assets/styles/components/_tag-pill.scss`
  Quand ils sont compilés via Webpack Encore
  Alors les classes suivent la nomenclature BEM (`.actualite-block`, `.actualite-block--text-only`, `.actualite-block--image-left`, `.actualite-block--mobile-image-before`, `.actualite-block--mobile-image-after`, etc.)
  Et le comportement mobile 50/50 → empilé utilise une classe modificatrice par bloc (pas une règle globale unique), pour respecter l'indépendance de `mobileImagePosition` par bloc (Décision #6)
  Et `.tag-pill` est un composant partagé réutilisable dans l'en-tête, les cartes related-posts et le futur picker admin (vérification préalable qu'aucun composant `.tag`/`.badge` existant ne fait déjà doublon)
  Et le titre utilise les tokens de typographie existants (`--font-serif`/variables heading-36) plutôt que des valeurs codées en dur, si ces tokens existent déjà dans `_typography.scss`
```
