Blogging with hugo & netlify

Blogging with hugo & netlify

Here is a great tutorial on how to host hugo on netlify

Other examples using the exact same theme:

Creating the hugo site

In order to create a new hugo site simply go:

hugo new site [path] [flags]

Create a new repository via git

init the git repo and push it to the guthub repo:

echo "# website2" >> README.md
git init
git add README.md
git commit -m "first commit"
git remote add origin https://github.com/thomaslaber/website2.git
git push -u origin master

# Push an existing repository from the command line
# Alternatively you could link it to an already existing git repo: 

git remote add origin https://github.com/thomaslaber/website2.git
git push -u origin master

Theme as git submodule

This is the theme I decided to go for Mainroad. Now you could add a theme of your choice git simply cloning it. However, it is more elegant to add it as a submodule.

Submodules allow you to include or embed one or more repositories as a sub-folder inside another repository.

git submodule add https://github.com/vimux/mainroad themes/mainroad
git submodule init
git submodule update

# This means it can be updated by running:

git submodule update --remote themes/mainroad

Adapting the theme

Now we simply copy the config.toml in order to immediately have a running config for the theme.

cp themes/mainroad/exampleSite/config.toml .

We also could copy the examplesite folder from the theme folder in order to have some sample content to display. However, for now we refrain from doing that. We start the hugo server by:

hugo server -D

Add custom CSS

We do not want to change anything in the theme folder as it will be updated and thus overwritten at some point of time. Therefore, we have to persist all our changes in the

Inside the config file we assign the path to an css file which can be found in static/css:

[params]
    custom_css = ["css/tl.css"]
You can reference as many stylesheets as you want. Their paths need to be relative to the static folder. Inside the header partial you can include every custom stylesheet from above beside the original one:

{{ range .Site.Params.custom_css -}}
    <link rel="stylesheet" href="{{ . | absURL }}">
{{- end }}

Changing colors

Unfortunately, the mainroad theme does not come with a built-in color-theme-support. Therefore, we have to replace color codes manually: I chose to go from ███ #e64946 ███ to ███ #191970 ███. This can easily be done by runnnig a search and replace in the style.css after it was copied to the static/css folder.

Remember: No changes in the theme folder!

Adding Particles background

In order to set a simple but important optical highlight, I decided to include the particle.js. This is done by adding the scripts in the static/js folder.

<div id="particles-js">	</div>
<script src="https://cdn.jsdelivr.net/particles.js/2.0.0/particles.min.js"></script>
<script src="{{ .Site.BaseURL }}js/particles.js"></script> 
#particles-js {
	/* position: absolute; */
	height: 100px;
	background-image: linear-gradient(to bottom right, black, navy,#aaa);
  }

A big upset was the possibility to add new menu items: It only works by adding the following code directly into menu.html (\layouts\partials) and not into the template file. A more elegant way would include an option in the config file, i.e. config.toml.

<li class="menu__item">
  <a class="menu__link" href="/categories/book/">Books</a>
</li>
<li class="menu__item">
  <a class="menu__link" href="/categories/project/">Projects</a>
</li>

Adding highlight.js

We are adding a few options to our config file:

highlight = true
highlightStyle = "monokai-sublime"
highlightLanguages = ["r", "sql", "bash", "css"]

Using these parameter we are loading them in the <head> of baseof.html:

{{ if .Site.Params.highlight | default false }}
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
    {{ range .Site.Params.highlightLanguages }} 
      <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/languages/{{ . }}.min.js"></script> 
    {{ end }}
  <script>hljs.initHighlightingOnLoad();</script>
{{ end }}

Adding a custom search function

Following a tutorial we again start by adding some parameters to config.toml.

[outputs]
  home = [ "HTML", "RSS", "JSON"]

Note: Make shure to locate the required index.json file in the layouts folder. Once the file exists, hugo is going to dump the index to file. It should look like:

[{{ range $index, $page := .Site.Pages }}
{{- if ne $page.Type "json" -}}
{{- if and $index (gt $index 0) -}},{{- end }}
{
    "uri": "{{ $page.Permalink }}",
    "title": "{{ htmlEscape $page.Title}}",
    "tags": [{{ range $tindex, $tag := $page.Params.tags }}{{ if $tindex }}, {{ end }}"{{ $tag| htmlEscape }}"{{ end }}],
    "description": "{{ htmlEscape .Description}}",
    "content": {{$page.Plain | jsonify}}
}
{{- end -}}
{{- end -}}]

Once this is done, hugo generates a lunrjs-index.json at the root of your public folder. If you encounter some problems run: hugo --verbose and check messages and warnings.

We add another css file css/auto-complete.css to our <head>.

Finally, we need to load lunr. Please note: as lunr.js is based on jquery, make sure jquery.js gets loaded first.

<body>
...
<!-- custom search -->
{{ if not .Site.Params.disableSearch }}
    <script type="text/javascript" src="{{ .Site.BaseURL }}js/lunr.min.js"></script>
    <script type="text/javascript" src="{{ .Site.BaseURL }}js/auto-complete.js"></script>
            
    <script type="text/javascript">
        var baseurl = "{{ .Site.BaseURL }}";
    </script>
    <script type="text/javascript" src="{{ .Site.BaseURL }}js/search.js"></script>
{{ end }}
...
  </body>

and finally, we add a search entry box somewhere in your webpage layout:

{{ if not .Site.Params.disableSearch }}
    <li class="dropdown">
    <a>
        <i class="fa fa-search"></i>
        <div class="searchbox pull-right">
        <input data-search-input id="search-by" type="text">
        </div>
    </a>
    </li>
{{ end }}

Finally, we delete  in » in search.js at line 80. I do not know what purpose is served.

Custom sidebar

I had to create a new widget in layouts\partials\widgets and called it toc.html:

{{ if eq .Kind "page"  }}
<div class="widget-toc" id="sticker">
  <h4 class="widget__title">Table of Content</h4>
  <div class="toc__menu">
    {{ .TableOfContents }}
  </div>
</div>
{{ end }}

Please not that {{ .TableOfContents }} virtually does all of the work.

The new widget has to be added to the site via the config.toml. Please not the right section:

[Params.sidebar]
  widgets_page = ["toc"]

I added some javascript for two toggle effects for the table of content:

  1. Make the toc sticky.
  2. Make the toc disappear.
$(document).ready(function(){
  $("#sticker").sticky({topSpacing:10});
});

var clicked = false;

function toggleBtnClick() {
  if (clicked) {
    $("#sticker").sticky({topSpacing:10});
    $("#pin_button img").removeClass("deactivated");
    $("#pin_button img").addClass("activated");
    clicked = false;
  } else {
    $("#sticker").unstick();
    $("#pin_button img").removeClass("activated");
    $("#pin_button img").addClass("deactivated");
    clicked = true;
  }
}

var clicked2 = false;

function toggleBtnClick2() {
  if (clicked2) {
    $("aside").show();
    $("#hide_button img").removeClass("deactivated");
    $("#hide_button img").addClass("activated");
    clicked2 = false;
  } else {
    $("aside").hide();
    $("#hide_button img").removeClass("activated");
    $("#hide_button img").addClass("deactivated");
    clicked2 = true;
  }
}

I pushed the table of content in the sidebar and made it sticky using stickyjs.com. This means I also have to add a custom javascript-file to get loaded: custom.js. I did this by adding the following lines to baseof.html in \layouts_default. I also added to small icons to be execute the javascript commands:

<script type="text/javascript" src="{{ .Site.BaseURL }}js/jquery.sticky.js"></script>
<script type="text/javascript" src="{{ .Site.BaseURL }}js/custom.js"></script> 
...
</head>

<body class="body">
{{ if eq .Kind "page"  }}
  <div class="sidebar_menu">
    <span onclick="toggleBtnClick()" id="pin_button"><sup><img src="{{ .Site.BaseURL }}img/pin.png" width="25px" class="activated"></sup></span>
    <span onclick="toggleBtnClick2()" id="hide_button"><sup><img src="{{ .Site.BaseURL }}img/eye.png" width="25px" class="activated"></sup></span>
  </div>
  {{ end }}

The usual target="_blank" is not really supported in markdown, only a few subversions do. Therefore, you can add this line of jquery code to let javascript do the work:

//add target="_blank" to all external links
$('.content a[href^="http"').attr('target', '_blank');