Converting Simple Web Page Into Hugo Theme Part 5 - Templating and Icons

February 12, 2019

We are almost done with creating theme. What is left is to add icons for social menu items and nav links.

Previous posts:

Part 1 - HTML & CSS

Part 2 - Theme Home Page

Part 3 - Single Post Page

Part 4 - Externalized Configuration

For that we’ll use Hugos templating functionalities (and the fact that Hugo doesn’t care what we are trying to template as long as it uses .html extension) to conveniently add SVG icons where needed.

We’ll obtain SVG icons from awesome feathericons.

Find and download github icon and open it in a text editor, it’ll look something like this:

<svg 
xmlns="http://www.w3.org/2000/svg" 
width="24" height="24" 
viewBox="0 0 24 24" 
fill="none" 
stroke="currentColor" 
stroke-width="2" 
stroke-linecap="round" 
stroke-linejoin="round" 
class="feather feather-github">
<path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22">
</path>
</svg>

Yep, standard SVG.

Now, lets copy the content of SVG icon into partials/svg/icons.html (extension needs to be .html) and add a bit Hugo logic:

<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather">

{{ if eq "github" . }}
<path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path>
{{ end }}

</svg>

Notice that once {{ if eq "github" . }} is added into SVG it is no longer a valid SVG. It becomes valid SVG when Hugo processes it and selects only one condition based on the parameter (icon name) that we’ll pass to this partial. So we have one SVG file that’ll contain all icons we need and we’ll select which icon we want using a parameter. That’s nice!

Lets add other icons too by copy-pasting content between svg tags of each icon we download:

<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather">

    {{ if eq "linkedin" . }}
    <path d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z"></path><rect x="2" y="9" width="4" height="12"></rect><circle cx="4" cy="4" r="2"></circle>
    {{ else if eq "github" . }}
    <path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path>
    {{ else if eq "gitlab" . }}
    <path d="M22.65 14.39L12 22.13 1.35 14.39a.84.84 0 0 1-.3-.94l1.22-3.78 2.44-7.51A.42.42 0 0 1 4.82 2a.43.43 0 0 1 .58 0 .42.42 0 0 1 .11.18l2.44 7.49h8.1l2.44-7.51A.42.42 0 0 1 18.6 2a.43.43 0 0 1 .58 0 .42.42 0 0 1 .11.18l2.44 7.51L23 13.45a.84.84 0 0 1-.35.94z"></path>
    {{ else if eq "twitter" . }}
    <path d="M23 3a10.9 10.9 0 0 1-3.14 1.53 4.48 4.48 0 0 0-7.86 3v1A10.66 10.66 0 0 1 3 4s-4 9 5 13a11.64 11.64 0 0 1-7 2c9 5 20 0 20-11.5a4.5 4.5 0 0 0-.08-.83A7.72 7.72 0 0 0 23 3z"></path>
    {{ else if eq "email" . }}
    <path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path><polyline points="22,6 12,13 2,6"></polyline>
    {{ else if eq "rss" . }}
    <path d="M4 11a9 9 0 0 1 9 9"></path><path d="M4 4a16 16 0 0 1 16 16"></path><circle cx="5" cy="19" r="1"></circle>
    {{ else if eq "chevron-right" . }}
    <polyline points="9 18 15 12 9 6"></polyline>
    {{ else if eq "chevron-left" . }}
    <polyline points="15 18 9 12 15 6"></polyline>
    {{ end }}

</svg>

svg tags are common for all icons, only actual icon content is changed for each icon.

To use this partial inside a layout simply call it with desired icon name as parameter, e.g.:

{{- partial "svg/icons" "github" -}}

and Hugo will generate desired SVG icon.

We can now update our sidebar to include icons for social menu items:

<nav class="main-nav">
  <h3>{{ .Site.Title }}</h3>

  <ul class="nav">
    {{ range .Site.Menus.main }}
    <li>
      <a href="{{ .URL }}">
        {{ .Pre }}
        <span>{{ .Name }}</span>
      </a>
    </li>
    {{ end }}
  </ul>

  <ul class="social">
    {{ range .Site.Params.social }}

    {{ if .enabled }}
    <li>
      <a href="{{ .url }}" {{ if ne .name "email" }} target="_blank" rel="noopener" {{ end }} >
        {{- partial "svg/icons" .name -}}
      </a>
    </li>
    {{ end }}
    
    {{ end }}
  </ul>

</nav>

And update pagination.html too:

<div class="page-nav">

  {{ if .Paginator.HasPrev }}
  <a href="{{ .Paginator.Prev.URL }}">
    {{- partial "svg/icons" "chevron-left" -}} Newer
  </a>
  {{ else }}
  <div></div>
  {{ end }}
  

  {{ if .Paginator.HasNext }}
  <a href="{{ .Paginator.Next.URL }}">
    Older {{- partial "svg/icons" "chevron-right" -}}
  </a>
  {{ end }}

</div> 

That’s it! We now have fully functional, minimal to the bones Hugo theme.

All theme sources (with some additions) can be found here.