Preface
Goal: Refactoring custom page, for categories and tags.
Making more layout is fun, especially in refactoring process.
Source Code
You can download the source code of this article here.
Extract and run on CLI:
$ npm install
1: Prepare
To achieve pretty looks, we require this iconic Fontawesome. So I decide to separate it in different tutorial.
Theme
This preparation is required.
- Create theme themes/tutor-04.
You can use source code above, oor from gitlab repository or, you can also copy paste from themes/tutor-03.
- Edit configuration _config.yml, and save.
# Extensions
theme: tutor-04
Vendors: FontAwesome
Prepare Fontawesome in vendor directory.
$ tree -d themes/tutor-04/sass/ -L 2
themes/tutor-04/sass/
├── css
└── vendors
├── bulma
└── font-awesome-5
Assets: Custom Stylesheet
And also custom stylesheet.
-
- themes/tutor-04/sass/css/fontawesome.scss
- gitlab.com/…/sass/css/fontawesome.scss
// Font Awesome
$fa-font-path: "https://use.fontawesome.com/releases/v5.2.0/webfonts";
// Import partials from `sass_dir` (defaults to `_sass`)
@import "vendors/font-awesome-5/fontawesome";
@import "vendors/font-awesome-5/solid";
@import "vendors/font-awesome-5/brands";
Do not forget to compile the SASS, with any tools that works for you.
$ dart-sass --watch -I sass sass/css:source/css/ --style=compressed --no-source-map
2: Header Menu
Real world website building require real links. Consider complete the previous header, to test this FontAwesome
Layout: EJS Header
This is a looong Header, with logo image.
-
- themes/tutor-04/layout/site/header.ejs
- gitlab.com/…/layout/site/header.ejs
<nav role="navigation" aria-label="main navigation"
class="navbar is-fixed-top is-white maxwidth header-deco"
id="navbar-vue-app">
<div class="navbar-brand">
...
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link">
Archives
</a>
<div class="navbar-dropdown">
<a class="navbar-item"
href="<%- url_for("/tags.html") %>">
<span class="fa fa-tags"></span> By Tags
</a>
<a class="navbar-item"
href="<%- url_for("/categories.html") %>">
<span class="fa fa-folder"></span> By Category
</a>
<hr class="navbar-divider">
<a class="navbar-item"
href="<%- url_for("/archives/") %>">
<span class="fa fa-calendar"></span> By Date
</a>
</div>
</div>
...
</div>
...
</nav>
Render: Browser
Open in your favorite browser.
- In any page
3: Refactoring Terms
Now it is time to go back to custom page as our primarily main focus. I do like to modularized long code, so it looks more human readable.
Artefacts
Our terms require at least four artefacts.
-
themes/tutor-04/layout/terms/title.ejs
-
themes/tutor-04/layout/terms/list.ejs
-
themes/tutor-04/layout/terms/buttons.ejs
-
themes/tutor-04/layout/terms/post-items.ejs
We need to put them in layout/terms directory.
Terms: Step One: List
Our first attempt of refactoring is as below:
- themes/tutor-03/layout/kind/tags.ejs
<main role="main"
class="column is-full box-deco has-background-white">
<%- partial('terms/title') %>
<%- partial('terms/list',
{terms: site.tags, taxonomyname: 'Tag' }) %>
</main>
While the title.ejs is simply moving that section.
-
- themes/tutor-04/layout/terms/title.ejs
- gitlab.com/…/layout/terms/title.ejs
<section class="section">
<h1 class="title is-4"><%= config.author %></h1>
<h2 class="subtitle is-4"><%= config.subtitle %></h2>
<h3 class="title is-3"><%= page.title %></h3>
</section>
And the title.ejs is simply moving that section.
- themes/tutor-04/layout/terms/list.ejs
<% terms.each(function(item){ %>
<section class="section box">
<div id="<%= item.name %>" class ="anchor-target">
<p>
<span class="fa fa-folder"></span> <%= taxonomyname %>:
<a href="<%- url_for(item.path) %>"><%= item.name %></a>
</p>
</div>
<ul>
<% item.posts.each(function(post){ %>
<li>
<div class="is-pulled-left">
<a href="<%- url_for(post.path) %>">
<%= post.title %>
</a></div>
<div class="is-pulled-right has-text-right"><time>
<%= date(post.date, "DD MMM") %>
</time></div>
<div class="is-clearfix"></div>
</li>
<% }) %>
</ul>
</section>
<% }) %>
Consider render our view in browser:
Terms: Step Two: Post Item
The thing is, the code above is still too long. We need more refactoring.
-
- themes/tutor-04/layout/terms/list.ejs
- gitlab.com/…/layout/terms/list.ejs
<% terms.each(function(item){ %>
<section class="section box">
<div id="<%= item.name %>" class ="anchor-target">
<p>
<span class="fa fa-folder"></span> <%= taxonomyname %>:
<a href="<%- url_for(item.path) %>"><%= item.name %></a>
</p>
</div>
<div class="archive-list">
<% item.posts.each(function(post){ %>
<%- partial('terms/post-item', {post: post}) %>
<% }) %>
</div>
</section>
<% }) %>
I make different design for the post-item.ejs, For practical reason, this template is using, div instead of ul.
-
- themes/tutor-04/layout/terms/post-item.ejs
- gitlab.com/…/layout/terms/post-item.ejs
<div class="archive-item meta-item">
<div class="meta_link has-text-right">
<time class="meta_time is-pulled-right"
datetime="<%= date(post.date, "YYYY-MM-DD[T]HH:mm:ss.SSS") %>">
<%= date(post.date, "MMM DD, YYYY") %>
<span class="fa fa-calendar"></span>
</time>
</div>
<div class="is-pulled-left">
<a href="<%- url_for(post.path) %>">
<%= post.title %>
</a>
</div>
<div class="is-clearfix"></div>
</div>
Consider render our view in browser:
Tag Buttons
Most CSS frameworks equipped with nice tag button. This is very useful in our case.
Consider use only buttons in our tags layout as below:
- themes/tutor-03/layout/kind/tags.ejs
<main role="main"
class="column is-full box-deco has-background-white">
<%- partial('terms/buttons', {terms: site.tags}) %>
</main>
And the button would be
-
- themes/tutor-03/layout/terms/buttons.ejs
- gitlab.com/…/layout/terms/buttons.ejs
<div class="field is-grouped is-grouped-multiline">
<% terms.each(function(item){ %>
<div class="tags has-addons">
<a href="<%- url_for(item.path) %>">
<div class="tag is-light"><%= item.name %>
</div><div class="tag is-dark"><%= item.posts.length %></div>
</a>
</div>
<% }) %>
<div class="tags dummy"></div>
</div>
Consider render our view in browser:
Final: Categories and Tags
Our final tags page would be like these below.
-
- themes/tutor-03/layout/kind/tags.ejs
- gitlab.com/…/layout/kind/tags.ejs
<main role="main"
class="column is-full box-deco has-background-white">
<%- partial('terms/buttons', {terms: site.tags}) %>
<%- partial('terms/title') %>
<%- partial('terms/list',
{terms: site.tags, taxonomyname: __('tag')}) %>
</main>
.
And so is the final categorie pages.
-
- themes/tutor-03/layout/kind/categories.ejs
- gitlab.com/…/layout/kind/categories.ejs
<main role="main"
class="column is-full box-deco has-background-white">
<%- partial('terms/buttons', {terms: site.categories}) %>
<%- partial('terms/title') %>
<%- partial('terms/list',
{terms: site.categories, taxonomyname: __('category')}) %>
</main>
Consider render the category page in browser:
4: Responsive
Refactoring make our code easier to modify. Suppose that we want to make a slight design change, we only need to change specific part.
Layout: EJS List
Responsive classes on outer element, and panel to wrap inner element.
-
- themes/tutor-04/layout/terms/list-responsive.ejs
- gitlab.com/…/layout/terms/list-responsive.ejs
<section class="columns is-multiline" id="archive">
<% terms.each(function(item){ %>
<div class="column is-full-mobile
is-half-tablet is-one-third-widescreen">
<section class="panel is-light">
<div class="panel-header" id="<%= item.name %>">
<p><%= taxonomyname %>:
<a href="<%- url_for(item.path) %>">
<%= item.name %></a></p>
<span class="fa fa-folder"></span>
</div>
<div class="panel-body has-background-white">
<div class="archive-list archive-p3">
<% item.posts.each(function(post){ %>
<%- partial('terms/post-item', {post: post}) %>
<% }) %>
</div>
</div>
</section>
</div>
<% }) %>
</section>
How Does It Works?
These bulma classes below do all the hardworks:
-
is-full-mobile
-
is-half-tablet
-
is-one-third-widescreen
<section class="columns is-multiline" id="archive">
<% terms.each(function(item){ %>
<div class="column
is-full-mobile
is-half-tablet
is-one-third-widescreen">
...
</div>
<% }) %>
</section>
Consider have a look at difference for each screen size.
Screen is Mobile: Full
You can test this in your smartphone.
Screen is Tablet: Half
Consider have a wider screen size. Such as landscape tablet, or regular PC monitor.
Screen is Wide: One Third
This take a wide screen flat monitor.
I think that’s all about this article.
What is Next ?
There are, some interesting topic about Widget in Hexo. Consider continue reading [ Hexo - Widget ].
Thank you for reading.