Hugo configuration base

This commit is contained in:
Thomas Schwery 2020-01-28 21:18:20 +01:00
parent 0dc906b101
commit 44b9d01ba7
62 changed files with 395 additions and 1562 deletions

13
.gitignore vendored
View file

@ -1,13 +1,4 @@
# Build directory
build
/public/
/resources/
# Dependency directories
node_modules
jspm_packages
# Optional npm cache directory
.npm
# Output files
*.pdf
*.epub

View file

@ -1,22 +1,28 @@
image: node:10.16
cache:
paths:
- node_modules/
variables:
S3_BUCKET_NAME: recettes.inf3.ch
AWS_BUCKET_REGION: us-east-1
node-build:
stage: build
gohugo-build-branch:
image: monachus/hugo:v0.63.1
script:
- npm ci
- npm run build
- hugo -b http://${S3_BUCKET_NAME}.s3-website-${AWS_BUCKET_REGION}.amazonaws.com/${CI_COMMIT_REF_SLUG}
artifacts:
expire_in: 1 week
paths:
- build
- public
except:
- /^master$/
gohugo-build-master:
image: monachus/hugo:v0.63.1
script:
- hugo
artifacts:
expire_in: 1 week
paths:
- public
only:
- /^master$/
deploys3-branch:
image: "python:latest"
@ -24,7 +30,7 @@ deploys3-branch:
before_script:
- pip install awscli
script:
- aws s3 cp build s3://${S3_BUCKET_NAME}/${CI_COMMIT_REF_SLUG} --recursive
- aws s3 cp public s3://${S3_BUCKET_NAME}/${CI_COMMIT_REF_SLUG} --recursive
environment:
name: ${CI_COMMIT_REF_SLUG}
url: http://${S3_BUCKET_NAME}.s3-website-${AWS_BUCKET_REGION}.amazonaws.com/${CI_COMMIT_REF_SLUG}
@ -38,7 +44,7 @@ deploys3-master:
before_script:
- pip install awscli
script:
- aws s3 cp build s3://${S3_BUCKET_NAME}/ --recursive
- aws s3 cp public s3://${S3_BUCKET_NAME}/ --recursive
environment:
name: ${CI_COMMIT_REF_SLUG}
url: http://${S3_BUCKET_NAME}.s3-website-${AWS_BUCKET_REGION}.amazonaws.com/

View file

@ -8,10 +8,9 @@ et les modifications intégrées sur la branche `master`.
## URLs utiles
## Usage
Le blog peut être généré en local avec `nodejs`. Il suffit d'installer
les dépendances avec `npm ci`, puis, une fois celles-ci installées,
lancer la génération avec `npm run build`.
## Installation
1. `curl -SsL https://github.com/gohugoio/hugo/releases/download/v0.63.2/hugo_0.63.2_Linux-64bit.tar.gz | tar zxvf - hugo`
2. `./hugo serve`
## Ajouter des recettes
@ -27,15 +26,7 @@ lancer la génération avec `npm run build`.
9. Suivre le lien donné pour créer une Merge Request avec les nouvelles
recettes.
### Visualiser les changements
* En local, il est possible de compiler le site avec `npm run build` puis
visualiser le site généré avec `http-server build`.
* A distance, GitLab compile et déploie sur le site sur une addresse de prévisualisation
disponible dans la MR.
## Technologies
* Le site est généré statiquement avec [metalsmith](https://metalsmith.io/)
* Le site est généré statiquement avec [Hugo](https://gohugo.io)
* Les fichiers générés sont déployés automatiquement dans un bucket Amazon S3
* Le site web est distribué par Amazon CloudFront
* Un fichier epub avec les recettes est généré à partir des pages générées
statiquement.

276
build.js
View file

@ -1,276 +0,0 @@
var metalsmith = require('metalsmith')
var layouts = require('metalsmith-layouts')
var markdown = require('metalsmith-markdown')
var collections = require('metalsmith-collections')
var pagination = require('metalsmith-pagination')
var paths = require('metalsmith-paths')
var filemetadata = require('metalsmith-filemetadata')
var matters = require('metalsmith-matters')
var postcss = require('metalsmith-postcss')
var discoverPartials = require('metalsmith-discover-partials')
var fs = require('fs');
var moment = require('moment');
var _ = require('underscore');
var handlebars = require('handlebars');
var handlebarsLayout = require('handlebars-layouts');
moment.locale('fr');
//--------------------------- Handlebars -----------------------------//
handlebars.registerHelper(handlebarsLayout(handlebars));
handlebars.registerHelper('formatDate', function(date) {
return moment(new Date(date)).format('DD MMMM YYYY');
});
handlebars.registerHelper('formatTimestamp', function(date) {
return moment(date, 'X').format('MMMM D, YYYY HH:mm:ss');
});
function compareWith(v1, v2, operator) {
var itm = false;
switch (operator) {
case '==':
itm = (v1 == v2);
break;
case '!=':
itm = (v1 != v2);
break;
case '===':
itm = (v1 === v2);
break;
case '<':
itm = (v1 < v2);
break;
case '<=':
itm = (v1 <= v2);
break;
case '>':
itm = (v1 > v2);
break;
case '>=':
itm = (v1 >= v2);
break;
}
return itm;
}
handlebars.registerHelper('eachSorted', function(context, member, item, order, options) {
var tot = '';
var entries = _.sortBy(context, function(item){
return item[member][item] === undefined? 0 : item[member][item];
})
if (order === 'desc') {
entries = entries.reverse();
}
for (var i = 0; i < entries.length; i++) {
tot += options.fn(entries[i]);
}
return tot;
});
handlebars.registerHelper('eachCenter', function(context, number, index, options) {
if (number > context.length) {
number = context.length;
}
var start = index - number / 2;
if (start < 0) {
start = 0;
}
var end = start + number;
if (end > context.length) {
end = context.length;
start = end - number;
}
var tot = '';
for (var i = start; i < end; i++) {
if (i === index) {
tot += options.inverse(context[i]);
} else {
tot += options.fn(context[i]);
}
}
return tot;
});
handlebars.registerHelper('ifCond', function (v1, operator, v2, options) {
if (compareWith(v1, v2, operator)) {
return options.fn(this);
} else {
return options.inverse(this);
}
});
//--------------------------- Build pipeline -------------------------//
metalsmith(__dirname)
.source('recettes')
.metadata(require('./config/metadata'))
.frontmatter(false)
.use(matters(require('./config/matters')))
.use(filemetadata(require('./config/filemetadata')))
.use(addCategory())
.use(createCategories())
.use(collections(require('./config/collections')))
.use(markdown(require('./config/markdown')))
.use(pagination(require('./config/pagination')))
.use(paths(require('./config/paths')))
.use(discoverPartials(require('./config/layouts-partials')))
.use(layouts(require('./config/layouts')))
.use(copyVendor())
.use(postcss(require('./config/postcss')))
.use(epubGen())
.destination('build')
.build(function (err) {
if (err) {
throw err
}
})
//--------------------- Helper functions -----------------------------//
// Generates an epub file from the list of recettes.
function epubGen() {
var fs = require('fs');
var epubGenerator = require('epub-generator');
return function(files, metalsmith, done) {
var epubStream = epubGenerator({
title: metalsmith.metadata().site.title,
author: metalsmith.metadata().site.authors,
language: metalsmith.metadata().site.language
});
for (var f in files) {
if (files[f].type == 'recette') {
epubStream.add(f, files[f].contents, {
title: files[f].data.title,
toc: true
});
} else if (files[f].type == 'style') {
epubStream.add(f, files[f].contents, {
toc: false
});
}
}
epubStream.end()
.pipe( fs.createWriteStream('basic.epub') )
.on('error', function(err){
console.trace(err);
});
return done();
}
}
function createCategories() {
return function(files, metalsmith, done) {
var tagList = {};
for (var fileName in files) {
var data = files[fileName];
if (!data) {
continue;
}
var tagsData = data.category;
if (!tagsData) {
continue;
}
if (typeof tagsData === 'string') {
tagsData = tagsData.split(',');
}
data.category = [];
tagsData.forEach(function(rawTag) {
var tag = String(rawTag).trim();
data.category.push(tag);
if (!tagList[tag]) {
tagList[tag] = [];
}
tagList[tag].push(fileName);
});
}
var metadata = metalsmith.metadata();
metadata.tags = metadata.tags || {};
for (var tag in tagList) {
var posts = tagList[tag].map(function(fileName) {
return files[fileName];
});
var tagPage = files[tag + '/index.md'];
tagPage.tag = tag;
tagPage.posts = posts;
tagPage.title = tagPage.data.title;
posts.forEach(function(post) {
post.categoryPage = tagPage;
});
metadata['tags'][tag] = tagPage;
}
tagList = {};
return done();
}
}
// Adds the category to the recette entry based on the parent directory
function addCategory() {
return function(files, metalsmith, done) {
for (var f in files) {
if (f.indexOf('.md') > 0 && f.indexOf('index.md') < 0) {
var idx = f.indexOf('/');
var cat = f.substring(0, idx);
files[f].category = cat;
files[f].title = files[f].data.title;
}
}
return done();
}
}
function copyVendor() {
return function(files, metalsmith, done){
var styleFiles = fs.readdirSync('styles');
for (var i = 0; i < styleFiles.length; i++) {
var stylePath = 'styles/' + styleFiles[i];
files[stylePath] = {
contents: fs.readFileSync(stylePath),
type: 'style'
};
}
var fontFiles = fs.readdirSync('fonts');
for (var i = 0; i < fontFiles.length; i++) {
var fontPath = 'fonts/' + fontFiles[i];
files[fontPath] = {
contents: fs.readFileSync(fontPath),
type: 'font'
};
}
return done();
};
}

20
config.toml Normal file
View file

@ -0,0 +1,20 @@
contentDir = "content"
layoutDir = "layouts"
publishDir = "public"
buildDrafts = false
baseURL = "https://recettes.inf3.ch"
canonifyURLs = true
theme = "hugo-recettes"
languageCode = "fr"
title = "Recettes"
author = "Anne-Catherine Pormann et Thomas Schwery"
copyright = ""
[taxonomies]
category = "categories"
tag = "tags"
[params]
logo = "/images/logo.png"

View file

@ -1,38 +0,0 @@
module.exports = {
recettes: {
pattern: '*/*.md',
sortBy: function(oa, ob) {
a = oa.data.publication;
b = ob.data.publication;
if (!a && !b) {
return 0;
}
if (!a) {
return -1;
}
if (!b) {
return 1;
}
if (a < b) {
return -1;
}
if (a > b) {
return 1;
}
ta = oa.data.title;
tb = ob.data.title;
return (ta > tb) ? -1 : 1;
},
reverse: true
},
categories: {
pattern: '*/index.md',
sortBy: 'title'
},
index: {
pattern: '*/*.md',
sortBy: 'title'
}
}

View file

@ -1,15 +0,0 @@
module.exports = [
{
pattern: '*/*.md',
metadata: {
layout: 'recette.hbs',
type: 'recette'
}
},{
pattern: '*/index.md',
metadata: {
layout: 'tag.hbs',
type: 'tag'
}
}
]

View file

@ -1,3 +0,0 @@
module.exports = {
preserveComments: 'some'
}

View file

@ -1,3 +0,0 @@
module.exports = {
directory: "templates/partials",
}

View file

@ -1,6 +0,0 @@
module.exports = {
engine: 'handlebars',
default: 'test.hbs',
directory: 'templates',
partials: 'templates/partials'
}

View file

@ -1,4 +0,0 @@
module.exports = {
gfm: true,
tables: true
}

View file

@ -1,3 +0,0 @@
module.exports = {
}

View file

@ -1,8 +0,0 @@
module.exports = {
site: {
title: 'Recettes',
url: 'none',
authors: 'Anne-Catherine Portmann, Thomas Schwery',
language: 'fr-CH'
}
}

View file

@ -1,19 +0,0 @@
module.exports = {
'collections.recettes': {
perPage: 20,
first: 'index.html',
layout: 'index.hbs',
path: 'page/:num/index.html',
filter: 'type == \'recette\''
},
'collections.index': {
perPage: 250,
first: 'search.html',
layout: 'search.hbs',
path: 'search/:num/index.html',
filter: 'type == \'recette\'',
groupBy: function(data) {
return data.title.normalize('NFD').charAt(0);
}
}
}

View file

@ -1,3 +0,0 @@
module.exports = {
}

View file

@ -1,5 +0,0 @@
module.exports = {
plugins: {
'autoprefixer': {}
}
}

View file

@ -1,3 +0,0 @@
module.exports = {
}

View file

@ -1,4 +0,0 @@
module.exports = {
src: 'vendor',
dest: 'vendor'
}

View file

@ -0,0 +1,4 @@
---
title: Recettes
type: sectionroot
---

View file

@ -1,5 +1,4 @@
---
data:
title: Accompagnements
title: Accompagnements
type: section
---
Test d'accompagnements avec commentaire

View file

@ -1,4 +1,4 @@
---
data:
title: Recettes de base
title: Recettes de base
type: section
---

View file

@ -1,4 +1,4 @@
---
data:
title: Boissons et cocktails
title: Boissons et cocktails
type: section
---

View file

@ -1,4 +1,4 @@
---
data:
title: Desserts
title: Desserts
type: section
---

View file

@ -1,4 +1,4 @@
---
data:
title: Divers
title: Divers
type: section
---

View file

@ -1,4 +1,4 @@
---
data:
title: Hors d'oeuvres et entrées
title: Hors d'oeuvres et entrées
type: section
---

View file

@ -1,4 +1,4 @@
---
data:
title: Plats exotiques
title: Plats exotiques
type: section
---

View file

@ -1,4 +1,4 @@
---
data:
title: Glaces et sorbets
title: Glaces et sorbets
type: section
---

View file

@ -1,4 +1,4 @@
---
data:
title: Pâtes à pain
title: Pâtes à pain
type: section
---

View file

@ -1,4 +1,4 @@
---
data:
title: Pommes de terre
title: Pommes de terre
type: section
---

View file

@ -1,4 +1,4 @@
---
data:
title: Pates
title: Pates
type: section
---

View file

@ -1,4 +1,4 @@
---
data:
title: Poissons et fruits de mer
title: Poissons et fruits de mer
type: section
---

View file

@ -1,4 +1,4 @@
---
data:
title: Quiches et tartes salées
title: Quiches et tartes salées
type: section
---

View file

@ -1,4 +1,4 @@
---
data:
title: Quinoa
title: Quinoa
type: section
---

View file

@ -1,4 +1,4 @@
---
data:
title: Riz et risottos
title: Riz et risottos
type: section
---

View file

@ -1,4 +1,4 @@
---
data:
title: Salades
title: Salades
type: section
---

View file

@ -1,4 +1,4 @@
---
data:
title: Sauces
title: Sauces
type: section
---

View file

@ -1,4 +1,4 @@
---
data:
title: Soupes et potages
title: Soupes et potages
type: section
---

View file

@ -1,4 +1,4 @@
---
data:
title: Viandes
title: Viandes
type: section
---

1052
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,38 +0,0 @@
{
"name": "inf3-recettes",
"version": "0.1.0",
"private": true,
"dependencies": {
"autoprefixer": "^9.6.1",
"epub-generator": "^1.0.1",
"handlebars": "^4.4.0",
"handlebars-layouts": "^3.1.0",
"jstransformer-handlebars": "^1.1.0",
"metalsmith": "^2.3.0",
"metalsmith-collections": "^0.9.0",
"metalsmith-discover-partials": "^0.1.2",
"metalsmith-filemetadata": "^1.0.0",
"metalsmith-layouts": "^2.3.1",
"metalsmith-markdown": "^1.2.0",
"metalsmith-matters": "^1.2.0",
"metalsmith-pagination": "^1.4.1",
"metalsmith-paths": "^3.0.1",
"metalsmith-permalinks": "^2.2.0",
"metalsmith-postcss": "^4.2.0",
"moment": "^2.24.0",
"underscore": "^1.9.1"
},
"scripts": {
"build": "node build.js",
"watch": "npm-watch"
},
"watch": {
"build": {
"patterns": [
"recettes/*/*.md"
],
"extensions": "hbs,md"
}
},
"license": "MIT"
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,22 @@
MIT License
Copyright (c) 2016 OCHIISHI Koichiro
Copyright (c) 2019 SCHWERY Thomas
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

View file

@ -0,0 +1,7 @@
+++
date = "now()"
slug = ""
tags = ["", ""]
title = ""
+++

File diff suppressed because one or more lines are too long

View file

@ -41,3 +41,7 @@
.navigation {
text-align: center;
}
small {
font-size: 0.95rem;
}

View file

@ -0,0 +1,10 @@
{{ partial "header.html" . }}
<main role="main">
<div>
<h2 class="mb-5">Page non disponible</h1>
<h3 id="entry-title"><a href="{{ "/" | relURL }}">Retourner à l'accueil</a></h2>
</div>
</main>
{{ partial "footer.html" . }}

View file

@ -0,0 +1,14 @@
{{ partial "header.html" . }}
<main role="main">
<h1 class="list-title">{{ .Title }}</h1>
{{ range .Data.Pages }}
<article itemscope itemtype="http://schema.org/Blog">
<h2 class="entry-title" itemprop="headline">
<a href="{{ .Permalink }}">{{ .Title }}</a>
</h2>
</article>
{{ end }}
</main>
{{ partial "footer.html" . }}

View file

@ -0,0 +1,16 @@
{{ partial "header.html" . }}
<main role="main">
<article itemscope itemtype="http://schema.org/BlogPosting">
<header class="header">
<h2 class="content-title">
{{ .Title }}
</h2>
</header>
<section class="content">
{{ .Content }}
</section>
</article>
</main>
{{ partial "footer.html" . }}

View file

@ -0,0 +1,26 @@
{{ partial "header.html" . }}
<div class="container">
<div class="content row">
<div class="col-sm-8">
<main role="main">
{{ $recettePages := where .Site.Pages ".Params.data" "!=" nil }}
{{ $recetteSorted := sort $recettePages ".Params.data.publication" "desc" }}
{{ $paginator := .Paginate $recetteSorted 20 }}
{{ range $paginator.Pages }}
{{ partial "list-entry.html" . }}
{{ end }}
</main>
</div>
<div class="col-sm-4">
{{ partial "navbox.html" . }}
</div>
</div>
<div class="content row justify-content-center">
<div class="col-4 mb-3 mt-3">
{{ template "_internal/pagination.html" . }}
</div>
</div>
</div>
{{ partial "footer.html" . }}

View file

@ -0,0 +1,14 @@
{{ partial "header.html" . }}
<main role="main">
<article itemscope itemtype="http://schema.org/BlogPosting">
<h1 class="entry-title" itemprop="headline">{{ .Title }}</h1>
<span class="entry-meta">
</span>
<section itemprop="entry-text">
{{ .Content }}
</section>
</article>
</main>
{{ partial "footer.html" . }}

View file

@ -0,0 +1,4 @@
</article>
</div>
</body>
</html>

View file

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html lang="{{ with .Site.LanguageCode }}{{ . }}{{ else }}en-US{{ end }}">
<head>
<meta charset="utf-8">
{{ hugo.Generator }}
{{ $bootstrapCSS := resources.Get "css/bootstrap.min.css" | resources.Fingerprint }}
{{ $customCSS := resources.Get "css/customHighlight.css" | resources.Minify | resources.Fingerprint }}
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="//fonts.googleapis.com/css?family=Roboto:400,700" rel="stylesheet" type="text/css">
<link rel="stylesheet" href="{{ $bootstrapCSS.Permalink }}">
<link rel="stylesheet" href="{{ $customCSS.Permalink }}">
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
<link rel="icon" href="/favicon.ico" type="image/x-icon">
<link rel="alternate" href="/index.xml" type="application/rss+xml" title="{{ .Site.Title }}">
<title>{{ $isHomePage := eq .Title .Site.Title }}{{ .Title }}{{ if eq $isHomePage false }} - {{ .Site.Title }}{{ end }}</title>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light mb-5">
<div class="container">
<div class="navbar-nav">
<a class="nav-link" href="/index.html">
<h3>
Recettes
</h3>
</a>
</div>
</div>
</nav>
<div class="container">
<article class="content">

View file

@ -0,0 +1,15 @@
<article itemscope itemtype="http://schema.org/Blog">
<h4 class="list-content-title pb-3">
<a href="{{ .RelPermalink }}index.html">{{ .Params.data.title }}</a>
<small class="text-muted font-weight-light">
{{ with .Params.data.publication }}
<time itemprop="datePublished" datetime="{{ dateFormat "2006-01-02" . }}">
{{ dateFormat "January 02, 2006" . }}
</time>
{{ end }}
{{ .Params.data.portion }}
{{ with .Params.data.time }} • {{ . }}{{ end }}
</small>
</h4>
</article>

View file

@ -0,0 +1,16 @@
{{ $parentPage := . }}
<div class="list-tags list">
<ul class="list-group list-group-flush">
{{ with .Site.GetPage "/recettes" }}
{{ range .Sections }}
{{ if eq $parentPage.File.UniqueID .File.UniqueID }}
{{ $active := "active" }}
{{ end }}
<a class="list-group-item d-flex justify-content-between list-group-item-action align-items-center $active" href="{{ .Permalink }}">
{{ .Title }}
<span class="badge badge-secondary badge-pill">{{ len .Pages }}</span>
</a>
{{ end }}
{{ end }}
</ul>
</div>

View file

@ -0,0 +1,65 @@
{{ partial "header.html" . }}
<main role="main">
<article itemscope itemtype="http://schema.org/BlogPosting">
<header class="header">
<h2 class="content-title">
{{ .Params.data.title }}
</h2>
<div class="header-container row">
<div class="header-category col-sm-4">
<a href="{{ .CurrentSection.Permalink }}">
{{ .CurrentSection.Title }}
</a>
</div>
<div class="col-sm-2">
</div>
<div class="header-metadata col-sm-6">
{{ with .Params.data.description }}{{ . }} • {{ end }}
{{ .Params.data.portion }}
{{ with .Params.data.time }} • {{ . }}{{ end }}
</div>
</div>
</header>
<section class="content">
{{range .Params.data.steps }}
<div class="row step">
<ul class="col-sm-5 ingredients">
{{ range .ingredients }}
<li class="row ingredient">
<span class="col-sm-4 ing-quantity">{{ .quantity }} {{ .unit }}</span>
<span class="col-sm-8 ing-name">{{ .name }}</span>
{{ with .comment }}<span class="ing-comment">{{ . }}</span>{{ end }}
</li>
{{ end }}
</ul>
<div class="col-sm-7 instructions">
{{ .instructions }}
</div>
</div>
{{ end }}
{{ .Content }}
</section>
<section class="comments hidden-print">
<h2>Commentaires</h2>
<div id="disqus_thread"></div>
<script>
(function() {
var d = document, s = d.createElement('script');
s.src = '//inf3recettes.disqus.com/embed.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
</section>
</article>
</main>
{{ partial "footer.html" . }}

View file

@ -0,0 +1,19 @@
{{ partial "header.html" . }}
<div class="container">
<div class="content row">
<div class="col-sm-8">
<h2 class="pb-3">{{ .Title }}</h2>
<main role="main">
{{ range sort .Pages ".Params.data.title" "asc" }}
{{ partial "list-entry.html" . }}
{{ end }}
</main>
</div>
<div class="col-sm-4">
{{ partial "navbox.html" . }}
</div>
</div>
</div>
{{ partial "footer.html" . }}

View file

@ -0,0 +1,22 @@
{{ partial "header.html" . }}
<div class="container">
<div class="content row">
<div class="col-sm-8">
<main role="main">
<h2 class="list-title">Catégories</h2>
{{ range .Sections }}
<h4 class="entry-title" itemprop="headline">
<a href="{{ .Permalink }}">{{ .Title }}</a>
<small class="text-muted">{{ len .Pages }} recettes</small>
</h4>
{{ end }}
</main>
</div>
<div class="col-sm-4">
{{ partial "navbox.html" . }}
</div>
</div>
</div>
{{ partial "footer.html" . }}

View file

@ -0,0 +1,11 @@
name = "Hugo Zen"
license = "MIT"
licenselink = "https://github.com/rakuishi/hugo-zen/blob/master/LICENSE.md"
description = "Hugo Zen is a minimal hugo theme."
tags = ["blog"]
features = ["blog", "themes"]
min_version = 0.13
[author]
name = "OCHIISHI Koichiro"
homepage = "http://rakuishi.com/"