Pagefind - Recherche Statique pour le Blog
🎯 Qu’est-ce que Pagefind ?
Pagefind est un outil de recherche statique ultra-performant qui remplace Fuse.js sur notre blog. Il génère un index de recherche au moment du build (via GitHub Actions), ce qui offre :
- ✅ Performance : Index créé au build-time, pas de chargement runtime
- ✅ Full-text search : Recherche dans tout le contenu des articles
- ✅ Léger : Chargement progressif des fragments d’index
- ✅ Multilingue : Support natif FR/EN
- ✅ SEO-friendly : Fonctionne avec le contenu statique généré
📦 Installation et Configuration
1. Workflow GitHub Actions
Le fichier .github/workflows/jekyll.yml a été modifié pour inclure :
- name: Install Pagefind
run: |
echo "📦 Installation de Pagefind pour l'indexation de recherche..."
npm install -g pagefind
echo "✅ Pagefind installé avec succès"
- name: Build Pagefind index
run: |
echo "🔍 Génération de l'index de recherche Pagefind..."
npx pagefind --site _site --output-path _site/pagefind
echo "✅ Index Pagefind généré avec succès"
2. Configuration Pagefind
La configuration se fait directement dans le workflow via les options CLI :
npx pagefind --site _site \
--output-path _site/pagefind \
--glob "**/*.html" \
--exclude-selectors ".social-sharing-section, .post-meta, nav, footer, .breadcrumb" \
--force-language fr \
--verbose
Options utilisées :
--site _site: Répertoire du site généré par Jekyll--output-path _site/pagefind: Où sauvegarder l’index--glob "**/*.html": Indexer tous les fichiers HTML--exclude-selectors: Éléments à ne pas indexer (navigation, metadata, etc.)--force-language fr: Langue principale (français)--verbose: Logs détaillés pour debugging
3. Attributs HTML pour l’indexation optimale
Les articles utilisent des attributs avancés pour une indexation riche :
Attributs utilisés :
data-pagefind-body: Marque le contenu principal à indexerdata-pagefind-meta: Métadonnées extractibles (titre, date, auteur, excerpt)data-pagefind-filter: Filtres pour catégories, tags, languedata-pagefind-ignore: Exclut certaines sections (partage social, navigation, etc.)
Exemple optimisé dans _layouts/post.html :
<article class="post-page"
data-pagefind-body
data-pagefind-meta="title:Pagefind - Recherche Statique pour le Blog"
data-pagefind-meta="date:"
data-pagefind-meta="author:Nicolas Dabène"
data-pagefind-meta="excerpt:"
data-pagefind-filter="category:"
data-pagefind-filter="tags:"
data-pagefind-filter="lang:fr">
<h1 class="post-title">Pagefind - Recherche Statique pour le Blog</h1>
<div class="post-meta" data-pagefind-ignore>
<!-- Metadata non indexée -->
</div>
<article class="post-content" data-pagefind-body>
<div class="page-header">
<div class="container">
<h1>Charte Graphique - ndabene.github.io</h1>
<nav class="breadcrumb">
<a href="/">Home</a>
<span>Charte Graphique - ndabene.github.io</span>
</nav>
</div>
</div>
<div class="container page-content">
<div class="main-content">
<h1 id="charte-graphique---ndabenegithubio">Charte Graphique - ndabene.github.io</h1>
<h2 id="table-des-matières">Table des matières</h2>
<ol>
<li><a href="#palette-de-couleurs">Palette de couleurs</a></li>
<li><a href="#typographie">Typographie</a></li>
<li><a href="#espacements-et-layout">Espacements et Layout</a></li>
<li><a href="#composants-ui">Composants UI</a></li>
<li><a href="#animations">Animations</a></li>
<li><a href="#breakpoints-responsive">Breakpoints Responsive</a></li>
<li><a href="#ombres-et-effets">Ombres et Effets</a></li>
</ol>
<hr />
<h2 id="1-palette-de-couleurs">1. Palette de couleurs</h2>
<h3 id="couleurs-de-base">Couleurs de base</h3>
<p>| Nom | Hex | Usage |
|—–|—–|——-|
| Blanc pur | <code class="language-plaintext highlighter-rouge">#FFFFFF</code> | Fond principal, éléments clairs |
| Noir journal | <code class="language-plaintext highlighter-rouge">#111827</code> | Texte principal |
| Gris anthracite | <code class="language-plaintext highlighter-rouge">#1E293B</code> | Texte secondaire, surfaces |
| Gris ardoise | <code class="language-plaintext highlighter-rouge">#475569</code> | Texte tertiaire |
| Gris clair | <code class="language-plaintext highlighter-rouge">#E2E8F0</code> | Bordures, séparateurs |
| Fond papier léger | <code class="language-plaintext highlighter-rouge">#FAFAFA</code> | Sections alternées |</p>
<h3 id="couleurs-primaires">Couleurs primaires</h3>
<p>| Nom | Hex | Usage |
|—–|—–|——-|
| Marine profond | <code class="language-plaintext highlighter-rouge">#0F172A</code> | Couleur primaire principale |
| Marine très sombre | <code class="language-plaintext highlighter-rouge">#020617</code> | Variante sombre de la primaire |</p>
<h3 id="couleurs-secondaires">Couleurs secondaires</h3>
<p>| Nom | Hex | Usage |
|—–|—–|——-|
| Gris anthracite | <code class="language-plaintext highlighter-rouge">#1E293B</code> | Couleur secondaire |
| Noir journal | <code class="language-plaintext highlighter-rouge">#111827</code> | Texte principal |
| Gris lecture | <code class="language-plaintext highlighter-rouge">#374151</code> | Texte léger |</p>
<h3 id="couleurs-daccentuation">Couleurs d’accentuation</h3>
<p>| Nom | Hex | Usage |
|—–|—–|——-|
| Or sourd | <code class="language-plaintext highlighter-rouge">#D4AF37</code> | Achievements, badges premium |
| Vert technique | <code class="language-plaintext highlighter-rouge">#059669</code> | Validations, succès |</p>
<h3 id="couleurs-de-feedback">Couleurs de feedback</h3>
<p>| Nom | Hex | Usage |
|—–|—–|——-|
| Vert technique | <code class="language-plaintext highlighter-rouge">#059669</code> | Messages de succès |
| Rouge professionnel | <code class="language-plaintext highlighter-rouge">#DC2626</code> | Erreurs |
| Or sourd | <code class="language-plaintext highlighter-rouge">#D4AF37</code> | Avertissements |</p>
<h3 id="couleurs-spécifiques-aux-tags-tech">Couleurs spécifiques aux tags tech</h3>
<p>| Nom | Hex | Usage |
|—–|—–|——-|
| PrestaShop | <code class="language-plaintext highlighter-rouge">#DF3163</code> | Tag PrestaShop |
| API | <code class="language-plaintext highlighter-rouge">#0F172A</code> | Tag API (primaire) |
| Integration | <code class="language-plaintext highlighter-rouge">#059669</code> | Tag intégration |
| E-commerce | <code class="language-plaintext highlighter-rouge">#F59E0B</code> | Tag e-commerce |</p>
<h3 id="gradients">Gradients</h3>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Gradient primaire</span>
<span class="nt">linear-gradient</span><span class="o">(</span><span class="nt">135deg</span><span class="o">,</span> <span class="nn">#0F172A</span> <span class="nt">0</span><span class="nv">%</span><span class="o">,</span> <span class="nn">#1E293B</span> <span class="nt">100</span><span class="nv">%</span><span class="o">)</span>
<span class="o">//</span> <span class="nt">Gradient</span> <span class="nt">hero</span>
<span class="nt">linear-gradient</span><span class="o">(</span><span class="nt">135deg</span><span class="o">,</span> <span class="nn">#FFFFFF</span> <span class="nt">0</span><span class="nv">%</span><span class="o">,</span> <span class="nn">#FAFAFA</span> <span class="nt">100</span><span class="nv">%</span><span class="o">)</span>
<span class="o">//</span> <span class="nt">Gradient</span> <span class="nt">or</span>
<span class="nt">linear-gradient</span><span class="o">(</span><span class="nt">135deg</span><span class="o">,</span> <span class="nn">#D4AF37</span> <span class="nt">0</span><span class="nv">%</span><span class="o">,</span> <span class="nn">#B8941F</span> <span class="nt">100</span><span class="nv">%</span><span class="o">)</span>
</code></pre></div></div>
<hr />
<h2 id="2-typographie">2. Typographie</h2>
<h3 id="familles-de-polices">Familles de polices</h3>
<h4 id="police-principale-corps-de-texte">Police principale (corps de texte)</h4>
<ul>
<li><strong>Nom</strong>: Inter</li>
<li><strong>Poids disponibles</strong>: 400, 500, 600, 700, 900</li>
<li><strong>Import Google Fonts</strong>:
```html</li>
</ul>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;900&display=swap" rel="stylesheet" />
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
#### Police des titres
- **Nom**: Poppins
- **Poids disponibles**: 600, 700, 800, 900
- **Import Google Fonts**:
```html
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@600;700;800;900&display=swap" rel="stylesheet">
</code></pre></div></div>
<h4 id="police-monospace">Police monospace</h4>
<ul>
<li><strong>Nom</strong>: JetBrains Mono</li>
<li><strong>Usage</strong>: Code, données techniques</li>
</ul>
<h3 id="échelle-typographique">Échelle typographique</h3>
<p>| Élément | Taille | Poids | Hauteur de ligne |
|———|——–|——-|——————|
| H1 | 40px (2.5rem) | 700 | 1.3 |
| H2 | 32px (2rem) | 700 | 1.3 |
| H3 | 24px (1.5rem) | 700 | 1.3 |
| H4 | 20px (1.25rem) | 700 | 1.3 |
| Corps de texte | 16px (1rem) | 400 | 1.6 |
| Texte large | 18px (1.125rem) | 400 | 1.6 |
| Texte petit | 14px (0.875rem) | 400 | 1.6 |
| Texte extra-petit | 12px (0.75rem) | 400 | 1.6 |</p>
<h3 id="poids-de-police">Poids de police</h3>
<p>| Nom | Valeur |
|—–|——–|
| Regular | 400 |
| Medium | 500 |
| Semi-bold | 600 |
| Bold | 700 |
| Black | 900 |</p>
<hr />
<h2 id="3-espacements-et-layout">3. Espacements et Layout</h2>
<h3 id="système-despacement-basé-sur-8px">Système d’espacement (basé sur 8px)</h3>
<p>| Nom | Valeur | Usage |
|—–|——–|——-|
| xs | 4px (0.25rem) | Espacement minimal |
| sm | 8px (0.5rem) | Petit espacement |
| md | 16px (1rem) | Espacement standard |
| lg | 24px (1.5rem) | Grand espacement |
| xl | 32px (2rem) | Très grand espacement |
| 2xl | 40px (2.5rem) | Espacement extra-large |
| 3xl | 48px (3rem) | Espacement entre sections |
| 4xl | 64px (4rem) | Espacement très large |</p>
<h3 id="conteneur">Conteneur</h3>
<ul>
<li><strong>Largeur maximale</strong>: 1200px</li>
<li><strong>Padding latéral</strong>: 24px (1.5rem)</li>
<li><strong>Padding mobile</strong>: 16px (1rem)</li>
</ul>
<h3 id="grilles">Grilles</h3>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Grille 2 colonnes</span>
<span class="na">grid-template-columns</span><span class="p">:</span> <span class="nf">repeat</span><span class="p">(</span><span class="m">2</span><span class="o">,</span> <span class="m">1fr</span><span class="p">);</span>
<span class="na">gap</span><span class="p">:</span> <span class="m">32px</span><span class="p">;</span>
<span class="c1">// Grille 3 colonnes</span>
<span class="na">grid-template-columns</span><span class="p">:</span> <span class="nf">repeat</span><span class="p">(</span><span class="m">3</span><span class="o">,</span> <span class="m">1fr</span><span class="p">);</span>
<span class="na">gap</span><span class="p">:</span> <span class="m">32px</span><span class="p">;</span>
</code></pre></div></div>
<hr />
<h2 id="4-composants-ui">4. Composants UI</h2>
<h3 id="boutons">Boutons</h3>
<h4 id="bouton-primaire">Bouton primaire</h4>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">background</span><span class="p">:</span> <span class="mh">#0F172A</span><span class="p">;</span>
<span class="nl">color</span><span class="p">:</span> <span class="mh">#FFFFFF</span><span class="p">;</span>
<span class="nl">padding</span><span class="p">:</span> <span class="m">1rem</span> <span class="m">2rem</span><span class="p">;</span>
<span class="nl">border-radius</span><span class="p">:</span> <span class="m">8px</span><span class="p">;</span>
<span class="nl">font-weight</span><span class="p">:</span> <span class="m">600</span><span class="p">;</span>
<span class="nl">transition</span><span class="p">:</span> <span class="n">all</span> <span class="m">0</span><span class="mi">.3s</span> <span class="n">ease-in-out</span><span class="p">;</span>
<span class="c1">// Hover</span>
<span class="nl">background</span><span class="p">:</span> <span class="mh">#020617</span><span class="p">;</span>
<span class="nl">transform</span><span class="p">:</span> <span class="nf">translateY</span><span class="p">(</span><span class="m">-2px</span><span class="p">);</span>
<span class="nl">box-shadow</span><span class="p">:</span> <span class="m">0</span> <span class="m">10px</span> <span class="m">20px</span> <span class="nf">rgba</span><span class="p">(</span><span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="mi">.15</span><span class="p">);</span>
</code></pre></div></div>
<h4 id="bouton-secondaire">Bouton secondaire</h4>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">background</span><span class="p">:</span> <span class="mh">#FFFFFF</span><span class="p">;</span>
<span class="nl">color</span><span class="p">:</span> <span class="mh">#0F172A</span><span class="p">;</span>
<span class="nl">border</span><span class="p">:</span> <span class="m">1px</span> <span class="nb">solid</span> <span class="mh">#E2E8F0</span><span class="p">;</span>
<span class="nl">padding</span><span class="p">:</span> <span class="m">1rem</span> <span class="m">2rem</span><span class="p">;</span>
<span class="nl">border-radius</span><span class="p">:</span> <span class="m">8px</span><span class="p">;</span>
</code></pre></div></div>
<h4 id="bouton-outline">Bouton outline</h4>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">background</span><span class="p">:</span> <span class="nb">transparent</span><span class="p">;</span>
<span class="nl">color</span><span class="p">:</span> <span class="mh">#0F172A</span><span class="p">;</span>
<span class="nl">border</span><span class="p">:</span> <span class="m">2px</span> <span class="nb">solid</span> <span class="mh">#0F172A</span><span class="p">;</span>
<span class="nl">padding</span><span class="p">:</span> <span class="m">1rem</span> <span class="m">2rem</span><span class="p">;</span>
<span class="nl">border-radius</span><span class="p">:</span> <span class="m">8px</span><span class="p">;</span>
</code></pre></div></div>
<h3 id="cartes-cards">Cartes (Cards)</h3>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">background</span><span class="p">:</span> <span class="mh">#FFFFFF</span><span class="p">;</span>
<span class="nl">border-radius</span><span class="p">:</span> <span class="m">8px</span><span class="p">;</span>
<span class="nl">box-shadow</span><span class="p">:</span> <span class="m">0</span> <span class="m">4px</span> <span class="m">12px</span> <span class="nf">rgba</span><span class="p">(</span><span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="mi">.08</span><span class="p">);</span>
<span class="nl">padding</span><span class="p">:</span> <span class="m">1</span><span class="mi">.5rem</span><span class="p">;</span>
<span class="nl">transition</span><span class="p">:</span> <span class="n">all</span> <span class="m">0</span><span class="mi">.3s</span> <span class="n">ease-in-out</span><span class="p">;</span>
<span class="c1">// Hover</span>
<span class="nl">transform</span><span class="p">:</span> <span class="nf">translateY</span><span class="p">(</span><span class="m">-4px</span><span class="p">);</span>
<span class="nl">box-shadow</span><span class="p">:</span> <span class="m">0</span> <span class="m">10px</span> <span class="m">20px</span> <span class="nf">rgba</span><span class="p">(</span><span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="mi">.15</span><span class="p">);</span>
</code></pre></div></div>
<h3 id="badges">Badges</h3>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">padding</span><span class="p">:</span> <span class="m">0</span><span class="mi">.25rem</span> <span class="m">0</span><span class="mi">.5rem</span><span class="p">;</span>
<span class="nl">border-radius</span><span class="p">:</span> <span class="m">20px</span><span class="p">;</span>
<span class="nl">font-size</span><span class="p">:</span> <span class="nf">14px</span> <span class="p">(</span><span class="m">0</span><span class="mi">.875rem</span><span class="p">);</span>
<span class="nl">font-weight</span><span class="p">:</span> <span class="m">500</span><span class="p">;</span>
</code></pre></div></div>
<p><strong>Couleurs de badges par catégorie</strong>:</p>
<ul>
<li>PHP/Symfony/Backend: <code class="language-plaintext highlighter-rouge">#0F172A</code></li>
<li>PrestaShop/E-commerce: <code class="language-plaintext highlighter-rouge">#ED8936</code></li>
<li>AI/ML: <code class="language-plaintext highlighter-rouge">#7C3AED</code></li>
<li>DevOps/Docker: <code class="language-plaintext highlighter-rouge">#38B2AC</code></li>
<li>Frontend/JavaScript: <code class="language-plaintext highlighter-rouge">#F59E0B</code></li>
<li>Database: <code class="language-plaintext highlighter-rouge">#059669</code></li>
</ul>
<h3 id="border-radius">Border Radius</h3>
<p>| Nom | Valeur | Usage |
|—–|——–|——-|
| None | 0 | Pas d’arrondi |
| Small | 4px (0.25rem) | Arrondi léger |
| Default | 8px (0.5rem) | Arrondi standard |
| Medium | 8px (0.5rem) | Arrondi moyen |
| Large | 12px (0.75rem) | Grand arrondi |
| XL | 16px (1rem) | Très grand arrondi |
| 2XL | 24px (1.5rem) | Arrondi extra-large |
| Full | 9999px | Arrondi complet (cercle) |</p>
<hr />
<h2 id="5-animations">5. Animations</h2>
<h3 id="transitions-de-base">Transitions de base</h3>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Rapide</span>
<span class="nl">transition</span><span class="p">:</span> <span class="m">150ms</span> <span class="n">ease-in-out</span><span class="p">;</span>
<span class="c1">// Normal</span>
<span class="nl">transition</span><span class="p">:</span> <span class="m">250ms</span> <span class="n">ease-in-out</span><span class="p">;</span>
<span class="c1">// Lente</span>
<span class="nl">transition</span><span class="p">:</span> <span class="m">350ms</span> <span class="n">ease-in-out</span><span class="p">;</span>
<span class="c1">// Base (par défaut)</span>
<span class="nl">transition</span><span class="p">:</span> <span class="n">all</span> <span class="m">0</span><span class="mi">.3s</span> <span class="n">ease-in-out</span><span class="p">;</span>
</code></pre></div></div>
<h3 id="animations-clés">Animations clés</h3>
<h4 id="float-flottement">Float (flottement)</h4>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">@keyframes</span> <span class="nt">float</span> <span class="p">{</span>
<span class="nt">0</span><span class="nv">%</span><span class="o">,</span> <span class="nt">100</span><span class="nv">%</span> <span class="p">{</span> <span class="nl">transform</span><span class="p">:</span> <span class="nf">translateY</span><span class="p">(</span><span class="m">0px</span><span class="p">);</span> <span class="p">}</span>
<span class="nt">50</span><span class="nv">%</span> <span class="p">{</span> <span class="nl">transform</span><span class="p">:</span> <span class="nf">translateY</span><span class="p">(</span><span class="m">-10px</span><span class="p">);</span> <span class="p">}</span>
<span class="p">}</span>
<span class="nl">animation</span><span class="p">:</span> <span class="n">float</span> <span class="m">3s</span> <span class="n">ease-in-out</span> <span class="n">infinite</span><span class="p">;</span>
</code></pre></div></div>
<h4 id="fade-in-up">Fade In Up</h4>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">@keyframes</span> <span class="nt">fadeInUp</span> <span class="p">{</span>
<span class="nt">from</span> <span class="p">{</span>
<span class="nl">transform</span><span class="p">:</span> <span class="nf">translateY</span><span class="p">(</span><span class="m">30px</span><span class="p">);</span>
<span class="nl">opacity</span><span class="p">:</span> <span class="m">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">to</span> <span class="p">{</span>
<span class="nl">transform</span><span class="p">:</span> <span class="nf">translateY</span><span class="p">(</span><span class="m">0</span><span class="p">);</span>
<span class="nl">opacity</span><span class="p">:</span> <span class="m">1</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nl">animation</span><span class="p">:</span> <span class="n">fadeInUp</span> <span class="m">0</span><span class="mi">.8s</span> <span class="n">ease-out</span><span class="p">;</span>
</code></pre></div></div>
<h4 id="pulse">Pulse</h4>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">@keyframes</span> <span class="nt">pulse</span> <span class="p">{</span>
<span class="nt">0</span><span class="nv">%</span> <span class="p">{</span> <span class="nl">transform</span><span class="p">:</span> <span class="nf">scale</span><span class="p">(</span><span class="m">1</span><span class="p">);</span> <span class="nl">opacity</span><span class="p">:</span> <span class="m">1</span><span class="p">;</span> <span class="p">}</span>
<span class="nt">50</span><span class="nv">%</span> <span class="p">{</span> <span class="nl">transform</span><span class="p">:</span> <span class="nf">scale</span><span class="p">(</span><span class="m">1</span><span class="mi">.1</span><span class="p">);</span> <span class="nl">opacity</span><span class="p">:</span> <span class="m">0</span><span class="mi">.8</span><span class="p">;</span> <span class="p">}</span>
<span class="nt">100</span><span class="nv">%</span> <span class="p">{</span> <span class="nl">transform</span><span class="p">:</span> <span class="nf">scale</span><span class="p">(</span><span class="m">1</span><span class="p">);</span> <span class="nl">opacity</span><span class="p">:</span> <span class="m">1</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
<span class="nl">animation</span><span class="p">:</span> <span class="n">pulse</span> <span class="m">2s</span> <span class="n">infinite</span><span class="p">;</span>
</code></pre></div></div>
<h3 id="effets-de-hover">Effets de hover</h3>
<h4 id="lift-élévation">Lift (élévation)</h4>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">transition</span><span class="p">:</span> <span class="n">all</span> <span class="m">0</span><span class="mi">.25s</span> <span class="n">ease-in-out</span><span class="p">;</span>
<span class="k">&</span><span class="nd">:hover</span> <span class="p">{</span>
<span class="nl">transform</span><span class="p">:</span> <span class="nf">translateY</span><span class="p">(</span><span class="m">-8px</span><span class="p">)</span> <span class="nf">scale</span><span class="p">(</span><span class="m">1</span><span class="mi">.02</span><span class="p">);</span>
<span class="nl">box-shadow</span><span class="p">:</span> <span class="m">0</span> <span class="m">25px</span> <span class="m">50px</span> <span class="m">-12px</span> <span class="nf">rgba</span><span class="p">(</span><span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="mi">.25</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<h4 id="scale-agrandissement">Scale (agrandissement)</h4>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">transition</span><span class="p">:</span> <span class="n">all</span> <span class="m">0</span><span class="mi">.15s</span> <span class="n">ease-in-out</span><span class="p">;</span>
<span class="k">&</span><span class="nd">:hover</span> <span class="p">{</span>
<span class="nl">transform</span><span class="p">:</span> <span class="nf">scale</span><span class="p">(</span><span class="m">1</span><span class="mi">.05</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<hr />
<h2 id="6-breakpoints-responsive">6. Breakpoints Responsive</h2>
<table>
<thead>
<tr>
<th>Nom</th>
<th>Valeur</th>
<th>Usage</th>
</tr>
</thead>
<tbody>
<tr>
<td>Mobile</td>
<td>576px</td>
<td>Petits smartphones</td>
</tr>
<tr>
<td>Tablet</td>
<td>768px</td>
<td>Tablettes</td>
</tr>
<tr>
<td>Desktop</td>
<td>1024px</td>
<td>Ordinateurs</td>
</tr>
<tr>
<td>Large</td>
<td>1200px</td>
<td>Grands écrans</td>
</tr>
</tbody>
</table>
<h3 id="media-queries">Media queries</h3>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Mobile</span>
<span class="k">@media</span> <span class="p">(</span><span class="n">max-width</span><span class="o">:</span> <span class="m">576px</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
<span class="c1">// Tablet</span>
<span class="k">@media</span> <span class="p">(</span><span class="n">max-width</span><span class="o">:</span> <span class="m">768px</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
<span class="c1">// Desktop</span>
<span class="k">@media</span> <span class="p">(</span><span class="n">max-width</span><span class="o">:</span> <span class="m">1024px</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
<span class="c1">// Large</span>
<span class="k">@media</span> <span class="p">(</span><span class="n">max-width</span><span class="o">:</span> <span class="m">1200px</span><span class="p">)</span> <span class="p">{</span> <span class="p">}</span>
</code></pre></div></div>
<hr />
<h2 id="7-ombres-et-effets">7. Ombres et Effets</h2>
<h3 id="ombres-shadows">Ombres (Shadows)</h3>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Small</span>
<span class="nl">box-shadow</span><span class="p">:</span> <span class="m">0</span> <span class="m">1px</span> <span class="m">2px</span> <span class="m">0</span> <span class="nf">rgba</span><span class="p">(</span><span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="mi">.05</span><span class="p">);</span>
<span class="c1">// Medium</span>
<span class="nl">box-shadow</span><span class="p">:</span> <span class="m">0</span> <span class="m">4px</span> <span class="m">6px</span> <span class="m">-1px</span> <span class="nf">rgba</span><span class="p">(</span><span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="mi">.1</span><span class="p">)</span><span class="o">,</span>
<span class="m">0</span> <span class="m">2px</span> <span class="m">4px</span> <span class="m">-1px</span> <span class="nf">rgba</span><span class="p">(</span><span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="mi">.06</span><span class="p">);</span>
<span class="c1">// Large</span>
<span class="nl">box-shadow</span><span class="p">:</span> <span class="m">0</span> <span class="m">10px</span> <span class="m">15px</span> <span class="m">-3px</span> <span class="nf">rgba</span><span class="p">(</span><span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="mi">.1</span><span class="p">)</span><span class="o">,</span>
<span class="m">0</span> <span class="m">4px</span> <span class="m">6px</span> <span class="m">-2px</span> <span class="nf">rgba</span><span class="p">(</span><span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="mi">.05</span><span class="p">);</span>
<span class="c1">// XL</span>
<span class="nl">box-shadow</span><span class="p">:</span> <span class="m">0</span> <span class="m">20px</span> <span class="m">25px</span> <span class="m">-5px</span> <span class="nf">rgba</span><span class="p">(</span><span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="mi">.1</span><span class="p">)</span><span class="o">,</span>
<span class="m">0</span> <span class="m">10px</span> <span class="m">10px</span> <span class="m">-5px</span> <span class="nf">rgba</span><span class="p">(</span><span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="mi">.04</span><span class="p">);</span>
<span class="c1">// Colored (avec couleur primaire)</span>
<span class="nl">box-shadow</span><span class="p">:</span> <span class="m">0</span> <span class="m">10px</span> <span class="m">25px</span> <span class="nf">rgba</span><span class="p">(</span><span class="m">15</span><span class="o">,</span> <span class="m">23</span><span class="o">,</span> <span class="m">42</span><span class="o">,</span> <span class="m">0</span><span class="mi">.15</span><span class="p">);</span>
</code></pre></div></div>
<h3 id="effet-glass-verre">Effet Glass (verre)</h3>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">background</span><span class="p">:</span> <span class="nf">rgba</span><span class="p">(</span><span class="m">255</span><span class="o">,</span> <span class="m">255</span><span class="o">,</span> <span class="m">255</span><span class="o">,</span> <span class="m">0</span><span class="mi">.1</span><span class="p">);</span>
<span class="na">backdrop-filter</span><span class="p">:</span> <span class="nf">blur</span><span class="p">(</span><span class="m">10px</span><span class="p">);</span>
<span class="nl">border</span><span class="p">:</span> <span class="m">1px</span> <span class="nb">solid</span> <span class="nf">rgba</span><span class="p">(</span><span class="m">255</span><span class="o">,</span> <span class="m">255</span><span class="o">,</span> <span class="m">255</span><span class="o">,</span> <span class="m">0</span><span class="mi">.2</span><span class="p">);</span>
</code></pre></div></div>
<h3 id="z-index-scale">Z-Index Scale</h3>
<p>| Élément | Valeur |
|———|——–|
| Dropdown | 1000 |
| Sticky | 1020 |
| Fixed | 1030 |
| Modal backdrop | 1040 |
| Modal | 1050 |
| Popover | 1060 |
| Tooltip | 1070 |</p>
<hr />
<h2 id="8-icons-et-assets">8. Icons et Assets</h2>
<h3 id="logo">Logo</h3>
<ul>
<li>Formats disponibles: PNG, WebP</li>
<li>Localisation: <code class="language-plaintext highlighter-rouge">/assets/images/logo.png</code>, <code class="language-plaintext highlighter-rouge">/assets/images/logo.webp</code></li>
</ul>
<h3 id="font-icons">Font Icons</h3>
<p>Le site utilise Font Awesome pour les icônes.</p>
<hr />
<h2 id="9-guidelines-dutilisation">9. Guidelines d’utilisation</h2>
<h3 id="principes-de-design">Principes de design</h3>
<ol>
<li><strong>Simplicité</strong>: Design épuré et professionnel</li>
<li><strong>Lisibilité</strong>: Hiérarchie typographique claire</li>
<li><strong>Cohérence</strong>: Respect strict du système d’espacement</li>
<li><strong>Performance</strong>: Optimisation des animations pour mobile</li>
<li><strong>Accessibilité</strong>: Contraste suffisant, support reduced-motion</li>
</ol>
<h3 id="bonnes-pratiques">Bonnes pratiques</h3>
<ul>
<li>Toujours utiliser le système d’espacement (multiples de 8px)</li>
<li>Respecter la hiérarchie typographique (H1 > H2 > H3 > H4)</li>
<li>Utiliser les couleurs d’accentuation avec parcimonie</li>
<li>Limiter les animations sur mobile pour les performances</li>
<li>Tester sur différents breakpoints</li>
</ul>
<h3 id="palette-de-couleurs-pour-les-états">Palette de couleurs pour les états</h3>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Hover sur liens</span>
<span class="nl">color</span><span class="p">:</span> <span class="mh">#1D4ED8</span><span class="p">;</span> <span class="c1">// Bleu légèrement plus clair</span>
<span class="c1">// Focus</span>
<span class="nl">outline</span><span class="p">:</span> <span class="m">2px</span> <span class="nb">solid</span> <span class="mh">#0F172A</span><span class="p">;</span>
<span class="nl">outline-offset</span><span class="p">:</span> <span class="m">2px</span><span class="p">;</span>
<span class="c1">// Disabled</span>
<span class="nl">opacity</span><span class="p">:</span> <span class="m">0</span><span class="mi">.5</span><span class="p">;</span>
<span class="nl">cursor</span><span class="p">:</span> <span class="ow">not</span><span class="o">-</span><span class="n">allowed</span><span class="p">;</span>
</code></pre></div></div>
<hr />
<h2 id="10-exemples-de-mise-en-œuvre">10. Exemples de mise en œuvre</h2>
<h3 id="section-hero">Section Hero</h3>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">background</span><span class="p">:</span> <span class="nf">linear-gradient</span><span class="p">(</span><span class="m">135deg</span><span class="o">,</span> <span class="mh">#FFFFFF</span> <span class="m">0%</span><span class="o">,</span> <span class="mh">#FAFAFA</span> <span class="m">100%</span><span class="p">);</span>
<span class="nl">padding</span><span class="p">:</span> <span class="m">3rem</span> <span class="m">0</span><span class="p">;</span>
<span class="nt">h1</span> <span class="p">{</span>
<span class="nl">font-family</span><span class="p">:</span> <span class="s1">'Poppins'</span><span class="o">,</span> <span class="nb">sans-serif</span><span class="p">;</span>
<span class="nl">font-size</span><span class="p">:</span> <span class="m">2</span><span class="mi">.5rem</span><span class="p">;</span>
<span class="nl">font-weight</span><span class="p">:</span> <span class="m">700</span><span class="p">;</span>
<span class="nl">color</span><span class="p">:</span> <span class="mh">#111827</span><span class="p">;</span>
<span class="nl">margin-bottom</span><span class="p">:</span> <span class="m">1rem</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt">p</span> <span class="p">{</span>
<span class="nl">font-family</span><span class="p">:</span> <span class="s1">'Inter'</span><span class="o">,</span> <span class="nb">sans-serif</span><span class="p">;</span>
<span class="nl">font-size</span><span class="p">:</span> <span class="m">1</span><span class="mi">.125rem</span><span class="p">;</span>
<span class="nl">color</span><span class="p">:</span> <span class="mh">#374151</span><span class="p">;</span>
<span class="nl">line-height</span><span class="p">:</span> <span class="m">1</span><span class="mi">.7</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<h3 id="card-component">Card Component</h3>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">.card</span> <span class="p">{</span>
<span class="nl">background</span><span class="p">:</span> <span class="mh">#FFFFFF</span><span class="p">;</span>
<span class="nl">border-radius</span><span class="p">:</span> <span class="m">8px</span><span class="p">;</span>
<span class="nl">padding</span><span class="p">:</span> <span class="m">1</span><span class="mi">.5rem</span><span class="p">;</span>
<span class="nl">box-shadow</span><span class="p">:</span> <span class="m">0</span> <span class="m">4px</span> <span class="m">12px</span> <span class="nf">rgba</span><span class="p">(</span><span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="mi">.08</span><span class="p">);</span>
<span class="nl">transition</span><span class="p">:</span> <span class="n">all</span> <span class="m">0</span><span class="mi">.3s</span> <span class="n">ease-in-out</span><span class="p">;</span>
<span class="k">&</span><span class="nd">:hover</span> <span class="p">{</span>
<span class="nl">transform</span><span class="p">:</span> <span class="nf">translateY</span><span class="p">(</span><span class="m">-4px</span><span class="p">);</span>
<span class="nl">box-shadow</span><span class="p">:</span> <span class="m">0</span> <span class="m">10px</span> <span class="m">20px</span> <span class="nf">rgba</span><span class="p">(</span><span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="o">,</span> <span class="m">0</span><span class="mi">.15</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<hr />
<h2 id="ressources">Ressources</h2>
<h3 id="fichiers-sources">Fichiers sources</h3>
<ul>
<li>Variables: <code class="language-plaintext highlighter-rouge">_sass/variables.scss</code></li>
<li>Base: <code class="language-plaintext highlighter-rouge">_sass/base.scss</code></li>
<li>Composants: <code class="language-plaintext highlighter-rouge">_sass/components.scss</code></li>
<li>Animations: <code class="language-plaintext highlighter-rouge">_sass/animations.scss</code></li>
</ul>
<h3 id="polices">Polices</h3>
<ul>
<li>Inter: https://fonts.google.com/specimen/Inter</li>
<li>Poppins: https://fonts.google.com/specimen/Poppins</li>
<li>JetBrains Mono: https://www.jetbrains.com/lp/mono/</li>
</ul>
<hr />
<p><strong>Version</strong>: 1.0
<strong>Date</strong>: 2025-11-25
<strong>Auteur</strong>: Nicolas Dabene</p>
</div>
</div>
</article>
<div class="social-sharing-section" data-pagefind-ignore>
<!-- Partage social non indexé -->
</div>
</article>
Avantages de cette configuration : ✅ Recherche full-text dans tout le contenu ✅ Filtrage possible par catégorie, tags, langue ✅ Métadonnées riches (date, auteur, excerpt) ✅ Exclusion intelligente des éléments non pertinents
🧪 Tester localement
Option 1 : Avec Jekyll + Pagefind
# 1. Build Jekyll
bundle exec jekyll build
# 2. Installer Pagefind (si pas déjà fait)
npm install -g pagefind
# 3. Générer l'index
npx pagefind --site _site --output-path _site/pagefind
# 4. Servir le site
bundle exec jekyll serve
Option 2 : Avec le serveur Pagefind
# 1. Build Jekyll et index
bundle exec jekyll build
npx pagefind --site _site
# 2. Servir avec le serveur Pagefind
npx pagefind --serve --site _site
🚀 Déploiement
L’indexation Pagefind se fait automatiquement à chaque push sur main via GitHub Actions :
- ✅ Jekyll build le site →
_site/ - ✅ Pagefind indexe le contenu →
_site/pagefind/ - ✅ Le tout est déployé sur GitHub Pages
Aucune action manuelle requise !
📝 Intégration JavaScript
Le fichier assets/js/blog-search-pagefind.js gère :
Recherche
- Chargement asynchrone de Pagefind
- Recherche avec debounce (300ms)
- Affichage des résultats
- Mise en surbrillance des termes de recherche
- Fallback vers recherche basique si Pagefind échoue
- Raccourcis clavier (
/ouCtrl+K)
Filtrage par tags 🆕
- API Pagefind avec filtres : Utilise
pagefind.search(query, { filters: { tags: [...] } }) - Gestion d’état : Tableau
activeFiltersmaintenant les tags/catégories actifs - Événements dynamiques : Transformation des liens tags en boutons de filtrage
- UI des filtres actifs : Génération dynamique des badges de filtres
- Fallback intelligent : Filtrage manuel si Pagefind non disponible
- Combinaison recherche + filtres : Recherche textuelle avec filtres simultanés
Fonctions principales
// Recherche avec filtres
performPagefindSearch(query, filters)
// Gestion des filtres
toggleTagFilter(tag) // Ajouter/retirer un tag
toggleCategoryFilter(category)// Ajouter/retirer une catégorie
clearAllFilters() // Réinitialiser tous les filtres
// UI
updateActiveFiltersUI() // Afficher les filtres actifs
updateTagsVisualState() // Mettre à jour l'état visuel des tags
🎨 Interface Utilisateur
La recherche offre une interface riche :
Recherche textuelle
- Barre de recherche globale
- Raccourcis clavier (
/ouCtrl+Kpour focus) - Bouton d’effacement rapide
- Surlignage des termes de recherche dans les résultats
Filtrage par tags 🆕
- Tags cliquables : Cliquez sur n’importe quel tag dans le cloud pour filtrer
- Filtres multiples : Combinez plusieurs tags pour affiner la recherche
- Filtres actifs visibles : Badges affichant les filtres actifs avec possibilité de les retirer
- Bouton “Tout effacer” : Réinitialisation rapide de tous les filtres
- État visuel : Tags actifs mis en surbrillance (✓) dans le cloud
- Combinaison : Recherche textuelle + filtres par tags fonctionne ensemble
Affichage des résultats
- Compteur de résultats en temps réel
- Message “Aucun résultat trouvé” si nécessaire
- Compatible avec la pagination existante
- Fallback automatique si Pagefind échoue
🔄 Migration depuis Fuse.js
Fichiers modifiés :
- ✅
.github/workflows/jekyll.yml- Ajout étapes Pagefind - ✅
pages/blog.html- Remplacement Fuse.js par Pagefind - ✅
en/blog.html- Remplacement Fuse.js par Pagefind - ✅
_layouts/post.html- Ajout attributs data-pagefind
Fichiers créés :
- ✅
assets/js/blog-search-pagefind.js- Script de recherche avec API Pagefind - ✅
PAGEFIND_README.md- Cette documentation
Fichiers conservés (rétrocompatibilité) :
- ⚠️
assets/js/blog-search-modern.js- Ancien script Fuse.js (peut être supprimé) - ⚠️ CDN Fuse.js - Peut être retiré après validation complète
📊 Performance & Fonctionnalités
Avant (Fuse.js) :
- Chargement CDN Fuse.js (~50KB)
- Indexation runtime de tous les articles
- Recherche côté client sur tous les posts
- ❌ Pas de filtrage par tags
- ❌ Recherche limitée (titres + excerpts)
Après (Pagefind) :
- Index pré-généré au build
- Chargement progressif (~10KB initial + fragments à la demande)
- Recherche ultra-rapide sur l’index pré-calculé
- ✅ Filtrage par tags/catégories via API Pagefind
- ✅ Filtres combinables (plusieurs tags simultanés)
- ✅ UI des filtres actifs avec badges cliquables
- ✅ Full-text search (contenu complet indexé)
- ✅ Recherche + filtres combinés (ex: “prestashop” + tag “PHP”)
🐛 Debugging
Vérifier que l’index est généré :
# Après le build
ls -la _site/pagefind/
# Devrait contenir : pagefind.js, index files, etc.
Logs GitHub Actions :
Vérifiez les logs de l’action “Build Pagefind index” dans le workflow Jekyll.
Console navigateur :
// Vérifier que Pagefind est chargé
console.log(window.pagefind);
📚 Ressources
Mis en place le : 31 décembre 2025 Indexation automatique : ✅ Activée via GitHub Actions