Skip to content

Commit e3cd087

Browse files
committed
Implemented blog post pagination.
With the new design on the blog post index, listing all blog posts is not a viable option anymore. This adds pagination by year and displaying summary for the top 10 posts per page.
1 parent afb299a commit e3cd087

6 files changed

Lines changed: 72 additions & 24 deletions

File tree

build.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const markdown = require('metalsmith-markdown')
1414
const prism = require('metalsmith-prism')
1515
const stylus = require('metalsmith-stylus')
1616
const permalinks = require('metalsmith-permalinks')
17+
const pagination = require('metalsmith-yearly-pagination')
1718
const marked = require('marked')
1819
const path = require('path')
1920
const fs = require('fs')
@@ -126,6 +127,13 @@ function buildlocale (source, locale) {
126127
refer: false
127128
}
128129
}))
130+
.use(pagination({
131+
path: 'blog/page',
132+
iteratee: (post, idx) => ({
133+
post,
134+
displaySummary: idx < 10
135+
})
136+
}))
129137
.use(markdown(markedOptions))
130138
.use(githubLinks({ locale: locale }))
131139
.use(prism())

layouts/blog-index.hbs

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,40 @@
11
<!DOCTYPE html>
2-
<html lang="{{site.locale}}">
2+
<html lang="{{ site.locale }}">
33
{{> html-head }}
44

55
<body>
66
{{> header }}
77

88
<div id="main">
99
<div class="container">
10+
<h2>News from {{ pagination.year }}</h2>
1011

1112
<ul class="blog-index">
12-
{{#each collections.blog}}
13-
{{#if title}}
14-
<li>
15-
<time datetime="{{ date }}">{{ strftime date "%d %b %y" }}</time>
16-
<a href="/{{../../site.locale}}/{{ path }}/">{{ title }}</a>
13+
{{#each pagination.posts}}
14+
<li>
15+
<time datetime="{{ post.date }}">{{ strftime post.date "%d %b" }}</time>
16+
<a href="/{{ ../site.locale }}/{{ post.path }}/">{{ post.title }}</a>
17+
18+
{{#if displaySummary}}
1719
<div class="summary">
18-
{{{ summary contents ../../site.locale path }}}
20+
{{{ summary post.contents ../site.locale post.path }}}
1921
<div>
20-
</li>
21-
{{/if}}
22+
{{/if}}
23+
</li>
2224
{{/each}}
2325
</ul>
2426

27+
{{#if pagination}}
28+
<nav class="pagination">
29+
{{#if pagination.prev.path}}
30+
<a href="/{{ site.locale }}/{{ pagination.prev.path }}">&lt; Newer</a>
31+
{{/if}}
32+
33+
{{#if pagination.next.path}}
34+
<a href="/{{ site.locale }}/{{ pagination.next.path }}">Older &gt;</a>
35+
{{/if}}
36+
</nav>
37+
{{/if}}
2538
</div>
2639
</div>
2740

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
.blog-index
2+
list-style none
3+
padding 0
4+
25
time
36
margin-right 1em
47
color $light-gray
58

69
.summary
7-
font-size: 75%
10+
margin-left 1em
11+
font-size: 75%

locale/en/blog/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
---
22
layout: blog-index.hbs
3+
paginate: blog
34
---

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
"metalsmith-permalinks": "0.4.0",
4444
"metalsmith-prism": "2.1.1",
4545
"metalsmith-stylus": "1.0.0",
46+
"metalsmith-yearly-pagination": "^1.0.2",
4647
"ncp": "2.0.0",
4748
"node-geocoder": "^3.4.1",
4849
"node-version-data": "1.0.0",

scripts/helpers/summary.js

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,46 @@
22

33
const cheerio = require('cheerio')
44

5-
const SUMMARY_LENGHT = 400
5+
const SUMMARY_MAX_LENGTH = 300
6+
const IGNORE_SELECTORS = ['.blogpost-header', '.anchor', 'h1', 'h2', 'h3', 'blockquote']
7+
8+
/**
9+
* Due to the nature of metalsmith and
10+
* how the metalsmith-paginate plugin operates,
11+
* this helper has to handle two different types of
12+
* HTML contents:
13+
* - clean blog posts converted from markdown to HTML,
14+
* seen on the first page of blog posts
15+
* - the remaining paginated pages has gone
16+
* through the handlebars process and therefore has the
17+
* entire page layout (w/<html>, <head> and <body> etc)
18+
* wrapped around the actual blog contents :(
19+
*/
620

721
module.exports = function (contents, locale, path) {
8-
let $ = cheerio.load(contents)
22+
const $ = cheerio.load(contents)
23+
const $body = $('body')
24+
const hasBody = $body.length > 0
25+
const $elements = hasBody ? $body.find('article > *') : $('*')
926

1027
let summary = ''
1128

12-
$('*').each((i, elem) => {
13-
if (summary.length > SUMMARY_LENGHT) {
14-
summary += `<p><a href='/${locale}/${path}/'>Read more...</a></p>`
15-
return false
16-
}
17-
18-
if (elem.parent) {
19-
return
20-
}
21-
22-
summary += $.html(elem)
23-
})
29+
$elements
30+
.not((i, elem) => IGNORE_SELECTORS.some((selector) => $(elem).is(selector)))
31+
.each((i, elem) => {
32+
if (summary.length > SUMMARY_MAX_LENGTH) {
33+
summary += `<p><a href='/${locale}/${path}/'>Read more...</a></p>`
34+
return false
35+
}
36+
37+
// dont re-add nested elements when extracting summary
38+
// from blog posts not contained in a complete HTML document
39+
if (!hasBody && elem.parent) {
40+
return
41+
}
42+
43+
summary += $.html(elem)
44+
})
2445

2546
return summary
2647
}

0 commit comments

Comments
 (0)