ssg  

Preface

Goal: Refactoring custom page, for categories and tags.

Making more layout is fun, especially in refactoring process.

Table of Content

  • Preface: Table of Content

  • 1: Prepare: Font Awesome

  • 2: Header Menu

  • 3: Refactoring Terms

  • 4: Responsive

  • What is Next ?

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.