Preface
Goal: Miscellanous range loop to achieved wordpress like widget.
We can make a sidebar, so that we can have more information, just like what common in wordpress site or other blogging platform. I’m using custom css based on Bulma box to suit example needs, and of course you can use any class other than this custom css.
Source Code
You can download the source code of this article here.
Extract and run on CLI:
$ npm install
Related Article: SASS
The SASS part of this article is already discussed in this two article:
It is time to reuse the class for real world situation.
1: Prepare
Theme
Still with tutor-04
.
-
- config.toml
- gitlab.com/…/config.toml
# Extensions
theme: tutor-04
Layout: EJS Post
This post.ejs is very similar with page.ejs. The point is you can customize as creative as you want.
-
- themes/tutor-04/layout/post.ejs
- gitlab.com/…/layout/post.ejs
<main role="main">
...
</main>
<aside class="sidebar column is-one-thirds is-paddingless">
<%- partial('widget/related-posts') %>
</aside>
Now we are using only related-posts. You can have as many widget as you want as shown below:
<aside class="sidebar column is-one-thirds is-paddingless">
<%- partial('widget/related-posts') %>
<%- partial('widget/tags', {view_tag_type: 'before'}) %>
<%- partial('widget/categories') %>
<%- partial('widget/archives-grouped') %>
<%- partial('widget/archives-github') %>
<%- partial('widget/archives-gitlab') %>
</aside>
We are going to discuss each partial, one by one.
Layout: EJS Page
The same method applied to page kind layout.
<aside class="sidebar column is-one-thirds is-paddingless">
<%- partial('widget/recent-posts') %>
<%- partial('widget/affiliates') %>
<%- partial('widget/friends') %>
<%- partial('widget/archives-simple') %>
</aside>
We are going to discuss each partial, one by one.
SASS: List
As already mention in other article, You can see the code here:
-
- themes/tutor-04/sass/css/_list.scss
- gitlab.com/…/sass/css/_list.scss.
// -- -- -- -- --
// _list.scss
...
.
2: Simple Example
Consider start with simple example. We need something without any loop, EJS tag or whatsoever. Pure HTML with a list of URLs, that you might need to show on your side panel.
Layout: EJS Page
Consider examine only affiliate links:
-
- themes/tutor-04/layout/page.ejs
- gitlab.com/…/layout/page.ejs
<aside class="sidebar column is-one-thirds is-paddingless">
<%- partial('widget/affiliates') %>
</aside>
Layout: Widget: HTML Affiliates
Notice the html
file extension.
-
- themes/tutor-04/layout/widget/affiliates.html
- gitlab.com/…/layout/widget/affiliates.html
<section class="panel is-light">
<div class="panel-header">
<p>Affiliates</p>
<span class="fa fa-child"></span>
</div>
<div class="panel-body has-background-white">
<ul class="panel-list">
<li><a href="http://epsi-rns.github.io/"
>Linux/BSD Desktop Customization</a></li>
<li><a href="http://epsi-rns.gitlab.io/"
>Mobile/Web Development Blog</a></li>
<li><a href="http://oto-spies.info/"
>Car Painting and Body Repair.</a></li>
</ul>
</div>
</section>
Render: Browser
Just open one of the quote post:
Now you can see the result in the browser.
This the basic of HTML class required for the rest of this article.
3: Recent Post
Layout: EJS Page
Consider examine only recent posts:
-
- themes/tutor-04/layout/page.ejs
- gitlab.com/…/layout/page.ejs
<aside class="sidebar column is-one-thirds is-paddingless">
<%- partial('widget/recent-posts') %>
</aside>
Layout: Widget: EJS Recent Post
Now with the usual ejs
file extension.
-
- themes/tutor-04/layout/widget/recent-posts.ejs
- gitlab.com/…/layout/widget/recent-posts.ejs
<section class="panel is-light">
<div class="panel-header">
<p>Recent Posts</p>
<span class="fa fa-newspaper"></span>
</div>
<div class="panel-body has-background-white">
<ul class="panel-list">
<% site.posts.sort('date', -1).limit(5).each(function(post){ %>
<li><a href="<%- url_for(post.path) %>"
><%= post.title || '(no title)' %></a></li>
<% }) %>
</ul>
</div>
</section>
The Loop
After sorting the posts array by date, I limit the result for only first five result.
<% site.posts.sort('date', -1).limit(5).each(function(post){ %>
...
<% }) %>
Render: Browser
Just open one of the page kind:
Now you can see the result in the browser.
4: Categories and Tags
Both are Taxonomies. So the layouts is pretty similar.
Layout: EJS Post
Now using post kind instead of page kind.
-
- themes/tutor-04/layout/post.ejs
- gitlab.com/…/layout/post.ejs
<aside class="sidebar column is-one-thirds is-paddingless">
<%- partial('widget/categories') %>
</aside>
Layout: Widget: EJS Categories
Using Bulma’s tag class tag is-small is-info:
-
- themes/tutor-04/layout/widget/categories.ejs
- gitlab.com/…/layout/widget/categories.ejs
<section class="panel is-light">
<div class="panel-header">
<p>Categories</p>
<span class="fa fa-tag"></span>
</div>
<div class="panel-body has-background-white">
<% site.categories.forEach(function(cat){ %>
<a class="tag is-small is-info" href="<%- url_for(cat.path) %>">
<%= cat.name %> <span class="fa fa-folder"></span>
</a>
<% }) %>
</div>
</section>
The Loop
The loop is self explanatory.
<% site.categories.forEach(function(cat){ %>
...
<% }) %>
Render: Browser
Just open one of the quote post:
Layout: EJS Post
Consider make the code above a little bit more complex.
We can pass argument to side panels.
Here we can have a choice of tag icon to be shown,
after
or before
.
-
- themes/tutor-04/layout/post.ejs
- gitlab.com/…/layout/post.ejs
<aside class="sidebar column is-one-thirds is-paddingless">
<%- partial('widget/tags', {view_tag_type: 'before'}) %>
</aside>
Using Bulma’s tag class tag is-small is-light:
-
- themes/tutor-04/layout/widget/tags.ejs
- gitlab.com/…/layout/widget/tags.ejs
<!-- view_tag_type : 'before' or 'after' -->
<section class="panel is-light">
<div class="panel-header">
<p>Tags</p>
<span class="fa fa-tag"></span>
</div>
<div class="panel-body has-background-white">
<% if (view_tag_type == 'after'){ %>
<% site.tags.forEach(function(tag){ %>
<a class="tag is-small is-light has-background-white"
href="<%- url_for(tag.path) %>">
<%= tag.name %> <span class="fa fa-folder"></span>
</a>
<% }) %>
<% } else { %>
<% site.tags.forEach(function(tag){ %>
<a class="tag is-small is-light has-background-white"
href="<%- url_for(tag.path) %>">
<span class="fa fa-folder"></span> <%= tag.name %>
</a>
<% }) %>
<% } %>
</div>
</section>
The Loop
The loop is still self explanatory.
<% site.tags.forEach(function(tag){ %>
...
<% }) %>
Render: Browser
Now you can see the result in the browser.
5: Archives
This archives widget is common in wordpress.
Layout: Widget: EJS Archives Simple
Hexo has built in list_archives helper.
-
- themes/tutor-04/layout/widget/archives-simple.ejs
- gitlab.com/…/layout/widget/archives-simple.ejs
<section class="panel is-light">
<div class="panel-header">
<p>Archives</p>
<span class="fa fa-archive"></span>
</div>
<div class="panel-body has-background-white">
<%- list_archives({show_count: theme.show_count, type: theme.archive_type}) %>
</div>
</section>
Now you can see the result in the browser.
We need something that we can style better.
Javascript: Widget: EJS Archives Grouped
Remember the Archives (section list) tutorial in a previous chapter ? We can also apply this in similar fashion, and of course with the same javascript.
// Data Model
// https://developer.mozilla.org/.../reduce
function groupBy(objectArray, property) {
return objectArray.reduce(function (acc, obj) {
var key = obj[property];
if (!acc[key]) {
acc[key] = [];
}
acc[key].push(obj);
return acc;
}, {});
}
// grouping by date
const posts = site.posts.map(post => ({
...post,
year: date(post.date, "YYYY"),
month: date(post.date, "MMMM")
}));
const postsByYear = groupBy(posts, 'year');
// additional
const pageYear = date(page.date, 'YYYY');
const pageMonth = date(page.date, 'MMMM');
Layout: Widget: EJS Archives Grouped
Now consider pour the javascript to HTML template in EJS artefact below:
-
- themes/tutor-04/layout/widget/archives-grouped.ejs
- gitlab.com/…/layout/widget/archives-grouped.ejs
<%
...
_%>
<section class="panel is-light">
<div class="panel-header">
<p>Archives</p>
<span class="fa fa-archive"></span>
</div>
<div class="panel-body has-background-white">
<% Object.keys(postsByYear).sort(date, -1).forEach(function (year){ %>
<div class ="archive-year" id="<%= year %>">
<a href="<%- url_for("/archives/") %>#<%= year %>">
<%= year %></a>
</div>
<% if (year == pageYear) {%>
<ul class="panel-archive">
<%
const postsByMonth = groupBy(postsByYear[year], 'month');
Object.keys(postsByMonth).forEach(function (month){
%>
<li class="list-month">
<span id="<%= year %>-<%= month %>">
<a href="<%- url_for("/archives/") %>#<%= year %>-<%= month %>">
<%= month %></a> - <%= year %></span>
<% if (month == pageMonth) {%>
<ul class="panel-list">
<% postsByMonth[month].forEach(function(post){ %>
<li>
<a href="<%- url_for(post.path) %>">
<%= post.title %>
</a>
</li>
<% }) %>
</ul>
<% } %>
</li>
<% }) %>
</ul>
<% } %>
<% }) %>
</div>
</section>
The Loop
I know it is complex. So I write again here as below:
<% Object.keys(postsByYear).sort(date, -1).forEach(function (year){ %>
<%= year %>
...
<% if (year == pageYear) {%>
<%
const postsByMonth = groupBy(postsByYear[year], 'month');
Object.keys(postsByMonth).forEach(function (month){
%>
<%= month %> - <%= year %>
...
<% if (month == pageMonth) {%>
<% postsByMonth[month].forEach(function(post){ %>
...
<%= post.title %>
...
<% }) %>
<% } %>
<% }) %>
<% } %>
<% }) %>
Th effort is worthy.
Render: Browser
Now you can see the result in the browser.
What is Next ?
Consider continue reading [ Hexo - Data ]. There are, some interesting topic about Example Static Data with Hexo.
Thank you for reading.