Le NAV Niveau 2

Pourquoi tu n'as plus jamais besoin d'éditer ton menu. Jamais.

Le problème de la main d'œuvre

Dans le nav niveau 1, on a nettoyé le code. On a isolé notre menu dans _includes/nav.html. C'est propre.

Mais si je veux ajouter un lien, je dois encore ouvrir ce fichier, copier une balise <a>, taper l'URL, taper le nom. C'est chiant. On est des bidouilleurs, on veut que la machine travaille pour nous. On va faire ça étape par étape.

Étape 1 : L'usine à liens (La boucle `for`)

On va introduire le concept de Source de Vérité. On crée un fichier texte brut _data/navigation.yml. Dedans, on ne met que de la donnée pure. Pas de HTML. Juste une liste avec le nom et le chemin.

# _data/navigation.yml
- name: "Accueil"
  url: "/index.html"

- name: "Grille"
  url: "/grille.html"

- name: "Rythme"
  url: "/rythme.html"

Ensuite, dans notre fichier _includes/nav.html, on demande à Jekyll de lire ce fichier et de fabriquer les boutons à notre place avec la commande {% for %} :

<nav class="grid">
{% for item in site.data.navigation %}
  <a href="{{ item.url }}" class="brutal-button">
    {{ item.name }}
  </a>
{% endfor %}
</nav>

Explication : La boucle for prend le premier élément du fichier YAML (qu'elle nomme item), crée le HTML, puis passe au suivant. Tu veux changer l'ordre de ton menu ? Tu déplaces les lignes dans le fichier YAML. Terminé.

Le mirage de l'automatisation totale

Attends... Wait. On déclare nos pages avec le Front Matter en haut de chaque fichier HTML. Pourquoi on les déclare UNE DEUXIÈME FOIS dans un fichier YAML ? C'est de la répétition non ?

Il existe une variable magique dans Jekyll : site.html_pages. Elle contient absolument toutes les pages du site.

{% for item in site.html_pages %}
  <a href="{{ item.url }}" class="brutal-button">{{ item.title }}</a>
{% endfor %}

Alors là c'est le pompon. Tu crées un fichier HTML, il apparaît tout seul dans le menu. Zéro configuration. Jamais.

Pourquoi c'est un piège (je suis tombé dedans comme un noob)?

Parce que la machine est stupide.
Si tu utilises site.html_pages, comment tu choisis l'ordre des boutons ?
Et ta page 404 ? Elle va dans le menu ?
Et tes brouillons ?
Et ta page de test ?

Pour un projet de 3 pages, c'est rigolo. Quand ton projet en a 20... c'est l'enfer. Tu perds le contrôle de ton architecture. C'est pour ça qu'on revient sagement à notre fichier _data/navigation.yml.

Étape 2 : Donner un cerveau (La condition `if`)

Puisqu'on a notre boucle propre, on veut que le bouton de la page actuelle s'allume (pour dire "Tu es ici"). On va dire à Jekyll d'analyser l'URL de la page où se trouve le visiteur (page.url), et de la comparer avec l'URL du bouton (item.url).

<nav class="grid">
  {% for item in site.data.navigation %}
    <a
      href="{{ item.url }}"
      class="brutal-button {% if page.url == item.url %}active{% endif %}"
      {% if page.url == item.url %}aria-current="page"{% endif %}
    >
      {{ item.name }}
    </a>
  {% endfor %}
</nav>

Explication : Si la condition est vraie, Jekyll écrit le mot active dans la classe, et ajoute aria-current="page" pour l'accessibilité. Zéro JavaScript. C'est généré en dur au Build-Time.

Ça marche. Tous les tutos sur internet s'arrêtent là. Mais si on regarde bien... il y a un truc très moche.

Étape 3 : Le niveau Pro (La variable `assign`)

Regarde le code juste au-dessus. On a écrit DEUX fois exactement la même question :
{% if page.url == item.url %}.
Une fois pour le CSS, une fois pour l'accessibilité.

Tu ne fais jamais la même comparaison plus d'une fois.

C'est la différence entre quelqu'un qui écrit du Liquid et quelqu'un qui maîtrise Liquid. Pour optimiser ça, on utilise la commande {% assign %}. Elle permet de faire le calcul une seule fois et de ranger le résultat (vrai ou faux) dans une "boîte". Ensuite, on réutilise cette boîte.

<nav class="grid">
  {% for item in site.data.navigation %}
    
    <!-- 1. ON CRÉE LA BOÎTE (Fausse par défaut) -->
    {% assign is_active = false %}

    <!-- 2. ON FAIT LE CALCUL UNE SEULE FOIS -->
    {% if page.url == item.url %}
      {% assign is_active = true %}
    {% endif %}

    <!-- 3. ON UTILISE LA BOÎTE POUR L'AFFICHAGE -->
    <a
      href="{{ item.url }}"
      class="brutal-button {% if is_active %}active{% endif %}"
      {% if is_active %}aria-current="page"{% endif %}
    >
      {{ item.name }}
    </a>
  {% endfor %}
</nav>

Pourquoi c'est mieux ? Moins de calculs à la compilation, impossible d'avoir un bug où la classe s'active mais pas l'attribut, et surtout, si on veut ajouter un style plus tard, on a juste à taper {% if is_active %}. C'est robuste.

Bilan de l'Architecture

1

La Séparation des Pouvoirs (pas comme certains pays...)

Le _layout (default.html) fait la structure. Le _includes (nav.html) fait la logique de boucle. Le _data (navigation.yml) donne le contenu et l'ordre. Rien ne se mélange.

2

L'Évolutivité

Tu veux renommer "Accueil" en "Home" ? Tu changes un mot dans le YAML. Le composant met à jour toutes les pages du site instantanément à la compilation.

3

L'Accessibilité Native

Grâce au aria-current="page" et la variable is_active générés côté serveur, les lecteurs d'écran savent exactement où ils sont sans attendre le chargement d'un lourd script JS.