Preface
Goal: More about blog post content, Header, Footer, and Navigation.
Source Code
This article use tutor-08 theme. We will create it step by step.
Layout Preview for Tutor 08
1: Prepare
This preparation is required.
Preview: General
Consider redesign the looks of blog post. This is what we want to achieve in this tutorial.
Layout: Nunjucks Post
We need to redesign layout/post.njk
partial.
{% block main %}
{% set color = color or 'blue' %}
<main role="main"
class="column is-two-thirds">
<section class="main-wrapper {{ color }}">
<div class="blog white z-depth-3 hoverable">
<section class="blog-header {{ color }} lighten-5">
{% include "post/blog-header.njk" %}
</section>
<article class="blog-body" itemprop="articleBody">
{% if toc %}
{% include toc %}
{% endif %}
<div class="blog-content">
{{ content | safe }}
</div>
{% include "post/navigation.njk" %}
</article>
<section class="blog-footer {{ color }} lighten-5">
{% include "post/blog-footer.njk" %}
</section>
</div>
</section>
</main>
{% endblock %}
Talking about schema, you can read this nice site:
Partials: New Artefacts
The code above require three new partials.
Create three empty partial artefacts,
-
views/_includes/post/blog-header.njk
, -
views/_includes/post/blog-footer.njk
, -
views/_includes/post/navigation.njk
.
And one more artefact that is required in post/blog-header.njk
.
views/_includes/post/time-elapsed.njk
SASS: Main
And add relevant stylesheet
...
// Tailor Made
@import "main/layout-page"
@import "main/layout-content"
@import "main/decoration"
@import "main/pagination"
@import "main/list"
@import "post/content"
@import "post/title"
@import "post/list"
@import "post/navigation"
@import "post/reset-highlight"
Even with Bulma, we still need adjustment. For example, you need to reset the font size, in Bulma Heading.
2: Header
Consider begin with header.
Preview
Partial: Header: Minimum
The minimum header is simply showing title.
<div class="main_title">
<h2 class="title is-4" itemprop="name headline">
<a href="{{ page.url | url }}">
{{ renderData.title or title or metadata.title }}
</a></h2>
</div>
Partial: Header: Meta
Consider add meta data in post header.
- Author
{% if (author or metadata.author) %}
<div class="is-pulled-left">
<span class="meta_author tag is-small is-dark
indigo z-depth-1 hoverable">
<span class="fa fa-user"></span>
<span itemprop="author"
itemscope itemtype="http://schema.org/Person">
<span itemprop="name">{{ author or metadata.author }}</span></span>
</span>
</div>
{% endif %}
- Time Elapsed (include partial)
<div class="is-pulled-left">
<span class="meta-time tag is-small is-dark
green z-depth-1 hoverable">
{% include "post/time-elapsed.njk" %}
</span>
</div>
- Tags
<div class="is-pulled-right">
{% for tag in tags %}
{% set tagUrl %}/tags/{{ tag | slug }}/{% endset %}
<a href="{{ tagUrl | url }}">
<span class="tag is-dark is-small teal z-depth-1 hoverable">
<span class="fa fa-tag"></span> {{ tag }}</span></a>
{% endfor %}
</div>
I use bulma tag
,
with the eye candy Awesome Font.
Partial: Header: Complete Code
Here below is my actual code.
<div class="main_title">
<h2 class="title is-4" itemprop="name headline">
<a href="{{ page.url | url }}">
{{ renderData.title or title or metadata.title }}
</a></h2>
</div>
<div class="field p-t-5">
{% if (author or metadata.author) %}
<div class="is-pulled-left">
<span class="meta_author tag is-small is-dark
indigo z-depth-1 hoverable">
<span class="fa fa-user"></span>
<span itemprop="author"
itemscope itemtype="http://schema.org/Person">
<span itemprop="name">{{ author or metadata.author }}</span></span>
</span>
</div>
{% endif %}
<div class="is-pulled-left">
<span class="meta-time tag is-small is-dark
green z-depth-1 hoverable">
{% include "post/time-elapsed.njk" %}
</span>
</div>
<div class="is-pulled-right">
{% for tag in tags %}
{% set tagUrl %}/tags/{{ tag | slug }}/{% endset %}
<a href="{{ tagUrl | url }}">
<span class="tag is-dark is-small teal z-depth-1 hoverable">
<span class="fa fa-tag"></span> {{ tag }}</span></a>
{% endfor %}
</div>
</div>
<div class="is-clearfix p-b-5"></div>
3: Elapsed Time
As it has been mentioned above, we need special partial for this.
Issue
As a static generator,
eleventy
build the content whenever there are any changes.
If there are no changes, the generated time remain static.
It means we cannot tell relative time in string such as three days ago,
because after a week without changes, the time remain three days ago,
not changing into ten days ago.
The solution is using javascript. You can download the script from here
That way the time ago is updated dynamically as time passes,
as opposed to having to rebuild eleventy
every day.
Do not forget to put the script in static directory.
Partial: Time Elapsed
<time datetime="{{ page.date | date() }}"
itemprop="datePublished">
<span class="timeago"
datetime="{{ page.date | date('Y-MM-DD hh:mm:ss') }}">
</span></time>
<script src="{{ "/assets/js/timeago.min.js" | url }}"></script>
<script type="text/javascript">
var timeagoInstance = timeago();
var nodes = document.querySelectorAll('.timeago');
timeagoInstance.render(nodes, 'en_US');
timeago.cancel();
timeago.cancel(nodes[0]);
</script>
4: Footer
We already have header
.
Why do not we continue with footer
?
Preview
Partial: Footer
<footer class="columns m-5">
<div class="column is-narrow has-text-centered">
<img src="{{ "/assets/images/license/cc-by-sa.png" | url }}"
class="bio-photo"
height="31"
width="88"
alt="CC BY-SA 4.0"></a>
</div>
<div class="column has-text-left">
This article is licensed under:
<a href="https://creativecommons.org/licenses/by-sa/4.0/deed"
class="text-dark">
<b>Attribution-ShareAlike</b>
4.0 International (CC BY-SA 4.0)</a>
</div>
</footer>
Assets: License
I have collect some image related with license, so that you can use license easily.
5: Post Navigation
Each post also need simple navigation.
Preview
Issue
By default, eleventy
does not have built in function,
to handle post navigation.
After duckduckwent fo a while, I found this issue below:
Luckily, in that thread,
there is already a solution from Boris Schapira
.
He propose to use collection
, and it works well for me.
Colection: postsPrevNext
We need to add postPrevNext
filter in .eleventy.js
:
// Modified from Boris Schapira
eleventyConfig.addCollection("postsPrevNext", function(collection) {
var posts = collection.getAllSorted().filter(function(item) {
// Filter by layout name
return "post" === item.data.layout;
});
return helper.addPrevNext(posts);
});
Where the code in helper.js
file is as below:
// https://github.com/11ty/eleventy/issues/426
// Copy paste from Boris Schapira
exports.addPrevNext = function (collectionArray) {
const l = collectionArray.length;
for (let p = 0; p < l; p++) {
if (p > 0)
collectionArray[p].data.previous = {
title: collectionArray[p - 1].data.title,
url: collectionArray[p - 1].url
};
if (p < l - 1)
collectionArray[p].data.next = {
title: collectionArray[p + 1].data.title,
url: collectionArray[p + 1].url
};
}
return collectionArray;
}
Later you can use this filter as code below:
{% set posts = collections.postsPrevNext %}
{% for post in posts %}
...
{% endfor %}
Then you can access post.data.previous
and post.data.next
.
How does it works?
Magic
Imagine a blog with number of posts is 17
.
It has array of [0..l6]
of post,
-
For array
[1..16]
: add previous post data. -
For array
[0..15]
: add next post data.
I can understand the logic, but I still amaze, how he find the solution, and also pour in code well.
Partial: Navigation
{% set posts = collections.postsPrevNext %}
{% for post in posts %}
{% if (post.url == page.url) %}
<nav class="pagination is-centered"
role="navigation" aria-label="pagination">
<!-- Previous Page. -->
{% if post.data.previous %}
<a class="button is-small pagination-previous post-previous"
href="{{ post.data.previous.url | url }}"
title="{{ post.data.previous.title }}">
<span class="fas fa-chevron-left"></span> </a>
{% endif %}
{% if post.data.next %}
<a class="button is-small pagination-next post-next"
href="{{ post.data.next.url | url }}"
title="{{ post.data.next.title }}">
<span class="fas fa-chevron-right"></span></a>
{% endif %}
</nav>
{% endif %}
{% endfor %}
SASS: Post Navigation
Code above require two more classes
-
post-previous
-
post-next
// -- -- -- -- --
// _post-navigation.sass
a.post-previous:after
content: " Previous"
a.post-next:before
content: "Next "
a.post-previous:hover,
a.post-next:hover
background-color: map-get($yellow, 'lighten-2')
color: #000
.
6: Before Content: Table of Content
Sometimes we need to show recurring content, such as table of content in article series. For article series, we only need one TOC. And we do not want to repeat ourself, writing it over and over again.
To solve this case, we need help form frontmatter.
Layout: Nunjucks Post
We are going to insert TOC, before the content,
by including toc
something partial, provided from frontmatter.
{% block main %}
...
<article class="blog-body" itemprop="articleBody">
{% if toc %}
{% include toc %}
{% endif %}
<div class="blog-content">
{{ content | safe }}
</div>
{% include "post/navigation.njk" %}
</article>
...
{% endblock %}
Page Content: Example Frontmatter
Now here it is, the TOC
in frontmatter,
as shown in this example below.
---
layout : post
title : Marilyn Manson - Redeemer
date : 2015-07-25 07:35:05
tags : ["industrial metal", "90s"]
keywords : ["OST", "Queen of the Damned"]
author : marylin
toc : "toc/2015-07-marylin.njk"
---
...
Layout: Nunjucks TOC
Now you can have your TOC here.
<div class="white hoverable p-t-5 p-b-5">
<div class="widget-header blue lighten-4">
<strong>Table of Content</strong>
<span class="fa fa-archive is-pulled-right"></span>
</div>
<div class="widget-body blue lighten-5">
<ul class="widget-list">
<li><a href="{{ "/lyrics/eurythmics-sweet-dreams/" | url }}"
>Marilyn Manson - Sweet Dreams</a></li>
<li><a href="{{ "/lyrics/marylin-manson-redeemer/" | url }}"
>Marilyn Manson - Redeemer</a></li>
</ul>
</div>
</div>
Notice the .njk
file extension.
We are still using nunjucks.
Render: Browser
Now you can see the result in the browser.
7: Conclusion
It is enough for now. There are many part that can be enhanced, in about content area.
After all, it is about imagination.
What is Next ?
Consider continue reading [ Eleventy - Content - Markdown ]. We are going to explore markdown in blog post content.
Thank you for reading.