diff --git a/article-v2.md b/article-v2.md
new file mode 100644
index 0000000..72747d0
--- /dev/null
+++ b/article-v2.md
@@ -0,0 +1,225 @@
+# Un frontend simple et efficace grâce aux Twig Components et à Tailwind CSS : une combinaison gagnante pour un monolithe Symfony
+
+Symfony, avec Twig pour le templating, reste un choix incontournable dans l’écosystème PHP, tandis que Tailwind CSS s’est imposé comme un des leader des framework CSS. Associés, ces outils apportent des synergies intéressantes pour moderniser votre frontend.
+
+## Pourquoi associer Tailwind CSS et Twig Components ?
+
+Symfony est réputé comme un solide framework backend, et son écosystème frontend a considérablement évolué. Avec la suite Symfony UX, le framework offre désormais des approches intéressantes pour le développement frontend. Twig, le moteur de templates, présente des avantages et des inconvénients comme tout moteur de template, mais il reste un choix solide pour structurer vos vues. De plus, Tailwind CSS permet un stylage rapide et cohérent grâce à ses classes utilitaires.
+
+Les Twig Components sont introduits pour encourager la réutilisabilité et la clarté dans les vues, et peuvent s’intégrer harmonieusement avec Tailwind CSS. Tailwind, en permettant de déclarer le style directement dans le DOM, facilite la mise en forme rapide des composants Twig. En associant les deux, on peut encapsuler à la fois la structure et l'UI d'un composant. De plus, avec les class components, il est aussi possible d'encapsuler le comportement du composant. Ainsi, on peut réutiliser le tout à notre guise dans notre application pour gagner en productivité et en cohérence.
+
+## Présentation rapide des outils
+
+Avant d’explorer leurs synergies, voici un rappel des fonctionnalités principales de chaque outil :
+
+### Twig Components
+
+Twig Components sont une évolution apporté dans Symfony UX, permettant de structurer vos templates en composants réutilisables.
+
+- **Anonymous Components** : simples et sans logique, juste un template Twig.
+- **Class Components** : pour les composants plus complexes, avec des méthodes et des propriétés. Une classe PHP associée à un template Twig.
+
+Il existe aussi les **Live Components**, qui permettent de mettre à jour dynamiquement le DOM. Si vous voulez en savoir plus, je vous invite à consulter [Symfony UX Live Components Documentation](https://symfony.com/bundles/ux-live-component/current/index.html)
+
+### Tailwind CSS
+
+Tailwind CSS est un framework CSS utility-first. Contrairement aux frameworks CSS traditionnels (comme *Bootstrap*), il favorise l’utilisation de classes utilitaires qui permettent un stylage rapide et sans limites. Il est particulièrement apprécié pour sa flexibilité et son écosystème.
+
+Totalement customisable grace à son fichier de configuration `tailwind.config.js`, Tailwind CSS permet de personnaliser les couleurs, les tailles, les polices, etc. Une bonne configuration est un atout pour une utilisation efficace de Tailwind.
+
+## Synergies entre Twig Components et Tailwind CSS
+
+### Anonymous Components
+
+Prenons un exemple simple, un bouton avec des variantes de couleurs et de tailles.
+
+Il existe un approche appelée **CVA** (*Class Variant Authority*), qui centralise la gestion des classes CSS conditionnelles, rendant vos composants modulaires, faciles à faire évoluer et à maintenir. Initialement popularisé dans le monde JavaScript, elle est désormait disponible dans Twig !
+
+```twig
+{# templates/components/button.html.twig #}
+
+{% props as = 'button', variant = 'default', size = 'default' %}
+
+{% set buttonVariants = cva({
+ base: 'inline-flex items-center justify-center gap-2 w-fit whitespace-nowrap rounded-md text-sm font-medium transition-colors',
+ variants: {
+ variant: {
+ default: 'bg-primary text-primary-foreground hover:bg-primary/90',
+ secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
+ },
+ size: {
+ default: 'h-10 px-4 py-2',
+ lg: 'h-12 rounded-md px-8',
+ }
+ },
+ defaultVariants: {
+ variant: 'default',
+ size: 'default',
+ }
+}) %}
+
+<{{ as }} {{ attributes.without('class') }}
+ class="{{ buttonVariants.apply({variant, size}, attributes.render('class'))|tailwind_merge }}"
+>
+ {% block content '' %}
+{{ as }}>
+```
+
+Voici notre composant bouton qui accepte trois props : `as`, `variant`, et `size`. Cette approche de composant dite "polymorphic" permet de rendre par défaut le composant comme une balise `button`, mais vous pouvez le changer en `a`, ou autre en passant le tag HTML voulu via la props `as`.
+
+#### Usage
+
+```twig
+Découvrir KNPlabs
+```
+
+#### Rendu HTML
+
+```html
+
+ Découvrir KNPlabs
+
+```
+
+*Retrouvez un autre exemple d'utilisation pour les headings sur notre [repo de démonstration](https://github.com/KnpLabs/symfony-tailwind-twig-components/blob/main/templates/components/heading.html.twig)*
+
+#### Bonus `tailwind_merge`
+
+Notez ici l'utiliation du filtre `tailwind_merge` qui permet de fusionner les classes Tailwind en doublon ou conflit quand vous surchargez les classes de vos composants.
+
+```twig
+Rouge KNPlabs
+```
+
+Rendu HTML:
+
+```html
+
+ Rouge KNPlabs
+
+```
+
+Au lieu d'avoir des classes en conflit `bg-primary` et `bg-red-500`, le filtre `tailwind_merge` fusionne les classes en doublon pour n'avoir que `bg-red-500` car on a surcharger la class de notre composant. Et on aura comme résultat un bouton rouge.
+
+*Filtre issue du bundle [tales-from-a-dev/twig-tailwind-extra: 🌱 A Twig extension for Tailwind](https://github.com/tales-from-a-dev/twig-tailwind-extra)*
+
+### Class Components
+
+Vous pouvez aussi créer des composants avec des classes PHP, pour des cas plus complexes nécessitant une certaine logique.
+
+Prenons un exemple simple de formatage d'un prix. Imaginons que votre contrôleur vous renvoie un prix, et que vous voulez l'afficher en euros. Par exemple, `1234` (on stock les prix en centime) devrait être affiché comme `12,34 €`.
+
+Vous pouvez créer un Twig Component avec une classe PHP et un template pour gerer le rendu. Ce composant acceptera des propriétés `price` et `locale`, et expose une méthode `formatPrice`.
+
+```php
+locale, NumberFormatter::CURRENCY);
+ return $formatter->formatCurrency($this->price / 100, 'EUR');
+ }
+}
+```
+
+Dans cet exemple, l'attributes `#[AsTwigComponent('product:price')]` définit le nom du composant, qui sera automatiquement lié au fichier `templates/components/product/price.html.twig`. Voici à quoi pourrait ressembler le template Twig stylisé avec Tailwind :
+
+```twig
+
+ {{ this.formatPrice }}
+
+```
+
+Dans ce template, la méthode `formatPrice` est appelée via `this.formatPrice`
+
+#### Usage
+
+```twig
+
+```
+
+#### Rendu HTML
+
+```html
+
+ 12,34 €
+
+```
+
+##### Bonus: Testez vos composants
+
+Vous pouvez tester vos composants Twig avec PHPUnit avec une simplicité déconcertante. Voici un exemple de test pour notre composant `Price`.
+
+```php
+mountTwigComponent(
+ name: Price::class,
+ data: ['price' => 9999, 'locale' => 'fr_FR'],
+ );
+
+ $this->assertInstanceOf(Price::class, $component);
+ $this->assertSame(9999, $component->price);
+ $this->assertSame('fr_FR', $component->locale);
+ }
+
+ public function testComponentRenders(): void
+ {
+ $rendered = $this->renderTwigComponent(
+ name: Price::class,
+ data: ['price' => 9999, 'locale' => 'fr_FR'],
+ );
+
+ $this->assertStringContainsString('99,99 €', $rendered);
+ }
+}
+```
+
+Et voilà rien de plus compliqué que ca pour tester vos composants Twig. On test le montage du composant et on test le rendu du composant, tout simplement.
+
+## Limites
+
+1. **Lisibilité du code**
+
+ L'abondance de classes Tailwind dans un même fichier peut rendre les templates volumineux difficiles à lire. Une bonne connaissances des utilities de Tailwind est nécessaire pour préserver une bonne lisibilité.
+ De plus les Twig Components introduisent une nouvelle syntaxe qui peut être un peu déroutante au début mais reste très proche du HTML.
+
+2. **Courbe d’apprentissage**
+
+ Bien que Tailwind soit facile à utiliser, sa logique utility-first peut dérouter les nouveaux développeurs habitués aux approches basées sur CSS traditionnel.
+ Tailwind reste relativement simple à apprendre et la documentation est très bien faite.
+
+## Conclusion
+
+Associer Twig Components et Tailwind CSS peut grandement moderniser votre workflow de développement frontend avec Symfony. Ces outils se complètent parfaitement : Twig apporte une structure modulaire, tandis que Tailwind accélère le stylage.
+
+Cependant, leur utilisation nécessite une bonne organisation et une compréhension des limites pour tirer pleinement parti de leurs synergies. Cette combinaison convient particulièrement aux équipes qui cherchent une approche moderne et modulable un peu à la manière des composants React.
+
+Pour les plus curieux, vous pouvez retrouver un exemple de cette stack sur notre [repo de demonstration](https://github.com/KnpLabs/symfony-tailwind-twig-components).
+
+Et vous ? Avez-vous déjà essayé cette stack ? Partagez vos retours d’expérience ou posez vos questions dans les commentaires !
diff --git a/blog-article.md b/blog-article.md
new file mode 100644
index 0000000..9d08806
--- /dev/null
+++ b/blog-article.md
@@ -0,0 +1,298 @@
+# Modernisez vos applications Symfony avec Tailwind et Twig Components
+
+Symfony est depuis longtemps un incontournable pour développer des applications web PHP. Mais qu’en est-il du frontend ? Grâce à Tailwind CSS et aux Twig Components, vous pouvez transformer vos interfaces en un rien de temps tout en restant organisé et maintenable. Dans cet article, découvrez comment combiner ces trois outils pour créer des applications Symfony à la fois modernes et élégantes.
+
+## Prérequis
+
+Une application Symfony >= 6.3 et Twig >= 3.0. Voir la documentation officielle : [Installing & Setting up the Symfony Framework (Symfony Docs)](https://symfony.com/doc/current/setup.html).
+
+Dans cet article, nous utiliserons une app Symfony 7.1 avec Symfony AssetMapper. Pas besoin d'installer Webpack Encore (bien que totalement compatible), ce qui simplifie l'installation.
+
+## Installation
+
+```bash
+composer require symfony/asset-mapper symfony/twig-bundle symfony/ux-twig-component
+```
+
+Ceci installe les dépendances nécessaires pour utiliser les Twig Components.
+
+Ensuite, il faut installer Tailwind CSS :
+
+```bash
+composer require symfonycasts/tailwind-bundle tales-from-a-dev/twig-tailwind-extra
+php bin/console tailwind:init
+```
+
+Le fichier `tailwind.config.js` sera créé à la racine de votre projet. Une bonne configuration de Tailwind est essentielle pour une utilisation optimale.
+
+## Utilisation
+
+Incluez le CSS de Tailwind dans le template de base :
+
+```twig
+{# templates/base.html.twig #}
+{% block stylesheets %}
+
+{% endblock %}
+```
+
+En développement, utilisez :
+
+```bash
+php bin/console tailwind:build --watch
+```
+
+Plus d'infos dans la [documentation officielle du bundle Tailwind.](https://symfony.com/bundles/TailwindBundle/current/index.html)
+
+```twig
+{# templates/default.html.twig #}
+{% extends 'base.html.twig' %}
+{% block body %}
+
+
Accueil
+
Bienvenue chez KNPlabs !
+
+{% endblock %}
+```
+
+## Configuration avancée
+
+Tailwind est extrêmement flexible. Vous pouvez personnaliser les couleurs, polices, tailles, etc., dans le fichier `tailwind.config.js`. Par exemple, définissez la classe `container` pour centrer le contenu et ajouter du padding différents selon les tailles d’écran :
+
+```js
+theme: {
+ container: {
+ center: true,
+ padding: {
+ DEFAULT: '1rem',
+ lg: '2rem',
+ },
+ },
+},
+```
+
+Ajoutez des couleurs personnalisées, radius, etc. dans la clé `extend` :
+
+```js
+extend: {
+ colors: {
+ background: "#ffffff",
+ foreground: "#020817",
+ primary: {
+ DEFAULT: "#0f172a",
+ foreground: "#f8fafc",
+ },
+ secondary: {
+ DEFAULT: "#f1f5f9",
+ foreground: "#0f172a",
+ },
+ },
+ borderRadius: {
+ lg: "0.6rem",
+ md: "0.4rem",
+ },
+},
+```
+
+Vous pouvez retrouver une configuration plus complète dans notre [repo de démonstration](https://github.com/KnpLabs/symfony-tailwind-twig-components/blob/main/tailwind.config.js).
+
+## Twig Components
+
+Twig Components, un composant Symfony, permet de créer des composants réutilisables dans vos templates Twig. Ces composants peuvent être :
+
+- Anonymes (Anonymous Twig Component) : fichiers Twig simples dédiés à l’UI.
+- Avec logique (Live Twig Component) : classes PHP pour des composants plus complexes, avec un template Twig associé.
+
+### Anonymous Twig Component et approche CVA
+
+Avec Twig Components, vous pouvez gérer les variantes de style CSS grâce à **CVA** (*Class Variant Authority*).
+
+Le CVA centralise la gestion des classes CSS conditionnelles, rendant vos composants modulaires et faciles à maintenir. Initialement popularisé dans le monde JavaScript, il est désormais disponible dans Twig !
+
+Voici un exemple de création d’un bouton avec variantes :
+
+```twig
+{# templates/components/button.html.twig #}
+
+{% props as = 'button', variant = 'default', size = 'default' %}
+
+{% set buttonVariants = cva({
+ base: 'inline-flex items-center justify-center gap-2 w-fit whitespace-nowrap rounded-md text-sm font-medium transition-colors',
+ variants: {
+ variant: {
+ default: 'bg-primary text-primary-foreground hover:bg-primary/90',
+ secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
+ },
+ size: {
+ default: 'h-10 px-4 py-2',
+ lg: 'h-12 rounded-md px-8',
+ }
+ },
+ defaultVariants: {
+ variant: 'default',
+ size: 'default',
+ }
+}) %}
+
+<{{ as }} {{ attributes.without('class') }}
+ class="{{ buttonVariants.apply({variant, size}, attributes.render('class'))|tailwind_merge }}"
+>
+ {% block content '' %}
+{{ as }}>
+```
+
+Voici notre composant bouton qui accepte trois props : `as`, `variant`, et `size`. Cette approche de composant dite "polymorphic" permet de rendre par défaut le composant comme une balise `button`, mais vous pouvez le changer en `a`, `div`, ou autre en passant la prop `as`.
+
+#### Usage
+
+```twig
+Découvrir KNPlabs
+```
+
+#### Rendu HTML
+
+```html
+
+ Découvrir KNPlabs
+
+```
+
+*Retrouvez un autre cas d'utilisation pour les headings sur notre [repo de démonstration](https://github.com/KnpLabs/symfony-tailwind-twig-components/blob/main/templates/components/heading.html.twig)*
+
+##### Bonus: Tailwind Merge
+
+Le filtre `tailwind_merge` permet de fusionner les classes CSS de manière intelligente. Par exemple, si vous surchager votre composant avec d'autre classes Tailwind en doublon ou en conflict, `tailwind_merge` les fusionnera et appliquera le style surchager en dernier. Cela évite l'utilisation pas très propre du `!` devant vos classes Tailwind.
+
+```twig
+Rouge KNPlabs
+```
+
+Rendu HTML:
+
+```html
+
+ Rouge KNPlabs
+
+```
+
+### Live Twig Components
+
+Comme je le disais, vous pouvez aussi créer des composants avec des classes PHP, pour des cas plus complexes nécessitant une certaine logique.
+
+Prenons un exemple très simple de formatage d'un prix. Imaginons que votre contrôleur vous renvoie un prix, et que vous voulez l'afficher en euros. Par exemple, `12.34` devrait être affiché comme `12,34 €`.
+
+Vous pouvez créer un Live Twig Component. Ce composant acceptera des propriétés `price` et `locale`, et expose une méthode `formatPrice`.
+
+```php
+locale, NumberFormatter::CURRENCY);
+ return $formatter->formatCurrency($this->price, 'EUR');
+ }
+}
+```
+
+Dans cet exemple, le attributes `#[AsTwigComponent('product:price')]` définit le nom du composant, qui sera automatiquement lié au fichier `templates/components/product/price.html.twig`. Voici à quoi pourrait ressembler le template Twig :
+
+```twig
+
+ {{ this.formatPrice }}
+
+```
+
+Dans ce template, la méthode `formatPrice` est appelée via `this.formatPrice`, permettant ainsi d'afficher le prix formaté de manière propre et réutilisable dans votre application.
+
+#### Pourquoi utiliser cette approche ?
+
+Avec cette approche, vous pouvez :
+
+- **Séparer la logique du rendu** : La méthode `formatPrice` encapsule la logique de formatage.
+- **Tirer parti de la puissance de PHP** : Vous avez accès à toutes les fonctionnalités de PHP pour construire vos composants, comme ici avec `NumberFormatter`.
+
+Fini les Twig Extension qui retournent du HTML. Grâce à cette méthode, vous obtenez des composants puissants, clairs et réutilisables.
+
+#### Exemple d'utilisation
+
+Voici comment intégrer ce composant dans un template Twig :
+
+```twig
+
+```
+
+Rendu HTML :
+
+```html
+
+ 19,99 €
+
+```
+
+##### Bonus: Testez vos composants
+
+Vous pouvez tester vos composants Twig avec PHPUnit avec une simplicité déconcertante. Voici un exemple de test pour notre composant `Price`.
+
+```php
+mountTwigComponent(
+ name: Price::class,
+ data: ['price' => 99.99, 'locale' => 'fr_FR'],
+ );
+
+ $this->assertInstanceOf(Price::class, $component);
+ $this->assertSame(99.99, $component->price);
+ $this->assertSame('fr_FR', $component->locale);
+ }
+
+ public function testComponentRenders(): void
+ {
+ $rendered = $this->renderTwigComponent(
+ name: Price::class,
+ data: ['price' => 99.99, 'locale' => 'fr_FR'],
+ );
+
+ $this->assertStringContainsString('99,99 €', $rendered); // Notez l'espace insécable entre le montant et le symbole de l'euro
+ }
+}
+```
+
+Et voilà rien de plus compliqué que ca pour tester nos composants Twig. On test le mount du composant et on test le rendu du composant, tout simplement.
+
+## Limites
+
+- **Lisibilité du Code** : Twig peut parfois rendre le code plus verbeux, surtout avec des composants complexes ou lorsque plusieurs niveaux de composants sont imbriqués. La syntaxe de Twig n'est pas toujours la plus concise et peut rendre le DOM final difficile à appréhender, surtout pour les développeurs non familiers avec cette approche. Par exemple, l'utilisation de directives Twig à l’intérieur des attributs HTML pour manipuler des classes, des styles, etc., peut rapidement rendre le code difficile à lire.
+
+- **Utilisation de Twig Extension vs Twig Components** : Twig permet créer des extensions ce qui peut simplifier certaines tâches. Additionné avec des Twig Components, Anonymous ou/et Live, cela peut créer un soucis d'harmonisation dans votre codebase.
+
+## Conclusion
+
+L’utilisation de Twig Components avec Tailwind CSS est une approche puissante et moderne pour développer le frontend d'un monolithe Symfony. Certes, cette méthodologie a ses limites, comme la lisibilité parfois complexe du DOM due aux (parfois) nombreuses classes Tailwind et à Twig qui peut parfois rendre le code plus verbeux, ou bien la nécessité de trouver un équilibre entre logique PHP et Twig. Cependant, cela peut être surmontés avec une bonne organisation, un découpage rigoureux des composants et des conventions claires.
+
+Suite à notre expérience, nous sommes pleinement satisfaits de cette approche. Elle nous a permis d'intégrer nos maquettes de plus en plus rapidement et efficacement grâce à une bibliothèque de composants que nous avons enrichie au fil du projet. Le gain de productivité apporté par Tailwind CSS, simplifie et nous a aidé à accélèrer le stylage de nos composants et du reste de notre interface. En somme, cette combinaison s'est révélée être un excellent choix pour nos besoins.
diff --git a/src/Twig/Components/Price.php b/src/Twig/Components/Price.php
index 46c82d3..63a2287 100644
--- a/src/Twig/Components/Price.php
+++ b/src/Twig/Components/Price.php
@@ -13,7 +13,7 @@ final class Price
public float $price;
public string $locale = 'en_US';
- public function getFormatPrice(): string
+ public function formatPrice(): string
{
$formatter = new NumberFormatter($this->locale, NumberFormatter::CURRENCY);
return $formatter->formatCurrency($this->price, 'USD');
diff --git a/tailwind.config.js b/tailwind.config.js
index 6cd8b03..a6e7ea7 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -1,6 +1,5 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
- darkMode: ["class"],
content: [
"./assets/**/*.js",
"./templates/**/*.html.twig",
diff --git a/templates/base.html.twig b/templates/base.html.twig
index 4fdf386..2c0d71b 100644
--- a/templates/base.html.twig
+++ b/templates/base.html.twig
@@ -4,11 +4,11 @@
Tailwind + Twig Components
- {% block javascripts %}
- {% block importmap %}{{ importmap('app') }}{% endblock %}
+ {% block stylesheets %}
+
{% endblock %}
-
+
{% block body %}{% endblock %}