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.
Sommaire
- Inventaire des fichiers nécessaires
- base.html, la colonne vertébrale du site
- La section head
- La section body
- One more thing : extends
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.html
n 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 !!
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 :
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;
}
Allure globale
Voici le rendu que vous devriez avoir :
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
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.