ssg  
Where to Discuss?

Local Group

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.

  1. 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.

  1. 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

Hexo: SASS Tree

Assets: Custom Stylesheet

And also custom stylesheet.

// 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.

<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>&nbsp;By Tags
          </a>
          <a class="navbar-item"
            href="<%- url_for("/categories.html") %>">
            <span class="fa fa-folder"></span>&nbsp;By Category
          </a>
          <hr class="navbar-divider">
          <a class="navbar-item"
            href="<%- url_for("/archives/") %>">
            <span class="fa fa-calendar"></span>&nbsp;By Date
          </a>
        </div>
      </div>

    ...
  </div>

  ...
</nav>

Render: Browser

Open in your favorite browser.

  • In any page

Hexo: Header Menu with FontAwesome


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.

  <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>&nbsp;<%= 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") %>&nbsp;
        </time></div>
        <div class="is-clearfix"></div>
      </li>
    <% }) %>
    </ul>
  </section>
  <% }) %>

Consider render our view in browser:

Hexo: Refactoring Terms: Tags Step One

Terms: Step Two: Post Item

The thing is, the code above is still too long. We need more refactoring.

  <% terms.each(function(item){ %>
  <section class="section box">
    <div id="<%= item.name %>" class ="anchor-target">
      <p>
        <span class="fa fa-folder"></span>&nbsp;<%= 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.

      <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") %>
            &nbsp;<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:

Hexo: Refactoring Terms: Tags Step Two

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

  <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>
    &nbsp;
    <% }) %>
    <div class="tags dummy"></div>
  </div>

Consider render our view in browser:

Hexo: Refactoring Terms: Button of Tags

Final: Categories and Tags

Our final tags page would be like these below.

<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.

<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:

Hexo: Refactoring Terms: Categories


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.

  <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.

Hexo: Responsive: is-full-mobile

Screen is Tablet: Half

Consider have a wider screen size. Such as landscape tablet, or regular PC monitor.

Hexo: Responsive: is-half-tablet

Screen is Wide: One Third

This take a wide screen flat monitor.

Hexo: Responsive: is-one-third-widescreen

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.