La base

Maintenant que le concept est vu, passons à la pratique en nous attaquant tout de suite à la création du squelette de notre site.

Cette partie va être très dense et longue, mais au profit des suivantes qui seront quant à elles plus légères. Je vous recommande donc d’y aller tranquillement, en prenant votre temps pour chaque morceau.

Inventaire des fichiers nécessaires

Comme je vous l’expliquais dans le chapitre précédent, un certain nombre de fichiers est nécessaire pour créer le design du site. En voici l’arborescence.

mon-theme/
├── static
│   ├── css
│   │   └── style.css
│   ├── images
│   │   └── [...]
│   └── js
│       └── [...]
└── templates
    ├── archives.html
    ├── article.html
    ├── author.html
    ├── authors.html
    ├── base.html
    ├── categories.html
    ├── category.html
    ├── index.html
    ├── page.html
    ├── parts
    │   └── [...]
    ├── period_archives.html
    ├── subcategory.html
    ├── tag.html
    └── tags.html

Je vous invite donc à créer tout de suite un dossier « mon-theme » directement à la racine de votre site (donc à côté du dossier content par exemple. Nous allons ensuite informer Pelican que c’est ce dossier qui servira de thème dorénavant en modifiant simplement la constante THEME du fichier pelicanconf.py par THEME = 'mon-theme'. Profitez-en aussi pour ajouter la ligne THEME_STATIC_DIR = 'static' à la suite. Cette information permet de prévenir l’outil que des fichiers statiques sont présents dans ce dossier.

Les fichiers statiques ne manipulent pas le contenu des articles, mais servent à la mise en page. Comme par exemple le fichier style.css pour le CSS ou encore des scripts javascript ou des images comme votre logo ou une favicon par exemple.

base.html, la colonne vertébrale du site

Une fois que tout est là, nous pouvons commencer à créer !

Nous allons commencer en éditant le fichier base.htmln qui se trouve dans le dossier templates/. Celui-ci va contenir tout le code HTML le plus commun à toutes les pages, tout en exposant des blocs qui seront personnalisés plus tard.

Sans plus de détour, voici le fichier. Je vais vous l’expliquer en détail ensuite.

<!DOCTYPE html>
<html lang="{{ DEFAULT_LANG }}">
<head>
    <meta charset="utf-8" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    
    <title>{% block titre %}{{ SITENAME }}{% endblock %}</title>
    <link rel="stylesheet" href="/{{ THEME_STATIC_DIR }}/css/style.css" />
    <link rel="icon" type="image/x-icon" href="/{{ THEME_STATIC_DIR }}/images/favicon.ico">
    
    {% block extra_head %}
    {% endblock %}
</head>

<body>
    {% include 'parts/header.part.html' %}

    <div class="main"> 
        {% include 'parts/sidebar.part.html' %}
        <div class="content">
            {% block content %}
            {% endblock %}
        </div>
    </div>

    {% include 'parts/footer.part.html' %}

    <script src="/{{ THEME_STATIC_DIR }}/js/script.js"></script>
    {% block extra_js %}
    {% endblock %}
</body>
</html>

Vous avez remarqué comme il est court ? C’est parce que je fais usage des directives que nous avons vu plus tôt, notamment la fonction include permettant d’inclure des morceaux de templates plutôt que de les écrire directement.

Voyons tout cela en détail.

La section head

Sans surprise, notre fichier reprend la même structure que n’importe quel autre. On trouve dons un DOCTYPE tout en haut, puis la balise <html> qui englobe le tout. Ensuite vient la balise <head> pour définir la section de métadonnée concernant la page puis on trouve le <body> qui contiendra le contenu affiché à l’écran.

Revenons sur la section <head>.

<head>
    <meta charset="utf-8" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>{% block title %}{{ SITENAME }}{%endblock%}</title>
    <link rel="stylesheet" href="/{{ THEME_STATIC_DIR }}/css/style.css" />
    
    <!-- Favicon -->
    <link rel="icon" type="image/x-icon" href="/{{ THEME_STATIC_DIR }}/images/favicon.ico">
    
    {% block extra_head %}
    {% endblock %}
</head>

Les deux premières lignes ne nous intéressent pas trop ici, elles servent surtout à informer le navigateur pour qu’il interprète correctement le contenu.

En revanche, la ligne suivante est très intéressante car elle fait appel à plusieurs nouveautés.

<title>{% block titre %}{{ SITENAME }}{% endblock %}</title>

D’un point de vue HTML, c’est simplement la balise <title>, qui définira le titre de la page (qui s’affichera dans l’onglet du navigateur). En revanche, son contenu est {% block titre %}{{ SITENAME }}{% endblock %}, ça c’est original !

De manière plus clair, nous avons affaire ici à notre premier bloc personnalisable ! Ce bloc s’appelle « title » et a pour l’instant comme valeur {{ SITENAME }}. J’attire votre attention sur la construction d’un bloc. On commence tout d’abord par créer un marqueur à base d’accolades et de symbole de pourcentage contenant le mot-clé bloc puis un nom qui référence ce bloc . En l’occurrence "titre". On obtient ainsi le marqueur {% block titre %}. Ensuite, il faut indiquer quand ce termine le bloc. Là encore avec des accolades et des symboles pourcentage et le mot-clé endblock pour former la chaîne {% endblock %}.

Ici, notre bloc n’est pas vide, il possède déjà une valeur qui est {{ SITENAME }}. C’est une valeur curieuse n’est ce pas ? En fait, c’est carrément l’appel d’une variable globale du site. Cette dernière est renseignée dans le fichier de configuration pelicanconf.py et sert à porter le nom de votre site. Par exemple "Cool Cookies". Ainsi, lorsque Jinja rencontre un marqueur composé de double accolades {{ ... }} il sait qu’il ne doit pas imprimer l’information telle quelle mais plutôt le contenu de la variable indiquée. Il existe plein de variables globales, nous les verrons au fur et à mesure de nos besoins.

Une fois que le générateur sera passé dessus, si aucune autre page ne vient modifier le bloc "titre", cette ligne se transformera simplement en :

<title>Cool Cookies</title>

Wahoo. Une seule ligne et on a découvert déjà tant de choses :lol: !!

Voyons la suivante :

    <link rel="stylesheet" href="/{{ THEME_STATIC_DIR }}/css/style.css" />

Cette dernière nous sert à inclure une feuille de style qui servira à mettre en forme notre page. J’espère que vous avez remarqué l’utilisation de nouveau d’une variable (globale) THEME_STATIC_DIR. Souvenez-vous, au tout début du chapitre je vous ai demandé de la créer pour indiquer à Pelican où se trouvait les fichiers statiques, notamment le CSS. Eh bien là nous y faisons appel ! Concrètement, une fois que le générateur sera passé sur cette ligne elle deviendra :

    <link rel="stylesheet" href="/static/css/style.css" />

Les plus pointus d’entre vous auront peut-être remarqué que l’adresse est relative, en commençant directement par un /. Cela nous permet ainsi d’être indépendant du nom de domaine utilisé.

Allez on continue, ligne suivante s’il vous plaît !

    <link rel="icon" type="image/x-icon" href="/{{ THEME_STATIC_DIR }}/images/favicon.ico">

Ici rien de super original, on retrouve ce que l’on vient de voir avec la ligne précédente. La variable THEME_STATIC_DIR sera remplacée pour obtenir un chemin valide et ainsi pouvoir afficher notre favicon (qu’il faudra placer dans le dossier mon-theme/static/images/ avec le nom favicon.ico pour que cela fonctionne).

Enfin, le dernier bout de code de cette section <head> est le suivante.

    {% block extra_head %}
    {% endblock %}

C’est la déclaration d’un bloc nommé « extra_head » et vide pour le moment. Ce dernier sera rempli par le template servant à générer le contenu d’un article, afin de rajouter des métadonnées utiles pour le référencement entre autres. Nous verrons donc cela plus tard ;) .

La section body

Nous venons déjà de voir un sacré morceau avec la section <head>, mais ne nous reposons pas sur nos lauriers, nous avons presque fini avec cette première page.

Voyons maintenant la section <body>.

    {% include 'parts/header.part.html' %}

    <div class="main"> 
        {% include 'parts/sidebar.part.html' %}
        <div class="content">
            {% block content %}
            {% endblock %}
        </div>
    </div>

    {% include 'parts/footer.part.html' %}

    <script src="/{{ THEME_STATIC_DIR }}/js/script.js"></script>
    {% block extra_js %}
    {% endblock %}

Il commence fort avec une nouvelle instruction, la fonction include. Comme brièvement expliqué plus tôt, cette dernière va nous permettre d’inclure un morceau de code qui sera écrit dans un autre fichier. On peut ainsi garder notre fichier plus léger et donc plus facile à lire et à créer. Un autre avantage est pour les morceaux de code qui se répètent (dans une boucle la plupart du temps). On peut ainsi les isoler et les ajouter de manière procédurale assez facilement. Nous verrons ce cas plus tard, lorsque nous étudierons la réalisation des pages de listing.

La fonction include a besoin du chemin du fichier HTML à inclure. En l’occurrence, le fichier se trouve dans le dossiers parts et se nomme header.part.html. Ce dernier contient tout le code de la barre d’en-tête de notre site. Nous verrons ce contenu à la fin de ce chapitre.

Je vous invite à essayer de respecter la convention de nommage *.part.html pour les fichiers contenant uniquement des morceaux de code destinés à être inclus. Vous savez ainsi en un clin d’œil qu’il ne se suffise pas à eux-mêmes mais sont destinés à être inclus dans un autre fichier.

Lorsque Jinja va croiser cette ligne, il va tout simplement copier et interpréter tout le contenu du fichier visé.

Le morceau suivant ne fait pas grand chose. Il se contente simplement de déclarer une <div> avec la classe CSS main qui contiendra de nouveau un include pour le code de la barre latérale et un bloc qui sera personnalisé plus tard (vide pour le moment).

Ensuite, on retrouve de nouveau un include mais cette fois-ci se sera pour ajouter le pied-de-page de notre site. Les mêmes remarques que pour l’en-tête s’appliquent.

Enfin, le dernier morceau de code contient à la fois l’inclusion d’un fichier javascript provenant du dossier static (remplacement d’une variable globale ;) ), et ensuite la déclaration d’un bloc "extra_js", vide pour le moment, qui sera personnalisé par d’autre template plus tard.

L'en-tête et le pied de page du site

Bon c’est bien sympa tout ça mais pour l’instant on a rien fait du tout ! Notre site n’affiche qu’une simple page blanche.

Je vous propose donc de compléter les fichiers header.part.html ainsi que footer.part.html pour donner un peu de corps (ahah) à notre page.

L’en-tête (header.part.html)

Commençons en toute logique par l’en-tête du site, c’est à dire la « barre de titre » tout en haut de notre page.

Cette dernière aura l’allure suivante :

En-tête
En-tête

Son code sera tout simple, et composé d’une balise <header> contenant un lien avec une image (redirigeant vers la racine du site) et un span contenant le nom du site.

<header class="header-bar">
    <a class="header-nav" href="/">
        <img src="/{{ THEME_STATIC_DIR }}/images/logo.png" alt="{{ SITENAME }} logo">
    </a>
    <span class="header-title">{{ SITENAME }}</span>
</header>

Rien de bien transcendant, j’attire toutefois votre attention sur l’utilisation une nouvelle fois des variables pour paramétrer le titre du site et aller chercher les images (le logo en l’occurrence) au bon endroit.

Voici le CSS associé :

.header-bar {
  padding: 5px;
  margin-bottom: 5px;
  background-color: #fafafb;
  box-shadow: 0 1px 0 rgba(12,13,14,0.1),0 1px 6px rgba(59,64,69,0.1);
}

a.header-nav {
  text-decoration: none;
}

a.header-nav img {
  height: 50px;
  vertical-align: middle;
  margin-left: 10px;
}

.header-title {
  font-size: 50px;
  margin-left: 50px;
  display: inline-block;
  vertical-align: middle
}

Maintenant place au pied de page !

Le pied de page (footer.part.html)

Le pied de page sera lui aussi assez simple à mettre en œuvre. Il ne possédera qu’une petite indication de copyright sur la gauche puis une liste de liens (tous bidon pour l’exemple) sur la droite.

Voici le HTML, le CSS et un rendu. Là encore l’utilisation de la variable SITENAME est faite pour le copyright.

<footer class="footer-bar">
    <span class="footer-copyright">© {{ SITENAME }}</span>
    <ul class="footer-list">
        <li><a href="#">À propos</a></li>
        <li><a href="#">Contact</a></li>
        <li><a href="#">Mentions Légales</a></li>
    </ul>
</footer>
.footer-bar {
  padding: 5px 20px;
  margin-top: 5px;
  background-color: #242729;
  color: #848d95;
  display: flex;
  justify-content: space-between;
}

.footer-bar span {
  margin-top: 4px;
}

.footer-bar ul {
  margin: 0;
  list-style-type: none;
}

.footer-bar li {
  margin: 4px 0;
}

.footer-bar a {
  color: #848d95;
  text-decoration: none;
}

.footer-bar a:hover {
  color: #bbc0c4;
}
Le pied de page
Le pied de page

Allure globale

Voici le rendu que vous devriez avoir :

Rendu global - base.html
Rendu global - base.html

Un peu de CSS a été utilisé pour étirer correctement le conteneur principale, voici-donc tout ce que j’ai passé sous silence :

html, body {
  height: 100%;
}

body {
  margin: 0;
  color: #242729;
  display: flex;
  flex-direction: column;
}

.main {
  flex-grow: 1;
}

La barre latérale

Dernière étape, rajouter la barre latérale (sidebar) qui recensera les catégories de notre blog ainsi que quelques liens « sociaux ».

Comme d’habitude, je vais tout d’abord vous copier le code puis je vous l’expliquerais ensuite :

<nav class="sidebar-nav">
    <ul class="categories">
        {% for cat, articles in categories|sort %}
        <li>
            <a href="/{{ cat.url }}">{{ cat }} ({{ articles|count }})</a>
        </li>
        {% endfor %}
    </ul>
    <hr>
    <ul class="links">
        <ul>
            {% for name, link in SOCIAL %}
            <li>
                <a href="{{ link }}">{{ name }}</a>
            </li>
            {% endfor %}
        </ul>
    </ul>
</nav>
.sidebar-nav {
  background-color: #f2f2f2;
  padding: 10px 20px;
  border: solid 1px grey;
  border-radius: 5px;
}

.sidebar-nav hr {
  color: #fff;
}

.sidebar-nav ul {
  padding: 0;
  margin: 0;
  list-style-type: none;
}

.sidebar-nav li {
  margin: 4px 0;
}

.sidebar-nav a {
  text-decoration: none;
  color: #43474b;
}

.sidebar-nav a:hover {
  color: #000;
}

Vous l’avez sûrement vu, encore de nouvelles choses sont au programme : les boucles !

Les boucles sont un moyen très pratique pour construire des listes d’éléments. Ici, nous faisons deux boucles, une pour générer la liste des catégories (et le nombre d’articles présents dans chacune) et une autre qui parcourt tout les éléments présents dans la liste globale SOCIAL qui est dans le fichier pelicanconf.py.

La liste des catégories

La construction de cette nouvelle instruction n’est pas très compliquée vous allez voir. Voici comment elle se décompose :

{% for element-de-la-liste in liste %}
    [ ... Instructions executer à chaque passage dans la boucle ... ]
{% endfor %}

On voit apparaître plusieurs choses. Tout d’abord le mot-clé for, qui indique que l’on veut faire une boucle. Ensuite, on donne un nom symbolique pour une variable que l’on souhaite utiliser pour stocker un élément de la liste à parcourir. Enfin, le mot-clé in suivi du nom de la variable contenant la liste à parcourir.

Notre cas d’études est un peu particulier :

{% for cat, articles in categories|sort %}

Déjà, on voit que l’on stocke dans cat, articles. C’est dû à la nature de la liste étudiée categories. Cette dernière est en fait une liste de couple (catégorie, liste d’articles de la catégorie). À chaque passage dans la boucle, à chaque élément récupéré, on récupère donc une catégorie (stockée dans cat) et la liste des articles de cette catégorie (stockée dans … articles). Petite facétie en plus, on applique le modificateur sort sur la liste categories initial pour récupérer ses éléments en ordre alphabétiques.

Ok, on a donc maintenant à chaque tour de boucle une catégorie et sa liste d’articles, il est temps de s’en servir.

<li>
    <a href="/{{ cat.url }}">{{ cat }} ({{ articles|count }})</a>
</li>

On va donc placer l’élément url de la catégorie cat dans le lien de la balise <a> et on utilisera directement cat dans le texte du lien (pour dire vrai, c’est alors sa représentation textuelle qui sera appelée). Enfin, on mettra entre parenthèses le nombre d’articles de la catégorie en cours. Pour ce faire, on utilise la fonction count sur la variables articles (qui est une liste je vous rappelle).

Et après toutes ces aventures, on obtient une jolie liste à puces avec toutes nos catégories, des liens vers ces dernières et le nombre d’articles qu’elles contiennent !

La liste des liens sociaux

Cette liste est un peu plus simple que la précédente puisque ce sont "juste" des tuples mis dans une liste. Voici un exemple de ce qu’elle peut contenir :

SOCIAL = (('Facebook', 'https://lien-vers-profil-facebook.com/'),
          ('Twitter', 'https://lien-vers-profil-twitter.com/'),
          ('Google+', 'https://lien-vers-profil-googleplus.com/'),
          ('ZdS', 'https://lien-vers-profil-zestedesavoir.com/'))

Ainsi, en la parcourant on va récupérer deux éléments, un "titre" et un lien vers une page web. Pour la parcourir, on fait donc de nouveau appel à la boucle for sur la variable globale SOCIAL, en précisant deux variables pour stocker les éléments :

{% for name, link in SOCIAL %}

Ensuite, il suffit de mettre ces éléments dans des balises <li> et <a> pour construire notre joli liste :

{% for name, link in SOCIAL %}
<li>
    <a href="{{ link }}">{{ name }}</a>
</li>
{% endfor %}

Notre liste va ainsi se construire auto-magiquement pour notre plus grand plaisir. Les deux variables étant de simples chaînes de caractères, il n’y a pas à accéder à un sous-élément.

Rendu final de base.html

Rendu final - base.html
Rendu final - base.html

One more thing : extends

Une petite dernière chose (promis c’est la dernière du chapitre !). Maintenant que nous avons une fondation solide, il faut pouvoir l’utiliser !

C’est ce à quoi nous servira le mot-clé extends, qui va informer Jinja que l’on souhaite "étendre", "compléter" un modèle. Ainsi, en tapant {% extends "base.html" %} au début de n’import lequel de vos fichier .html, Jinja utilisera automatiquement le fichier base.html et complètera les blocs personnalisables avec ce que vous souhaitez.

Par exemple, le rendu final que l’on a obtenu à la section précédente pourra être fait en tapant simplement :

{% extends "base.html" %}


{% block content %}
<h1>Le contenu ira ici !</h1>
{% endblock %}

Automatiquement Jinja saura que vous voulez travailler avec le squelette base.html et que vous souhaitez modifier le bloc content.


Eh bien, sacré morceau !

Ce chapitre fût assez dense, je le reconnais, mais il a posé les bases de plusieurs choses, comme l’utilisation de variables ainsi que celles des blocs. Tout ceci est essentiel pour la suite et il était donc important de bien les introduire.

Les chapitres suivants vont rentrer dans le vif du sujet en vous permettant de découvrir la personnalisation des différents types de pages que votre site proposera.