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 à indexer
  • data-pagefind-meta : Métadonnées extractibles (titre, date, auteur, excerpt)
  • data-pagefind-filter : Filtres pour catégories, tags, langue
  • data-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&amp;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
&lt;link href="https://fonts.googleapis.com/css2?family=Poppins:wght@600;700;800;900&amp;display=swap" rel="stylesheet"&gt;
</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">&amp;</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">&amp;</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 &gt; H2 &gt; H3 &gt; 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">&amp;</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 :

  1. ✅ Jekyll build le site → _site/
  2. ✅ Pagefind indexe le contenu → _site/pagefind/
  3. ✅ 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 (/ ou Ctrl+K)

Filtrage par tags 🆕

  • API Pagefind avec filtres : Utilise pagefind.search(query, { filters: { tags: [...] } })
  • Gestion d’état : Tableau activeFilters maintenant 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 (/ ou Ctrl+K pour 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