Create a website with Hugo
You’ll find in this article, All the element to create a website based on Hugo generator tool.
The topics covered are website architecture, theme creation, rss feed output definition, setting up the multilingual properties, …
What’s Hugo
Hugo is a static website generator written in Go and created by Steve Francia in 2013 (wikipedia)
The documentation is pretty complete and well written to handle the tool.
Objective
- Created a blog system linnked with a tags system allowing an eeasy navigation in a documentation spirit (wihtout using a wiki)
- Do not use external ressource (google,facebook,javascript,…)
- Do not retrieve visitor information (trackers,cookies,comments,…)
- Do as much as i can by myself
- Automatically generate html pages
Source code
All the source code of this website can be found on my github repository.
Starting up
Download
I mainly worked with the version 0.54.0, by retrieving the executable from the official release repository.
Direct link to the Windows10 (en 64bit) version or the Linux (en 64bit) version.
Handle Hugo
To create a first website, you can follow the official documentation. The steps are well explained and you will find a large number of themes choices to start handle the tool.
Website architecture
Base directories definition
1/documentation
2 +-- /archetypes
3 +-- /config
4 | +-- /_default
5 +-- /content
6 +-- /ressources
7 +-- /themes
- The folder “archetypes” allow to store the blog articles template
- The folder “config” allow to store global config files
- The folder “content” allow to store the content of the website (with *.md files)
- The foder “ressources” allow to store all the ressources elements generated
- The folder “themes” allow to store the theme files
Theme directories definition
The folders used for a theme (example with my own theme) :
1/themes
2 +-- /pragmatias
3 | +-- /i18n
4 | +-- /layouts
5 | | +-- /_default
6 | | +-- /partials
7 | | +-- 404.html
8 | | +-- index.html
9 | +-- /static
10 | | +-- /css
11 | | +-- /fonts
12 | | +-- /images
13 | | +-- /js
14 | +-- LICENSE
15 | +-- theme.toml
The theme is named pragmatias and the meta-data will be find in the file theme.toml An example of the file theme.toml content can be found in the officiel website.
Important folders :
- i18n : manage the multilingue parts (vocabulary)
- layouts : manage the display of the website
- static : store all the needed ressources (js,fonts,css,images)
Website structure definition
Create the file baseof.html in the folder /themes/pragmatias/layouts/_default
1<html lang="{{ with $.Site.LanguageCode }}{{ . }}{{ else }}fr{{ end }}">
2 {{- partial "head.html" . -}}
3 <body>
4 {{- partial "header.html" . -}}
5 <div id="content">
6 {{- block "main" . }}{{- end }}
7 </div>
8 {{- partial "footer.html" . -}}
9 </body>
10</html>
This page will be the default skeleton of each website page.
You need to create the following files in the folder /themes/pragmatias/layouts/partials
:
- head.html : allow to define the header part of each html page
- header.html : allow to define the navigation menu part (on top of the website)
- footer.html : allow to define the footer part of each html page
For the header and footer, the invocation of the files *.html is done using the following syntax :
1{{- partial "*.html" . -}}
For the body, the invocation of the files *.html is done in a more complex way. You will find all the information in the chapter about the creation of the website sections. (blog, tags, archives, …)
Navigation menu management
To manage the navigation menu Afin de gérer un menu de navigation depending on the screen size (mobile/desktop), i used the bootstrap javascript library .
Implementation steps are :
1. Download the bootstrap,jquery et popper javascripts files in the folders /themes/pragmatias/static/js
and /themes/pragmatias/static/css
- js/bootstrap.min.js
- js/bootstrap.min.js.map
- js/jquery-3.4.0.slim.min.js
- js/jquery-3.4.0.slim.min.js.map
- js/popper.min.js
- js/popper.min.js.map
- css/bootstrap.min.css
- css/bootstrap.min.css.map
2. Add the following information in the file /themes/pragmatias/layouts/partial/head.html
to load the needed Javascript and CSS files
1 <!-- Bootstrap CSS -->
2 <link rel="stylesheet" href="{{ .Site.BaseURL }}/css/bootstrap.min.css">
3
4 <!-- Optional JavaScript -->
5 <!-- jQuery first, then Popper.js, then Bootstrap JS -->
6 <script src="{{ .Site.BaseURL }}/js/jquery-3.4.0.slim.min.js"></script>
7 <script src="{{ .Site.BaseURL }}/js/popper.min.js"></script>
8 <script src="{{ .Site.BaseURL }}/js/bootstrap.bundle.min.js"></script>
3. Create the navigation menu /themes/pragmatias/layouts/partial/header.html
1 <div class="navbar navbar-expand-md prag-bg-primary prag-header" role="navigation">
2 <div class="container-fluid justify-content-center">
3
4 <button class="navbar-toggler justify-content-end prag-navbar" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
5 <span class="navbar-toggler-icon"></span>
6 </button>
7
8 <div class="collapse navbar-collapse" id="navbarSupportedContent">
9 <ul class="navbar-nav text-center">
10 {{ $currentPage := . }}
11 {{ range .Site.Menus.global }}
12 <li class="nav-item">
13 <a class="nav-link" href="{{ .URL | absLangURL }}">{{ .Name }}</a>
14 </li>
15 {{ end }}
16 </ul>
17 </div>
18
19 </div>
20 </div>
4. Create entries in the global menu, by adding the following information to the main configuration file config\_default\config.toml
1[[menus]]
2 [[menu.global]]
3 name = "Test"
4 weight = 1
5 identifier = "test"
6 url = "/test"
Blog section definition
To create articles, you need to define and manage a blog section.
1. Create a blog entrie in the global menu in the main configuration file config\_default\config.toml
1 [[menu.global]]
2 name = "Blog"
3 weight = 1
4 identifier = "blog"
5 url = "/blog"
2. Create the folder /content/blog
This folder will be used to store all the articles content of the blog section in the *.md format.
Example of a article content :
1---
2Categories : [""]
3Tags : [""]
4title : "First article with Hugo"
5date : 2019-01-01
6draft : false
7---
8
9Welcome !
3. Create the file /themes/pragmatias/layouts/blog/list.html
This file will be called by default by the file baseof.html when the url /blog will be called.
1{{ define "main" }}
2<div class="container">
3 {{ range (where .Site.Pages "Type" "blog") }}
4 <article class="list-blog-post">
5 <header>
6 <h2 class="list-blog-post-title">
7 <a href="{{ .RelPermalink }}">{{ .Title }}</a>
8 </h2>
9 </header>
10 <div class="list-blog-post-summary">
11 {{ .Summary | safeHTML }}
12 </div>
13 </article>
14 {{ end}}
15</div>
16{{ end }}
Note : the syntax
{{ define "main" }} ... {{ end }}
will replace the block{{- block "main" . }}{{- end }}
of the file baseof.html
4. Create the file /themes/pragmatias/layouts/blog/single.html
This file will be called by default by the file baseof.html when the url /blog/titre_article.html will be called to display the article content.
Un article being defined by the content of a file *.md in the folder /content/blog
1{{ define "main" }}
2<div class="container">
3 <article class="blog-post">
4 <header>
5 <h2 class="blog-post-title">
6 {{ .Title }}
7 </h2>
8 </header>
9 <main class="blog-post-main">
10 {{ .Content }}
11 </main>
12 </article>
13</div>
14{{ end }}
Tags section definition
To list the articles by Tags with Hugo.
1. Add an entrie Tags in the global menu in the main configuration file config\_default\config.toml
1 [[menu.global]]
2 name = "Tags"
3 weight = 2
4 identifier = "tags"
5 url = "/tags"
2. Add the following parameter in the main configuration file config\_default\config.toml
to activate the Tags management
1[taxonomies]
2 tag = "tags"
3. Add in the *.md files of the foler content/blog
, the parameter Tags with the desired keywords
1---
2Tags : ["Tags1","Tags2"]
3---
4. Create the file /themes/pragmatias/layouts/_default/terms.html
to manage the display of the url /Tags
1{{ define "main" }}
2<div class="container prag-tags">
3 {{ $type := .Type }}
4 {{ range $key, $value := .Data.Terms.ByCount }}
5 {{ $name := .Name }}
6 {{ $count := .Count }}
7 {{ with $.Site.GetPage (printf "/%s/%s" $type $name) }}
8 <p>
9 <a class="" href="{{ .Permalink }}">
10 {{ $name | humanize }}
11 </a>
12 </p>
13 {{ end }}
14 {{ end }}
15</div>
16{{ end }}
5. Create the file /themes/pragmatias/layouts/_default/taxonomy.html
to manage the display of a Tags content (articles listing)
1{{ define "main" }}
2<div class="container">
3 {{ range (where .Site.Pages "Type" "blog") }}
4 <article class="list-blog-post">
5 <header>
6 <h2 class="list-blog-post-title">
7 <a href="{{ .RelPermalink }}">{{ .Title }}</a>
8 </h2>
9 </header>
10 <div class="list-blog-post-summary">
11 {{ .Summary | safeHTML }}
12 </div>
13 </article>
14 {{ end}}
15</div>
16{{ end }}
Archives section definition
To list all the articles by year, you need to create an Archives section.
1. Add an entrie Archives in the global menu in the main configuration file config\_default\config.toml
1[[menus]]
2 [[menu.global]]
3 name = "Archives"
4 weight = 3
5 identifier = "archives"
6 url = "/archives"
2. Create the folder content\archives
and the file _index.md with the following content
1---
2Title : "Archives"
3date : 2019-01-01
4---
3. Create the file /themes/pragmatias/layouts/_default/list.html
to manage the display of the url /Archives
1{{ define "main" }}
2<div class="container">
3 {{ $v1 := where .Site.RegularPages "Type" "blog" }}
4 {{ range ($v1.GroupByDate "2006") }}
5 <div class="arch-posts-group">
6 <div class="arch-post-year">{{ .Key }}</div>
7 <ul class="arch-post-list">
8 {{ range (where .Pages "Type" "blog") }}
9 <li class="arch-post-item">
10 <a href="{{ .RelPermalink }}">
11 <span class="arch-post-title">{{ .Title }}</span>
12 </a>
13 </li>
14 {{ end }}
15 </ul>
16 </div>
17 {{ end }}
18</div>
19{{ end }}
Implementation of multilingual
Definition of two language (fr/en)
1. Define the default language by adding the following parameter at the beginning of the main configuration file /config/_default/config.toml
1languageCode = "en"
2DefaultContentLanguage = "en"
2. Define other language by adding the following parameters at the end of the main configuration file /config/_default/config.toml
1[languages]
2 [languages.en]
3 weight = 10
4 languageName = "English"
5 contentDir = "content/en"
6 languageCode = "en"
7 [languages.en.params]
8 imagePNG = "united-kingdom-flag-round-xs.png"
9
10 [languages.fr]
11 weight = 20
12 languageName = "Français"
13 contentDir = "content/fr"
14 languageCode = "fr"
15 [languages.fr.params]
16 imagePNG = "france-flag-round-xs.png"
3. Define the english dictionary by creating the file en.toml in the folder /themes/pragmatias/i18n
1[more_read]
2other = "Read more"
4. Define the french dictionary by creating the file fr.toml in the folder /themes/pragmatias/i18n
1[more_read]
2other = "Continer la lecture"
5. To use the dictionary term in the html files of the folder /themes/pragmatias/layouts
, you need to use the following syntax :
1{{ i18n "more_read" }}
Management of months according to language
1. Add the translation of the months in the english dictionary /themes/pragmatias/i18n/en.toml
1[January]
2other = "January"
3[February]
4other = "February"
5[March]
6other = "March"
7[April]
8other = "April"
9[May]
10other = "May"
11[June]
12other = "June"
13[July]
14other = "July"
15[August]
16other = "August"
17[September]
18other = "September"
19[October]
20other = "October"
21[November]
22other = "November"
23[December]
24other = "December"
2. Add the translation of the months in the french dictionary /themes/pragmatias/i18n/fr.toml
1[January]
2other = "Janvier"
3[February]
4other = "Février"
5[March]
6other = "Mars"
7[April]
8other = "Avril"
9[May]
10other = "Mai"
11[June]
12other = "Juin"
13[July]
14other = "Juillet"
15[August]
16other = "Aout"
17[September]
18other = "Septembre"
19[October]
20other = "Octobre"
21[November]
22other = "Novembre"
23[December]
24other = "Décembre"
3. Use the following syntax to display the dates in the html files in the folder /themes/pragmatias/layouts
1{{.Date.Day}} {{i18n .Date.Month}} {{.Date.Year}}
Added an RSS feed for the Blog section
1. Add output information in the main configuration file /config/_default/config.toml
1[outputs]
2 home = [ "HTML", "RSS" ]
3 section = [ "HTML"]
4 taxonomy = [ "HTML"]
2. Create the RSS feed definition in the file /themes/pragmatias/layouts/_default/rss.xml
1<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
2 <channel>
3 <title>{{ .Site.Title }}</title>
4 <link>{{ "/blog" | absLangURL }}</link>
5 <description>{{ i18n "rss_content" }} {{ .Site.Title }}</description>
6 <generator>Hugo {{ .Hugo.Version }}</generator>
7 {{ with .Site.LanguageCode }}
8 <language>{{.}}</language>
9 {{end}}
10 {{ with $.Site.Author.name }}
11 <webMaster>{{.}}</webMaster>
12 {{end}}
13 {{ with .Site.Copyright }}
14 <copyright>{{.}}</copyright>
15 {{end}}
16 <lastBuildDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</lastBuildDate>
17 <atom:link href="{{ "/feed.xml" | absLangURL }}" rel="self" type="application/rss+xml" />
18 {{ range first 10 (where .Data.Pages "Type" "blog") }}
19 <item>
20 <title>{{ .Title }}</title>
21 <link>{{ .Permalink }}</link>
22 <pubDate>
23 {{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}
24 </pubDate>
25 <lastModDate>
26 {{ .Lastmod.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}
27 </lastModDate>
28 <guid>{{ .Permalink }}</guid>
29 <description>{{ .Summary | html }}</description>
30 </item>
31 {{ end }}
32 </channel>
33</rss>
3. Add the following information in the file /themes/pragmatias/layouts/partials/head.html
:
1 <!-- Flux RSS -->
2 <link rel="alternate" type="application/rss+xml" href="{{ "/feed.xml" | absLangURL }}" />
4. Add a svg RSS icon in the file /themes/pragmatias/layouts/partials/header.html
:
1 <li class="nav-item">
2 <a href="{{ "/feed.xml" | absLangURL }}" title="{{ .Site.Title}}" class="prag_header_svg mr-1 ml-1">
3 {{ partial "svg/social-rss-circle-internet.svg" (dict "size" "24px") }}
4 </a>
5 </li>
Manage the main CSS file
Utilisation d’un fichier CSS
1. Create the main CSS file in the folder /themes/pragmatias/static/css
1html {}
2
3body {}
2. Add the call of the CSS file in the file /themes/pragmatias/layouts/partials/head.html
1 <link rel="stylesheet" href="{{ .Site.BaseURL }}/css/pragmatias.css">
Manage colors
To manage all the website colors in one place.
1. Define all the needed variables at the beginning of the CSS file
1:root {
2 --color-bg-primary:#fdfaee;
3 --color-fg-head-titre:#03416d;
4}
2. Use the following syntax to call the wanted color variable
1body {
2 background-color: var(--color-bg-primary);
3 color: var(--color-fg-blog-texte);
4}
Fonts management
To be able to use a specific font without using an external webservice.
1. Copy the files of the chosen font in woff and woff2 format in the folder /themes/pragmatias/static/fonts
- OpenSans-Regular.woff
- OpenSans-Regular.woff2
- OpenSans-Bold.woff
- OpenSans-Bold.woff2
- OpenSans-Italic.woff
- OpenSans-Italic.woff2
- OpenSans-BoldItalic.woff
- OpenSans-BoldItalic.woff2
2. Define the fonts in the CSS file
1@font-face {
2 font-family: 'OpenSans';
3 src: url('/fonts/OpenSans-Regular.woff2') format('woff2'), url('/fonts/OpenSans-Regular.woff') format('woff');
4 font-weight: 400;
5 font-style: normal;
6}
7
8@font-face {
9 font-family: 'OpenSans';
10 src: url('/fonts/OpenSans-Bold.woff2') format('woff2'), url('/fonts/OpenSans-Bold.woff') format('woff');
11 font-weight: 700;
12 font-style: normal;
13}
14
15@font-face {
16 font-family: 'OpenSans';
17 src: url('/fonts/OpenSans-Italic.woff2') format('woff2'), url('/fonts/OpenSans-Italic.woff') format('woff');
18 font-weight: 400;
19 font-style: italic;
20}
21
22@font-face {
23 font-family: 'OpenSans';
24 src: url('/fonts/OpenSans-BoldItalic.woff2') format('woff2'), url('/fonts/OpenSans-BoldItalic.woff') format('woff');
25 font-weight: 700;
26 font-style: italic;
27}
3. Use the name of the font in the CSS properties
1body {
2 font-family: 'OpenSans';
3}